Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
insync / usr / lib / insync / PySide2 / Qt / resources / qtwebengine_resources_100p.pak
Size: Mime:
¯Ø1ˆÙ1’Ú1ÿÛ1½Ü1Ò)Ý1M<Þ1Fß1\xà1°{á1·â1žã1Áä1“å1‰"æ1%ç1ç.è1¦2é1ÌQê1waë1Ùqì1ðxí1“‚î1Ҍï1ސð1ܔñ1´šò1“ó1™ ô1í©õ1ǹö1KÏ÷1¼áø1eåù1Kêú1òøû1ýü1Úý1?þ13ÿ1h2 2ë"2?32Pœ2¥c2®2'F2‚X2Aa2fl2Ry2q2"(2B)2«Bz?™C{?îE|?%J}?±L~?CN?3O€?@R? U‚?yXƒ?T\„?Â_‹?]dŒ?ae?gf‘?»q“?¼r”?Ét•?du–?Â~Ôb›€Õb[‚ÖbC…×b<ˆØbӉÙbk‹œc5c½“žcø•Ÿc{—dn˜dödòèg¶ ég»"êgñ+ëgî-ìg)1ígV6îgÃ?ñg¨AògHógNôgnSõgVZög|]÷g
bùgéeûg	iýgñlþg=whx{h ~h‡hҏhº	h*’
h”h9—h÷—h(šhΛh°h& h/¡h­¢hA¤h¾¥hP§hª hQ¬"h&½#hú½$hÀ%h!Â&hâÂ'hÄÃ(hCÄ)h¾Ä*h#Å+h®Å,h„Æ-hYÇ.h(È/h
É0hÊ1hkÊ2héÊ3h’Ë4hgÌ5h<Í6hÎ7hæÎ8h»Ï9hÐ:hpÒ;hNÔ?h-Ö@hê	Ah±	Bhx	Ch?	Dh¤	Hh"	PhŠ	Qhù	Rhl	Shß	ThR 	Uh!	VhÑ!	Wh›"	Xhe#	Yh$	ZhÎ$	[h–%	\h[&	]h'	^hÎ'	_h)	`hû)	ò*	ïgZðgZøgdúgeügfÿgehfhehdhZhm
hmhwhxhyhxhyhxhw!hm<h‘=h’>h“<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no">
    
      <script>
        function setMessage(msg) {
          document.getElementById('message').textContent = msg;
        }
        function notifyDidFinishLoading() {
          if (plugin.didFinishLoading)
            plugin.didFinishLoading();

          if (plugin.didFinishIconRepositionForTesting)
            plugin.didFinishIconRepositionForTesting();
        }
      </script>
    
    
    <style>/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file. */

html, body {
  -webkit-user-select: none;
  font-family: sans-serif;
  height: 100%;
  margin: 0;
  overflow: hidden;
  text-align: center;
  width: 100%;
}

h1 {
  display: none;
  font-size: 10pt;
  font-weight: normal;
  padding: 0pt 10pt;
}

p {
  font-size: 8pt;
  padding: 0pt 14pt;
}

#t {
  background-color: #f7f7f7;
  color: #646464;
}

#outer {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  height: 100%;
  justify-content: center;
  position: absolute;
  width: 100%;
  flex-direction: column;
}

.icon {
  max-height: 100%;
  max-width: 100%;
  opacity: .3;
}

@media (orientation: landscape) and (min-height: 2em) and (min-width: 14em) {
  #outer {
    flex-direction: row;
  }
  .icon {
    max-height: 100%;
    max-width: 50%;
  }
  h1 {
    display: block;
  }
}

@media (min-height: 7em) and (min-width: 6em) {
  #outer {
    flex-direction: column;
  }
  .icon {
    max-height: 50%;
    max-width: 100%;
  }
  h1 {
    display: block;
  }
}
</style>
  </head>
  <body id="t" onload="notifyDidFinishLoading();">
    <div i18n-values="title:name" id="outer">
      <img class="icon"
           src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0iIzYyNjI2MiI+CiAgICA8cGF0aCBkPSJNMCAwaDQ4djQ4SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNDEgMjJoLTN2LThjMC0yLjIxLTEuNzktNC00LTRoLThWN2MwLTIuNzYtMi4yNC01LTUtNXMtNSAyLjI0LTUgNXYzSDhjLTIuMjEgMC0zLjk4IDEuNzktMy45OCA0bC0uMDEgNy42SDdjMi45OCAwIDUuNCAyLjQyIDUuNCA1LjRTOS45OCAzMi40IDcgMzIuNEg0LjAxTDQgNDBjMCAyLjIxIDEuNzkgNCA0IDRoNy42di0zYzAtMi45OCAyLjQyLTUuNCA1LjQtNS40IDIuOTggMCA1LjQgMi40MiA1LjQgNS40djNIMzRjMi4yMSAwIDQtMS43OSA0LTR2LThoM2MyLjc2IDAgNS0yLjI0IDUtNXMtMi4yNC01LTUtNXoiLz4KPC9zdmc+Cg==">
      <h1 id="message">$i18n{message}</h1>
    </div>
  </body>
</html>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no">
    <style>/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file. */

html, body {
  -webkit-user-select: none;
  font-family: sans-serif;
  height: 100%;
  margin: 0;
  overflow: hidden;
  text-align: center;
  width: 100%;
}

h1 {
  display: none;
  font-size: 10pt;
  font-weight: normal;
  padding: 0pt 10pt;
}

p {
  font-size: 8pt;
  padding: 0pt 14pt;
}

#t {
  background-color: #f7f7f7;
  color: #646464;
}

#outer {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  height: 100%;
  justify-content: center;
  position: absolute;
  width: 100%;
  flex-direction: column;
}

.icon {
  max-height: 100%;
  max-width: 100%;
  opacity: .3;
}

@media (orientation: landscape) and (min-height: 2em) and (min-width: 14em) {
  #outer {
    flex-direction: row;
  }
  .icon {
    max-height: 100%;
    max-width: 50%;
  }
  h1 {
    display: block;
  }
}

@media (min-height: 7em) and (min-width: 6em) {
  #outer {
    flex-direction: column;
  }
  .icon {
    max-height: 50%;
    max-width: 100%;
  }
  h1 {
    display: block;
  }
}
</style>
  </head>
  <body id="t" onLoad="insertLink()">
    <div i18n-values="title:name" id="outer">
      <img class="icon"
           src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0iIzYyNjI2MiI+CiAgICA8cGF0aCBkPSJNMCAwaDQ4djQ4SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNDEgMjJoLTN2LThjMC0yLjIxLTEuNzktNC00LTRoLThWN2MwLTIuNzYtMi4yNC01LTUtNXMtNSAyLjI0LTUgNXYzSDhjLTIuMjEgMC0zLjk4IDEuNzktMy45OCA0bC0uMDEgNy42SDdjMi45OCAwIDUuNCAyLjQyIDUuNCA1LjRTOS45OCAzMi40IDcgMzIuNEg0LjAxTDQgNDBjMCAyLjIxIDEuNzkgNCA0IDRoNy42di0zYzAtMi45OCAyLjQyLTUuNCA1LjQtNS40IDIuOTggMCA1LjQgMi40MiA1LjQgNS40djNIMzRjMi4yMSAwIDQtMS43OSA0LTR2LThoM2MyLjc2IDAgNS0yLjI0IDUtNXMtMi4yNC01LTUtNXoiLz4KPC9zdmc+Cg==">
      <h1 id="message">$i18n{message}</h1>
    </div>
  </body>
</html>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no">
    <style>
      html,
      body {
        height: 100%;
        width: 100%;
      }

      body {
        background-color: #f5f5f5;  /* google-grey-100 */
        margin: 0;
      }

      svg {
        height: 40px;
        width: 40px;
      }

      path {
        fill: #bdbdbd;  /* google-grey-400 */
      }

      #icon-container {
        align-items: center;
        display: flex;
        height: 100%;
        justify-content: center;
        width: 100%;
      }

      #footer {
        align-items: center;
        background-color: #4285f4;  /* google-blue-500 */
        border-radius: 2px;
        bottom: 0;
        color: white;
        display: flex;
        font-size: 14px;
        justify-content: space-between;
        left: 0;
        max-height: 52px;
        min-height: 20px;
        padding: 14px 24px;
        position: absolute;
        right: 0;
      }

      p,
      a {
        line-height: 20px;
      }

      p {
        font-family: Roboto;
        margin: 0;
      }

      a {
        font-family: Roboto Medium;
        margin-left: 48px;
        text-transform: uppercase;
      }

      a:link,
      a:visited {
        color: white;
        text-decoration: none;
      }

    </style>
  </head>
  <body>
    <div id="icon-container">
      <!-- Material Design PDF icon -->
      <svg viewbox="0 0 24 24">
        <path d="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9.5 8.5c0 .83-.67 1.5-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83-.67 1.5-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"></path>
      </svg>
    </div>
    <div id="footer" i18n-values="title:name">
      <p>$i18n{fileName}</p>
      <a href="#" onclick="plugin.openPDF()">View PDF</a>
    </div>
  </body>
</html>
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, user-scalable=no">
  <script>
    function setMessage(msg) {
      document.getElementById('message').textContent = msg;
    }
    function notifyDidFinishLoading() {
      if (plugin.didFinishLoading)
        plugin.didFinishLoading();

      if (plugin.didFinishIconRepositionForTesting)
        plugin.didFinishIconRepositionForTesting();
    }
  </script>
  <style>/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file. */

html, body {
  -webkit-user-select: none;
  font-family: sans-serif;
  height: 100%;
  margin: 0;
  overflow: hidden;
  text-align: center;
  width: 100%;
}

h1 {
  display: none;
  font-size: 10pt;
  font-weight: normal;
  padding: 0pt 10pt;
}

p {
  font-size: 8pt;
  padding: 0pt 14pt;
}

#t {
  background-color: #f7f7f7;
  color: #646464;
}

#outer {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  height: 100%;
  justify-content: center;
  position: absolute;
  width: 100%;
  flex-direction: column;
}

.icon {
  max-height: 100%;
  max-width: 100%;
  opacity: .3;
}

@media (orientation: landscape) and (min-height: 2em) and (min-width: 14em) {
  #outer {
    flex-direction: row;
  }
  .icon {
    max-height: 100%;
    max-width: 50%;
  }
  h1 {
    display: block;
  }
}

@media (min-height: 7em) and (min-width: 6em) {
  #outer {
    flex-direction: column;
  }
  .icon {
    max-height: 50%;
    max-width: 100%;
  }
  h1 {
    display: block;
  }
}
</style>
  <style>
  #outer {
    cursor: pointer;
  }
  </style>
</head>
<body id="t" onload="notifyDidFinishLoading();">
  <div i18n-values="title:name" id="outer">
    <img class="icon"
         src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0iIzYyNjI2MiI+CiAgICA8cGF0aCBkPSJNMCAwaDQ4djQ4SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNDEgMjJoLTN2LThjMC0yLjIxLTEuNzktNC00LTRoLThWN2MwLTIuNzYtMi4yNC01LTUtNXMtNSAyLjI0LTUgNXYzSDhjLTIuMjEgMC0zLjk4IDEuNzktMy45OCA0bC0uMDEgNy42SDdjMi45OCAwIDUuNCAyLjQyIDUuNCA1LjRTOS45OCAzMi40IDcgMzIuNEg0LjAxTDQgNDBjMCAyLjIxIDEuNzkgNCA0IDRoNy42di0zYzAtMi45OCAyLjQyLTUuNCA1LjQtNS40IDIuOTggMCA1LjQgMi40MiA1LjQgNS40djNIMzRjMi4yMSAwIDQtMS43OSA0LTR2LThoM2MyLjc2IDAgNS0yLjI0IDUtNXMtMi4yNC01LTUtNXoiLz4KPC9zdmc+Cg==">
    <h1 id="message">$i18n{message}</h1>
  </div>
  <script>
    window.onkeydown = function(e) {
      if (e.key == 'Enter' || e.key == ' ') {
        plugin.showPermissionBubble();
        e.preventDefault();
      }
    };

    document.getElementById('outer').onclick = function() {
      plugin.showPermissionBubble();
    };
  </script>
</body>
</html>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<script>
  window.onload = function() {
    if (plugin.didFinishLoading)
      plugin.didFinishLoading();
  };

  window.onkeydown = function(e) {
    if (e.key == 'Enter' || e.key == ' ') {
      plugin.load();
      e.preventDefault();
    }
  };
</script>
<style>/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file. */

html, body {
  -webkit-user-select: none;
  font-family: sans-serif;
  height: 100%;
  margin: 0;
  overflow: hidden;
  text-align: center;
  width: 100%;
}

h1 {
  display: none;
  font-size: 10pt;
  font-weight: normal;
  padding: 0pt 10pt;
}

p {
  font-size: 8pt;
  padding: 0pt 14pt;
}

#t {
  background-color: #f7f7f7;
  color: #646464;
}

#outer {
  align-items: center;
  box-sizing: border-box;
  display: flex;
  height: 100%;
  justify-content: center;
  position: absolute;
  width: 100%;
  flex-direction: column;
}

.icon {
  max-height: 100%;
  max-width: 100%;
  opacity: .3;
}

@media (orientation: landscape) and (min-height: 2em) and (min-width: 14em) {
  #outer {
    flex-direction: row;
  }
  .icon {
    max-height: 100%;
    max-width: 50%;
  }
  h1 {
    display: block;
  }
}

@media (min-height: 7em) and (min-width: 6em) {
  #outer {
    flex-direction: column;
  }
  .icon {
    max-height: 50%;
    max-width: 100%;
  }
  h1 {
    display: block;
  }
}
</style>
<style>
#outer {
  border: none;
  flex-direction: row;
  cursor: pointer;
}

#shielding {
  background-color: rgba(0, 0, 0, 0.5);
  height: 100%;
  left: 0px;
  position: absolute;
  top: 0px;
  width: 100%;
  z-index: 2;
}

#plugin-icon {
  opacity: 0.8;
  max-height: 100%;
  max-width: 100%;
  min-width: 0;
  min-height: 0;
}

#plugin-icon:hover {
  opacity: 0.95;
}

#poster {
  height: 100%;
  object-fit: contain;
  width: 100%;
  z-index: 1;
}

#inner-container {
  align-items: center;
  display: flex;
  height: 100%;
  justify-content: center;
  left: 0px;
  max-height: 100%;
  max-width: 100%;
  position: absolute;
  top: 0px;
  width: 100%;
  z-index: 2;
}
</style>
<base i18n-values="href:baseurl">
</head>

<body>
  <div i18n-values="title:name" id="outer">
    <img id="poster" i18n-values="srcset:poster">
    <div id="shielding"></div>
    <div id="inner-container"
         i18n-values=".style.width:visibleWidth;.style.height:visibleHeight">
      <img id="plugin-icon" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAA8dJREFUaAXdWs9vEkEUZkvZQloNxJoY40kxJsDNo9GDif+Bf4CHpjEmJPoPeMce1F408dYjQePBgycv3vRG4GBMPREPLSlpCUWggN+3ncVl6PJrZ5a6k0x2Z2fnve/befPmzcwaIbVpGeLCyEsiG5L4Pso9kbu4nkj1CysSaAQ5trm5uV6pVB4eHx+/brVan3u93s9+v19Fbolc5TPW8R2+yzZsK2TIpPFYf6LS6Pb29rX9/f0NgPsIsA3kWVODbSmDsigT2TdCZjabvVyv158D9eGsyMe8f0iZlA0yJrK2FE4mkxer1eoTmMjvMYA8VVE2dVAXmHC8KU1mPp9Pdjqd755QztCYuqgTLJT1TrRYLN7T2Qtu/KiTukGGY8dTiu3t7T2CoqabMh+eN4kBLOjd5kpRQcIHrJNVCDIz94zJLoX4RfaEzK4pzGzqMRPmIFvEmJCRy2ViEg5gsjej2/PTO8lgJ5WJTbjmsePFpA+fJGzR9cQIFq4mZnBWPY8mJX84YhQRwJnhTFSEHXK7mcrNZvMdGjBQ1JqIFb0y4sUMBm3Q7Dl2KpVKd5jx1Xa1MgFWEWgO9UqEEagKxSSBL7WSy+WuIrJ9r0Kmmwxihi4uIwYpJkJxtzZTPxdE7IXVaq1We4bGWkyNmMHAmvGpMIQFzqppmg8GtNTccCXYSCQSb8rl8n2Q+aVG7D8pxEzs9pNlrtam/uQTXnT0iC2f14guUyN2yOcSO7TCpecEfFNXuxChHvY+Te0phCkzNWInB8uWw+HwLWrSnGxTe6vS1AT2JYtIJBK5oZmEU/yfTCbzbWtr62673f7grJjnXmC3xvoaupq7HUrSGNOScaoytSoEr1lMcHNB1uJDWZWpWdhtIj7g1qvCcltQUUe+pFfViHR+xBi82EY8Hn+Be9dodqTl8ANit1wix0ZtuE57ifPKFczMOyDxCtrmJRES2PvskR4WK7uYJZPa4Z8qiMIh3E6lUjuGYVz3qpPYyYHd2+t2uz+8CpyiPXVxQnycTqe/qCBBnQK7RaR7cHDwdQogXl5xmtJLCJrblGQQAjt39q2gcR22Ns8mNMfXUDpjHqEp6VqfNMSO/oCfzjBeaWzl/GojYTzonBwdHX0a0PJ+o82UnNAE5qHDosAsdUk0EJsPJBKY7SCSCcQGHYmEgrJlSi7B2MQmE6RAHCucUoEXC8JBj00mEEdvNplAHIbaZMxCoXDTzwMg6lJ9PG2TCcQPAzYZXv/7XzicZALxU41M6Fz85jR02uNEOOc9NzN4dMz1ObMsX9uPZ38BvwZw6z92PI4AAAAASUVORK5CYII=" />
    </div>
  </div>
  <script>
    document.getElementById('poster').onerror = function() {
      this.hidden = true;
    };

    document.getElementById('outer').onclick = function() {
      plugin.load();
    };

    window.resizePoster = function(marginLeft, marginTop, width, height) {
      var container = document.getElementById('inner-container');
      container.style.marginLeft = marginLeft;
      container.style.marginTop = marginTop;
      container.style.width = width;
      container.style.height = height;

      if (plugin.didFinishIconRepositionForTesting) {
        // Defer until reflow complete.
        window.setTimeout(function() {
          plugin.didFinishIconRepositionForTesting();
        });
      }
    };
  </script>
</body>
</html>
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the app API.

var appNatives = requireNative('app');
var process = requireNative('process');
var extensionId = process.GetExtensionId();
var logActivity = requireNative('activityLogger');

function wrapForLogging(fun) {
  if (!extensionId)
    return fun;  // nothing interesting to log without an extension

  return function() {
    // TODO(ataly): We need to make sure we use the right prototype for
    // fun.apply. Array slice can either be rewritten or similarly defined.
    logActivity.LogAPICall(extensionId, "app." + fun.name,
        $Array.slice(arguments));
    return $Function.apply(fun, this, arguments);
  };
}

// This becomes chrome.app
var app = {
  getIsInstalled: wrapForLogging(appNatives.GetIsInstalled),
  getDetails: wrapForLogging(appNatives.GetDetails),
  runningState: wrapForLogging(appNatives.GetRunningState)
};

// Tricky; "getIsInstalled" is actually exposed as the getter "isInstalled",
// but we don't have a way to express this in the schema JSON (nor is it
// worth it for this one special case).
//
// So, define it manually, and let the getIsInstalled function act as its
// documentation.
var isInstalled = wrapForLogging(appNatives.GetIsInstalled);
$Object.defineProperty(
    app, 'isInstalled',
    {
      __proto__: null,
      configurable: true,
      enumerable: true,
      get: function() { return isInstalled(); },
    });

// Called by app_bindings.cc.
function onInstallStateResponse(state, callbackId) {
  var callback = callbacks[callbackId];
  delete callbacks[callbackId];
  if (typeof callback == 'function') {
    try {
      callback(state);
    } catch (e) {
      console.error('Exception in chrome.app.installState response handler: ' +
                    e.stack);
    }
  }
}

// TODO(kalman): move this stuff to its own custom bindings.
var callbacks = { __proto__: null };
var nextCallbackId = 1;

function getInstallState(callback) {
  var callbackId = nextCallbackId++;
  callbacks[callbackId] = callback;
  appNatives.GetInstallState(callbackId);
}

$Object.defineProperty(
    app, 'installState',
    {
      __proto__: null,
      configurable: true,
      enumerable: true,
      value: wrapForLogging(getInstallState),
      writable: true,
    });

exports.$set('binding', app);
exports.$set('onInstallStateResponse', onInstallStateResponse);
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom bindings for the automation API.
var AutomationNode = require('automationNode').AutomationNode;
var AutomationRootNode = require('automationNode').AutomationRootNode;
var automation = apiBridge || require('binding').Binding.create('automation');
var automationInternal =
    getInternalApi ?
        getInternalApi('automationInternal') :
        require('binding').Binding.create('automationInternal').generate();
var exceptionHandler = require('uncaught_exception_handler');
var logging = requireNative('logging');
var nativeAutomationInternal = requireNative('automationInternal');
var DestroyAccessibilityTree =
    nativeAutomationInternal.DestroyAccessibilityTree;
var GetIntAttribute = nativeAutomationInternal.GetIntAttribute;
var StartCachingAccessibilityTrees =
    nativeAutomationInternal.StartCachingAccessibilityTrees;
var AddTreeChangeObserver = nativeAutomationInternal.AddTreeChangeObserver;
var RemoveTreeChangeObserver =
    nativeAutomationInternal.RemoveTreeChangeObserver;
var GetFocusNative = nativeAutomationInternal.GetFocus;

var jsLastError = bindingUtil ? undefined : require('lastError');
function hasLastError() {
  return bindingUtil ?
      bindingUtil.hasLastError() : jsLastError.hasError(chrome);
}

/**
 * A namespace to export utility functions to other files in automation.
 */
window.automationUtil = function() {};

// TODO(aboxhall): Look into using WeakMap
var idToCallback = {};

var DESKTOP_TREE_ID = 0;

automationUtil.storeTreeCallback = function(id, callback) {
  if (!callback)
    return;

  var targetTree = AutomationRootNode.get(id);
  if (!targetTree) {
    // If we haven't cached the tree, hold the callback until the tree is
    // populated by the initial onAccessibilityEvent call.
    if (id in idToCallback)
      idToCallback[id].push(callback);
    else
      idToCallback[id] = [callback];
  } else {
    callback(targetTree);
  }
};

/**
 * Global list of tree change observers.
 * @type {Object<number, TreeChangeObserver>}
 */
automationUtil.treeChangeObserverMap = {};

/**
 * The id of the next tree change observer.
 * @type {number}
 */
automationUtil.nextTreeChangeObserverId = 1;

/**
 * @type {AutomationNode} The current focused node. This is only updated
 *   when calling automationUtil.updateFocusedNode.
 */
automationUtil.focusedNode = null;

/**
 * Gets the currently focused AutomationNode.
 * @return {AutomationNode}
 */
automationUtil.getFocus = function() {
  var focusedNodeInfo = GetFocusNative(DESKTOP_TREE_ID);
  if (!focusedNodeInfo)
    return null;
  var tree = AutomationRootNode.getOrCreate(focusedNodeInfo.treeId);
  if (tree)
    return privates(tree).impl.get(focusedNodeInfo.nodeId);
};

/**
 * Update automationUtil.focusedNode to be the node that currently has focus.
 */
automationUtil.updateFocusedNode = function() {
  automationUtil.focusedNode = automationUtil.getFocus();
};

/**
 * Updates the focus on blur.
 */
automationUtil.updateFocusedNodeOnBlur = function() {
  var focus = automationUtil.getFocus();
  automationUtil.focusedNode = focus ? focus.root : null;
};

automation.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj.
  apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) {
    StartCachingAccessibilityTrees();

    // enableTab() ensures the renderer for the active or specified tab has
    // accessibility enabled, and fetches its ax tree id to use as
    // a key in the idToAutomationRootNode map. The callback to
    // enableTab is bound to the callback passed in to getTree(), so that once
    // the tree is available (either due to having been cached earlier, or after
    // an accessibility event occurs which causes the tree to be populated), the
    // callback can be called.
    var params = { tabID: tabID };
    automationInternal.enableTab(params,
        function onEnable(id) {
          if (hasLastError()) {
            callback();
            return;
          }
          automationUtil.storeTreeCallback(id, callback);
        });
  });

  var desktopTree = null;
  apiFunctions.setHandleRequest('getDesktop', function(callback) {
    StartCachingAccessibilityTrees();
    desktopTree = AutomationRootNode.get(DESKTOP_TREE_ID);
    if (!desktopTree) {
      if (DESKTOP_TREE_ID in idToCallback)
        idToCallback[DESKTOP_TREE_ID].push(callback);
      else
        idToCallback[DESKTOP_TREE_ID] = [callback];

      // TODO(dtseng): Disable desktop tree once desktop object goes out of
      // scope.
      automationInternal.enableDesktop(function() {
        if (hasLastError()) {
          AutomationRootNode.destroy(DESKTOP_TREE_ID);
          callback();
          return;
        }
      });
    } else {
      callback(desktopTree);
    }
  });

  apiFunctions.setHandleRequest('getFocus', function(callback) {
    callback(automationUtil.getFocus());
  });

  function removeTreeChangeObserver(observer) {
    for (var id in automationUtil.treeChangeObserverMap) {
      if (automationUtil.treeChangeObserverMap[id] == observer) {
        RemoveTreeChangeObserver(id);
        delete automationUtil.treeChangeObserverMap[id];
        return;
      }
    }
  }
  apiFunctions.setHandleRequest('removeTreeChangeObserver', function(observer) {
    removeTreeChangeObserver(observer);
  });

  function addTreeChangeObserver(filter, observer) {
    removeTreeChangeObserver(observer);
    var id = automationUtil.nextTreeChangeObserverId++;
    AddTreeChangeObserver(id, filter);
    automationUtil.treeChangeObserverMap[id] = observer;
  }
  apiFunctions.setHandleRequest('addTreeChangeObserver',
      function(filter, observer) {
    addTreeChangeObserver(filter, observer);
  });

  apiFunctions.setHandleRequest('setDocumentSelection', function(params) {
    var anchorNodeImpl = privates(params.anchorObject).impl;
    var focusNodeImpl = privates(params.focusObject).impl;
    if (anchorNodeImpl.treeID !== focusNodeImpl.treeID)
      throw new Error('Selection anchor and focus must be in the same tree.');
    if (anchorNodeImpl.treeID === DESKTOP_TREE_ID) {
      throw new Error('Use AutomationNode.setSelection to set the selection ' +
          'in the desktop tree.');
    }
    automationInternal.performAction({ treeID: anchorNodeImpl.treeID,
                                       automationNodeID: anchorNodeImpl.id,
                                       actionType: 'setSelection'},
                                     { focusNodeID: focusNodeImpl.id,
                                       anchorOffset: params.anchorOffset,
                                       focusOffset: params.focusOffset });
  });

});

automationInternal.onChildTreeID.addListener(function(treeID,
                                                      nodeID) {
  var tree = AutomationRootNode.getOrCreate(treeID);
  if (!tree)
    return;

  var node = privates(tree).impl.get(nodeID);
  if (!node)
    return;

  // A WebView in the desktop tree has a different AX tree as its child.
  // When we encounter a WebView with a child AX tree id that we don't
  // currently have cached, explicitly request that AX tree from the
  // browser process and set up a callback when it loads to attach that
  // tree as a child of this node and fire appropriate events.
  var childTreeID = GetIntAttribute(treeID, nodeID, 'childTreeId');
  if (!childTreeID)
    return;

  var subroot = AutomationRootNode.get(childTreeID);
  if (!subroot || subroot.role == 'unknown') {
    automationUtil.storeTreeCallback(childTreeID, function(root) {
      // Return early if the root has already been attached.
      if (root.parent)
        return;

      privates(root).impl.setHostNode(node);

      if (root.docLoaded) {
        privates(root).impl.dispatchEvent('loadComplete', 'page');
      }

      privates(node).impl.dispatchEvent('childrenChanged', 'none');
    });

    automationInternal.enableFrame(childTreeID);
  } else {
    privates(subroot).impl.setHostNode(node);
  }
});

automationInternal.onTreeChange.addListener(function(observerID,
                                                     treeID,
                                                     nodeID,
                                                     changeType) {
  var tree = AutomationRootNode.getOrCreate(treeID);
  if (!tree)
    return;

  var node = privates(tree).impl.get(nodeID);
  if (!node)
    return;

  var observer = automationUtil.treeChangeObserverMap[observerID];
  if (!observer)
    return;

  try {
    observer({target: node, type: changeType});
  } catch (e) {
    exceptionHandler.handle('Error in tree change observer for ' +
        treeChange.type, e);
  }
});

automationInternal.onNodesRemoved.addListener(function(treeID, nodeIDs) {
  var tree = AutomationRootNode.getOrCreate(treeID);
  if (!tree)
    return;

  for (var i = 0; i < nodeIDs.length; i++) {
    privates(tree).impl.remove(nodeIDs[i]);
  }
});

/**
 * Dispatch accessibility events fired on individual nodes to its
 * corresponding AutomationNode. Handle focus events specially
 * (see below).
 */
automationInternal.onAccessibilityEvent.addListener(function(eventParams) {
  var id = eventParams.treeID;
  var targetTree = AutomationRootNode.getOrCreate(id);
  if (eventParams.eventType == 'blur') {
    // Work around an issue where Chrome sends us 'blur' events on the
    // root node when nothing has focus, we need to treat those as focus
    // events but otherwise not handle blur events specially.
    var node = privates(targetTree).impl.get(eventParams.targetID);
    if (node == node.root)
      automationUtil.updateFocusedNodeOnBlur();
  } else if (eventParams.eventType == 'mediaStartedPlaying' ||
      eventParams.eventType == 'mediaStoppedPlaying') {
    // These events are global to the tree.
    eventParams.targetID = privates(targetTree).impl.id;
  } else {
    var previousFocusedNode = automationUtil.focusedNode;
    automationUtil.updateFocusedNode();

    // Fire focus events if necessary.
    if (automationUtil.focusedNode &&
        automationUtil.focusedNode != previousFocusedNode) {
      var eventParamsCopy = {};
      for (var key in eventParams)
        eventParamsCopy[key] = eventParams[key];
      eventParamsCopy['eventType'] = 'focus';
      eventParamsCopy['treeID'] =
          privates(automationUtil.focusedNode.root).impl.treeID;
      eventParamsCopy['targetID'] =
          privates(automationUtil.focusedNode).impl.id;
      privates(automationUtil.focusedNode.root)
          .impl.onAccessibilityEvent(eventParamsCopy);
    }
  }

  // Note that focus type events have already been handled above if there was a
  // focused node. All other events, even non-focus events that triggered a
  // focus dispatch, still need to have their original event fired.
  if ((!automationUtil.focusedNode || eventParams.eventType != 'focus') &&
      !privates(targetTree).impl.onAccessibilityEvent(eventParams))
    return;

  // If we're not waiting on a callback to getTree(), we can early out here.
  if (!(id in idToCallback))
    return;

  // We usually get a 'placeholder' tree first, which doesn't have any url
  // attribute or child nodes. If we've got that, wait for the full tree before
  // calling the callback.
  // TODO(dmazzoni): Don't send down placeholder (crbug.com/397553)
  if (id != DESKTOP_TREE_ID && !targetTree.url &&
      targetTree.children.length == 0)
    return;

  // If the tree wasn't available when getTree() was called, the callback will
  // have been cached in idToCallback, so call and delete it now that we
  // have the complete tree.
  for (var i = 0; i < idToCallback[id].length; i++) {
    var callback = idToCallback[id][i];
    callback(targetTree);
  }
  delete idToCallback[id];
});

automationInternal.onAccessibilityTreeDestroyed.addListener(function(id) {
  // Destroy the AutomationRootNode.
  var targetTree = AutomationRootNode.get(id);
  if (targetTree) {
    privates(targetTree).impl.destroy();
    AutomationRootNode.destroy(id);
  } else {
    logging.WARNING('no targetTree to destroy');
  }

  // Destroy the native cache of the accessibility tree.
  DestroyAccessibilityTree(id);
});

automationInternal.onAccessibilityTreeSerializationError.addListener(
    function(id) {
  automationInternal.enableFrame(id);
});

automationInternal.onActionResult.addListener(
    function(treeID, requestID, result) {
  var targetTree = AutomationRootNode.get(treeID);
  if (!targetTree)
    return;

  privates(targetTree).impl.onActionResult(requestID, result);
    });

if (!apiBridge)
  exports.$set('binding', automation.generate());
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var utils = require('utils');

function AutomationEventImpl(type, target, eventFrom) {
  this.propagationStopped = false;
  this.type = type;
  this.target = target;
  this.eventPhase = Event.NONE;
  this.eventFrom = eventFrom;
}

AutomationEventImpl.prototype = {
  __proto__: null,
  stopPropagation: function() {
    this.propagationStopped = true;
  },
};

function AutomationEvent() {
  privates(AutomationEvent).constructPrivate(this, arguments);
}
utils.expose(AutomationEvent, AutomationEventImpl, {
  functions: [
    'stopPropagation',
  ],
  readonly: [
    'type',
    'target',
    'eventPhase',
    'eventFrom',
  ],
});

exports.$set('AutomationEvent', AutomationEvent);
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var AutomationEvent = require('automationEvent').AutomationEvent;
var automationInternal =
    getInternalApi ?
        getInternalApi('automationInternal') :
        require('binding').Binding.create('automationInternal').generate();
var exceptionHandler = require('uncaught_exception_handler');

var natives = requireNative('automationInternal');

var IsInteractPermitted = natives.IsInteractPermitted;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?number} The id of the root node.
 */
var GetRootID = natives.GetRootID;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?string} The title of the document.
 */
var GetDocTitle = natives.GetDocTitle;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?string} The url of the document.
 */
var GetDocURL = natives.GetDocURL;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?boolean} True if the document has finished loading.
 */
var GetDocLoaded = natives.GetDocLoaded;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?number} The loading progress, from 0.0 to 1.0 (fully loaded).
 */
var GetDocLoadingProgress =
    natives.GetDocLoadingProgress;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?number} The ID of the selection anchor object.
 */
var GetAnchorObjectID = natives.GetAnchorObjectID;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?number} The selection anchor offset.
 */
var GetAnchorOffset = natives.GetAnchorOffset;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?string} The selection anchor affinity.
 */
var GetAnchorAffinity = natives.GetAnchorAffinity;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?number} The ID of the selection focus object.
 */
var GetFocusObjectID = natives.GetFocusObjectID;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?number} The selection focus offset.
 */
var GetFocusOffset = natives.GetFocusOffset;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @return {?string} The selection focus affinity.
 */
var GetFocusAffinity = natives.GetFocusAffinity;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?number} The id of the node's parent, or undefined if it's the
 *    root of its tree or if the tree or node wasn't found.
 */
var GetParentID = natives.GetParentID;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?number} The number of children of the node, or undefined if
 *     the tree or node wasn't found.
 */
var GetChildCount = natives.GetChildCount;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {number} childIndex An index of a child of this node.
 * @return {?number} The id of the child at the given index, or undefined
 *     if the tree or node or child at that index wasn't found.
 */
var GetChildIDAtIndex = natives.GetChildIDAtIndex;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?number} The ids of the children of the node, or undefined
 *     if the tree or node wasn't found.
 */
var GetChildIds = natives.GetChildIDs;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?Object} An object mapping html attributes to values.
 */
var GetHtmlAttributes = natives.GetHtmlAttributes;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?number} The index of this node in its parent, or undefined if
 *     the tree or node or node parent wasn't found.
 */
var GetIndexInParent = natives.GetIndexInParent;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?Object} An object with a string key for every state flag set,
 *     or undefined if the tree or node or node parent wasn't found.
 */
var GetState = natives.GetState;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {string} The restriction, one of
 * "disabled", "readOnly" or undefined if enabled or other object not disabled
 */
var GetRestriction = natives.GetRestriction;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {string} The checked state, as undefined, "true", "false" or "mixed".
 */
var GetChecked = natives.GetChecked;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {string} The role of the node, or undefined if the tree or
 *     node wasn't found.
 */
var GetRole = natives.GetRole;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?automation.Rect} The location of the node, or undefined if
 *     the tree or node wasn't found.
 */
var GetLocation = natives.GetLocation;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {number} startIndex The start index of the range.
 * @param {number} endIndex The end index of the range.
 * @return {?automation.Rect} The bounding box of the subrange of this node,
 *     or the location if there are no subranges, or undefined if
 *     the tree or node wasn't found.
 */
var GetBoundsForRange = natives.GetBoundsForRange;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?automation.Rect} The unclipped location of the node, or
 * undefined if the tree or node wasn't found.
 */
var GetUnclippedLocation = natives.GetUnclippedLocation;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {!Array.<number>} The text offset where each line starts, or an empty
 *     array if this node has no text content, or undefined if the tree or node
 *     was not found.
 */
var GetLineStartOffsets = requireNative(
    'automationInternal').GetLineStartOffsets;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {string} attr The name of a string attribute.
 * @return {?string} The value of this attribute, or undefined if the tree,
 *     node, or attribute wasn't found.
 */
var GetStringAttribute = natives.GetStringAttribute;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {string} attr The name of an attribute.
 * @return {?boolean} The value of this attribute, or undefined if the tree,
 *     node, or attribute wasn't found.
 */
var GetBoolAttribute = natives.GetBoolAttribute;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {string} attr The name of an attribute.
 * @return {?number} The value of this attribute, or undefined if the tree,
 *     node, or attribute wasn't found.
 */
var GetIntAttribute = natives.GetIntAttribute;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {string} attr The name of an attribute.
 * @return {?number} The value of this attribute, or undefined if the tree,
 *     node, or attribute wasn't found.
 */
var GetFloatAttribute = natives.GetFloatAttribute;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {string} attr The name of an attribute.
 * @return {?Array.<number>} The value of this attribute, or undefined
 *     if the tree, node, or attribute wasn't found.
 */
var GetIntListAttribute =
    natives.GetIntListAttribute;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @param {string} attr The name of an HTML attribute.
 * @return {?string} The value of this attribute, or undefined if the tree,
 *     node, or attribute wasn't found.
 */
var GetHtmlAttribute = natives.GetHtmlAttribute;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {automation.NameFromType} The source of the node's name.
 */
var GetNameFrom = natives.GetNameFrom;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {boolean}
 */
var GetBold = natives.GetBold;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {boolean}
 */
var GetItalic = natives.GetItalic;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {boolean}
 */
var GetUnderline = natives.GetUnderline;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {boolean}
 */
var GetLineThrough = natives.GetLineThrough;

/**
 * @param {number} axTreeID The id of the accessibility tree.
 * @param {number} nodeID The id of a node.
 * @return {?Array.<automation.CustomAction>} List of custom actions of the
 *     node.
 */
var GetCustomActions = natives.GetCustomActions;

var logging = requireNative('logging');
var utils = require('utils');

/**
 * A single node in the Automation tree.
 * @param {AutomationRootNodeImpl} root The root of the tree.
 * @constructor
 */
function AutomationNodeImpl(root) {
  this.rootImpl = root;
  this.hostNode_ = null;
  this.listeners = {__proto__: null};
}

AutomationNodeImpl.prototype = {
  __proto__: null,
  treeID: -1,
  id: -1,
  isRootNode: false,

  detach: function() {
    this.rootImpl = null;
    this.hostNode_ = null;
    this.listeners = {__proto__: null};
  },

  get root() {
    return this.rootImpl && this.rootImpl.wrapper;
  },

  get parent() {
    if (!this.rootImpl)
      return undefined;
    if (this.hostNode_)
      return this.hostNode_;
    var parentID = GetParentID(this.treeID, this.id);
    return this.rootImpl.get(parentID);
  },

  get htmlAttributes() {
    return GetHtmlAttributes(this.treeID, this.id) || {};
  },

  get state() {
    return GetState(this.treeID, this.id) || {};
  },

  get role() {
    return GetRole(this.treeID, this.id);
  },

  get restriction() {
    return GetRestriction(this.treeID, this.id);
  },

  get checked() {
    return GetChecked(this.treeID, this.id);
  },

  get location() {
    return GetLocation(this.treeID, this.id);
  },

  boundsForRange: function(startIndex, endIndex) {
    return GetBoundsForRange(this.treeID, this.id, startIndex, endIndex);
  },

  get unclippedLocation() {
    var result = GetUnclippedLocation(this.treeID, this.id);
    if (result === undefined)
      result = GetLocation(this.treeID, this.id);
    return result;
  },

  get indexInParent() {
    return GetIndexInParent(this.treeID, this.id);
  },

  get lineStartOffsets() {
    return GetLineStartOffsets(this.treeID, this.id);
  },

  get childTree() {
    var childTreeID = GetIntAttribute(this.treeID, this.id, 'childTreeId');
    if (childTreeID)
      return AutomationRootNodeImpl.get(childTreeID);
  },

  get firstChild() {
    if (!this.rootImpl)
      return undefined;
    if (this.childTree)
      return this.childTree;
    if (!GetChildCount(this.treeID, this.id))
      return undefined;
    var firstChildID = GetChildIDAtIndex(this.treeID, this.id, 0);
    return this.rootImpl.get(firstChildID);
  },

  get lastChild() {
    if (!this.rootImpl)
      return undefined;
    if (this.childTree)
      return this.childTree;
    var count = GetChildCount(this.treeID, this.id);
    if (!count)
      return undefined;
    var lastChildID = GetChildIDAtIndex(this.treeID, this.id, count - 1);
    return this.rootImpl.get(lastChildID);
  },

  get children() {
    if (!this.rootImpl)
      return [];

    if (this.childTree)
      return [this.childTree];

    var children = [];
    var childIds = GetChildIds(this.treeID, this.id);
    for (var i = 0; i < childIds.length; ++i) {
      var childID = childIds[i];
      var child = this.rootImpl.get(childID);
      $Array.push(children, child);
    }
    return children;
  },

  get previousSibling() {
    var parent = this.parent;
    if (!parent)
      return undefined;
    parent = privates(parent).impl;
    var indexInParent = GetIndexInParent(this.treeID, this.id);
    return this.rootImpl.get(
        GetChildIDAtIndex(parent.treeID, parent.id, indexInParent - 1));
  },

  get nextSibling() {
    var parent = this.parent;
    if (!parent)
      return undefined;
    parent = privates(parent).impl;
    var indexInParent = GetIndexInParent(this.treeID, this.id);
    return this.rootImpl.get(
        GetChildIDAtIndex(parent.treeID, parent.id, indexInParent + 1));
  },

  get nameFrom() {
    return GetNameFrom(this.treeID, this.id);
  },

  get bold() {
    return GetBold(this.treeID, this.id);
  },

  get italic() {
    return GetItalic(this.treeID, this.id);
  },

  get underline() {
    return GetUnderline(this.treeID, this.id);
  },

  get lineThrough() {
    return GetLineThrough(this.treeID, this.id);
  },

  get customActions() {
    return GetCustomActions(this.treeID, this.id);
  },

  doDefault: function() {
    this.performAction_('doDefault');
  },

  focus: function() {
    this.performAction_('focus');
  },

  getImageData: function(maxWidth, maxHeight) {
    this.performAction_('getImageData',
                        { maxWidth: maxWidth,
                          maxHeight: maxHeight });
  },

  hitTest: function(x, y, eventToFire) {
    this.hitTestInternal(x, y, eventToFire);
  },

  hitTestWithReply: function(x, y, opt_callback) {
    this.hitTestInternal(x, y, 'hitTestResult', opt_callback);
  },

  hitTestInternal: function(x, y, eventToFire, opt_callback) {
    // Convert from global to tree-relative coordinates.
    var location = GetLocation(this.treeID, GetRootID(this.treeID));
    this.performAction_('hitTest',
                        { x: Math.floor(x - location.left),
                          y: Math.floor(y - location.top),
                          eventToFire: eventToFire },
                        opt_callback);
  },

  makeVisible: function() {
    this.performAction_('makeVisible');
  },

  performCustomAction: function(customActionId) {
    this.performAction_('customAction', { customActionID: customActionId });
  },

  resumeMedia: function() {
    this.performAction_('resumeMedia');
  },

  scrollBackward: function(opt_callback) {
    this.performAction_('scrollBackward', {}, opt_callback);
  },

  scrollForward: function(opt_callback) {
    this.performAction_('scrollForward', {}, opt_callback);
  },

  scrollUp: function(opt_callback) {
    this.performAction_('scrollUp', {}, opt_callback);
  },

  scrollDown: function(opt_callback) {
    this.performAction_('scrollDown', {}, opt_callback);
  },

  scrollLeft: function(opt_callback) {
    this.performAction_('scrollLeft', {}, opt_callback);
  },

  scrollRight: function(opt_callback) {
    this.performAction_('scrollRight', {}, opt_callback);
  },

  setSelection: function(startIndex, endIndex) {
    if (this.state.editable) {
      this.performAction_('setSelection',
                          { focusNodeID: this.id,
                            anchorOffset: startIndex,
                            focusOffset: endIndex });
    }
  },

  setSequentialFocusNavigationStartingPoint: function() {
    this.performAction_('setSequentialFocusNavigationStartingPoint');
  },

  showContextMenu: function() {
    this.performAction_('showContextMenu');
  },

  startDuckingMedia: function() {
    this.performAction_('startDuckingMedia');
  },

  stopDuckingMedia: function() {
    this.performAction_('stopDuckingMedia');
  },

  suspendMedia: function() {
    this.performAction_('suspendMedia');
  },

  domQuerySelector: function(selector, callback) {
    if (!this.rootImpl)
      callback();
    automationInternal.querySelector(
      { treeID: this.rootImpl.treeID,
        automationNodeID: this.id,
        selector: selector },
      $Function.bind(this.domQuerySelectorCallback_, this, callback));
  },

  find: function(params) {
    return this.findInternal_(params);
  },

  findAll: function(params) {
    return this.findInternal_(params, []);
  },

  matches: function(params) {
    return this.matchInternal_(params);
  },

  addEventListener: function(eventType, callback, capture) {
    this.removeEventListener(eventType, callback);
    if (!this.listeners[eventType])
      this.listeners[eventType] = [];
    $Array.push(this.listeners[eventType], {
      __proto__: null,
      callback: callback,
      capture: !!capture,
    });
  },

  // TODO(dtseng/aboxhall): Check this impl against spec.
  removeEventListener: function(eventType, callback) {
    if (this.listeners[eventType]) {
      var listeners = this.listeners[eventType];
      for (var i = 0; i < listeners.length; i++) {
        if (callback === listeners[i].callback)
          $Array.splice(listeners, i, 1);
      }
    }
  },

  toJSON: function() {
    return { treeID: this.treeID,
             id: this.id,
             role: this.role,
             attributes: this.attributes };
  },

  dispatchEvent: function(eventType, eventFrom, mouseX, mouseY) {
    var path = [];
    var parent = this.parent;
    while (parent) {
      $Array.push(path, parent);
      parent = parent.parent;
    }
    var event = new AutomationEvent(eventType, this.wrapper, eventFrom);
    event.mouseX = mouseX;
    event.mouseY = mouseY;

    // Dispatch the event through the propagation path in three phases:
    // - capturing: starting from the root and going down to the target's parent
    // - targeting: dispatching the event on the target itself
    // - bubbling: starting from the target's parent, going back up to the root.
    // At any stage, a listener may call stopPropagation() on the event, which
    // will immediately stop event propagation through this path.
    if (this.dispatchEventAtCapturing_(event, path)) {
      if (this.dispatchEventAtTargeting_(event, path))
        this.dispatchEventAtBubbling_(event, path);
    }
  },

  toString: function() {
    var parentID = GetParentID(this.treeID, this.id);
    var childTreeID = GetIntAttribute(this.treeID, this.id, 'childTreeId');
    var count = GetChildCount(this.treeID, this.id);
    var childIDs = [];
    for (var i = 0; i < count; ++i) {
      var childID = GetChildIDAtIndex(this.treeID, this.id, i);
      $Array.push(childIDs, childID);
    }

    var result = 'node id=' + this.id +
        ' role=' + this.role +
        ' state=' + $JSON.stringify(this.state) +
        ' parentID=' + parentID +
        ' childIds=' + $JSON.stringify(childIDs);
    if (this.hostNode_) {
      var hostNodeImpl = privates(this.hostNode_).impl;
      result += ' host treeID=' + hostNodeImpl.treeID +
          ' host nodeID=' + hostNodeImpl.id;
    }
    if (childTreeID)
      result += ' childTreeID=' + childTreeID;
    return result;
  },

  dispatchEventAtCapturing_: function(event, path) {
    privates(event).impl.eventPhase = Event.CAPTURING_PHASE;
    for (var i = path.length - 1; i >= 0; i--) {
      this.fireEventListeners_(path[i], event);
      if (privates(event).impl.propagationStopped)
        return false;
    }
    return true;
  },

  dispatchEventAtTargeting_: function(event) {
    privates(event).impl.eventPhase = Event.AT_TARGET;
    this.fireEventListeners_(this.wrapper, event);
    return !privates(event).impl.propagationStopped;
  },

  dispatchEventAtBubbling_: function(event, path) {
    privates(event).impl.eventPhase = Event.BUBBLING_PHASE;
    for (var i = 0; i < path.length; i++) {
      this.fireEventListeners_(path[i], event);
      if (privates(event).impl.propagationStopped)
        return false;
    }
    return true;
  },

  fireEventListeners_: function(node, event) {
    var nodeImpl = privates(node).impl;
    if (!nodeImpl.rootImpl)
      return;

    var listeners = nodeImpl.listeners[event.type];
    if (!listeners)
      return;
    var eventPhase = event.eventPhase;
    for (var i = 0; i < listeners.length; i++) {
      if (eventPhase == Event.CAPTURING_PHASE && !listeners[i].capture)
        continue;
      if (eventPhase == Event.BUBBLING_PHASE && listeners[i].capture)
        continue;

      try {
        listeners[i].callback(event);
      } catch (e) {
        exceptionHandler.handle('Error in event handler for ' + event.type +
            ' during phase ' + eventPhase, e);
      }
    }
  },

  performAction_: function(actionType, opt_args, opt_callback) {
    if (!this.rootImpl)
      return;

    // Not yet initialized.
    if (this.rootImpl.treeID === undefined ||
        this.id === undefined) {
      return;
    }

    // Check permissions.
    if (!IsInteractPermitted()) {
      throw new Error(actionType + ' requires {"desktop": true} or' +
          ' {"interact": true} in the "automation" manifest key.');
    }
    var requestID = -1;
    if (opt_callback) {
      requestID = this.rootImpl.addActionResultCallback(opt_callback);
    }

    automationInternal.performAction({ treeID: this.rootImpl.treeID,
                                       automationNodeID: this.id,
                                       actionType: actionType,
                                       requestID: requestID},
                                     opt_args || {});
  },

  domQuerySelectorCallback_: function(userCallback, resultAutomationNodeID) {
    // resultAutomationNodeID could be zero or undefined or (unlikely) null;
    // they all amount to the same thing here, which is that no node was
    // returned.
    if (!resultAutomationNodeID || !this.rootImpl) {
      userCallback(null);
      return;
    }
    var resultNode = this.rootImpl.get(resultAutomationNodeID);
    if (!resultNode) {
      logging.WARNING('Query selector result not in tree: ' +
                      resultAutomationNodeID);
      userCallback(null);
    }
    userCallback(resultNode);
  },

  findInternal_: function(params, opt_results) {
    var result = null;
    this.forAllDescendants_(function(node) {
      if (privates(node).impl.matchInternal_(params)) {
        if (opt_results)
          $Array.push(opt_results, node);
        else
          result = node;
        return !opt_results;
      }
    });
    if (opt_results)
      return opt_results;
    return result;
  },

  /**
   * Executes a closure for all of this node's descendants, in pre-order.
   * Early-outs if the closure returns true.
   * @param {Function(AutomationNode):boolean} closure Closure to be executed
   *     for each node. Return true to early-out the traversal.
   */
  forAllDescendants_: function(closure) {
    var stack = $Array.reverse(this.wrapper.children);
    while (stack.length > 0) {
      var node = $Array.pop(stack);
      if (closure(node))
        return;

      var children = node.children;
      for (var i = children.length - 1; i >= 0; i--)
        $Array.push(stack, children[i]);
    }
  },

  matchInternal_: function(params) {
    if ($Object.keys(params).length === 0)
      return false;

    if ('role' in params && this.role != params.role)
        return false;

    if ('state' in params) {
      for (var state in params.state) {
        if (params.state[state] != (state in this.state))
          return false;
      }
    }
    if ('attributes' in params) {
      for (var attribute in params.attributes) {
        var attrValue = params.attributes[attribute];
        if (typeof attrValue != 'object') {
          if (this[attribute] !== attrValue)
            return false;
        } else if (attrValue instanceof $RegExp.self) {
          if (typeof this[attribute] != 'string')
            return false;
          if (!attrValue.test(this[attribute]))
            return false;
        } else {
          // TODO(aboxhall): handle intlist case.
          return false;
        }
      }
    }
    return true;
  }
};

var stringAttributes = [
    'accessKey',
    'ariaInvalidValue',
    'autoComplete',
    'className',
    'containerLiveRelevant',
    'containerLiveStatus',
    'description',
    'display',
    'htmlTag',
    'imageDataUrl',
    'language',
    'liveRelevant',
    'liveStatus',
    'name',
    'placeholder',
    'roleDescription',
    'textInputType',
    'url',
    'value'];

var boolAttributes = [
    'busy',
    'clickable',
    'containerLiveAtomic',
    'containerLiveBusy',
    'liveAtomic',
    'scrollable'
];

var intAttributes = [
    'backgroundColor',
    'color',
    'colorValue',
    'hierarchicalLevel',
    'posInSet',
    'scrollX',
    'scrollXMax',
    'scrollXMin',
    'scrollY',
    'scrollYMax',
    'scrollYMin',
    'setSize',
    'tableCellColumnIndex',
    'ariaCellColumnIndex',
    'tableCellColumnSpan',
    'tableCellRowIndex',
    'ariaCellRowIndex',
    'tableCellRowSpan',
    'tableColumnCount',
    'ariaColumnCount',
    'tableColumnIndex',
    'tableRowCount',
    'ariaRowCount',
    'tableRowIndex',
    'textSelEnd',
    'textSelStart'];

var nodeRefAttributes = [
    ['activedescendantId', 'activeDescendant'],
    ['inPageLinkTargetId', 'inPageLinkTarget'],
    ['nextFocusId', 'nextFocus'],
    ['nextOnLineId', 'nextOnLine'],
    ['previousFocusId', 'previousFocus'],
    ['previousOnLineId', 'previousOnLine'],
    ['tableColumnHeaderId', 'tableColumnHeader'],
    ['tableHeaderId', 'tableHeader'],
    ['tableRowHeaderId', 'tableRowHeader']];

var intListAttributes = [
    'lineBreaks',
    'markerEnds',
    'markerStarts',
    'markerTypes',
    'wordEnds',
    'wordStarts'];

var nodeRefListAttributes = [
    ['controlsIds', 'controls'],
    ['describedbyIds', 'describedBy'],
    ['flowtoIds', 'flowTo'],
    ['labelledbyIds', 'labelledBy']];

var floatAttributes = [
    'valueForRange',
    'minValueForRange',
    'maxValueForRange'];

var htmlAttributes = [
    ['type', 'inputType']];

var publicAttributes = [];

$Array.forEach(stringAttributes, function(attributeName) {
  $Array.push(publicAttributes, attributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
    __proto__: null,
    get: function() {
      return GetStringAttribute(this.treeID, this.id, attributeName);
    }
  });
});

$Array.forEach(boolAttributes, function(attributeName) {
  $Array.push(publicAttributes, attributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
    __proto__: null,
    get: function() {
      return GetBoolAttribute(this.treeID, this.id, attributeName);
    }
  });
});

$Array.forEach(intAttributes, function(attributeName) {
  $Array.push(publicAttributes, attributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
    __proto__: null,
    get: function() {
      return GetIntAttribute(this.treeID, this.id, attributeName);
    }
  });
});

$Array.forEach(nodeRefAttributes, function(params) {
  var srcAttributeName = params[0];
  var dstAttributeName = params[1];
  $Array.push(publicAttributes, dstAttributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, dstAttributeName, {
    __proto__: null,
    get: function() {
      var id = GetIntAttribute(this.treeID, this.id, srcAttributeName);
      if (id && this.rootImpl)
        return this.rootImpl.get(id);
      else
        return undefined;
    }
  });
});

$Array.forEach(intListAttributes, function(attributeName) {
  $Array.push(publicAttributes, attributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
    __proto__: null,
    get: function() {
      return GetIntListAttribute(this.treeID, this.id, attributeName);
    }
  });
});

$Array.forEach(nodeRefListAttributes, function(params) {
  var srcAttributeName = params[0];
  var dstAttributeName = params[1];
  $Array.push(publicAttributes, dstAttributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, dstAttributeName, {
    __proto__: null,
    get: function() {
      var ids = GetIntListAttribute(this.treeID, this.id, srcAttributeName);
      if (!ids || !this.rootImpl)
        return undefined;
      var result = [];
      for (var i = 0; i < ids.length; ++i) {
        var node = this.rootImpl.get(ids[i]);
        if (node)
          $Array.push(result, node);
      }
      return result;
    }
  });
});

$Array.forEach(floatAttributes, function(attributeName) {
  $Array.push(publicAttributes, attributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, attributeName, {
    __proto__: null,
    get: function() {
      return GetFloatAttribute(this.treeID, this.id, attributeName);
    }
  });
});

$Array.forEach(htmlAttributes, function(params) {
  var srcAttributeName = params[0];
  var dstAttributeName = params[1];
  $Array.push(publicAttributes, dstAttributeName);
  $Object.defineProperty(AutomationNodeImpl.prototype, dstAttributeName, {
    __proto__: null,
    get: function() {
      return GetHtmlAttribute(this.treeID, this.id, srcAttributeName);
    }
  });
});

/**
 * AutomationRootNode.
 *
 * An AutomationRootNode is the javascript end of an AXTree living in the
 * browser. AutomationRootNode handles unserializing incremental updates from
 * the source AXTree. Each update contains node data that form a complete tree
 * after applying the update.
 *
 * A brief note about ids used through this class. The source AXTree assigns
 * unique ids per node and we use these ids to build a hash to the actual
 * AutomationNode object.
 * Thus, tree traversals amount to a lookup in our hash.
 *
 * The tree itself is identified by the accessibility tree id of the
 * renderer widget host.
 * @constructor
 */
function AutomationRootNodeImpl(treeID) {
  $Function.call(AutomationNodeImpl, this, this);
  this.treeID = treeID;
  this.axNodeDataCache_ = {__proto__: null};
  this.actionRequestIDToCallback_ = {__proto__: null};
}

utils.defineProperty(AutomationRootNodeImpl, 'idToAutomationRootNode_',
    {__proto__: null});

utils.defineProperty(AutomationRootNodeImpl, 'get', function(treeID) {
  var result = AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
  return result || undefined;
});

utils.defineProperty(AutomationRootNodeImpl, 'getOrCreate', function(treeID) {
  if (AutomationRootNodeImpl.idToAutomationRootNode_[treeID])
    return AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
  var result = new AutomationRootNode(treeID);
  AutomationRootNodeImpl.idToAutomationRootNode_[treeID] = result;
  return result;
});

utils.defineProperty(AutomationRootNodeImpl, 'destroy', function(treeID) {
  delete AutomationRootNodeImpl.idToAutomationRootNode_[treeID];
});

AutomationRootNodeImpl.prototype = {
  __proto__: AutomationNodeImpl.prototype,

  /**
   * @type {boolean}
   */
  isRootNode: true,

  /**
   * @type {number}
   */
  treeID: -1,

  /**
   * The parent of this node from a different tree.
   * @type {?AutomationNode}
   * @private
   */
  hostNode_: null,

  /**
   * A map from id to AutomationNode.
   * @type {Object.<number, AutomationNode>}
   * @private
   */
  axNodeDataCache_: null,

  actionRequestCounter_: 0,

  actionRequestIDToCallback_: null,

  get id() {
    var result = GetRootID(this.treeID);

    // Don't return undefined, because the id is often passed directly
    // as an argument to a native binding that expects only a valid number.
    if (result === undefined)
      return -1;

    return result;
  },

  get chromeChannel() {
    return GetStringAttribute(this.treeID, this.id, 'chromeChannel');
  },

  get docUrl() {
    return GetDocURL(this.treeID);
  },

  get docTitle() {
    return GetDocTitle(this.treeID);
  },

  get docLoaded() {
    return GetDocLoaded(this.treeID);
  },

  get docLoadingProgress() {
    return GetDocLoadingProgress(this.treeID);
  },

  get anchorObject() {
    var id = GetAnchorObjectID(this.treeID);
    if (id && id != -1)
      return this.get(id);
    else
      return undefined;
  },

  get anchorOffset() {
    var id = GetAnchorObjectID(this.treeID);
    if (id && id != -1)
      return GetAnchorOffset(this.treeID);
  },

  get anchorAffinity() {
    var id = GetAnchorObjectID(this.treeID);
    if (id && id != -1)
      return GetAnchorAffinity(this.treeID);
  },

  get focusObject() {
    var id = GetFocusObjectID(this.treeID);
    if (id && id != -1)
      return this.get(id);
    else
      return undefined;
  },

  get focusOffset() {
    var id = GetFocusObjectID(this.treeID);
    if (id && id != -1)
      return GetFocusOffset(this.treeID);
  },

  get focusAffinity() {
    var id = GetFocusObjectID(this.treeID);
    if (id && id != -1)
      return GetFocusAffinity(this.treeID);
  },

  get: function(id) {
    if (id == undefined)
      return undefined;

    if (id == this.id)
      return this.wrapper;

    var obj = this.axNodeDataCache_[id];
    if (obj)
      return obj;

    obj = new AutomationNode(this);
    privates(obj).impl.treeID = this.treeID;
    privates(obj).impl.id = id;
    this.axNodeDataCache_[id] = obj;

    return obj;
  },

  remove: function(id) {
    if (this.axNodeDataCache_[id])
      privates(this.axNodeDataCache_[id]).impl.detach();
    delete this.axNodeDataCache_[id];
  },

  destroy: function() {
    this.dispatchEvent('destroyed', 'none');
    for (var id in this.axNodeDataCache_)
      this.remove(id);
    this.detach();
  },

  setHostNode(hostNode) {
    this.hostNode_ = hostNode;
  },

  onAccessibilityEvent: function(eventParams) {
    var targetNode = this.get(eventParams.targetID);
    if (targetNode) {
      var targetNodeImpl = privates(targetNode).impl;
      targetNodeImpl.dispatchEvent(
          eventParams.eventType, eventParams.eventFrom,
          eventParams.mouseX, eventParams.mouseY);

      if (eventParams.actionRequestID != -1) {
        this.onActionResult(eventParams.actionRequestID, targetNode);
      }
    } else {
      logging.WARNING('Got ' + eventParams.eventType +
                      ' event on unknown node: ' + eventParams.targetID +
                      '; this: ' + this.id);
    }
    return true;
  },

  addActionResultCallback: function(callback) {
    this.actionRequestIDToCallback_[++this.actionRequestCounter_] = callback;
    return this.actionRequestCounter_;
  },

  onActionResult: function(requestID, result) {
    if (requestID in this.actionRequestIDToCallback_) {
      this.actionRequestIDToCallback_[requestID](result);
      delete this.actionRequestIDToCallback_[requestID];
    }
  },

  toString: function() {
    function toStringInternal(nodeImpl, indent) {
      if (!nodeImpl)
        return '';
      var output = '';
      if (nodeImpl.isRootNode)
        output += indent + 'tree id=' + nodeImpl.treeID + '\n';
      output += indent +
        $Function.call(AutomationNodeImpl.prototype.toString, nodeImpl) + '\n';
      indent += '  ';
      var children = nodeImpl.children;
      for (var i = 0; i < children.length; ++i)
        output += toStringInternal(privates(children[i]).impl, indent);
      return output;
    }
    return toStringInternal(this, '');
  },
};

function AutomationNode() {
  privates(AutomationNode).constructPrivate(this, arguments);
}
utils.expose(AutomationNode, AutomationNodeImpl, {
  functions: [
    'doDefault',
    'find',
    'findAll',
    'focus',
    'getImageData',
    'hitTest',
    'hitTestWithReply',
    'makeVisible',
    'matches',
    'performCustomAction',
    'resumeMedia',
    'scrollBackward',
    'scrollForward',
    'scrollUp',
    'scrollDown',
    'scrollLeft',
    'scrollRight',
    'setSelection',
    'setSequentialFocusNavigationStartingPoint',
    'showContextMenu',
    'startDuckingMedia',
    'stopDuckingMedia',
    'suspendMedia',
    'addEventListener',
    'removeEventListener',
    'domQuerySelector',
    'toString',
    'boundsForRange',
  ],
  readonly: $Array.concat(publicAttributes, [
      'parent',
      'firstChild',
      'lastChild',
      'children',
      'previousSibling',
      'nextSibling',
      'isRootNode',
      'role',
      'checked',
      'restriction',
      'state',
      'location',
      'indexInParent',
      'lineStartOffsets',
      'root',
      'htmlAttributes',
      'nameFrom',
      'bold',
      'italic',
      'underline',
      'lineThrough',
      'customActions',
      'unclippedLocation',
  ]),
});

function AutomationRootNode() {
  privates(AutomationRootNode).constructPrivate(this, arguments);
}
utils.expose(AutomationRootNode, AutomationRootNodeImpl, {
  superclass: AutomationNode,
  readonly: [
    'chromeChannel',
    'docTitle',
    'docUrl',
    'docLoaded',
    'docLoadingProgress',
    'anchorObject',
    'anchorOffset',
    'anchorAffinity',
    'focusObject',
    'focusOffset',
    'focusAffinity',
  ],
});

utils.defineProperty(AutomationRootNode, 'get', function(treeID) {
  return AutomationRootNodeImpl.get(treeID);
});

utils.defineProperty(AutomationRootNode, 'getOrCreate', function(treeID) {
  return AutomationRootNodeImpl.getOrCreate(treeID);
});

utils.defineProperty(AutomationRootNode, 'destroy', function(treeID) {
  AutomationRootNodeImpl.destroy(treeID);
});

exports.$set('AutomationNode', AutomationNode);
exports.$set('AutomationRootNode', AutomationRootNode);
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the browserAction API.

var binding = apiBridge || require('binding').Binding.create('browserAction');

var setIcon = require('setIcon').setIcon;
var getExtensionViews = requireNative('runtime').GetExtensionViews;
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;

var jsLastError = bindingUtil ? undefined : require('lastError');
function hasLastError() {
  return bindingUtil ?
      bindingUtil.hasLastError() : jsLastError.hasError(chrome);
}

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setHandleRequest('setIcon', function(details, callback) {
    setIcon(details, function(args) {
      sendRequest('browserAction.setIcon',
                  [args, callback],
                  apiBridge ? undefined : this.definition.parameters,
                  undefined);
    }.bind(this));
  });

  apiFunctions.setCustomCallback('openPopup',
      function(name, request, callback, response) {
    if (!callback)
      return;

    if (hasLastError()) {
      callback();
    } else {
      var views = getExtensionViews(-1, -1, 'POPUP');
      callback(views.length > 0 ? views[0] : null);
    }
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Cast Streaming RtpStream API.

var binding = apiBridge ||
              require('binding').Binding.create('cast.streaming.rtpStream');
var natives = requireNative('cast_streaming_natives');

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setHandleRequest('destroy',
      function(transportId) {
        natives.DestroyCastRtpStream(transportId);
  });
  apiFunctions.setHandleRequest('getSupportedParams',
      function(transportId) {
        return natives.GetSupportedParamsCastRtpStream(transportId);
  });
  apiFunctions.setHandleRequest('start',
      function(transportId, params) {
        natives.StartCastRtpStream(transportId, params);
  });
  apiFunctions.setHandleRequest('stop',
      function(transportId) {
        natives.StopCastRtpStream(transportId);
  });
  apiFunctions.setHandleRequest('toggleLogging',
      function(transportId, enable) {
        natives.ToggleLogging(transportId, enable);
  });
  apiFunctions.setHandleRequest('getRawEvents',
      function(transportId, extraData, callback) {
        natives.GetRawEvents(transportId, extraData, callback);
  });
  apiFunctions.setHandleRequest('getStats',
      function(transportId, callback) {
        natives.GetStats(transportId, callback);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Cast Streaming Session API.

var binding = apiBridge ||
              require('binding').Binding.create('cast.streaming.session');
var natives = requireNative('cast_streaming_natives');

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;
  apiFunctions.setHandleRequest('create',
      function(audioTrack, videoTrack, callback) {
        natives.CreateSession(audioTrack, videoTrack, callback);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Cast Streaming UdpTransport API.

var binding = apiBridge ||
              require('binding').Binding.create('cast.streaming.udpTransport');
var natives = requireNative('cast_streaming_natives');

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setHandleRequest('destroy', function(transportId) {
    natives.DestroyCastUdpTransport(transportId);
  });
  apiFunctions.setHandleRequest('setDestination',
    function(transportId, destination) {
      natives.SetDestinationCastUdpTransport(transportId, destination);
  });
  apiFunctions.setHandleRequest('setOptions',
    function(transportId, options) {
      natives.SetOptionsCastUdpTransport(transportId, options);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Cast Streaming Session API.

var binding =
    apiBridge ||
    require('binding').Binding.create('cast.streaming.receiverSession');
var natives = requireNative('cast_streaming_natives');

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;
  apiFunctions.setHandleRequest(
      'createAndBind',
      function(ap, vp, local, weidgth, height, fr, url, cb, op) {
        natives.StartCastRtpReceiver(
            ap, vp, local, weidgth, height, fr, url, cb, op);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var Event = require('event_bindings').Event;
var sendRequest = require('sendRequest').sendRequest;
var validate = require('schemaUtils').validate;

function extendSchema(schema) {
  var extendedSchema = $Array.slice(schema);
  $Array.unshift(extendedSchema, {'type': 'string'});
  return extendedSchema;
}

// TODO(devlin): Maybe find a way to combine this and ContentSetting.
function ChromeSetting(prefKey, valueSchema, schema) {
  var getFunctionParameters = function(name) {
    var f = $Array.filter(
                schema.functions, function(f) { return f.name === name; })[0];
    return f.parameters;
  };
  this.get = function(details, callback) {
    var getSchema = getFunctionParameters('get');
    validate([details, callback], getSchema);
    return sendRequest('types.ChromeSetting.get',
                       [prefKey, details, callback],
                       extendSchema(getSchema));
  };
  this.set = function(details, callback) {
    // The set schema included in the Schema object is generic, since it varies
    // per-setting. However, this is only ever for a single setting, so we can
    // enforce the types more thoroughly.
    var rawSetSchema = getFunctionParameters('set');
    var rawSettingParam = rawSetSchema[0];
    var props = $Object.assign({}, rawSettingParam.properties);
    props.value = valueSchema;
    var modSettingParam = {
      name: rawSettingParam.name,
      type: rawSettingParam.type,
      properties: props,
    };
    var modSetSchema = $Array.slice(rawSetSchema);
    modSetSchema[0] = modSettingParam;
    validate([details, callback], modSetSchema);
    return sendRequest('types.ChromeSetting.set',
                       [prefKey, details, callback],
                       extendSchema(modSetSchema));
  };
  this.clear = function(details, callback) {
    var clearSchema = getFunctionParameters('clear');
    validate([details, callback], clearSchema);
    return sendRequest('types.ChromeSetting.clear',
                       [prefKey, details, callback],
                       extendSchema(clearSchema));
  };
  this.onChange = new Event('types.ChromeSetting.' + prefKey + '.onChange');
};

exports.$set('ChromeSetting', ChromeSetting);
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var binding = apiBridge ||
              require('binding').Binding.create('chromeWebViewInternal');
var contextMenusHandlers = require('contextMenusHandlers');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  var handlers = contextMenusHandlers.create(true /* isWebview */);

  apiFunctions.setHandleRequest(
      'contextMenusCreate', handlers.requestHandlers.create);

  apiFunctions.setHandleRequest(
      'contextMenusUpdate', handlers.requestHandlers.update);

  apiFunctions.setHandleRequest(
      'contextMenusRemove', handlers.requestHandlers.remove);

  apiFunctions.setHandleRequest(
      'contextMenusRemoveAll', handlers.requestHandlers.removeAll);
});

if (!apiBridge)
  exports.$set('ChromeWebView', binding.generate());
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This module implements chrome-specific <webview> API.
// See web_view_api_methods.js for details.

var ChromeWebView = getInternalApi ?
    getInternalApi('chromeWebViewInternal') :
    require('chromeWebViewInternal').ChromeWebView;
var ChromeWebViewSchema =
    requireNative('schema_registry').GetSchema('chromeWebViewInternal');
var CreateEvent = require('guestViewEvents').CreateEvent;
var GuestViewInternalNatives = requireNative('guest_view_internal');
var idGeneratorNatives = requireNative('id_generator');
var utils = require('utils');
var WebViewImpl = require('webView').WebViewImpl;

// This is the only "webViewInternal.onClicked" named event for this renderer.
//
// Since we need an event per <webview>, we define events with suffix
// (subEventName) in each of the <webview>. Behind the scenes, this event is
// registered as a ContextMenusEvent, with filter set to the webview's
// |viewInstanceId|. Any time a ContextMenusEvent is dispatched, we re-dispatch
// it to the subEvent's listeners. This way
// <webview>.contextMenus.onClicked behave as a regular chrome Event type.
var ContextMenusEvent = CreateEvent('chromeWebViewInternal.onClicked');
// See comment above.
var ContextMenusHandlerEvent =
    CreateEvent('chromeWebViewInternal.onContextMenuShow');

var jsEvent;
function createCustomEvent(name, schema, options, webviewId) {
  if (bindingUtil)
    return bindingUtil.createCustomEvent(name, undefined, false, false);
  if (!jsEvent)
    jsEvent = require('event_bindings').Event;
  return new jsEvent(name, schema, options, webviewId);
}

// This event is exposed as <webview>.contextMenus.onClicked.
function createContextMenusOnClickedEvent(webViewInstanceId,
                                          opt_eventName,
                                          opt_argSchemas,
                                          opt_eventOptions) {
  var subEventName = GetUniqueSubEventName(opt_eventName);
  var newEvent = createCustomEvent(subEventName, opt_argSchemas,
                                   opt_eventOptions, webViewInstanceId);

  var view = GuestViewInternalNatives.GetViewFromID(webViewInstanceId);
  if (view) {
    view.events.addScopedListener(
        ContextMenusEvent,
        $Function.bind(function() {
          // Re-dispatch to subEvent's listeners.
          $Function.apply(newEvent.dispatch, newEvent, $Array.slice(arguments));
        }, newEvent),
        {instanceId: webViewInstanceId});
  }
  return newEvent;
}

// This event is exposed as <webview>.contextMenus.onShow.
function createContextMenusOnContextMenuEvent(webViewInstanceId,
                                              opt_eventName,
                                              opt_argSchemas,
                                              opt_eventOptions) {
  var subEventName = GetUniqueSubEventName(opt_eventName);
  var newEvent = createCustomEvent(subEventName, opt_argSchemas,
                                   opt_eventOptions, webViewInstanceId);

  var view = GuestViewInternalNatives.GetViewFromID(webViewInstanceId);
  if (view) {
    view.events.addScopedListener(
        ContextMenusHandlerEvent,
        $Function.bind(function(e) {
          var defaultPrevented = false;
          var event = {
            preventDefault: function() { defaultPrevented = true; }
          };

          // Re-dispatch to subEvent's listeners.
          $Function.apply(newEvent.dispatch, newEvent, [event]);

          if (!defaultPrevented) {
          // TODO(lazyboy): Remove |items| parameter completely from
          // ChromeWebView.showContextMenu as we don't do anything useful with
          // it currently.
          var items = [];
          var guestInstanceId = GuestViewInternalNatives.
              GetViewFromID(webViewInstanceId).guest.getId();
          ChromeWebView.showContextMenu(guestInstanceId, e.requestId, items);
        }
      }, newEvent),
      {instanceId: webViewInstanceId});
  }

  return newEvent;
}

// -----------------------------------------------------------------------------
// WebViewContextMenusImpl object.

// An instance of this class is exposed as <webview>.contextMenus.
function WebViewContextMenusImpl(viewInstanceId) {
  this.viewInstanceId_ = viewInstanceId;
}
$Object.setPrototypeOf(WebViewContextMenusImpl.prototype, null);

WebViewContextMenusImpl.prototype.create = function() {
  var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
  return $Function.apply(ChromeWebView.contextMenusCreate, null, args);
};

WebViewContextMenusImpl.prototype.remove = function() {
  var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
  return $Function.apply(ChromeWebView.contextMenusRemove, null, args);
};

WebViewContextMenusImpl.prototype.removeAll = function() {
  var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
  return $Function.apply(ChromeWebView.contextMenusRemoveAll, null, args);
};

WebViewContextMenusImpl.prototype.update = function() {
  var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
  return $Function.apply(ChromeWebView.contextMenusUpdate, null, args);
};

function WebViewContextMenus() {
  privates(WebViewContextMenus).constructPrivate(this, arguments);
}
utils.expose(WebViewContextMenus, WebViewContextMenusImpl, {
  functions: [
    'create',
    'remove',
    'removeAll',
    'update',
  ],
});

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

WebViewImpl.prototype.maybeSetupContextMenus = function() {
  if (!this.contextMenusOnContextMenuEvent_) {
    var eventName = 'chromeWebViewInternal.onContextMenuShow';
    var eventSchema =
        utils.lookup(ChromeWebViewSchema.events, 'name', 'onShow');
    var eventOptions = {supportsListeners: true, supportsLazyListeners: false};
    this.contextMenusOnContextMenuEvent_ = createContextMenusOnContextMenuEvent(
        this.viewInstanceId, eventName, eventSchema, eventOptions);
  }

  var createContextMenus = $Function.bind(function() {
    return this.weakWrapper(function() {
      if (this.contextMenus_) {
        return this.contextMenus_;
      }

      this.contextMenus_ = new WebViewContextMenus(this.viewInstanceId);

      // Define 'onClicked' event property on |this.contextMenus_|.
      var getOnClickedEvent = $Function.bind(function() {
        return this.weakWrapper(function() {
          if (!this.contextMenusOnClickedEvent_) {
            var eventName = 'chromeWebViewInternal.onClicked';
            var eventSchema =
                utils.lookup(ChromeWebViewSchema.events, 'name', 'onClicked');
            var eventOptions =
                {supportsListeners: true, supportsLazyListeners: false};
            var onClickedEvent = createContextMenusOnClickedEvent(
                this.viewInstanceId, eventName, eventSchema, eventOptions);
            this.contextMenusOnClickedEvent_ = onClickedEvent;
            return onClickedEvent;
          }
          return this.contextMenusOnClickedEvent_;
        });
      }, this);
      $Object.defineProperty(
          this.contextMenus_,
          'onClicked',
          {get: getOnClickedEvent(), enumerable: true});
      $Object.defineProperty(
          this.contextMenus_,
          'onShow',
          {
            get: this.weakWrapper(function() {
              return this.contextMenusOnContextMenuEvent_;
            }),
            enumerable: true
          });
      return this.contextMenus_;
    });
  }, this);

  // Expose <webview>.contextMenus object.
  $Object.defineProperty(
      this.element,
      'contextMenus',
      {
        get: createContextMenus(),
        enumerable: true
      });
};

function GetUniqueSubEventName(eventName) {
  return eventName + '/' + idGeneratorNatives.GetNextId();
}
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the contentSettings API.

var sendRequest = require('sendRequest').sendRequest;
var validate = require('schemaUtils').validate;

// Some content types have been removed and no longer correspond to a real
// content setting. Instead, these always return a fixed dummy value, and issue
// a warning when accessed. This maps the content type name to the dummy value.
var DEPRECATED_CONTENT_TYPES = {
  __proto__: null,

  fullscreen: 'allow',
  mouselock: 'allow',
};

function extendSchema(schema) {
  var extendedSchema = $Array.slice(schema);
  $Array.unshift(extendedSchema, {'type': 'string'});
  return extendedSchema;
}

function ContentSetting(contentType, settingSchema, schema) {
  var getFunctionParameters = function(name) {
    var f = $Array.filter(
                schema.functions, function(f) { return f.name === name; })[0];
    return f.parameters;
  };
  this.get = function(details, callback) {
    var getSchema = getFunctionParameters('get');
    validate([details, callback], getSchema);

    var dummySetting = DEPRECATED_CONTENT_TYPES[contentType];
    if (dummySetting !== undefined) {
      console.warn('contentSettings.' + contentType + ' is deprecated; it will '
                   + 'always return \'' + dummySetting + '\'.');
      $Function.apply(callback, undefined, [{setting: dummySetting}]);
      return;
    }

    return sendRequest('contentSettings.get',
                       [contentType, details, callback],
                       extendSchema(getSchema));
  };

  this.set = function(details, callback) {
    // We check if the setting is deprecated first, since the validation will
    // fail for deprecated types.
    if ($Object.hasOwnProperty(DEPRECATED_CONTENT_TYPES, contentType)) {
      console.warn('contentSettings.' + contentType + ' is deprecated; setting '
                   + 'it has no effect.');
      $Function.apply(callback, undefined, []);
      return;
    }

    // The set schema included in the Schema object is generic, since it varies
    // per-setting. However, this is only ever for a single setting, so we can
    // enforce the types more thoroughly.
    var rawSetSchema = getFunctionParameters('set');
    var rawSettingParam = rawSetSchema[0];
    var props = $Object.assign({}, rawSettingParam.properties);
    props.setting = settingSchema;
    var modSettingParam = {
      name: rawSettingParam.name,
      type: rawSettingParam.type,
      properties: props,
    };
    var modSetSchema = $Array.slice(rawSetSchema);
    modSetSchema[0] = modSettingParam;
    validate([details, callback], modSetSchema);

    return sendRequest('contentSettings.set',
                       [contentType, details, callback],
                       extendSchema(modSetSchema));
  };

  this.clear = function(details, callback) {
    var clearSchema = getFunctionParameters('clear');
    validate([details, callback], clearSchema);

    if ($Object.hasOwnProperty(DEPRECATED_CONTENT_TYPES, contentType)) {
      console.warn('contentSettings.' + contentType + ' is deprecated; '
                   + 'clearing it has no effect.');
      $Function.apply(callback, undefined, []);
      return;
    }

    return sendRequest('contentSettings.clear',
                       [contentType, details, callback],
                       extendSchema(clearSchema));
  };

  this.getResourceIdentifiers = function(callback) {
    var schema = getFunctionParameters('getResourceIdentifiers');
    validate([callback], schema);

    if ($Object.hasOwnProperty(DEPRECATED_CONTENT_TYPES, contentType)) {
      $Function.apply(callback, undefined, []);
      return;
    }

    return sendRequest(
        'contentSettings.getResourceIdentifiers',
        [contentType, callback],
        extendSchema(schema));
  };
}

exports.$set('ContentSetting', ContentSetting);
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the declarativeContent API.

var binding =
    apiBridge || require('binding').Binding.create('declarativeContent');

if (!apiBridge) {
  var utils = require('utils');
  var validate = require('schemaUtils').validate;
  var canonicalizeCompoundSelector =
      requireNative('css_natives').CanonicalizeCompoundSelector;
}

var setIcon = require('setIcon').setIcon;

binding.registerCustomHook(function(api) {
  var declarativeContent = api.compiledApi;

  if (apiBridge) {
    // Validation for most types is done in the native C++ with native bindings,
    // but setIcon is funny (and sadly broken). Ideally, we can move this
    // validation entirely into the native code, and this whole file can go
    // away.
    var nativeSetIcon = declarativeContent.SetIcon;
    declarativeContent.SetIcon = function(parameters) {
      // TODO(devlin): This is very, very wrong. setIcon() is potentially
      // asynchronous (in the case of a path being specified), which means this
      // becomes an "asynchronous constructor". Errors can be thrown *after* the
      // `new declarativeContent.SetIcon(...)` call, and in the async cases,
      // this wouldn't work when we immediately add the action via an API call
      // (e.g.,
      //   chrome.declarativeContent.onPageChange.addRules(
      //       [{conditions: ..., actions: [ new SetIcon(...) ]}]);
      // ). Some of this is tracked in http://crbug.com/415315.
      setIcon(parameters, $Function.bind(function(data) {
        // Fake calling the original function as a constructor.
        $Object.setPrototypeOf(this, nativeSetIcon.prototype);
        $Function.apply(nativeSetIcon, this, [data]);
      }, this));
    };
    return;
  }

  // Returns the schema definition of type |typeId| defined in |namespace|.
  function getSchema(typeId) {
    return utils.lookup(api.schema.types,
                        'id',
                        'declarativeContent.' + typeId);
  }

  // Helper function for the constructor of concrete datatypes of the
  // declarative content API.
  // Makes sure that |this| contains the union of parameters and
  // {'instanceType': 'declarativeContent.' + typeId} and validates the
  // generated union dictionary against the schema for |typeId|.
  function setupInstance(instance, parameters, typeId) {
    for (var key in parameters) {
      if ($Object.hasOwnProperty(parameters, key)) {
        instance[key] = parameters[key];
      }
    }
    instance.instanceType = 'declarativeContent.' + typeId;
    var schema = getSchema(typeId);
    validate([instance], [schema]);
  }

  function canonicalizeCssSelectors(selectors) {
    for (var i = 0; i < selectors.length; i++) {
      var canonicalizedSelector = canonicalizeCompoundSelector(selectors[i]);
      if (canonicalizedSelector == '') {
        throw new Error(
            'Element of \'css\' array must be a ' +
            'list of valid compound selectors: ' +
            selectors[i]);
      }
      selectors[i] = canonicalizedSelector;
    }
  }

  // Setup all data types for the declarative content API.
  declarativeContent.PageStateMatcher = function(parameters) {
    setupInstance(this, parameters, 'PageStateMatcher');
    if ($Object.hasOwnProperty(this, 'css')) {
      canonicalizeCssSelectors(this.css);
    }
  };
  declarativeContent.ShowPageAction = function(parameters) {
    setupInstance(this, parameters, 'ShowPageAction');
  };
  declarativeContent.RequestContentScript = function(parameters) {
    setupInstance(this, parameters, 'RequestContentScript');
  };
  // TODO(rockot): Do not expose this in M39 stable. Making this restriction
  // possible will take some extra work. See http://crbug.com/415315
  // Note: See also the SetIcon wrapper above for more issues.
  declarativeContent.SetIcon = function(parameters) {
    setIcon(parameters, $Function.bind(function(data) {
      setupInstance(this, data, 'SetIcon');
    }, this));
  };
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the desktopCapture API.

var binding = apiBridge || require('binding').Binding.create('desktopCapture');
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;
var idGenerator = requireNative('id_generator');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  var pendingRequests = {};

  function onRequestResult(id, result, options) {
    if (id in pendingRequests) {
      var callback = pendingRequests[id];
      delete pendingRequests[id];
      callback(result, options);
    }
  }

  apiFunctions.setHandleRequest('chooseDesktopMedia',
                                function(sources, target_tab, callback) {
    // |target_tab| is an optional parameter.
    if (callback === undefined) {
      callback = target_tab;
      target_tab = undefined;
    }
    var id = idGenerator.GetNextId();
    pendingRequests[id] = callback;
    sendRequest('desktopCapture.chooseDesktopMedia',
                [id, sources, target_tab,
                 $Function.bind(onRequestResult, null, id)],
                apiBridge ? undefined : this.definition.parameters,
                undefined);
    return id;
  });

  apiFunctions.setHandleRequest('cancelChooseDesktopMedia', function(id) {
    if (id in pendingRequests) {
      delete pendingRequests[id];
      sendRequest('desktopCapture.cancelChooseDesktopMedia',
                  [id], apiBridge ? undefined : this.definition.parameters,
                  undefined);
    }
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the developerPrivate API.

var binding =
    apiBridge || require('binding').Binding.create('developerPrivate');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  // Converts the argument of |functionName| from DirectoryEntry to URL.
  function bindFileSystemFunction(functionName) {
    apiFunctions.setUpdateArgumentsPostValidate(
        functionName, function(directoryEntry, callback) {
          var fileSystemName = directoryEntry.filesystem.name;
          var relativePath = $String.slice(directoryEntry.fullPath, 1);
          var url = directoryEntry.toURL();
          return [fileSystemName, relativePath, url, callback];
    });
  }

  bindFileSystemFunction('loadDirectory');

  // developerPrivate.enable is the same as chrome.management.setEnabled.
  // TODO(devlin): Migrate callers off developerPrivate.enable.
  bindingsAPI.compiledApi.enable = chrome.management.setEnabled;

  apiFunctions.setHandleRequest('allowFileAccess',
                                function(id, allow, callback) {
    chrome.developerPrivate.updateExtensionConfiguration(
        {extensionId: id, fileAccess: allow}, callback);
  });

  apiFunctions.setHandleRequest('allowIncognito',
                                function(id, allow, callback) {
    chrome.developerPrivate.updateExtensionConfiguration(
        {extensionId: id, incognitoAccess: allow}, callback);
  });

  apiFunctions.setHandleRequest('inspect', function(options, callback) {
    var renderViewId = options.render_view_id;
    if (typeof renderViewId == 'string') {
      renderViewId = parseInt(renderViewId);
      if (isNaN(renderViewId))
        throw new Error('Invalid value for render_view_id');
    }
    var renderProcessId = options.render_process_id;
    if (typeof renderProcessId == 'string') {
      renderProcessId = parseInt(renderProcessId);
      if (isNaN(renderProcessId))
        throw new Error('Invalid value for render_process_id');
    }
    chrome.developerPrivate.openDevTools({
        extensionId: options.extension_id,
        renderProcessId: renderProcessId,
        renderViewId: renderViewId,
        incognito: options.incognito
    }, callback);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom bindings for the downloads API.

var binding = apiBridge || require('binding').Binding.create('downloads');
var downloadsInternal =
    getInternalApi ?
        getInternalApi('downloadsInternal') :
        require('binding').Binding.create('downloadsInternal').generate();
var registerArgumentMassager = bindingUtil ?
    $Function.bind(bindingUtil.registerEventArgumentMassager, bindingUtil) :
    require('event_bindings').registerArgumentMassager;

registerArgumentMassager('downloads.onDeterminingFilename',
                         function(args, dispatch) {
  var downloadItem = args[0];
  // Copy the id so that extensions can't change it.
  var downloadId = downloadItem.id;
  var suggestable = true;
  function isValidResult(result) {
    if (result === undefined)
      return false;
    if (typeof(result) != 'object') {
      console.error('Error: Invocation of form suggest(' + typeof(result) +
                    ') doesn\'t match definition suggest({filename: string, ' +
                    'conflictAction: string})');
      return false;
    } else if ((typeof(result.filename) != 'string') ||
               (result.filename.length == 0)) {
      console.error('Error: "filename" parameter to suggest() must be a ' +
                    'non-empty string');
      return false;
    } else if ([undefined, 'uniquify', 'overwrite', 'prompt'].indexOf(
                 result.conflictAction) < 0) {
      console.error('Error: "conflictAction" parameter to suggest() must be ' +
                    'one of undefined, "uniquify", "overwrite", "prompt"');
      return false;
    }
    return true;
  }
  function suggestCallback(result) {
    if (!suggestable) {
      console.error('suggestCallback may not be called more than once.');
      return;
    }
    suggestable = false;
    if (isValidResult(result)) {
      downloadsInternal.determineFilename(
          downloadId, result.filename, result.conflictAction || "");
    } else {
      downloadsInternal.determineFilename(downloadId, "", "");
    }
  }
  try {
    var results = dispatch([downloadItem, suggestCallback]);
    var async = (results &&
                 results.results &&
                 (results.results.length != 0) &&
                 (results.results[0] === true));
    if (suggestable && !async)
      suggestCallback();
  } catch (e) {
    suggestCallback();
    throw e;
  }
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var Event = require('event_bindings').Event;

// The EasyUnlockProximityRequired object is just a stub that has an onChange
// event, which is never triggered.
// TODO(devlin): Remove this once the preferencesPrivate API is fully removed.
// https://crbug.com/593166
function EasyUnlockProximityRequired(prefKey, valueSchema, schema) {
  // Note: technically, extensions could intercept this through a setter on
  // Object.prototype(). We don't really care, because a) this is only for a
  // private API, so we shouldn't have to worry about untrusted code, and b)
  // this is an anonymous event, which exposes no attack surface and will be
  // exposed to the extension anyway.
  this.onChange = new Event();
};

exports.$set('EasyUnlockProximityRequired', EasyUnlockProximityRequired);
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom bindings for the feedbackPrivate API.

var binding = apiBridge || require('binding').Binding.create('feedbackPrivate');

var blobNatives = requireNative('blob_natives');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;
  apiFunctions.setUpdateArgumentsPostValidate(
      "sendFeedback", function(feedbackInfo, callback) {
    var attachedFileBlobUuid = '';
    var screenshotBlobUuid = '';

    if (feedbackInfo.attachedFile)
      attachedFileBlobUuid =
          blobNatives.GetBlobUuid(feedbackInfo.attachedFile.data);
    if (feedbackInfo.screenshot)
      screenshotBlobUuid =
          blobNatives.GetBlobUuid(feedbackInfo.screenshot);

    feedbackInfo.attachedFileBlobUuid = attachedFileBlobUuid;
    feedbackInfo.screenshotBlobUuid = screenshotBlobUuid;

    return [feedbackInfo, callback];
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the GCM API.

var binding = apiBridge || require('binding').Binding.create('gcm');
var forEach = require('utils').forEach;

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;
  var gcm = bindingsAPI.compiledApi;

  apiFunctions.setUpdateArgumentsPostValidate(
    'send', function(message, callback) {
      // Validate message.data.
      var payloadSize = 0;
      forEach(message.data, function(property, value) {
        if (property.length == 0)
          throw new Error("One of data keys is empty.");

        var lowerCasedProperty = property.toLowerCase();
        // Issue an error for forbidden prefixes of property names.
        if (lowerCasedProperty.startsWith("goog.") ||
            lowerCasedProperty.startsWith("google") ||
            property.startsWith("collapse_key")) {
          throw new Error("Invalid data key: " + property);
        }

        payloadSize += property.length + value.length;
      });

      if (payloadSize > gcm.MAX_MESSAGE_SIZE)
        throw new Error("Payload exceeded allowed size limit. Payload size is: "
            + payloadSize);

      if (payloadSize == 0)
        throw new Error("No data to send.");

      return arguments;
    });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Identity API.

var binding = apiBridge || require('binding').Binding.create('identity');

binding.registerCustomHook(function(binding, id, contextType) {
  var apiFunctions = binding.apiFunctions;

  apiFunctions.setHandleRequest('getRedirectURL', function(path) {
    if (path === null || path === undefined)
      path = '/';
    else
      path = String(path);
    if (path[0] != '/')
      path = '/' + path;
    return 'https://' + id + '.chromiumapp.org' + path;
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the image writer private API.

var binding =
    apiBridge || require('binding').Binding.create('imageWriterPrivate');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setUpdateArgumentsPostValidate(
      'writeFromFile', function(device, fileEntry, options, callback) {
    var fileSystemName = fileEntry.filesystem.name;
    var relativePath = $String.slice(fileEntry.fullPath, 1);
    return [device, fileSystemName, relativePath, callback];
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the input ime API. Only injected into the
// v8 contexts for extensions which have permission for the API.

var binding = apiBridge || require('binding').Binding.create('input.ime');
var appWindowNatives = requireNative('app_window_natives');
var registerArgumentMassager = bindingUtil ?
    $Function.bind(bindingUtil.registerEventArgumentMassager, bindingUtil) :
    require('event_bindings').registerArgumentMassager;

// TODO(crbug.com/733825): These bindings have some issues.

var inputIme;
registerArgumentMassager('input.ime.onKeyEvent',
                         function(args, dispatch) {
  var keyData = args[1];
  var result = false;
  try {
    // dispatch() is weird - it returns an object {results: array<results>} iff
    // there is at least one result value that !== undefined. Since onKeyEvent
    // has a maximum of one listener, we know that any result we find is the one
    // we're interested in.
    var dispatchResult = dispatch(args);
    if (dispatchResult && dispatchResult.results)
      result = dispatchResult.results[0];
  } catch (e) {
    console.error('Error in event handler for onKeyEvent: ' + e.stack);
  }
  if (!inputIme.onKeyEvent.async)
    inputIme.keyEventHandled(keyData.requestId, result);
});

binding.registerCustomHook(function(api) {
 inputIme = api.compiledApi;

  var originalAddListener = inputIme.onKeyEvent.addListener;
  inputIme.onKeyEvent.addListener = function(cb, opt_extraInfo) {
    inputIme.onKeyEvent.async = false;
    if (opt_extraInfo instanceof Array) {
      for (var i = 0; i < opt_extraInfo.length; ++i) {
        if (opt_extraInfo[i] == 'async') {
          inputIme.onKeyEvent.async = true;
        }
      }
    }
    $Function.call(originalAddListener, this, cb);
  };

  api.apiFunctions.setCustomCallback('createWindow',
      function(name, request, callback, windowParams) {
    if (!callback) {
      return;
    }
    var view;
    if (windowParams && windowParams.frameId) {
      view = appWindowNatives.GetFrame(
          windowParams.frameId, false /* notifyBrowser */);
      view.id = windowParams.frameId;
    }
    callback(view);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Media Gallery API.

var binding = apiBridge || require('binding').Binding.create('mediaGalleries');
var blobNatives = requireNative('blob_natives');
var mediaGalleriesNatives = requireNative('mediaGalleries');
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;

var blobsAwaitingMetadata = {};
var mediaGalleriesMetadata = {};

function createFileSystemObjectsAndUpdateMetadata(response) {
  var result = [];
  mediaGalleriesMetadata = {};  // Clear any previous metadata.
  if (response) {
    for (var i = 0; i < response.length; i++) {
      var filesystem = mediaGalleriesNatives.GetMediaFileSystemObject(
          response[i].fsid);
      $Array.push(result, filesystem);
      var metadata = response[i];
      delete metadata.fsid;
      mediaGalleriesMetadata[filesystem.name] = metadata;
    }
  }
  return result;
}

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;

  // getMediaFileSystems and addUserSelectedFolder use a custom callback so that
  // they can instantiate and return an array of file system objects.
  apiFunctions.setCustomCallback('getMediaFileSystems',
                                 function(name, request, callback, response) {
    var result = createFileSystemObjectsAndUpdateMetadata(response);
    if (callback)
      callback(result);
  });

  apiFunctions.setCustomCallback('addUserSelectedFolder',
      function(name, request, callback, response) {
    var fileSystems = [];
    var selectedFileSystemName = "";
    if (response && 'mediaFileSystems' in response &&
        'selectedFileSystemIndex' in response) {
      fileSystems = createFileSystemObjectsAndUpdateMetadata(
          response['mediaFileSystems']);
      var selectedFileSystemIndex = response['selectedFileSystemIndex'];
      if (selectedFileSystemIndex >= 0) {
        selectedFileSystemName = fileSystems[selectedFileSystemIndex].name;
      }
    }
    if (callback)
      callback(fileSystems, selectedFileSystemName);
  });

  apiFunctions.setHandleRequest('getMediaFileSystemMetadata',
                                function(filesystem) {
    if (filesystem && filesystem.name &&
        filesystem.name in mediaGalleriesMetadata) {
      return mediaGalleriesMetadata[filesystem.name];
    }
    return {
      'name': '',
      'galleryId': '',
      'isRemovable': false,
      'isMediaDevice': false,
      'isAvailable': false,
    };
  });

  function getMetadataCallback(uuid, name, request, callback, response) {
    if (response && response.attachedImagesBlobInfo) {
      for (var i = 0; i < response.attachedImagesBlobInfo.length; i++) {
        var blobInfo = response.attachedImagesBlobInfo[i];
        var blob = blobNatives.TakeBrowserProcessBlob(
            blobInfo.blobUUID, blobInfo.type, blobInfo.size);
        response.metadata.attachedImages.push(blob);
      }
    }

    if (callback)
      callback(response ? response.metadata : null);

    delete blobsAwaitingMetadata[uuid];
  }

  apiFunctions.setHandleRequest('getMetadata',
                                function(mediaFile, options, callback) {
    var blobUuid = blobNatives.GetBlobUuid(mediaFile)
    // Store the blob in a global object to keep its refcount nonzero -- this
    // prevents the object from being garbage collected before any metadata
    // parsing gets to occur (see crbug.com/415792).
    blobsAwaitingMetadata[blobUuid] = mediaFile;

    var optArgs = {
      __proto__: null,
      customCallback: $Function.bind(getMetadataCallback, null, blobUuid),
    };

    sendRequest('mediaGalleries.getMetadata', [blobUuid, options, callback],
                bindingUtil ? undefined : this.definition.parameters, optArgs);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom bindings for the notifications API.
//
var binding = apiBridge || require('binding').Binding.create('notifications');

var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;
var exceptionHandler = require('uncaught_exception_handler');
var imageUtil = require('imageUtil');
var notificationsPrivate = requireNative('notifications_private');

var jsLastError = bindingUtil ? undefined : require('lastError');
function runCallbackWithLastError(name, message, stack, callback, args) {
  if (bindingUtil) {
    bindingUtil.runCallbackWithLastError(message, function() {
      $Function.apply(callback, null, args);
    });
  } else {
    jsLastError.run(name, message, stack, callback, args);
  }
}

function imageDataSetter(context, key) {
  var f = function(val) {
    this[key] = val;
  };
  return $Function.bind(f, context);
}

// A URL Spec is an object with the following keys:
//  path: The resource to be downloaded.
//  width: (optional) The maximum width of the image to be downloaded in device
//         pixels.
//  height: (optional) The maximum height of the image to be downloaded in
//          device pixels.
//  callback: A function to be called when the URL is complete. It
//    should accept an ImageData object and set the appropriate
//    field in |notificationDetails|.
function getUrlSpecs(imageSizes, notificationDetails) {
  var urlSpecs = [];

  // |iconUrl| might be optional for notification updates.
  if (notificationDetails.iconUrl) {
    $Array.push(urlSpecs, {
      path: notificationDetails.iconUrl,
      width: imageSizes.icon.width * imageSizes.scaleFactor,
      height: imageSizes.icon.height * imageSizes.scaleFactor,
      callback: imageDataSetter(notificationDetails, 'iconBitmap')
    });
  }

  // |appIconMaskUrl| is optional.
  if (notificationDetails.appIconMaskUrl) {
    $Array.push(urlSpecs, {
      path: notificationDetails.appIconMaskUrl,
      width: imageSizes.appIconMask.width * imageSizes.scaleFactor,
      height: imageSizes.appIconMask.height * imageSizes.scaleFactor,
      callback: imageDataSetter(notificationDetails, 'appIconMaskBitmap')
    });
  }

  // |imageUrl| is optional.
  if (notificationDetails.imageUrl) {
    $Array.push(urlSpecs, {
      path: notificationDetails.imageUrl,
      width: imageSizes.image.width * imageSizes.scaleFactor,
      height: imageSizes.image.height * imageSizes.scaleFactor,
      callback: imageDataSetter(notificationDetails, 'imageBitmap')
    });
  }

  // Each button has an optional icon.
  var buttonList = notificationDetails.buttons;
  if (buttonList && typeof buttonList.length === 'number') {
    var numButtons = buttonList.length;
    for (var i = 0; i < numButtons; i++) {
      if (buttonList[i].iconUrl) {
        $Array.push(urlSpecs, {
          path: buttonList[i].iconUrl,
          width: imageSizes.buttonIcon.width * imageSizes.scaleFactor,
          height: imageSizes.buttonIcon.height * imageSizes.scaleFactor,
          callback: imageDataSetter(buttonList[i], 'iconBitmap')
        });
      }
    }
  }

  return urlSpecs;
}

function replaceNotificationOptionURLs(notification_details, callback) {
  var imageSizes = notificationsPrivate.GetNotificationImageSizes();
  var url_specs = getUrlSpecs(imageSizes, notification_details);
  if (!url_specs.length) {
    callback(true);
    return;
  }

  var errors = 0;

  imageUtil.loadAllImages(url_specs, {
    onerror: function(index) {
      errors++;
    },
    oncomplete: function(imageData) {
      if (errors > 0) {
        callback(false);
        return;
      }
      for (var index = 0; index < url_specs.length; index++) {
        var url_spec = url_specs[index];
        url_spec.callback(imageData[index]);
      }
      callback(true);
    }
  });
}

function genHandle(name, failure_function) {
  return function(id, input_notification_details, callback) {
    // TODO(dewittj): Remove this hack. This is used as a way to deep
    // copy a complex JSON object.
    var notification_details = $JSON.parse(
        $JSON.stringify(input_notification_details));
    var that = this;
    var stack = exceptionHandler.getExtensionStackTrace();
    replaceNotificationOptionURLs(notification_details, function(success) {
      if (success) {
        sendRequest(
            name, [id, notification_details, callback],
            bindingUtil ? undefined : that.definition.parameters,
            bindingUtil ? undefined : {__proto__: null, stack: stack});
        return;
      }
      runCallbackWithLastError(
          name, 'Unable to download all specified images.',
          stack, failure_function, [callback || function() {}, id]);
    });
  };
}

var handleCreate = genHandle('notifications.create',
                             function(callback, id) { callback(id); });
var handleUpdate = genHandle('notifications.update',
                             function(callback, id) { callback(false); });

var notificationsCustomHook = function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;
  apiFunctions.setHandleRequest('create', handleCreate);
  apiFunctions.setHandleRequest('update', handleUpdate);
};

binding.registerCustomHook(notificationsCustomHook);

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the omnibox API. Only injected into the v8 contexts
// for extensions which have permission for the omnibox API.

var binding = apiBridge || require('binding').Binding.create('omnibox');

var registerArgumentMassager = bindingUtil ?
    $Function.bind(bindingUtil.registerEventArgumentMassager, bindingUtil) :
    require('event_bindings').registerArgumentMassager;

var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;

// Remove invalid characters from |text| so that it is suitable to use
// for |AutocompleteMatch::contents|.
function sanitizeString(text, shouldTrim) {
  // NOTE: This logic mirrors |AutocompleteMatch::SanitizeString()|.
  // 0x2028 = line separator; 0x2029 = paragraph separator.
  var kRemoveChars = /(\r|\n|\t|\u2028|\u2029)/gm;
  if (shouldTrim)
    text = text.trimLeft();
  return text.replace(kRemoveChars, '');
}

// Parses the xml syntax supported by omnibox suggestion results. Returns an
// object with two properties: 'description', which is just the text content,
// and 'descriptionStyles', which is an array of style objects in a format
// understood by the C++ backend.
function parseOmniboxDescription(input) {
  var domParser = new DOMParser();

  // The XML parser requires a single top-level element, but we want to
  // support things like 'hello, <match>world</match>!'. So we wrap the
  // provided text in generated root level element.
  var root = domParser.parseFromString(
      '<fragment>' + input + '</fragment>', 'text/xml');

  // DOMParser has a terrible error reporting facility. Errors come out nested
  // inside the returned document.
  var error = root.querySelector('parsererror div');
  if (error) {
    throw new Error(error.textContent);
  }

  // Otherwise, it's valid, so build up the result.
  var result = {
    description: '',
    descriptionStyles: []
  };

  // Recursively walk the tree.
  function walk(node) {
    for (var i = 0, child; child = node.childNodes[i]; i++) {
      // Append text nodes to our description.
      if (child.nodeType == Node.TEXT_NODE) {
        var shouldTrim = result.description.length == 0;
        result.description += sanitizeString(child.nodeValue, shouldTrim);
        continue;
      }

      // Process and descend into a subset of recognized tags.
      if (child.nodeType == Node.ELEMENT_NODE &&
          (child.nodeName == 'dim' || child.nodeName == 'match' ||
           child.nodeName == 'url')) {
        var style = {
          'type': child.nodeName,
          'offset': result.description.length
        };
        $Array.push(result.descriptionStyles, style);
        walk(child);
        style.length = result.description.length - style.offset;
        continue;
      }

      // Descend into all other nodes, even if they are unrecognized, for
      // forward compat.
      walk(child);
    }
  };
  walk(root);

  return result;
}

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setUpdateArgumentsPreValidate('setDefaultSuggestion',
                                             function(suggestResult) {
    if (suggestResult.content != undefined) {  // null, etc.
      throw new Error(
          'setDefaultSuggestion cannot contain the "content" field');
    }
    return [suggestResult];
  });

  apiFunctions.setHandleRequest('setDefaultSuggestion', function(details) {
    var parseResult = parseOmniboxDescription(details.description);
    sendRequest('omnibox.setDefaultSuggestion', [parseResult],
                bindingUtil ? undefined : this.definition.parameters,
                undefined);
  });

  apiFunctions.setUpdateArgumentsPostValidate(
      'sendSuggestions', function(requestId, userSuggestions) {
    var suggestions = [];
    for (var i = 0; i < userSuggestions.length; i++) {
      var parseResult = parseOmniboxDescription(
          userSuggestions[i].description);
      parseResult.content = userSuggestions[i].content;
      parseResult.deletable = userSuggestions[i].deletable;
      $Array.push(suggestions, parseResult);
    }
    return [requestId, suggestions];
  });
});

registerArgumentMassager('omnibox.onInputChanged', function(args, dispatch) {
  var text = args[0];
  var requestId = args[1];
  var suggestCallback = function(suggestions) {
    chrome.omnibox.sendSuggestions(requestId, suggestions);
  };
  dispatch([text, suggestCallback]);
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the pageAction API.

var binding = apiBridge || require('binding').Binding.create('pageAction');
var setIcon = require('setIcon').setIcon;
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setHandleRequest('setIcon', function(details, callback) {
    setIcon(details, $Function.bind(function(args) {
      sendRequest('pageAction.setIcon', [args, callback],
                  bindingUtil ? undefined : this.definition.parameters,
                  undefined);
    }, this));
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the pageCapture API.

var binding = apiBridge || require('binding').Binding.create('pageCapture');

var handleUncaughtException = require('uncaught_exception_handler').handle;
var pageCaptureNatives = requireNative('page_capture');
var CreateBlob = pageCaptureNatives.CreateBlob;
var SendResponseAck = pageCaptureNatives.SendResponseAck;

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setCustomCallback('saveAsMHTML',
      function(name, request, callback, response) {
    if (response)
      response = CreateBlob(response.mhtmlFilePath, response.mhtmlFileLength);

    try {
      callback(response);
    } catch (e) {
      handleUncaughtException(
          'Error in chrome.pageCapture.saveAsMHTML callback', e, request.stack);
    } finally {
      // Notify the browser. Now that the blob is referenced from JavaScript,
      // the browser can drop its reference to it.
      SendResponseAck(request.id);
    }
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the syncFileSystem API.

var binding =
    apiBridge || require('binding').Binding.create('syncFileSystem');

var registerArgumentMassager = bindingUtil ?
    $Function.bind(bindingUtil.registerEventArgumentMassager, bindingUtil) :
    require('event_bindings').registerArgumentMassager;

var fileSystemNatives = requireNative('file_system_natives');
var syncFileSystemNatives = requireNative('sync_file_system');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  // Functions which take in an [instanceOf=FileEntry].
  function bindFileEntryFunction(functionName) {
    apiFunctions.setUpdateArgumentsPostValidate(
        functionName, function(entry, callback) {
      var fileSystemUrl = entry.toURL();
      return [fileSystemUrl, callback];
    });
  }
  $Array.forEach(['getFileStatus'], bindFileEntryFunction);

  // Functions which take in a FileEntry array.
  function bindFileEntryArrayFunction(functionName) {
    apiFunctions.setUpdateArgumentsPostValidate(
        functionName, function(entries, callback) {
      var fileSystemUrlArray = [];
      for (var i=0; i < entries.length; i++) {
        $Array.push(fileSystemUrlArray, entries[i].toURL());
      }
      return [fileSystemUrlArray, callback];
    });
  }
  $Array.forEach(['getFileStatuses'], bindFileEntryArrayFunction);

  // Functions which take in an [instanceOf=DOMFileSystem].
  function bindFileSystemFunction(functionName) {
    apiFunctions.setUpdateArgumentsPostValidate(
        functionName, function(filesystem, callback) {
      var fileSystemUrl = filesystem.root.toURL();
      return [fileSystemUrl, callback];
    });
  }
  $Array.forEach(['getUsageAndQuota'], bindFileSystemFunction);

  // Functions which return an [instanceOf=DOMFileSystem].
  apiFunctions.setCustomCallback('requestFileSystem',
      function(name, request, callback, response) {
    var result = null;
    if (response) {
      result = syncFileSystemNatives.GetSyncFileSystemObject(
          response.name, response.root);
    }
    if (callback)
      callback(result);
  });

  // Functions which return an array of FileStatusInfo object
  // which has [instanceOf=FileEntry].
  apiFunctions.setCustomCallback('getFileStatuses',
      function(name, request, callback, response) {
    var results = [];
    if (response) {
      for (var i = 0; i < response.length; i++) {
        var result = {};
        var entry = response[i].entry;
        result.fileEntry = fileSystemNatives.GetFileEntry(
            entry.fileSystemType,
            entry.fileSystemName,
            entry.rootUrl,
            entry.filePath,
            entry.isDirectory);
        result.status = response[i].status;
        result.error = response[i].error;
        $Array.push(results, result);
      }
    }
    if (callback)
      callback(results);
  });
});

registerArgumentMassager('syncFileSystem.onFileStatusChanged',
                         function(args, dispatch) {
  // Make FileEntry object using all the base string fields.
  var fileEntry = fileSystemNatives.GetFileEntry(
      args[0].fileSystemType,
      args[0].fileSystemName,
      args[0].rootUrl,
      args[0].filePath,
      args[0].isDirectory);

  // Combine into a single dictionary.
  var fileInfo = new Object();
  fileInfo.fileEntry = fileEntry;
  fileInfo.status = args[1];
  if (fileInfo.status == "synced") {
    fileInfo.action = args[2];
    fileInfo.direction = args[3];
  }
  dispatch([fileInfo]);
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the systemIndicator API.
// TODO(dewittj) Refactor custom binding to reduce redundancy between the
// extension action APIs.

var binding =
    apiBridge || require('binding').Binding.create('systemIndicator');

var setIcon = require('setIcon').setIcon;
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  apiFunctions.setHandleRequest('setIcon', function(details, callback) {
    setIcon(details, $Function.bind(function(args) {
      sendRequest('systemIndicator.setIcon', [args, callback],
                  bindingUtil ? undefined : this.definition.parameters,
                  undefined);
    }, this));
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the Tab Capture API.

var binding = apiBridge || require('binding').Binding.create('tabCapture');

var jsLastError = bindingUtil ? undefined : require('lastError');
function runCallbackWithLastError(name, message, stack, callback, args) {
  if (bindingUtil) {
    bindingUtil.runCallbackWithLastError(message, function() {
      $Function.apply(callback, null, args);
    });
  } else {
    jsLastError.run(name, message, stack, callback, args);
  }
}

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;

  function proxyToGetUserMedia(name, request, callback, response) {
    if (!callback)
      return;

    if (!response) {
      // When the response is missing, runtime.lastError has already been set.
      // See chrome/browser/extensions/api/tab_capture/tab_capture_api.cc.
      callback(null);
      return;
    }

    // Convenience function for processing webkitGetUserMedia() error objects to
    // provide runtime.lastError messages for the tab capture API.
    function getErrorMessage(error, fallbackMessage) {
      if (!error || (typeof error.message != 'string'))
        return fallbackMessage;
      return error.message.replace(/(navigator\.)?(webkit)?GetUserMedia/gi,
                                   name);
    }

    var options = {};
    if (response.audioConstraints)
      options.audio = response.audioConstraints;
    if (response.videoConstraints)
      options.video = response.videoConstraints;
    try {
      navigator.webkitGetUserMedia(
          options,
          function onSuccess(media_stream) {
            callback(media_stream);
          },
          function onError(error) {
            runCallbackWithLastError(
                name,
                getErrorMessage(error, "Failed to start MediaStream."),
                request.stack,
                function() { callback(null); });
          });
    } catch (error) {
      runCallbackWithLastError(
          name, getErrorMessage(error, "Invalid argument(s)."), request.stack,
          function() { callback(null); });
    }
  }

  apiFunctions.setCustomCallback('capture', proxyToGetUserMedia);
  apiFunctions.setCustomCallback('captureOffscreenTab', proxyToGetUserMedia);
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the tabs API.

var binding = apiBridge || require('binding').Binding.create('tabs');

var messaging = require('messaging');
var OpenChannelToTab = requireNative('messaging_natives').OpenChannelToTab;
var sendRequestIsDisabled = requireNative('process').IsSendRequestDisabled();
var forEach = require('utils').forEach;

binding.registerCustomHook(function(bindingsAPI, extensionId) {
  var apiFunctions = bindingsAPI.apiFunctions;
  var tabs = bindingsAPI.compiledApi;

  apiFunctions.setHandleRequest('connect', function(tabId, connectInfo) {
    var name = '';
    var frameId = -1;
    if (connectInfo) {
      name = connectInfo.name || name;
      frameId = connectInfo.frameId;
      if (typeof frameId == 'undefined' || frameId < 0)
        frameId = -1;
    }
    var portId = OpenChannelToTab(tabId, frameId, extensionId, name);
    return messaging.createPort(portId, name);
  });

  apiFunctions.setHandleRequest('sendRequest',
                                function(tabId, request, responseCallback) {
    if (sendRequestIsDisabled)
      throw new Error(sendRequestIsDisabled);
    var port = tabs.connect(tabId, {name: messaging.kRequestChannel});
    messaging.sendMessageImpl(port, request, responseCallback);
  });

  apiFunctions.setHandleRequest('sendMessage',
      function(tabId, message, options, responseCallback) {
    var connectInfo = {
      name: messaging.kMessageChannel
    };
    if (options) {
      forEach(options, function(k, v) {
        connectInfo[k] = v;
      });
    }

    var port = tabs.connect(tabId, connectInfo);
    messaging.sendMessageImpl(port, message, responseCallback);
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the tts API.

var binding = apiBridge || require('binding').Binding.create('tts');

var idGenerator = requireNative('id_generator');
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;
var lazyBG = requireNative('lazy_background_page');

binding.registerCustomHook(function(api) {
  var apiFunctions = api.apiFunctions;
  var tts = api.compiledApi;
  var handlers = {};

  function ttsEventListener(event) {
    var eventHandler = handlers[event.srcId];
    if (eventHandler) {
      eventHandler({
                     type: event.type,
                     charIndex: event.charIndex,
                     errorMessage: event.errorMessage
                   });
      if (event.isFinalEvent) {
        delete handlers[event.srcId];
        // Balanced in 'speak' handler.
        lazyBG.DecrementKeepaliveCount();
      }
    }
  }

  // This file will get run if an extension needs the ttsEngine permission, but
  // it doesn't necessarily have the tts permission. If it doesn't, trying to
  // add a listener to chrome.tts.onEvent will fail.
  // See http://crbug.com/122474.
  try {
    tts.onEvent.addListener(ttsEventListener);
  } catch (e) {}

  apiFunctions.setHandleRequest('speak', function() {
    var args = $Array.from(arguments);
    if (args.length > 1 && args[1] && args[1].onEvent) {
      var id = idGenerator.GetNextId();
      args[1].srcId = id;
      handlers[id] = args[1].onEvent;
      // Keep the page alive until the event finishes.
      // Balanced in eventHandler.
      lazyBG.IncrementKeepaliveCount();
    }
    sendRequest('tts.speak', args,
                bindingUtil ? undefined : this.definition.parameters,
                undefined);
    return id;
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the ttsEngine API.

var binding = apiBridge || require('binding').Binding.create('ttsEngine');
var registerArgumentMassager = bindingUtil ?
    $Function.bind(bindingUtil.registerEventArgumentMassager, bindingUtil) :
    require('event_bindings').registerArgumentMassager;

registerArgumentMassager('ttsEngine.onSpeak', function(args, dispatch) {
  var text = args[0];
  var options = args[1];
  var requestId = args[2];
  var sendTtsEvent = function(event) {
    chrome.ttsEngine.sendTtsEvent(requestId, event);
  };
  dispatch([text, options, sendTtsEvent]);
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the webrtcDesktopCapturePrivate API.

var binding = apiBridge ||
              require('binding').Binding.create('webrtcDesktopCapturePrivate');
var sendRequest = bindingUtil ?
    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
    require('sendRequest').sendRequest;
var idGenerator = requireNative('id_generator');

binding.registerCustomHook(function(bindingsAPI) {
  var apiFunctions = bindingsAPI.apiFunctions;

  var pendingRequests = {};

  function onRequestResult(id, result) {
    if (id in pendingRequests) {
      var callback = pendingRequests[id];
      delete pendingRequests[id];
      callback(result);
    }
  }

  apiFunctions.setHandleRequest('chooseDesktopMedia',
                                function(sources, request, callback) {
    var id = idGenerator.GetNextId();
    pendingRequests[id] = callback;
    sendRequest('webrtcDesktopCapturePrivate.chooseDesktopMedia',
                [id, sources, request,
                 $Function.bind(onRequestResult, null, id)],
                bindingUtil ? undefined : this.definition.parameters,
                undefined);
    return id;
  });

  apiFunctions.setHandleRequest('cancelChooseDesktopMedia', function(id) {
    if (id in pendingRequests) {
      delete pendingRequests[id];
      sendRequest('webrtcDesktopCapturePrivate.cancelChooseDesktopMedia', [id],
                  bindingUtil ? undefined : this.definition.parameters,
                  undefined);
    }
  });
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the webrtcLoggingPrivate API.

var binding = apiBridge ||
              require('binding').Binding.create('webrtcLoggingPrivate');

var getBindDirectoryEntryCallback =
    require('fileEntryBindingUtil').getBindDirectoryEntryCallback;

binding.registerCustomHook(function(binding, id, contextType) {
  var apiFunctions = binding.apiFunctions;
  apiFunctions.setCustomCallback('getLogsDirectory',
                                 getBindDirectoryEntryCallback());
});

if (!apiBridge)
  exports.$set('binding', binding.generate());
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Custom binding for the webstore API.

var webstoreNatives = requireNative('webstore');

var onInstallStageChanged;
var onDownloadProgress;

function Installer() {
  this._pendingInstall = null;
}

Installer.prototype.install = function(url, onSuccess, onFailure) {
  if (this._pendingInstall)
    throw new Error('A Chrome Web Store installation is already pending.');

  // With native bindings, these calls go through argument validation, which
  // sets optional/missing arguments to null. The native webstore bindings
  // expect either present or undefined, so transform null to undefined.
  if (url === null)
    url = undefined;
  if (onSuccess === null)
    onSuccess = undefined;
  if (onFailure === null)
    onFailure = undefined;

  if (url !== undefined && typeof url !== 'string') {
    throw new Error(
        'The Chrome Web Store item link URL parameter must be a string.');
  }
  if (onSuccess !== undefined && typeof onSuccess !== 'function') {
    throw new Error('The success callback parameter must be a function.');
  }
  if (onFailure !== undefined && typeof onFailure !== 'function') {
    throw new Error('The failure callback parameter must be a function.');
  }

  // Since we call Install() with a bool for if we have listeners, listeners
  // must be set prior to the inline installation starting (this is also
  // noted in the Event documentation in
  // chrome/common/extensions/api/webstore.json).
  var installId = webstoreNatives.Install(
      onInstallStageChanged.hasListeners(),
      onDownloadProgress.hasListeners(),
      url,
      onSuccess,
      onFailure);
  if (installId !== undefined) {
    this._pendingInstall = {
      installId: installId,
      onSuccess: onSuccess,
      onFailure: onFailure
    };
  }
};

Installer.prototype.onInstallResponse =
    function(installId, success, error, resultCode) {
  var pendingInstall = this._pendingInstall;
  if (!pendingInstall || pendingInstall.installId != installId) {
    // TODO(kalman): should this be an error?
    return;
  }

  try {
    if (success && pendingInstall.onSuccess)
      pendingInstall.onSuccess();
    else if (!success && pendingInstall.onFailure)
      pendingInstall.onFailure(error, resultCode);
  } catch (e) {
    console.error('Exception in chrome.webstore.install response handler: ' +
                  e.stack);
  } finally {
    this._pendingInstall = null;
  }
};

Installer.prototype.onInstallStageChanged = function(installStage) {
  onInstallStageChanged.dispatch(installStage);
};

Installer.prototype.onDownloadProgress = function(progress) {
  onDownloadProgress.dispatch(progress);
};

var installer = new Installer();


if (apiBridge) {
  apiBridge.registerCustomHook(function(api) {
    api.apiFunctions.setHandleRequest('install',
                                      function(url, onSuccess, onFailure) {
      installer.install(url, onSuccess, onFailure);
    });

    onInstallStageChanged = api.compiledApi.onInstallStageChanged;
    onDownloadProgress = api.compiledApi.onDownloadProgress;
  });
} else {
  var Event = require('event_bindings').Event;
  onInstallStageChanged =
      new Event(null, [{name: 'stage', type: 'string'}], {unmanaged: true});
  onDownloadProgress =
      new Event(null, [{name: 'progress', type: 'number'}], {unmanaged: true});

  var chromeWebstore = {
    install: function (url, onSuccess, onFailure) {
      installer.install(url, onSuccess, onFailure);
    },
    onInstallStageChanged: onInstallStageChanged,
    onDownloadProgress: onDownloadProgress,
  };
  exports.$set('binding', chromeWebstore);
}

// Called by webstore_bindings.cc.
exports.$set('onInstallResponse',
             $Function.bind(Installer.prototype.onInstallResponse, installer));
exports.$set('onInstallStageChanged',
             $Function.bind(Installer.prototype.onInstallStageChanged,
                            installer));
exports.$set('onDownloadProgress',
             $Function.bind(Installer.prototype.onDownloadProgress, installer));
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'chrome/common/media_router/mojo/media_controller.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('mediaRouter.mojom');
  var media_status$ =
      mojo.internal.exposeNamespace('mediaRouter.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'chrome/common/media_router/mojo/media_status.mojom', 'media_status.mojom.js');
  }
  var time$ =
      mojo.internal.exposeNamespace('mojo.common.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'mojo/common/time.mojom', '../../../../mojo/common/time.mojom.js');
  }



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


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

  MediaController_Play_Params.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;
  };

  MediaController_Play_Params.encodedSize = codec.kStructHeaderSize + 0;

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

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


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

  MediaController_Pause_Params.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;
  };

  MediaController_Pause_Params.encodedSize = codec.kStructHeaderSize + 0;

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

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


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

  MediaController_SetMute_Params.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;
  };

  MediaController_SetMute_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaController_SetMute_Params.decode = function(decoder) {
    var packed;
    var val = new MediaController_SetMute_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.mute = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaController_SetMute_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaController_SetMute_Params.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.mute & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaController_SetVolume_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaController_SetVolume_Params.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;
  };

  MediaController_SetVolume_Params.encodedSize = codec.kStructHeaderSize + 8;

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

  MediaController_SetVolume_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaController_SetVolume_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Float, val.volume);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaController_Seek_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaController_Seek_Params.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 MediaController_Seek_Params.time
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, time$.TimeDelta, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaController_Seek_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaController_Seek_Params.decode = function(decoder) {
    var packed;
    var val = new MediaController_Seek_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.time = decoder.decodeStructPointer(time$.TimeDelta);
    return val;
  };

  MediaController_Seek_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaController_Seek_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(time$.TimeDelta, val.time);
  };
  function MediaController_ConnectHangoutsMediaRouteController_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaController_ConnectHangoutsMediaRouteController_Params.prototype.initDefaults_ = function() {
    this.controllerRequest = new bindings.InterfaceRequest();
  };
  MediaController_ConnectHangoutsMediaRouteController_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  MediaController_ConnectHangoutsMediaRouteController_Params.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 MediaController_ConnectHangoutsMediaRouteController_Params.controllerRequest
    err = messageValidator.validateInterfaceRequest(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaController_ConnectHangoutsMediaRouteController_Params.encodedSize = codec.kStructHeaderSize + 8;

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

  MediaController_ConnectHangoutsMediaRouteController_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaController_ConnectHangoutsMediaRouteController_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.InterfaceRequest, val.controllerRequest);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function HangoutsMediaRouteController_SetLocalPresent_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  HangoutsMediaRouteController_SetLocalPresent_Params.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;
  };

  HangoutsMediaRouteController_SetLocalPresent_Params.encodedSize = codec.kStructHeaderSize + 8;

  HangoutsMediaRouteController_SetLocalPresent_Params.decode = function(decoder) {
    var packed;
    var val = new HangoutsMediaRouteController_SetLocalPresent_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.localPresent = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  HangoutsMediaRouteController_SetLocalPresent_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(HangoutsMediaRouteController_SetLocalPresent_Params.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.localPresent & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  var kMediaController_Play_Name = 805768224;
  var kMediaController_Pause_Name = 1730431875;
  var kMediaController_SetMute_Name = 1350303890;
  var kMediaController_SetVolume_Name = 1058468242;
  var kMediaController_Seek_Name = 222187904;
  var kMediaController_ConnectHangoutsMediaRouteController_Name = 986560610;

  function MediaControllerPtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(MediaController,
                                                   handleOrPtrInfo);
  }

  function MediaControllerAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        MediaController, associatedInterfacePtrInfo);
  }

  MediaControllerAssociatedPtr.prototype =
      Object.create(MediaControllerPtr.prototype);
  MediaControllerAssociatedPtr.prototype.constructor =
      MediaControllerAssociatedPtr;

  function MediaControllerProxy(receiver) {
    this.receiver_ = receiver;
  }
  MediaControllerPtr.prototype.play = function() {
    return MediaControllerProxy.prototype.play
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaControllerProxy.prototype.play = function() {
    var params = new MediaController_Play_Params();
    var builder = new codec.MessageV0Builder(
        kMediaController_Play_Name,
        codec.align(MediaController_Play_Params.encodedSize));
    builder.encodeStruct(MediaController_Play_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaControllerPtr.prototype.pause = function() {
    return MediaControllerProxy.prototype.pause
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaControllerProxy.prototype.pause = function() {
    var params = new MediaController_Pause_Params();
    var builder = new codec.MessageV0Builder(
        kMediaController_Pause_Name,
        codec.align(MediaController_Pause_Params.encodedSize));
    builder.encodeStruct(MediaController_Pause_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaControllerPtr.prototype.setMute = function() {
    return MediaControllerProxy.prototype.setMute
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaControllerProxy.prototype.setMute = function(mute) {
    var params = new MediaController_SetMute_Params();
    params.mute = mute;
    var builder = new codec.MessageV0Builder(
        kMediaController_SetMute_Name,
        codec.align(MediaController_SetMute_Params.encodedSize));
    builder.encodeStruct(MediaController_SetMute_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaControllerPtr.prototype.setVolume = function() {
    return MediaControllerProxy.prototype.setVolume
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaControllerProxy.prototype.setVolume = function(volume) {
    var params = new MediaController_SetVolume_Params();
    params.volume = volume;
    var builder = new codec.MessageV0Builder(
        kMediaController_SetVolume_Name,
        codec.align(MediaController_SetVolume_Params.encodedSize));
    builder.encodeStruct(MediaController_SetVolume_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaControllerPtr.prototype.seek = function() {
    return MediaControllerProxy.prototype.seek
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaControllerProxy.prototype.seek = function(time) {
    var params = new MediaController_Seek_Params();
    params.time = time;
    var builder = new codec.MessageV0Builder(
        kMediaController_Seek_Name,
        codec.align(MediaController_Seek_Params.encodedSize));
    builder.encodeStruct(MediaController_Seek_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaControllerPtr.prototype.connectHangoutsMediaRouteController = function() {
    return MediaControllerProxy.prototype.connectHangoutsMediaRouteController
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaControllerProxy.prototype.connectHangoutsMediaRouteController = function(controllerRequest) {
    var params = new MediaController_ConnectHangoutsMediaRouteController_Params();
    params.controllerRequest = controllerRequest;
    var builder = new codec.MessageV0Builder(
        kMediaController_ConnectHangoutsMediaRouteController_Name,
        codec.align(MediaController_ConnectHangoutsMediaRouteController_Params.encodedSize));
    builder.encodeStruct(MediaController_ConnectHangoutsMediaRouteController_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };

  function MediaControllerStub(delegate) {
    this.delegate_ = delegate;
  }
  MediaControllerStub.prototype.play = function() {
    return this.delegate_ && this.delegate_.play && this.delegate_.play();
  }
  MediaControllerStub.prototype.pause = function() {
    return this.delegate_ && this.delegate_.pause && this.delegate_.pause();
  }
  MediaControllerStub.prototype.setMute = function(mute) {
    return this.delegate_ && this.delegate_.setMute && this.delegate_.setMute(mute);
  }
  MediaControllerStub.prototype.setVolume = function(volume) {
    return this.delegate_ && this.delegate_.setVolume && this.delegate_.setVolume(volume);
  }
  MediaControllerStub.prototype.seek = function(time) {
    return this.delegate_ && this.delegate_.seek && this.delegate_.seek(time);
  }
  MediaControllerStub.prototype.connectHangoutsMediaRouteController = function(controllerRequest) {
    return this.delegate_ && this.delegate_.connectHangoutsMediaRouteController && this.delegate_.connectHangoutsMediaRouteController(controllerRequest);
  }

  MediaControllerStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMediaController_Play_Name:
      var params = reader.decodeStruct(MediaController_Play_Params);
      this.play();
      return true;
    case kMediaController_Pause_Name:
      var params = reader.decodeStruct(MediaController_Pause_Params);
      this.pause();
      return true;
    case kMediaController_SetMute_Name:
      var params = reader.decodeStruct(MediaController_SetMute_Params);
      this.setMute(params.mute);
      return true;
    case kMediaController_SetVolume_Name:
      var params = reader.decodeStruct(MediaController_SetVolume_Params);
      this.setVolume(params.volume);
      return true;
    case kMediaController_Seek_Name:
      var params = reader.decodeStruct(MediaController_Seek_Params);
      this.seek(params.time);
      return true;
    case kMediaController_ConnectHangoutsMediaRouteController_Name:
      var params = reader.decodeStruct(MediaController_ConnectHangoutsMediaRouteController_Params);
      this.connectHangoutsMediaRouteController(params.controllerRequest);
      return true;
    default:
      return false;
    }
  };

  MediaControllerStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    default:
      return false;
    }
  };

  function validateMediaControllerRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kMediaController_Play_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaController_Play_Params;
      break;
      case kMediaController_Pause_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaController_Pause_Params;
      break;
      case kMediaController_SetMute_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaController_SetMute_Params;
      break;
      case kMediaController_SetVolume_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaController_SetVolume_Params;
      break;
      case kMediaController_Seek_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaController_Seek_Params;
      break;
      case kMediaController_ConnectHangoutsMediaRouteController_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaController_ConnectHangoutsMediaRouteController_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateMediaControllerResponse(messageValidator) {
    return validator.validationError.NONE;
  }

  var MediaController = {
    name: 'media_router::mojom::MediaController',
    kVersion: 0,
    ptrClass: MediaControllerPtr,
    proxyClass: MediaControllerProxy,
    stubClass: MediaControllerStub,
    validateRequest: validateMediaControllerRequest,
    validateResponse: null,
  };
  MediaControllerStub.prototype.validator = validateMediaControllerRequest;
  MediaControllerProxy.prototype.validator = null;
  var kHangoutsMediaRouteController_SetLocalPresent_Name = 203222817;

  function HangoutsMediaRouteControllerPtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(HangoutsMediaRouteController,
                                                   handleOrPtrInfo);
  }

  function HangoutsMediaRouteControllerAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        HangoutsMediaRouteController, associatedInterfacePtrInfo);
  }

  HangoutsMediaRouteControllerAssociatedPtr.prototype =
      Object.create(HangoutsMediaRouteControllerPtr.prototype);
  HangoutsMediaRouteControllerAssociatedPtr.prototype.constructor =
      HangoutsMediaRouteControllerAssociatedPtr;

  function HangoutsMediaRouteControllerProxy(receiver) {
    this.receiver_ = receiver;
  }
  HangoutsMediaRouteControllerPtr.prototype.setLocalPresent = function() {
    return HangoutsMediaRouteControllerProxy.prototype.setLocalPresent
        .apply(this.ptr.getProxy(), arguments);
  };

  HangoutsMediaRouteControllerProxy.prototype.setLocalPresent = function(localPresent) {
    var params = new HangoutsMediaRouteController_SetLocalPresent_Params();
    params.localPresent = localPresent;
    var builder = new codec.MessageV0Builder(
        kHangoutsMediaRouteController_SetLocalPresent_Name,
        codec.align(HangoutsMediaRouteController_SetLocalPresent_Params.encodedSize));
    builder.encodeStruct(HangoutsMediaRouteController_SetLocalPresent_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };

  function HangoutsMediaRouteControllerStub(delegate) {
    this.delegate_ = delegate;
  }
  HangoutsMediaRouteControllerStub.prototype.setLocalPresent = function(localPresent) {
    return this.delegate_ && this.delegate_.setLocalPresent && this.delegate_.setLocalPresent(localPresent);
  }

  HangoutsMediaRouteControllerStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kHangoutsMediaRouteController_SetLocalPresent_Name:
      var params = reader.decodeStruct(HangoutsMediaRouteController_SetLocalPresent_Params);
      this.setLocalPresent(params.localPresent);
      return true;
    default:
      return false;
    }
  };

  HangoutsMediaRouteControllerStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    default:
      return false;
    }
  };

  function validateHangoutsMediaRouteControllerRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kHangoutsMediaRouteController_SetLocalPresent_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = HangoutsMediaRouteController_SetLocalPresent_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateHangoutsMediaRouteControllerResponse(messageValidator) {
    return validator.validationError.NONE;
  }

  var HangoutsMediaRouteController = {
    name: 'media_router::mojom::HangoutsMediaRouteController',
    kVersion: 0,
    ptrClass: HangoutsMediaRouteControllerPtr,
    proxyClass: HangoutsMediaRouteControllerProxy,
    stubClass: HangoutsMediaRouteControllerStub,
    validateRequest: validateHangoutsMediaRouteControllerRequest,
    validateResponse: null,
  };
  HangoutsMediaRouteControllerStub.prototype.validator = validateHangoutsMediaRouteControllerRequest;
  HangoutsMediaRouteControllerProxy.prototype.validator = null;
  exports.MediaController = MediaController;
  exports.MediaControllerPtr = MediaControllerPtr;
  exports.MediaControllerAssociatedPtr = MediaControllerAssociatedPtr;
  exports.HangoutsMediaRouteController = HangoutsMediaRouteController;
  exports.HangoutsMediaRouteControllerPtr = HangoutsMediaRouteControllerPtr;
  exports.HangoutsMediaRouteControllerAssociatedPtr = HangoutsMediaRouteControllerAssociatedPtr;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'chrome/common/media_router/mojo/media_router.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('mediaRouter.mojom');
  var media_controller$ =
      mojo.internal.exposeNamespace('mediaRouter.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'chrome/common/media_router/mojo/media_controller.mojom', 'media_controller.mojom.js');
  }
  var media_status$ =
      mojo.internal.exposeNamespace('mediaRouter.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'chrome/common/media_router/mojo/media_status.mojom', 'media_status.mojom.js');
  }
  var mirror_service_remoting$ =
      mojo.internal.exposeNamespace('media.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'media/mojo/interfaces/mirror_service_remoting.mojom', '../../../../media/mojo/interfaces/mirror_service_remoting.mojom.js');
  }
  var time$ =
      mojo.internal.exposeNamespace('mojo.common.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'mojo/common/time.mojom', '../../../../mojo/common/time.mojom.js');
  }
  var ip_address$ =
      mojo.internal.exposeNamespace('net.interfaces');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'net/interfaces/ip_address.mojom', '../../../../net/interfaces/ip_address.mojom.js');
  }
  var ip_endpoint$ =
      mojo.internal.exposeNamespace('net.interfaces');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'net/interfaces/ip_endpoint.mojom', '../../../../net/interfaces/ip_endpoint.mojom.js');
  }
  var origin$ =
      mojo.internal.exposeNamespace('url.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'url/mojo/origin.mojom', '../../../../url/mojo/origin.mojom.js');
  }
  var url$ =
      mojo.internal.exposeNamespace('url.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'url/mojo/url.mojom', '../../../../url/mojo/url.mojom.js');
  }


  var SinkIconType = {};
  SinkIconType.CAST = 0;
  SinkIconType.CAST_AUDIO_GROUP = SinkIconType.CAST + 1;
  SinkIconType.CAST_AUDIO = SinkIconType.CAST_AUDIO_GROUP + 1;
  SinkIconType.MEETING = SinkIconType.CAST_AUDIO + 1;
  SinkIconType.HANGOUT = SinkIconType.MEETING + 1;
  SinkIconType.EDUCATION = SinkIconType.HANGOUT + 1;
  SinkIconType.WIRED_DISPLAY = SinkIconType.EDUCATION + 1;
  SinkIconType.GENERIC = SinkIconType.WIRED_DISPLAY + 1;

  SinkIconType.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
      return true;
    }
    return false;
  };

  SinkIconType.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  var RouteControllerType = {};
  RouteControllerType.kNone = 0;
  RouteControllerType.kGeneric = RouteControllerType.kNone + 1;
  RouteControllerType.kHangouts = RouteControllerType.kGeneric + 1;
  RouteControllerType.kMirroring = RouteControllerType.kHangouts + 1;

  RouteControllerType.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
    case 3:
      return true;
    }
    return false;
  };

  RouteControllerType.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  var RouteRequestResultCode = {};
  RouteRequestResultCode.UNKNOWN_ERROR = 0;
  RouteRequestResultCode.OK = RouteRequestResultCode.UNKNOWN_ERROR + 1;
  RouteRequestResultCode.TIMED_OUT = RouteRequestResultCode.OK + 1;
  RouteRequestResultCode.ROUTE_NOT_FOUND = RouteRequestResultCode.TIMED_OUT + 1;
  RouteRequestResultCode.SINK_NOT_FOUND = RouteRequestResultCode.ROUTE_NOT_FOUND + 1;
  RouteRequestResultCode.INVALID_ORIGIN = RouteRequestResultCode.SINK_NOT_FOUND + 1;
  RouteRequestResultCode.INCOGNITO_MISMATCH = RouteRequestResultCode.INVALID_ORIGIN + 1;
  RouteRequestResultCode.NO_SUPPORTED_PROVIDER = RouteRequestResultCode.INCOGNITO_MISMATCH + 1;
  RouteRequestResultCode.CANCELLED = RouteRequestResultCode.NO_SUPPORTED_PROVIDER + 1;

  RouteRequestResultCode.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
      return true;
    }
    return false;
  };

  RouteRequestResultCode.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };

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


  MediaSink.prototype.initDefaults_ = function() {
    this.sinkId = null;
    this.name = null;
    this.description = null;
    this.domain = null;
    this.iconType = 0;
    this.providerId = 0;
    this.extraData = null;
  };
  MediaSink.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaSink.sinkId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaSink.description
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaSink.domain
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 24, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaSink.iconType
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 32, SinkIconType);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaSink.providerId
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 36, MediaRouteProvider.Id);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaSink.extraData
    err = messageValidator.validateUnion(offset + codec.kStructHeaderSize + 40, MediaSinkExtraData, true);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaSink.encodedSize = codec.kStructHeaderSize + 56;

  MediaSink.decode = function(decoder) {
    var packed;
    var val = new MediaSink();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.sinkId = decoder.decodeStruct(codec.String);
    val.name = decoder.decodeStruct(codec.String);
    val.description = decoder.decodeStruct(codec.NullableString);
    val.domain = decoder.decodeStruct(codec.NullableString);
    val.iconType = decoder.decodeStruct(codec.Int32);
    val.providerId = decoder.decodeStruct(codec.Int32);
    val.extraData = decoder.decodeStruct(MediaSinkExtraData);
    return val;
  };

  MediaSink.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaSink.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.sinkId);
    encoder.encodeStruct(codec.String, val.name);
    encoder.encodeStruct(codec.NullableString, val.description);
    encoder.encodeStruct(codec.NullableString, val.domain);
    encoder.encodeStruct(codec.Int32, val.iconType);
    encoder.encodeStruct(codec.Int32, val.providerId);
    encoder.encodeStruct(MediaSinkExtraData, val.extraData);
  };
  function DialMediaSink(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  DialMediaSink.prototype.initDefaults_ = function() {
    this.ipAddress = null;
    this.modelName = null;
    this.appUrl = null;
  };
  DialMediaSink.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate DialMediaSink.ipAddress
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, ip_address$.IPAddress, false);
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate DialMediaSink.appUrl
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 16, url$.Url, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  DialMediaSink.encodedSize = codec.kStructHeaderSize + 24;

  DialMediaSink.decode = function(decoder) {
    var packed;
    var val = new DialMediaSink();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.ipAddress = decoder.decodeStructPointer(ip_address$.IPAddress);
    val.modelName = decoder.decodeStruct(codec.String);
    val.appUrl = decoder.decodeStructPointer(url$.Url);
    return val;
  };

  DialMediaSink.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(DialMediaSink.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(ip_address$.IPAddress, val.ipAddress);
    encoder.encodeStruct(codec.String, val.modelName);
    encoder.encodeStructPointer(url$.Url, val.appUrl);
  };
  function CastMediaSink(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  CastMediaSink.prototype.initDefaults_ = function() {
    this.ipEndpoint = null;
    this.modelName = null;
    this.capabilities = 0;
    this.castChannelId = 0;
  };
  CastMediaSink.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate CastMediaSink.ipEndpoint
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, ip_endpoint$.IPEndPoint, false);
    if (err !== validator.validationError.NONE)
        return err;


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



    return validator.validationError.NONE;
  };

  CastMediaSink.encodedSize = codec.kStructHeaderSize + 24;

  CastMediaSink.decode = function(decoder) {
    var packed;
    var val = new CastMediaSink();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.ipEndpoint = decoder.decodeStructPointer(ip_endpoint$.IPEndPoint);
    val.modelName = decoder.decodeStruct(codec.String);
    val.capabilities = decoder.decodeStruct(codec.Uint8);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.castChannelId = decoder.decodeStruct(codec.Int32);
    return val;
  };

  CastMediaSink.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(CastMediaSink.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(ip_endpoint$.IPEndPoint, val.ipEndpoint);
    encoder.encodeStruct(codec.String, val.modelName);
    encoder.encodeStruct(codec.Uint8, val.capabilities);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.Int32, val.castChannelId);
  };
  function MediaRoute(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRoute.prototype.initDefaults_ = function() {
    this.mediaRouteId = null;
    this.presentationId = null;
    this.mediaSource = null;
    this.mediaSinkId = null;
    this.description = null;
    this.isLocal = false;
    this.forDisplay = false;
    this.isIncognito = false;
    this.isLocalPresentation = false;
    this.controllerType = 0;
  };
  MediaRoute.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRoute.mediaRouteId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaRoute.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRoute.mediaSinkId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 24, false)
    if (err !== validator.validationError.NONE)
        return err;


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



    // validate MediaRoute.controllerType
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 44, RouteControllerType);
    if (err !== validator.validationError.NONE)
        return err;




    return validator.validationError.NONE;
  };

  MediaRoute.encodedSize = codec.kStructHeaderSize + 48;

  MediaRoute.decode = function(decoder) {
    var packed;
    var val = new MediaRoute();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaRouteId = decoder.decodeStruct(codec.String);
    val.presentationId = decoder.decodeStruct(codec.String);
    val.mediaSource = decoder.decodeStruct(codec.NullableString);
    val.mediaSinkId = decoder.decodeStruct(codec.String);
    val.description = decoder.decodeStruct(codec.String);
    packed = decoder.readUint8();
    val.isLocal = (packed >> 0) & 1 ? true : false;
    val.forDisplay = (packed >> 1) & 1 ? true : false;
    val.isIncognito = (packed >> 2) & 1 ? true : false;
    val.isLocalPresentation = (packed >> 3) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.controllerType = decoder.decodeStruct(codec.Int32);
    return val;
  };

  MediaRoute.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRoute.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaRouteId);
    encoder.encodeStruct(codec.String, val.presentationId);
    encoder.encodeStruct(codec.NullableString, val.mediaSource);
    encoder.encodeStruct(codec.String, val.mediaSinkId);
    encoder.encodeStruct(codec.String, val.description);
    packed = 0;
    packed |= (val.isLocal & 1) << 0
    packed |= (val.forDisplay & 1) << 1
    packed |= (val.isIncognito & 1) << 2
    packed |= (val.isLocalPresentation & 1) << 3
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.Int32, val.controllerType);
  };
  function Issue(values) {
    this.initDefaults_();
    this.initFields_(values);
  }

  Issue.Severity = {};
  Issue.Severity.FATAL = 0;
  Issue.Severity.WARNING = Issue.Severity.FATAL + 1;
  Issue.Severity.NOTIFICATION = Issue.Severity.WARNING + 1;

  Issue.Severity.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
      return true;
    }
    return false;
  };

  Issue.Severity.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  Issue.ActionType = {};
  Issue.ActionType.DISMISS = 0;
  Issue.ActionType.LEARN_MORE = Issue.ActionType.DISMISS + 1;

  Issue.ActionType.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
      return true;
    }
    return false;
  };

  Issue.ActionType.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };

  Issue.prototype.initDefaults_ = function() {
    this.routeId = null;
    this.severity = 0;
    this.isBlocking = false;
    this.title = null;
    this.message = null;
    this.defaultAction = 0;
    this.helpPageId = 0;
    this.secondaryActions = null;
  };
  Issue.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate Issue.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate Issue.severity
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 8, Issue.Severity);
    if (err !== validator.validationError.NONE)
        return err;



    // validate Issue.title
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate Issue.message
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 24, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate Issue.defaultAction
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 32, Issue.ActionType);
    if (err !== validator.validationError.NONE)
        return err;


    // validate Issue.secondaryActions
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 40, 4, new codec.Enum(Issue.ActionType), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  Issue.encodedSize = codec.kStructHeaderSize + 48;

  Issue.decode = function(decoder) {
    var packed;
    var val = new Issue();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.NullableString);
    val.severity = decoder.decodeStruct(codec.Int32);
    packed = decoder.readUint8();
    val.isBlocking = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.title = decoder.decodeStruct(codec.String);
    val.message = decoder.decodeStruct(codec.NullableString);
    val.defaultAction = decoder.decodeStruct(codec.Int32);
    val.helpPageId = decoder.decodeStruct(codec.Int32);
    val.secondaryActions = decoder.decodeArrayPointer(new codec.Enum(Issue.ActionType));
    return val;
  };

  Issue.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(Issue.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.NullableString, val.routeId);
    encoder.encodeStruct(codec.Int32, val.severity);
    packed = 0;
    packed |= (val.isBlocking & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.String, val.title);
    encoder.encodeStruct(codec.NullableString, val.message);
    encoder.encodeStruct(codec.Int32, val.defaultAction);
    encoder.encodeStruct(codec.Int32, val.helpPageId);
    encoder.encodeArrayPointer(new codec.Enum(Issue.ActionType), val.secondaryActions);
  };
  function RouteMessage(values) {
    this.initDefaults_();
    this.initFields_(values);
  }

  RouteMessage.Type = {};
  RouteMessage.Type.TEXT = 0;
  RouteMessage.Type.BINARY = RouteMessage.Type.TEXT + 1;

  RouteMessage.Type.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
      return true;
    }
    return false;
  };

  RouteMessage.Type.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };

  RouteMessage.prototype.initDefaults_ = function() {
    this.type = 0;
    this.message = null;
    this.data = null;
  };
  RouteMessage.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate RouteMessage.type
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, RouteMessage.Type);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RouteMessage.message
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 8, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate RouteMessage.data
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 16, 1, codec.Uint8, true, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  RouteMessage.encodedSize = codec.kStructHeaderSize + 24;

  RouteMessage.decode = function(decoder) {
    var packed;
    var val = new RouteMessage();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.type = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.message = decoder.decodeStruct(codec.NullableString);
    val.data = decoder.decodeArrayPointer(codec.Uint8);
    return val;
  };

  RouteMessage.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RouteMessage.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.type);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.NullableString, val.message);
    encoder.encodeArrayPointer(codec.Uint8, val.data);
  };
  function SinkSearchCriteria(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  SinkSearchCriteria.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 SinkSearchCriteria.input
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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

    return validator.validationError.NONE;
  };

  SinkSearchCriteria.encodedSize = codec.kStructHeaderSize + 16;

  SinkSearchCriteria.decode = function(decoder) {
    var packed;
    var val = new SinkSearchCriteria();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.input = decoder.decodeStruct(codec.String);
    val.domain = decoder.decodeStruct(codec.String);
    return val;
  };

  SinkSearchCriteria.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(SinkSearchCriteria.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.input);
    encoder.encodeStruct(codec.String, val.domain);
  };
  function MediaRouteProviderConfig(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProviderConfig.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;
  };

  MediaRouteProviderConfig.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProviderConfig.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProviderConfig();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.enableDialDiscovery = (packed >> 0) & 1 ? true : false;
    val.enableCastDiscovery = (packed >> 1) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProviderConfig.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProviderConfig.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.enableDialDiscovery & 1) << 0
    packed |= (val.enableCastDiscovery & 1) << 1
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_CreateRoute_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_CreateRoute_Params.prototype.initDefaults_ = function() {
    this.mediaSource = null;
    this.sinkId = null;
    this.originalPresentationId = null;
    this.origin = null;
    this.tabId = 0;
    this.incognito = false;
    this.timeout = null;
  };
  MediaRouteProvider_CreateRoute_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_CreateRoute_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaRouteProvider_CreateRoute_Params.originalPresentationId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_CreateRoute_Params.origin
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 24, origin$.Origin, false);
    if (err !== validator.validationError.NONE)
        return err;



    // validate MediaRouteProvider_CreateRoute_Params.timeout
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 40, time$.TimeDelta, false);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  MediaRouteProvider_CreateRoute_Params.encodedSize = codec.kStructHeaderSize + 48;

  MediaRouteProvider_CreateRoute_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_CreateRoute_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    val.sinkId = decoder.decodeStruct(codec.String);
    val.originalPresentationId = decoder.decodeStruct(codec.String);
    val.origin = decoder.decodeStructPointer(origin$.Origin);
    val.tabId = decoder.decodeStruct(codec.Int32);
    packed = decoder.readUint8();
    val.incognito = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.timeout = decoder.decodeStructPointer(time$.TimeDelta);
    return val;
  };

  MediaRouteProvider_CreateRoute_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_CreateRoute_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
    encoder.encodeStruct(codec.String, val.sinkId);
    encoder.encodeStruct(codec.String, val.originalPresentationId);
    encoder.encodeStructPointer(origin$.Origin, val.origin);
    encoder.encodeStruct(codec.Int32, val.tabId);
    packed = 0;
    packed |= (val.incognito & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStructPointer(time$.TimeDelta, val.timeout);
  };
  function MediaRouteProvider_CreateRoute_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_CreateRoute_ResponseParams.prototype.initDefaults_ = function() {
    this.route = null;
    this.errorText = null;
    this.resultCode = 0;
  };
  MediaRouteProvider_CreateRoute_ResponseParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_CreateRoute_ResponseParams.route
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, MediaRoute, true);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_CreateRoute_ResponseParams.errorText
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 8, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_CreateRoute_ResponseParams.resultCode
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 16, RouteRequestResultCode);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_CreateRoute_ResponseParams.encodedSize = codec.kStructHeaderSize + 24;

  MediaRouteProvider_CreateRoute_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_CreateRoute_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.route = decoder.decodeStructPointer(MediaRoute);
    val.errorText = decoder.decodeStruct(codec.NullableString);
    val.resultCode = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_CreateRoute_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_CreateRoute_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(MediaRoute, val.route);
    encoder.encodeStruct(codec.NullableString, val.errorText);
    encoder.encodeStruct(codec.Int32, val.resultCode);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_JoinRoute_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_JoinRoute_Params.prototype.initDefaults_ = function() {
    this.mediaSource = null;
    this.presentationId = null;
    this.origin = null;
    this.tabId = 0;
    this.incognito = false;
    this.timeout = null;
  };
  MediaRouteProvider_JoinRoute_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_JoinRoute_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaRouteProvider_JoinRoute_Params.origin
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 16, origin$.Origin, false);
    if (err !== validator.validationError.NONE)
        return err;



    // validate MediaRouteProvider_JoinRoute_Params.timeout
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 32, time$.TimeDelta, false);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  MediaRouteProvider_JoinRoute_Params.encodedSize = codec.kStructHeaderSize + 40;

  MediaRouteProvider_JoinRoute_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_JoinRoute_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    val.presentationId = decoder.decodeStruct(codec.String);
    val.origin = decoder.decodeStructPointer(origin$.Origin);
    val.tabId = decoder.decodeStruct(codec.Int32);
    packed = decoder.readUint8();
    val.incognito = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.timeout = decoder.decodeStructPointer(time$.TimeDelta);
    return val;
  };

  MediaRouteProvider_JoinRoute_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_JoinRoute_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
    encoder.encodeStruct(codec.String, val.presentationId);
    encoder.encodeStructPointer(origin$.Origin, val.origin);
    encoder.encodeStruct(codec.Int32, val.tabId);
    packed = 0;
    packed |= (val.incognito & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStructPointer(time$.TimeDelta, val.timeout);
  };
  function MediaRouteProvider_JoinRoute_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_JoinRoute_ResponseParams.prototype.initDefaults_ = function() {
    this.route = null;
    this.errorText = null;
    this.resultCode = 0;
  };
  MediaRouteProvider_JoinRoute_ResponseParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_JoinRoute_ResponseParams.route
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, MediaRoute, true);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_JoinRoute_ResponseParams.errorText
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 8, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_JoinRoute_ResponseParams.resultCode
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 16, RouteRequestResultCode);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_JoinRoute_ResponseParams.encodedSize = codec.kStructHeaderSize + 24;

  MediaRouteProvider_JoinRoute_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_JoinRoute_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.route = decoder.decodeStructPointer(MediaRoute);
    val.errorText = decoder.decodeStruct(codec.NullableString);
    val.resultCode = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_JoinRoute_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_JoinRoute_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(MediaRoute, val.route);
    encoder.encodeStruct(codec.NullableString, val.errorText);
    encoder.encodeStruct(codec.Int32, val.resultCode);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_ConnectRouteByRouteId_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_ConnectRouteByRouteId_Params.prototype.initDefaults_ = function() {
    this.mediaSource = null;
    this.routeId = null;
    this.presentationId = null;
    this.origin = null;
    this.tabId = 0;
    this.incognito = false;
    this.timeout = null;
  };
  MediaRouteProvider_ConnectRouteByRouteId_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_ConnectRouteByRouteId_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaRouteProvider_ConnectRouteByRouteId_Params.presentationId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_ConnectRouteByRouteId_Params.origin
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 24, origin$.Origin, false);
    if (err !== validator.validationError.NONE)
        return err;



    // validate MediaRouteProvider_ConnectRouteByRouteId_Params.timeout
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 40, time$.TimeDelta, false);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  MediaRouteProvider_ConnectRouteByRouteId_Params.encodedSize = codec.kStructHeaderSize + 48;

  MediaRouteProvider_ConnectRouteByRouteId_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_ConnectRouteByRouteId_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    val.routeId = decoder.decodeStruct(codec.String);
    val.presentationId = decoder.decodeStruct(codec.String);
    val.origin = decoder.decodeStructPointer(origin$.Origin);
    val.tabId = decoder.decodeStruct(codec.Int32);
    packed = decoder.readUint8();
    val.incognito = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.timeout = decoder.decodeStructPointer(time$.TimeDelta);
    return val;
  };

  MediaRouteProvider_ConnectRouteByRouteId_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_ConnectRouteByRouteId_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
    encoder.encodeStruct(codec.String, val.routeId);
    encoder.encodeStruct(codec.String, val.presentationId);
    encoder.encodeStructPointer(origin$.Origin, val.origin);
    encoder.encodeStruct(codec.Int32, val.tabId);
    packed = 0;
    packed |= (val.incognito & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStructPointer(time$.TimeDelta, val.timeout);
  };
  function MediaRouteProvider_ConnectRouteByRouteId_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.prototype.initDefaults_ = function() {
    this.route = null;
    this.errorText = null;
    this.resultCode = 0;
  };
  MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.route
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, MediaRoute, true);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.errorText
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 8, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.resultCode
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 16, RouteRequestResultCode);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.encodedSize = codec.kStructHeaderSize + 24;

  MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_ConnectRouteByRouteId_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.route = decoder.decodeStructPointer(MediaRoute);
    val.errorText = decoder.decodeStruct(codec.NullableString);
    val.resultCode = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(MediaRoute, val.route);
    encoder.encodeStruct(codec.NullableString, val.errorText);
    encoder.encodeStruct(codec.Int32, val.resultCode);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_TerminateRoute_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_TerminateRoute_Params.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 MediaRouteProvider_TerminateRoute_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_TerminateRoute_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_TerminateRoute_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_TerminateRoute_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_TerminateRoute_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_TerminateRoute_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
  };
  function MediaRouteProvider_TerminateRoute_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_TerminateRoute_ResponseParams.prototype.initDefaults_ = function() {
    this.errorText = null;
    this.resultCode = 0;
  };
  MediaRouteProvider_TerminateRoute_ResponseParams.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  MediaRouteProvider_TerminateRoute_ResponseParams.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 MediaRouteProvider_TerminateRoute_ResponseParams.errorText
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, true)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_TerminateRoute_ResponseParams.resultCode
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 8, RouteRequestResultCode);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_TerminateRoute_ResponseParams.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouteProvider_TerminateRoute_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_TerminateRoute_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.errorText = decoder.decodeStruct(codec.NullableString);
    val.resultCode = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_TerminateRoute_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_TerminateRoute_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.NullableString, val.errorText);
    encoder.encodeStruct(codec.Int32, val.resultCode);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_SendRouteMessage_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_SendRouteMessage_Params.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 MediaRouteProvider_SendRouteMessage_Params.mediaRouteId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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

    return validator.validationError.NONE;
  };

  MediaRouteProvider_SendRouteMessage_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouteProvider_SendRouteMessage_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_SendRouteMessage_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaRouteId = decoder.decodeStruct(codec.String);
    val.message = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_SendRouteMessage_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_SendRouteMessage_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaRouteId);
    encoder.encodeStruct(codec.String, val.message);
  };
  function MediaRouteProvider_SendRouteMessage_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_SendRouteMessage_ResponseParams.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;
  };

  MediaRouteProvider_SendRouteMessage_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_SendRouteMessage_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_SendRouteMessage_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.sent = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_SendRouteMessage_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_SendRouteMessage_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.sent & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_SendRouteBinaryMessage_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_SendRouteBinaryMessage_Params.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 MediaRouteProvider_SendRouteBinaryMessage_Params.mediaRouteId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_SendRouteBinaryMessage_Params.data
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 8, 1, codec.Uint8, false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_SendRouteBinaryMessage_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouteProvider_SendRouteBinaryMessage_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_SendRouteBinaryMessage_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaRouteId = decoder.decodeStruct(codec.String);
    val.data = decoder.decodeArrayPointer(codec.Uint8);
    return val;
  };

  MediaRouteProvider_SendRouteBinaryMessage_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_SendRouteBinaryMessage_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaRouteId);
    encoder.encodeArrayPointer(codec.Uint8, val.data);
  };
  function MediaRouteProvider_SendRouteBinaryMessage_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_SendRouteBinaryMessage_ResponseParams.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;
  };

  MediaRouteProvider_SendRouteBinaryMessage_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_SendRouteBinaryMessage_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_SendRouteBinaryMessage_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.sent = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_SendRouteBinaryMessage_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_SendRouteBinaryMessage_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.sent & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_StartObservingMediaSinks_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_StartObservingMediaSinks_Params.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 MediaRouteProvider_StartObservingMediaSinks_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_StartObservingMediaSinks_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_StartObservingMediaSinks_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_StartObservingMediaSinks_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_StartObservingMediaSinks_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_StartObservingMediaSinks_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
  };
  function MediaRouteProvider_StopObservingMediaSinks_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_StopObservingMediaSinks_Params.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 MediaRouteProvider_StopObservingMediaSinks_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_StopObservingMediaSinks_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_StopObservingMediaSinks_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_StopObservingMediaSinks_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_StopObservingMediaSinks_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_StopObservingMediaSinks_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
  };
  function MediaRouteProvider_StartObservingMediaRoutes_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_StartObservingMediaRoutes_Params.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 MediaRouteProvider_StartObservingMediaRoutes_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_StartObservingMediaRoutes_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_StartObservingMediaRoutes_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_StartObservingMediaRoutes_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_StartObservingMediaRoutes_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_StartObservingMediaRoutes_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
  };
  function MediaRouteProvider_StopObservingMediaRoutes_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_StopObservingMediaRoutes_Params.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 MediaRouteProvider_StopObservingMediaRoutes_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_StopObservingMediaRoutes_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_StopObservingMediaRoutes_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_StopObservingMediaRoutes_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_StopObservingMediaRoutes_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_StopObservingMediaRoutes_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
  };
  function MediaRouteProvider_StartListeningForRouteMessages_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_StartListeningForRouteMessages_Params.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 MediaRouteProvider_StartListeningForRouteMessages_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_StartListeningForRouteMessages_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_StartListeningForRouteMessages_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_StartListeningForRouteMessages_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_StartListeningForRouteMessages_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_StartListeningForRouteMessages_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
  };
  function MediaRouteProvider_StopListeningForRouteMessages_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_StopListeningForRouteMessages_Params.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 MediaRouteProvider_StopListeningForRouteMessages_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_StopListeningForRouteMessages_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_StopListeningForRouteMessages_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_StopListeningForRouteMessages_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_StopListeningForRouteMessages_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_StopListeningForRouteMessages_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
  };
  function MediaRouteProvider_DetachRoute_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_DetachRoute_Params.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 MediaRouteProvider_DetachRoute_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_DetachRoute_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_DetachRoute_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_DetachRoute_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_DetachRoute_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_DetachRoute_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
  };
  function MediaRouteProvider_EnableMdnsDiscovery_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_EnableMdnsDiscovery_Params.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;
  };

  MediaRouteProvider_EnableMdnsDiscovery_Params.encodedSize = codec.kStructHeaderSize + 0;

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

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


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

  MediaRouteProvider_UpdateMediaSinks_Params.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 MediaRouteProvider_UpdateMediaSinks_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_UpdateMediaSinks_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_UpdateMediaSinks_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_UpdateMediaSinks_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.mediaSource = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_UpdateMediaSinks_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_UpdateMediaSinks_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.mediaSource);
  };
  function MediaRouteProvider_SearchSinks_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_SearchSinks_Params.prototype.initDefaults_ = function() {
    this.sinkId = null;
    this.mediaSource = null;
    this.searchCriteria = null;
  };
  MediaRouteProvider_SearchSinks_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_SearchSinks_Params.sinkId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaRouteProvider_SearchSinks_Params.searchCriteria
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 16, SinkSearchCriteria, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_SearchSinks_Params.encodedSize = codec.kStructHeaderSize + 24;

  MediaRouteProvider_SearchSinks_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_SearchSinks_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.sinkId = decoder.decodeStruct(codec.String);
    val.mediaSource = decoder.decodeStruct(codec.String);
    val.searchCriteria = decoder.decodeStructPointer(SinkSearchCriteria);
    return val;
  };

  MediaRouteProvider_SearchSinks_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_SearchSinks_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.sinkId);
    encoder.encodeStruct(codec.String, val.mediaSource);
    encoder.encodeStructPointer(SinkSearchCriteria, val.searchCriteria);
  };
  function MediaRouteProvider_SearchSinks_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_SearchSinks_ResponseParams.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 MediaRouteProvider_SearchSinks_ResponseParams.sinkId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_SearchSinks_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_SearchSinks_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_SearchSinks_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.sinkId = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouteProvider_SearchSinks_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_SearchSinks_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.sinkId);
  };
  function MediaRouteProvider_ProvideSinks_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_ProvideSinks_Params.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 MediaRouteProvider_ProvideSinks_Params.providerName
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_ProvideSinks_Params.sinks
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 8, 8, new codec.PointerTo(MediaSink), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_ProvideSinks_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouteProvider_ProvideSinks_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_ProvideSinks_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.providerName = decoder.decodeStruct(codec.String);
    val.sinks = decoder.decodeArrayPointer(new codec.PointerTo(MediaSink));
    return val;
  };

  MediaRouteProvider_ProvideSinks_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_ProvideSinks_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.providerName);
    encoder.encodeArrayPointer(new codec.PointerTo(MediaSink), val.sinks);
  };
  function MediaRouteProvider_CreateMediaRouteController_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouteProvider_CreateMediaRouteController_Params.prototype.initDefaults_ = function() {
    this.routeId = null;
    this.mediaController = new bindings.InterfaceRequest();
    this.observer = new media_status$.MediaStatusObserverPtr();
  };
  MediaRouteProvider_CreateMediaRouteController_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouteProvider_CreateMediaRouteController_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_CreateMediaRouteController_Params.mediaController
    err = messageValidator.validateInterfaceRequest(offset + codec.kStructHeaderSize + 8, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouteProvider_CreateMediaRouteController_Params.observer
    err = messageValidator.validateInterface(offset + codec.kStructHeaderSize + 12, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouteProvider_CreateMediaRouteController_Params.encodedSize = codec.kStructHeaderSize + 24;

  MediaRouteProvider_CreateMediaRouteController_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_CreateMediaRouteController_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    val.mediaController = decoder.decodeStruct(codec.InterfaceRequest);
    val.observer = decoder.decodeStruct(new codec.Interface(media_status$.MediaStatusObserverPtr));
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_CreateMediaRouteController_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_CreateMediaRouteController_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
    encoder.encodeStruct(codec.InterfaceRequest, val.mediaController);
    encoder.encodeStruct(new codec.Interface(media_status$.MediaStatusObserverPtr), val.observer);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouteProvider_CreateMediaRouteController_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouteProvider_CreateMediaRouteController_ResponseParams.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;
  };

  MediaRouteProvider_CreateMediaRouteController_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouteProvider_CreateMediaRouteController_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouteProvider_CreateMediaRouteController_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.success = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouteProvider_CreateMediaRouteController_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouteProvider_CreateMediaRouteController_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.success & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouter_RegisterMediaRouteProvider_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouter_RegisterMediaRouteProvider_Params.prototype.initDefaults_ = function() {
    this.providerId = 0;
    this.mediaRouterProvider = new MediaRouteProviderPtr();
  };
  MediaRouter_RegisterMediaRouteProvider_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  MediaRouter_RegisterMediaRouteProvider_Params.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 MediaRouter_RegisterMediaRouteProvider_Params.providerId
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, MediaRouteProvider.Id);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_RegisterMediaRouteProvider_Params.mediaRouterProvider
    err = messageValidator.validateInterface(offset + codec.kStructHeaderSize + 4, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_RegisterMediaRouteProvider_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouter_RegisterMediaRouteProvider_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_RegisterMediaRouteProvider_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.providerId = decoder.decodeStruct(codec.Int32);
    val.mediaRouterProvider = decoder.decodeStruct(new codec.Interface(MediaRouteProviderPtr));
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouter_RegisterMediaRouteProvider_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_RegisterMediaRouteProvider_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.providerId);
    encoder.encodeStruct(new codec.Interface(MediaRouteProviderPtr), val.mediaRouterProvider);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouter_RegisterMediaRouteProvider_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouter_RegisterMediaRouteProvider_ResponseParams.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 MediaRouter_RegisterMediaRouteProvider_ResponseParams.instanceId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_RegisterMediaRouteProvider_ResponseParams.config
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 8, MediaRouteProviderConfig, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_RegisterMediaRouteProvider_ResponseParams.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouter_RegisterMediaRouteProvider_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_RegisterMediaRouteProvider_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.instanceId = decoder.decodeStruct(codec.String);
    val.config = decoder.decodeStructPointer(MediaRouteProviderConfig);
    return val;
  };

  MediaRouter_RegisterMediaRouteProvider_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_RegisterMediaRouteProvider_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.instanceId);
    encoder.encodeStructPointer(MediaRouteProviderConfig, val.config);
  };
  function MediaRouter_OnSinksReceived_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouter_OnSinksReceived_Params.prototype.initDefaults_ = function() {
    this.providerId = 0;
    this.mediaSource = null;
    this.sinks = null;
    this.origins = null;
  };
  MediaRouter_OnSinksReceived_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouter_OnSinksReceived_Params.providerId
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, MediaRouteProvider.Id);
    if (err !== validator.validationError.NONE)
        return err;


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


    // validate MediaRouter_OnSinksReceived_Params.sinks
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 16, 8, new codec.PointerTo(MediaSink), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnSinksReceived_Params.origins
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 24, 8, new codec.PointerTo(origin$.Origin), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnSinksReceived_Params.encodedSize = codec.kStructHeaderSize + 32;

  MediaRouter_OnSinksReceived_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnSinksReceived_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.providerId = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.mediaSource = decoder.decodeStruct(codec.String);
    val.sinks = decoder.decodeArrayPointer(new codec.PointerTo(MediaSink));
    val.origins = decoder.decodeArrayPointer(new codec.PointerTo(origin$.Origin));
    return val;
  };

  MediaRouter_OnSinksReceived_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnSinksReceived_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.providerId);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.String, val.mediaSource);
    encoder.encodeArrayPointer(new codec.PointerTo(MediaSink), val.sinks);
    encoder.encodeArrayPointer(new codec.PointerTo(origin$.Origin), val.origins);
  };
  function MediaRouter_OnIssue_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouter_OnIssue_Params.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 MediaRouter_OnIssue_Params.issue
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, Issue, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnIssue_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouter_OnIssue_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnIssue_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.issue = decoder.decodeStructPointer(Issue);
    return val;
  };

  MediaRouter_OnIssue_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnIssue_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(Issue, val.issue);
  };
  function MediaRouter_OnRoutesUpdated_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouter_OnRoutesUpdated_Params.prototype.initDefaults_ = function() {
    this.providerId = 0;
    this.routes = null;
    this.mediaSource = null;
    this.joinableRouteIds = null;
  };
  MediaRouter_OnRoutesUpdated_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouter_OnRoutesUpdated_Params.providerId
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, MediaRouteProvider.Id);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnRoutesUpdated_Params.routes
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 8, 8, new codec.PointerTo(MediaRoute), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnRoutesUpdated_Params.mediaSource
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnRoutesUpdated_Params.joinableRouteIds
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 24, 8, codec.String, false, [0, 0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnRoutesUpdated_Params.encodedSize = codec.kStructHeaderSize + 32;

  MediaRouter_OnRoutesUpdated_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnRoutesUpdated_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.providerId = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.routes = decoder.decodeArrayPointer(new codec.PointerTo(MediaRoute));
    val.mediaSource = decoder.decodeStruct(codec.String);
    val.joinableRouteIds = decoder.decodeArrayPointer(codec.String);
    return val;
  };

  MediaRouter_OnRoutesUpdated_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnRoutesUpdated_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.providerId);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeArrayPointer(new codec.PointerTo(MediaRoute), val.routes);
    encoder.encodeStruct(codec.String, val.mediaSource);
    encoder.encodeArrayPointer(codec.String, val.joinableRouteIds);
  };
  function MediaRouter_OnSinkAvailabilityUpdated_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouter_OnSinkAvailabilityUpdated_Params.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 MediaRouter_OnSinkAvailabilityUpdated_Params.providerId
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, MediaRouteProvider.Id);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnSinkAvailabilityUpdated_Params.availability
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 4, MediaRouter.SinkAvailability);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnSinkAvailabilityUpdated_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaRouter_OnSinkAvailabilityUpdated_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnSinkAvailabilityUpdated_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.providerId = decoder.decodeStruct(codec.Int32);
    val.availability = decoder.decodeStruct(codec.Int32);
    return val;
  };

  MediaRouter_OnSinkAvailabilityUpdated_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnSinkAvailabilityUpdated_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.providerId);
    encoder.encodeStruct(codec.Int32, val.availability);
  };
  function MediaRouter_OnPresentationConnectionStateChanged_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouter_OnPresentationConnectionStateChanged_Params.prototype.initDefaults_ = function() {
    this.routeId = null;
    this.state = 0;
  };
  MediaRouter_OnPresentationConnectionStateChanged_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  MediaRouter_OnPresentationConnectionStateChanged_Params.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 MediaRouter_OnPresentationConnectionStateChanged_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnPresentationConnectionStateChanged_Params.state
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 8, MediaRouter.PresentationConnectionState);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnPresentationConnectionStateChanged_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouter_OnPresentationConnectionStateChanged_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnPresentationConnectionStateChanged_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    val.state = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MediaRouter_OnPresentationConnectionStateChanged_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnPresentationConnectionStateChanged_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
    encoder.encodeStruct(codec.Int32, val.state);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaRouter_OnPresentationConnectionClosed_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouter_OnPresentationConnectionClosed_Params.prototype.initDefaults_ = function() {
    this.routeId = null;
    this.reason = 0;
    this.message = null;
  };
  MediaRouter_OnPresentationConnectionClosed_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaRouter_OnPresentationConnectionClosed_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnPresentationConnectionClosed_Params.reason
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 8, MediaRouter.PresentationConnectionCloseReason);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnPresentationConnectionClosed_Params.message
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnPresentationConnectionClosed_Params.encodedSize = codec.kStructHeaderSize + 24;

  MediaRouter_OnPresentationConnectionClosed_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnPresentationConnectionClosed_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    val.reason = decoder.decodeStruct(codec.Int32);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.message = decoder.decodeStruct(codec.String);
    return val;
  };

  MediaRouter_OnPresentationConnectionClosed_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnPresentationConnectionClosed_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
    encoder.encodeStruct(codec.Int32, val.reason);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.String, val.message);
  };
  function MediaRouter_OnRouteMessagesReceived_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaRouter_OnRouteMessagesReceived_Params.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 MediaRouter_OnRouteMessagesReceived_Params.routeId
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnRouteMessagesReceived_Params.messages
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 8, 8, new codec.PointerTo(RouteMessage), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnRouteMessagesReceived_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouter_OnRouteMessagesReceived_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnRouteMessagesReceived_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.routeId = decoder.decodeStruct(codec.String);
    val.messages = decoder.decodeArrayPointer(new codec.PointerTo(RouteMessage));
    return val;
  };

  MediaRouter_OnRouteMessagesReceived_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnRouteMessagesReceived_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.routeId);
    encoder.encodeArrayPointer(new codec.PointerTo(RouteMessage), val.messages);
  };
  function MediaRouter_OnMediaRemoterCreated_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


  MediaRouter_OnMediaRemoterCreated_Params.prototype.initDefaults_ = function() {
    this.tabId = 0;
    this.remoter = new mirror_service_remoting$.MirrorServiceRemoterPtr();
    this.remotingSource = new bindings.InterfaceRequest();
  };
  MediaRouter_OnMediaRemoterCreated_Params.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  MediaRouter_OnMediaRemoterCreated_Params.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 MediaRouter_OnMediaRemoterCreated_Params.remoter
    err = messageValidator.validateInterface(offset + codec.kStructHeaderSize + 4, false);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaRouter_OnMediaRemoterCreated_Params.remotingSource
    err = messageValidator.validateInterfaceRequest(offset + codec.kStructHeaderSize + 12, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaRouter_OnMediaRemoterCreated_Params.encodedSize = codec.kStructHeaderSize + 16;

  MediaRouter_OnMediaRemoterCreated_Params.decode = function(decoder) {
    var packed;
    var val = new MediaRouter_OnMediaRemoterCreated_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.tabId = decoder.decodeStruct(codec.Int32);
    val.remoter = decoder.decodeStruct(new codec.Interface(mirror_service_remoting$.MirrorServiceRemoterPtr));
    val.remotingSource = decoder.decodeStruct(codec.InterfaceRequest);
    return val;
  };

  MediaRouter_OnMediaRemoterCreated_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaRouter_OnMediaRemoterCreated_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.tabId);
    encoder.encodeStruct(new codec.Interface(mirror_service_remoting$.MirrorServiceRemoterPtr), val.remoter);
    encoder.encodeStruct(codec.InterfaceRequest, val.remotingSource);
  };

  function MediaSinkExtraData(value) {
    this.initDefault_();
    this.initValue_(value);
  }
  
  
  MediaSinkExtraData.Tags = {
    dialMediaSink: 0,
    castMediaSink: 1,
  };
  
  MediaSinkExtraData.prototype.initDefault_ = function() {
    this.$data = null;
    this.$tag = undefined;
  }
  
  MediaSinkExtraData.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 = [
        "dialMediaSink",
        "castMediaSink",
    ];
  
    if (fields.indexOf(keys[0]) < 0) {
      throw new ReferenceError(keys[0] + " is not a MediaSinkExtraData member.");
  
    }
  
    this[keys[0]] = value[keys[0]];
  }
  Object.defineProperty(MediaSinkExtraData.prototype, "dialMediaSink", {
    get: function() {
      if (this.$tag != MediaSinkExtraData.Tags.dialMediaSink) {
        throw new ReferenceError(
            "MediaSinkExtraData.dialMediaSink is not currently set.");
      }
      return this.$data;
    },
  
    set: function(value) {
      this.$tag = MediaSinkExtraData.Tags.dialMediaSink;
      this.$data = value;
    }
  });
  Object.defineProperty(MediaSinkExtraData.prototype, "castMediaSink", {
    get: function() {
      if (this.$tag != MediaSinkExtraData.Tags.castMediaSink) {
        throw new ReferenceError(
            "MediaSinkExtraData.castMediaSink is not currently set.");
      }
      return this.$data;
    },
  
    set: function(value) {
      this.$tag = MediaSinkExtraData.Tags.castMediaSink;
      this.$data = value;
    }
  });
  
  
    MediaSinkExtraData.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 MediaSinkExtraData.Tags.dialMediaSink:
          encoder.encodeStructPointer(DialMediaSink, val.dialMediaSink);
          break;
        case MediaSinkExtraData.Tags.castMediaSink:
          encoder.encodeStructPointer(CastMediaSink, val.castMediaSink);
          break;
      }
      encoder.align();
    };
  
  
    MediaSinkExtraData.decode = function(decoder) {
      var size = decoder.readUint32();
      if (size == 0) {
        decoder.readUint32();
        decoder.readUint64();
        return null;
      }
    
      var result = new MediaSinkExtraData();
      var tag = decoder.readUint32();
      switch (tag) {
        case MediaSinkExtraData.Tags.dialMediaSink:
          result.dialMediaSink = decoder.decodeStructPointer(DialMediaSink);
          break;
        case MediaSinkExtraData.Tags.castMediaSink:
          result.castMediaSink = decoder.decodeStructPointer(CastMediaSink);
          break;
      }
      decoder.align();
    
      return result;
    };
  
  
    MediaSinkExtraData.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 MediaSinkExtraData.Tags.dialMediaSink:
          
    
    // validate MediaSinkExtraData.dialMediaSink
    err = messageValidator.validateStructPointer(data_offset, DialMediaSink, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
        case MediaSinkExtraData.Tags.castMediaSink:
          
    
    // validate MediaSinkExtraData.castMediaSink
    err = messageValidator.validateStructPointer(data_offset, CastMediaSink, false);
    if (err !== validator.validationError.NONE)
        return err;
          break;
      }
    
      return validator.validationError.NONE;
    };
  
  MediaSinkExtraData.encodedSize = 16;
  var kMediaRouteProvider_CreateRoute_Name = 532762503;
  var kMediaRouteProvider_JoinRoute_Name = 2106021236;
  var kMediaRouteProvider_ConnectRouteByRouteId_Name = 1337330625;
  var kMediaRouteProvider_TerminateRoute_Name = 1446798134;
  var kMediaRouteProvider_SendRouteMessage_Name = 165525264;
  var kMediaRouteProvider_SendRouteBinaryMessage_Name = 1573256505;
  var kMediaRouteProvider_StartObservingMediaSinks_Name = 541421523;
  var kMediaRouteProvider_StopObservingMediaSinks_Name = 837606112;
  var kMediaRouteProvider_StartObservingMediaRoutes_Name = 135291614;
  var kMediaRouteProvider_StopObservingMediaRoutes_Name = 1922660390;
  var kMediaRouteProvider_StartListeningForRouteMessages_Name = 1098695957;
  var kMediaRouteProvider_StopListeningForRouteMessages_Name = 1641046848;
  var kMediaRouteProvider_DetachRoute_Name = 1832892794;
  var kMediaRouteProvider_EnableMdnsDiscovery_Name = 1287884081;
  var kMediaRouteProvider_UpdateMediaSinks_Name = 2013107007;
  var kMediaRouteProvider_SearchSinks_Name = 636267362;
  var kMediaRouteProvider_ProvideSinks_Name = 338192070;
  var kMediaRouteProvider_CreateMediaRouteController_Name = 1740134779;

  function MediaRouteProviderPtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(MediaRouteProvider,
                                                   handleOrPtrInfo);
  }

  function MediaRouteProviderAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        MediaRouteProvider, associatedInterfacePtrInfo);
  }

  MediaRouteProviderAssociatedPtr.prototype =
      Object.create(MediaRouteProviderPtr.prototype);
  MediaRouteProviderAssociatedPtr.prototype.constructor =
      MediaRouteProviderAssociatedPtr;

  function MediaRouteProviderProxy(receiver) {
    this.receiver_ = receiver;
  }
  MediaRouteProviderPtr.prototype.createRoute = function() {
    return MediaRouteProviderProxy.prototype.createRoute
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.createRoute = function(mediaSource, sinkId, originalPresentationId, origin, tabId, timeout, incognito) {
    var params = new MediaRouteProvider_CreateRoute_Params();
    params.mediaSource = mediaSource;
    params.sinkId = sinkId;
    params.originalPresentationId = originalPresentationId;
    params.origin = origin;
    params.tabId = tabId;
    params.timeout = timeout;
    params.incognito = incognito;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_CreateRoute_Name,
          codec.align(MediaRouteProvider_CreateRoute_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_CreateRoute_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_CreateRoute_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.joinRoute = function() {
    return MediaRouteProviderProxy.prototype.joinRoute
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.joinRoute = function(mediaSource, presentationId, origin, tabId, timeout, incognito) {
    var params = new MediaRouteProvider_JoinRoute_Params();
    params.mediaSource = mediaSource;
    params.presentationId = presentationId;
    params.origin = origin;
    params.tabId = tabId;
    params.timeout = timeout;
    params.incognito = incognito;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_JoinRoute_Name,
          codec.align(MediaRouteProvider_JoinRoute_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_JoinRoute_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_JoinRoute_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.connectRouteByRouteId = function() {
    return MediaRouteProviderProxy.prototype.connectRouteByRouteId
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.connectRouteByRouteId = function(mediaSource, routeId, presentationId, origin, tabId, timeout, incognito) {
    var params = new MediaRouteProvider_ConnectRouteByRouteId_Params();
    params.mediaSource = mediaSource;
    params.routeId = routeId;
    params.presentationId = presentationId;
    params.origin = origin;
    params.tabId = tabId;
    params.timeout = timeout;
    params.incognito = incognito;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_ConnectRouteByRouteId_Name,
          codec.align(MediaRouteProvider_ConnectRouteByRouteId_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_ConnectRouteByRouteId_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_ConnectRouteByRouteId_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.terminateRoute = function() {
    return MediaRouteProviderProxy.prototype.terminateRoute
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.terminateRoute = function(routeId) {
    var params = new MediaRouteProvider_TerminateRoute_Params();
    params.routeId = routeId;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_TerminateRoute_Name,
          codec.align(MediaRouteProvider_TerminateRoute_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_TerminateRoute_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_TerminateRoute_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.sendRouteMessage = function() {
    return MediaRouteProviderProxy.prototype.sendRouteMessage
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.sendRouteMessage = function(mediaRouteId, message) {
    var params = new MediaRouteProvider_SendRouteMessage_Params();
    params.mediaRouteId = mediaRouteId;
    params.message = message;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_SendRouteMessage_Name,
          codec.align(MediaRouteProvider_SendRouteMessage_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_SendRouteMessage_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_SendRouteMessage_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.sendRouteBinaryMessage = function() {
    return MediaRouteProviderProxy.prototype.sendRouteBinaryMessage
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.sendRouteBinaryMessage = function(mediaRouteId, data) {
    var params = new MediaRouteProvider_SendRouteBinaryMessage_Params();
    params.mediaRouteId = mediaRouteId;
    params.data = data;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_SendRouteBinaryMessage_Name,
          codec.align(MediaRouteProvider_SendRouteBinaryMessage_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_SendRouteBinaryMessage_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_SendRouteBinaryMessage_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.startObservingMediaSinks = function() {
    return MediaRouteProviderProxy.prototype.startObservingMediaSinks
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.startObservingMediaSinks = function(mediaSource) {
    var params = new MediaRouteProvider_StartObservingMediaSinks_Params();
    params.mediaSource = mediaSource;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_StartObservingMediaSinks_Name,
        codec.align(MediaRouteProvider_StartObservingMediaSinks_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_StartObservingMediaSinks_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.stopObservingMediaSinks = function() {
    return MediaRouteProviderProxy.prototype.stopObservingMediaSinks
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.stopObservingMediaSinks = function(mediaSource) {
    var params = new MediaRouteProvider_StopObservingMediaSinks_Params();
    params.mediaSource = mediaSource;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_StopObservingMediaSinks_Name,
        codec.align(MediaRouteProvider_StopObservingMediaSinks_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_StopObservingMediaSinks_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.startObservingMediaRoutes = function() {
    return MediaRouteProviderProxy.prototype.startObservingMediaRoutes
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.startObservingMediaRoutes = function(mediaSource) {
    var params = new MediaRouteProvider_StartObservingMediaRoutes_Params();
    params.mediaSource = mediaSource;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_StartObservingMediaRoutes_Name,
        codec.align(MediaRouteProvider_StartObservingMediaRoutes_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_StartObservingMediaRoutes_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.stopObservingMediaRoutes = function() {
    return MediaRouteProviderProxy.prototype.stopObservingMediaRoutes
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.stopObservingMediaRoutes = function(mediaSource) {
    var params = new MediaRouteProvider_StopObservingMediaRoutes_Params();
    params.mediaSource = mediaSource;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_StopObservingMediaRoutes_Name,
        codec.align(MediaRouteProvider_StopObservingMediaRoutes_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_StopObservingMediaRoutes_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.startListeningForRouteMessages = function() {
    return MediaRouteProviderProxy.prototype.startListeningForRouteMessages
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.startListeningForRouteMessages = function(routeId) {
    var params = new MediaRouteProvider_StartListeningForRouteMessages_Params();
    params.routeId = routeId;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_StartListeningForRouteMessages_Name,
        codec.align(MediaRouteProvider_StartListeningForRouteMessages_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_StartListeningForRouteMessages_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.stopListeningForRouteMessages = function() {
    return MediaRouteProviderProxy.prototype.stopListeningForRouteMessages
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.stopListeningForRouteMessages = function(routeId) {
    var params = new MediaRouteProvider_StopListeningForRouteMessages_Params();
    params.routeId = routeId;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_StopListeningForRouteMessages_Name,
        codec.align(MediaRouteProvider_StopListeningForRouteMessages_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_StopListeningForRouteMessages_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.detachRoute = function() {
    return MediaRouteProviderProxy.prototype.detachRoute
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.detachRoute = function(routeId) {
    var params = new MediaRouteProvider_DetachRoute_Params();
    params.routeId = routeId;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_DetachRoute_Name,
        codec.align(MediaRouteProvider_DetachRoute_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_DetachRoute_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.enableMdnsDiscovery = function() {
    return MediaRouteProviderProxy.prototype.enableMdnsDiscovery
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.enableMdnsDiscovery = function() {
    var params = new MediaRouteProvider_EnableMdnsDiscovery_Params();
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_EnableMdnsDiscovery_Name,
        codec.align(MediaRouteProvider_EnableMdnsDiscovery_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_EnableMdnsDiscovery_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.updateMediaSinks = function() {
    return MediaRouteProviderProxy.prototype.updateMediaSinks
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.updateMediaSinks = function(mediaSource) {
    var params = new MediaRouteProvider_UpdateMediaSinks_Params();
    params.mediaSource = mediaSource;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_UpdateMediaSinks_Name,
        codec.align(MediaRouteProvider_UpdateMediaSinks_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_UpdateMediaSinks_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.searchSinks = function() {
    return MediaRouteProviderProxy.prototype.searchSinks
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.searchSinks = function(sinkId, mediaSource, searchCriteria) {
    var params = new MediaRouteProvider_SearchSinks_Params();
    params.sinkId = sinkId;
    params.mediaSource = mediaSource;
    params.searchCriteria = searchCriteria;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_SearchSinks_Name,
          codec.align(MediaRouteProvider_SearchSinks_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_SearchSinks_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_SearchSinks_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouteProviderPtr.prototype.provideSinks = function() {
    return MediaRouteProviderProxy.prototype.provideSinks
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.provideSinks = function(providerName, sinks) {
    var params = new MediaRouteProvider_ProvideSinks_Params();
    params.providerName = providerName;
    params.sinks = sinks;
    var builder = new codec.MessageV0Builder(
        kMediaRouteProvider_ProvideSinks_Name,
        codec.align(MediaRouteProvider_ProvideSinks_Params.encodedSize));
    builder.encodeStruct(MediaRouteProvider_ProvideSinks_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouteProviderPtr.prototype.createMediaRouteController = function() {
    return MediaRouteProviderProxy.prototype.createMediaRouteController
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouteProviderProxy.prototype.createMediaRouteController = function(routeId, mediaController, observer) {
    var params = new MediaRouteProvider_CreateMediaRouteController_Params();
    params.routeId = routeId;
    params.mediaController = mediaController;
    params.observer = observer;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouteProvider_CreateMediaRouteController_Name,
          codec.align(MediaRouteProvider_CreateMediaRouteController_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouteProvider_CreateMediaRouteController_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouteProvider_CreateMediaRouteController_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };

  function MediaRouteProviderStub(delegate) {
    this.delegate_ = delegate;
  }
  MediaRouteProviderStub.prototype.createRoute = function(mediaSource, sinkId, originalPresentationId, origin, tabId, timeout, incognito) {
    return this.delegate_ && this.delegate_.createRoute && this.delegate_.createRoute(mediaSource, sinkId, originalPresentationId, origin, tabId, timeout, incognito);
  }
  MediaRouteProviderStub.prototype.joinRoute = function(mediaSource, presentationId, origin, tabId, timeout, incognito) {
    return this.delegate_ && this.delegate_.joinRoute && this.delegate_.joinRoute(mediaSource, presentationId, origin, tabId, timeout, incognito);
  }
  MediaRouteProviderStub.prototype.connectRouteByRouteId = function(mediaSource, routeId, presentationId, origin, tabId, timeout, incognito) {
    return this.delegate_ && this.delegate_.connectRouteByRouteId && this.delegate_.connectRouteByRouteId(mediaSource, routeId, presentationId, origin, tabId, timeout, incognito);
  }
  MediaRouteProviderStub.prototype.terminateRoute = function(routeId) {
    return this.delegate_ && this.delegate_.terminateRoute && this.delegate_.terminateRoute(routeId);
  }
  MediaRouteProviderStub.prototype.sendRouteMessage = function(mediaRouteId, message) {
    return this.delegate_ && this.delegate_.sendRouteMessage && this.delegate_.sendRouteMessage(mediaRouteId, message);
  }
  MediaRouteProviderStub.prototype.sendRouteBinaryMessage = function(mediaRouteId, data) {
    return this.delegate_ && this.delegate_.sendRouteBinaryMessage && this.delegate_.sendRouteBinaryMessage(mediaRouteId, data);
  }
  MediaRouteProviderStub.prototype.startObservingMediaSinks = function(mediaSource) {
    return this.delegate_ && this.delegate_.startObservingMediaSinks && this.delegate_.startObservingMediaSinks(mediaSource);
  }
  MediaRouteProviderStub.prototype.stopObservingMediaSinks = function(mediaSource) {
    return this.delegate_ && this.delegate_.stopObservingMediaSinks && this.delegate_.stopObservingMediaSinks(mediaSource);
  }
  MediaRouteProviderStub.prototype.startObservingMediaRoutes = function(mediaSource) {
    return this.delegate_ && this.delegate_.startObservingMediaRoutes && this.delegate_.startObservingMediaRoutes(mediaSource);
  }
  MediaRouteProviderStub.prototype.stopObservingMediaRoutes = function(mediaSource) {
    return this.delegate_ && this.delegate_.stopObservingMediaRoutes && this.delegate_.stopObservingMediaRoutes(mediaSource);
  }
  MediaRouteProviderStub.prototype.startListeningForRouteMessages = function(routeId) {
    return this.delegate_ && this.delegate_.startListeningForRouteMessages && this.delegate_.startListeningForRouteMessages(routeId);
  }
  MediaRouteProviderStub.prototype.stopListeningForRouteMessages = function(routeId) {
    return this.delegate_ && this.delegate_.stopListeningForRouteMessages && this.delegate_.stopListeningForRouteMessages(routeId);
  }
  MediaRouteProviderStub.prototype.detachRoute = function(routeId) {
    return this.delegate_ && this.delegate_.detachRoute && this.delegate_.detachRoute(routeId);
  }
  MediaRouteProviderStub.prototype.enableMdnsDiscovery = function() {
    return this.delegate_ && this.delegate_.enableMdnsDiscovery && this.delegate_.enableMdnsDiscovery();
  }
  MediaRouteProviderStub.prototype.updateMediaSinks = function(mediaSource) {
    return this.delegate_ && this.delegate_.updateMediaSinks && this.delegate_.updateMediaSinks(mediaSource);
  }
  MediaRouteProviderStub.prototype.searchSinks = function(sinkId, mediaSource, searchCriteria) {
    return this.delegate_ && this.delegate_.searchSinks && this.delegate_.searchSinks(sinkId, mediaSource, searchCriteria);
  }
  MediaRouteProviderStub.prototype.provideSinks = function(providerName, sinks) {
    return this.delegate_ && this.delegate_.provideSinks && this.delegate_.provideSinks(providerName, sinks);
  }
  MediaRouteProviderStub.prototype.createMediaRouteController = function(routeId, mediaController, observer) {
    return this.delegate_ && this.delegate_.createMediaRouteController && this.delegate_.createMediaRouteController(routeId, mediaController, observer);
  }

  MediaRouteProviderStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMediaRouteProvider_StartObservingMediaSinks_Name:
      var params = reader.decodeStruct(MediaRouteProvider_StartObservingMediaSinks_Params);
      this.startObservingMediaSinks(params.mediaSource);
      return true;
    case kMediaRouteProvider_StopObservingMediaSinks_Name:
      var params = reader.decodeStruct(MediaRouteProvider_StopObservingMediaSinks_Params);
      this.stopObservingMediaSinks(params.mediaSource);
      return true;
    case kMediaRouteProvider_StartObservingMediaRoutes_Name:
      var params = reader.decodeStruct(MediaRouteProvider_StartObservingMediaRoutes_Params);
      this.startObservingMediaRoutes(params.mediaSource);
      return true;
    case kMediaRouteProvider_StopObservingMediaRoutes_Name:
      var params = reader.decodeStruct(MediaRouteProvider_StopObservingMediaRoutes_Params);
      this.stopObservingMediaRoutes(params.mediaSource);
      return true;
    case kMediaRouteProvider_StartListeningForRouteMessages_Name:
      var params = reader.decodeStruct(MediaRouteProvider_StartListeningForRouteMessages_Params);
      this.startListeningForRouteMessages(params.routeId);
      return true;
    case kMediaRouteProvider_StopListeningForRouteMessages_Name:
      var params = reader.decodeStruct(MediaRouteProvider_StopListeningForRouteMessages_Params);
      this.stopListeningForRouteMessages(params.routeId);
      return true;
    case kMediaRouteProvider_DetachRoute_Name:
      var params = reader.decodeStruct(MediaRouteProvider_DetachRoute_Params);
      this.detachRoute(params.routeId);
      return true;
    case kMediaRouteProvider_EnableMdnsDiscovery_Name:
      var params = reader.decodeStruct(MediaRouteProvider_EnableMdnsDiscovery_Params);
      this.enableMdnsDiscovery();
      return true;
    case kMediaRouteProvider_UpdateMediaSinks_Name:
      var params = reader.decodeStruct(MediaRouteProvider_UpdateMediaSinks_Params);
      this.updateMediaSinks(params.mediaSource);
      return true;
    case kMediaRouteProvider_ProvideSinks_Name:
      var params = reader.decodeStruct(MediaRouteProvider_ProvideSinks_Params);
      this.provideSinks(params.providerName, params.sinks);
      return true;
    default:
      return false;
    }
  };

  MediaRouteProviderStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMediaRouteProvider_CreateRoute_Name:
      var params = reader.decodeStruct(MediaRouteProvider_CreateRoute_Params);
      this.createRoute(params.mediaSource, params.sinkId, params.originalPresentationId, params.origin, params.tabId, params.timeout, params.incognito).then(function(response) {
        var responseParams =
            new MediaRouteProvider_CreateRoute_ResponseParams();
        responseParams.route = response.route;
        responseParams.errorText = response.errorText;
        responseParams.resultCode = response.resultCode;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_CreateRoute_Name,
            codec.align(MediaRouteProvider_CreateRoute_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_CreateRoute_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_JoinRoute_Name:
      var params = reader.decodeStruct(MediaRouteProvider_JoinRoute_Params);
      this.joinRoute(params.mediaSource, params.presentationId, params.origin, params.tabId, params.timeout, params.incognito).then(function(response) {
        var responseParams =
            new MediaRouteProvider_JoinRoute_ResponseParams();
        responseParams.route = response.route;
        responseParams.errorText = response.errorText;
        responseParams.resultCode = response.resultCode;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_JoinRoute_Name,
            codec.align(MediaRouteProvider_JoinRoute_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_JoinRoute_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_ConnectRouteByRouteId_Name:
      var params = reader.decodeStruct(MediaRouteProvider_ConnectRouteByRouteId_Params);
      this.connectRouteByRouteId(params.mediaSource, params.routeId, params.presentationId, params.origin, params.tabId, params.timeout, params.incognito).then(function(response) {
        var responseParams =
            new MediaRouteProvider_ConnectRouteByRouteId_ResponseParams();
        responseParams.route = response.route;
        responseParams.errorText = response.errorText;
        responseParams.resultCode = response.resultCode;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_ConnectRouteByRouteId_Name,
            codec.align(MediaRouteProvider_ConnectRouteByRouteId_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_ConnectRouteByRouteId_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_TerminateRoute_Name:
      var params = reader.decodeStruct(MediaRouteProvider_TerminateRoute_Params);
      this.terminateRoute(params.routeId).then(function(response) {
        var responseParams =
            new MediaRouteProvider_TerminateRoute_ResponseParams();
        responseParams.errorText = response.errorText;
        responseParams.resultCode = response.resultCode;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_TerminateRoute_Name,
            codec.align(MediaRouteProvider_TerminateRoute_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_TerminateRoute_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_SendRouteMessage_Name:
      var params = reader.decodeStruct(MediaRouteProvider_SendRouteMessage_Params);
      this.sendRouteMessage(params.mediaRouteId, params.message).then(function(response) {
        var responseParams =
            new MediaRouteProvider_SendRouteMessage_ResponseParams();
        responseParams.sent = response.sent;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_SendRouteMessage_Name,
            codec.align(MediaRouteProvider_SendRouteMessage_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_SendRouteMessage_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_SendRouteBinaryMessage_Name:
      var params = reader.decodeStruct(MediaRouteProvider_SendRouteBinaryMessage_Params);
      this.sendRouteBinaryMessage(params.mediaRouteId, params.data).then(function(response) {
        var responseParams =
            new MediaRouteProvider_SendRouteBinaryMessage_ResponseParams();
        responseParams.sent = response.sent;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_SendRouteBinaryMessage_Name,
            codec.align(MediaRouteProvider_SendRouteBinaryMessage_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_SendRouteBinaryMessage_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_SearchSinks_Name:
      var params = reader.decodeStruct(MediaRouteProvider_SearchSinks_Params);
      this.searchSinks(params.sinkId, params.mediaSource, params.searchCriteria).then(function(response) {
        var responseParams =
            new MediaRouteProvider_SearchSinks_ResponseParams();
        responseParams.sinkId = response.sinkId;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_SearchSinks_Name,
            codec.align(MediaRouteProvider_SearchSinks_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_SearchSinks_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMediaRouteProvider_CreateMediaRouteController_Name:
      var params = reader.decodeStruct(MediaRouteProvider_CreateMediaRouteController_Params);
      this.createMediaRouteController(params.routeId, params.mediaController, params.observer).then(function(response) {
        var responseParams =
            new MediaRouteProvider_CreateMediaRouteController_ResponseParams();
        responseParams.success = response.success;
        var builder = new codec.MessageV1Builder(
            kMediaRouteProvider_CreateMediaRouteController_Name,
            codec.align(MediaRouteProvider_CreateMediaRouteController_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouteProvider_CreateMediaRouteController_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    default:
      return false;
    }
  };

  function validateMediaRouteProviderRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kMediaRouteProvider_CreateRoute_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_CreateRoute_Params;
      break;
      case kMediaRouteProvider_JoinRoute_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_JoinRoute_Params;
      break;
      case kMediaRouteProvider_ConnectRouteByRouteId_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_ConnectRouteByRouteId_Params;
      break;
      case kMediaRouteProvider_TerminateRoute_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_TerminateRoute_Params;
      break;
      case kMediaRouteProvider_SendRouteMessage_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_SendRouteMessage_Params;
      break;
      case kMediaRouteProvider_SendRouteBinaryMessage_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_SendRouteBinaryMessage_Params;
      break;
      case kMediaRouteProvider_StartObservingMediaSinks_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_StartObservingMediaSinks_Params;
      break;
      case kMediaRouteProvider_StopObservingMediaSinks_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_StopObservingMediaSinks_Params;
      break;
      case kMediaRouteProvider_StartObservingMediaRoutes_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_StartObservingMediaRoutes_Params;
      break;
      case kMediaRouteProvider_StopObservingMediaRoutes_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_StopObservingMediaRoutes_Params;
      break;
      case kMediaRouteProvider_StartListeningForRouteMessages_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_StartListeningForRouteMessages_Params;
      break;
      case kMediaRouteProvider_StopListeningForRouteMessages_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_StopListeningForRouteMessages_Params;
      break;
      case kMediaRouteProvider_DetachRoute_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_DetachRoute_Params;
      break;
      case kMediaRouteProvider_EnableMdnsDiscovery_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_EnableMdnsDiscovery_Params;
      break;
      case kMediaRouteProvider_UpdateMediaSinks_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_UpdateMediaSinks_Params;
      break;
      case kMediaRouteProvider_SearchSinks_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_SearchSinks_Params;
      break;
      case kMediaRouteProvider_ProvideSinks_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouteProvider_ProvideSinks_Params;
      break;
      case kMediaRouteProvider_CreateMediaRouteController_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouteProvider_CreateMediaRouteController_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateMediaRouteProviderResponse(messageValidator) {
   var message = messageValidator.message;
   var paramsClass = null;
   switch (message.getName()) {
      case kMediaRouteProvider_CreateRoute_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_CreateRoute_ResponseParams;
        break;
      case kMediaRouteProvider_JoinRoute_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_JoinRoute_ResponseParams;
        break;
      case kMediaRouteProvider_ConnectRouteByRouteId_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_ConnectRouteByRouteId_ResponseParams;
        break;
      case kMediaRouteProvider_TerminateRoute_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_TerminateRoute_ResponseParams;
        break;
      case kMediaRouteProvider_SendRouteMessage_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_SendRouteMessage_ResponseParams;
        break;
      case kMediaRouteProvider_SendRouteBinaryMessage_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_SendRouteBinaryMessage_ResponseParams;
        break;
      case kMediaRouteProvider_SearchSinks_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_SearchSinks_ResponseParams;
        break;
      case kMediaRouteProvider_CreateMediaRouteController_Name:
        if (message.isResponse())
          paramsClass = MediaRouteProvider_CreateMediaRouteController_ResponseParams;
        break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  var MediaRouteProvider = {
    name: 'media_router::mojom::MediaRouteProvider',
    kVersion: 0,
    ptrClass: MediaRouteProviderPtr,
    proxyClass: MediaRouteProviderProxy,
    stubClass: MediaRouteProviderStub,
    validateRequest: validateMediaRouteProviderRequest,
    validateResponse: validateMediaRouteProviderResponse,
  };
  MediaRouteProvider.Id = {};
  MediaRouteProvider.Id.EXTENSION = 0;
  MediaRouteProvider.Id.WIRED_DISPLAY = MediaRouteProvider.Id.EXTENSION + 1;

  MediaRouteProvider.Id.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
      return true;
    }
    return false;
  };

  MediaRouteProvider.Id.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  MediaRouteProviderStub.prototype.validator = validateMediaRouteProviderRequest;
  MediaRouteProviderProxy.prototype.validator = validateMediaRouteProviderResponse;
  var kMediaRouter_RegisterMediaRouteProvider_Name = 1633404846;
  var kMediaRouter_OnSinksReceived_Name = 2015856829;
  var kMediaRouter_OnIssue_Name = 1759034049;
  var kMediaRouter_OnRoutesUpdated_Name = 2003346426;
  var kMediaRouter_OnSinkAvailabilityUpdated_Name = 2056392117;
  var kMediaRouter_OnPresentationConnectionStateChanged_Name = 1154951203;
  var kMediaRouter_OnPresentationConnectionClosed_Name = 426891386;
  var kMediaRouter_OnRouteMessagesReceived_Name = 1939797999;
  var kMediaRouter_OnMediaRemoterCreated_Name = 1740078423;

  function MediaRouterPtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(MediaRouter,
                                                   handleOrPtrInfo);
  }

  function MediaRouterAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        MediaRouter, associatedInterfacePtrInfo);
  }

  MediaRouterAssociatedPtr.prototype =
      Object.create(MediaRouterPtr.prototype);
  MediaRouterAssociatedPtr.prototype.constructor =
      MediaRouterAssociatedPtr;

  function MediaRouterProxy(receiver) {
    this.receiver_ = receiver;
  }
  MediaRouterPtr.prototype.registerMediaRouteProvider = function() {
    return MediaRouterProxy.prototype.registerMediaRouteProvider
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.registerMediaRouteProvider = function(providerId, mediaRouterProvider) {
    var params = new MediaRouter_RegisterMediaRouteProvider_Params();
    params.providerId = providerId;
    params.mediaRouterProvider = mediaRouterProvider;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMediaRouter_RegisterMediaRouteProvider_Name,
          codec.align(MediaRouter_RegisterMediaRouteProvider_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MediaRouter_RegisterMediaRouteProvider_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MediaRouter_RegisterMediaRouteProvider_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MediaRouterPtr.prototype.onSinksReceived = function() {
    return MediaRouterProxy.prototype.onSinksReceived
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onSinksReceived = function(providerId, mediaSource, sinks, origins) {
    var params = new MediaRouter_OnSinksReceived_Params();
    params.providerId = providerId;
    params.mediaSource = mediaSource;
    params.sinks = sinks;
    params.origins = origins;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnSinksReceived_Name,
        codec.align(MediaRouter_OnSinksReceived_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnSinksReceived_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onIssue = function() {
    return MediaRouterProxy.prototype.onIssue
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onIssue = function(issue) {
    var params = new MediaRouter_OnIssue_Params();
    params.issue = issue;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnIssue_Name,
        codec.align(MediaRouter_OnIssue_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnIssue_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onRoutesUpdated = function() {
    return MediaRouterProxy.prototype.onRoutesUpdated
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onRoutesUpdated = function(providerId, routes, mediaSource, joinableRouteIds) {
    var params = new MediaRouter_OnRoutesUpdated_Params();
    params.providerId = providerId;
    params.routes = routes;
    params.mediaSource = mediaSource;
    params.joinableRouteIds = joinableRouteIds;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnRoutesUpdated_Name,
        codec.align(MediaRouter_OnRoutesUpdated_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnRoutesUpdated_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onSinkAvailabilityUpdated = function() {
    return MediaRouterProxy.prototype.onSinkAvailabilityUpdated
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onSinkAvailabilityUpdated = function(providerId, availability) {
    var params = new MediaRouter_OnSinkAvailabilityUpdated_Params();
    params.providerId = providerId;
    params.availability = availability;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnSinkAvailabilityUpdated_Name,
        codec.align(MediaRouter_OnSinkAvailabilityUpdated_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnSinkAvailabilityUpdated_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onPresentationConnectionStateChanged = function() {
    return MediaRouterProxy.prototype.onPresentationConnectionStateChanged
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onPresentationConnectionStateChanged = function(routeId, state) {
    var params = new MediaRouter_OnPresentationConnectionStateChanged_Params();
    params.routeId = routeId;
    params.state = state;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnPresentationConnectionStateChanged_Name,
        codec.align(MediaRouter_OnPresentationConnectionStateChanged_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnPresentationConnectionStateChanged_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onPresentationConnectionClosed = function() {
    return MediaRouterProxy.prototype.onPresentationConnectionClosed
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onPresentationConnectionClosed = function(routeId, reason, message) {
    var params = new MediaRouter_OnPresentationConnectionClosed_Params();
    params.routeId = routeId;
    params.reason = reason;
    params.message = message;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnPresentationConnectionClosed_Name,
        codec.align(MediaRouter_OnPresentationConnectionClosed_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnPresentationConnectionClosed_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onRouteMessagesReceived = function() {
    return MediaRouterProxy.prototype.onRouteMessagesReceived
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onRouteMessagesReceived = function(routeId, messages) {
    var params = new MediaRouter_OnRouteMessagesReceived_Params();
    params.routeId = routeId;
    params.messages = messages;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnRouteMessagesReceived_Name,
        codec.align(MediaRouter_OnRouteMessagesReceived_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnRouteMessagesReceived_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MediaRouterPtr.prototype.onMediaRemoterCreated = function() {
    return MediaRouterProxy.prototype.onMediaRemoterCreated
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaRouterProxy.prototype.onMediaRemoterCreated = function(tabId, remoter, remotingSource) {
    var params = new MediaRouter_OnMediaRemoterCreated_Params();
    params.tabId = tabId;
    params.remoter = remoter;
    params.remotingSource = remotingSource;
    var builder = new codec.MessageV0Builder(
        kMediaRouter_OnMediaRemoterCreated_Name,
        codec.align(MediaRouter_OnMediaRemoterCreated_Params.encodedSize));
    builder.encodeStruct(MediaRouter_OnMediaRemoterCreated_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };

  function MediaRouterStub(delegate) {
    this.delegate_ = delegate;
  }
  MediaRouterStub.prototype.registerMediaRouteProvider = function(providerId, mediaRouterProvider) {
    return this.delegate_ && this.delegate_.registerMediaRouteProvider && this.delegate_.registerMediaRouteProvider(providerId, mediaRouterProvider);
  }
  MediaRouterStub.prototype.onSinksReceived = function(providerId, mediaSource, sinks, origins) {
    return this.delegate_ && this.delegate_.onSinksReceived && this.delegate_.onSinksReceived(providerId, mediaSource, sinks, origins);
  }
  MediaRouterStub.prototype.onIssue = function(issue) {
    return this.delegate_ && this.delegate_.onIssue && this.delegate_.onIssue(issue);
  }
  MediaRouterStub.prototype.onRoutesUpdated = function(providerId, routes, mediaSource, joinableRouteIds) {
    return this.delegate_ && this.delegate_.onRoutesUpdated && this.delegate_.onRoutesUpdated(providerId, routes, mediaSource, joinableRouteIds);
  }
  MediaRouterStub.prototype.onSinkAvailabilityUpdated = function(providerId, availability) {
    return this.delegate_ && this.delegate_.onSinkAvailabilityUpdated && this.delegate_.onSinkAvailabilityUpdated(providerId, availability);
  }
  MediaRouterStub.prototype.onPresentationConnectionStateChanged = function(routeId, state) {
    return this.delegate_ && this.delegate_.onPresentationConnectionStateChanged && this.delegate_.onPresentationConnectionStateChanged(routeId, state);
  }
  MediaRouterStub.prototype.onPresentationConnectionClosed = function(routeId, reason, message) {
    return this.delegate_ && this.delegate_.onPresentationConnectionClosed && this.delegate_.onPresentationConnectionClosed(routeId, reason, message);
  }
  MediaRouterStub.prototype.onRouteMessagesReceived = function(routeId, messages) {
    return this.delegate_ && this.delegate_.onRouteMessagesReceived && this.delegate_.onRouteMessagesReceived(routeId, messages);
  }
  MediaRouterStub.prototype.onMediaRemoterCreated = function(tabId, remoter, remotingSource) {
    return this.delegate_ && this.delegate_.onMediaRemoterCreated && this.delegate_.onMediaRemoterCreated(tabId, remoter, remotingSource);
  }

  MediaRouterStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMediaRouter_OnSinksReceived_Name:
      var params = reader.decodeStruct(MediaRouter_OnSinksReceived_Params);
      this.onSinksReceived(params.providerId, params.mediaSource, params.sinks, params.origins);
      return true;
    case kMediaRouter_OnIssue_Name:
      var params = reader.decodeStruct(MediaRouter_OnIssue_Params);
      this.onIssue(params.issue);
      return true;
    case kMediaRouter_OnRoutesUpdated_Name:
      var params = reader.decodeStruct(MediaRouter_OnRoutesUpdated_Params);
      this.onRoutesUpdated(params.providerId, params.routes, params.mediaSource, params.joinableRouteIds);
      return true;
    case kMediaRouter_OnSinkAvailabilityUpdated_Name:
      var params = reader.decodeStruct(MediaRouter_OnSinkAvailabilityUpdated_Params);
      this.onSinkAvailabilityUpdated(params.providerId, params.availability);
      return true;
    case kMediaRouter_OnPresentationConnectionStateChanged_Name:
      var params = reader.decodeStruct(MediaRouter_OnPresentationConnectionStateChanged_Params);
      this.onPresentationConnectionStateChanged(params.routeId, params.state);
      return true;
    case kMediaRouter_OnPresentationConnectionClosed_Name:
      var params = reader.decodeStruct(MediaRouter_OnPresentationConnectionClosed_Params);
      this.onPresentationConnectionClosed(params.routeId, params.reason, params.message);
      return true;
    case kMediaRouter_OnRouteMessagesReceived_Name:
      var params = reader.decodeStruct(MediaRouter_OnRouteMessagesReceived_Params);
      this.onRouteMessagesReceived(params.routeId, params.messages);
      return true;
    case kMediaRouter_OnMediaRemoterCreated_Name:
      var params = reader.decodeStruct(MediaRouter_OnMediaRemoterCreated_Params);
      this.onMediaRemoterCreated(params.tabId, params.remoter, params.remotingSource);
      return true;
    default:
      return false;
    }
  };

  MediaRouterStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMediaRouter_RegisterMediaRouteProvider_Name:
      var params = reader.decodeStruct(MediaRouter_RegisterMediaRouteProvider_Params);
      this.registerMediaRouteProvider(params.providerId, params.mediaRouterProvider).then(function(response) {
        var responseParams =
            new MediaRouter_RegisterMediaRouteProvider_ResponseParams();
        responseParams.instanceId = response.instanceId;
        responseParams.config = response.config;
        var builder = new codec.MessageV1Builder(
            kMediaRouter_RegisterMediaRouteProvider_Name,
            codec.align(MediaRouter_RegisterMediaRouteProvider_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MediaRouter_RegisterMediaRouteProvider_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    default:
      return false;
    }
  };

  function validateMediaRouterRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kMediaRouter_RegisterMediaRouteProvider_Name:
        if (message.expectsResponse())
          paramsClass = MediaRouter_RegisterMediaRouteProvider_Params;
      break;
      case kMediaRouter_OnSinksReceived_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnSinksReceived_Params;
      break;
      case kMediaRouter_OnIssue_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnIssue_Params;
      break;
      case kMediaRouter_OnRoutesUpdated_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnRoutesUpdated_Params;
      break;
      case kMediaRouter_OnSinkAvailabilityUpdated_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnSinkAvailabilityUpdated_Params;
      break;
      case kMediaRouter_OnPresentationConnectionStateChanged_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnPresentationConnectionStateChanged_Params;
      break;
      case kMediaRouter_OnPresentationConnectionClosed_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnPresentationConnectionClosed_Params;
      break;
      case kMediaRouter_OnRouteMessagesReceived_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnRouteMessagesReceived_Params;
      break;
      case kMediaRouter_OnMediaRemoterCreated_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaRouter_OnMediaRemoterCreated_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateMediaRouterResponse(messageValidator) {
   var message = messageValidator.message;
   var paramsClass = null;
   switch (message.getName()) {
      case kMediaRouter_RegisterMediaRouteProvider_Name:
        if (message.isResponse())
          paramsClass = MediaRouter_RegisterMediaRouteProvider_ResponseParams;
        break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  var MediaRouter = {
    name: 'media_router::mojom::MediaRouter',
    kVersion: 0,
    ptrClass: MediaRouterPtr,
    proxyClass: MediaRouterProxy,
    stubClass: MediaRouterStub,
    validateRequest: validateMediaRouterRequest,
    validateResponse: validateMediaRouterResponse,
  };
  MediaRouter.SinkAvailability = {};
  MediaRouter.SinkAvailability.UNAVAILABLE = 0;
  MediaRouter.SinkAvailability.PER_SOURCE = MediaRouter.SinkAvailability.UNAVAILABLE + 1;
  MediaRouter.SinkAvailability.AVAILABLE = MediaRouter.SinkAvailability.PER_SOURCE + 1;

  MediaRouter.SinkAvailability.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
      return true;
    }
    return false;
  };

  MediaRouter.SinkAvailability.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  MediaRouter.PresentationConnectionState = {};
  MediaRouter.PresentationConnectionState.CONNECTING = 0;
  MediaRouter.PresentationConnectionState.CONNECTED = MediaRouter.PresentationConnectionState.CONNECTING + 1;
  MediaRouter.PresentationConnectionState.CLOSED = MediaRouter.PresentationConnectionState.CONNECTED + 1;
  MediaRouter.PresentationConnectionState.TERMINATED = MediaRouter.PresentationConnectionState.CLOSED + 1;

  MediaRouter.PresentationConnectionState.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
    case 3:
      return true;
    }
    return false;
  };

  MediaRouter.PresentationConnectionState.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  MediaRouter.PresentationConnectionCloseReason = {};
  MediaRouter.PresentationConnectionCloseReason.CONNECTION_ERROR = 0;
  MediaRouter.PresentationConnectionCloseReason.CLOSED = MediaRouter.PresentationConnectionCloseReason.CONNECTION_ERROR + 1;
  MediaRouter.PresentationConnectionCloseReason.WENT_AWAY = MediaRouter.PresentationConnectionCloseReason.CLOSED + 1;

  MediaRouter.PresentationConnectionCloseReason.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
      return true;
    }
    return false;
  };

  MediaRouter.PresentationConnectionCloseReason.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  MediaRouterStub.prototype.validator = validateMediaRouterRequest;
  MediaRouterProxy.prototype.validator = validateMediaRouterResponse;
  exports.SinkIconType = SinkIconType;
  exports.RouteControllerType = RouteControllerType;
  exports.RouteRequestResultCode = RouteRequestResultCode;
  exports.MediaSink = MediaSink;
  exports.DialMediaSink = DialMediaSink;
  exports.CastMediaSink = CastMediaSink;
  exports.MediaRoute = MediaRoute;
  exports.Issue = Issue;
  exports.RouteMessage = RouteMessage;
  exports.SinkSearchCriteria = SinkSearchCriteria;
  exports.MediaRouteProviderConfig = MediaRouteProviderConfig;
  exports.MediaSinkExtraData = MediaSinkExtraData;
  exports.MediaRouteProvider = MediaRouteProvider;
  exports.MediaRouteProviderPtr = MediaRouteProviderPtr;
  exports.MediaRouteProviderAssociatedPtr = MediaRouteProviderAssociatedPtr;
  exports.MediaRouter = MediaRouter;
  exports.MediaRouterPtr = MediaRouterPtr;
  exports.MediaRouterAssociatedPtr = MediaRouterAssociatedPtr;
})();// Copyright 2015 The Chromium Authors. All rights reserved.
// 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) {
  loadScript('mojo_bindings');
}
mojo.config.autoLoadMojomDeps = false;

loadScript('chrome/common/media_router/mojo/media_controller.mojom');
loadScript('chrome/common/media_router/mojo/media_router.mojom');
loadScript('chrome/common/media_router/mojo/media_status.mojom');
loadScript('extensions/common/mojo/keep_alive.mojom');
loadScript('media/mojo/interfaces/mirror_service_remoting.mojom');
loadScript('media/mojo/interfaces/remoting_common.mojom');
loadScript('mojo/common/time.mojom');
loadScript('net/interfaces/ip_address.mojom');
loadScript('net/interfaces/ip_endpoint.mojom');
loadScript('url/mojo/origin.mojom');
loadScript('url/mojo/url.mojom');

// The following adapter classes preserve backward compatibility for the media
// router component extension.
// TODO(crbug.com/787128): Remove these adapters.

function assignFields(object, fields) {
  for(var field in fields) {
    if (object.hasOwnProperty(field))
      object[field] = fields[field];
  }
}

/**
 * Adapter for mediaRouter.mojom.DialMediaSink.
 * @constructor
 */
function DialMediaSinkAdapter(fields) {
  this.ip_address = null;
  this.model_name = null;
  this.app_url = null;

  assignFields(this, fields);
}

DialMediaSinkAdapter.fromNewVersion = function(other) {
  return new DialMediaSinkAdapter({
    'ip_address': IPAddressAdapter.fromNewVersion(other.ipAddress),
    'model_name': other.modelName,
    'app_url': other.appUrl,
  });
};

DialMediaSinkAdapter.prototype.toNewVersion = function() {
  return new mediaRouter.mojom.DialMediaSink({
    'ipAddress' : this.ip_address.toNewVersion(),
    'modelName' : this.model_name,
    'appUrl' : this.app_url,
  });
};

/**
 * Adapter for mediaRouter.mojom.CastMediaSink.
 * @constructor
 */
function CastMediaSinkAdapter(fields) {
  this.ip_endpoint = null;
  this.model_name = null;
  this.capabilities = 0;
  this.cast_channel_id = 0;

  assignFields(this, fields);
}

CastMediaSinkAdapter.fromNewVersion = function(other) {
  return new CastMediaSinkAdapter({
    'ip_endpoint': IPEndpointAdapter.fromNewVersion(other.ipEndpoint),
    'model_name': other.modelName,
    'capabilities': other.capabilities,
    'cast_channel_id': other.castChannelId,
  });
};

CastMediaSinkAdapter.prototype.toNewVersion = function() {
  return new mediaRouter.mojom.CastMediaSink({
    'ipEndpoint': this.ip_endpoint.toNewVersion(),
    'modelName': this.model_name,
    'capabilities': this.capabilities,
    'castChannelId': this.cast_channel_id,
  });
};

/**
 * Adapter for mediaRouter.mojom.HangoutsMediaStatusExtraData.
 * @constructor
 */
function HangoutsMediaStatusExtraDataAdapter(fields) {
  this.local_present = false;

  assignFields(this, fields);
}

HangoutsMediaStatusExtraDataAdapter.prototype.toNewVersion = function() {
  return new mediaRouter.mojom.HangoutsMediaStatusExtraData({
    'localPresent': this.local_present,
  });
};

/**
 * Adapter for net.interfaces.IPAddress.
 * @constructor
 */
function IPAddressAdapter(fields) {
  this.address_bytes = null;

  assignFields(this, fields);
}

IPAddressAdapter.fromNewVersion = function(other) {
  return new IPAddressAdapter({
    'address_bytes': other.addressBytes,
  });
};

IPAddressAdapter.prototype.toNewVersion = function() {
  return new net.interfaces.IPAddress({
    'addressBytes': this.address_bytes,
  });
};

/**
 * Adapter for net.interfaces.IPEndpoint.
 * @constructor
 */
function IPEndpointAdapter(fields) {
  this.address = null;
  this.port = 0;

  assignFields(this, fields);
}

IPEndpointAdapter.fromNewVersion = function(other) {
  return new IPEndpointAdapter({
    'address': IPAddressAdapter.fromNewVersion(other.address),
    'port': other.port,
  });
};

IPEndpointAdapter.prototype.toNewVersion = function() {
  return new net.interfaces.IPEndpoint({
    'address': this.address.toNewVersion(),
    'port': this.port,
  });
};

/**
 * Adapter for mediaRouter.mojom.MediaStatus.
 * @constructor
 */
function MediaStatusAdapter(fields) {
  this.title = null;
  this.description = null;
  this.can_play_pause = false;
  this.can_mute = false;
  this.can_set_volume = false;
  this.can_seek = false;
  this.is_muted = false;
  this.play_state = 0;
  this.volume = 0;
  this.duration = null;
  this.current_time = null;
  this.hangouts_extra_data = null;

  assignFields(this, fields);
}

MediaStatusAdapter.PlayState = mediaRouter.mojom.MediaStatus.PlayState;

MediaStatusAdapter.prototype.toNewVersion = function() {
  return new mediaRouter.mojom.MediaStatus({
    'title': this.title,
    'description': this.description,
    'canPlayPause': this.can_play_pause,
    'canMute': this.can_mute,
    'canSetVolume': this.can_set_volume,
    'canSeek': this.can_seek,
    'isMuted': this.is_muted,
    'playState': this.play_state,
    'volume': this.volume,
    'duration': this.duration,
    'currentTime': this.current_time,
    'hangoutsExtraData':
        this.hangouts_extra_data && this.hangouts_extra_data.toNewVersion(),
  });
};

/**
 * Adapter for media.mojom.RemotingSinkMetadata.
 * @constructor
 */
function RemotingSinkMetadataAdapter(fields) {
  this.features = null;
  this.audio_capabilities = null;
  this.video_capabilities = null;
  this.friendly_name = null;

  assignFields(this, fields);
}

RemotingSinkMetadataAdapter.fromNewVersion = function(other) {
  return new RemotingSinkMetadataAdapter({
    'features': other.features,
    'audio_capabilities': other.audioCapabilities,
    'video_capabilities': other.videoCapabilities,
    'friendly_name': other.friendlyName,
  });
};

RemotingSinkMetadataAdapter.prototype.toNewVersion = function() {
  return new media.mojom.RemotingSinkMetadata({
    'features': this.features,
    'audioCapabilities': this.audio_capabilities,
    'videoCapabilities': this.video_capabilities,
    'friendlyName': this.friendly_name,
  });
};

/**
 * Adapter for mediaRouter.mojom.MediaSink.
 * @constructor
 */
function MediaSinkAdapter(fields) {
  this.sink_id = null;
  this.name = null;
  this.description = null;
  this.domain = null;
  this.icon_type = 0;
  this.extra_data = null;

  assignFields(this, fields);
}

MediaSinkAdapter.fromNewVersion = function(other) {
  return new MediaSinkAdapter({
    'sink_id': other.sinkId,
    'name': other.name,
    'description': other.description,
    'domain': other.domain,
    'icon_type': other.iconType,
    'extra_data': other.extraData &&
        MediaSinkExtraDataAdapter.fromNewVersion(other.extraData),
  });
};

MediaSinkAdapter.prototype.toNewVersion = function() {
  return new mediaRouter.mojom.MediaSink({
    'sinkId': this.sink_id,
    'name': this.name,
    'description': this.description,
    'domain': this.domain,
    'iconType': this.icon_type,
    'extraData': this.extra_data && this.extra_data.toNewVersion(),
  });
};

/**
 * Adapter for mediaRouter.mojom.MediaSinkExtraData.
 * @constructor
 */
function MediaSinkExtraDataAdapter(value) {
  this.$data = null;
  this.$tag = undefined;

  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 = [
    'dial_media_sink',
    'cast_media_sink',
  ];

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

  this[keys[0]] = value[keys[0]];
}

MediaSinkExtraDataAdapter.Tags = {
  dial_media_sink: 0,
  cast_media_sink: 1,
};

Object.defineProperty(MediaSinkExtraDataAdapter.prototype, 'dial_media_sink', {
  get: function() {
    if (this.$tag != MediaSinkExtraDataAdapter.Tags.dial_media_sink) {
      throw new ReferenceError(
          'MediaSinkExtraDataAdapter.dial_media_sink is not currently set.');
    }
    return this.$data;
  },

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

Object.defineProperty(MediaSinkExtraDataAdapter.prototype, 'cast_media_sink', {
  get: function() {
    if (this.$tag != MediaSinkExtraDataAdapter.Tags.cast_media_sink) {
      throw new ReferenceError(
          'MediaSinkExtraDataAdapter.cast_media_sink is not currently set.');
    }
    return this.$data;
  },

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

MediaSinkExtraDataAdapter.fromNewVersion = function(other) {
  if (other.$tag == mediaRouter.mojom.MediaSinkExtraData.Tags.dialMediaSink) {
    return new MediaSinkExtraDataAdapter({
      'dial_media_sink':
          DialMediaSinkAdapter.fromNewVersion(other.dialMediaSink),
    });
  } else {
    return new MediaSinkExtraDataAdapter({
      'cast_media_sink':
          CastMediaSinkAdapter.fromNewVersion(other.castMediaSink),
    });
  }
};

MediaSinkExtraDataAdapter.prototype.toNewVersion = function() {
  if (this.$tag == MediaSinkExtraDataAdapter.Tags.dial_media_sink) {
    return new mediaRouter.mojom.MediaSinkExtraData({
      'dialMediaSink': this.dial_media_sink.toNewVersion(),
    });
  } else {
    return new mediaRouter.mojom.MediaSinkExtraData({
      'castMediaSink': this.cast_media_sink.toNewVersion(),
    });
  }
};

/**
 * Adapter for media.mojom.MirrorServiceRemoterPtr.
 * @constructor
 */
function MirrorServiceRemoterPtrAdapter(handleOrPtrInfo) {
  this.ptr = new mojo.InterfacePtrController(MirrorServiceRemoterAdapter,
                                             handleOrPtrInfo);
}

MirrorServiceRemoterPtrAdapter.prototype =
    Object.create(media.mojom.MirrorServiceRemoterPtr.prototype);
MirrorServiceRemoterPtrAdapter.prototype.constructor =
    MirrorServiceRemoterPtrAdapter;

MirrorServiceRemoterPtrAdapter.prototype.startDataStreams = function() {
  return MirrorServiceRemoterProxy.prototype.startDataStreams
      .apply(this.ptr.getProxy(), arguments).then(function(response) {
    return Promise.resolve({
      'audio_stream_id': response.audioStreamId,
      'video_stream_id': response.videoStreamId,
    });
  });
};

/**
 * Adapter for media.mojom.MirrorServiceRemoter.stubclass.
 * @constructor
 */
function MirrorServiceRemoterStubAdapter(delegate) {
  this.delegate_ = delegate;
}

MirrorServiceRemoterStubAdapter.prototype = Object.create(
    media.mojom.MirrorServiceRemoter.stubClass.prototype);
MirrorServiceRemoterStubAdapter.prototype.constructor =
    MirrorServiceRemoterStubAdapter;

MirrorServiceRemoterStubAdapter.prototype.startDataStreams =
    function(hasAudio, hasVideo) {
  return this.delegate_ && this.delegate_.startDataStreams &&
      this.delegate_.startDataStreams(hasAudio, hasVideo).then(
          function(response) {
            return {
              'audioStreamId': response.audio_stream_id,
              'videoStreamId': response.video_stream_id,
            };
          });
};

/**
 * Adapter for media.mojom.MirrorServiceRemoter.
 */
var MirrorServiceRemoterAdapter = {
    name: 'media::mojom::MirrorServiceRemoter',
    kVersion: 0,
    ptrClass: MirrorServiceRemoterPtrAdapter,
    proxyClass: media.mojom.MirrorServiceRemoter.proxyClass,
    stubClass: MirrorServiceRemoterStubAdapter,
    validateRequest: media.mojom.MirrorServiceRemoter.validateRequest,
    validateResponse: media.mojom.MirrorServiceRemoter.validateResponse,
};

/**
 * Adapter for media.mojom.MirrorServiceRemotingSourcePtr.
 * @constructor
 */
function MirrorServiceRemotingSourcePtrAdapter(handleOrPtrInfo) {
  this.ptr = new mojo.InterfacePtrController(MirrorServiceRemotingSourceAdapter,
                                             handleOrPtrInfo);
}

MirrorServiceRemotingSourcePtrAdapter.prototype =
    Object.create(media.mojom.MirrorServiceRemotingSourcePtr.prototype);
MirrorServiceRemotingSourcePtrAdapter.prototype.constructor =
    MirrorServiceRemotingSourcePtrAdapter;

MirrorServiceRemotingSourcePtrAdapter.prototype.onSinkAvailable =
    function(metadata) {
  return this.ptr.getProxy().onSinkAvailable(metadata.toNewVersion());
};

/**
 * Adapter for media.mojom.MirrorServiceRemotingSource.
 */
var MirrorServiceRemotingSourceAdapter = {
    name: 'media::mojom::MirrorServiceRemotingSource',
    kVersion: 0,
    ptrClass: MirrorServiceRemotingSourcePtrAdapter,
    proxyClass: media.mojom.MirrorServiceRemotingSource.proxyClass,
    stubClass: null,
    validateRequest: media.mojom.MirrorServiceRemotingSource.validateRequest,
    validateResponse: null,
};

/**
 * Adapter for mediaRouter.mojom.MediaStatusObserver.
 * @constructor
 */
function MediaStatusObserverPtrAdapter(handleOrPtrInfo) {
  this.ptr = new mojo.InterfacePtrController(MediaStatusObserverAdapter,
                                             handleOrPtrInfo);
}

MediaStatusObserverPtrAdapter.prototype =
    Object.create(mediaRouter.mojom.MediaStatusObserverPtr.prototype);
MediaStatusObserverPtrAdapter.prototype.constructor =
    MediaStatusObserverPtrAdapter;

MediaStatusObserverPtrAdapter.prototype.onMediaStatusUpdated =
    function(status) {
  return this.ptr.getProxy().onMediaStatusUpdated(status.toNewVersion());
};

/**
 * Adapter for mediaRouter.mojom.MediaStatusObserver.
 */
var MediaStatusObserverAdapter = {
  name: 'mediaRouter::mojom::MediaStatusObserver',
  kVersion: 0,
  ptrClass: MediaStatusObserverPtrAdapter,
  proxyClass: mediaRouter.mojom.MediaStatusObserver.proxyClass,
  stubClass: null,
  validateRequest: mediaRouter.mojom.MediaStatusObserver.validateRequest,
  validateResponse: null,
};

/**
 * Converts a media sink to a MediaSink Mojo object.
 * @param {!MediaSink} sink A media sink.
 * @return {!mediaRouter.mojom.MediaSink} A Mojo MediaSink object.
 */
function sinkToMojo_(sink) {
  return new mediaRouter.mojom.MediaSink({
    'name': sink.friendlyName,
    'description': sink.description,
    'domain': sink.domain,
    'sinkId': sink.id,
    'iconType': sinkIconTypeToMojo(sink.iconType),
    'providerId': mediaRouter.mojom.MediaRouteProvider.Id.EXTENSION,
  });
}

/**
 * Converts a media sink's icon type to a MediaSink.IconType Mojo object.
 * @param {!MediaSink.IconType} type A media sink's icon type.
 * @return {!mediaRouter.mojom.MediaSink.IconType} A Mojo MediaSink.IconType
 *     object.
 */
function sinkIconTypeToMojo(type) {
  switch (type) {
    case 'cast':
      return mediaRouter.mojom.SinkIconType.CAST;
    case 'cast_audio_group':
      return mediaRouter.mojom.SinkIconType.CAST_AUDIO_GROUP;
    case 'cast_audio':
      return mediaRouter.mojom.SinkIconType.CAST_AUDIO;
    case 'meeting':
      return mediaRouter.mojom.SinkIconType.MEETING;
    case 'hangout':
      return mediaRouter.mojom.SinkIconType.HANGOUT;
    case 'education':
      return mediaRouter.mojom.SinkIconType.EDUCATION;
    case 'generic':
      return mediaRouter.mojom.SinkIconType.GENERIC;
    default:
      console.error('Unknown sink icon type : ' + type);
      return mediaRouter.mojom.SinkIconType.GENERIC;
  }
}

/**
 * Returns a Mojo MediaRoute object given a MediaRoute and a
 * media sink name.
 * @param {!MediaRoute} route
 * @return {!mediaRouter.mojom.MediaRoute}
 */
function routeToMojo_(route) {
  return new mediaRouter.mojom.MediaRoute({
    'mediaRouteId': route.id,
    'mediaSource': route.mediaSource,
    'mediaSinkId': route.sinkId,
    'description': route.description,
    'iconUrl': route.iconUrl,
    'isLocal': route.isLocal,
    'forDisplay': route.forDisplay,
    'isIncognito': route.offTheRecord,
    'isLocalPresentation': route.isOffscreenPresentation,
    'controllerType': route.controllerType,
    // Begin newly added properties, followed by the milestone they were
    // added.  The guard should be safe to remove N+2 milestones later.
    'presentationId': route.presentationId || ''  // M64
  });
}

/**
 * Converts a route message to a RouteMessage Mojo object.
 * @param {!RouteMessage} message
 * @return {!mediaRouter.mojom.RouteMessage} A Mojo RouteMessage object.
 */
function messageToMojo_(message) {
  if ("string" == typeof message.message) {
    return new mediaRouter.mojom.RouteMessage({
      'type': mediaRouter.mojom.RouteMessage.Type.TEXT,
      'message': message.message,
    });
  } else {
    return new mediaRouter.mojom.RouteMessage({
      'type': mediaRouter.mojom.RouteMessage.Type.BINARY,
      'data': message.message,
    });
  }
}

/**
 * Converts presentation connection state to Mojo enum value.
 * @param {!string} state
 * @return {!mediaRouter.mojom.MediaRouter.PresentationConnectionState}
 */
function presentationConnectionStateToMojo_(state) {
  var PresentationConnectionState =
      mediaRouter.mojom.MediaRouter.PresentationConnectionState;
  switch (state) {
    case 'connecting':
      return PresentationConnectionState.CONNECTING;
    case 'connected':
      return PresentationConnectionState.CONNECTED;
    case 'closed':
      return PresentationConnectionState.CLOSED;
    case 'terminated':
      return PresentationConnectionState.TERMINATED;
    default:
      console.error('Unknown presentation connection state: ' + state);
      return PresentationConnectionState.TERMINATED;
  }
}

/**
 * Converts presentation connection close reason to Mojo enum value.
 * @param {!string} reason
 * @return {!mediaRouter.mojom.MediaRouter.PresentationConnectionCloseReason}
 */
function presentationConnectionCloseReasonToMojo_(reason) {
  var PresentationConnectionCloseReason =
      mediaRouter.mojom.MediaRouter.PresentationConnectionCloseReason;
  switch (reason) {
    case 'error':
      return PresentationConnectionCloseReason.CONNECTION_ERROR;
    case 'closed':
      return PresentationConnectionCloseReason.CLOSED;
    case 'went_away':
      return PresentationConnectionCloseReason.WENT_AWAY;
    default:
      console.error('Unknown presentation connection close reason : ' +
          reason);
      return PresentationConnectionCloseReason.CONNECTION_ERROR;
  }
}

/**
 * Converts string to Mojo origin.
 * @param {string|!url.mojom.Origin} origin
 * @return {!url.mojom.Origin}
 */
function stringToMojoOrigin_(origin) {
  if (origin instanceof url.mojom.Origin) {
    return origin;
  }
  var originUrl = new URL(origin);
  var mojoOrigin = {};
  mojoOrigin.scheme = originUrl.protocol.replace(':', '');
  mojoOrigin.host = originUrl.hostname;
  var port = originUrl.port ? Number.parseInt(originUrl.port) : 0;
  switch (mojoOrigin.scheme) {
    case 'http':
      mojoOrigin.port = port || 80;
      break;
    case 'https':
      mojoOrigin.port = port || 443;
      break;
    default:
      throw new Error('Scheme must be http or https');
  }
  mojoOrigin.suborigin = '';
  return new url.mojom.Origin(mojoOrigin);
}

/**
 * Parses the given route request Error object and converts it to the
 * corresponding result code.
 * @param {!Error} error
 * @return {!mediaRouter.mojom.RouteRequestResultCode}
 */
function getRouteRequestResultCode_(error) {
  return error.errorCode ? error.errorCode :
    mediaRouter.mojom.RouteRequestResultCode.UNKNOWN_ERROR;
}

/**
 * Creates and returns a successful route response from given route.
 * @param {!MediaRoute} route
 * @return {!Object}
 */
function toSuccessRouteResponse_(route) {
  return {
      route: routeToMojo_(route),
      resultCode: mediaRouter.mojom.RouteRequestResultCode.OK
  };
}

/**
 * Creates and returns a error route response from given Error object.
 * @param {!Error} error
 * @return {!Object}
 */
function toErrorRouteResponse_(error) {
  return {
      errorText: error.message,
      resultCode: getRouteRequestResultCode_(error)
  };
}

/**
 * Creates a new MediaRouter.
 * Converts a route struct to its Mojo form.
 * @param {!mediaRouter.mojom.MediaRouterPtr} service
 * @constructor
 */
function MediaRouter(service) {
  /**
   * The Mojo service proxy. Allows extension code to call methods that reside
   * in the browser.
   * @type {!mediaRouter.mojom.MediaRouterPtr}
   */
  this.service_ = service;

  /**
   * The provider manager service delegate. Its methods are called by the
   * browser-resident Mojo service.
   * @type {!MediaRouter}
   */
  this.mrpm_ = new MediaRouteProvider(this);

  /**
   * Handle to a KeepAlive service object, which prevents the extension from
   * being suspended as long as it remains in scope.
   * @type {boolean}
   */
  this.keepAlive_ = null;

  /**
   * The bindings to bind the service delegate to the Mojo interface.
   * Object must remain in scope for the lifetime of the connection to
   * prevent the connection from closing automatically.
   * @type {!mojo.Binding}
   */
  this.mediaRouteProviderBinding_ = new mojo.Binding(
      mediaRouter.mojom.MediaRouteProvider, this.mrpm_);
}

/**
 * Returns definitions of Mojo core and generated Mojom classes that can be
 * used directly by the component.
 * @return {!Object}
 * TODO(imcheng): We should export these along with MediaRouter. This requires
 * us to modify the component to handle multiple exports. When that logic is
 * baked in for a couple of milestones, we should be able to remove this
 * method.
 * TODO(imcheng): We should stop exporting mojo bindings classes that the
 * Media Router extension doesn't directly use, such as
 * mojo.AssociatedInterfacePtrInfo, mojo.InterfacePtrController and
 * mojo.interfaceControl.
 */
MediaRouter.prototype.getMojoExports = function() {
  return {
    AssociatedInterfacePtrInfo: mojo.AssociatedInterfacePtrInfo,
    Binding: mojo.Binding,
    DialMediaSink: DialMediaSinkAdapter,
    CastMediaSink: CastMediaSinkAdapter,
    HangoutsMediaRouteController:
        mediaRouter.mojom.HangoutsMediaRouteController,
    HangoutsMediaStatusExtraData: HangoutsMediaStatusExtraDataAdapter,
    IPAddress: IPAddressAdapter,
    IPEndpoint: IPEndpointAdapter,
    InterfacePtrController: mojo.InterfacePtrController,
    InterfacePtrInfo: mojo.InterfacePtrInfo,
    InterfaceRequest: mojo.InterfaceRequest,
    MediaController: mediaRouter.mojom.MediaController,
    MediaStatus: MediaStatusAdapter,
    MediaStatusObserverPtr: mediaRouter.mojom.MediaStatusObserverPtr,
    MirrorServiceRemoter: MirrorServiceRemoterAdapter,
    MirrorServiceRemoterPtr: MirrorServiceRemoterPtrAdapter,
    MirrorServiceRemotingSourcePtr: MirrorServiceRemotingSourcePtrAdapter,
    RemotingStopReason: media.mojom.RemotingStopReason,
    RemotingStartFailReason: media.mojom.RemotingStartFailReason,
    RemotingSinkFeature: media.mojom.RemotingSinkFeature,
    RemotingSinkAudioCapability:
        media.mojom.RemotingSinkAudioCapability,
    RemotingSinkVideoCapability:
        media.mojom.RemotingSinkVideoCapability,
    RemotingSinkMetadata: RemotingSinkMetadataAdapter,
    RouteControllerType: mediaRouter.mojom.RouteControllerType,
    Origin: url.mojom.Origin,
    Sink: MediaSinkAdapter,
    SinkExtraData: MediaSinkExtraDataAdapter,
    TimeDelta: mojo.common.mojom.TimeDelta,
    Url: url.mojom.Url,
    interfaceControl: mojo.interfaceControl,
    makeRequest: mojo.makeRequest,
  };
};

/**
 * Registers the Media Router Provider Manager with the Media Router.
 * @return {!Promise<Object>} Instance ID and config for the Media Router.
 */
MediaRouter.prototype.start = function() {
  return this.service_.registerMediaRouteProvider(
      mediaRouter.mojom.MediaRouteProvider.Id.EXTENSION,
      this.mediaRouteProviderBinding_.createInterfacePtrAndBind()).then(
          function(response) {
            return {
              'instance_id': response.instanceId,
              'config': {
                'enable_dial_discovery': response.config.enableDialDiscovery,
                'enable_cast_discovery': response.config.enableCastDiscovery,
              }
            };
          });
}

/**
 * Sets the service delegate methods.
 * @param {Object} handlers
 */
MediaRouter.prototype.setHandlers = function(handlers) {
  this.mrpm_.setHandlers(handlers);
}

/**
 * The keep alive status.
 * @return {boolean}
 */
MediaRouter.prototype.getKeepAlive = function() {
  return this.keepAlive_ != null;
};

/**
 * Called by the provider manager when a sink list for a given source is
 * updated.
 * @param {!string} sourceUrn
 * @param {!Array<!MediaSink>} sinks
 * @param {!Array<string|!url.mojom.Origin>} origins
 */
MediaRouter.prototype.onSinksReceived = function(sourceUrn, sinks, origins) {
  // |origins| is a string array if the Media Router component extension version
  // is 59 or older. Without the stringToMojoOrigin_() conversion, clients using
  // those extension versions would see a crash shown in
  // https://crbug.com/787427.
  this.service_.onSinksReceived(
      mediaRouter.mojom.MediaRouteProvider.Id.EXTENSION, sourceUrn,
      sinks.map(sinkToMojo_), origins.map(stringToMojoOrigin_));
};

/**
 * Called by the provider manager when a sink is found to notify the MR of the
 * sink's ID. The actual sink will be returned through the normal sink list
 * update process, so this helps the MR identify the search result in the
 * list.
 * @param {string} pseudoSinkId  ID of the pseudo sink that started the
 *     search.
 * @param {string} sinkId ID of the newly-found sink.
 */
MediaRouter.prototype.onSearchSinkIdReceived = function(
    pseudoSinkId, sinkId) {
  this.service_.onSearchSinkIdReceived(pseudoSinkId, sinkId);
};

/**
 * Called by the provider manager to keep the extension from suspending
 * if it enters a state where suspension is undesirable (e.g. there is an
 * active MediaRoute.)
 * If keepAlive is true, the extension is kept alive.
 * If keepAlive is false, the extension is allowed to suspend.
 * @param {boolean} keepAlive
 */
MediaRouter.prototype.setKeepAlive = function(keepAlive) {
  if (keepAlive === false && this.keepAlive_) {
    this.keepAlive_.ptr.reset();
    this.keepAlive_ = null;
  } else if (keepAlive === true && !this.keepAlive_) {
    this.keepAlive_ = new extensions.KeepAlivePtr;
    Mojo.bindInterface(extensions.KeepAlive.name,
                       mojo.makeRequest(this.keepAlive_).handle);
  }
};

/**
 * Called by the provider manager to send an issue from a media route
 * provider to the Media Router, to show the user.
 * @param {!Object} issue The issue object.
 */
MediaRouter.prototype.onIssue = function(issue) {
  function issueSeverityToMojo_(severity) {
    switch (severity) {
      case 'fatal':
        return mediaRouter.mojom.Issue.Severity.FATAL;
      case 'warning':
        return mediaRouter.mojom.Issue.Severity.WARNING;
      case 'notification':
        return mediaRouter.mojom.Issue.Severity.NOTIFICATION;
      default:
        console.error('Unknown issue severity: ' + severity);
        return mediaRouter.mojom.Issue.Severity.NOTIFICATION;
    }
  }

  function issueActionToMojo_(action) {
    switch (action) {
      case 'dismiss':
        return mediaRouter.mojom.Issue.ActionType.DISMISS;
      case 'learn_more':
        return mediaRouter.mojom.Issue.ActionType.LEARN_MORE;
      default:
        console.error('Unknown issue action type : ' + action);
        return mediaRouter.mojom.Issue.ActionType.OK;
    }
  }

  var secondaryActions = (issue.secondaryActions || []).map(issueActionToMojo_);
  this.service_.onIssue(new mediaRouter.mojom.Issue({
    'routeId': issue.routeId || '',
    'severity': issueSeverityToMojo_(issue.severity),
    'title': issue.title,
    'message': issue.message || '',
    'defaultAction': issueActionToMojo_(issue.defaultAction),
    'secondaryActions': secondaryActions,
    'helpPageId': issue.helpPageId,
    'isBlocking': issue.isBlocking
  }));
};

/**
 * Called by the provider manager when the set of active routes
 * has been updated.
 * @param {!Array<MediaRoute>} routes The active set of media routes.
 * @param {string=} sourceUrn The sourceUrn associated with this route
 *     query.
 * @param {Array<string>=} joinableRouteIds The active set of joinable
 *     media routes.
 */
MediaRouter.prototype.onRoutesUpdated = function(
    routes, sourceUrn = '', joinableRouteIds = []) {
  this.service_.onRoutesUpdated(
      mediaRouter.mojom.MediaRouteProvider.Id.EXTENSION,
      routes.map(routeToMojo_), sourceUrn, joinableRouteIds);
};

/**
 * Called by the provider manager when sink availability has been updated.
 * @param {!mediaRouter.mojom.MediaRouter.SinkAvailability} availability
 *     The new sink availability.
 */
MediaRouter.prototype.onSinkAvailabilityUpdated = function(availability) {
  this.service_.onSinkAvailabilityUpdated(
      mediaRouter.mojom.MediaRouteProvider.Id.EXTENSION, availability);
};

/**
 * Called by the provider manager when the state of a presentation connected
 * to a route has changed.
 * @param {string} routeId
 * @param {string} state
 */
MediaRouter.prototype.onPresentationConnectionStateChanged =
    function(routeId, state) {
  this.service_.onPresentationConnectionStateChanged(
      routeId, presentationConnectionStateToMojo_(state));
};

/**
 * Called by the provider manager when the state of a presentation connected
 * to a route has closed.
 * @param {string} routeId
 * @param {string} reason
 * @param {string} message
 */
MediaRouter.prototype.onPresentationConnectionClosed =
    function(routeId, reason, message) {
  this.service_.onPresentationConnectionClosed(
      routeId, presentationConnectionCloseReasonToMojo_(reason), message);
};

/**
 * @param {string} routeId
 * @param {!Array<!RouteMessage>} mesages
 */
MediaRouter.prototype.onRouteMessagesReceived = function(routeId, messages) {
  this.service_.onRouteMessagesReceived(
      routeId, messages.map(messageToMojo_));
};

/**
 * @param {number} tabId
 * @param {!media.mojom.MirrorServiceRemoterPtr} remoter
 * @param {!mojo.InterfaceRequest} remotingSource
 */
MediaRouter.prototype.onMediaRemoterCreated = function(tabId, remoter,
    remotingSource) {
  this.service_.onMediaRemoterCreated(
      tabId,
      new media.mojom.MirrorServiceRemoterPtr(remoter.ptr.passInterface()),
      remotingSource);
}

/**
 * Object containing callbacks set by the provider manager.
 *
 * @constructor
 * @struct
 */
function MediaRouterHandlers() {
  /**
   * @type {function(!string, !string, !string, !string, !number)}
   */
  this.createRoute = null;

  /**
   * @type {function(!string, !string, !string, !number)}
   */
  this.joinRoute = null;

  /**
   * @type {function(string): Promise}
   */
  this.terminateRoute = null;

  /**
   * @type {function(string)}
   */
  this.startObservingMediaSinks = null;

  /**
   * @type {function(string)}
   */
  this.stopObservingMediaSinks = null;

  /**
   * @type {function(string, string): Promise}
   */
  this.sendRouteMessage = null;

  /**
   * @type {function(string, Uint8Array): Promise}
   */
  this.sendRouteBinaryMessage = null;

  /**
   * @type {function(string)}
   */
  this.startListeningForRouteMessages = null;

  /**
   * @type {function(string)}
   */
  this.stopListeningForRouteMessages = null;

  /**
   * @type {function(string)}
   */
  this.detachRoute = null;

  /**
   * @type {function()}
   */
  this.startObservingMediaRoutes = null;

  /**
   * @type {function()}
   */
  this.stopObservingMediaRoutes = null;

  /**
   * @type {function()}
   */
  this.connectRouteByRouteId = null;

  /**
   * @type {function()}
   */
  this.enableMdnsDiscovery = null;

  /**
   * @type {function()}
   */
  this.updateMediaSinks = null;

  /**
   * @type {function(string, string, !SinkSearchCriteria): string}
   */
  this.searchSinks = null;

  /**
   * @type {function()}
   */
  this.provideSinks = null;

  /**
   * @type {function(string, !mojo.InterfaceRequest,
   *            !mediaRouter.mojom.MediaStatusObserverPtr): !Promise<void>}
   */
  this.createMediaRouteController = null;
};

/**
 * Routes calls from Media Router to the provider manager extension.
 * Registered with the MediaRouter stub.
 * @param {!MediaRouter} MediaRouter proxy to call into the
 * Media Router mojo interface.
 * @constructor
 */
function MediaRouteProvider(mediaRouter) {
  /**
   * Object containing JS callbacks into Provider Manager code.
   * @type {!MediaRouterHandlers}
   */
  this.handlers_ = new MediaRouterHandlers();

  /**
   * Proxy class to the browser's Media Router Mojo service.
   * @type {!MediaRouter}
   */
  this.mediaRouter_ = mediaRouter;
}

/*
 * Sets the callback handler used to invoke methods in the provider manager.
 *
 * @param {!MediaRouterHandlers} handlers
 */
MediaRouteProvider.prototype.setHandlers = function(handlers) {
  this.handlers_ = handlers;
  var requiredHandlers = [
    'stopObservingMediaRoutes',
    'startObservingMediaRoutes',
    'sendRouteMessage',
    'sendRouteBinaryMessage',
    'startListeningForRouteMessages',
    'stopListeningForRouteMessages',
    'detachRoute',
    'terminateRoute',
    'joinRoute',
    'createRoute',
    'stopObservingMediaSinks',
    'startObservingMediaRoutes',
    'connectRouteByRouteId',
    'enableMdnsDiscovery',
    'updateMediaSinks',
    'searchSinks',
    'provideSinks',
    'createMediaRouteController',
    'onBeforeInvokeHandler'
  ];
  requiredHandlers.forEach(function(nextHandler) {
    if (handlers[nextHandler] === undefined) {
      console.error(nextHandler + ' handler not registered.');
    }
  });
}

/**
 * Starts querying for sinks capable of displaying the media source
 * designated by |sourceUrn|.  Results are returned by calling
 * OnSinksReceived.
 * @param {!string} sourceUrn
 */
MediaRouteProvider.prototype.startObservingMediaSinks =
    function(sourceUrn) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.startObservingMediaSinks(sourceUrn);
};

/**
 * Stops querying for sinks capable of displaying |sourceUrn|.
 * @param {!string} sourceUrn
 */
MediaRouteProvider.prototype.stopObservingMediaSinks =
    function(sourceUrn) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.stopObservingMediaSinks(sourceUrn);
};

/**
 * Requests that |sinkId| render the media referenced by |sourceUrn|. If the
 * request is from the Presentation API, then origin and tabId will
 * be populated.
 * @param {!string} sourceUrn Media source to render.
 * @param {!string} sinkId Media sink ID.
 * @param {!string} presentationId Presentation ID from the site
 *     requesting presentation. TODO(mfoltz): Remove.
 * @param {!url.mojom.Origin} origin Origin of site requesting presentation.
 * @param {!number} tabId ID of tab requesting presentation.
 * @param {!mojo.common.mojom.TimeDelta} timeout If positive, the timeout
 *     duration for the request. Otherwise, the default duration will be used.
 * @param {!boolean} incognito If true, the route is being requested by
 *     an incognito profile.
 * @return {!Promise.<!Object>} A Promise resolving to an object describing
 *     the newly created media route, or rejecting with an error message on
 *     failure.
 */
MediaRouteProvider.prototype.createRoute =
    function(sourceUrn, sinkId, presentationId, origin, tabId,
             timeout, incognito) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.createRoute(
      sourceUrn, sinkId, presentationId, origin, tabId,
      Math.floor(timeout.microseconds / 1000), incognito)
      .then(function(route) {
        return toSuccessRouteResponse_(route);
      },
      function(err) {
        return toErrorRouteResponse_(err);
      });
};

/**
 * Handles a request via the Presentation API to join an existing route given
 * by |sourceUrn| and |presentationId|. |origin| and |tabId| are used for
 * validating same-origin/tab scope.
 * @param {!string} sourceUrn Media source to render.
 * @param {!string} presentationId Presentation ID to join.
 * @param {!url.mojom.Origin} origin Origin of site requesting join.
 * @param {!number} tabId ID of tab requesting join.
 * @param {!mojo.common.mojom.TimeDelta} timeout If positive, the timeout
 *     duration for the request. Otherwise, the default duration will be used.
 * @param {!boolean} incognito If true, the route is being requested by
 *     an incognito profile.
 * @return {!Promise.<!Object>} A Promise resolving to an object describing
 *     the newly created media route, or rejecting with an error message on
 *     failure.
 */
MediaRouteProvider.prototype.joinRoute =
    function(sourceUrn, presentationId, origin, tabId, timeout,
             incognito) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.joinRoute(
      sourceUrn, presentationId, origin, tabId,
      Math.floor(timeout.microseconds / 1000), incognito)
      .then(function(route) {
        return toSuccessRouteResponse_(route);
      },
      function(err) {
        return toErrorRouteResponse_(err);
      });
};

/**
 * Handles a request via the Presentation API to join an existing route given
 * by |sourceUrn| and |routeId|. |origin| and |tabId| are used for
 * validating same-origin/tab scope.
 * @param {!string} sourceUrn Media source to render.
 * @param {!string} routeId Route ID to join.
 * @param {!string} presentationId Presentation ID to join.
 * @param {!url.mojom.Origin} origin Origin of site requesting join.
 * @param {!number} tabId ID of tab requesting join.
 * @param {!mojo.common.mojom.TimeDelta} timeout If positive, the timeout
 *     duration for the request. Otherwise, the default duration will be used.
 * @param {!boolean} incognito If true, the route is being requested by
 *     an incognito profile.
 * @return {!Promise.<!Object>} A Promise resolving to an object describing
 *     the newly created media route, or rejecting with an error message on
 *     failure.
 */
MediaRouteProvider.prototype.connectRouteByRouteId =
    function(sourceUrn, routeId, presentationId, origin, tabId,
             timeout, incognito) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.connectRouteByRouteId(
      sourceUrn, routeId, presentationId, origin, tabId,
      Math.floor(timeout.microseconds / 1000), incognito)
      .then(function(route) {
        return toSuccessRouteResponse_(route);
      },
      function(err) {
        return toErrorRouteResponse_(err);
      });
};

/**
 * Terminates the route specified by |routeId|.
 * @param {!string} routeId
 * @return {!Promise<!Object>} A Promise resolving to an object describing
 *    the result of the terminate operation, or rejecting with an error
 *    message and code if the operation failed.
 */
MediaRouteProvider.prototype.terminateRoute = function(routeId) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.terminateRoute(routeId).then(
      () => ({resultCode: mediaRouter.mojom.RouteRequestResultCode.OK}),
      (err) => toErrorRouteResponse_(err));
};

/**
 * Posts a message to the route designated by |routeId|.
 * @param {!string} routeId
 * @param {!string} message
 * @return {!Promise.<boolean>} Resolved with true if the message was sent,
 *    or false on failure.
 */
MediaRouteProvider.prototype.sendRouteMessage = function(
  routeId, message) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.sendRouteMessage(routeId, message)
      .then(function() {
        return {'sent': true};
      }, function() {
        return {'sent': false};
      });
};

/**
 * Sends a binary message to the route designated by |routeId|.
 * @param {!string} routeId
 * @param {!Array<number>} data
 * @return {!Promise.<boolean>} Resolved with true if the data was sent,
 *    or false on failure.
 */
MediaRouteProvider.prototype.sendRouteBinaryMessage = function(
  routeId, data) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.sendRouteBinaryMessage(routeId, new Uint8Array(data))
      .then(function() {
        return {'sent': true};
      }, function() {
        return {'sent': false};
      });
};

/**
 * Listen for messages from a route.
 * @param {!string} routeId
 */
MediaRouteProvider.prototype.startListeningForRouteMessages = function(
    routeId) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.startListeningForRouteMessages(routeId);
};

/**
 * @param {!string} routeId
 */
MediaRouteProvider.prototype.stopListeningForRouteMessages = function(
    routeId) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.stopListeningForRouteMessages(routeId);
};

/**
 * Indicates that the presentation connection that was connected to |routeId|
 * is no longer connected to it.
 * @param {!string} routeId
 */
MediaRouteProvider.prototype.detachRoute = function(
    routeId) {
  this.handlers_.detachRoute(routeId);
};

/**
 * Requests that the provider manager start sending information about active
 * media routes to the Media Router.
 * @param {!string} sourceUrn
 */
MediaRouteProvider.prototype.startObservingMediaRoutes = function(sourceUrn) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.startObservingMediaRoutes(sourceUrn);
};

/**
 * Requests that the provider manager stop sending information about active
 * media routes to the Media Router.
 * @param {!string} sourceUrn
 */
MediaRouteProvider.prototype.stopObservingMediaRoutes = function(sourceUrn) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.stopObservingMediaRoutes(sourceUrn);
};

/**
 * Enables mDNS device discovery.
 */
MediaRouteProvider.prototype.enableMdnsDiscovery = function() {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.enableMdnsDiscovery();
};

/**
 * Requests that the provider manager update media sinks.
 * @param {!string} sourceUrn
 */
MediaRouteProvider.prototype.updateMediaSinks = function(sourceUrn) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.updateMediaSinks(sourceUrn);
};

/**
 * Requests that the provider manager search its providers for a sink matching
 * |searchCriteria| that is compatible with |sourceUrn|. If a sink is found
 * that can be used immediately for route creation, its ID is returned.
 * Otherwise the empty string is returned.
 *
 * @param {string} sinkId Sink ID of the pseudo sink generating the request.
 * @param {string} sourceUrn Media source to be used with the sink.
 * @param {!SinkSearchCriteria} searchCriteria Search criteria for the route
 *     providers.
 * @return {!Promise.<!{sink_id: !string}>} A Promise resolving to either the
 *     sink ID of the sink found by the search that can be used for route
 *     creation, or the empty string if no route can be immediately created.
 */
MediaRouteProvider.prototype.searchSinks = function(
    sinkId, sourceUrn, searchCriteria) {
  this.handlers_.onBeforeInvokeHandler();
 return this.handlers_.searchSinks(sinkId, sourceUrn, searchCriteria).then(
      sinkId => {
        return { 'sinkId': sinkId };
      },
      () => {
        return { 'sinkId': '' };
      });
};

/**
 * Notifies the provider manager that MediaRouter has discovered a list of
 * sinks.
 * @param {string} providerName
 * @param {!Array<!mediaRouter.mojom.MediaSink>} sinks
 */
MediaRouteProvider.prototype.provideSinks = function(providerName, sinks) {
  this.handlers_.onBeforeInvokeHandler();
  this.handlers_.provideSinks(providerName,
                              sinks.map(MediaSinkAdapter.fromNewVersion));
};

/**
 * Creates a controller for the given route and binds the given
 * InterfaceRequest to it, and registers an observer for media status updates
 * for the route.
 * @param {string} routeId
 * @param {!mojo.InterfaceRequest} controllerRequest
 * @param {!mediaRouter.mojom.MediaStatusObserverPtr} observer
 * @return {!Promise<!{success: boolean}>} Resolves to true if a controller
 *     is created. Resolves to false if a controller cannot be created, or if
 *     the controller is already bound.
 */
MediaRouteProvider.prototype.createMediaRouteController = function(
    routeId, controllerRequest, observer) {
  this.handlers_.onBeforeInvokeHandler();
  return this.handlers_.createMediaRouteController(
      routeId, controllerRequest,
      new MediaStatusObserverPtrAdapter(observer.ptr.passInterface())).then(
          () => ({success: true}), e => ({success: false}));
};

var ptr = new mediaRouter.mojom.MediaRouterPtr;
Mojo.bindInterface(mediaRouter.mojom.MediaRouter.name,
                   mojo.makeRequest(ptr).handle);
exports.$set('returnValue', new MediaRouter(ptr));
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'chrome/common/media_router/mojo/media_status.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('mediaRouter.mojom');
  var time$ =
      mojo.internal.exposeNamespace('mojo.common.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'mojo/common/time.mojom', '../../../../mojo/common/time.mojom.js');
  }



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

  MediaStatus.PlayState = {};
  MediaStatus.PlayState.PLAYING = 0;
  MediaStatus.PlayState.PAUSED = MediaStatus.PlayState.PLAYING + 1;
  MediaStatus.PlayState.BUFFERING = MediaStatus.PlayState.PAUSED + 1;

  MediaStatus.PlayState.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
      return true;
    }
    return false;
  };

  MediaStatus.PlayState.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };

  MediaStatus.prototype.initDefaults_ = function() {
    this.title = null;
    this.description = null;
    this.canPlayPause = false;
    this.canMute = false;
    this.canSetVolume = false;
    this.canSeek = false;
    this.isMuted = false;
    this.playState = 0;
    this.volume = 0;
    this.duration = null;
    this.currentTime = null;
    this.hangoutsExtraData = null;
  };
  MediaStatus.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate MediaStatus.title
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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






    // validate MediaStatus.playState
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 20, MediaStatus.PlayState);
    if (err !== validator.validationError.NONE)
        return err;




    // validate MediaStatus.duration
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 32, time$.TimeDelta, false);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaStatus.currentTime
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 40, time$.TimeDelta, false);
    if (err !== validator.validationError.NONE)
        return err;


    // validate MediaStatus.hangoutsExtraData
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 48, HangoutsMediaStatusExtraData, true);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaStatus.encodedSize = codec.kStructHeaderSize + 56;

  MediaStatus.decode = function(decoder) {
    var packed;
    var val = new MediaStatus();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.title = decoder.decodeStruct(codec.String);
    val.description = decoder.decodeStruct(codec.String);
    packed = decoder.readUint8();
    val.canPlayPause = (packed >> 0) & 1 ? true : false;
    val.canMute = (packed >> 1) & 1 ? true : false;
    val.canSetVolume = (packed >> 2) & 1 ? true : false;
    val.canSeek = (packed >> 3) & 1 ? true : false;
    val.isMuted = (packed >> 4) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.playState = decoder.decodeStruct(codec.Int32);
    val.volume = decoder.decodeStruct(codec.Float);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.duration = decoder.decodeStructPointer(time$.TimeDelta);
    val.currentTime = decoder.decodeStructPointer(time$.TimeDelta);
    val.hangoutsExtraData = decoder.decodeStructPointer(HangoutsMediaStatusExtraData);
    return val;
  };

  MediaStatus.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaStatus.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.title);
    encoder.encodeStruct(codec.String, val.description);
    packed = 0;
    packed |= (val.canPlayPause & 1) << 0
    packed |= (val.canMute & 1) << 1
    packed |= (val.canSetVolume & 1) << 2
    packed |= (val.canSeek & 1) << 3
    packed |= (val.isMuted & 1) << 4
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.Int32, val.playState);
    encoder.encodeStruct(codec.Float, val.volume);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStructPointer(time$.TimeDelta, val.duration);
    encoder.encodeStructPointer(time$.TimeDelta, val.currentTime);
    encoder.encodeStructPointer(HangoutsMediaStatusExtraData, val.hangoutsExtraData);
  };
  function HangoutsMediaStatusExtraData(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  HangoutsMediaStatusExtraData.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;
  };

  HangoutsMediaStatusExtraData.encodedSize = codec.kStructHeaderSize + 8;

  HangoutsMediaStatusExtraData.decode = function(decoder) {
    var packed;
    var val = new HangoutsMediaStatusExtraData();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.localPresent = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  HangoutsMediaStatusExtraData.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(HangoutsMediaStatusExtraData.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.localPresent & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MediaStatusObserver_OnMediaStatusUpdated_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MediaStatusObserver_OnMediaStatusUpdated_Params.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 MediaStatusObserver_OnMediaStatusUpdated_Params.status
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, MediaStatus, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MediaStatusObserver_OnMediaStatusUpdated_Params.encodedSize = codec.kStructHeaderSize + 8;

  MediaStatusObserver_OnMediaStatusUpdated_Params.decode = function(decoder) {
    var packed;
    var val = new MediaStatusObserver_OnMediaStatusUpdated_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.status = decoder.decodeStructPointer(MediaStatus);
    return val;
  };

  MediaStatusObserver_OnMediaStatusUpdated_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MediaStatusObserver_OnMediaStatusUpdated_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(MediaStatus, val.status);
  };
  var kMediaStatusObserver_OnMediaStatusUpdated_Name = 1718512640;

  function MediaStatusObserverPtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(MediaStatusObserver,
                                                   handleOrPtrInfo);
  }

  function MediaStatusObserverAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        MediaStatusObserver, associatedInterfacePtrInfo);
  }

  MediaStatusObserverAssociatedPtr.prototype =
      Object.create(MediaStatusObserverPtr.prototype);
  MediaStatusObserverAssociatedPtr.prototype.constructor =
      MediaStatusObserverAssociatedPtr;

  function MediaStatusObserverProxy(receiver) {
    this.receiver_ = receiver;
  }
  MediaStatusObserverPtr.prototype.onMediaStatusUpdated = function() {
    return MediaStatusObserverProxy.prototype.onMediaStatusUpdated
        .apply(this.ptr.getProxy(), arguments);
  };

  MediaStatusObserverProxy.prototype.onMediaStatusUpdated = function(status) {
    var params = new MediaStatusObserver_OnMediaStatusUpdated_Params();
    params.status = status;
    var builder = new codec.MessageV0Builder(
        kMediaStatusObserver_OnMediaStatusUpdated_Name,
        codec.align(MediaStatusObserver_OnMediaStatusUpdated_Params.encodedSize));
    builder.encodeStruct(MediaStatusObserver_OnMediaStatusUpdated_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };

  function MediaStatusObserverStub(delegate) {
    this.delegate_ = delegate;
  }
  MediaStatusObserverStub.prototype.onMediaStatusUpdated = function(status) {
    return this.delegate_ && this.delegate_.onMediaStatusUpdated && this.delegate_.onMediaStatusUpdated(status);
  }

  MediaStatusObserverStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMediaStatusObserver_OnMediaStatusUpdated_Name:
      var params = reader.decodeStruct(MediaStatusObserver_OnMediaStatusUpdated_Params);
      this.onMediaStatusUpdated(params.status);
      return true;
    default:
      return false;
    }
  };

  MediaStatusObserverStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    default:
      return false;
    }
  };

  function validateMediaStatusObserverRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kMediaStatusObserver_OnMediaStatusUpdated_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MediaStatusObserver_OnMediaStatusUpdated_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateMediaStatusObserverResponse(messageValidator) {
    return validator.validationError.NONE;
  }

  var MediaStatusObserver = {
    name: 'media_router::mojom::MediaStatusObserver',
    kVersion: 0,
    ptrClass: MediaStatusObserverPtr,
    proxyClass: MediaStatusObserverProxy,
    stubClass: MediaStatusObserverStub,
    validateRequest: validateMediaStatusObserverRequest,
    validateResponse: null,
  };
  MediaStatusObserverStub.prototype.validator = validateMediaStatusObserverRequest;
  MediaStatusObserverProxy.prototype.validator = null;
  exports.MediaStatus = MediaStatus;
  exports.HangoutsMediaStatusExtraData = HangoutsMediaStatusExtraData;
  exports.MediaStatusObserver = MediaStatusObserver;
  exports.MediaStatusObserverPtr = MediaStatusObserverPtr;
  exports.MediaStatusObserverAssociatedPtr = MediaStatusObserverAssociatedPtr;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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/common/time.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.common.mojom');



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


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

  Time.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;
  };

  Time.encodedSize = codec.kStructHeaderSize + 8;

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

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


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

  TimeDelta.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;
  };

  TimeDelta.encodedSize = codec.kStructHeaderSize + 8;

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

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


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

  TimeTicks.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;
  };

  TimeTicks.encodedSize = codec.kStructHeaderSize + 8;

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

  TimeTicks.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(TimeTicks.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int64, val.internalValue);
  };
  exports.Time = Time;
  exports.TimeDelta = TimeDelta;
  exports.TimeTicks = TimeTicks;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'net/interfaces/ip_address.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('net.interfaces');



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


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

  IPAddress.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 IPAddress.addressBytes
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 0, 1, codec.Uint8, false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  IPAddress.encodedSize = codec.kStructHeaderSize + 8;

  IPAddress.decode = function(decoder) {
    var packed;
    var val = new IPAddress();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.addressBytes = decoder.decodeArrayPointer(codec.Uint8);
    return val;
  };

  IPAddress.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(IPAddress.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeArrayPointer(codec.Uint8, val.addressBytes);
  };
  exports.IPAddress = IPAddress;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'net/interfaces/ip_endpoint.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('net.interfaces');
  var ip_address$ =
      mojo.internal.exposeNamespace('net.interfaces');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'net/interfaces/ip_address.mojom', 'ip_address.mojom.js');
  }



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


  IPEndPoint.prototype.initDefaults_ = function() {
    this.address = null;
    this.port = 0;
  };
  IPEndPoint.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

  IPEndPoint.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 IPEndPoint.address
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, ip_address$.IPAddress, false);
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  IPEndPoint.encodedSize = codec.kStructHeaderSize + 16;

  IPEndPoint.decode = function(decoder) {
    var packed;
    var val = new IPEndPoint();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.address = decoder.decodeStructPointer(ip_address$.IPAddress);
    val.port = decoder.decodeStruct(codec.Uint16);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  IPEndPoint.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(IPEndPoint.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(ip_address$.IPAddress, val.address);
    encoder.encodeStruct(codec.Uint16, val.port);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  exports.IPEndPoint = IPEndPoint;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'url/mojo/origin.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('url.mojom');



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


  Origin.prototype.initDefaults_ = function() {
    this.scheme = null;
    this.host = null;
    this.port = 0;
    this.unique = false;
    this.suborigin = null;
  };
  Origin.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate Origin.scheme
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;


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



    // validate Origin.suborigin
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 24, false)
    if (err !== validator.validationError.NONE)
        return err;


    return validator.validationError.NONE;
  };

  Origin.encodedSize = codec.kStructHeaderSize + 32;

  Origin.decode = function(decoder) {
    var packed;
    var val = new Origin();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.scheme = decoder.decodeStruct(codec.String);
    val.host = decoder.decodeStruct(codec.String);
    val.port = decoder.decodeStruct(codec.Uint16);
    packed = decoder.readUint8();
    val.unique = (packed >> 0) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    val.suborigin = decoder.decodeStruct(codec.String);
    return val;
  };

  Origin.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(Origin.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.scheme);
    encoder.encodeStruct(codec.String, val.host);
    encoder.encodeStruct(codec.Uint16, val.port);
    packed = 0;
    packed |= (val.unique & 1) << 0
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.encodeStruct(codec.String, val.suborigin);
  };
  exports.Origin = Origin;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'url/mojo/url.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('url.mojom');



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


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

  Url.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 Url.url
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  Url.encodedSize = codec.kStructHeaderSize + 8;

  Url.decode = function(decoder) {
    var packed;
    var val = new Url();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.url = decoder.decodeStruct(codec.String);
    return val;
  };

  Url.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(Url.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.String, val.url);
  };
  exports.Url = Url;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'media/mojo/interfaces/mirror_service_remoting.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('media.mojom');
  var remoting_common$ =
      mojo.internal.exposeNamespace('media.mojom');
  if (mojo.config.autoLoadMojomDeps) {
    mojo.internal.loadMojomIfNecessary(
        'media/mojo/interfaces/remoting_common.mojom', 'remoting_common.mojom.js');
  }



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


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

  MirrorServiceRemoter_Start_Params.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;
  };

  MirrorServiceRemoter_Start_Params.encodedSize = codec.kStructHeaderSize + 0;

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

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


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

  MirrorServiceRemoter_StartDataStreams_Params.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;
  };

  MirrorServiceRemoter_StartDataStreams_Params.encodedSize = codec.kStructHeaderSize + 8;

  MirrorServiceRemoter_StartDataStreams_Params.decode = function(decoder) {
    var packed;
    var val = new MirrorServiceRemoter_StartDataStreams_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    packed = decoder.readUint8();
    val.hasAudio = (packed >> 0) & 1 ? true : false;
    val.hasVideo = (packed >> 1) & 1 ? true : false;
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    decoder.skip(1);
    return val;
  };

  MirrorServiceRemoter_StartDataStreams_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemoter_StartDataStreams_Params.encodedSize);
    encoder.writeUint32(0);
    packed = 0;
    packed |= (val.hasAudio & 1) << 0
    packed |= (val.hasVideo & 1) << 1
    encoder.writeUint8(packed);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MirrorServiceRemoter_StartDataStreams_ResponseParams(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemoter_StartDataStreams_ResponseParams.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;
  };

  MirrorServiceRemoter_StartDataStreams_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;

  MirrorServiceRemoter_StartDataStreams_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MirrorServiceRemoter_StartDataStreams_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.audioStreamId = decoder.decodeStruct(codec.Int32);
    val.videoStreamId = decoder.decodeStruct(codec.Int32);
    return val;
  };

  MirrorServiceRemoter_StartDataStreams_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemoter_StartDataStreams_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.audioStreamId);
    encoder.encodeStruct(codec.Int32, val.videoStreamId);
  };
  function MirrorServiceRemoter_Stop_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemoter_Stop_Params.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 MirrorServiceRemoter_Stop_Params.reason
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, remoting_common$.RemotingStopReason);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MirrorServiceRemoter_Stop_Params.encodedSize = codec.kStructHeaderSize + 8;

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

  MirrorServiceRemoter_Stop_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemoter_Stop_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.reason);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MirrorServiceRemoter_SendMessageToSink_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemoter_SendMessageToSink_Params.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 MirrorServiceRemoter_SendMessageToSink_Params.message
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 0, 1, codec.Uint8, false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MirrorServiceRemoter_SendMessageToSink_Params.encodedSize = codec.kStructHeaderSize + 8;

  MirrorServiceRemoter_SendMessageToSink_Params.decode = function(decoder) {
    var packed;
    var val = new MirrorServiceRemoter_SendMessageToSink_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.message = decoder.decodeArrayPointer(codec.Uint8);
    return val;
  };

  MirrorServiceRemoter_SendMessageToSink_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemoter_SendMessageToSink_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeArrayPointer(codec.Uint8, val.message);
  };
  function MirrorServiceRemoter_EstimateTransmissionCapacity_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemoter_EstimateTransmissionCapacity_Params.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;
  };

  MirrorServiceRemoter_EstimateTransmissionCapacity_Params.encodedSize = codec.kStructHeaderSize + 0;

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

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


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

  MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams.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;
  };

  MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;

  MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams.decode = function(decoder) {
    var packed;
    var val = new MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.rate = decoder.decodeStruct(codec.Double);
    return val;
  };

  MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Double, val.rate);
  };
  function MirrorServiceRemotingSource_OnSinkAvailable_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemotingSource_OnSinkAvailable_Params.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 MirrorServiceRemotingSource_OnSinkAvailable_Params.metadata
    err = messageValidator.validateStructPointer(offset + codec.kStructHeaderSize + 0, remoting_common$.RemotingSinkMetadata, false);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MirrorServiceRemotingSource_OnSinkAvailable_Params.encodedSize = codec.kStructHeaderSize + 8;

  MirrorServiceRemotingSource_OnSinkAvailable_Params.decode = function(decoder) {
    var packed;
    var val = new MirrorServiceRemotingSource_OnSinkAvailable_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.metadata = decoder.decodeStructPointer(remoting_common$.RemotingSinkMetadata);
    return val;
  };

  MirrorServiceRemotingSource_OnSinkAvailable_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemotingSource_OnSinkAvailable_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStructPointer(remoting_common$.RemotingSinkMetadata, val.metadata);
  };
  function MirrorServiceRemotingSource_OnMessageFromSink_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemotingSource_OnMessageFromSink_Params.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 MirrorServiceRemotingSource_OnMessageFromSink_Params.message
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 0, 1, codec.Uint8, false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MirrorServiceRemotingSource_OnMessageFromSink_Params.encodedSize = codec.kStructHeaderSize + 8;

  MirrorServiceRemotingSource_OnMessageFromSink_Params.decode = function(decoder) {
    var packed;
    var val = new MirrorServiceRemotingSource_OnMessageFromSink_Params();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.message = decoder.decodeArrayPointer(codec.Uint8);
    return val;
  };

  MirrorServiceRemotingSource_OnMessageFromSink_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemotingSource_OnMessageFromSink_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeArrayPointer(codec.Uint8, val.message);
  };
  function MirrorServiceRemotingSource_OnStopped_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemotingSource_OnStopped_Params.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 MirrorServiceRemotingSource_OnStopped_Params.reason
    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, remoting_common$.RemotingStopReason);
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  MirrorServiceRemotingSource_OnStopped_Params.encodedSize = codec.kStructHeaderSize + 8;

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

  MirrorServiceRemotingSource_OnStopped_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemotingSource_OnStopped_Params.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeStruct(codec.Int32, val.reason);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
    encoder.skip(1);
  };
  function MirrorServiceRemotingSource_OnError_Params(values) {
    this.initDefaults_();
    this.initFields_(values);
  }


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

  MirrorServiceRemotingSource_OnError_Params.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;
  };

  MirrorServiceRemotingSource_OnError_Params.encodedSize = codec.kStructHeaderSize + 0;

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

  MirrorServiceRemotingSource_OnError_Params.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(MirrorServiceRemotingSource_OnError_Params.encodedSize);
    encoder.writeUint32(0);
  };
  var kMirrorServiceRemoter_Start_Name = 81813800;
  var kMirrorServiceRemoter_StartDataStreams_Name = 1868370921;
  var kMirrorServiceRemoter_Stop_Name = 1544600824;
  var kMirrorServiceRemoter_SendMessageToSink_Name = 161806593;
  var kMirrorServiceRemoter_EstimateTransmissionCapacity_Name = 189629937;

  function MirrorServiceRemoterPtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(MirrorServiceRemoter,
                                                   handleOrPtrInfo);
  }

  function MirrorServiceRemoterAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        MirrorServiceRemoter, associatedInterfacePtrInfo);
  }

  MirrorServiceRemoterAssociatedPtr.prototype =
      Object.create(MirrorServiceRemoterPtr.prototype);
  MirrorServiceRemoterAssociatedPtr.prototype.constructor =
      MirrorServiceRemoterAssociatedPtr;

  function MirrorServiceRemoterProxy(receiver) {
    this.receiver_ = receiver;
  }
  MirrorServiceRemoterPtr.prototype.start = function() {
    return MirrorServiceRemoterProxy.prototype.start
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemoterProxy.prototype.start = function() {
    var params = new MirrorServiceRemoter_Start_Params();
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemoter_Start_Name,
        codec.align(MirrorServiceRemoter_Start_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemoter_Start_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MirrorServiceRemoterPtr.prototype.startDataStreams = function() {
    return MirrorServiceRemoterProxy.prototype.startDataStreams
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemoterProxy.prototype.startDataStreams = function(hasAudio, hasVideo) {
    var params = new MirrorServiceRemoter_StartDataStreams_Params();
    params.hasAudio = hasAudio;
    params.hasVideo = hasVideo;
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMirrorServiceRemoter_StartDataStreams_Name,
          codec.align(MirrorServiceRemoter_StartDataStreams_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MirrorServiceRemoter_StartDataStreams_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MirrorServiceRemoter_StartDataStreams_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };
  MirrorServiceRemoterPtr.prototype.stop = function() {
    return MirrorServiceRemoterProxy.prototype.stop
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemoterProxy.prototype.stop = function(reason) {
    var params = new MirrorServiceRemoter_Stop_Params();
    params.reason = reason;
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemoter_Stop_Name,
        codec.align(MirrorServiceRemoter_Stop_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemoter_Stop_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MirrorServiceRemoterPtr.prototype.sendMessageToSink = function() {
    return MirrorServiceRemoterProxy.prototype.sendMessageToSink
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemoterProxy.prototype.sendMessageToSink = function(message) {
    var params = new MirrorServiceRemoter_SendMessageToSink_Params();
    params.message = message;
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemoter_SendMessageToSink_Name,
        codec.align(MirrorServiceRemoter_SendMessageToSink_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemoter_SendMessageToSink_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MirrorServiceRemoterPtr.prototype.estimateTransmissionCapacity = function() {
    return MirrorServiceRemoterProxy.prototype.estimateTransmissionCapacity
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemoterProxy.prototype.estimateTransmissionCapacity = function() {
    var params = new MirrorServiceRemoter_EstimateTransmissionCapacity_Params();
    return new Promise(function(resolve, reject) {
      var builder = new codec.MessageV1Builder(
          kMirrorServiceRemoter_EstimateTransmissionCapacity_Name,
          codec.align(MirrorServiceRemoter_EstimateTransmissionCapacity_Params.encodedSize),
          codec.kMessageExpectsResponse, 0);
      builder.encodeStruct(MirrorServiceRemoter_EstimateTransmissionCapacity_Params, params);
      var message = builder.finish();
      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
        var reader = new codec.MessageReader(message);
        var responseParams =
            reader.decodeStruct(MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams);
        resolve(responseParams);
      }).catch(function(result) {
        reject(Error("Connection error: " + result));
      });
    }.bind(this));
  };

  function MirrorServiceRemoterStub(delegate) {
    this.delegate_ = delegate;
  }
  MirrorServiceRemoterStub.prototype.start = function() {
    return this.delegate_ && this.delegate_.start && this.delegate_.start();
  }
  MirrorServiceRemoterStub.prototype.startDataStreams = function(hasAudio, hasVideo) {
    return this.delegate_ && this.delegate_.startDataStreams && this.delegate_.startDataStreams(hasAudio, hasVideo);
  }
  MirrorServiceRemoterStub.prototype.stop = function(reason) {
    return this.delegate_ && this.delegate_.stop && this.delegate_.stop(reason);
  }
  MirrorServiceRemoterStub.prototype.sendMessageToSink = function(message) {
    return this.delegate_ && this.delegate_.sendMessageToSink && this.delegate_.sendMessageToSink(message);
  }
  MirrorServiceRemoterStub.prototype.estimateTransmissionCapacity = function() {
    return this.delegate_ && this.delegate_.estimateTransmissionCapacity && this.delegate_.estimateTransmissionCapacity();
  }

  MirrorServiceRemoterStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMirrorServiceRemoter_Start_Name:
      var params = reader.decodeStruct(MirrorServiceRemoter_Start_Params);
      this.start();
      return true;
    case kMirrorServiceRemoter_Stop_Name:
      var params = reader.decodeStruct(MirrorServiceRemoter_Stop_Params);
      this.stop(params.reason);
      return true;
    case kMirrorServiceRemoter_SendMessageToSink_Name:
      var params = reader.decodeStruct(MirrorServiceRemoter_SendMessageToSink_Params);
      this.sendMessageToSink(params.message);
      return true;
    default:
      return false;
    }
  };

  MirrorServiceRemoterStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMirrorServiceRemoter_StartDataStreams_Name:
      var params = reader.decodeStruct(MirrorServiceRemoter_StartDataStreams_Params);
      this.startDataStreams(params.hasAudio, params.hasVideo).then(function(response) {
        var responseParams =
            new MirrorServiceRemoter_StartDataStreams_ResponseParams();
        responseParams.audioStreamId = response.audioStreamId;
        responseParams.videoStreamId = response.videoStreamId;
        var builder = new codec.MessageV1Builder(
            kMirrorServiceRemoter_StartDataStreams_Name,
            codec.align(MirrorServiceRemoter_StartDataStreams_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MirrorServiceRemoter_StartDataStreams_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    case kMirrorServiceRemoter_EstimateTransmissionCapacity_Name:
      var params = reader.decodeStruct(MirrorServiceRemoter_EstimateTransmissionCapacity_Params);
      this.estimateTransmissionCapacity().then(function(response) {
        var responseParams =
            new MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams();
        responseParams.rate = response.rate;
        var builder = new codec.MessageV1Builder(
            kMirrorServiceRemoter_EstimateTransmissionCapacity_Name,
            codec.align(MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams.encodedSize),
            codec.kMessageIsResponse, reader.requestID);
        builder.encodeStruct(MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams,
                             responseParams);
        var message = builder.finish();
        responder.accept(message);
      });
      return true;
    default:
      return false;
    }
  };

  function validateMirrorServiceRemoterRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kMirrorServiceRemoter_Start_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemoter_Start_Params;
      break;
      case kMirrorServiceRemoter_StartDataStreams_Name:
        if (message.expectsResponse())
          paramsClass = MirrorServiceRemoter_StartDataStreams_Params;
      break;
      case kMirrorServiceRemoter_Stop_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemoter_Stop_Params;
      break;
      case kMirrorServiceRemoter_SendMessageToSink_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemoter_SendMessageToSink_Params;
      break;
      case kMirrorServiceRemoter_EstimateTransmissionCapacity_Name:
        if (message.expectsResponse())
          paramsClass = MirrorServiceRemoter_EstimateTransmissionCapacity_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateMirrorServiceRemoterResponse(messageValidator) {
   var message = messageValidator.message;
   var paramsClass = null;
   switch (message.getName()) {
      case kMirrorServiceRemoter_StartDataStreams_Name:
        if (message.isResponse())
          paramsClass = MirrorServiceRemoter_StartDataStreams_ResponseParams;
        break;
      case kMirrorServiceRemoter_EstimateTransmissionCapacity_Name:
        if (message.isResponse())
          paramsClass = MirrorServiceRemoter_EstimateTransmissionCapacity_ResponseParams;
        break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  var MirrorServiceRemoter = {
    name: 'media::mojom::MirrorServiceRemoter',
    kVersion: 0,
    ptrClass: MirrorServiceRemoterPtr,
    proxyClass: MirrorServiceRemoterProxy,
    stubClass: MirrorServiceRemoterStub,
    validateRequest: validateMirrorServiceRemoterRequest,
    validateResponse: validateMirrorServiceRemoterResponse,
  };
  MirrorServiceRemoterStub.prototype.validator = validateMirrorServiceRemoterRequest;
  MirrorServiceRemoterProxy.prototype.validator = validateMirrorServiceRemoterResponse;
  var kMirrorServiceRemotingSource_OnSinkAvailable_Name = 354805125;
  var kMirrorServiceRemotingSource_OnMessageFromSink_Name = 1263719888;
  var kMirrorServiceRemotingSource_OnStopped_Name = 1994824442;
  var kMirrorServiceRemotingSource_OnError_Name = 1852939234;

  function MirrorServiceRemotingSourcePtr(handleOrPtrInfo) {
    this.ptr = new bindings.InterfacePtrController(MirrorServiceRemotingSource,
                                                   handleOrPtrInfo);
  }

  function MirrorServiceRemotingSourceAssociatedPtr(associatedInterfacePtrInfo) {
    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
        MirrorServiceRemotingSource, associatedInterfacePtrInfo);
  }

  MirrorServiceRemotingSourceAssociatedPtr.prototype =
      Object.create(MirrorServiceRemotingSourcePtr.prototype);
  MirrorServiceRemotingSourceAssociatedPtr.prototype.constructor =
      MirrorServiceRemotingSourceAssociatedPtr;

  function MirrorServiceRemotingSourceProxy(receiver) {
    this.receiver_ = receiver;
  }
  MirrorServiceRemotingSourcePtr.prototype.onSinkAvailable = function() {
    return MirrorServiceRemotingSourceProxy.prototype.onSinkAvailable
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemotingSourceProxy.prototype.onSinkAvailable = function(metadata) {
    var params = new MirrorServiceRemotingSource_OnSinkAvailable_Params();
    params.metadata = metadata;
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemotingSource_OnSinkAvailable_Name,
        codec.align(MirrorServiceRemotingSource_OnSinkAvailable_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemotingSource_OnSinkAvailable_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MirrorServiceRemotingSourcePtr.prototype.onMessageFromSink = function() {
    return MirrorServiceRemotingSourceProxy.prototype.onMessageFromSink
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemotingSourceProxy.prototype.onMessageFromSink = function(message) {
    var params = new MirrorServiceRemotingSource_OnMessageFromSink_Params();
    params.message = message;
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemotingSource_OnMessageFromSink_Name,
        codec.align(MirrorServiceRemotingSource_OnMessageFromSink_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemotingSource_OnMessageFromSink_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MirrorServiceRemotingSourcePtr.prototype.onStopped = function() {
    return MirrorServiceRemotingSourceProxy.prototype.onStopped
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemotingSourceProxy.prototype.onStopped = function(reason) {
    var params = new MirrorServiceRemotingSource_OnStopped_Params();
    params.reason = reason;
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemotingSource_OnStopped_Name,
        codec.align(MirrorServiceRemotingSource_OnStopped_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemotingSource_OnStopped_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };
  MirrorServiceRemotingSourcePtr.prototype.onError = function() {
    return MirrorServiceRemotingSourceProxy.prototype.onError
        .apply(this.ptr.getProxy(), arguments);
  };

  MirrorServiceRemotingSourceProxy.prototype.onError = function() {
    var params = new MirrorServiceRemotingSource_OnError_Params();
    var builder = new codec.MessageV0Builder(
        kMirrorServiceRemotingSource_OnError_Name,
        codec.align(MirrorServiceRemotingSource_OnError_Params.encodedSize));
    builder.encodeStruct(MirrorServiceRemotingSource_OnError_Params, params);
    var message = builder.finish();
    this.receiver_.accept(message);
  };

  function MirrorServiceRemotingSourceStub(delegate) {
    this.delegate_ = delegate;
  }
  MirrorServiceRemotingSourceStub.prototype.onSinkAvailable = function(metadata) {
    return this.delegate_ && this.delegate_.onSinkAvailable && this.delegate_.onSinkAvailable(metadata);
  }
  MirrorServiceRemotingSourceStub.prototype.onMessageFromSink = function(message) {
    return this.delegate_ && this.delegate_.onMessageFromSink && this.delegate_.onMessageFromSink(message);
  }
  MirrorServiceRemotingSourceStub.prototype.onStopped = function(reason) {
    return this.delegate_ && this.delegate_.onStopped && this.delegate_.onStopped(reason);
  }
  MirrorServiceRemotingSourceStub.prototype.onError = function() {
    return this.delegate_ && this.delegate_.onError && this.delegate_.onError();
  }

  MirrorServiceRemotingSourceStub.prototype.accept = function(message) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    case kMirrorServiceRemotingSource_OnSinkAvailable_Name:
      var params = reader.decodeStruct(MirrorServiceRemotingSource_OnSinkAvailable_Params);
      this.onSinkAvailable(params.metadata);
      return true;
    case kMirrorServiceRemotingSource_OnMessageFromSink_Name:
      var params = reader.decodeStruct(MirrorServiceRemotingSource_OnMessageFromSink_Params);
      this.onMessageFromSink(params.message);
      return true;
    case kMirrorServiceRemotingSource_OnStopped_Name:
      var params = reader.decodeStruct(MirrorServiceRemotingSource_OnStopped_Params);
      this.onStopped(params.reason);
      return true;
    case kMirrorServiceRemotingSource_OnError_Name:
      var params = reader.decodeStruct(MirrorServiceRemotingSource_OnError_Params);
      this.onError();
      return true;
    default:
      return false;
    }
  };

  MirrorServiceRemotingSourceStub.prototype.acceptWithResponder =
      function(message, responder) {
    var reader = new codec.MessageReader(message);
    switch (reader.messageName) {
    default:
      return false;
    }
  };

  function validateMirrorServiceRemotingSourceRequest(messageValidator) {
    var message = messageValidator.message;
    var paramsClass = null;
    switch (message.getName()) {
      case kMirrorServiceRemotingSource_OnSinkAvailable_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemotingSource_OnSinkAvailable_Params;
      break;
      case kMirrorServiceRemotingSource_OnMessageFromSink_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemotingSource_OnMessageFromSink_Params;
      break;
      case kMirrorServiceRemotingSource_OnStopped_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemotingSource_OnStopped_Params;
      break;
      case kMirrorServiceRemotingSource_OnError_Name:
        if (!message.expectsResponse() && !message.isResponse())
          paramsClass = MirrorServiceRemotingSource_OnError_Params;
      break;
    }
    if (paramsClass === null)
      return validator.validationError.NONE;
    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
  }

  function validateMirrorServiceRemotingSourceResponse(messageValidator) {
    return validator.validationError.NONE;
  }

  var MirrorServiceRemotingSource = {
    name: 'media::mojom::MirrorServiceRemotingSource',
    kVersion: 0,
    ptrClass: MirrorServiceRemotingSourcePtr,
    proxyClass: MirrorServiceRemotingSourceProxy,
    stubClass: MirrorServiceRemotingSourceStub,
    validateRequest: validateMirrorServiceRemotingSourceRequest,
    validateResponse: null,
  };
  MirrorServiceRemotingSourceStub.prototype.validator = validateMirrorServiceRemotingSourceRequest;
  MirrorServiceRemotingSourceProxy.prototype.validator = null;
  exports.MirrorServiceRemoter = MirrorServiceRemoter;
  exports.MirrorServiceRemoterPtr = MirrorServiceRemoterPtr;
  exports.MirrorServiceRemoterAssociatedPtr = MirrorServiceRemoterAssociatedPtr;
  exports.MirrorServiceRemotingSource = MirrorServiceRemotingSource;
  exports.MirrorServiceRemotingSourcePtr = MirrorServiceRemotingSourcePtr;
  exports.MirrorServiceRemotingSourceAssociatedPtr = MirrorServiceRemotingSourceAssociatedPtr;
})();// Copyright 2014 The Chromium Authors. All rights reserved.
// 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 = 'media/mojo/interfaces/remoting_common.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('media.mojom');


  var RemotingStopReason = {};
  RemotingStopReason.ROUTE_TERMINATED = 0;
  RemotingStopReason.LOCAL_PLAYBACK = RemotingStopReason.ROUTE_TERMINATED + 1;
  RemotingStopReason.SOURCE_GONE = RemotingStopReason.LOCAL_PLAYBACK + 1;
  RemotingStopReason.MESSAGE_SEND_FAILED = RemotingStopReason.SOURCE_GONE + 1;
  RemotingStopReason.DATA_SEND_FAILED = RemotingStopReason.MESSAGE_SEND_FAILED + 1;
  RemotingStopReason.UNEXPECTED_FAILURE = RemotingStopReason.DATA_SEND_FAILED + 1;
  RemotingStopReason.SERVICE_GONE = RemotingStopReason.UNEXPECTED_FAILURE + 1;
  RemotingStopReason.USER_DISABLED = RemotingStopReason.SERVICE_GONE + 1;

  RemotingStopReason.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
      return true;
    }
    return false;
  };

  RemotingStopReason.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  var RemotingStartFailReason = {};
  RemotingStartFailReason.CANNOT_START_MULTIPLE = 0;
  RemotingStartFailReason.ROUTE_TERMINATED = RemotingStartFailReason.CANNOT_START_MULTIPLE + 1;
  RemotingStartFailReason.SERVICE_NOT_CONNECTED = RemotingStartFailReason.ROUTE_TERMINATED + 1;

  RemotingStartFailReason.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
      return true;
    }
    return false;
  };

  RemotingStartFailReason.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  var RemotingSinkFeature = {};
  RemotingSinkFeature.RENDERING = 0;
  RemotingSinkFeature.CONTENT_DECRYPTION = RemotingSinkFeature.RENDERING + 1;

  RemotingSinkFeature.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
      return true;
    }
    return false;
  };

  RemotingSinkFeature.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  var RemotingSinkAudioCapability = {};
  RemotingSinkAudioCapability.CODEC_BASELINE_SET = 0;
  RemotingSinkAudioCapability.CODEC_AAC = RemotingSinkAudioCapability.CODEC_BASELINE_SET + 1;
  RemotingSinkAudioCapability.CODEC_OPUS = RemotingSinkAudioCapability.CODEC_AAC + 1;

  RemotingSinkAudioCapability.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
      return true;
    }
    return false;
  };

  RemotingSinkAudioCapability.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };
  var RemotingSinkVideoCapability = {};
  RemotingSinkVideoCapability.SUPPORT_4K = 0;
  RemotingSinkVideoCapability.CODEC_BASELINE_SET = RemotingSinkVideoCapability.SUPPORT_4K + 1;
  RemotingSinkVideoCapability.CODEC_H264 = RemotingSinkVideoCapability.CODEC_BASELINE_SET + 1;
  RemotingSinkVideoCapability.CODEC_VP8 = RemotingSinkVideoCapability.CODEC_H264 + 1;
  RemotingSinkVideoCapability.CODEC_VP9 = RemotingSinkVideoCapability.CODEC_VP8 + 1;
  RemotingSinkVideoCapability.CODEC_HEVC = RemotingSinkVideoCapability.CODEC_VP9 + 1;

  RemotingSinkVideoCapability.isKnownEnumValue = function(value) {
    switch (value) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
      return true;
    }
    return false;
  };

  RemotingSinkVideoCapability.validate = function(enumValue) {
    var isExtensible = false;
    if (isExtensible || this.isKnownEnumValue(enumValue))
      return validator.validationError.NONE;

    return validator.validationError.UNKNOWN_ENUM_VALUE;
  };

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


  RemotingSinkMetadata.prototype.initDefaults_ = function() {
    this.features = null;
    this.audioCapabilities = null;
    this.videoCapabilities = null;
    this.friendlyName = null;
  };
  RemotingSinkMetadata.prototype.initFields_ = function(fields) {
    for(var field in fields) {
        if (this.hasOwnProperty(field))
          this[field] = fields[field];
    }
  };

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

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


    // validate RemotingSinkMetadata.features
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 0, 4, new codec.Enum(RemotingSinkFeature), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RemotingSinkMetadata.audioCapabilities
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 8, 4, new codec.Enum(RemotingSinkAudioCapability), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RemotingSinkMetadata.videoCapabilities
    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 16, 4, new codec.Enum(RemotingSinkVideoCapability), false, [0], 0);
    if (err !== validator.validationError.NONE)
        return err;


    // validate RemotingSinkMetadata.friendlyName
    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 24, false)
    if (err !== validator.validationError.NONE)
        return err;

    return validator.validationError.NONE;
  };

  RemotingSinkMetadata.encodedSize = codec.kStructHeaderSize + 32;

  RemotingSinkMetadata.decode = function(decoder) {
    var packed;
    var val = new RemotingSinkMetadata();
    var numberOfBytes = decoder.readUint32();
    var version = decoder.readUint32();
    val.features = decoder.decodeArrayPointer(new codec.Enum(RemotingSinkFeature));
    val.audioCapabilities = decoder.decodeArrayPointer(new codec.Enum(RemotingSinkAudioCapability));
    val.videoCapabilities = decoder.decodeArrayPointer(new codec.Enum(RemotingSinkVideoCapability));
    val.friendlyName = decoder.decodeStruct(codec.String);
    return val;
  };

  RemotingSinkMetadata.encode = function(encoder, val) {
    var packed;
    encoder.writeUint32(RemotingSinkMetadata.encodedSize);
    encoder.writeUint32(0);
    encoder.encodeArrayPointer(new codec.Enum(RemotingSinkFeature), val.features);
    encoder.encodeArrayPointer(new codec.Enum(RemotingSinkAudioCapability), val.audioCapabilities);
    encoder.encodeArrayPointer(new codec.Enum(RemotingSinkVideoCapability), val.videoCapabilities);
    encoder.encodeStruct(codec.String, val.friendlyName);
  };
  exports.RemotingStopReason = RemotingStopReason;
  exports.RemotingStartFailReason = RemotingStartFailReason;
  exports.RemotingSinkFeature = RemotingSinkFeature;
  exports.RemotingSinkAudioCapability = RemotingSinkAudioCapability;
  exports.RemotingSinkVideoCapability = RemotingSinkVideoCapability;
  exports.RemotingSinkMetadata = RemotingSinkMetadata;
})();‰PNG


IHDR**oÊÐ`IDATx^í×1
 CÑÜÿÒ
nò‡.…´3(¥¼Aé $ހìÉC;—‚Ëߎ DŽ,`ºíN3QlÃyJ 	ÝÿúAõg
uJŒ!îC™7 £'*膟”.Ms€ß*IEND®B`‚‰PNG


IHDRJAÌuϵIDATx^µÓQj1@QÁ¸•î-º!áý
·¯#©#¥ÓK¾($y ˜,;Ùltó¿YvÓÙBz¦«ÀOó(#DQ6«&«}úŒɝE'¥Ú̲Œ®¦°Ú,”9VF|۲á&ÓÑòï&Ýä~Ÿ¯«½!jY͑›…Èa¶›¼­RoFZ7'•”Ê!€fg¿7m¼>wÓ%Zëá§Ùa-Ÿ-Ÿ4…­çȿõޤ‘I]ÏIEND®B`‚‰PNG


IHDR ì‘?OsRGB®ÎéIDATH
íVÍNÛ@þvmÇv )P;@qU¡"õЩU¥ª굗ÐK%$ޡ}‡¾@_¢§^9¶‡J¤r
M
¦I0qclf%âfQ……‘ì±wwf¾™ovµÌuÝ7I’|JÓÔÁ…1V圯±J¥âZ–åäóù1†‚ €çyUUd>*xéýú›-èØúðj¨½ˆ)bó¡³c¼píPet¿{±€ÅÛ&ªÍŒ¦¦ îG°'s¤»X˜2 )n#Ǟ†9j¼úI„[¦Šϛu™{H+ Њýã.~ìùÐ8G|–ÂkG¸7c ¢ï¿Á)¾í6±ü¸„?m”lÄÈç)i¦L
ºʱúÒÁ!eæLÐ5NjXyRBxšàáü$¾–›xæ¡p†×,áKƒ‹R×
½}>­š¢ –QBœÐ~FJº÷”½ ¿o™™õ’RÐ7ü‹jpÊpÉꝚq’Âc´è™ïu`Qo4:1&t%շÿ—–Vࢡ]Èaš­!¡¬EӉÓNH­ՅJ žÞ-f´<ºӣå¢ý°ïK xø²}˜ù¨µBÌu4¨ÅxÁP`¨½†ûyЦæL°Q=FNt°D.
@øùþ»5p·Gˤ_QëäGY_ÁÜ
€ìBb۶cšò={¸è_HØu_ÉΝÀÂ^sIEND®B`‚‰PNG


IHDR ì‘?OsRGB®ÎéñIDATH
ÅVÝo“Uÿõû#m7ÄÚvµí6¶n“”mº%šŒFÁâf‚`¸ &^.FýŒñÒȝ&zN™a°³AÈV+
°õ¥Ÿ[x»®]·¶k-ýx=ç̚u”ðrÏÅyÏyÎ9Ïï÷|œóÉØؘÍår—Éd=x‚R.—½Dޑ¯ÅbéÖh4OÈçóàyÞ+'ž?x$žÅ÷ãw`Ð*!“ó\ÌEÑù|#†ܭøäè>ȥ’G:CfQ‡ÂX™½¾»)T*•š-¾PRØs꬀Cß
}ãB®Pª™؀bÄI¡Ty™†¸pþzs\œmüêZÍzŒ|þ¨ãTÿÙ×Ä%«Dð$Ä-ø;˜ÄÑ/ǑÉÈ٫w1üÝ,^î4áÅ=Æÿu‚H
¢	܊¦°׾3·cØiüÏ[<ƒÛëØžëÙ¢¤VĈhÍ&=‚±ºlØ}£Zɰ¯Z)GÓn-ë?ªM ¿݈7"x½ۊ/>ìƒô¿Jïwqúc7‚|7·êâí~;􈈑Ç9£3AáÒ\”uõ$ÐïZúÁýéoìXOþ$Ä7ò+ü=ŖÐÆápˆáÊÖ\õñ˜ð.ÃEò½[¯†‡çéß}HmÞÇЫ­øú£Wð¬A-Ê^$A]“°ÛíP©Õ0™LìÖjl¬Íý:¤9'.A«’£½©ÎÏÆr¹¡Po8\¾4Ž·<@Ѝ›(ÎϡÝéÄôä$ÈU
btq4E6›E<G9Ÿ†E[Ä3ÒÚÌ:wÁßãÑÑÙ	CC’É$VWW±¼¼Œô8ÿ¹,ä;ÛÇΎx<¬7·`aaôú”ËÆd6ÿèÇÀÀA\¹rÇ>8ŽH8KSÛn4I‘J1=5…J¹ÌtJ•
£¿žÃàûCÛ!P—@"‘ ‹H¥RèíéÁÊÊ
TÄ@¡P`é Ä
Ôjž#)J$V±ÿkøyd„ü¤Ìû|.‡ÍÍJ¥"ôzJÅ\û\5àtP·ª«h~)(¥Rɼ¢:*Šj¿Xܺiî©çTè]SíÓquŽ)ICÓZ7?ž9ƒCoo/8›ɀã8tuuazz
ï
"LЬµ­
×g¯áð»G0~ñ"d$*ä׎ñ<Mötz¼Ô߇ùù9äHDŽŸ8Jr»Ô-BN·ۍµÔ¬V+l6;3¬ÑjÐìh!©Y'áìF<ƒÙbÆZ"	«ÍzR”JÓ9IK÷‰#<ר5XZZڎÍúôAòaÝóÔ$ôYD¨\xO2ŸÏwø_ë­q[ÓôüÇIEND®B`‚‰PNG


IHDR ì‘?OSIDATxí–Cƒ\Y@ûoĶm›m۶ض­M8ÏÄf۶U/œ®»ˆm]|Xóüt


ôòòòJZ6_x—´°uu´…L&ãK-SËÖ
𵆖ýKàûP«ÕÏõòGò'u}nJ©ùÓ0gG"Ã#xøð!¡a,]¼_/oþÿ÷?®\¾̜™³puræ޵ËÜqžL†IkR]{òàì¬Ì-سk7ûöîepÿx¸¹qþÜoL;;k’“’_/0ÎÄ'°cÇ!àîêʚU«©««cִéTUV¸m¹m¨òhGepҖNÂÅщÌÌLôçëÒÜÜÌؑ£ػ{7ׯ]ÇÉށ„¸xN;þn»wír¹œ#‡ããéŌ©S©®® yW…î�èHÝÂNdn˜̥‹ѝ;E0eâ$n޸Cû„¼h4š7_G{{b¢¢HLLnÎ.8Øٱß>qfϘ)ÎʽkI^0…âøä¯êKɽSTPPðÜ%ð÷õeóÆMb¿÷M(Iғºåžë닒QH
OúÆÆFÞuäÞüë+=†²çãHìð…äM(/oBZÖYB'ÒÚ~!©å…uH+
°Ø_B@S–‚âLҒ^O Ÿ_@V‹êöAä»
Ÿ~NM<…ü¨3ҢîOï"ð?$4%‰(/nG*-èò®Ð'»:º™1ƒ”Ú_2ݷþ’%Ý"çŸýd#cµ.i¡݅ýGl/?ÿß?ßühÃOIEND®B`‚‰PNG


IHDR ÛOÏ}¢PLTEÝÝݭ­­°°°ÝÝÝ½½½~~~///000òòò£££öööÿÿÿààϏ<<<ÓÓÓÉÉÉEEE*„}ÑÅ-+ÎÎÎFFF¢¢¢ªªª!"’Å)'zs¾¾¾999"#‹¼%z¦¦¦ÛÛÛ***]]]$1Õ0$ms€tRNSÏÐñ>|›IDATx’…„0@у1ÛëîîþÿO»îÃxÖæhÂŒÄà„A,ᗀÍ‘Åv”€rð†£dåã_I¶ƒ/[`¼’-Ý>,hÌåE×)Wª5Ԃa½Ñl¹íN·×GúãÉt64.–«õf»ÛŽhÉA¾áôi¦/”Tj¡YšH͊m7$
Œ?ræF¶#?næžìIEND®B`‚‰PNG


IHDR ì‘?OgAMA±üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<nIDATHÇc```àâ~ ~Äÿé„AvMb fXJG‹Ññ
>#	Ìâã™Hö}9à’€1í1Z(¼þ`uÀàp?Áä€É£ø?ê€ï€ï]¯è	´y4 M2yXwŽ=•IEND®B`‚‰PNG


IHDR ì‘?OÔIDATxŖ¸+ACŸm۶m۶mÛֵm۶m۶‘×)¶×Fjíž/&šššcÃÂÂ<"##і7rN55µ1hO<óóóÑÖ"ç$M{‰œ»V€€l¾ ‚[ÿ¡ÏAt?£€Î7tA”
é='!>r´/}ïeîºD~ÉáØ$y	“¹Wb‘èrl[‚}‹°õ(†­ú„[9Ð÷ (zœQD§ë®ýÇð{ÂBHŒZÁKaßg‚º,сKúsMeõ…=ÿ9
à3 ρʼ˜±&.‚ÄÈÅдv½—"¨+ LJõÆX(²ë›æxÆØÆÁہÓà÷Dâ ’Ýiā)<«šëÀ3eŽ`ÞM%lùb†‰¯ÌAôzîR(»ë;oàvå|¶\AHßu Ú"qûäïà¤Ú-\ҹ†Ý*š0jÓZ…õýAôQ'DY‰I(ÊɅÛ>x=ú†D5Äl¾	–\Áá(‚ÒòR¤æ§à€Æâæ@Ā	 L}ný“›=‚Þ˨q8Há›-JÊJ`mF2ÐT#2
Ñ;í Ê#©Pːè¹É?\ÕyŠÄÜ$¤ä'ãªñÞÆYúã‡Þ
[#;¿Y´Û܏–•FàþK Æˆ¹«ƒÛI9E9ô1Ü7;ޔàÄÅW*¸ñÓ‡>bø5uj¾š³Šǯ
Â×ðÝz¡}×3Cx—
áeë8ª±«‰#`e`+«	+-CªWÎ@wv´Ð2$=p€Õ:TýžP"jBâ©âŸ­+Taäâ3*;pd é=¾‡D±â|ã²)Ÿ>ŸŒ€î€îeðZ}E¾a€÷ë¨,[«g•Ú€¶þ;&›‚vݐmQ{mÉÈvð?Wã,þãvæ{IEND®B`‚‰PNG


IHDR ì‘?OsRGB®ÎéIDATH
ÅVMhAþf³Ù4¿6iCIšÐBEJ°¦x(*)z(XAð¨Þ<(è[AðRQð䱧<”zQ‚(ôÔ\­¶¦$˜B´¦´‰11?»ë̖Ýfén¼ٹÌ{ß÷ޛoÞ&3C–––ÂÑhtÙb±Œã?QÓt\$¹\.NÛíöÿ¸<P¯ױ½½æéÎÿ½x­Žæëw?o‚¸°DOÁznà-Šh¹˜„TZ‡Ü(óŒ€͂§ë†؆Y×ù®Q”l%V°ãÄÂw](?€ëñUHdÒþWGl^X'™ÓáFgªXcá%*®Yœñ¤¶~ù>H~C
×f¹QFóý-ˆŸk˜™a*@úöµÛóÍrO•é'aÝ,ƒ´$øvú	äòCNMÔç_@ªüRãt³®ƒs·0º¸¥X×ñª#‹M´?<U]ÃÙT@{eÕ0ց¦Žã*
ßéHôÚm˜
ÊÓ<bӷœ´õ¾.±a^‡ř
à‚º:Žôûàï§b² ÷UœÍÄa^‡ñ¦„Ù8ã
G«УÃEŸÞï$¹yg*À~ç&,‘‘ÎZšÝ*
hmŠ/ۭüƧ(éñ?sWË32LÀÞ÷Â3p½'ŽäÉ©®x!5´Æ|
ªÞëÔ<`óÉïRi~2†ÞOo!Ì΀¢̶^¾<\»N9ýÊ
œ…pé
¸ðy-ÇÌ ù|^2ã5œLâFV¹ø±“€ˡqÿ@þ™UîBïâ
r]¬­-zšvá‘ÉdZh«[-‘ööö€Ì»É0::о¾>°B^ïrë9øýmȲŒÝÝ]å֛žž6]¦«€T*…R©&Àáp Z­¢V«!‹Áåraqq¡PÁ`PËâ‰âñ8*•ŠîÓ©èú	ŠŢ’CšLLL`mm
n·N§SS(Ðßߏl6‹ÁÁA#™L"‰ЎøÖV:Ç$)ú ?¶	{Qy¯ŽãIF»8÷~š‚³G¡IEND®B`‚‰PNG


IHDR ì‘?OsRGB®Îé“IDATH
íVKLAþf)²-X(­5U­¥C¼ ‰1Ñ(z¨‰âÍĄ«&è©	111ñàƒèAԃ‰gx3„ QP Q>Øe+ØR‘Ð.±Ýufp6´,Gê…9ìÿœù¾ùwþÙ%𦵛¦ùв¬:”pB’$uUUµ@ PçñxJd2躞ØÎK
ÎvÊ0¶TÒm;€mp­¬JrqŠ›)ƒßíG•lüZJÃÈ\ßâ	"oæ0g̡¢L†OötLèYÊ<ª+ªA$7’ÙÏ珜	VêÙoÅòš"X@àLß)áG{ø$â»ñ~êº/Ùþg±>ŒϏãÊËË8²ã(n¾‰ëo¯¡_yÁsº\žP‘ç?ì9PR€ñ‡۽±(:[BvlÍ30”x<ÝÑ+mÐNvR´…	¨ý¡=Uåˆ7Ó
JdÙoYvüöpÂ֙RP‰øð-ýc³£žB¸&e^á¥9B>ýô²KF¤¦ç3?{=±àw´²yÖ!³åwW‹©\:hÛ}÷Ó=x<Ö=3‹³Ñ<{°Š€ú[ÁυNGÏ!¹8i/<2óÝoâ¶-/=w[ï	“KG¡Êšü{1:3“Žílå
fRC¥UqI.t4žGχ[ÅaHD€¬JµMöÁɎX~I}Fƒ/ŠmUÛEþ*y|W‚´3œ½ïѲu¿SÈöEQ¬úúzîmè“k9ûm­ÊòJlÞäÅt&ɮN¬lC֮w€禍4–òoÃäâ4'¨ŸàBóE¬X¡ß!(NXo›X³
×\¬¿A€ž’Èf³¢"%“쇄a“ÿýKö>*ï·?NO9IEND®B`‚‰PNG


IHDR ì‘?OsRGB®Îé•IDATH
ÅVILSQ=¿s©´ԒbQZ Rœ
Ê4Ñ`b4J⇅1.tebbâÞÄiaŒq¥ƍnŒ!jbœˆC
…
Ž(µBjKÁÒöwø¾÷Ÿ¿¸«÷çåßwÞ{÷Üû–––»Ý~O*•®D%;ˆì`&“©Z­V琅Bðx<	‰<çä4R0uٿÂö8ƒ™æGàبÐõҮ}¸îžÆLx£­èùà#ѥ‹ՠÇÃCPAþÉ"I®¤ë3-O¼ó …ÜQ_˟}äƢ|´=¢äÔîàO?¾é˜ӁȋŽŒmK30
Xm…ˆ%¢m”HÔ-4e´Ïí@g/4›†zû&~ð›„xÖä2©©Æñ5u°h3ˆìEFè”Ê<«	2e!Î۽²ŠR¨êW«Ð56…Ңސ”DÅM)—"18R[
£Fƒ½+–
DRbƒ–s‰€%+âᐑŽ>(k툼vòZDÝ#˜ÿøÉÿ|Ó!èóUXf6âӰ«㪳B¤”IaÕèñúØaÜq i‰
WÚ;±Þ"î@Ö`;û÷xrye9þ)|Ão4òbC>ú¾B›§„{r
†<5Î>oéG­0ëtàÈ׿róÁ6¿ÿˆˢäÀ=û¼éE¤û_	/„µhþ2.ԗ[ŒpMbçž*|	ùÑ?>*’ëӭ¯0bÕ2œ|ø%dM˜u™ë‚u€GÀ:?D•voð¯Šͫʱo£“Óa¬®7CŸ§Âùm8Z_w`
¡hŒÿw{F‰#˅qéŠh
؞pÄ@²—•atrցÕKJP[QŒR“”äF—Ûlˆ'8t
{PS¼Ͼ~ãMdË?mw £7™›׻m•)˜Z)Ãå»�QYh@çX
Ъdêð‹eÑ32Ə™ËÑDÈL—®yó	4!Àçn¿ä£_E«÷;±Ö^»IöºQr q¹p¦U)Aπl"êÛݟÑÿm0ž‚ÍDþÜ^.„`töNDؔ~åed{¦@)Ѩ6­C"ar¡lœ'Z!ƒBžZTa´ä„SýŸ^֑­wqkc
az…â,K:ž“ºË傄¾Lèã ×B9)·Œ>‹ùýÿñ$s:M¿\LeQVÑQIEND®B`‚‰PNG


IHDR ì‘?OsRGB®Îé(IDATH
ÝV[HÓQÿmÎLﭦó^*ê̜ËD–E䍲û…H²‹Ùå!ˆ’¢@”4!¨‚"%º¦¹ҢÐÈnBér9—&IÓ)ޯÛrsýÏÑ-'îG&ô=œóïúû¾óýÿ–D"ñÏlll"`EÒëõ2†¶°Z[[e<o•½½½Ójµ*•JÆf*·zrR))˜tmղçHöèGwßèuZ™uàñˤf>‚ûÚlpcrPT!3yfݨ„‹(G.–@R¥ |rzÕ»°ÍW±bS‚ó!ÞÓäWUóâËԾ ´Ö$72fv'†ãޕ}È<º:=J^ɩá–×SþØÞhÔÊQ>JÀÇÇ/Jœʑ`pXC;DHÝ*Dl¤/Փ%ÿN5Ԛ	z–6v˜äFÆ€Q˜$¢lÃwÝ+Þ4¡w`áÁ<D‡{Aª˜ÆÇ©ƒ>nÈ9ë—R{6‰ú}mVásC;V‡xҳя¦—9‚–ÃÕف&UõŒ ðI5ÏØ
~$0¡(@|l l96h`d‘ۯáékՑåVñ'ʟIƒ·Ô-Ê^ŒŒiMzÂÌ	€(ÄB?²¡¬²ïë~R@;hlé‚F;Azp™ê<P}ÿ8"C=ÑÓ?Š´óÅxñ¶ýCã(e®ÐÅÉ	â@ª'’5uҸÆÅ"€¸5þÔ&ïv5ÝnÂnµïß$$€‹ªÂtÄDøPQý·NÜ-“Bû[­VG‡²¦¾ê¤
ó9àƒÌÞãDS†G5Ì‹ûDS¦ˆ˜ö“–8W„¨P>ô“Ô3ձX,¬ùádvµðv›Í×u	˜®̞‹ü½\áÍsF{×’ã‚Á_æDÖ1H! ‹™îÞQ=Ÿú\ý½Üp!c†F4èèÆJ_w¼{p‚ú‘»÷ۘҝ™ÄR*•Ÿ©ÖÍṪRÃΎ‡ŶóqC[[,v`>‘\œìçcnfkqͬþáaᐗ	yX›HN’›CžELòò…x’Éåò”?Žr*ñ4Å$IEND®B`‚‰PNG


IHDR&¡V¬sRGB®ÎéPLTEÿÿÿ€ÿ€UªUªªª€€€ÿ¿@€€€ÿUU@¿``€€M™ÿff€êU@7¶[mmmîDDkkkffs=ªUamm`jjGõhhqÿ½	ddmajjffoH‡÷ddlðF6biiéI:ccjÿ¼biiddjGˆùeekchh`flddi`ejchh_di8¬Safk`diú¿	aejû¾`dlëD8C…÷bfj6ªUadhbeiìD87«TbfjéE75ªUBˆõaehadk6ªUbek`djD…÷üµ	`eh_dj6¦c6¨T_diacj6©Sadh4©S_dhacj¢µ)`eiëC6C…ö_dh`ei`dh`dhëB6aei`dj_ciadh`di_ei`djaehðh'`di4©T_ehD†õëB6C†õ_diêC6`cjB†ô`ci_dh_dh`dhéC6`diêC6êB6_ci`di`diêB6`dh_diêC5B†ô`di_ci_ch`diêC5_di`dh4¨S5¨SìP0`ci`ch`ci_dhո5©T_dh_dhB†õ`dh_diû»`ci_dh_ciéC65©T_di@‹Ü`ch_di_ci`dhéB6?’Á`diC…õ`dhêB5_diú¼4¨T`di4§]_ch4¨SB…ô_chd­@éB5ò‚ú»s3\;«tRNS

 !!"#$&')++,-.0137788:?@@AABBDDFFFHILOQQRZZbcddfghiknqqrrssw}‚ƒ„…†‡‰‰ŠŽŽ“–˜›œ¦§©®°°²³µ¶·¸¹º»¿ÀÀÃÆÇÍÑÒÖÙÚÝßâããääæçèééêëììíîòòóôõ÷øøùúúûüýýþþ¢K¹«|IDAT­Áù;aÀñ/¹:HR²‘rLّŽM¡D‘«BÑ}G´¥ƒXʱ¹¢ĦC—t8*ó¾Mó6³íó°ú%Ÿíêš{X^âsçMQ>ú$j^š†±ÑÕÌÑݔÅqLFŠ`¤UpãûÙF™+ûáyü…ü"*´Fužȃëðk-ˆ#ØøšzÍöô*¦ååۙåˆan6nÂ_˜þ¶ý3 ¹·áóª/	j_$؁±!ÈA˔›Vx>$ÄÜO’Ag{MÓ~悄è–˒+0,
dÖÿزƒEŠlÖ-“UX¶z<žg®4æ«ÖõÛá°y^ªT t ‰†Qq–S€]*5qºkø\íø­4é€ü	l0¦OÂz§ÓùMÔª¼Tvtd>þôÞ-c&ÖÅÏìkZßþe%ċ•€]*˜Èd8#mTŽãuüfz²K‚k#–ôÎ×mY®hè¹ÂpÝeÉýùžk4ǽ7þIEND®B`‚‰PNG


IHDR ì‘?OËIDATx^í–!ƒ@E9µáÔ"h.íÀq4`
8‚ ¡­ùåy¨i`+ ù™ÙýÉΙ٬S–e°ª_¥“EÍÀ!išF]ם*j†Q¥ijCÿpØlÂcú¶՘皣HOß×Ûu‰¬ÙÇßøùãŒ0”îw©ª¤qÄ ²f_C]$RQ|eğãø c¤e!S–e›ÿåyÖÿÀI=0Mč8c
Œa
ˆ{S`ÿ¸l?Hn$М¬µ?fuQVqXÈIEND®B`‚‰PNG


IHDR ì‘?OÍIDATx^í–=
ƒP„=‘•xã,<‡½¥­±··ÕJmòžE ! ä§ÙøÕIŸ ÃìÛ˜AߊVY–þ=ACãmQ´m+J)£ÀoÐØxï/€î{¹湌a(Oϓ·mÜé3_/ÀPUò¹DZ\ŠB†º¦s¦ÏÝ:Æ(’[–-i˜£['ÀËqDwµ¤iú™£Ûç˜߁¦¡Ï-p]¶þmŽQ’$ü_
ÀûxG€­Hœ(Hcg¼?™›ÓK„ˆq¢IEND®B`‚‰PNG


IHDRŒŒ™±ÙPLTEDˆÌ?ƒÅ?ƒÄDˆÌÿÿÿ?ƒÅ@ŒÌUªÿF‹Ñ@πÿÿC†É@•Õ@ƒÄ?‚Å@‚Ä@¿ÿUŽÆUªÕ@‡Æ?ƒÄ?‚Å?ƒÄ@Ÿß@ƒÅ@ƒÄ?‚ÄN‰Äf™ÌGŽÆ?‚Å@‚Å?‚ÅF‹Å?ƒÅI’È?ƒÄ@‚Ä@‚ÄI’Û@‚ÄM™ÌB„Å?‚ÅC…ÈBƒÅ@ƒÄAƒÆD‡Ë?ƒÅ@ƒÅEƒÈ@ƒÅ@ƒÅG…Ì@‚Å?‚Å@ƒÄA‚Ç@ƒÄ@ƒÅ?ƒÅ?ƒÅ?ƒÅ?„Æ?ƒÅBƒÅ?ƒÄ@ƒÅ?‚Ä?‚Å@ƒÄ?ƒÅC†ÉI†Î@ƒÅ?„Å@‚ÅAƒÄ@ƒÅ@ƒÅA„ÅAƒÇ?ƒÄK‡Ò?ƒÄ?ƒÅ?‚Å?ƒÆ?‚ÅAƒÅ@ƒÅ@ƒÄ@ƒÅB„Æ?‚Ä?ƒÅ@‚ÅE‰Ä?‚ÅC†Ä@ƒÄ?ƒÄC…ÄB„ÆB„ÆFƒÉA„ÅF„ÊA„Å?ƒÅD‚Æ@ƒÆ@‚Ä?„Æ?‚ÆA‚Æ@ƒÆ@…ÅA…Æ@ƒÄ@‚ÄA‚È@ƒÄAƒÄ?ƒÅ@‚Å@ƒÅDƒÇA…Æ@‚Æ@†Æ@ƒÆA„Å@„Ä@ƒÅ@‚Ä?ƒÄ?ƒÅ@„ÆA‚Æ?‚Å@„ÆC…ÈA†Ç@„È@„Ç?‚Å@ƒÅA„Å@ƒÄ@‚ÄA‚Ê?‚Å@‚Ä@‚Å?‚Å@„Ä@‚Å@‚Å?ƒÅ@‚ÅC†Å@‚Ä@„ÄA„Ä?‚Ä@ƒÆ@ƒÆA‚ÉD‚ÆAƒÄ@ƒÅ?ƒÅB„Ç?‚Ä@ƒÅ@ƒÅ@ƒÅ?ƒÅ@‚ÅA„Å@ƒÆ?ƒÄ@ƒÅ@‚ÄC†È?‚ÄB…Ç@‚Å@ƒÆ@„Ä?ƒÅ@…Å@„Æ@‚Ä?‚ÄAƒÅ?ƒÅA‚Æ@ƒÅC‡Å@ƒÅ?ƒÅ@ƒÅ@ƒÅ?ƒÅAƒÅ@ƒÄB„ÅB„ÆC…È@‡Ç@ŠÊ@„ÅBƒÅAƒÄA†Ç@ƒÅA†Æ?‚ÅAƒÆ?„Å?ƒÆ@ƒÅ@„È@‰È@ƒÇ?‚ÅAƒÅA‚Æ@ƒÄ@‚ÄB…Ç?‚ÅAƒÅA…Å@‚Å@„Å@‚ÅAƒÅ?‚Ä”тòtRNSÉÞþüõû	$îéÑÏÃá
åƒýòâÌÈ÷
ùBЎ"ÍË%ìèãñôVø€¹úÁUÖ#ê¨Õí ö&«]ß'¤wvRæ¥ґ}…¢äÔàÝÎ`Ê=ǡA:6!Sn±-kdY^P0G˜3¿JÚی)C—(HO4TóuÅxb¾t.;<_Æðj»‹+™çÀÂh´¼a×9ëW~®gL/1NÓeM٣{„i¬rc©§ï*ºI\o[ª,pĶžmZØ5ܽ³sµ¦”>QE ŸF‚7ˆ?‰Šy8@•šfœ‡2–K°›¸’äL)e8IDATx^íØg{TuÇáo3ÉdR„NÖ$z/†&½wDzïMé¨H—΢X@A{Yuu­»º–յ—í½÷ò}ûà÷;3sNÂäœ33œ;÷³ó$×'çüÛüñ/%%%%%%%¥rÌÎ?<{ óª=‹ƒðP«ý³'õ¨bXíÌq/ʀV–i`ü]º¾‘‹kiؠŒ¡íoÿ†keÿ`6k曙H>ßÔî´eÁ3ùH²KE´mÞ$SÆ_ütâ¡nHšË#iæñVù›K·«Ûí‰ӛ½ҥ‚fµ'|HŠÂí4)Þ;$YfÝny9!$X.ŒRõã>4íÒÞ6ŒR½	·ôUFôžÒ
1n,fDÃf$ؖZ†
?Í(9֗aþuH¨M­i¨Ø>6~•ð›@ãý4]›îëp[0»shX€mù³väwÙT/Âbíšçç\H:"ýœçu‚ŗUT‡‹‡Sõ[hÁÎÛ-‹J‹oËD´m©>‰ÈLÕ{+¢dü´šM˜öË>ˆRЂêöˆßMTLDÄؿgó*þc>"æS݈¸uöSôÿaÁÇÚ0†ßä"l_/ªMˆSÍm9Û6v0›ѽ%ÂVeS¼Z‰ø̦š‚°“óج¶§¶ˆj9âҭ–âS[Ӥêƒã3F½>×òᮿˆ°QTKoS”…`øŸ£×«„ê8೻¥k¸?ðÅBÄá5?Å^dĈu0)yc#Áðª½I70"‡†²M™hlÍm4ø‡Àð-ŠepmXkýþ=¡ºõ¢áÞ<4)wJkªì'¡êûQt†[³(î‡ê0—ªö{¸ªmwSU×C•S<—JtSÊY
µœjÚ*İï6Z¿o¨¿þ­z¸ó,Ũ/¨FCL•ŴŽü;(¾wÆQì„>M‘Óì—ßڟâæ<ˆNþ¸fwÝ@ÀP—œ”Öø)¾µ‹bÜø	Åd_;а¡+Eß|ˆ‹/ŸS¬…¸“¢¶%lÈjCaL»×Ëó8¸±DOàPs(î…-'¬êœ‹|p®ƒ®]ŸCtL¶™[
uFµîq…bœûÅTˆÇm¿uÅ˧)~çn¥Xl‘§`SOŠI5úÊýٷ
ªHOMAØ5T7T¨zv”é‘©“áװí¯!ˆwå±Υ›•ç_ü+Š•;䱜ӗÜb7ŰmÅ"ˆ£z s}ÍÃm<EOؖFñ	ÄFŠ|8¦‡’÷P`_¶?-ó3ÇtÍ{мjTAJÌS):qþæ]wž$áÀóUÑfŠq$f6Ä7)ra_ó¶ÿ E{ÎüŽ¿¤èÛò+Ì_zŠnVpN/Áþqâ+Øöňt§…sgÍ'€:=º½ÛÆS˜<M€s{õk™ö÷tÌ!ÊóY8÷>Ečò8:6ùô
íDp´<ςswR¬´L§°iÅËîöœëCqD½šó°éQŠƒ–ÿf)\ÐKΏ ŽP|[
t	/ó™¿sE\xE7ـervöbAGÊ󸱈â)ˆÂ^—¹œù—(ÊáÆbŠ·¬7	#f•V[/\ÿHq®̔˜†zˆŽPœ¯A32×S4ô„è
M¿Üøn:B­£º!¯™–Ϩ>‡z™bܙ¯ó¡E.DIծbÈýUï¨î§àÒdžz{ Õ;c´Œ£áqXV#àÖSeyP/Qµ!·á`	"ҾAëý[æÃîïŠTæŠÉ0,זDdœ#~YZӾêÅáR¸¶ˆ¢_K¨ü]ZBíHrø}jžA…zdzÈXßîTÖkK	nk­Y°c@LC†Pm„!pÖÔRZDÕö5SÍÓ}`@5ñð-¡È>	CMitËB†õÞ]S
Ã׽(úÖ!.(ŠëфéÝå}0±ÞdïFœ®P¥Æjњ‰h$óSªQpϺêþ+Â4Lͦ5ªñÝOU–…¸Mõnž¥¥™6&Á÷¨*ö#Ðp¼¢¤-aÊz"JæŽ"!ʩ®K‹nIg“n.@D =Õ$$†ïÑ&Z:^GڨiÕÞ<üãW÷Qã–e¼ª¾ÃÕ̭DÂä½niép†1Tw³ÔÌ‹*ü¹åcª^mª钁„ª鈈Vï°ŦšR$ƒØæ}k"pž6ÌëtMZӖ	נ&xœ6µÈ@²ÝJÛþ‹dÛAÛÎ!ٞ¡m;l%ËhS‹’.-ÝfKKÀûk‹÷5Úâ}¶x_cmñ¾F[¼¯Ñïk¬-Þ×h‹÷5Úâ}µÅûmñ¾F[¼¯ñ¾Ek¬-Þ×h‹÷5Öïk´ÅûšõdQ'ﭝDJJJJJJJJ
þ`Ã4Fz©ұIEND®B`‚‰PNG


IHDRóÿasRGB®Îé»IDAT8c` 0‚ôGFF¶022–™¬ þÿÿÿ÷=þÜý@||€	*Y¤ZA| aN“ rx)°¢¢¢þãU…)ùí߿V¬XQ
s¦ü"\LLL %äÒ˅Ӏe˖½RØÄ@r”¸l6¹ÖrÅ.`……@÷3®¨ÆjH3ºlb {©4ÿ‹/ð
Áô€ÈéªþWª$Hmª™<P=ÌFæIEND®B`‚‰PNG


IHDRóÿabKGDÿÿÿ ½§“	pHYs
×
×B(›x­IDAT8˕“½‹QÅ÷%QYVX°-„4ÖBÄ/ÔÂZd„÷BÂ$Bì,m3‚X§Ø?@0ÉDE­±,ƒUš%é…`§Á@&̵a“ˆ§zλ÷œÃ{B
çÜM४ލ¢è
+Ai±X/Êår;ÃÄXkÏï€myÖjµ­Çñ}àðh<ï|ß÷Œ1DäDªۉãx:†ÙËõz}'I’×@)¥ÎW*•¡)‹·Ed7+VÕÇÍfs+Ë-—ˇ1œ©'FD+ÜNçóù‘,!"?Vè΁Ë92QÕ;QM«Õê-U=©ª½^¯×vÎ]®gÅ&“é7¾DQt`­½§ªoŽˆ|L]ôòŠÀé\Ó?Óã^†Þ
‚ äyÞ`6›}ú#kܻ¼Ïûý~ƒÿE­V;ž¾‘µ‹69)ð¸˜$ÉÓÁ`ðuUÁZ{hg¹B¡°ÔòZ“'Â04"ÒÉóªZuÎíýsÀd2©g×Äíäc›üvU}°¡×ÖÚ+Kô}Û󼆪ÞHÞQù¦ªCc̫n·û9«ÿj“©ӖJáIEND®B`‚‰PNG


IHDRHHo#!PLTESSS¨i'ÿtRNS@æØfCIDATx^íͱ	!Dс-à°³kiKltFØA00ñG/ûØïE2rj‘²–˵~
vEßPrëB_®RMÔX4›uIEND®B`‚‰PNG


IHDR« mŸˆ	%IDATxÚìœkl×ÇϝÇڻ^¯½kÁ&Ä18Rá… ¥
ÍÒ¨0mTUª]Ú´¤jã¥J[µêîÚ%J£¨š6¾+UWI«¶ˆ6l҄–ŠW<,
¶ƒ»ó¸=3¾cî¬gö^¯q戻³;sçΙ;¿ùßsό!”Rð̳ÛÁ$ë!¤è>ö•ӍŠNtȺ(Èê@G®éÿKõ¬-¶ïFñ¬#0…`ݒ8³«|k=–QèUÇý&ÿM'‹Ä ÷®;4–џÿ˳+/{°z6k°nNœ^.‰ä9E…GU
õÓԂ”±FxüzY"¢H^V¿†j;æÁêYYaÝÒy계²	Lª(‚uŠUê«µ¨–ÉYMƒ¯¸÷mVÏÊë֧N~7«	ûuÀõD0jLÁ:	Zq°ë|FMÞþ§­|­¬‰ýO—â¿Õ™Ç×(Œ%Ž%‰%Uîƒu}ïÛs¶#Ç	ԓo}ãÒý:û@¡_¿¥ƒd=„MürÃÞw×xúP² v±ò¶i°nKœܬ©ô›Žݦ’êVªsŠX¼äY¦h4$‰ð‹èžÕzü•di¶Ly°r¶³û²¿©¥ùçTS%ƒHªë“d"°:¥6©‘ÓbRûPŸUhK­_üŽÇ_Iv„…9‰zGH¶à¨Þÿcâ“ýáp®Ž‚ bœ*èf_ap‹Àêfüº¤Q€÷ ­Ù‘ ½6’õõõk'N
OŒ«ˆ°@èd”‹Ÿ‚€ñ0P‚KA©(;ï?pú¥g÷­x§Èx-Ê)Lº@ýVV,%*²¬ý†\ìfÛ5,–ÇþüJmw&cbWp1uîÏ&猲ʲ´ÝX.lY‚–3Ð'C#~ÃOoÀó{›!º*ç®áÏç5—²aù¡šªŸŽ·Õ?¸:^P'G5VGš"K›k#-KëŒrWs¨qishQÛÝáÝü2:¯Ë [¥•Ö<õû¸úƒ,Î;ÀcÈ}ÛÆïw¨{¡ÝÃ.~XmÇYû¹þ÷²c¥'gû K\jµٛ³¾—­¹ôa'ÛÞ鲾•}·ù€pv1H£Xl}Š¿íñŠ+뮃×6PBªŒÓ ¢‹Øg/Tû
]E¬)ìÞ‚GÖ5À3 ðæyj{ ðò1ŒwÛØ[¿?>ýCÔ܏d2Ó@L…5K1nŠ/5Ìîô#Üú¨ƒ:¥Y}Cºٲ•c]¨„Ëq:Y]k¿tÎĦ‡Š-Åí`ŀd­‹ÚÇYûIV¬}ŒfÇ}‘íÏû›fëËm‡™Ó|@ Ãìù>±҃ۓ¨²éŠJíà'Nõw,‚«ï]±±@û² lÝÐßú
…_âŸ\M~W1B8ú€ˆZ½¥½ŽÃu‚	§K¤U &¼Kz^iÀ
NÙv1NÜSän€´)g; ît5Î.Ò2‡á7̩ܞxºÄ̛\n„«kًL¥bìx›rBŽ4;fÇ,Áe7ïCŠ;7³OJ«oº™ÒƘÝ¡{§žN1›—·ÕPAßPÇþÓ@åg\Æϣ8hŽ«Čg}U2È>Ù\ZE®ò™Åï÷-tȱF¹‹¹§„óèv.ɩ^Ì%VÛé'ÆÙö¤8	Nmœ!‡‹™fíYà¦&RgX/ÇÄ-×ÛMɁZ)]`%А;“¯ª	BãaÐ1n½oYNœ£Ó@ÍÍ
(*…·Î,®@â@•d,’¢h©-„òLF’7ÑñùÒ>N–̳½µ€CÜ6§W(͔*Ñ×rX!“sÀGgX‘G?uÈF-¼ëN¨­‘ Æ/Á(]yÞ0là:‚îÃØTqølOÇè㉷Бå¶Ö"üHq
]ª
Á7U;yV]×Çyµ´Š€ŠX·h¡©˜õ~;pN Ÿá€¬fWé\Ó4MÏ<»Xqî>45aÊ)õë©scÐÞBn¨)§®<¨"Š蚥(×É4PmÌR.üWÒÒEø»]TrÞJqé?íšÊ€ãçdúÐ=8u^`ÕøØÖ¬ҵ‹ïÛGyÛ\̈$ñ½<qR¬Âý’*àŸH¯T¢|('dɵŽy+R÷['Uµʻ—}äí8
~`U³õ–™àÇÖ5ŸXOàogT1£	ÎïL>‚íÿ̇«â¤Sµ0—㬄áfûñ<éµd'©<PÆçÀè4ã6•gýÉ޺?î:8’EÅó¹U~å8µ_àd?w.R™h¬%ðàr\ÖPøõ_qVSç>ü›¿é¡<>é¤^®Ãù‡<‘YR-#uv˜Ý4œ‚v0_JM¯•ã†êd}Òǥ¢ÌÇÔ|Öön€¢(¿$ñãn•Í•»fý2
W¨Â®SøÇY^?9¬
»ÜâTÐtª	‚øBÅØÄÔ+–ÓáéY†a-çG,g[¢©œ4»YºX(ÐÅÝh	æcß|‚Õöòõ?¨­®–DY’‹ÙÙRO-›%“MîF<ë´ªšֳkcàs|¼Ë[ÎËץ¾ÈRÎTÖ;È2åRh·CÏ嗯§ý¥'ž¹úTu¿;ßæñêÆZ>º®t;ª¨Z¿$‰«1^}ß
VÏ<+<Ábö³/5~?;‘y͘±»M¶ìt]ƒµmþ¼ jº>Ž7@‡ªgžÝ2¬†½üÅÈ#ì›%¥¦%³¬\+Õ!äÓ öuúõq]§Ûvmô÷ºܳ…Õv_$šŸø•®ëàD¬õUSTh¿'uHQ™“6õ<.Þý‘+^w{VX
ûé“
Û'FÇ>©f•a>§Ê?h®ӠÊ/ÛՔšjªªŠrP’¥¡¢þÝëjÏf|‚åfOüàʗ%YÞ'ˆB“ ŠÄü[TՇW˔ÿ»ê iúE¬~!}ãÓù³	Þ˳2Àjٶo¤eIö­W•ì}1»¢­I~#
ü·&è¿ú/9=™ò`õlFaõ̳Û:fõ̳¹dÿ`´Ï#Õ?¼ڳIEND®B`‚‰PNG


IHDRóÿasRGB®Îé“IDAT8ÅR=KÃPM^:XA€„:ÙÁA'‹tÉP¨MºDñüupqr¯n’„Št‰sI~‚uUZ:”ÄsӼÚBœzá½ûqî¹ïÞ÷ž LZÄ1
ˆº®hS<ˆ¢èÒqœøÑ0g¤@¡P˜K¥RW ¯‚Pƒ~¤dØY؛0›Ýnw«^¯ð"27 E"Cσ°lÛöë&”Ëå3øn’³;îDâIh{—1¶?ÇɈ«ª*Aðîûþg&“i¢“SÄZðŸ‰Ëx&µÍÉ1È؊$I<‡°d4ºŸXà©|æ«’~¹3£‚HƒqŽYïòùü±qZê T*-’?N˜eY'‚pßn·7<Ïû"-!VÅ78d;ÉÉBd“žfv:Z£ÑøîC¿»¦iӸý)Y–gÑéS†ûøՑ<#öz½[×u_xŒ4âKP.
¼¡ëìøPR±XL+Šr
s
ËÅzÀúó# dȿ¾rŸ2Éý°ü¥ãgúfIEND®B`‚‰PNG


IHDR&”N:‡IDAT(SI/CQ†¿µ_„¥„Ÿ 6XX³°·"$jèÀ5Tç•HŒMìÄXAՐâVU¥† ¸´h¯×ù·Q¹¢oò,Î9ϳ9P
DTF?ç÷ e?ð˜1ç)£CQ°Wû|~œßé8NçLI޼ːÇn!öz½8¹Ö9}“3Îjêµòؗ±ÛíAüJÇvâ¿ÇwG"´ÙlEpC.—[†fۊg‰k¸¸Ëá^ËKø?¸!§sñKÇ/¦„O2ØOfqpöEêV74:êD,GH}.	v¹¡áá¨â°v¨•»¢!R”!¨y¬DµËÑGÌD¢îĊîárC48¨àH„‹{Ohµã娛¬4Ï5b6¬ï$\nˆŽž籰ûےWȕ…Ƞ~²
›	W6d·;dèZ
šFßPÃT5ͅ‚²ZíXO¤Ñ8]ógdÐlB4õn¨¿ߊ¶…Ö#ã®w­½Ö>PggÚÛ;̠½u[,ø*eŽ;5 ¶‹IEND®B`‚‰PNG


IHDRr
ߔ¯IDATx^•ÓQgäPÇáw3Weo‡!ÃÊÐ/0„Ñ|‚¥,ý"ÛS–~‰ÚzWÊ0��«a˜Û6çœýɾœLŽé^<BþoßÿœÖw¹¬ïþôýäݤõËGî!hwÜBú¢oÎI˶nñ¸ـp£®Àw¯;EQH‘ºс	¦Zº
ËWxÄTwÝã¦+ñ˜@Ô9V/Z!Ç¢&xÐ
»>)3)r\B@Č_6Rz<c+Ž`„.(p‰±\4+Nʜg‹g
í‘0ðCSähK}6Ñl
	xA†c¤Á
$`®×&• ÀÌŸi½`CN‡-ìJ³a©ó´¥•;gg0ïc~‹G(ôÈH¶€r{%^i»cƒº,r}à€[È	ӊ٨-2ò¤C9ÓÈ)³G†4;Oïa?2£'·Ç;/saÖÚ6؃¬OOh)ëJ_! ó9¨Wk›
öˆó|6ïrƾCÎ`æã2Jçô„MÈOÌÌ!g´³˜C0:鑦>#ˆQ8cæýnœ‡Yý{}ÌDÆ|ÄzÞc<aa̻w¬ÏϘÅbÍ<c…1
, oJ(³hp×1
,!P
”iސª7ÍÆ,uWÜÛÓûÇ'@Ž¥#(‘¢V)e°Ô4Käˆÿuè7Ä9H@‰5jˆª-ïPBäÚўpî»I %RÔ#§¨5+!	
Ì"Ž9á'Þ7sž
©>É}Î5‚
©>Êt,‘5&øQaÍLiÙөàÏoˆ®H¯†«úHQATï]#_T!Õççž
)j2‰ôȰÒöim5JWþ?J¤¨uO
v۶‡BB(E‰T•sX4¦Ě‚%DÔ_@ëqo°¾˜FIEND®B`‚‰PNG


IHDRr
ߔÀIDATx^•ÔAg\QÆñÿÛ{7!«RB(a(eh•î†a4Ÿ ”ÒU¿V颺(ýá2dJ¡”B	e¶mç>5¯‡ã^s2ͳ™ÅÜûþÎûÞsNûüý@”ðâ8@b•<#˜Ÿ(¡
)A›À/àØè0€uNŒì
Š7ÆàQ¾‚‹ÿ€©ß}„À5_D	¾F|NÌ1Ú%ŠÑ ±Îïb°¬½¾¶¬õŠÐgT0TP"Ñ9pi‘Jž&Æ
XPXµHgHçÀK¶EY`YPհ¥ÇXËÆ8kéûqGñ¢2¶2Þp§ғÁƒmùi¬ZzA°ÊbF+«<0:¾›{âάAËڱ" E=Îʫ8AîÐ
×`'cFÍsŽ;sëe²œ¿Îg©Þi†Á¢˜‰-\“­ú5Î=٠bC޶ŸÑìLÆ	þeˆ[£`
‚±PÀqÍ¿{+‰	öµ+cƒ.hJI”âÂc¼Ýò¯Gªu
£ ¥Ï¢šK۾‰<Ò~ý§
:{ }vg_ÄÀvƒ¹iT§þÝ?Ë¸®M£Åà|àÈ2N}i	ÄcÊ9½ÞÚá:w©ŠqèΎ¸ŽŒÎnšr¤þ†qg;°&w¢ÁŒp
@¨`“êæWbs­¡"<^£’oš2ÆΫ¦^¡jçºkôЉk."QmŽÅ__ÊÑùö§^3dH8˜QE×씝êç¦Ã`©*†1w6Š0¿ë»ÍñnîÒ¢Q9÷\ƒr›$BùŒÑљ}€ƒDjZõ}®PDK¬äJ¤á³FÇß^þöޥ܈²Bƒ¹Äj	-ã5êry‹(‹Ɲ]±3ª}ïSð¢e½ìD£±ûsÆuø{ªSG/]IEND®B`‚‰PNG


IHDRJ~õs^IDATx^•ӽKBQ‡ñ›EXQD&H[CK´¸õ²4µE†€¶D‹ÔÐØ´õ2Dc9ÅCÑP$Dm‘´HP’ö¢aAŠz‚Ãá@ÞS(Ïö½÷3ü†c‰&³ÐÑK;N	ЇeLƒ¶xEPd7RÄþ䨑$A	Á)NƸ&üè'KŽq9,!œ3Lœ3ˆ#ª!‚2H†°\ ˜VGß+Pe„ŽŒ@þôÉÛdxY¡B›	œ l•	±I™(]v5€~Ž%}&BÇoà¢`y¼¬iþÄN
°˜£Z
øhá‹4
eX¤S,fy«#¹·²Jž[…²ø%ud;
鑱I½¢€nˆš&èW< xÑ@çb†	*xÑS|“ÀÖB–ÄQÿÍæYV$dÆxǍíÅÓÇï6
F¹” fæÔ?û¤)ڀh²òdsˆÃ(>IEND®B`‚‰PNG


IHDRJ~õs_IDATx^•ӻK‚Q‡ñ7‹°¢ˆL†Z¢ŭËÒÔ!AþbØ-jPCcSÐÖeˆÆjŠ(Š„¨-’	JÒ.¤¨'8ä{
åپœÏðŽ%ÌBG7­8ñ2M–1
úØàAUÜxHûŒ’¥J‚CŠNq2Ì5á¿@/²ŒÈaàœâ$ñ˜AAP
„l/iÂfp`B}¯@…A¶80ùè“=6É 4ð±D™8AØ*bQ:ì jEIúL„¶ßÀEÞrøXÑü‰9œ`1C¥äñÓÄ)>J3O»XLñVC¦åÞÌ29nʐ@ÖIî4x¤K~Æôz¬€®Ÿª&kèW< xÑ@çb’	ÊøÐã|s(­3„,C̲¨HÈŒ)ðŽۏ3¦߮q)AÕ̩;êvIQ°Ñ`?iˆO¢öi#’IEND®B`‚‰PNG


IHDR``â˜w8‘IDATxìØS›ûh†ñ»HÞo3©ƞŒֶm۶m۶½û=öl}¾Ÿe¯¬1ž¦ûoúÜ×õœï¯kM)¥”RJ)¥”RJ©K¦™ž·Ù2\\,ð!ðUޗ>Ϧá’ôy§ϟÿ«وƒŠ>ÈçA¯#‰8˜N7äsR±ÀÇÀW½¾ô}N¦S%‡üçãF%‡’u·Ì3Q*ðž}I„÷ošg’,›
9$Õց/ýQ4r(YÖ0œW€Ouàÿ]z.u—óɸ·uØ+î] ï€4@€4@€4@€zf€&h€&h€&høïL‘§f-GWn@‡çyu ÂÞ-ô_â	tpÕ2w|»/૽ð&Î@‡fËÜwá$ƒü­c‡‰=.@ÆÊ<¶kY–(±ö¹Ü.€ŒfJ<?°+Ô2L¤H€"‡ëªiŠ<³ÙÛrм[u8VîË=©̄œÜóa™‡=ÆFöNµlæöún}jkbÖÐ1ÃDÃõ4ÀlÀñ?ˆËï59EÞÜè—î¡-Faí%–VìrKOŒûœ}ù!ëÓ=ˆm™{Ö{[éïûIJÈj†ÓwbOôW¸j·:5–èòiÃ2°öº/övfƒ}¾'f¾Êñ=P-sרÇ+´Oƒô_ë£k¹½†áگ²ñÒï;ês^îüOÇc¬¡Y˶•ÒʿŒb—[.œ¤	›/±Ôk.7æ`6äø緥ÂöØ5ýˆaé/ÝûwŒ™¤µ¶̃¹8ïÈa,ë¬Ჯ[äõ¿ߖWæ©р­isŸìÙ:â¨ÜÔ]®ŸµÔØ@íNÔçrë·U*ð©)r0uô0ÁDÀY¹¨:Ü7P¡Å&ºx’þÈá.à«f…kޞˆK,qÃp].vˆ8ä§ýpØd[GÌmsô5&è@-C3ýs×Õ³!'^2‰GöÁn8;Äڵéu–]kXº¸£†ð§BNï:€Øá–˜45
Ww
@Pâ±>‡&9ªiˆ«÷tÀö‡>±5.9êí]qv©qà0c9íð!<rØCx‰åä-@€4@ÙõK{w, Ìß:Œž
¤¤‹‡tñïòõÃÀÁÀaX˜X˜Ÿwcec#½êz {LIEND®B`‚‹µV]oã6|÷¯ط\4‡ÚúdYIؒ*ÉIýv²DÛD%Ѡ¨˥Eÿ{‡´œ8qZ»äƒwgg†˕º Wn•X­5}pÏéã—Wt#åªà܏ñ\ÔZ‰E£…¬(­rjjN¢¢Z6*ãöÉBT©z¤¥Teݥ¡×$•ý+mPJ™‹¥ÈRƒѥTqÚpU
­yN%¿‰½N5~qà…|Պ2YåÂ$ÕÅä•\Íú²ÿŠZMr¹ã”É‘M­Iq‚«AMò›ÙjE|UR‹Œw!j*€g`žËZy/9¡hV¤¢äÊxD‰ àž#;"Й7 ÷ÿp¡­Ê)—YSòJ§»Cà<$ö•©æJ¤Eýl¼=0¼/c×É-‹)®“{'òë0
îØØÓhNNN<rƒi8K¼¨KÌwûôõ«#ð쌌Ÿ¹ñ~#/Ž)ˆˆMÃ	C>#ÇO˜ÛÄÉlÌü›.f	ùAB6e	’ ž9̤ڦ^äÞâ_gÄ&,™۪×,ñM¹kÔs(t¢„¹³‰”p…Aì‘Ñ3f±;qØÔ÷	$P˜¼;ÏO(¾u&“·õÅ
ü$b D1<ÐuFˆµý9€#ÏMLÆóʅm 9éRz.ÃbëŒYN4ïs{¿Î‡};Sç*?ü»?VU@tüـŒf1³ò™ÚÑ,LXàŸÓmpq¨áÌbol}
|Ëþ‘='øi”X'»tëa+2ÎX½ŽC·›쇡$lHLþ3Sò½›	»ñ|×3ºg±wãYlضø½3§¢P1n-‘­׵C욜ñ3üÛxœeÌڣǣxæ޶¾™t:ƒš↦æ*i%Ñù¸–䮕,ES.ˆSåJŠ|r>ø
)11«‘ 0³´BpñHµ~Ŀ_Ò&ò{+¿˜‹„5/¸¹vµE²ûôgÇ\È57÷|HŸ~Ú|ÿÜù«Ý{|ñ»нÒìíöx•²n†E>øfó¤UïAäz½ÿ"­6|§˜+‘‘‹vu--¡÷;ejѬú™,W—?_]ýا°à)f.«3MÙ:­Vܢá´ÚYo,®›B›ÙdÇùÄØaâ0ôÔ£kHk‘ç¼:IMZñâ˜6¨uÒØr;B·ñFz;„1õ$-x»‘cfîøgRñÁZ—Š^§¹|؎qÛýl³yq¢Ņ¨xï0v	È^-þàCºüÔöÂNœ¨0š«´x-ÏØV¤½,­uÓY£e·bªþÇ>ÓxuX¢æ	^”\³ú0ã}ž5J¡Ý,^ï
«ýVÎûª[ÅK@«žZÿí¬÷10™íYíî½Ð#¨e£ù‰¨û¡GP—MQԙâ¼:û0á©Â?õø^o?£Ÿ|·¹*dšŸŒþ:áh…ÝX;¹Âë„Α¾“+|*ï™IÏsˆß؏ƒ/'Á&Ís4吞FÁÑÙð7¼¿ùé‹¥“ÛjÛ@†ïõCBÀ6^[rÅ6…¦n
ҋ¸½*½XiGҒծ؃%øÝ;:Øi›Z*ÐüšùvNšO`cêÆʢô0Êưˆ“Wð©DؔÖT2Tp|i¬›uRÐ9:°èÐîPÌ"øìL¾”œ	6CȌ@ ³0;´¤
px»}ǜo‚’j
ó%÷q
)¶¤Ü-@jÒ>Ünn>no —
g“y	¹ûR;¼>aR{"sżåÙ=sXT¨=KCž£•º8ù
O„dƒÂD°ÜK£W°Œãʭéײ´iD.`ÇíèEزʌ¥ø(юâYOáð\Ð3¡÷1¥žK-=NÛjTϥúKêòj򂺎öÿ܅•ö%39óM£Ÿkʱp&PñfW—mKþ“~þúò<èoî±É-¯ÐýÔñ6*>ƒ'P˜û$q|¶†=‰íÛQîÅßRº)ݎüA=	3ŸL"˜À6³!M©2hËN}ª´£ÕÆÉ~?,Uâ実@ïr`mÛ/+üŝ§ΨÐ Äáà«ú¡µûb.{#5ޛêùcͅ Lh"õ$‹^45Ϥ§FÒ~tA4Œ¶¿Ê
NßwWϲ‚za¹Áu…öṡ$s^IEˆ;CGv‡EPÜN{
ŽkG¶2?†8ùˆ„¹è)™QÆÒyqwõ…xZæÚìڔ;ÑãE–\˜o¤НPÏYî£ïäßñ›q‹mPÑNã0|ÏWŒÔ"œ¶׊ðr\áéÄ ñê8›Æàؑír¨ÿŽ“"Ž•¥•g4³;»g'X›¶·rS{LÄ3–­p_ֵ5ì\v¾6֥¸T
£ÐR#»¥2<8‚©àkéàLgA˜’àÆlÉj*Qôàø}w•8ß+‚’‚t°ùš{®QÐЩ2.!uà	nÖ׷wר¤¢ôä,ŠbE•O¸µæå4ŠÇ${„·`®½æÈ.¢݁n»ùO˜ÑQÓ@æ˜/Û׋€_déë?üÞeôx˵«Œmr8Á=N’l:ªƒ"~êšé¿LÏ;,•#fÙð†A¦åBú>ײá^cÅXã0ú“¶Sá@¢+¤H
ú+ÉNXzÎNÁR6ÖY¨YøOÃÁ*©¥§Ãñ¾ÏlLò9$)Iñ0z¹jÜQýü¸>›/>¿ž©¯,oè0éàb?ðöu;치°érOgìˆz½¢"ø¢‘‹͒‚0€ï>E&g¥ê,,xØ7A찬µí´Háí
àèe^š¦ùòµi‡bçl…"ݥ¿ûÍ#Œ7cc…¿}ïÆRJYR™-“œsFO¤Mg¯ÿ"Ïs¶T	­ûazơÓéÇͧÀAAîb?]¡¶õÙèݹn®mpw{)¬Nð⾗{‹èë†`tÔaÐxڔޙ©uSGz{‚KëLËvGz×ٞj‡­ø¡2ŠÛ# ûH!ß
±ŸR®Ê>–¨·D*j£…LJ¬¦YRÎ?|Ú<`Á1W¢‹ÔWW“âN’ŸOQ·ÿ™¥»q‚¦{v/¢d@9d0½±+äA©„€ûî—ÐfÇÞÃ=D7e²2i+«ý—Oè/ˆI³SúAŸ™/¨×é<!œe‘‹„Ä~@Gj¶”»…›\çá{Ǻ4ISÿz(j"Íu‚äá¦$aš +qPY¸(LP‘–¹í6+›0±òòÒ<.îP’¥y󛖤æ§N腶Uó¸CVî¢ÌÍã×AYžB$°üsO¥U˜øÈN'¬5—ú\ì’çzÜ}ø7hJ½&;u€²,(L,ÀZsµ6é¡޺*]3O’’Ðvï€",Püj6obõ>b¡vd…±›7Vì}¾³È
èé”îÿºhyåä¤v»	±nNkƒ?RØÏQl7­¨x3|㰚ñ{5n`ð‚Žtel,±Æ!«š²XŽEôaU9Ä(’jœv‡™y@ÿü'ցð?–Yø[×l¸•ªqºŽ
	’*
pjX6NoŠ&+ȓ;D›’‰‚$@f(w‚«™|{)c$qÃÃӂ(ëFêX0äZÜäa¤bÍSÄZÍE55UÑ9TëÃ
:#bAâXHAH[p²t‹â÷õS.Œ"š`MG4p1
´@y
Œ5Ž1êo#Ì0Å;¤«#ÀàbÔÂÚú®6°չ¹	t°X,á	hùùçöi´ÒPZÿZ3¡M]hÔd€­™ª!(òÄ+KPd`SçØÆNŠܠû*Zã'°g­IcÉ;´ä9ØÒjË4úâZôfŒ÷d Ì`Ôçߐ"™›ˆ„“®&PjFKA羀á½&.—xP
D
lW Bï®qƳ¡Æ¥_êÂÕ��µ[ÂíOŸÚଠO㰌‘ãzV(#NhչEòRáJrdöŒŒ:í¢@^åж”&Ñ	äӿZ¥¦ÿդã_ë‚±¹u¾]85ûϐ͟ÿ~“ð/è_ŸšÌ‹,²Nϐ쉋þ#Œ³4'VB¾~úïëÁ+a:$xFýN';~mV·®°ԫWnäÏÏ÷•»مä¾Ñéþ&ñîSíGÛ¥„	”†|”óa1K‹¦
=C%‹ ¬ܯW}r׾lD$ÿúQG/r¯ØëÑý;Z;Ê8¹î¤{ϊÃŽ讟B	üïFʡ…d·tÿt‡´t“’ôáºxݡ×ý;TXIq÷Zè]øm¡ކީQ|rqï&ÎeۊB?¹‰€Üü×քãv”eØ~j×7îv:þž_Sy˜ìžQç²ʒ4~÷HîÃÄiô¹®e–ãÀ%ð:­Ü“w€ixn(6iî¸ù=,ý†ª™•¸ѯÔlˆþ=¦ìï<­~býz£N?·é-.æ VNÀV`G’"7i,úÚ!ÔâÜSn7ÈÔCX„ÈL÷à&
3¨¡‡*·iHš¢"¶ NEV¨ß4y¸hÿ$v0˜7sЂ./¹üó4ù&
΍7¯ނ~ ÷àVFA耛߹½1Ùó¥…ûVIÒU&÷W©Ôè¶…‰{ÿ-íƲw~ž–‰ŠGiþŒþӳêï«kŒº;(óK?‡þl™¹6´uÐA@ó!ÕñÁ\ŒÊ]«ოeM™­t‚†[¢ÝRûc8=l‹›Hé|µašYvHN¨óÐ/¾~z+Ö.ó-êÅêªV=—}m`KÖÎEo¡á¤ÉäVÚjÇÝ_¯„âá†à"¢.õ¯ÌꤹäÃÍÿ^E¾{IŒk&ÜRðÍ1oam
(zä$Í^}Ÿ_€?ó#׻ì½æí Ü2öW¯ðõê‡ý•°_Ÿ뷊ʫ~粻p÷—‚ð«ÊõŽô*êFhe™kAøÙàxHO(M‰}<þM¾„1¨õüʢ™B] Ÿ/e•yôٱˆõÜ촳Äÿº±
wH݅ZѪÎlâ§>²nœéÃH¨§|×ð˲j̋õ
OE­3ÇíŠmcµå,×h(W´°\I0*ê¹ÈU޳jݜékSÃ4y
Kʘ-ö¾k~ëXžjÜØtåœ$vK\D¦<™Géx<î†;-;ø<‘…]e•1`+[ã2+ŽÅãt1ÙÏúÖt³×l%RƧ™µY¦<PfRʗìT°vžyÔñÜwN´ó¤Œú}59ããcÒqKé0H‚–ôïi08Ÿ»½jÎi¿þÎ4OTežÆ-\RX©Ø~2´BK+æ	Ï(F¡øU2í·ƒ¦ԹÞÂÓõ@oÇ·_¹¸8º戦×"wŽ£„š',ÕÕÊÅìËÙڎ&Å2ÅLì/[¸;èG¬$xþœ9wO]?٨Îè@ó3Óm†³S_QO>K|1g&FtŸí-Ycz²/é|Dm}§°ы9A¬:#m=c]»Ļ£i>éŝXí+¿2ùÂñ=†–ZøÑÚèéM€#V#֠$½»…4í-ƒq‹ǓÅã„ó•±N|fwõð8õ)F
º=æ1ëœö´˯f&ûÒrn±ÎdɈ¡aÚé0‘ڥè¶OJ~ãA­Ÿ_ڏ•ڦ´½áS9Z#î1L×ù¨ÅnŒ6}¦ËÐïù£æcØér$úzI«AÕ=­7ŒÑõ¥؟´§ßÁV5nûÝbÆ'¬FÂa4ÝSBÇTôÔÖóù¶ó$‘5_ÍNoT8çé#¸µàöBÊ0ï=õ6³<hû§ýäoì…@h¦¤‹*Vôamx³5vçѳ…~Lº>ëxc·±nm·ÔpÁTiᒩx°Áµ•!Ž™°Ï½Űßoh-*٪ýÉnœ?Žu˜Ï3ß[±EFmLŒ€VÍØmoKyfi­›¹ºÝör[Y†´é_ҒÛòv¡£U{إ
f3âûü¼­ÄÝ̦;¶rã§ÐO}<K1ݢ™-žá%õøâaÏ'Õ9kÑmíÅÏÏ.s WE¾Ä+ŸÚ,ËršªÍõ€©ÂEʳEw‚¾ÏÇ%÷4.™ǀórjº‘Ô<ÚölnÜq÷äÍÃõzcm9=hýxޚqÈhxÜ2’nâ0_œ¨:çJIL|ìŽvÎ2ó)iÅîIö|ªÅó†8¥™¹Ø=žòސ¼6™ûÕz;,NI•?Žð6ÜêiŻb隁ɜô´ôú‹Š視M?È7žá©´5¦Äԙe¶ߜԪ—½„ͺ]jÉ
Wœ¶¤ðÆNgÂ0‡Õä4ط¤™ r¡֪Îí`֓†Óï?ö×ttZƒ~7[p”N«Ãx÷ãْÙOƒc®wդëñÓxJ³¦HÍÈÖ(¾æó¥»*úó*Ús»:ö{w‰íp\õÔÕÈów»¨Æj"dä<bT¼.£--¶»m[“ýóx÷ej¢‘T"òr4Œ³.ÁX7Š60kAøÛÔ=~ùæ¹´3ßmÇr®¤¦©¹¿¡xk0.Ýô‡¦úùûŽõGτ÷oÐÞ÷Ÿ !¯è/L®g;?î1À[×+õuíúæüßÜøõØùŃ÷Û·Fãÿée^{mƒzF¿»̣|ÌqfpTäp[2­÷]ÕõÅsã(qä‡3ŠS—þôܣRm{ÂË~lè­C	¼ª‡3¦óB³çÝ4Üùs*§6«§²o<Yû¤̋}Ëx¤ú֋wx”´-w˜
'´çÃ÷Èa#wˆ¢k)û¸Qæ(ë·ÔÑÎ{
ÁL}u՛¯¦Ób·;Öa'NO&ãåݧ9­6S¨8BÖ
º­-šC™ߑ¥ο0•ñdx£y¸œËÞf%˜8R_fÄoæ‡Vì„[»ëT‰4’:CÞ×ÓÁ,ÚIšÒ;'òn+Gz„_±Mê@ØTFx
>†RÈ,Ô)'edJŸ^èv‹Of;uG‘>
z%yuŠ1e廗j==³ã<æ)GæÝÂû —w©:Íú«senb^›rû¹Üï,ñ>I)¶w«c-¥rÇ^ðj+¯Fd™àñ²;è¥r Öÿÿÿ̚Y³8v†ÿJ_ÇIX*•‰Ìf¹ŒŎÍb–_?|_ÏLOjf:]S•ªÜÊX #WÏy%9ò¶àëtU
Kš¹zWj(.Ìc„7U=†ÏÂ7MEžI½‹ëM|Æ:Ðl!>K-ŸDŽ=äNQ‘Ø÷K¡-mÈÙs4
Îî
õÕnî›˙_éÁÐӠ¬S{Ý"îÖ	¼,¨0ɵˆ«γÑD_š`¼6S˜xە\ô¨Ϗ«Ã/²žNdòœb¡YÒHeŸïlvZwO£ÇW"@ý¸5Cgmöà”ުâìâ»,/FXË"O)ü+0^Sv|8Åúëú¢3«ȼÄó­òy
uØévìg¢|&M¸ҷ¬b?ž+4ËÜrãL½©Éa£‹6ä-РìX:&
å.|Vy÷tOŽ¢+Äð®¦D’j÷ºϭÛõî³;JK·ÿNšw°½èA‹Ïâ÷q%¹w’g<ä{‹}»ø”ߡZú¨{é9yÙ8X ЃÁx•¯U{3W"µg¹M&9WDç×±ïŠNˆðŸý—9^=¼ÁÙi$PâV…€¸ä¾fON@³#¼ª÷Æuü™R¥c‹ï¼_’,%k^‚l5o7oÞk7xIۛ÷®A-=Ù±_D-*M¬
-)Cv32§Uf5I™àX;Ôðd
¢ZòõÉÃRÔ袔UÈïäàn
)ðQ(Àû„ïBZÛ>ԛ<‚ÐÀ0uF½róýX,&MòîÚÌåf@uaªŠÂòmÔ\Úw·êB]ëe¦Úêm%Vƒ֎÷ÕPžci‘Ÿ4•p9_¸y„ÐË
é9äcº¯¦-ή[з&Nڛ`È„ýÇƅýâϵIüdðåööµ8oÜÎ2g#<PÙ%£.Qʽ¯ õ®¦#%%µÑðܝCsGUΔ3²ËzùÇâ딯ŠŠ*ö(äE«¤iBõYß]gBNÁÆæ3M™5–\¼YSmǍ¦ýù1ÑfÛ*(GÍè@nÙ.ŽÀzetûvàá~‡a¿ڕ5v1lÌð±§3^?µ~>ï¨|§ÈïðÛ<šËQ^K_·xÙÚ:õ;LúÙ&¶’ßx‹ÓñüŸáäÝyXU'TüÓù?¬�Lþå~~ƒ–f«ýž­ü¯Ø?ññ›öìÁÿ‰™‡ýÛ/öøÃ|œ||ڝi²üj•ÃÐM¿°ý48þóõõë_^¦=*¦ÿ¥šžþŻüé®eşÿi¯åÃX`åܵØT¦ÏaÅþÖoûi´ýտúՄú¿(Ä_ì™ȿ‡ïIþá9ý1ÿ¯M–ˆ„?sÙ	Iòªüh‘#W
×ÏÈ’Ҟ8&2W%ԲP꓇ÖơKçy{V¬gzù{=fãñÈӍåDœ|ςH[î]ȹҼ”$ñõi†ÝÛÔÞ&bXӀ»¢Sãa“Åm%ÜÚÓåS
øÅhr7Ï
¿êJ¹§¢IZƒÔp7þ”‚ÄQf%^÷ùXâoê7½\	ë8SŠ©+öÂÖg?Ž2;÷¤ÛД«~¡xwk{™ÌՁҎ.²2‡ôºfó+UG3ÄFÇp\8¨gÌÛÉOt+FS Ì)
T_•s99ľ½Y>[qöG"Ó>ÕÃï=;ëûS¸€‰üˆ5ÂòH¥Éz‘Xµ¸÷WÜ.˜æv4‹
мÔB£å£}þ¬…wLޮŸ(âÄ`<„T¤ô7uø¥8±”¨3ôo«ƒ-ß¶§;—‹Ï/€ãÝëÂß-ÅOp†(Õv}?L Ùg\ú‡%Là¢}$Y¾ìãkS¼͈'R¢EªÌ'J_Y,0¼ŸÜD\
ÉùïäG·«S]îÙޑU€ݩÃ-Zڵúܲ½
§'vžSÏ×#êKyÿ€ÜYAxyDÍëÖ͔ԯªBaSL]Ž·(\iÜã
C*¶÷¼Vö'8ÿ£fÞD¶âÈ&<gum8.‰ØL;y‡9'sڞ0x3!Nª”ÚzjÍ<êf`‰[ƒùðó㬎E¨+YÄc·Ìbß.e£rúª4å½W}c€pÑٺ…öâ‰9§´òºÙV€«èこâ’ÌëxÄ:’ª#“ ˜âb§~J
‡2¬>wt7Ö;͉*µ€°y¾›–”œŒÞÃÕèWŸ5íW)t¥½£ÒFúj÷¬*¨§1d5ñ¾á~ªÜϑTÒU>•”OզKooö˜®—^ÊËz·çÇBôî7Ûg‘¡Ò>;MøŽ¥“VÍ„V‘XRÙçÅNË*ÔÓsÕ2ÑÍYA‚¤ˆh¬ÒȜûê'ΏðY	4
¼­XÍwD«ٽ;°T iG¸•ê•bÀmB†hÔâ#ú8¨ŠA‹·›GA
\^;8ú‚ŸÂÛY‡¼+Ä6ÃÓ}ƒŒðXj4ah‘Y¥bÜP¸«> ¯Î
	Ϊ÷ÉÎÍß/W÷©ÚM&L,6ªÐÜnPEkο…^¢²q{¡I+G užvJe¡[+Lð(‘§³ïiKµIxÉàò.´ôß-ïHXÖÑúð}y˜ѸÖ%dq”C,CñmNñˆy¯Š¼Ҫ¼ŸŽö G Y¹oB–â0[U-ÎâŒgžœ´Ýyt¾$Iþðt%xµ–üQa·È#›œ+N±¤ºÀtHº€»Äï;Py|®]{½7âeb«‡îoeŠz<J×ÍQ@ð°É[#þ8Bu…AžÃPª´Ð
I8W?w©ïÂù©õþ‘艙»–/˜råG¾D6u¡•4yµòìZßÉg»¦<—ÈP¸ĺOgÅuQk¿¤4éNAt›wzÔÏ*DyàO·òJ §·\ꌷ”MͦèÆäQF0Rèè˳6‘¶é‘Ø.YEYGËþóÚà¿2†+¸lÆm3¡O
§Q_
í<0a·WÞËù1nòÖÎ$ót¾Ä3~½ÇWÝX™$VÈcé<7
ÏÒ$!_šàà>–«xÿ06ãѶÉYÞ\ÒXAž"ˠîñ]£Y2!oÅæšlÈñbëMôíúfÔ.Ŭ'‘Z„I	
¼˜ÏuŠ¡FÑØùÑY}+XAÔÉ`®/7íœù²}ÞL¥&˜R cŸ{ û1	§À-)è›wçú7μ62–‰Jßm>‘1Õ{]\WØw¤
;“­ýEño]E9šѫOׯ]ˆ9Ëù&úŸ
Íþ¸·g¹}eT%~XÀ+]Qq$cînÏjQXFïq‰øÎwôîzUI4ŸÀçse3ês½ú¨	˜Ãõպ†î¬Gk‰@Çoç:–_v?=zˆۇ¶+@,ý³ÂÔã̬ΘÚôðh*h”PÍÖ7ºü…Õkì=Üå\†ӗяw—Œó
à˰¶ijÎcSrPà¿¶ÚÛ:êÇv1+^™dtîu¼Oés8טµ¡ëænFçkÇHÎx ²£1õuÜ	†ýH3fQXlü	Äô&6;,*‘‘	wÐEÅ`¾Ÿϸ?¶ÀQ÷41»ãàXáY9$y³úãòݲ+œ2x†P*³“¾±ÛWu«ˆ
dp¥’O6Ÿï|â».P*N¬Àx$459š’=åYciÅ|f^.½'ôpR¡EPÂ1ÄsȦKtïø#báCF@Ö½œ9ÁìÜ׽rïâêÈj�@0ܯºÄ)‘ã€ílÆ+Ͼڝ f
¢61®êbXuÕ|]YLYóɿ‰?¤Ç}Éès8†÷Ç)0C|êã°@t¬¦*ÉþcÝJf>•ù«·àè:뽡-o½`¯ï@²®2êzÒÎT=ó OV‹g,—x@ÚIÅ5„ºyÙ®b'<—þÌéeÙñç”;3ÒôS„ÚßvV‘¿Ìäۨªܼ9ù(-]œC[©×P±ðŽM0®~7x]ò¾gN)ØXˆV¢\¡ËõAàV¤'2Ûð÷ýÖ}ÂB6'D2>ÀV+·뭽â+¤IXjHBcýEü]ڹNÚéܱ®sòˆÑ]0,JS…t¹=»ÃåòÃzãzb¬r¸"åҕœßéÉ|‰üÅ›¨@}ÕrD\i’kÃmh6%«ëØfù^´š8àF}ý©ÍeõqÿÜ4Vr·ÁÐU¡’Nmü"XÊöÕD3ïéƒÍMJàcÈ9n|WÕ̕·)ìڹ… ·]Z~"Aà¬ôÜ(^øX®^7	°`ҥ²˜FͨÐa;GPuéýk[;w./ð:»jO\aºÁs9bÃÙëmî{ïÇUz  a½Ô1˜—´Ž„ʍô|gÝ[‚_-¿?ÑBM—G† 0F$mé>εlÞXÀæå
ÀàUX>H«Ä~G\k|öên$’DÙï¿DÙ{øtŸ  »µ¶Ru÷}òxUÎòƒv­IÆ‚`ÐO=Y{~WR
P$úBg¸?ÌþÊ2Ý zâ�ëÁ®†¿Êxã��Tõ©¼ÓCÒM„·
•Š<´7š³t]±ùgm£¡ÁÔø`ÄëM9EeõkR<¯îG�ü‰
NîžÞÕ|tx>(§g¨ØÀÛèjM7· :NMÏÊ'—öͪªÁ|îõ‚öžB‡zœa“BÄçj{ô慾ç0~	1ˆ¤ñP¶y|}pÇÑx±D¼҅­ôüàžsöîšòËç*
çVQä$‰¬	vîôw¾âã؂Ô3/;q¶ž9?ԾñE<w žië÷Ýc@§V[×mD2ˆƒKwPî<ŸOŸÀ@z,°G
µ9·‰¦a	à8¯|cªʃºÒÊòKtU«Õ"N:„JڝûísöMɳe҃¾~¼ÌXìãœ>Mö(婽‹@J°B^õ¨÷9»±º•_KàOÏ`÷xq¾צ¿H¸2Ÿ1ø»m&dÝCã0rçT¦ï°\aKñË5_ª¨÷WN.èˆ÷ÔFÀVlN:Rüg%‡ٵ97¤oý]ÛýA\qù
Ýhgd†é%›s Z§IÞÝ¿>«Kß".0´›_™‚³r?Hßè>+ߙ˛ÛUvo͆¾&Ý}ý"ŒŽU÷à?.Sٵ=;ìL=®÷B˜[¼ÃLh½
ãõþbx¦Җóæ‚*ñõ¦CBÛ>ÎÐyA¡]Ÿæ]I½õ´áÑ/\p$ŠÞud†Q©>;¢äÖI¥Þcåñ€‹ëL¿åÙb¼bþ̔±°Ø’_Þâ±pt²€,HUþ¤#;~êÅwʡë¹Ðtaè‡è,×néÄ_L®æê繊ÔÜp‰`¹¢oÂúãI륻GZ
“êŠÄþáÓ§²Õ蠋ÜAv/üR2…“~̇Ò;j\Žk¸¦›uV²¶ǙÚÃKfž}9Hú­ÑxCõ,(bcŽçxU	k±œª2?ŒŠâæËMñ®!¨¸p(^-±£'B'ÁáMÎÕ7FùÚCÓÛy x³N5{ý%îν¿§‘Sެëu¶íwñ^ª=G¤Һhºìhq†=^Œbé9õ8ê«%âòÃØëÝ)ñk×ïY+©tý°Q~½Wlw¿(+¾ÄW|­Êø&š‡ùõó|jn@‹c£!„þûw4»vöz ùGnXýõÕ?¼'ùÏ+ÞL{§cÑÏÿõûW;kùÛ;šÿÿ̛Y“¢H€ÿ
/¡a·ŠØÌ ((*¾!"âÊ)FÌß*P[íé{&vv#Ú֪Ò,¬¬ÌĬ/¿猱6h
JÇõ©ü
“Q@göΏÑ‰#3±Іó™‘}e‘ó$ß%÷=»È(úÃ(?]ýq¾¿š=ã‡ËÃÐÎBüahGh…æ6ªb@5œÍÌO”fM\;EÅ׾ž˜Zퟩ�ÝfyÎ
ÂÉý•i`ÖÅ^rf‘ Î#8ݸUѥ\ä!¬
ÕS¬0û¸ì0,àÈo—ñ\v+ö
e„ǗàÞHRØÎç+c5¬„äåò„˜Û¼^«DWax•xKÒòÓ{ôŒP¾ƒÄ?À+«DˆÙfhÍóêÇÑ]š÷³=ö˜}&woŸfX˜ëT-v|ÚÒ
3¾'~հÉjhy’ífBuØH‹•±ù6J$Rãy)Kv?µ~–F¯®õéñ›¯ò¯æÂÙ/PϹ𥤂(?šöU¥.2A,
þ‚dÌEžë°íhÛÂE¦Ώ”¸ÆôΈc|·Ep¬1Á7¾îNؠ‹;"¥fõm7ǜ4éoýYSTëÎÊ0CE
ÍñL¢uYÓ^MVxâVHAº3UŸْ7Ë쌰šËV¬ó£V+ȩ%™â”tYÅZõ-qâŽíD¦Åʁj©÷÷~`†“ï'æd~O£N݆z<x´hj+ã¼zÃØò8=n
Ò*iu{0¨amÈZ¡ùæP–#bÈëxEI\n±b·'°­lí©qb$Jj­MÇc¹©;°V­ÈÜ
lʙx°!¢£gœm)´離PéO‡M°Îb¼½¶<%{Әá¡9™ò’ákW“N€3A|”GËÞFäèÔBŸu(ÑÞvЛ\Eç‘ðŒ&ÃßR®ÇÁúd´ü¥t´Ӟß«šӱ)f`g­¦Ú<1“½±Á7ÅnºJf§ö䤋ÊÎpÖKÃßD}Uš0••¸4ʴçÓNgbî·	sÜÉÀù“ ÞõÀj¬C'Q¡³:3eïðÜx¥f­ä19cz9Uü9ú*ՉZAZ!4¶ï}XÓ얹WS¿N±ÚïÝøqquR_¦›>8•‹ËjTÉ$½ç«.í0Uáó@ÂՀa}º|ã2oƈ|äY瓟î`Ôú÷v=T)ðÄýÕuv™ÞÃÒW|^“›¥I¾\U”?ñðù奁¹¿•s[q«Ñ'–ÿ& җ9î*Š£WÅvâ­¼`구èåR•¤­kíÑgZ»Û5Oè#ò‘B~W8µ~sáÆðöªqyçgŠÁð{½¼4ü¦^ò™@ýà#ás½Ú,ÿ1
áõ}„5üw}õ%}8çÎ-é§çÜ*r¨ýÈÙÃøzhMXQ Œ-+ítjZ8%8âèL9Ço³ìÒ°k_u)žëvùõ"©ߋ2?²fºJwyÉ5ŒÝÉØÍõL«´×MO¬…L‘±5—Aszƒ7ž±x£fòiØ#ã¥שZo.k|ŽF‹qþ!F’ùs}*ÃR¾èi_ß8§8e¸÷7ÿÿ|š·ҫ:„ˆ‚h¥ȶ	Â&™Î&ƒMÎOôw·º…i4£ÝýV£B5
Òá¨;ÆþqGƒK²F$‘ÉøÙ12z¶ƒíáú!™¯--\¦#¦9QÝmÿbŒlW;—©’X±‰Ì/Èz¬:¦·rÐ}E Y³ȿÌîmÛD6џŒ™œ½¿ŸšÜûu‹'%m
u-x$¾Uv6$OBó•Û/ëVþ>aüHøf¦„$'ÔMaÚMÞÈ
k3I¶`TAI(Üj†#/d	/E<Î߁¦†çW?ÀàÿKy†ã÷¸¼[?ßn߃8֛[q)A®;'ä†I‰̅ýL¤˜ç¬(ûôڗ”*Ö]ÐJ2i°qBÕo3`ƒ
)Äpö3ûéiq1µŠw”‚CH’eˆ)Üzâºï¼øž·´CW½vF#åè7&Òë˜I½ܠ[o<yFû¹äO›^¶pe®Ìà6J\à}>¸G²DF\D«‚Á#1ngÍ6*»ÌÈh^Ȑ¡¬Ñʃ˜,¹yìׯãÀ̀x$.Ô<"%-,޼³LAøõ¬ÝÊզë
¶¼é_ëÐL±7ɸƒÁ#ôŸȐ\±Ú_€XÂ16ê&óÎ8èåßçÅ~ýèç„ÍkO ¾4i^/ä§[ŽcR)îyWFðñí¨×Ž$‚.—&Wánðã&AÈÑn5ÍT@ÄykM¿ëô“(ÅB3z2â
Ð-Öm]+Ì+|³®àŒˆÚz»äk4Йžµ=hÁsß*¢õò|eâ(®CïõðÞ	O	'=àü„ÕÛC"RYNTïÛÅê5ІR÷¾—ø¾¹v—à~%n!—:íó°=Ÿ6²¹.fÌÌH?WòŠ‚xŠÕFQèÂÔèLz‰óyçMmÐlªvþ1@U„έޅS$È„g“eãí(TïUá.(‡ô÷D⼶—îä–2E„]¬ýà¡e(ã··ÓÒËUÕôÖI_÷Õp) &P³ñ°bT»¬©ë_ÿ¥¥à–+)

ÜLÇPvç·2 Ñ΋À۟ta>ѫTÃ3Y•¸qW.NúØ.uåƒù|©­êšÏq`&JYú0߾‡ץ¤Œ¥	#1ÃF¢µ-9‘juv8˜òØ?\딝àýì?‰_†Z»Oä)R¼-©w`+Ž¿ô>™xûý‡›üps˜	áâfq;ÛP^0
·løæ"w\‹››HßMÃw LCHk)¼º®ÓTj‚ãÖުh±|Î.¡[©ÂçJµm™¼sÓ	ñÁc'¸4¹ãM‚/I’àƋ٪pŒU+ûüßó÷=1ã?ÿÿì\W«ÆþALˆ>yDïôˆ&D à×gusm續8ř‰Vše¶ò}˞õÆ\ŸЏ­GŸ#º¶³VÖᤘ¤õð1³¯QÕu)°ú04	œ
uÏ,®pËþûÌ(’be^3:Ò¢8$fS=¶ֲ[%OWŽøG/	í)Çü®ǾdYôâiHè#䶯MÂñ—éxFu¶©À4‚ùÓM°OH_4ŒªëòL2hižŒËÞÝʌjºMÛÝÉOoÔßd†8ólIn£ò±—XèulÄåÏJ^5N^
*ZP~ö
s¢|LwWìqÑd¬ÄǬ*|Êqüéíˆ<k
tf–«Yo»xôú;„°ȯͱ^‚{_5èݧVÂ=šØw	È`ög *Ú
%±Çþbn7¢cè0Ñ÷ÃÏXr¶‡Œý$$§úcWÙۥìC+›ÅXKÓò»tÁ_䁲юÚúp0ÊÊBÀ4AÂÀð„T¸)j •Û]ÆîHI‡GZ¾>–RÆGv¨a6£à–wûâô$} Ž÷m€ýQ,ýÔ		ŸÖ~Ä÷¡ÄÝî JÿáÌ?¨cMKýèo9ş~´1öµöÛͳ߽£ýÛ~þò+ùÚÿŒþó÷Hú•±xb÷eóÃ6Û2aá=e†~À"RÓċ€‰ó®¬Q•-®Y{WLÓÖ+r	G/ÖÓ^4q2¤jq:ÀS=AÐ]eºÇòÖ.ë¢ÀxG—.˧]ʙ¶½„æ³àR|yÞÿ¨`¿˜Cõãâ_ÔG¾ß?×f4{¾^Ú'•c•›Üì7¸?ovÅã!JF˜ì·‡pÒèbCÝmA¡A¨‚;óñ"#Nöúá%¬ÔÁï»ì"¾ºÉ/A²o3§ £sݧKܜ
¾•;´×¾úlmSâ¤wXwS»7êÉҳâP¿s޾™M‚dêÕu”§Ù"µPáÑk7ÖäOà·ÂZ¦Ì‘VÁY‰g9¼â-–@Ý\¾؎º$.X¨dÃ}–ëԟì.fë¯Í%cnÛB®<€°Â)zç2·_J«çžéϨÉ

¢«†À劁å/¦€SÃ̗¬rXAS–Ïi,f“lùÑl®ñO¨œ7¨È̎¡= ÿåÌ/™‰mÙe Ï\îyÄsÎÅ3ACiަÌÍÈîÍ/1,6Øê¯ÕÛjˆºXVï8SØB‘¹Ùû¥Zã¹å+íV…—ŽÕØ"*{!$q_¹Ç1zҷÚÿþb¼¿"]tߊ3ð‚E`UŸã]åŒ"Sb„yÀ¥FóüÛ w"Ûy"ÅB¨Û
Øü<S
—0ÚéÝàž¥ô’'</­-I~ˆ_: ‘,Ât‰ü"ò)ÚH~œ#BmÇ~{­ÎÉ:G4ÐW “ôàdÚ{
ˆݤ"Š+60®õjRãªD^‹QꍬŽpZаú”w¼Îqþ™¸‡ӅÌ!8š-e¸ƒD¥‹Ôò´~ÈnÇ!ð‹\=iQ’¨!MO…Eï7¨y‰I«NüV+6j$HH{‹´³|Ã`X~¿b½Ù缿]îZm&£Ó:m_ß8cõ“XÇsã÷7SôN»Ph3¶Ä''Pw޵‚mz¢ÿ®*c¸ã^:s•_±€æDKP'‹ÖÚF×è©m%÷VǩàæfÞ,°‹¸Æ¨
Ü1mŸ>ÝT¹$”¡¢v\ÔU°#ºÛu°Sžë÷qÔJ­#\VûÛË咅Û…îg0y{áW“	œA	æw(M…­†ÿy#­e½zÐàKØ,çV+Â%— ¼£8‰AdJ¡,y	ì?—qÑÃSqC嵞IW‰ýt‰^³
0UZ¼`7ÊaD´-jÇ#2\ôÂ}-|βќ^u@CËkoíøªO­qº¦¯¾돱K⺲Ï&¢lLWÎHˆK*({oO×ÞvÕ¨Xã©ފáÝ\1Τ©n¨mžìáxŽ¥Êüºè¶ѰŠW®««j†
—û~÷‘¯èJ0Æ3€îQw‚)ָxQy¡¹¸dÔ!Ú#NÅXi>ôýe8ˆõ)GÄùEªž€’»狲†T¬Jè±µv úhÀÆt L—ÝëƒÚƒ… o7G–X޹Êg
ŸætÑù¬5⌮‰£\9G0p²DîÊÒÕ=ÀϨLò?=©‡}¶|̕ÂÝÍ׃Ùó±~­aQéµd5aW9œéI{xš­'åсr„5ÇXàáÙ`AçÐûM¹Å‘¬œ’!“KB<³÷yÈ7xaÂd~þKqkÈˆ¸rªëOlz»ÖުJüA_ô u9$ñWQ¹‰|¶¬6œUμ¬/Šyuæ|!Öj-L÷i¥5°žT-—êL¥È^lžfJ™Wq<k,¦Y_‘Ø-38 ~WŠÕA¼ŠÛ÷j§jòœ†ąÌtzÈ3$Íó\àBNÌ91µ¸›‚„øSq	§›?œb׊’ÍSᏅ±xۑljrD§񞪷Ôhgº³ÝH±ƒñ.ïðš74Æ
˜w­/¾E RÜÇþzs_Rè2ÖÜZ©ŠQÞá]9žžf†ëè1xõA­eóÒ,±NðýÒv,·Ž€E|°ìx¡oñ·,ÁáíJB	óØÖM—½ÓûYÎ׽™Í%
ÖnaLj–ñ.„>“HÄ>)kbÝ
<•흗#&wºßҎ´YG}NƒÐå­yRÌMÅ`'8Df0}ôåvj{îMÄV'ü®ÖÂÒä<ÖÝrú²Jìû;QWÊÓTÕd}ߚGøæU±L|nÔ/fñÿ|;6ù²Î_^¬÷ó»Kj~å®ò§~õ&®?zªտ)^ØãR;±ôy ¡ߣt„L0˜Â^EÄgo­ïb|'Õüv
÷íü|j¤Í7t9q]ö´ˆi™`ý„—µ•‹Çýd¿¶_X&÷aÕ6ª²_tÇûZ	;#¥_+W›Ÿÿh|u؁—AÉUÖ/¤oþÿn‰ß·ÄߙԟÇt}¿v·ÄO|±ÄÿQ³j™‚úc)ÿÿ¼\ٮ£8ü 4"ìAód @H€„°ÞØC!¬¾~ÈíÝéåöµFóV²TÆ>²}ê»²ä½ø•ÑF;™êqQB½;W‡}	jåmC×ƚßmœË!°¦Vß-aïT—:¿v‘š.¤7Q<u¸ï(¦¬ےx'S£ÞòžŋO~´âñZm<cmð•N>ãM9ºêu”°Û/ýmOåȺ6ÙHýh.@ò0÷™´0
6ģtѪúλŽp¢çŸÑ%ÏLnI¢zL¢¥?5•I’'>Ç2¦ž$MÉI¸IÌQ.{Wç[À¬¾ö9–©îpVº-»gý¨_Q4öa³í4å3î
P*[ႇkñ²KúLñKNžO¤.¥¯þ½€œð/ýSI‹Z¼½ÍNâʮ„˜5c_Q–›²²‰|<Ædó3þˆÐ µÅ!Þè¾FŒ„
Õ¾¸)AóvìëJ"ÂÚXòÂˎé`.¥Î5r5†×²˜_žƒH¤W;µ•%ÀWBîä»ˆæ§ݏØÙ`#ö|na~<!´ªVݳj ӆ2- ž1uɗ<¦`à±ÜÉ:ß.dd¢V…`»›C
Ӕ©ÒÆ1¥ܰ܊þÂÓÅݷXûÀUdkà`l>)”֬Fãã×쿝¤ÿÏMüÚmÂÓ`Ë/³{âÅ]u´;+ËY¢ïUkM½¹é/nñÕöE[z’㏱ó§Q^¢fƒ¦RìV0š&×±¸ã˜"—ßWKA¢,iÎ@YÛOrýy-æ†N,Ý1”Âl&Eåytg8Õà9#I
ϮT	]
šߤP‘Gz<åtNm¼ŸW(5ܬ5'w痖ªÓ~
\$&çdd4żªbšc¡|ƒ#gÝÏÂeëa«²·Թa°.Rä8ԏ=Ä‚J†mũ§
a \TV©ê«!Žވ`µc$ƒ¡Iû1fÁC…܋ÙrM”I›ÉŸ-Æ͠E†!±TI²íïÇT…5Ñs4‡“\2)vVÛ5Ê	}âw ­Ax½äR#(oxŒp°4ÑI´ŒlEÏŸ!­$çà€ä\£ßÁ0ˆiÙ̵n}Ò8°þñÍëoá*›¹s¨K|òHš¸³iòµíF¾Š¾aIîÅgꏭv":Áº+â
%ýqËã¹ÁíxZžaØ73§g3ã”C²æõ9ÉsѺ¾
ƒ#—DƠ.a̬±Yl[Øt'Ð-Ò|¯©qrÍé*!ö¥
h܍©bH2ZW«˜œNlÙâÛMM5ƣ*yE„Š=¾%¶”÷¯x_Té›×é«%\Aû™Šþ‘ñ1ý÷ýˆøó¿óÃýä¶ôw.ŸØÒþ­­ޯäÿ`ün»ùއöõ×à-l|ïg!þçó ÿ„ôÿÿ"ÊËèmQ,‘‚eZiQ1¨©=zæ,j˶&´æI¡¨4¯r~+líyjJz*èÜ~‘– «º‘C¹iªlš‚P\ԒŸ@³) ŰChÁÍf ›±ˀ×`gc@·`¬ÎB;÷,9JCiJjr>ä¨_¤³\g8Ðz6 oAڈLØu4ÿÿÜ]ËNÃ0ü•UލŠ@?àˆâà6†X8u;éï3ë$N¶´¥= ÔCÕ4^?f¼±cïxD…®,	ÒÊ9ÿƒt5߯ë|œŒif%Ód“Lþs
òŸHÅ>ùPßýÛ×;g²p¯[4¶#Ä¥¨%q¨ƋRù#6,Jë#G8—Uù|Bô‚Ia³ZKÖx9êu¸­Fš’R#-ëS£Áàé1c”CêWوr¯{Ýò4/ï·9‚ÑN4»ã«þëàáµÇÂÕM1è#§M²k
ÂøÙ×|ÄÑÍgō-šM’´–d^¨²	¢Ef¬\rO̅[ddt:æäsd&jeª2è6ñY8@JZ`êZº®,1V`ÈyÅÂܷáuG ]iLmD«L¡˜ªdl6üÆôC/F=ûIJcNÇÌc(ÙÙѾD°Ŧ¼ö•çi“çßæéôŸtó$?9ôN¦ô\"Çæðµ,*÷VXY¥æ!Ùã€Rï?L4m—{ÔÅ×è0ãõËa JIã¾Q·ú
\_P‡Ɔý¨؏Á~ïÝgNœԐ¾6]íÖÆÛçhÂoÿÿÂe6êÎIÂ'ú#t«ޔDę©ì}Y·£8–î_éµúé.n`æ~ó<cof4f4üúÆ'#22*#*£²ªî­\݇ãu8B’%$íými_”v~B¿Ö÷ù2@Ÿ¢|IøÈO|”o:gû'¾äûñõͻ	?%ù‘áŸÿ¦ÿØü½¿f}Ìþ•­ÿù>͖Ïcýƒ ˆ/֋_}ø%:úÃSèÏ=ú¿UùúbñMäø¿®ÿ'È7zø¦áDüç&Cÿã\èS¦ŸÛúÓÏèà÷òµý{ž6ò›Fë'½¾,­ü‹`kĉwAÆ óç½ϔøØyMLªikÔZk݇ÉÑO€¯ÙUà;pٰ¶ªäΞ"\ÐC½¿ˆÙ=¼ó•‡z+
¬
©ÂCñªŸ3Փµ`O|ª‘.¥(„…ÛöÕ
¤¯X ø“tRìG˗εÚ[/Pդá'Ôa_ÈʢÌ`<³ÓíÚ_¢B¡p61ÜÍ^Ռ³8aæ͈
r6ž
lÎ <IúšÇn)¯·ß3C(Ö|açæ	ô.’¢b‘\I
õéL¶³†6Æe¾Ûâ²>Sfúǰú÷sÀá‹Ýô;G¿Ä“(txWã\gÕ-°«§.—ç®N_ç¢!`ï¦î¶s“½Ü,(Fm«h5J!b
}}=ݓ+pbt½«IziÂ{ÊƏš4Ç_RpÔì利³µÎs˜„‡p¡/¼
»"¹Ѯ¾Ûø¾-¤]٦ƒ׫BèµM…գØ̦¨Ø׽V®}3ÕgF}Æç“[҈úÑîå|öKLA㞗FŸÆ!6÷I¢‰p£„ުc™s)Ü?Þ÷˜»6Ä`J—ØJiÊ> ö0Õh^VL€F7«û‘¹šÏ\#ʒ½ã?£ŽÐÚM€νDmœÝ^î—¾3ž(oCC8š³Øñì?ùÄ÷;ۈ¿0ªÓקºäoL!¿£=üÁÀNxÿ7T£W’|ûaÓ!˺T™øMÿa€ꬮGùÃÈßP¿œðꊠeƒÌ1L9–e ñµÿT1úrÄïèN¬JPÐå:kÜ?tcÖŠ>«ËrÀwäH_yнp0°ְ°niÀȋ¯žÉ_”2J½xÅðzQÃu
ûD˜uûwðÍ2ßþ1ÀʧÏޔ[ÎÑìO TñíHqVU‹ß,ſ|Iù=­‹¿UöÏܣÞQ½~(+ýJ³é4ê{º©l´ÇE2Š–TÝpâä¶9o–³7„Aï&ÔáßÖDR8¾сzIßYd¿:ƒ縘߄ß.ÀOo”炱‘ïiB}Ç1=«ô{vyóóï;¦ÿÞþǯìH¾ð€Èüo`»ý/›K—0Üzý(Få¬|Vü³½ðÛýÀ8C©ºzÚՑA*­Oª?Ï%½¥¯»E˜J`ľç*K&ÓÙêñ'’àù ©7¥m0%ŽÍM’Âu IV)’Ùés–ÁĄ°ÕTpÌ4ՅØFÿP zÚ6ÖÞæ1J
y:á\Ÿ†\1Š:ìJns)ÕEd.£M;2+Be:PYJ"¨t[:ÛÑ8W:Ï|ƣ²˲i¨vqw֓Ûè~q&/¸R0ù>® F,Ä:ÙEåĮ5V†OConò>©þÏk¥÷œÿÐ(ýüWRªÂD‚S©šÔ¡*¤Íe;ë*x‹“K¡=ÌîMt»l|¬kµ„Z¹’Àź>9(]¿=È#	M¬›Cà7ֺÓç¦jÑë­<®OsuU@î[—
І´!œÒ	h,u{ò°GéèޕäÆ8ža‚@ª‹çMªt„z°×z\Êx°y»ŽõÎh®\n•ékçÆtšE·´To-©Õ<ŽÞÁ^ÕÎ/àÉ
¥ӝ^Êk¬ָQ[ˆE'–ŠÈfddì€gÔèj(ѕ‹–ôšX³çàøb ÀÑiˆä¢3
ߎޱæñÿ²&7Qìð!Âä2¶Áíí§gHrBÚÀvcI>.X~Ro¿®…ÇÔ8ŸÂ!]oT*Áò4¸ÅrÒv¨2¢׃SÁœÕ~º-bVÜR‡6ƒNó Q&‡̺©Yû™ƒ¥>_iœº¥…§,cøcÒÎ*tîà$^‡GU°ؐê^˜¶†J³°½D ӂ!׵”Àô.^´l<½u1-pw3߷Í9Ǎ(¥VûtF×ÊëŒݛ4˜Ükq¬÷ܺ|R¯
~¼2qusd›OÖã‰ö¦€ê«S£–Oè*͜R‡SõIù
éXM¼kC€ÜôĖ"˜Gú¥8-º‘ÑOýæ—´µ7q§]öfWoŒ^®a-ÏHհ»^º¢}Š×sÊãkæb¡íh:’߈Ð拈"ë×U[˜Mÿ0C(Š8cF̚yÇõDª‘xºŸPíÎæŠ ’ÐÝw[ÄFÈæ¸Ó|Bt‚aN–4§Ž¢§fËÛüZìÐyçóàb%xœ¡c.Ÿ֫q~bçòþ`Ä$_³:3±.¦.MŠzw¡x­hÄeÑ@6ÎAó"]öϳ%õAüäòP‹P¾Ðjµ…êM¬/ǪŸžÜ"êuÚW—ˆ”åñHî(v«ábÑä.¿Œ”~Gãë@úʙí.š\9–EûFŠo¥
,%jLŒThA¾ÞÝÜ+}ï¤f$¾ÂlŸŸ‹3å ݝf¼=֜¼Wðv7X½«ö×-•¢(ןò¼ã+i'RŊœÀ‡]	:Ϛu6¿””ÁØÅøÂN%™ éæÁÆEނg¥£ùa}å29~ŠÖõ¿Ñé~ߺös|ÞÿùËãW¸÷Çòÿ¹±î£ÈÀMÅ>¬pկðÉùD…º©ë¥^L‰uSsÎ(=¸ªQ"0îñkJ"'<Ù:÷'ž$bážå뾺¤°ž:>:ïøªÊ$ñY"½.n7á ‘ÈÎùUN¡ewx>9JQöq(<bRÅþHxZ	3pXw•ªf².·d‘d·­rÊ=qà²Ô‘ùXk°ì"·ՈìåC͞}¾ýsÇ!ۭ©aXT§m°pe4t6iîqàì­jޛ©gɰÚ>¼°ŽhŠbWNX–¯Ïc´¾÷	ĢT¼%…OëæpϷ̃>0+á â: é¤Åj){[åH´Œp×¾Yõþd]²°΢Å2ø”=JMà'eqµ=Ҭb®`ðÓաÁۋpÁÂàE³êɠB V“¸Ðš¡ŠÂÜ#WI.”™ýsF£jQ­j`ÒÎbEdiDbI‡F
wæKÿ¶î8«±$æ´d'ºîY
7ñ‚/4êŒ)^ '
‘Ãr†T؝dX+uµâñuŠB˜Ûw Ÿ´š§(+ºùéÑNíȫèV9㺺ÚB4´`Žf¥m@VwÒvnX­,Ƽ̒7Z½ …bƒÑ@M.^VIçF\åË$tç€ó3Üd{@ÜD!¨9¿Mdz~=ߨ`ïLê}œŒ½Ü'!‰€Oœq$õ¯H¼²´q“Ž+)ŽÖTŽU7><*Аe½ÝÓÚlПh³R:Àáq•·ô޹ä:#¬̬yeq¡Q¡¹…ô÷#{ËM•Ëàû±ÌÑ\Ä[@­äÛ\´Jï(Gµ ýõƫ½§Ø[·*¾oÊrAÝYƒè~öWxðÇíËpa��ÂR[HyíZE½¡©=WÞw(ã
zˆµï!SŠ=k¸ùƒ¡œŠbʛŒ—ع“h¿­â
œóگA—NӋ-;Îqw0„+ïL>ü]½‹py¦`ðdfì5’¨µíR/°îj~V6¹ß
g:æ—"$
náj9Ø?‹¦Òeµ^úÒ<€ʕ*ÙqÖ!#«xô°N°)0Á'F0÷1p§ÍÈ8£Nž?¸х¬;?‘D(mã"rx&9ý:Ž´õxl	ðšy¼ÅçGWÜ1±+O܃ź°{»Ü\ý6ƒ®I˜&¸A¼E·Ùt
1‘)^\¯kŸ؋^›ê„Úý±J´‡YŒ]"³oýB0^2%°¡½>Æå²Â÷™]_³ù1†Ûæ)ApÎ5µb/àKx¦³æ7µ2»‰4ÛN3p2®µ<Ѝ£bN_ëÇÃ:ææpœeÖsY8]§[ի¦Ê.)&üA•ïݐ‹›D¼@)¯œ¸ANZÇWpcí{GKq‹«rå4.n76<FÝÓÍËÖ¶Êä~tjÛ|Æ_£™êÈk·»ZÏ1<Æ
²EßFc	°3Rüœ¤#ã'‘ôQ‰Y¨M?Š>ž2ØÝq£0>a/J×t?ŠŸnbZö>ù0‘iœÎõ»1oo:ÊM`†Ÿü§OS
hú´`ÅÂÏðDžDÉò¾Op~v%ÛåWƒ¶l½)›RþîÕ)\¾šÈÝ9áyî•ïïãÿ¾>ܣ(šì§w´¼ì€IÿFVã×[o¾©óʶxAN¨í½÷ÆÀþú²-nLÏҖÚ>áæHK¦Ճãݣ¹¬¡א£rêÌgÑG1|ïtPê͹ν†C)ÆQK¸AiœˆX ,baسšèˆC<ñ½˭ݍï_eá¦{æåsZóËdW°ƒræ‹®¡<
I¶@<Æ"]Á
E–Õ €¬—yvü¼p	²{xB¬y½öбՕi;>H¦r‡ÖÜ6„lå¦)U…§ÄM›ò°¯OˆEo…‚³õ`9žäRF\ c¥pn*{#‡	,–ªœ‹RͬÌüS¯Õ¥ªX]AQø‚Ž+ºqdEEi7@÷b)̿Êûà7î¯Çܶ÷n+G¼yºÈjvd„t+»}ÁyZ‡f¹û
ÈH4ÀÀÙÏaÛä‡>M¦F¡}Ó3O/+«USÀ}�'g^‹¹°õ
Qª#I]
CH:–ţí•}ðY$ÔRUŠ.	½°" Œ›¼Ö¹ èrï¸íÃÊ'lbx•?¯#QµypqàIÜÚ4—BG®YØW==—@×7N! Ö֕ÌØt÷û‰A^ð䊕Ñ1a‹ÌÑF‡“ÀÄ'ïÎÏ=Öç‚]L·²(D˜;Ž÷Œƒ@¦Ÿ#
#A)
«ç²ÖGݚŠîm8Ë"ÊÁ7ÛŸ–™‡s$îXåìEðÐÃtÕ	¯ªYbj /`ö%¨z†¬™O¦²r§ñ	ÔT^V­KЕB»’¹fŸ:ÚNãd½f
K> ]yX;HfZÑQXöXB…ސ}æ”×qÞ7†àþ2¾ۧvû˜2ÇÍÊòõ1қĿ¼Üx¤\۾ä|T9¤ôªPKÑÇc*rደíG¤±r”Ʀ\u95\©
eÁ,Ï=ð}
?Ñ)xqɞã39ü(G©ã±UžË7$(ŠRQ²²…4iñ‹áwò¥‰Ju¥W£JmƒW0~/6§„gÔÆ߹ÎÝ=/Œ2.'S Pü}'¹ÿ+yÿ#’÷?Àýþ²”cym²?·x]܏•p}{ōû…©âS8	Ñ’îHk*T°àXìd8F;HtÑ2Àí?2šM(
°%
EyNE §;×u½îÄ8‡.b§ôÚ<í¦"ëo·žt•­[Ëåë'£½mÜ:o>A·¢‘<œÃGؓ5h]§ܴn*ßö7¸ä՗ª„{é«ýÚÈ[_ Ê3HêÙx¼zO.³Íf¨nÂQ-¶ç l®ûÊޙgeCqjˆ¡}(¸ˆ·žèyGŒ•~}TõûçÊÚÃ|ð¹wÃÛ,Vëå`“Òfj׿„éû=«e,UŸÓ2îšG·Àv畺Ð|OAº›닜‰Pf‰C4§Ö,#©'֡°wl
Fú¼ªŠ+mßDùJs
çQý¢‘‡kAYT…ÙJ ?èہL ®ª^þÌ~·ÝaQmìÄÎyI\‹#8ںÀõ©‰:c°ŒìhónS_\
I9tá*"ržv:V·ôu•™٤ˆ&s襑($‹çÙõðÊèEû12ÎÊ
ªOÿö{½¼\ÀÓS:d°9“”›Q'¹AãXY4uôS'q±R³:+ôlg‚ÒûûuZÂså¡(ù:fQÛ?jÉóâ‹Eq­çÄ&ÖҾª‘^‡᫖´óÑ%ŸFA•åýծò)ÝY-¾19¹}a¾Ä ÷ºÂSýÇ-‰?[ˤõOM9N¿ùù,ÿHïæOe~o¯ð·e>¨/?/_Ùí{ó?óä}ýƾà]ÔwÚ/
§Ä’üEý’úKk^_ë#ü’¾ýZv½—Söaiôq²úv#þßß(þWã³ÓrôKúë+#äí!ñ?>´ o{‡·{ñ·WñŸÿ‚âÿçÿ~"Ê_~ÿÀÞe>
~«Ìé›eÞñWޱ´ÿã'ì…ð?4C>?ÿZr»6´þŠ¡ý'~z_¿õµ>NÉð‰õ¯þ¢ …üþÌIQò«`à_tI²¦)û±ÿp/þëþ®ìLù¯Šÿý³ÿWſ¯c›!ïëwî§½Ù_-߄jqé!7Øôtx觮þ |Íê‰Íþ®=þço)ë”å5û¨ä†x*²à¸BØ <õìM
Ê\ö,W	?áëkjd%…¯·8Î3°Ï8åá®Ц*è��}£n¸Ñ^8±.اïŠÏÉÉ¡aµÜ^\æ
Íã²EØyºJ|:0+]ÊvK›íÌ?…^Mçœb|ÊN¬tî±9c ‘ê¶à‡Nº,þ(­3+¡Œ±Á˦†¥Hî]h´M·§…£—Jy“Ÿ.”‘w¢OÒãf–ñ…„+9|AHúíÚ[BSg
´¥¡¯ºTYy™xQUtå¯ö“hßáÏsÆQY mà<¯ÓÊ%ï5²˜÷§yƞVEl£:+/¦5æS3&‘	][¢¼V–3{f%Ž€œ4†I²=¿_çýŽgRž¸ÐÕIáˆHmî›`ÂӺ•Z~ˆÞk/óó:ô˜ÍVÔU–	Öâð\hŸoer‚µSÛè¶®ÓM:	¼
?²9`·P‡ÅsÊ霡¿Âidhµæ4úyB;âۅ€ë=
dõf-­9E§ꊜÊnåRq…€_ÌÝ
Ò¡AuÀL­.!?Õ>ù»µ[e»“ZcÐÕ÷s-€ÃÚ>piHÈÙwc7ý³DV‰9åZq´šµú‹[´ր(,#°8ª!dm×Qg– 3là/ݒÒW¬aòü´‡ô™oKßÖã`ƊX
BöTçÆjR7øµ
’e§aÛföƒé+ä^r ¢VÏP³™*µÃ(Ú%YM³(7FññZè¥EudRvl$&á˜?´q<¿X9°ÐS†)«d¯%c0t3n;l]Æþ!¸°¶Ì%@H·äMrÅù¾¦»ƒãVMéGÎã	ÔÕ£6k¯™yš÷“
³j(7ÑS&(«¾ÑÐ
%s…$aí3uÙÕún‘^Ǫ̆Ý hÆãÔ8½??§ijžÓuˆŠ‹eÞ!UԹ.ËÌ÷\ªú°ßsºË9«äžÎKh!.—æi9+G
õ€úexY¦`RU<=Qh¶…Ú-r“É
:¦wéñ]Ê.3_£ׁºº^›ð˜äzKÌWÁ{x•·”zè›\{=çH<·<°ƽú¢ą̀ÎcO‚%ƒãé—WTš¶*îÒO(Sص¸m€çTOïñ-‡eâ:ËNr]j>‚—é{Áê¹XÝl𜁧yt S%^úLŒ*JVQç“=KÓLƃvVêÈ:©p®ÅѰ¹ò/pÄÛÃ7»–ŽL¹`,V0;¡C©YqŒ(Z}EGFá€.®R‹ðˆšì¦yk¯°F¹xە€'ÎÎRˆ¬P,äƒíòMˆ)SX7¡_!èîÒñ>0=b+Á߼Õ]V'´ÀiJ0LÖ۩»IëÒÿï'û’sÙ|žû5*ü*ãp?ld?ƒ™öÈØüuܥ؅|.ò’½ñ€’ßÜOøYþbúÿ•޳´Î>›þºgŸöþÐÔe÷ßäÇ븆Hª.Õ,[V§úNÝVï¶ôôѝw23¹ÈbV¸`“Èóýä!Ïï+°Àn
ZºÔrå;à'X丕ßVÑË/ M7w·&Tì§Oõâ—÷‹~†ÕøþÑ8¾n½1,/ûÙBˆä”{JÂ)Äê&é¯-4E´+¦‹dٺÕ7™U$çÝa±@ˆ®Î̟b6UU"Aм”›`saQæ@wsCNþiâ
Ê{i#sƃ89j{73Ëâ1»ÁH±ûsz[‹,£²
Æ.ÄÖ¦{<#Ry𧴱ç"yÍ‘±µq²9•iFÉÒ3à*QŽÂ::ͨ½'°Š€U™¬–È8Þpm
I”X»̧µµ(ìàûÙw¨&	Â%ŸMhž‡™[Ñ6CRoùL3¾~Ð&³¡3®&öþÙB¬v8Sîà“i>ñ!
1;äû'~“§­ùɞZNb}¦4½n¿E„Núñ@€Á[z®¤Ñá±ût™¸­šIz½ªZúù+»œ‡92(áÁs;ƒn'Ôyu€4©”7œð‡[ðㇲøëô)ÛÞÄåQެë±Úå¼UUš·“îù¥L·9‹}¦IÞëà¼ЀÅ0w‚"¬Øýø²·¹I–³@Ç#ï}°|KöãÕæV	ãj²ïb«•õâS æËáÓÜACÒO#‚Ø+1ü›e‚Z±ñã'Œwôî9-ê.ÅÓʚY©ƒ¸à“hÒö%êÿÀ’[7#}eڈž»Ëì<Å7‡—¥þàFnÀoD•"#6µٰžÌs?¢Cßʑw6£µkð ޝ`遆Àþé[ª]tùQÏEoré}yò?ŒéoNJK셬¥KŠîÔ*Åž«?‚ñh¼¼
R·æxN1´1֮*}êN
É^,…ru1cH[IX^ñúŽ”
õß_¶¼sh[ôh&ƙY\…Ž[S÷"w
•ô﵈˜~ô{ãcòiŸÒxŽÖ\ýo4ùûĞ$_Å]>·ötwzÝdÏuç>®V2äÉVô3á
„‹ÑtQCʮ±­{‘6ë\ÿs’WGMú#@RKNŸ´Šø{.j+ÙKaO–ÿê™û«ÔrെÍÍ\z,ߋ‚µÏêyg̋øûä”וë÷ÃSÜq_
5½3vV‰üÃmvºÂ)šÂ[¸£…µDñ©{Š^%{бåµÖ^jďC=•iÙq¤i/m!¸)þ}b(́Aޡª6F¶ñrnÇ1`õ–ƒ$;ª­úAÖf«y:–‹eŸ…óA•ÏÒÝ&ùüõS+Ò#§*Œ٠ ]9ÆRÑ4õfž§szÜmVÿ²Ť"T‘	Ã1ÇÞ)€ç«3íŒH+žƒÌJ!•ÓêO%m9Šc¡¡Ö߂oç®íxž-öYh¶ÑgÜƪ9`¼òº’P¢‹«=Ô
ÄJ½ÿ;¨üÜçús¨YâßPà?³E/ÿ-,[º¾׶ø{Á. *mývÑEç‡ /óº?Ê/Ã,ŒÎl"t–ȋ²êýt٨ZÚ9ûEvь“ôû‹×ÉUÿa¾b7¯hh«—ø¶™/7zÀJ÷üîÅÝøs"Ðmq"—s¡@87³X„޴£þ‚ÖIú˜'^Æe	øºT±qøy»Ú3ÀÆR¬Üç6ˆ¿á
Ñq˜“«ì0à:õȀtIýñ9­
)ñ€
ïâ	ç¥ÂîMó‘ó*ô\¢L­؃eñ×°áqç׺õÂk蓮bÔú"2}8EÜËۙ<_CreÞÖÂû§å7Œ%RÿâÉËS‹õ—rýŽf+¦ ÌMÀäO“5'Ò!¤ž¬g3Q‰£®º]`QÎ1&œ’Rߵo^Öÿ¡¦ZpIãupâ­_Fò鴕içêÍ1·Þ*%‹Ƽ&õ7€Žùý]ߛ譛Úÿ2æOöx†œc˜.†¤hyiQÎ+¾€b™_–ñÐÑê¬G}·d–<Ãßþ<H.ž‘‰
òøû äϛøCl¡è÷åCsVQžݺL\¿ïz9““àUD—ó{РЦeY¥…„Nvå9ÏÖm֛:¶Þ"v[˜ë¼8„b†õsmèÔäl'âip‹àÁݰqD&ñäëÝe{@”‡•IÏc\ Ñä…Šõ‡axD¤¹©ïj²ÄõMuc3WÊnŽÞstŠ˜Ÿ£ÿÜýj‘šWr™„œƻo }'¿)DU69j-«?¬̶Ϫ³)ÞÛ×p§ö©K©T€¼AJ¿{Dïaˆ‡‹‘‡w-56þ–º‘˜Ĥ+±€ùíàˆʧrO«[+ic‘Î\9ÏôìÓ/Tù«ª•x¬ôÂ5† 4ã
Ÿ›¿§aøÿÿì]Y£Hþ+£y±#îë13Á89lÆƖ��¹ÌmÿúÁխîêêjÍÌjw4+
%$IDfòŗ_&·ߓÄÿÁ
ã4¶õgB[âd×WÞÏlõ•ÀöBߎ´jÜ›ýQ
¬u8™ե`´
G¿E­j4VýÃKª„ö"%/áÔçs“³|fù*8PÕå,|ó`ÂãZ%Ø
IýxÊM9k€›ûMÓEæ91s9x‰c¯#œ[Äâ‡Ùú”uC{ú„áùyoxÈÒéíã®çlQ‹ìhKËunÜä]žCïlßžspcé—7Qâ-:t¤`e ëX\u2K’myÕÑúÞ+ÔÇ&ª”BЁñ ¥GDȗ¨ij,¤Áìù¹9ð6¶µ±O–hB™TQۚ۝›º`Ì0¼[wÑ
Ů¾×p€âå¡p7õ3
‰‹‹ÉkS±Ó†ãp°	ç,Ílé#š½ÙéÙҧ†۾:x±\1°¥©éǀቪ¢d=s1yݫĢ#ÏÛ/#ÙÇX&E¡áóN"+iƒê;S%rÏَsQEÝz ‘oÞôDau‡6*©–²A¡š¢›:ÀÜÑM‘g_zbD¨éÊFӪ)*(̹à1°pܝrAMvʕQ{è™Ç
ébSk»B5#[$Eȿ§{ǰÔc½•á€EÆ8ÜàrÞب`›¶ª½È0¹۫Œ×}{Wéù~GJ㸂v^$ݲ¤'e¬M“)?îã͈ÿI§ùËA=?r‹Q=UEýýa?ú®ÂÿQœúDEƒuÏîéA+T/+Õ2<Ùø`"·EhC1ުPµ2ŒwÛslGGõ¶v¬ΠòƒxB‘GBÇɶåÂà‚ä¤Ú1QøZ6…È_Ê·Gÿ¹Ž\¶'8B}®˜ìeÿÅ2GB—“4ÅW’DAìdfx´ýmùxŸŽ$it;¶NI\I\	d"¬W–â“(Gђ9r>$7Ë{`Ö^©Û(òϙµ<{)*·µZ+[ó:•Øû¨¡äÁju٫èƒ$dÐ@Äotd!Տ#ôÊ9¯W¨)¨­¬ėn*m\`F?J¬æ´Çú2š„y6€r­g*¤ú8E6WŽJu^tÛ:\"ܰG§À
Sy–nk¡¿ø_œ¸|ºmX"ÐÛÒm&v3¡°ö*°MTÍ4’‘Ør¼)†½ÑÇ‘æ®ñ	X=ÀIYs‘RǤëzlz3ÒÕä2ûdj"›4›ð‰™H“Sr”óñ’+Êp`	Ñ7xVۇGÒ>Þmåe3q^?îG&9¬«ؤ%ÂF¡sGdC¸Å,˜3‚[ЁËr0ÁuÊB3’#°ÅΰˆûUÌ">1C˜«~åf¤O;ÿÎÚQºÆk‘?…xB9R­n§J@tfX/*Z:àØÎ)Òh…—èLê®pò;SKtDv¬
\ÊÏ2fp«ù>åÒYy]2ß@•]àÆëFa‰n׳M'F‹h-eý(Õ/Ëô>|M‚:T؃Â0THêÏPdI­ĆÎÖ¶ÕÅXM5v2&#/Ӄ,Lj´¥ÏY·Ël²&²ow„˜Ä÷‹Ìö27šÈêÉ®da–Bª¡&@ê)§ȞWé*@ƒ.Ċ
ãMæNÎU¯2*ܧ8ìWç»@›ÇUNÑf¯Rqå¢/,àCŽ[×r1¦¾•ØÉ`OÿÃoSn´«žë·*ì/àëß(Öýó#iޣ‘¾*øORÕÆ&ýÇô;€¥Oúd¾0M}@é½h§x	ââ+Ÿݟ|ןÿýÓ[`Ï7–ü•a>¶¥ðî—â7Èâ7S{ïøˆpõM[übó·Íñ›Â@çE=‘lÝKõä€móä{¨Ø[ƒ}6Ç+†mÙü맯;ú—¿š/ü{bðOÚzµå¯ñ¸TèޞùŽ÷ßÿÿ­]Ë‚0üãIá šÿŃԪ`Múóîö.hÐ	Ô�m!gtn©âÛ”=^"¼ó¹b¬âM‹3¢юܯÑ&Ùo5mìsC%…âQ¿b¶©ƒ’âXÆIr=Úá°<r¹ƒ­õ(•x β¨L}ڶ¼{ֿžFägÒY$ÔÎîÇD˜6lR‚j¦ÓbÃtÌPÀòüÝyÃ=T\0ØM2Ê~zÞץ¼ŒI’zí¶J÷ÐÛµ<hCÃwÉ/B¦½(½鴮¿®3М—è`ø¹¤@&ë}…NHS›™EÌA¡Óm™º6šÃ{³˜MeÖ,ºIåZzuhåʔ ý‰ KòžÁXà]0Ý4†S&Þ"
Y)ÆGA§vmãÍl`–çç Îý/yzh!¡?‰‡gUËÒŽ@õh7Öl~äë°¢šû´ûdt½?î¾M¦]0ÜÇ‹ÄV[sâ8}ϯPÕÖÔäæ`$„<Ù`<B¸“°e[`[I¶­ùï+™K&“°[û}˶[­VëôÑiÎAÄ+Š=ŸƒSûhjñ}ê>%!NB 'Ü'”]=@îÈEÑ9W'€C€¸€û˜Fj#`ñé‘Ñ9`¶ƒ†Âø*@ À6ŠÄ4îCl’‘\’D°#ðp_7&pq€®Î''…óópº0BpšØ<¡bžƒ‰ƒI­¦dh¶À\	‘ƒ¡b“ˆS°˓;è·ÃàO±v†î×ÄÚ>¢˜ß	‹ä^ߘbÂ0Ç$ª	ÈqФÕÁÙsÀéÆÂâ®jÀ
ÐRäSyåg“ 	£|D$¡¸0āpÿÚ'3ÂÉ×Kðõqód0bŠÀ»ÒYL#´þPUU~ÎƱ»Ê7‚"¾YNA‘#a€½HÁ…L¬'†ݯÇðÕ@±‹ä~~žˆg„	¤?ñÅ1Tl„“°òL9ZrGNžen‰¡ãàÈÛ~…z8Ú~ÌÈRf˜ÎuU„éîä=`?„@¾‹m޽”·¨ª_ò-¼ÉZ±ÌNö‹G$BGK¢~Zß9À8FÂÈ%˜‰ºE0x;í},~O²Qڭ›š	ªbún‹¬óª-·•‘¸¸ÉjÀǎ(æݫ:ē<¯GÊîr5^¾)ĵí°4eÛãÂà€Â9hÃ9þ¹Pd8$úÊwGRf©8ȅI>	؅—"³%WA{áQ)/
¡‡jRn„EjţÐÁ—S¥XUä]æƒPoOµJå¼ü©g@ýò‘ÕvsJÚÇ>·gà¶úåì
‰Þ/5Sf‰8:dÓ1ÞÿˆV‡,¢$ûEN^Ó瀆'yážtÚø1)j*«H€ý}=¥Ê˹`“´l)fx&JQ$<ؕu‡ùl˜(h ã0Ÿd@¾ïvž·¢œï³=OãS¾¿¯ðoÔã˜C‘ë]YmÓ2=)/
¦´=ïIPeï§nŒ/Ò)2Š—òq½ùrÏ2Cѣi¶qÏy¶?ã?÷º-ç#weGôiE’aúSÝ|íúqÔ0áèȨïºþ2ÑÔìϣºI0›"™ñ;ŽJæ0úQΟEÞñûèè¿LøN</@Šì´È©Åòü±£WsH:Gïç`ÂßÉ7ÝdÓɴòö¾P$Båʲ}=QšÍåìÕm+;]ø@'v¦··©íÑßú¨o/‘8ËÃàյrÑýù¿9§›káa#ÞcŸ
Aæ§yçLhpê@k¹½GÞÝ2t]¾Äc£ÓÏԖå]ü#ßyâ͐ú¤®÷äGËMÇkixfoÜ/ëOmÝ[Ù|aµõRÁ–³iCÏ?t£¡W×Ðhq½Úó^Æ+Ò{VÚ{Ã83ºٞ^ès¢›n8º[–åfë¡ÕõI¥ºî¨=kõÍHŸăAÇñ¦Ö`ٰ[zÃy¶ŠŒÇ2ÝšÃÅ é…õú(.ώ@ûŸé×ÿí‰x4<g]*K«±Aû£Ò(Q©Ù3†Vuz»=O¨ÑcézW]b‘{+4/¼X?\·֚‘¤7&ãÍþ­qó°ò`=[y}][~7úaAõÚß•Ju§ÕrÛ,h¥ØO­ۊõ²S^[»ý̟/ÚújÞ4¦S±ÛXXz÷Qû–è¶\{Ôi°°}7XFÅu֤,ê薳²ø¤}©ãéÐí¦i8@zyZ^–f÷ZV¤ßKOz_7Z‹zëG¥þ\Öé ֦E£Iy}AÕ)bÏ3>ÁzHÆãTç(c¦·Î0sp¯…FÕûÙC–VWcœ¶»k½%·Ëˁ;|žNŠpҠ÷hÒKצ:áõ¤c¦ZÜ2/*3“öæt’Ϳi|0軘Ï*•ï£ƵV½0ø¿&+ùîü
Nm&üWÌzP_˜•ŽH£×XeÛ!Íæ#oº·úƒUbý~cðc¢Þ?ë¤7d}s’š=¿ws3TuÓ쵲§ÙS'cÖÞ,ÛڠŸ.=«»x£uJíN¡ëmÍï´K‹çiÅK;֭ߘ'å¬i•«Ú_ÒK‚ еðS‰-ÑB$ə2v¤¢Ĥ†ŸòöõÎð‡Y$€"C¸!6>ÐqT{=×|9̌1…
HœÚd[ºþ ú%šŒGJÎôˆb ÚáTò©Õ6I‹õÍœW»”Ñi-é
¿Ž㷎íî^âcLÇlrA8³Gåß[N»ÐυuÉw.ò½›Wï*P5 ½N]Píu"үµÑO®ޒ ©6pŒݕ1Â&/š´Hþÿÿ
/qMM3sµ4ËwÎÌtŠÊ7
3Ôw
ööŒÿÿÔZY³¸•ýAT0«ò ö}ßß0;˜Ŭ†_?|_w¦35ÓI'™©©ËÈÒսçœk{@T‡jΰ­SÄ:’´è£vӧ'áðìfÂwȇ ø<@•oO·Ð"D]º½kÔþûù;”<ý¸޴õ›’ú¿w­.Ü_\‹)ÿ%"ÃuÌž‘?Ø#͇|“×7‡Êámgƒُ/Ù,›Ç=ËÄ!ڍ~2³ŠV2éžÈMTÀ*¡ñJv‘ªŽÓÅQ–¯òdy°{*“uX£{‚c5‰ë'…2$gqbUr›ÏÛ·™ú‘)©
ãdµ‘Éa|n2zÊЇ¤>³blƔófº„	?îé?GÍ#/õá~?ó™=—;ÙyÄo}” Ôûwߟ˜´`‹_Γ§,]_1‹÷QÈÙ6¯™��._q½ˆâ(¤"À\'
5fVskڛY…Ã}"råŸl‘9ÏtLe’¬ëÓÍ�b›
Î&kÑØ|֊%^‰GOaaåÂÙ߾º]jÌãr/ؘH¤tá>ÅB>ÿ°ž®«r3ðÞ^17–ʷ8´Q
\¯’
˜ÅÉQ.upŠ{"ÔlŽzO.1¼|Ùéãª-ã±[
WIb›TËeš;‘6>+)L§÷¾½ŽöΈ¸øsöh—jwÝÝßïéLÏ&=Ç*(gµA€Ï2rÆ‹.)­Ü|@˜ÇMùì\:¹LjŒ÷ÁÅñ	~ªþüç?
ÐCüÿÁþ¿„–ü›ЊÉ¨ª¾ÀsB.ÓN:¤á×6<&Ѣ¥÷¹{Í?Keÿmáú­å6Ú_Ýûÿe?…ÿk¡*ÒÑ8`θGëñø±ç^’ü‘mÀÿņèéž×߷áÿJ2øWÿŸ[Iþqʂ_eÀ-»%ígTõŠæ 6€Tíiáý¼2bä0ÒïÚòã\ãôÓñðÌQ<ߗp ›7~ù9Ÿ´û3Yø‰ó…1¯C°É^ÀÇ_<¯“‰›ÅѲ¡»¥¡Ü{·ð’“ï:¯õôø­M}=ñ\GÞ‰.—{Çùïî”û7&'‰qŠbtÌ$É(E>/:(
ø	=#؅:ªŒf8y¾	jˆ°“þéïÁA㬞KçžîSî W#ì×G7ýFqüLGCÞ¥8¨žnM£Ù@QK(Ï´fÈBi5Ð3¤‹MJypO²ȗ$ºbUµ}<œ·æùkp¼#ú«çá2¢'|⢫Uµvâ˜K«{4t³ø· |ÚÌíœüö.Ême þ£QUìýHá³wxšÂúî®&ä^©£1äÐJ@yxr‰¦v"j–àIºîaë q¼Jp!—$T¡{“2ϝŒYÓ{íÑWÞð.ۂw:šÂ#5Âtͨsö&ìƎ€ ï]ÿp±±±5÷E²K’l0A mèÚ÷”Z
¡Fæխ¼Œ‹N÷R¢¥»žª«‡=$úÕ&¥¾>6AÂM5Óz“E:¥L’г±/OõÛ¸’Liô 5ґ(®w&bҩ© ’ë3ãÂêzè²ÏC`q¤ª'Ýw¢Z5q|×Q`k4D²q@Ãù½:ƸÏ÷#…ܕŠa›‹(¥áÒûù:ŸӒOP#óųÉ%ÕKJOíÃ1‘¢ë•õ(Ҵ·Â"ÂN¥X™ùõ\íõ‚Z=þެ^ P¦5߅¢Ê3›û¼gæ@*¯6;ݻc¬O	ö.xÑ8•g•+ïcø¸ªüÆ|‘ÓàEáM&¢¦fh²ÙRQqãϯ$šץ®S˜¾„P-–'
™¡q«f;5Êë<í ybÖbGt'¬~gþ꼪;ÞgŠwºæC}OxüÂá”ȹ=ÌñƒÎÖS@ÝˮæE-Wô7Vî¢uˆ§´ùò•8"æ{ºm­ó“=˜fGxãn«Çî+'éýüÑrdztîL&ƒ^ïKɟVީ—¹bEÅj
‡ªÿ¯ ãð£p°ȲU
HÝDdqUL‘Ý÷–È=Œ÷4”­UR<ÌÜ8ÇgåA*±ð¨¨Z³•q ˆÈyꜻð拭Ãyö±=x>¦¸e¶¬eFÏYÜQ]Ppq¥š)ÞøtûòãxéÁšz|
iy]a`CB…ïuk¾úhÌñL¾íóbMò‚Í'?ù°e¤Æ(W©ÒCÝHÇ×6»OŒ§yL}×áá"‘1 ƴF±@hçФÉKúêÍ?dٷ|žµ4‡“ÔڦI{z†ŸOJáJPŸ	Ңùý±̫ծA|_³ˆy\	Sì&kH~Ùï%’¬[ø¬uFÚë› õPe§GYœþ"­ôD*¼Rؓhè!^ã£+Öjðö†ҟVµ|±GC¦hvº°þG<зŠû–¹üÂÊÀõÓQ	6–å?ÿS,ú§HÿôoͥUrûÑî*ÿ…Kƒ+-r2ÇÍÜƿ”óSåT'+(Í)qÊ?ûiˆˏcq,sýÁÓT¨œ@z]‡Cò'˜¨»hœí)
{‡ï§A&M8sþöïX`¶òæÕGdZ^Îz‰R”B¥0:S&¶ïüƒ)
ðŠçÛ÷j†ÎEd‘äpRÆ~pà0T€ˆ¶ƜM«*M™AUbW3*‹11lM‚$b†#Ó̓j´vv”]cÒwø¶ÏäíÛæ܍ú4è€,œâ3¶`>ªê’XQŸ{·~¯ø)bRŠ‚[6þZÌÜf?÷~Ý~򌈃–€ª‘&£fL~H±`êѥêÜûЦ‡#0ÁdžøZŒÊs«¼ۀ:?@~B©ú`ö²æƒ3kÅÀàK3ó¡J E
 æ;åq~¨T]õU…MxB^¢TɳxAA£JÕŠoâÅ`UlªHb逯2p—ÎhU"
å	íŃî&Äs.„øN£ö’qÁá)•‰–"0gÂÌ\O^‚Õ
P/3Y¾8‚ÙëÒCí8Š2ãÜË6ˆ¶}èB¾ÕpÈH€kÊa¹ñ¦y°4#ž3r8«z±óa	æŽ0Cæ´RÜy»5Ød?D]p…k&҃
‚3ÑÇ~—OäïwcɝëÝ7A=ßÙ3ì¤6%(˜°^ù4àH潐ä`h%fW
—3ܳim>ns.ºP‘ýÈkÄ0OLÚhå°xҖ=“íÅyl#=²µnÇ{:Ð"ÓìNz×}yϮ­óį;ŒÅ؅¼ò¡^´õs«zy²å{XÐ,ޑsÊäʖMàfÞ&õ)ï!BhöáÇuàðì-=:5ÑÎÜ)ù#3ÔÙÒDN}µñ¤«ÊÄ6õœîR£Ðyvá0%[›Jܛ½²[êÙäÞ`A%¤ñ•B‚ÝxM‡?dëú%@Ïl:„³l
æèà¼êYÎ7)¯jçÃOfWY|b‘:ú!“ð
ëà¡ã6þ`Ò:¯ìež÷¾TQ¹t·ûMUš‰áa~µæÅm­#¶’	’¢ף§¤àñÀÀ)×êþ6%ÀG»/Ȥ oÖ)Gvq ³ææ[¬ëiŒÒ.P „7’Õ^ËBñ„'&…˙LŒCUcÂÐ<(x»2&“‡¹£åó¼>Ñ#²Ê9ęt_¬ŸR‰â„ãµ3փ	µÎ©jMw”Êè3³ÇÆÔ{•~óGN4DpîKxÀõÆ·Þì˜òÞÃóô€˜"8ëjuUp8î9˜Û-Öޝ<ë_4ӯ°¶7wÜ×ô{`V;ºq4oß܎3Ï#hZgǚqw¨ŠäBÊݨ\¹?&:iÌñ”ü½‰”ÇurU‹$yœ±ê“_ùłõÔÜz[ð߸§9ÃUæÎôòêú^üèûrÿ‹‘ÍÊ©y­Tw?Ɠ÷^A–àYè¬ï> 
4[ž^ÛÏ>n0µèѧè»÷‰նGI°D“ ¾²ë¾ý‘Yë[×êÁD¡²;]úvþÀÑ'ñŽ}L·ʇ÷ñhê
ÞSV1Båø¾ ê3OÖ×
—#Zwè¤G.ŸrówAfËÃ@jûÂ`›dûŸÿ^çoþÎùSüO1ú~;ý÷¹¢–«ü踾ÿ)*0}ýøŸU–ØO)»•@ܵ›m·Ž·¦ƒ¾s‰J™½º--Bô
êº$Dµ_ۤ"ü\Åòø´•Žßè"á	“؟O]ߊŽˆ[{n˜÷—þûGS9Ùʹœd-±½`°Ï@r$»95¾4ÿj	y¬@,Z<1.Uv€†Q!€á¶ÙO<ØÙ¹\| ÆdŽv8m%w”c
{§Oà(-/Мªܦlôx@ìzʣõú@¨&3â˜éfÓfñè!5â	kl€³k3鸳`2Tk‡r»1Wq­SFÈrÛp8¼,slGúµbK2ªF¿+wž^W{µc^ýëµ#w²urØ,{gÅóÎäKü€uåù¾ÒL¬®çhžß{í
  ҁW–ÁÍS–ÞüD¡SÓw'´Œڮþsž:÷?¬ñª¶ÊÒZDnï&åÐu>Tc?Ø
3rEÌwbÛX­2c O'ý³! ా•ñóeL
jþÜb“{·bA±8Úð*œ}VŠ‘-u	¬—–•ͦÆNo»âóšçòêúÁ$ ¬8òøvت°ÕÅfEpáÃـõJ—ñؑ·ªudp³ˆ#äY3à¶3|‰þ,(Œø¾
Ö>j?ûÑÝc«
zõ±oƒÈ7ö3$|L£Œ¶X¸°־*ԢlŽ”oÛM|v@ÛÁæ‰Pû‰£\
ù`VåR(™´ꐢ…•)±ïkh+KÒãUÈ9Bš<š13‹ÆzVæ¡Êwd÷šYù{W
€Î;ÿ¹¿ç¯æüé2wå`¸îÞéSä¾Hٜœ2¶ï¿HJ.nmRZ[)ã^Mɒ‰ºTyly1iČg‰!µC	"—ÛJÞ1Óun©ÞÁtõ¿lÈ Å{zÏ›E8쐶Æ|ŽøUÕÈrÑô*î^u‹õA
ßq£��¥s2Æ]թãÿ‰ûäwŽ`¨ËJo
?|<…òàoù¿¼ú˿Øþ}¸¾wíuþèx;¿°/|ø!±FzCQޒ­c‰]àm#q¨€½VnyÚh±¢(ÀvŸ¯dù³V¾–]ìäwÝq˸€="ÒÛ9ètÕ\AŽÿžk
Óõ¦ÃuŸ§2O–žîö€òê-º8‹/°+©Ðq¬¥aæ
×O9ÜpÊW‘£«ñ”Q{½¥3NBˆru’ú¼]N©Óp³˜Õ,˜×ÛÝrm„)5O¾#´&Ö71÷£ŒËO!Ÿˆ‰³…˜àPñ6´}››¿ÍÍüøâÔìýòKÓ-Ø_:~4Õ÷‹:#Wº9Þ‰Òí7¤CH_(C_b¬]u0F-f˜'۩¤%Ü1îe-‚ƒ
i®3]Æñ%7"’âΩ£(^œˆc®¬;ü…E¶J¹/á\îd¨TqÕB•m¶MÕVF/‚鎜E¡¡m¿ÞÆüª=™•!ìàØH¼ª»áYÚÌ+àxÔ-€ì¥ó™§äÌèûǜ¦ê��Ew¶%" •ٰ£ÿÿÿí\Y“¢Jþ+}_¦ƒ®E{bpWÀ}â>Ȏ‚ ‹¢óß'Qp·ÕZº#&Æêèn³Èíä—gãœLU%–k¥ùBSà'	[m$®sH-XJRgæÇ¥’TwŒù€in¦鿿¦ë K…Н¡­¨HŠ™¯`*Ó6EÂ}–a°l+­iŸ£‚޺O
ϔÃå°?•r¹bQäxî¬*IãA›dI·Ø~]ñ¦3Ìk ¨\×	¨Qõ@,.š3!IM÷äÎT•
4¤Ã+àd6«
ÊZ8"Ê+4œ=ýòûvۓoŠË\¼3Lj§µï梪]î™NÙQF×o0’Ï0-,߫Ø媣höXÔAyQ›A³úäˆQ{(-ŠfÁ$Zž2%}ÞF4͹™ãÙ$1u–œ?ärX€¡á'!9ü$ ð‰m"ÅLGTa1§(T–u¹SÊG?\´h¯4X¯(ڈrþÒd†ró"ªk•&;DMY’ÍRûúò’.äk=‡u86›píÉ.je—m7f+B½«z9–éÑóÊz҅¨ç#ªhÒufÃ-ži2塦B‚›
4	«,ãϛ.ЦÁÊ$0¥M¨Nô šu9Œ­U1Žë€]ÍÄ]ތT¡`>§:头]E2š…¨ˌL@·òó^“ªʐ÷:œ.FÛÙ÷©(Wc¤#,¾ÁgEÜSmÄ[-Q•ôDÃòø"7˜æU´Ññ†H©l­TÖÕPIêáƢnTVR¾¡y1WU"1bè#},³ãÁÔb٨ï۰Nàծ2@…ÁZ`'­U¡gh›õ ¯Ǘ¹FŽBF*	ªÓ
Ýæpë
•nƒLá☭L¥¡–TÐæĨ!ë]æp†Ð
m•‡†ºt"3üª3\ã‚jԸIŒ¨IYL¹tÊ ŘvI™Ñê
'X:L…[Y8ʺuz¢Ó`é9k3M.êàè\£”´á´I·«Ã!ÖŽXéz¼ssJ·zrè‚öl,äôºÏ t¶…KÊC×1ÖQX¥hžfñ>›Ïc
Ê÷{u¶D•礇±C»W±
˛¯A_êK¢”‹JÅUYmçÆfЁ¦ª¯BŽäw6:®õ9”[OKxXB4¯Jâ¼+•R1¦̃"å[êõæÐÜ`"¾¨±­µLi%B;a"Sº§„•ñZ7´¹…å=£ìٲdä„R(Ôܒ½4†M]Ð#aõ…w“4&f¼Å/æJ8©p_Ùü‡á éº„“EÚ,c}dXê$™r	ϸ暌\”ê<‹±eôÚ>gél¯Kùb¹2
±æIVŽ_ôzn(ÍsÞL^ã`PŠ«~Y‘-A¾/Ó~>uûûd”õýd¯CÈô­l·CX5ERcW’:nåNÜÈzڟúϗn%ð&>œõËöše{¼²´+©%”Ö܋Â{©=NÑo/Ößw zÖcÿìqÂ#Q<
2'ö©$[$™Q$i~›òõ¡ïÿ?¿m×b÷oä”mh‹Ɣ¼®7Q¬pý¢D²¥¼ÊÚÆÒü`o…/Ø–üUüñ’ûþRÄ0'؂ñÍ3!_=_ƒ'7Q×/
ǻØûB߂pjÛNðš>¶¶³5ýx× _°Á?ôê!¼lDë”Yæ1T¡½jk/ªmhÁÐA&ªË(××o³þ4·«k9Z’öHZW˜>{7(}î]y‹;͈yµ56f	rY«¿{6k>M?¾ÅÚÿóè>·ëϦ
].êlþL8ìÚï{›nL\7G¦ã>ïlø;˜4ÃIµú
ɢÌޝ]š
äc:oZ‘¶Þò߯‰ ‹ѳ¦¶•Ìš‘#,ìb#ù}¯[˜5Ñ!°CÚæ_º®o©²WENeqöýŒÄ1hw0x-'Z'S`Ç
â´0Ãg’éòeՇжU²×Qw ߟúD\;
¯åånIýó’\jpŸ»XÎf'3B«»I¥„/|¢‡i²íurœìúkwx&Ã.€O®]axP_¹´}¹’—Ìå.ƒ_&´ô&ܓf'ÿ†éºæ'*Ím€¼÷ÀΠ¿ûG†ÔNÄb§7ðr¯)/:¬óË6¿Ÿ[¶]ev®µ¼°»_?ª¹$iJkžˆ×tàGô˜Ë^;½ö¨0@B·#F¾#ãc5Y”ÈOt’ÝL®êzŸ߼ÿÔ" ñ¢þͮüͫ¨‘=ñ¤ßϫà\”°9)Œ“ÖƱµ0Lê;$óí£·ԿÄU¶Ÿcœ´SñÒÔæÑ)PniG۱w¨´­ ¼zÑáaï„|ôà$—}Î؃nŚºCaœeŒ;qš´ìï=]$Ÿ粶ý$ñ±‹dߺ>”¼X™d۪	gXùïƉ³ªýkR9xz¥­*•r³íÏ[{„Å?x.õ‘’·ú=;_âÄz~¶]¯ç!ôàt7:ž²ÛÌOwÃ÷˺,ŸÍ
N‘Êü+<á¼ÆJVxåÌ|$RìØY³"ëIj}û{'ó¶T;áú¯¥>•®Å!ö§™,㽸Íz¿QN~§û{îÎ{÷}è{î ɤ‹†%?ÿãLäÄǰC'‘^Š+zÕï¥Ãùd7Ÿºð@ä[>‘ðWýË÷¼ԟï–ãÒÜóÄ-ÇR1&+Û(ì֛´0ÔG«Ú(¦hnf]}ܥF›i>Ü//.¨
±^sÌMü®P[@ÀVU¡Ûݾ%º•¿ò 纆ˆ¶uÍ7’ÏÊôê̍AzÙrDæ¬pú§õ±>g?SSf¿£Fw\H`°q‰aҰܾL
S
gš4S)t)±2²Ýî„w€i¶فÍÍ%…ˆ­‘!ѓYÝìFF±ÕgsÎp0m<´ƒ
¢Ëڴk7ÖÚçƒeÏé9¨j‰×C€ j]q<ó0©
mß)l(ëÛk…jýùläUû¯¡ø”NÂòr
”ÙÚZÓæÚڰ=.Ç|^ª¶jUÌʲ¦{ô„.tŠӭF×YÑúHSXÅ]õ¼TPBÔ5"7‰9e‘ØòÈFÄNˆ¯éiU#Œñ®ÿ$Œã…IÏô[l'4Úg>{¯önõ#ûÕ]kësÊAžö>V®‰#ïݕÒ{§ªp®‚W
¿2կ:»¨T¹¯âvg	ûRy§eèޫø= DÎß#?Kùk–ï…5¾/Ów¢˜0ÇßcZŸ£<3œRÇîMê¹w©>1ww(ö\í¯'
W½'¶âàÎÆ3ë-+ìkIÜË֧´ãoQ eÕ@àš/p}Þí¿ñ*ðÇÕéUky_œWì¼=ÔÓβ7%¥_/q—ž5ŸkþŽ‚÷”2{×éˆ]\w3^u{Oj_¯ػ‰ވ‡8ÄåÊnú³G-œ$2ÿô~Á÷D½T+ž›ã	 Üîi0|p¨/xÿ}pÃRRüH–áÓ+½[tµ~Ž‡q>²ëëðú/»[ºöI]‹íX[oâH~ï_QÒj4Ét“.ߤ5҂MmB xó¥06¾ _bìÖü÷=e›	¤gV«ծÔvÝÎ9õթªïTÕ×ߐnóȱ×	º2¯‹™[4]$®£ÐwRuÒdFñ
êx*c‘˜D/ĺù„zŠ	
W(Y;1ŠÃ42	2C‹ (Úá‰b!#G:êN¤FœäAžc’Ԓµž SA¨¥U˜r¨'H‘Ş6顕㑛߾~úôx뉫H÷	úÛ0v'înġ—&äԮ	Ey‡„ævG˙c%ëC1	·P?мGVÉkÁ×#Û	e{ƒ«¥ëÊJ°vªZ:®•fwhíX	¾}ú󰄦ޝWØÌ0Ht‡"ÂDOb„fˏÁÑ#ïÊ	œSè® ÕЫâQ7–mÊ~ÝÜØu\Ã½0ºC†U'Òwú*©a÷EHè÷Wô뫋¬pä£}i¨öÙ+àº|ÆoP̈±q’ª؈IrE§¥‘weé‰~W֍_ìÏ;ßûfè1iò_¤6o<g¶åÏr“õ^;ê„Ïd§ë¾ö²ì{é²5ô•©í<üb/Q&ÝÁòYðLÿœܔ{÷ƒzrϋl°õÕoç²ÔWNÕIf?1ˁܛñ&Ô[bwrò䥲ÈWm÷KÏ´­ÁòMYZ¤ªԱÇÁlkôǶ*nlYÄɃ¶LnȃWٶìö>lëÏ㶼٭Éó,Ÿ=G¬£/“ah
³‘Óz±8‹S³Püv¾Ì[9ô‘)œÆ.sÙ&}&6µIú»­áÇmÙ_ckÐi*y´ÌÔ*ÔÔƁRô„ÑtóRËA?6`èfDSðߠËËv8ŒÛåÜ
޶w`&™¶:sà_ð‘/Aü¸^ø;Oy®l˜~›1üqÓðgœ,êjœ£@ËϚcËLV,çCv9‘?‹;éb2ïÒv¼œ¯±Âj…™C»½IMnœv	~͚2^ö7ð¹I[t³“{Œþµ“-握Ü×âÅ\£>,,©ãÈ}êc¼SEžQ¤®¬¼âj¬:U3ŲªÃó–û”j¾½S‹§tԳ»õ<ùbFë™E6‘z ;ƒ5v\5֊GW³\Ëù2•wŠ»‰5i“À©W(ӱP×'uýâ3ô7•9ÅíÅ*Ìÿh‚ñh’á2©•]XCP·ï£);­ÏÕ—¬£߯³»~³—Ûˆöòéö6È*ŒÈßÝßlEeÕö®Qµ›ë’&IèНxîP¶®Ë#‹2›n9i|ÌTžžלsBbg8ŽšjÄ[ݶÂ,ҷߎ	´ÝßÑ8à5ҠL*=•²Ҩæ[ãX?>mMß	ìÆ*
Ìڏ©á˜
ƒ‰®ð
ÿáLìÄ\Ÿ*¾Ê6PlJÝx ì£ihøz¼i0_ÞT°ÌËϰu¹¢ášY?9ußeW5_oBÆ1šzš/È0ÃL¿ÍQÛ;ZºÙ=¡3[gÎ^XåÀñ¥ùe8ŽûoÍï±X¹ô|8ÚÀb£L¬øÞ;šü3:þßFÇÑtQnÃþÝè¸×û‰ŽDÆ"=gßð†ԡ‘,¤ßhº¦)K£Ú̥_7.#œÔUiÄS{T§K££0¢6æ¼Èq®‰<Èt ú=AÄëb¬AÄÓÆápQtbujÃ×I5'+ԜgIfªHÚIGý,uË)’
‘™FêÅ©)D]QsZ¾w•)µ
yš:˜Ê& S”år<]Iƒþ5Y‹1Mqe§&í›æ…Q'Ž:&3+1´ŠÎY=¦ÐQʽÒ.,ß¿ÿþ—¢q¹ÅÏŬš(?œãâóLÑسàO¶øÉÿY¶€ù¾w€)’…ïꬕÜ,]JÛt97Á÷{Äájõ—¸aº0Ƕ½`wk“SÛr a|°”°3ö°»s"…‰Ôe){‹°0ŠLï
Äéj4¥T1Äv(œ¹'ô쮲Šû”¨®
»XDä1e)µ¯&5#Ð4/™aBY@-™B´=·nËö=[¸•ž!b8§›	e qÑ+à>€	Ò	e¤–¦X–qQãcz~ÏK»Ó1³ÿ,c°‘kÚe“ÒœZ2a™Fƒ“IʓÙE*aTòÏ
ɡøýûÂ÷ò…¾£$҃Î*p†¯š®¸&¶ˆ}þ|cãý麴°7Â/g
1œPBˆtVнůRÜí%[<>؂#é[°ռˆ«y{°u{W‹9Øj]ÄÕæ¶l1¸uާGì_:_ð¤p{2ú³ӆ|låö‡ Œ üEãÇ0ŽìÐxg¦I¸Z•—¢:˲Ü!Ëÿ¥»Äëµó‚é·ÇíúšƒOê�aì/¹§€ûÚêðH=¨jQ¦}òbXݱñõwc~¤²s¬sa\§ˆ÷W÷ÖmþH»Ö8øåÍûæAy¥o½TúHY=4ÖðJ­ó3uÖõû'‚;‚Žõî堾
bĀ«s[9ñõ*\ú%§B¨‰PNG


IHDRnàMèÌIDATx^½Ô?ha‡ñç.¹\Z5=*IEO	èRpÈ$¸Hî¦s—€8ˆ A$ÄA»8¹œ‹ƒà°—£i‘–t„þA¡)‘‚-5Rܾ^—»€Ky¸í>üÞß;¼è¿;TB&Y,rXd0à_$“Ü×ÉýÝÎÇΟö÷kä0‡{kƗ+„yښÁÆL'ÖۋAäkª‡}Þ{x#˜Œnޫ
j·Ú-/¢ýnjb¦“c눯é©é©ý~Me­í1Ž5„´®BUm<ÕTѬvµVæ¤ŒS½9WÈqeõ{8dÓÖÏQ|sÓªËׯúîF5â7Èc$ÈPÀÝYvä¨÷ãɭÍO]!W¿)I&y&î6¢ª„_MÈ×óKØI²Œqvg¹.¢ê
DH¾æ(f21æܾê+Ð7m¯Ì?íu*B]q+™Äû,.!WšL¾¼Ó
â+H&6¥WµªPsðå™/Ghõ'I#ñœwKŽˆó´òˆv:1ÈS¼~ùý\sÐЬVó÷9ÃXê.ñœ#LpŽ”ÃÎã2Ž9Œdaĉ°"…Jbdba“ˑòó'wÓ_0Õ1IEND®B`‚‰PNG


IHDR@@`¹UýIDATx^í™kpUÕý†ß@’sr;¹‡„B\$$@¡*X­…ÑÚiíX¬X‹Š"¥8t°ढ़*„QükۿŽ¢ã࠶Öb¬ ƒB©w¢E”p“[ˆ„ÜHÈ9'çifÍɚ=ŒÄÙ'ú¥óÌ0¾¬g޽æ]¿u–ø/ó?s}ÎOL?ÃÃ
æoó¿r‰;»ôpÅ)^yûI0ÿz¯8źÐp/`—öÌó™۵6°½ïa >Üuæ©ã?½/CřD¬ÄPœ¡›ÅÿYÜQno#ÜֹöµÑòD’²€ÅÄ«ø»2Úÿî€vêyˆEÌç6îe#'$Z›oW‚É!f¨ÎåãäÝQü L=sˆCNˆa›ÀÐõì…>Å…¡
Øåö\nØE-:/WҌQX¯$«0»ü3Â3
J!û8ºHIŠ3{aˆ±òÞ72t`ún(§èk»¯P	f;F/`v¾G)­ëþŒœpki`/°ž9È}œø£|ò˜Ï­€‰?±n\ø"Y¦³œ°™+Ìi Ô<3O‰æ3D'`ŠÇ#ßá‘åçtnøìå¦7më‘eMwÚ¢ˆU¢2ºނéV Š6<Q0[iºfTý°ý„cüô½_¤d)Q±Q
˜¬œP3|Œ,¯ð×û5U“U©‰š¤šWV¬C–gøè:“íE·ù”G¼†,­@G“jU¡ñ*Ò«<³¦ç8t:ršÊ0D)àUšüo"Ë pzTµŠåW޲•§B•ïZ°Y6P?K)Šװhҕß{!ËC¼
”-ŸR”¡<×LuÂ1GE_@ÛËJ7}µÀÉz€J+0’^ 竄QÊP²’”ªuo]Úú	ÀîgeÑh6룕J6ÕH•ëçn°õ¼{ƒ²•öñ%íÿ:çrU, åq¥Ék
ɵ@¼|ÊÍ+ë9]dX
<ØôrˆÝ ËJ„0¥Üqcaä\pÝqJR¶Š>¬ûÖ
f—y…”cÇr3[Áòõ½Jµ¸,¢e¨`zM¨Žo¾†÷YLúV&ñ΀âÉrm.š Wã¾|à&dÙ
-hbX
†ƒ˕jKم€ùÊRá‚Yá |†,óØK”µ`ö²L®†˫TTɑMWZ8Žp2c
·°œE|XdƧ‘l)»†E6â˜Õ?؂,¿`b*Ñ–#\‹,—<ªLSÊîL¦Uzê=€*+FÁ_ ‹i(6ΐϔ²+{&ª襅Ï!Ë#؅ƒGßýÛ—ÌÕŵsßþÀ	¼VàzZ7(#RÊnL	JW~|yç>ï@ƒ@¨ûµ3çhšjT­MՌž€Žýò5îý}™-e¦•¢*~k%@²làñŪQ¥ÊUªrUÞzu_/Àd¹“Ê[ʮl!Vm6ÇôWÀ7ï©R%2³AÝÜîý`pŒª©t}­W²…äBÀQH»X‚,ÛhÝþáÝۮÿ|ië¦pà
¶!Ë,³…äF 2fjôœé}ÝpÐq=Ç1pB‡NS¬Àh‚@ïþ9&·‘£9Oã›6üY²yÄJìãQJâG<,øt¾-$ҰR^|y8GICNÁh|ÎäK H¨ û_vJt#à,å½Ïl!
Êí¬F–·xóvJt!àÈ`ô¤Î&€ŒDÀÃýt8r™@û&[HnlywͬPÀi–Œ΅DnÅ8–:Žç/BÏLQ²É€½)*S*߼´³L£\Š˜Éíl¤mMá vœŽ7Ðò¤Ò#…äBÀޕ5BEIUÝGÂ4ÂyéØÿUÞÙ{ëæY/'p÷ⱑBr%`ú r6–ì\ë˜É:šÀI¸óО—[¤iýL_r=ÀGç^Ý9xÏ@!¹°[qRu°½‹t„ðQËrà›ƻL¸\ÓT­*UôS©êæwf["º¶G¦wö3˜Jú÷S8'e!¼ðZUk¢JU¤Â~ƪü酯"KÐצ™“ѥ€³’n¸40W1b™H¿ö¿¨TdîŒYÊÖH©âÌAèA–”gѽ€³’¿w0Bxh¦¯g^üÊTŠ’”¢L_hÓȲÓÌò›£ٽ€sN|ðøYVûV®R• •ž|ÀSÈr8{XùJRÀ9'¶4ÀeV “nB§~S®4%*AÉïÎîÞ	ÐLžãºpâUåG€sN|áxYV_-zaÂ]þ¿W·=ð5åI¶ß)¿™¢°s¢Ê:¿;àwtƒåëÈ@–‰ôgå•)×ÌÈQ	8çı[—A=rÉ|êx‚¸šäÀÇç4¬T‘²e“(ìœ8*yB[#܆¾“vpr{|¹ق	.šp°–Î	´…X€e{èüêҋT¤œ™ J›Aºü*©»îl<wދz6kÐúÉU—j¼üöw£¡˜’•¥•Ýteó.èæ/\F<²¤rÏrÂ{6ä֪T£”©$3E>åh´Ê4ùÅe­Aö°×ÙÁú BëîoT•JÍok)v4^À>äxBJ4Qտ¾¶aݡ-m_vŸœî>~ªq_ýæÕ?ûñGÿ¿v¦¨B㔯,¥ȫX÷3áyg£%¿ŠTª
MRj5Õp¡¹/NV¥&¨D…ÊS†’í£ÖÐl
%)MÙò«PÅ*Q™.è§\e*ÕxkŒ
4RÙJ<äØå‡*à|MLP²Ҕ©åɯ|ƒ_#•k~ÎÍ0‹{#¯i..§nrˆ—W‰J–O©JSºҔ*_?ÉJR¹OšÑþ¤;ð¨kðDžtͣ®]ü¼ÿ+è=D¦,âIEND®B`‚‰PNG


IHDR@@`¹UÄIDATx^íÙQ‹‚@Fá“eIȀPŠèMEA ±ÐÿÿO-x±6}ÂÔ.Lïeˆύãy|xà´@ÏoĈ€€qgAû½“{Œ˜1cþ»!“á ·‰/-BŽ"b1qY`ÚÛuÖB·€ˆ%+°bIä0fFB¦2fŒÝærc˜¿P(€bÀ<À<À<ÀNM}SbRJP’3e¬OòUvjê‹1¬©@ÍC¬\kå«ÔÔÔgôéù*IMçÉWX©éfv¾
@RÓù$_`¥¦›Ùù*IMç“|}o¯¿ñÈÐ}
Üì§@Î*öœ¹ÒèãÆ7÷×î|s£ÑǕ3{*9:'!*¶ìùRwàąF4\8qЯgϖŠœ„w†9…º’šGpdGMI¡.'c…‘wAçmȂ%	F)kJv
`Gɚ£„%y~´>\Dÿ:J=À<À<Àr=5Ýô|uÿ½%_ŸSÓ!ÀÎW;5ú‡’¯ϩ	½
°óÕNM‡€á_NuÀÓMÏLÈyIEND®B`‚‰PNG


IHDR@@`¹UIDATx^íØ=K#QÅñ£Nތ/‰F#ɺA
[‰,ø)¶Y_š-+a]A?ÓÊZY[Ùm/"kgc¹½{ðž…Á3NFb3ó´üȝ¹pï<ïH) ¤€@ gÀFl‰}‘7€Èr†þ~Á
!â¶Íý¤€fd6] !’ ã:›È" c  óYî·\Ç9#$€yn
;ç:÷[(AB@ç‹wÛÌóÁ	™H@†Ð1HøóE#€Êßìú<eŒ"	Èq«ìœ'ÜìAtþÔªGž,ñ0•çVÕñ9
@çá5L 	(p«öŽ$@绀9”^(aÎ4Á:o€ú«uÐè¼æ_
˜7€ @ä4Á:o€*!pHL–4 y,`%
bFPâÖB"ìÁ"o€øƒ‚D>1@ôoŸ|¢	"ß7‚?¿nw,ßÂív÷l
¿۶|ÿ<¬ó¬SQ¼Þ#ô
pò¸ÞC‘ud1Š©«ý§Gú–z¼ÚÇËYxš‡žПüÅ!š]@E”QGëüèeBȟ¡ÅbÙÿ‡Á,Ÿá­–?;Æ2kþý*è¾FN`Ñ6B€
|Æ:Öô`[,½œo³4âÅíž(¡öÁø„U´±,¦Un­±¥ò5Öì¿P€´°€æÅ4¸ÑŠãÎÿüÎsœ& Åø4*(‰©p£–TÞNCAHö> ó„doD:oEHôN¨óЄÞ2hB/™4¡—‘$_±?͘ÿõ]ç
 	Kþ¤ŒõqêO¼%7€&4±xyà:±>Ï;—XDSç
 	U̢þû[œ
n×1‹ªÎ@Æ1‰
Êq®hˆ­`ã:oeM(1ʉqIî3^ðùÈNô5ӹ8×tà>ãA¬¼¾¨äĸ¨ôÛÆMHøÞx;½-O) àŸôm‹
¸tÍIEND®B`‚‰PNG


IHDR@@`¹UôIDATx^͘mˆUÇgæޛö!$-X-´¢’`/ë–”R¹õ¡Óò¥¨ úPFŸLÒÕòmWWñK`-ÅÊE`A,T¢D¡Q°‚©»¾ìû:sçt8ïäNw{.ØüØOsï>¿}þóœsv<ÍõŃëÊÿH@a¸êª5”Á3øÿŠgP^ªŠW[‰‡uVq–¾!o(d’7ø…jŠÀêx…ƒWž!‡‡qœxy]×U]ÑåL*æ3u¯©¼ñǿ©w¤Ë:NLÁ3ä¡eòx†T|r€?uߙ•TP†…֞
äš;€í@ÿ¶=NLÁ}»e
øx¤BÀ&ðg‚J"¤e|¼tܯx7¥@
i}MÒàAJÿ¬٫GZH€‚ädÈtš‰ír•&C@¢ @¬ @® @® @® @® @® @® @® ®…P@„P ­Ð%P8…OÒ
h—}&蔀XAӀ–i£€XAF@ÍVsÔýj¾Z4.óÍý9jv" €XbêԨP" 8.%*Ԩ[T!‡GLH™c†+ãaï–(S'r+œî²14¨Sn¡ej„Įr…YŸ^‰DԩRɤšÐÈè€@¡a%²
Iyð }
fuôÝ@f´éº ^	å
¡Bz›ÁK*ùNÙþ–¢Çå°
gžÂGYÚ#Ðޝø²°ïFžtñÊ^ç0 AÓ
\lLéRËÔµ8ÙdªªSݧîUw«™ªcÚg¨6E°‘€
à8Àenö·?NH•’Á-±v•‹h Û6†ëÙZ³‚éÐ<¼̮üÅÔVPv{\à%¶¢t_ßð¥kÀÑM̭SߚMÝö hÚh*®Z(ð";Pº÷sG¿„Õ á4x¬~MHjz«!$9pV±Å7;Ÿø”`C1º¥i¶ÓçΚĄ©Í&)/Šàyv£ø~ے>JQñÄϰƒüFÞ;²ŽŠ˜X7®"¶H"x–½øíXØK¡øþ¾yt¦†qÖ
&S°í<–?Í|~ÜõÀnƒ²?ΜkÆƸqÊÁÅäÉáµK@ÂçøÞy;)JöÇ0pD³‚HØ,}Èã)¯Èq²gn·-_qOxùÍ//†ւã#4ÓîéšNޅ Ðħzælu]'ĞóJI!x¡iQ꽍I”T@0Üs×fʮ|d©S£úa_™Ž¦a<ܾ|Úd|<„ڍ왱	W>9¿E„˜(ú>kóGègŸ´‘PÀ)4ïx;I½†]N´¹ÐDԨP8Ñɣ¼ʯe9èáSÛ×?v¬=chÿҠš,§!¦¼»Q¥´yp$„¶p'åú·Ç:×Îذîb À-ªMå±wìƒxvôäwøktǡ©kê¦H‰*F<Cd±ÍOÇC…àЁ¡¯W½ѱîåϫç9Ï—(R%$wÀ'h­ÓŠè=þà¦ޟ¸€)ÏF¹L@Eځ´‚F+N€*E.sÁpΕ/R±Ãê¾ãhó+š8	aŒKŒ2’/Ùò
ƒ4‚l\5ÊM/¢֊ËH–¤:Õäð鎒ëoÒ¹¸ÎZ>WIEND®B`‚‰PNG


IHDR@@ªiqÞ	4IDATx^í[}lVWçýì[úñBûÒõ»S*Z¶“¡Ø1†ÃA‰‚K±¢Ý©Ä"$$‚’…„¿œؒj•Ď™!I#! F‚eP *ý²¾Jéñù%¿ӜÜÜ֛޼7Ñ'ùårï9ç9<¿óô<Ï}îy'(¥þ§álø?–ìã]Æ$ ä†ј´Œ¼=Á	§ÑALd2ø<Æ~aÏÿ_gƒsÒGÕâj²ì3Nã0níڵɛ7o¾vï޽]?þxxxx@‰àŠ{<G;ú‘Œ¨I„gǤmh``à{Z)ÉùE€cÅã˖-Ëéééùá“'Oº”A?é߀qoz„7h<Ýj"õ‰ҕrŸi(
3Nò§Nš)«û‘¢œû×Gê§m›Õ+ïÎW•¿)WٿãŠ{<G»҂q§OŸž=¦7x% ã¹¹C7nÜX-mYn$؈éyœ;qþüùâÞ}˜øjÿõÝ÷kUôí	*2Ў~èÁxè!	1M‚°úp¡”¢CW¯^}Íq®|[[ÛâÊ=˜°µ³U6N‚žþÇ?‰^èszÂXDØ9)(T”m۶I‚54~á…ùƒƒƒç1ÑŸR?w7Ò×vŒÃxˆèûz5	^ÈL”p4øCWŸz²oݺõ&¸ÜwI¥~Eƒ¼`ã?éíPè…~ÎC/›€<A™A€_$èÕÏ\¼xq‘¸l7”¿þçe0Šz CCCÝÐOۢ^	(7ð‹½ú9/^|JÿÑõ!°'€€>ôcí^¨0ð®>ÿäúúúöB!BÚx}þþþ÷0éŸŽ{Lb7åáÇ¡q}<	˜ßR­ ¢ÿŸ˜‡óÅì°'Átÿ\A¡„¬;P„äF`#ZGqS¾‚@?æÁ|z3´#s$͈c†>qõÌÃù2,	°'$rKe§¾X1?<ú1çKØ`O‚I@Ùýû÷;0øå–}Ù<xЁy¬	°'ÁݺººÞÇù±/Qú}ð{1cÇ~„Avµ+Ð9~üøöQ ªªêY)nôú‘	B/ôû,Hpä‚Ϟ={ö€Þö] oGæȻ€èýôÛä~63AAYii錻wï^ϷAèƒ^è·É}!ˆ3GJ0uë֭¯‰Ëþþré€öÏ@Œ£ë@ôB¿ͻÀx’ð¦&A×õœŒÓ_hllü>þóÐÙ•Oƣúkã¡ú —ú'êÕ÷—ï$d€^³¹T¦o޼ùõ;wît8k‚ˆëEy0WÜ;k‚JÆ]Âx衾)f=H8o.]õiŸŸÿ¥#GŽüLÊó=ʃ úcšúr]+BöؓI$$IBÝwfyyù¼}ûömíììü@V÷²¸÷=(À÷xŽvôCŽ« ž¤Y´!Àzݶ”Øt6[€՝«ÁûÙlŸÎþ¥ŸëZ¶'ÀOà}W±Œq|š JðŒ隣½Œýó8Þ}åí	🃈Æï)ÌäJ¸Âe¼–ðùöËḸ»ñöøO£§AYté$
ÕHòy–«á4>
ØGùT_‡J:	°O–h”Ýù{ÒN‚WãÒ@@ðI>öå5‹3B€„à°hÑ"e)æù„L3ÄŠ€ÚÚZ׶P(¤.\¸ l…'Uðz›6mRêêj×öuëÖ)HooïP2™ü¶´Õ¾*xIð¢jÁW_f~?ƒin93½ÆýH`ذaƒҲwï^×>ÙÙÙø8© ïŠHÛBúEÁ,jâ9æùŸgŽ_"HŽ€õë×ã,ä£
£Š‹‹]ûîرCVèáÊÏ|NðÌe‚+^¦ó|ŸˊN,Ô×׏ßÒÒòÇk׮õáfûöí®ý+++ñP[¶l©Ã[,äsN't®ŸCã3±	®Y³fÄøýû÷¿#mßinnþܾ}[ÅãqW<¨ ÖÚY´(¤|‘q…Î÷cNãÓB@]]6^Iù©YÚ^,F£+¤:ó
+W®t%@Ž©èƒKO¦N:‹‡ÝáÌùÓF*U«ð•UANœ8ÑĊL5wô¥òìïh;sæÌh!GUäܹs`å&W×꼐–LpŊ#ÆË)ÌfîàÏY–,YòY]™;w®+	


"ç{û¹	¦èæáÀ°|ùòãÛÛÛßaèšƪkÿý‚ æʕ+]è·gϞQC¢œ?Vݻw£RÄ"H4h”goõ7¶ßkãuá‘(á®þ’l†¿•耵***r%¡©©Iqü@'ë/xrîv—´=¯gèÊÑÅK2;++ë’²þ·($ÒBW3NÄüÁ €‡¥££ÆÏ0׵;€$²,½@ÎçžÀ89Ã?jH<|ø°Öýó¤þj›n‚I‚"qýúõ]Œٕ¦ñfèâ˜<ÖäçÊyýzÙäԨ!‘…!ñA*•±y$3œFxjƒ&º»»g¤¦Å.Ƈˆ(ãy	SÜW%Ü݄'Ož1:#P@F¨´:tè
ÌG›€83³I²cðCkît{ï=RŒó$÷o֛gMMڸq#ÜÝüuǰxWÇΝ;8¦ (Di$ëðsq‡ñ„yês½åy‰ߔŸAeãÿ££GþmΜ9õÒo	?mU‚¼ rÔàŽ\|¬ßEHR÷Œy­­­m‰ú-PBäîD"Ø_+ø:úðµ·ä¥}0kï4(JD<üjLoÌZ½zuüöç¯r݄&wK¯°èñ=&E‹¥› d ìñwxæŸA6½ ’éò|@¾&x™†?ÇöF,soI'¶ˆQä)VsªŒ*OŸEŽLÇg-PÌßи”ñE·HPÀϱ0<Ð8#ÉD†Î\\Ǫê‹{˜›¨‰ˆÓðtðkl,M^LݶIEND®B`‚‰PNG


IHDR@@ªiqÞ¬IDATx횆Ã@…WaÐ[`
TE!Т Q@€À.%ìBÀ9Ãaï”ý‡ž²VH&Iû¤Óùç™Lffò"I’$I’$ ¦iÞ[ž2ÿ d€2àñµ4#3
6àt:}ãz‚r£…±6ތŠa6›Íÿ†òkü¶ZÝ%þiäÆÑرeY~ázŽrlÄjŽw=¥$®ÆHG4-u]Wt=Bù+ՑΥ7¼4úfœ˜’û×"Æÿo¨ï‚ú'«%ÿaì)™®0{Ô¦ÛRJ~k¸>[2!耇n;ߧ`OÃjR]ŸFû³á†0œéí0™GaM£}<°1âTˆ;¾èî7¤à@½`t-i’2 B¼
ñGU‚†ä†aÈ71FU††pDÜ,øî-ãWq~!ãçò>‰.ÜÐÏÇõñі?é%ÿpD3Ïk€T`0Úwˆ[è- y€f‚Zh5¨ýíiOP»Â:ÐɐÎu:¬ïô…Ȭ$d€2H’$I’^¿’òÀڸŸ¼
IEND®B`‚‰PNG


IHDR@@`¹U¬IDATx^ÅÖkŒ]U‡ñßÞ{n½*†ÖRK¸¶É(ŠB‚Z41‚EDÃ-š)Xl´ÔÄÐhhE¹©$Rä¢I¥ÃU ´8,:#ˆM[¦Îíœ9ÊÎJV89ΜÂó~›ù°žõß��¼·•zyïHÆSo‘†zc­TTîžD*•ÉԅJ¥IyŸ'¾’$É×ät7ù«G­q¡÷çI’¼K3ä'ÊÌö¤Û-t‚c}ÑÕÚ|L®™ÐçL^I¢oðÍ_Öj›/ZRJ¦»ÃԼY¨4ɒ¼-µ
ÄN×;ØW,v²÷©Ïkžžìnóì¯Ña®KÎã`ghÔàp,բY½LP¨E „íPwÛâN7ø“nK4ht<-‘³áS´J‡[üÄ*mtj.‘HjÇ?b~s²܍–ØoŠ•–j2é"̂ƒüÚés’nu•“¤G¹ә²Ê
¤UܿÞ
^â~ä|×yÆþ\f–)ʘÇ9~žç|Ç9.ñ ¿iLüØdY­	dšœxˆ•Àá–ÑèT™J4q•'8‹išeÒZHe¦k˜+™ÍR•
#Â0C&­5>¥ÿŠp„ŒٕطÌlÕIkA=m
"Ma–LEÊGc+l—„ªa%ºúuŠp$¦©ÈTèפy%a'T)PBIID˜R‘ýD ›^ýêòª—ɂJùñFtð¬GAմ `+¯™æ{÷²
~fN˜‡¤zv#’jZðª“Ýç‚ú¹Ok˜ë›Ö;[]XLÒ*Žѫ§Ýp¹€j聙É~`›n;ýÒä?w´Lú΂@Qç€v‘}ÌD5	tƒÅ.·/&Yìœ+ü>T“@Q1ŒaUì[ž‰œG©«2A{…1¬:&Í"{ X@T(ê4²¡ffõ"OÀfáû±Úvùw»A‘9Õ¡Oˆ°ž©vˆS0dS
	ôàZ)zVXr•’PPŠï€
"8@eö٦٦ƒ.½y®H+|ÿ¥a]†—2ØT>†sªxݘêH‘V%žɏ/)‘Vøøœ­Å>oŠ:™  K1&ßpJ¼-`’k_Þ)QžRÒ»TƒÜæ«\ï]¾eª:)Júü«ÀH‹{}X„&m–JG€u[¯¨ˆ߾GxÔ‡¦W¸ٹg¸ÆF'
:ڌF£ÃD »l^ÑÅ&»Cb™©֘u©N߷ȯ¼d¡t¶Õîq´L¢“õÆÆIî5_d-ü]1(A
!þ3¶ÀJ
€™nñ¬OóYkÝìp/Ðfl|Î)¦”<'€44 SçD¾-GkµڜÔ|��ÆÈµôj+O@˜þ©œÄiÚÝæÐÔG˜n<¬÷OT#Hœ©¼ª©›ýÞ\4þ+ÄûÇ$ROs£ʐùªv§÷1b]8>¶¥¼îòÆծ´wSÔNvÚl	R”PR´ÓE¥í˝§`âáxØpܐ‚EÃڜ£çf_²ûÝX§· Ø#

Øâë6=hž×M,ƒZyÅKqŁ!ýöxÝùÖmtœ.ÉZ}<V~R ä
;]êÎnŸÔjâ¸'4 L€( ~ý†úìr•ëw”N´ÆÄ0â~vy2”'Š!…=¹Äo,:ËM&‚G¼Î:‚å”â(æ}ta±÷|?4~~‰ǗD…8}öxÊbÛ.·Ìø°†ùŽ’@xŽoSèÓe‘׮u™ñp—^Ò–*D‰¢áð"öØb±­+ýVí\«
+„U@hİPB·e†–ԼšZ=ÇÏ+(Ž> ¾‰\!ž·j‡‹ÔÆÕp«áÞY >ˠàÿ\ícçq÷ÓéaCq«7Cފ]¾kp‘vccÈp­¡8Õ
ˆÈ:­Øíþc,,×ÎCž4h(¨V |9õû£Û^ñ/«–_ø)[­0(4€1	ÄG®q×Ǻ݀Ñ)h·Ѕ¼éboÄû5ð¶½p¥ë·
Í$ɨU¯٭ôX¤݀ÁøÆ,‡1,¦UÎrŸç½8jmö˜•ÎÐaO.î_‹@P“Ý6»Â-ÎÞk-°ÀR·ۡO¿Ãñ#¤0	QaWÕ՗ß?ÎÍQa (ôêõæ(Õk—ÝùýÃñ㈿á{Áîü€JþÂŽǏO@ü^0h ¯þJþ7X¾ý*ó?ÄP°R)ªŽÔIEND®B`‚‰PNG


IHDR@@`¹U@IDATx^íÙáTWÇñϹ3˲%ÄPjڠ­ZM)ñE«DŨ¤Mc‚ÚVcKB¢B"ÆB@Û465Òؔhզ‘j©¡"”Ä,‘•‚e»ؚ¡A
ڄ¢‰$twggî_ô$—L®Ûvˆ/ä{þ€ç{~Ï3çœÜ	Ñÿ–Ìÿ»À%KU‚7%€ˆ 
€€ˆ”„àüE¡51Fã#´ۂT>S5Ϸm3h—
–š¢GU÷[î?òcûºëTeBH ¤|EÕýî*T}Þ7Ýá ,S@ôCkäò Ʈ¤ò·[5ÇZ1Ӱ#~ê'sâ+,›k¥w™b²3þfm8¶Ân»ÐQA4ŽPµøo£ß|0Õ
n0պ™îf/)¸Ú”ÉDQS±|6ÈÞ43¸V·À{Ép=¼Ódð¨ýN:唃÷!i6:H	x•c­ÖLÒÂ[ ÏMv[Òû¾¹ÓçN»bÚä÷ø‚gÜ*)t>™ÌëäÚ$sï¤êF‹U@n§ÏVF¾£¹<±ý™N˜áÊOúœ
 â&72Ë;ôêѣª"“	ã%¤¥}¦ñ6Зû´…úüÅ{54EQlh)š%ßéSÂz׀Zâwîô9ˆYkÇUT]ë>Ûüڃ®W´Or®ù¸jÜÈGms™ŠYë̛å	Üm‘…–ù­{Tµ0Û|嘤»Ê$Ÿð¬[˜o‰™P¤C×ûÜ6'{Ô+NÙäªÌR7káJ´Ã­ôˆ;ÌÖ
SÌT=7«ªB•¢¼ë¯ôÝëzÁíú˜ýJXd‘a0Ï<˕ñVWÃU
¹fÈTL÷D¥o³o)*^n“ªr¸L»×T„¬è¾e޾ÆgÀu–›8Ó¼‡dÅ¥þûŠV¸Ï4á‹vø•‚à%€*¤¦2³4¾&­@!@îøÆÊTü™§•±Ln1ìOsNS2@Àfq•3Zá
ïÖ-ž“s@žcYñ ô’M¯”NA·€!¹¦fjA*Ÿkxȑ-s1ÙIÝ>¹¼H€(×P÷ºÕÎ}Í‹WᠳRdһMؚã֎XìÌÅÛ?¿—§Àù-3jÄvOðU‡íð¬†4ÎP7fԨuN<iP÷9g¯yY£5¤jFµŽïê>F٣QŒ`!Ó ŽU3èø€“ºM?<“öß2JFmÍmÔ]ê¶sڋI H UAݘ~#ë5u“½Î0¨&	Ð*@ÊùÍ	Ow¿»‹òåÅïa£øîõ3ì9ñ€fjÃQ/٭[üÁIžw.(ˆElà~ÝbìTא‹å-éXn3ä𠽺AÓVFìIñ/êƬïVûœdÈYI€rPØíðƒ&ÎÏa‡zûéfð=VŠ&ƨ§8[Ö2ÆÍàyCû=iblsš]†%Æ€”šu«6~ýêmÄóŸ(Gmü»U.œã8n¿$ËÊ3PSóˆ¿n°مò}M~a,ímÄâbª9ku<·ԀÎáeñO¿,oU(W1ePqÔ]êυòÿ6¦.c»Hs “ÙçN_6KÐ)u{lUSOû׶@Œá92²RL¦}R†F$Ú­£˜^Œ´J›Zˆbh?D䈢†šªLèH ]îÅþu$Ò4Td~7ŒI!ה‹bçD4“Bgå!&‰˜Êw.€(
.Œ¢R.ýw|Ià?ñÛyÈlNªIEND®B`‚‰PNG


IHDR@@`¹U/IDATx^í×}¨–gÇñÏußÏ9í8§ÕY´E؆•Ô2FÖ‡ 7Xåp•4
Lƒة
涃­|	k‹¶^d:ÉQQsj­li#–8¦é*Šƒ
ÜÆÈô¨Íóò¼ÜW0.¸á¹9p{Eõ½ÿ8ÿë{ý~×Û¢/™ÿuÔ €ˆˆz"¢¡Q2AQúb
‰Ðk!r
óÝéQû=á»>ª_.Yz NAɽËcæ­´ßr£:âÌ/ 7àá|î—ý٘ӆ½—Ak5dB3*æÿ6W-s·…Ì5èqWð1/×0ó	dšJÐo³ÍÑÌxAf”UhÉf>T‚*äò™O€0å éd˜é
 ügÞábÄÿòëøÿH'D "ãÅÈ5ô™-ˆFE…Ò+áâ¼Óç]k³Ï]žÑ!ˆñâlÑwµyfiÆf\ï:owRGˆuo›¾õցÛm˜ç6i+D¢ĺA@ĩo¸RÉ
6ðVïp‹%æih:f§uþ©PÔJ 
–	.·HÇgeSP(™K|ÜÀ|¯ÃÙþã'ô>-DQ¬
¨¾þ\ã’cÂf÷«뻆Í>
xÉGì[â:Oië¤2J
d•=Ýg•–.̿à³æ_bȰµô[`¶÷Ã[,s·5ë“ËdB%}ŸÏÙ0Û}V
ØhµÍo´Ër“j2 (Éàk.÷ÚiÈ?t@„Œrþ[;×o­%²†+lóÓç²ØáA‹Yê	säBw駇›å¸V	ë|’«¬×Š~õ¸ÜNKÝì€å¼ÙJ}2j}²L	y‹tq¯·ºTÉ"²Å*Ý,ð
а>¨!„ª@î$Ïé¦ß6¯VåJݠ$x“6êæU^	2™ê.s›¨›×zÐô)ž‚crUø‰gvZ§Êr7š¯÷E«<		Õ
¢¨Ðt›3wڣÊ×]âü¹É7¼À8ˆÝm-Ϻ«SÜdD7op«ވ2êo
Q2Êùkkš´×ý'|ØÝ\¯79Á!E)PM`҄	[ìø‹µ]X~ûuJ2(´^VóU‡öZãÂòsÖÑQ¨&2hš0á¬Û=ÿM[]8F=ɈçËá«	D…–IãƼ`±!G\(~¡Ã~mmE5 *¤Œ;jݘ
†Gaö”	”E¤Æí°ﰟêÆý’ž–ª	¤í˜RøßÖ;ìvŽ=šÒ`jRaÒG‡ýQïl‡_k§§™Š
?恨GZvqÆﵧH ZCڒM?ó÷­á¤ÞØg”aIUՕ ­éœG^r_Ô?‚Ýݰ*PUh™ôCg¿FMŸ¦휶_;)Ԑ΄–S¶¶>ö²N±۸V*@½bRhÚêìý^4]]eõJh:åûcáK¦ǨÇxÎÓZI¡¶@,ׁ8¾5œæü'x\3
º婨tÎúè3EÓù³‰Âö4ÿ(Ö¨¾“v;'¿q˜½Ži¥[°¶@õ~\ïøºðQ}Z5µªýC£¦@®á¤[⦡yCΓß9(-@ÎW©„Læ¯>eµ«u‰F¬5©YYµb© xÖé7>j¤—ž¹šÚ
‘úÕGŠô·O.ԩ/ݩ-qºi.I )—êP¤s¤•æoÚ©†BG&j&ŠôïI€Hú7!}uˆé›bpøu=cP¶®„,IEND®B`‚‰PNG


IHDR@@`¹U¯IDATx^íÙkŒ”WÇñïÜﳷ™aöÊˊ°[V¶ ´KƒTӆvA[nj(	ZkS_5!ƘTIÖl”¨$
	¶oššµ-
ÛµA75¥7ʂ\Êì2?ÉÉÉ83q	'ÏDßx~¯çùæ9×çyÐÿ8Èæÿ|”R¡tÏď¹byûOû“
A˜9ʮBa"D"DÃÐm~‚„4yé+„	Àç
°×黸ëÏNü¹ðúø®Ó÷DZˆ)¦|„¸¤És#\"Üyñ!¢=\xSUmbäø‚†0% Dœ´$iòÔF‚ @x¤¯p@’.j·6k…úµRßÕIIÅk#÷µ„)Rd,yòýÍXÂü„ˆ]’Æõ¤b¢,aí–4ùÁc9C˜ JyIz¶Šp‡€0ɟöêU	訤SO‘$Œ*@ŒZ%	G‚í€iòc/JCB1­Ós҃–ð5I—_¦ž¨éØ)´€;Át!u´­VñŠ~ 1Éf™,–ôñ12$ÝÐaÎÛiòÌ>H¦¼µoòcÙ{°TÒø;L#EÿԀéàNð"A–Î6JÿxcÇ«/¾'ýÍÈm’Æ^¢™´	à3øžfºön`Ñ××^;#×!”Ш¤7¾íp'Ø{ÐH³»Ÿ”þ¨;
_”tíݖ9]àN°3!E–Žc;¤J
¡z½*iòÊsщ„'‚Ÿf2_="=jøYýURáüÎ/3‡;
nŸ]Κ'ÎJͰGÒÕ÷¶¬aÓɘßûÁàBPi5ÐMÉooKúþFæ3“i¤1ÿßà@°3Ìzú®É
ݬe¶¹ý1‚ø®»£4ЮŠ¶óKöö‡LyN„ÒUê;cÒ+ڦï骤׿I+vø
`qšö?$*PZ/ü¼]€p¸AâdÞÞ.í³à^I׏“'åPM؂%T~·N:lk%]>èá8|Ðt÷œÉKҰ´^§$<ëàB(kÚ<U¼!Û.éžKŽ$!G€;A`ÏEtý葏ö_9wøðg, ƒ&â„ð9Ü	²;"M´ÓÍ|ú襇äíè
p'ØÝ E†V:™ÅL:ÈSoþ¿p¸üø	%IYrdi"MÜò^	b$H’$N”-ïðF°§6ö™Ðàa,Øøñ™®ï„êæàààa›ªˆÀ;¡ö€Ïëö;_°ǯË>ÜáÜc„kxZÒ@a›¤ó“u²Š{XÎÝ&,e1ý, ›²¤ˆ¨	àIIÒóe€¤.Hڳ‡ûXÊBúX`3ŸyÌa&­djø†ŠR±¨	µ”vJ:sŽåô2›L·頝VòdÌúª`«)ÿ«_~ðOiG K7oå™MôÐNŽ&Ki Žq"5„_5å_Úźá_Kg.#ì—ôþQ撧ޱ²D‰²åñؤ¢¤W‡YɚàúËÒãe€û%nÎê³çÝ@Eü&>O€
š”thˆ%pk–ŽTLÆ’Žý‚6Òñ‰ê+ázSþ­aòÉ[égÅO$-)#l—4~Ùdˆâ¯)àSþè.ú覓étó)Vü»´¯b2^’´wÍ$	Ö
Ð!I’Þù¹)ßF–,­ô°|ø'EÝPsaHÒÙ:i Œ¿†é/»¹˔o"E’F:éO|á\¡z2U,#N €Ú$it7lù$"$Éó	V¼vH:]1+iôک#„Ï>d“>ÜÍ\ºly3HÒÈ,–<¸u\•“qƒ¤ÂõL7Dð{ø‰&;ö3³¤¶”Êûð$E+½¬<qZú“øu¿~£›’¤—7“%FÀ+ L‚údŽidi ‰ÙLJݓ¡›e;‡'$­ҷ4jJß,~8úãít“« H„iÒv-·å>BÔÓÁ]Í_<Smã7\´•ø4]d¼|&j×òÊoFâä˜˲߿V4;áðÞèYÍ2æÑF½÷1à+=P	T53#¤éômÜôæ+ŸfkYý,fö”'@å׾êH’£‹…|†ûøŸe1ó颕F¶ünûä?™ô˜³O3i!Cš˜}üªn5ø#M†<­4“£‘ÔÔÅk(}Y$Išdå™ç¿ 4HKÀà_̃J°%‹zÙIEND®B`‚‰PNG


IHDR@@ªiqÞíIDATxÚì›=‹Q†ÏHP4i„р4’"EºÄ&VjÔ&6ùh–­Û©©F›4¦Q'ÕV¦Ú"h±° M6 ]e$drÎdFfÖÙud'7j΁×{ç~1ç™;…¯¤ë:Ü4‹źE¾£¨#ÔÇP(ôõòMÓ`ñ•E¥PòuƒA	|I{üBuP‡â¿õ·¨*àu‘­€	­ôQ[2™„T*årJ¥„Ãaê:G½G½DݙÏçÐét ÝnÃ`0€ÑhD»\vН€ÜTxR:‰–[§D"¡«ªª[sHtLí^æ[sü8oãâ‹`©^¯s¨ÜdÞVpÓd21®p6›]I¦X,®´Ñ8Oó®[wgإ(ŠŽ÷®땥vê÷ºֶ¸òƒ}2ê5êœN¼Ñh¸h6›Vr4îWigØ@<A]P’ù|ޑ<›É_˜ã`üA¯Ãc,êT¯V«Ž¾J¥bU©ÿ†_ß®ß.» †ŷÙlÑhtَ<ˆD"T£Î<~ù  ’6B2’3“]†íøGþó`€0À`€0À`€0À`€0À`€0Àð%4M»M%ýUÖ¶cyßwÀcú!O=†áU}´·ðê“Ééꪪ:úÈ,eÆJJ@„_ûï¢òŒÇc=‹9ü²,í¦g@1Çñõ
҉
è÷û+}™Lz½ž§¿ÝSøe›rL§ScۧÓiGò¹\nY§vê§q—’»pll›«ÕjÆ*a_lsàÑ8Ùív0Üúûkœ”$IÇã†1ªÕjéx;XIü@½1K£úi§y"üó4Å'Ô+›yúêÙ&ì’{ü'üñ¢>£>`â_\Þ±xzŠº‡"ƒխ¿
à·ÏK*"SXIEND®B`‚‰PNG


IHDR@@`¹UUIDATx^½Ù_OiðV†°X” ¬„?Ò&¥½©-AaC‚÷
ßGoֽÞMŒÊzµ›¸üù<«1¡ÔbVw³êPµØÚÙ3=ÉäP§OÂ;¡s2!¡'y~í̼s&ó֧ðò»–~ìÞ/õTð·¯׀>	€×ø¥ñ+<£¯w÷0ôå¡/ۗ‡‚GŽ?ˆáÊ#߯Kù~å†1¨€KüŃÇAüºT@8xŒ‹Jp¸ÇCŠâx<%¸xüOÇxKxbÇx­µ®„øÏ	ñ<žñ”àpˆ§‰w"¸l¼l?û‹å…ï›Ï ƒÀ<>ºfC,ßm;Ü0àñÍZ¥X)îuP:(5;ÍãàÿÚô6k>ÿ,€û{ø\ƲԒÔ2V°zô¡pô«X	{–?—}ÿ>9,€Æßõs
¸‰䑓}·¾¾ï|}[XÔé¼rz:’¡6 úJ¢3HaNö򑀼éÈU_‚°øÁ,~8ì³ÈÖÞujï5€€Å+਄”D_B—q©H@J>¹,—„:*)€,ÀÆn„ñ0‡q‰ÿ^öq$#IÓ1g„ oúýè/`;€@ãÐjÔß6ޜüTãMýmë¤Ð:éèh(€@ãà¸*ÀÖ]%üè±7+}*².„€]:<pBø”ƒa®¥„ʆá)¡ª˜¯g„!I;=Üi>>EžÚÇ“ÿü®„Þ|ÿÿ$¤Êy.ÿ©„ó?	÷7‘z0$rÅm%œïe¸·ƒ’’¨‡@OBŒbJT…ÝC0€æqõ?[QÑéŽæ±˜øÝ–´Q=	ÃËc˜FBˆXŠ+¯ÛãƏX–}·#’ۦcµòÚlü‚¤ÌHZx†®`Æ,àÓ~{Ü( /û
,EÎK¸¡ÁÈòi_‘ñWìBÿ[¶%èD$ÑY7í6Øˆx¼™A’ö¸qã²_ë:\ÓéÌê@Âã
€bގ×H¼Bœ„Æ[%ÜsÉîküvt¼P‚>˜T_Ö^ԟ7þª?¯½¨¾l5:­Æé}0aßÞ¡¸çѬ¸Eâ
€ò{›àYNjö6‘'ñÀó¸^Ú
΅µ³ó$ÞaiBàñiL“x`„1!Ì#_ܦ;ûê±Ïc^ðc®ç]Æ.<ˆOàñ“Àã''¬Ÿ!þGwðÚx||8aÆÇp‰w8h||'ôN¹»…‰	à÷ˆ\ùYùr§×ü½¶Ã¦DZ*‰)„k~_\b˜”šÀh¬—p~u‹F¤äÕmüâ/¯1(åaÀ=þ¡Öъ7qØIEND®B`‚‰PNG


IHDR@@`¹U¦IDATx^íٻoUÆáßîìeÆãY|Yvm᯽+ãKDbPšHHD‚††(¨nґŽ*eþ7(E¢@J4q$
‰IlCjß3Gc>Ér2sr¤¡Ùy¥mßGs9óÍYÔÿœ> èú€“N#8
QŠQƒ£¢€5  «ËTq£x™âR¥L)FX¤~£sô@ìeÜõ¹ÇƀAª”ì|µåýM¥î(_‘!âS¦h4€æõK»[BÈ¥F{e<êŒ1uíòζRMê¸8öOC•€aÚÌ\½òô/!¤ڄx¶9CŒò
½Õ!¤&,)„¿…@uF™bî³÷„@4h2ýñÛÿü©ÔOª‘#@nƑϗŸþ!õù*7æwïK}ޗ;9»wOês¿	oužU_°P8ŽN¯?øýôúwÕÊa€6¿ÿ&ãú]%¥) 7Žlt(ãÄ…yýNL\¥ŽÞ폦õ?ßúð£'…`бøðÑúž²Öÿò
¹øÉ²:šªFMø~þ˜^ÿŽ®ÿõkγÄ"ç>}?&¬+ßààRc$¬Ç×r3!88Iý½çÕÿöKt™æ,^[]I†€ã1ÀO· J%Sý&i2N‹3ô‚Á<ààÒÒâÿß-ܜÍP?M‹a2&ó‚) ­J_ž¿1¿w?SýKx¸PGÏW¯ìh-c€ö·v7²Õ'÷##3×.ïm+Å8
Ül€	Ą;`^/_251ÁÔõKû[ŒP3d¾ †£¹¶L¨yE€Lë
Â(å`^/„*~—J4XÖ#ßÒT¨ÈËÍ`Sr7!yÁc5‰NZ½ ’€=àÇxiz²ºB—I†	RëŎ5@–¦í/ޢIEÈ «ãæÚ2C¸8ráàѷKÈȒ#@·djÊ ™šò˜ìæ{@[™z‚–õÀàR§©”9án79V€"UjzߣÇ9.ðæ3óF”¼Î"]ÎÐ$ħ‚=€2>!/3Å=æRÒc–³L2–[@úӄQš´™xnÚQZŒ3BH€›º$¥d„ð©Q'̔5ñ¨àØ4RŒ0،×ÛñRo°ÿCú€>à_#:„¤¡E€{IEND®B`‚‰PNG


IHDR@@`¹UçIDATx^í×OKbQ‡ñ§n×?WM¼é YŠŽX)%ô6š†þ¬Zͬ„i‚æ5ML+׽Þ@Ä³i´¬œë„ýˆ{8Œýnjõ|…¿CoÄ{3ý>´‰`“ƒ©Ÿ‘§B` âS¸ûû¸L)ÄLàà»ÿÜ{ê=ÝÃÅv:ÁûsäûŸ§߇xD‚]€Î'îŽûùÁú„»#Á*@çoOT^ù„Ûc` ç‚]€œ	–r^&XÈy™` äß'ØÈy™p¢	ƃ¼@0ä%‚@ÊLBޔ`0ËËÿ!rޜ Î
âêWøðjòG}YÇ'K8@D=c€ž:Y"aQRä(Q§É:›l±M›vÙ{À»ìж͛¬ӤN‰)¢8&€,Eª,²Ä
Í`-Öؠ-Úl°F‹¦Ú
K,R¥HÖàâ1M–<Eæ)QV¡FƒU°JƒÊj%æ)’'Ë4®ÿ£x¤H“ÁŒ*4@ƒ
røzҤðˆ†ÿ#T\¢Ĉë%ñ)P5
ø$‰£GŒ¨>ÛCÝŠ æ G„$9* BŽ$œWÓO7¡CŸ²(ãǑŽÒÑƀ1`ƀ1`ô_Ç#>HBŸd¶Îò‡OŠþ(µó0ù{ˆ‡kx–ߜö	=v¡ò7§ú,7{˜\}yVƒüËóõӇÉ$Ì0G½ÛQƒ|·C9fHè§Y¸Ç)iòTY¾:“	rþêŒeªäIëÇiøç9>Eh]ž1yN‹Šø&Ïs™`œ7¸‚QÞäKÐùŸ߇óf™*æ™"o
Eóæ€9o ÞÉ[È9o ļ}À0¡ÙÿŽxyþ��·&Ìò‘F·ÓíÐà#³BÞ:@Ȑ§D5X‰<!o
§	i²|–%'çÕDÀ?ã@ÜeÈլIEND®B`‚‰PNG


IHDR@@`¹U¯IDATx^íÙMoUÅáŸ=ö¼db'ÅÉ;Â-qjË4IEP6HH ñ"6l€+D°ƒ+–|‚nUbÔê¦^ƒT$+¢M[Ú5͛“áf®¬¿°p|ÇS
çìsžѵæ'Dÿs&€	`˜=9•¼Š• y•œ
‰€Q€¸¼@Ï(®ŠC1fäÒt½*ÿßÙn
!
 €ÃtRÀÑN·ƒK1= OŸà€Aü¨«‡w¯nàcc¥8”©*€qýÁýÏ^ ԀôG`á2K¨†õ{}ò2
˜ţHz50¬ÿè5V©3G	G - ®õ»®\¦ÍST™‘çÏ`RŸ0²þƒ7èР*§™‚èGøûÏw_b…
SRŸ@»|¼ɼ|ø2aÿ÷ÏÏSÂÎ ©Ąƒ߾<‡—É䆮53øúэè•!„ÞhB®Ÿ1råìAyóði=Z¤¾·7!.·(n7o÷'KB€ÝT˜Gß~ç§kI	ýys«u|;Šp±±¤~÷Á{o±ÅÖÏߤÞëvŽvâ*i 1@êß“¬³ÁÅ_¾6%ôë¿?tG¯&¦q̺^_9ÏÐä,+´Øøõ+#‚…¥ë{êé»0OËtH}›3,±HÈ2M֌6S××zwOêõÄd‘J@<7ô…Ë3T˜c‰•Ó?Äõv,Qún½_,à™–tý‡¯ë¹Á,S¸x”x„p îˆ/.êz?¢¨™\*,žLMµõVen`éÁþo«Cûۇ÷¤>) Ìüá=µtÔeíèWŠ9¡_/ê&€|\¨²ÀÜÀØÊ¤>1 Ÿu R¡$õˆ õ‰ºÀÆÅWñp¤>)qúòÀƖËL	隐—oü1+!=™Â:•ÐdCÝBH’„á„s,Ӻr¹÷(Šnd
€<<*„Ÿ¾¸w_¿t³È1¸Ì\Ý<”—nF™Sßnôv¤>#€¬ëkRŸ!@֎Ôg¬¿)õê³X8ݎžšIB-%@žÿVKêÍCÈ,.騸„œ¡Å:Ïr‰çTžšK\ Mƒ*eòi–°À2g9G›Έ´Y¥Sø
Ã"G€K‰€yY¢¦R?55Bªúk	ré6Ӕ©e–2¾ž7i2Y\ó?èÇå½®RÒÿCc ûLÀ?YrtÉÄ>ĊIEND®B`‚‰PNG


IHDR@@ªiqÞ
IDATx^í[}LTÙßÁ)3ÀÈÇ2"ˆbT]Ñ-®µKYݏV³‹ÛݦJMëvuÝøUi¬¦MMì¶ÑhHmq7Q0.d5²Y?𢬶Dc4l¢È"à–ongrîd¼yÌ#½™¼IړüÂË}çžÇù½wι_óœâjÃÿ	b±1BLÀzã¿،0“ºR>|œž؁o)ÀÁ÷ì¬2®ÿWQP™ž000'
ú3ª%f޳ӵµµ3Ÿ>}úûÁÁÁó###mp¤tt´ghh¨	mŸѽ˗/ϖdø!”€É6چ?~ü\‡ú°k êÿà¸xñâ¬þþþ“ô¿s&]êÃDØL	ð>—F»»»W¡-5"ASTçå[»wïÞr¼å'220 ¾*ýX4ä­Ÿ/*_„>'ªg${ÚZËJ=:$èó”ú’
¶%_œ9Ü!ˆôe¶µµu
Ú"ŒHÐcçÃAúNòm•âlò4=¿ ¶ŠrÁ2B6ȖB‚)`"àV?¯æææuF$hìø’ßÒҲÎó"‡‡ōß¨ŽŠs³RÅç¹oŽ~¾ì-ºVï{úP_²A¶$	2ü0³j/XöìÙã—@Wd腕——§Ñ', ¾ÎWÿÞðžø¦¹Y¨Bmt¯B!A†Ceeå²-s‚¤$
\’÷ ټB@ZO–©oVÜýðˆ½¯ÚÚھ@ÒûZ¶=8W-N…{õɆԭ ۀC†‚ÏÓ|$	2ïD?~<lS2«Jˆå7oLÂððpÿþýûGVqqñúúúR{çùϼ}ªâcdb>zôè<_s’ôH0ûQíí퐖’b¯ÃÿzïWânÑߞ%áH‘—„C‡mGß×òòòV€„nj§pº÷Š	²MÏðý
̘®H×ÎI*Ÿê?äòOßñ:Ðóå—Ô4&	õ>|x3ú/<qâÄ鶴÷î]¯Þåw"HÈ6=ƒŸe× @“ãÏßÄaT×! ŸNLxj<‹)	EEE8ÎW1z�s3SHÇc‹„lÓ3—-ôI`8ù	È؞€­´yµÙY‚¤§§§b~<_Âýû÷멡vÉbN%ÀÕ`ž!“¡>ú$Hœ@4(	øÄù,„]ٷoßÎñÐÛÛÛ懀D~–S}Tb€©˜Ô<êÔéτ%7|ދ8°Ì	5È6=ˆÑ @‡s=zT;V¤Gٞ²¾	=Íͣj$ۚè“`·nÝú³Z©¤‘`Àӹjժw ÷
HØê‡Ã2H¶uB  $¨Ip÷îÝo VGԁ7’„.kw"<xpÛ$<;ê��m$Ô2¤"‹* 4½•ÑðöAÍ9!…J]GGG=ªC‹a‰d
²I¶uÊ`@HPBDú֭[³ãßȍ‚ÿýd}IÈÙ$Û:¡€ …¹NϨ®®þ­œ7~°‰bpu¨[šMð\«÷7½ï“-²I¶u†#ÀÛÝ@†õ½?É‘Öò“ã^‘3@êK6ÈÛt«“!
´HÈWHñ“d`nYYٯ=¼$FՁʚ\#Ð5µÑ=ґŸ}oiié²v&›L‡uÐ'agò£9Rȁüüü\¬êԌB„‰P!]êÃΧ°­h“MôI°û®1LB20xiíڵo_¹råpgggF†]pvˆ@×ÔF÷6lØð.érŸd¶£.‰YD€9	IB4‡C'±9À<`ð2Aàë|oë&qßh“EQ
OBÇm,‡Ät®å3ù
§1fs[*ë$pŸH“eqü×ÁíQìT;˜Le$r[é°n„º1(¢M@àIðÝã°p‘1Œhns±Ž²5ÆÎ[C€~‰ÔÙXô	°’›þö¸>֓ !V`=	Ö`=	ÁO€þʒÆ!¬'!ø	X²d‰Ð>Ÿ LhlAEöæÛm6›¸yó¦Ð>©òK
… #   @dffêlڴI<|øp8**jÚr€7€EÀ+>È~Èœù>“›IÀDeNo=۶mR°a¨ãr¹h]^CÐöcvô% U0HãIN2÷ÝAG-[¯SŒBhRL™2ÅP{ùr…¶›ßü÷€ïß!²$ÓØñxv>R™ÚZKÀƍ½Î;vì(Ne}Mº{÷î5ÔOMM¥½;víڵm/°“r÷¼bxv7QNt‚"	®_¿Þëü©S§þжŸ~L
X¡¡¡†$œ9sF ¬]CÛ, ÞgúfƒÉNˆ¥eKSÒyqá…B´e¹v»}å“'O†¨[X†dggˍʑ”””t&`¢¬ï~ Lx,"`õêմâ*Hêêêò’T&gô\´}AúW¯^³$޾}[\¿~ýC^Ј”ãu‘àʕ+½Î744rŸØ¼¾téÒ÷ñvIFF†!	›7o$ØÇÄIÐ-7+ƒ–€å˗{¿víÅ|:×ço“_ȹsçNogYqþX”””äór–°I‚…ÊIccãé<¾“‰œÕ!þ9‚60EBB‚!	ØÙœ0o2‰1r„|0nܸñ/=Kçc9¹HŸ™ñ†¬ƒf%$F1„ÎäRLøĆ`ijj"ç_Tœw†‹3úlàuW¯ã³yc–ijgÏJÛe<ˆâRg³š§ܞl5}Ä5;Õ×y¥t99lR€Œe˖mD’þJ"*Š,‰}n·{÷w!V žؘÔÕÕUä34b།açpHä!nÊ]»€Ô××{		ñŒNŸ>íJ©ªªZǹ$ŒìZM@(̢‘±ãx‹i‡…Ëw2b:n“…ûÊ䙓“#¶oßN¡$Xˆ:Êބó>›¹O\P ìÈD”±¸Ñ/Fl¿ÑüµÌCxŸA¡BcàҥKÿ\°`ÁFè-~Àá嶚õW¡êƃÉo†&0Iqœ3ÖÔÔ\¤l/g(‘%8àDµ?x“t€4Î-ÑPl»1f?ESO|ÅpÞH_³fÍZl[ŸÇßš0?r/ްšÀ`'f|¿´©'¾x¸ü*/€,^cÇçòýDÎþJxYF€Œº¼ Wyø:™+Š[ÝÂf²Í$˜	à’È{ûìd¼²…ý<0QÃñ &7’¨[Ú.“U "@jŒ·®­$à?
“!<…R/IEND®B`‚‰PNG


IHDR@@`¹UIDATx^͘]h\E†Ÿ™³®Ò4ÊV1±^ÑÛ*‚ЪP(±6±*j+¶õ"*("*5â•B(
‰š´MŒJJj„–ñÂ"B£ բV±Á"Es‘ìž=û¿ã0v؅p‡3Îs±WËûð~ó±ÃJ…_$xå$ ÐXÄp	bi–YêEb\’@"Ó,>D
‰LFA6Å\FpåÄ|úÓ($Ü@@
®>x¡×*$' 	H\¿ÿ|"
­—P’€ sÔ*$y	€×Z‰Ä
$« ¡E
SÐJ²
ü*Hð« o‚¿
ü*Hð« o‚¿
ü*Hð« á?+ôY…$¬»ç¼%øUàWA‚_	~$øUàWA‚_	~$øUàWA‚s…^«à@ÀÁ{uÀÔ%ÙFჃ>ì9ÉY–8úÿ…ù-Hg#xžC¬…Å0ðÏq¸[Ü%ÖǬkE·¸MÜ*n"sÍ4ÂÑžå-àì™dŽU‰È’ӄä‰(R¢J
ål
û¥ê=,‡˜	àñÍDäȲh!KHD‰25êv±¡>š;•b7öS熍.3„¦ÛB¡тjSàIFêäЦéO>…¤!æ7Ž!/߳…
%Š,fe*¦…jCà	FœÚp˜Â³ÙsM»0tn[)©Q¥BÙB¥ßÎcÁ7ûîœ$Òf§ {Nð©åGî:NÕ,ªnhgÛ8@Àé‘;&ˆÈk¢þ™êBÝ-˸bGü4wû*ÞÊ$ߍ®#oˆ(ü”ýýHó2Ž“eY÷Ìj# \	(€	øþ@×ÛD†E4ÃSªÖCÆ.#ï붓"@8}§øq|õp#¼¤)SšûûË4OcÏ>Wõ¼r­é	€¢pn|ÕÞÆFW¨*”¿8;š–ñ⊧±´' 45øs|å›Dq|™ªY)£ðð×ᯙ¦e<d¶ߔvрÒè ùý7ØøxŸëÓY)Ø›oä3‚^ƏÖ#4¨QYñ2E
qù:^郊*»¦«ÝÜËsüÌq6AåâÌÇ=]_¹ÙêxŠñìu<@£ƒò¹¹£pŒAn¦pqöžû3/ný¥ÁÍtÍoÛÑz”FÞW5Ôü驗®{àö±£Å÷¤n$Œ@ÇLùÐ: Jƒ̾þê掝}Çs‹ä‰âa)
(ê1ª5^c†@aÍäg	ɚøxU©·'Ъ P€ˆß@¡&o/«ýŽÅå³Üޑ"òDM¿üX#P3-”æªÚð$b\Ó(C[ç_¤[ ™w/–HIEND®B`‚‰PNG


IHDR@@ªiqÞoIDATxÚì™?‹AÆGA°°PØþR)z] ­mÔoO`—tjwǥ´°(j¡¥äl,mB°B°É}É&øçTDɼ›™Éx¹;RfwŸGgg^…緻ï¼;àœ3?·øÀñx|Ž@@uÂá°kM>çԤiPŒyÀcƒÌç
~·P(äIƒ"Ù%è{½^ÿ1žøAD"¡w»êZ`ð†>f³™0¼þ$ߨ—ÉdtÀd2QÝ+s)táÙ)=°F£¡Ç
¯wtCëd³٤µÒQ:æ›͆ӸÐX(+u‘ñ¸Ð[¡{òÐn·µ7y•ÞÞS!”ƒ_¶Û-K&“l±X8’ËåX·Û=»5ÜØ:«T*ºð±,‹Íçs:çóҙº%"ý~ÿŒT<çõzO§S¾Z­µÿ^¶móÑhÄ…™y”q·	à…Ж&ªÕê_?òŠț4O^/L¤kE°T*yÎ|¹\6¯’kå[™¿P	£V«yö
 ÛY¸x|¤‰Á`ðdX.—®É”¯þ!gçq8%&¾>\²Ù,ëõz^_2Ö©TŠ‹ÒѬ^»´p{«Õzª¸¡àOtÏçuÀp8T„ƉÛ*ÁWB;òR,µ?ò*ý}¦ ›ĥ¡ŒûÝÒÙҽåð;ò2µ?ò*ýÙzK,‰°Óéä¹-1ù4ø}¿߳X,¦Ÿ‡ö±!x3ä{x=à³öK€¶Ę––_>žIEND®B`‚‰PNG


IHDR@@`¹U¶IDATx^íÙkp\uÇñ'÷ͽͥMLڦ÷@[Zjah‹€ãTñ‚0ÅQGp†‹8¨3T±
Î`gÐñE•¡‚µÙ={kÒdJQK	¥”n’†Ü6ÙK6»¹oö|=ýÏéxv§MO¢‚/Øß$³çÕó9ÿ˳ç"|Èù|ø b¥œã“e$[%çlÔQ–‘ù|ìÌÒ9’'ùR Ž{¼V׶êϵâ0R y’«(Yÿ€Y:WòëÛâOûSý`f2ùÎÄÑ;4ˆC1ì!ìÌ3ϓ‚_/ùqªT˜ LQ0Ã̔³{‡J¾
„}€*nœùgˢê1€nžf
d™Ê".å.ö1	ÀôëooU#‘£àÿ)À<wGۥÉcÛÈFΙ
î'ŒýâÚrÉ7WÄ<Öò…]7ë£pŠë¤„Ý$ɖ=uR`NÅ|fù¢¾ÛHÂó” ¶r5=Àôñ½ËÅa%ؤ•ïØÉìBì‡:ځ©<Tkæ°¾û2=#sL5§€±}R*j9ΐ+ŽË+§ކ½HF
¹‰çéBÆ9Â#lÊ$°ŠÐû=)–|sìÔùçKéÀ.8Eq ‡Û€Ìð*gnRÃϬ–"ɓì¹Ôì?А!cåWâ 9šèŠ
¶ŽÐg`Š;2ûÈsRfNƒm@–äH”õÿ´Œ™}HMÇN[[†šU†šƒ‡B¯OܟXŽ>þø)6ÇÀ6 WŠJ«¦߇miƒï’cá#¡æðp?ì{U|Æ÷ƒC-ñºΗÒ¯=»¤Ü{5ÿeþÐE–p:ûð‘ÈhoØu‡Ü
FÈñD|¨y´BTZ7“ǤRŠ$×&@M@¡,ì
ž²”/&Œ¼9ó&´¸+êr)CÆ÷˜6â��qxÌ(`ôGÖI©Ú6yR,ՉVØa|HÆϔÕƜ‰¦HSŸ	ès…㸖pGý±cП6n߷ÉqHŽ=€ڀR“Â2àE`¬#êKåǚ¢MýÎNMèÔúѦ„3nŒBğš„Ë-€§€îݖI°(òO.‡‰´39
¿1썻M±f­ݣ´{:´ AŠ;‡ÝßÄÜk|úƒT«`ЅßßCˆ%)t¢þ¨;êLjöŽvè<iì¯Éb)µ	PK°âgW@·
èzØrÍÔ½‰÷tžµ¾DR#ejÚܼbˆ%㤈
i³zÝAOütŠG2oè/R«ú¡m@¥£AŸÖ)²þNŠᣃî>­C{ËsØçly¹Mx¹ÍÙrØwÌp÷¸û½ã¡·Zïÿf®€
Y:~Š´߸'I1ÚsÐí:î>âsµìkUöµºZŽøÞötiÆø§f¦YdìÞܥ¶§Àa–÷ÝÀt’Épó«Ïթµ»[ý®fÀÕÜêowwj½ZÐ=˜GX~÷e©1[‘Í]°@êŽ<¯ –¸I1Ö5ÚN¿3 ½éiõ+­þ7=­×èŒі©dŠ/X@r¤j­,’û۰@ʤöŽ­úÌ$À&0'ƞ6Üÿîw°)⌻§â)ö§¡ú^•åR%ŪÙlÅ%†xeäPæÏë×ÐÑõ©“	§ê„ÚqO»÷¸§SësEœ£þä°N‹-€BBÀ¿!K¤B
%Ç. WФR–½ômf\ÿ€ =vöj]ZÀm,=-ä{wf¬Iß$NÈZ˰CªV4ƎÁn$-Ÿ#ŒN’‰ёÞPGðdøôHx2•Dg?iØzbwÉ
sØd›“°bϭz*ÉU„
%È4“Œ3Æ8“LqÏg@sp~Ù 
Reù%°yET(¥^Oüz¨G2’ËV¾Ë<ϸ•%ç¼=сèÑ!çå‹͋²,û¥ùR"ղ|ÁÆÈðÕȜs—"$^ڰÐr—dë²<W­ƒÉêk®Nà$+lr¸Æ$|Š›¸`ìÅM,÷Š6ÙêºÈèˆÒxãö‘w Æ-¶õ¸йÇÚJ&ÁޝQŽ9
Kå¢ÍW÷zö³aV@!÷©b s­
Â,“P ¥a™4ÊfÏÓqÐy/â8 ‘Ÿ0@w[ð(ìDf%Ød«•P¦Fa­l¼áúš™˜ÀËnîf'7ñMb/ {÷¹ʶ.܉ÌJ˜N(•*©“•²N6_á_FOè:df:ÞyàWw˕r…\yl/Ĺ꜄„…0ÀJ(bY(5²LÖÈzÙ,—úúßß߶çä+§µ_—«ýÏÏûVé'd‹l’
²^.)»ìý$äH¶ÍgDj9I™TI­X%e6-r™ÊµQÖÉZY!
s…4–Ü!ëÂë8”K¥,–:Udµ¬1J6«e¥,—%o‘TY|fÍ„¿Ÿ0úBU©ä+‚
ÀÙqÈ3ER*Fµ©‘Z•U¸BʤÄ@«±Zb¶œžeúï=۞mҟ•ŠÃ`23¥ªp¡ÁËSqH©"4žðU`ú””«Û5»a2T¡|#ê¿ùœ؈š.³,=!›ðÀ*Qc``…˜3æ±ùQÄÂÀÃëԕ²
€íØ%l’ƒ…õêÁÅÜó'ÜBÙl§xïi©›`þ„¿Œ Ҷôbu¿8Àü	jSÊ&ïccÝCGŸ]t‰4HõÜáü	õ²úLÿÌö¯“ͲNVJ­چ¹sنó'”H…Q°Á@4ÊE¥Á8Z(EçnDöcŸ¯Úx•ÔH‘©6ŽŠfiÅÿåd©6îPMºÜH™Á9ûNE>€X߶©X^m}0³‰gôNÉ|Èù\"·ÏÚçc‚IEND®B`‚‰PNG


IHDR@@`¹UŠIDATx^í˜{pTÕÀç޻Ù]!<"
µ"iÇ vÂCªíŠSe:V
íT°
Å)´#µvZ§¶±P_VßÀ(
°J ¢ƒ”È#˜˜çnvï=_»×3sf§!܌Íø¿oÎÎ=»™|¿ùÎs®¾X¾`¾øRÀ#DØ^>(Óì ¶u±`S+T.nIŒ+,MnÒÁ]#’€2ᔻëGöŸåuN!DÚýý]©
ÛVO:B€Q¡Ë(éhlÑ]œ彯¹¹èûÎBҴ’¢Aæõ#^K€t.`ŠîLJ<1§÷|UyŽשæ##ڃaŒäR&²o}0ïœwŒÈçP(\Ü7Ï:ÿ/޹°–{X¦#úpó~ãýS—¬M ¹ø&½Wsåà?«Â}ÌáU:§ˆEÌţ}ÓÊko>Ne(¤Ã}&Õ~oÈãªð¯|ã¤顅ÛË!âßøê£ñ̊‰„Óqúý߸ïn®£…hlä"v;{Ú3w”…®
Øâ¯ýú©Ëp±˜®PËXöQðͅÍZçúî=ƬTE±„|’\ÍԠÚx‹ÅTO“h¤Çw݄g"GüðܲŸV,.7°„2ò—XÀ,0'џ>pÁOjÉ »2	Ãò/(í+ÌÉK_Êk,§¿µå@ýŽ£ێ¾Y·­aOêˆWðO~ˆžbNïëo³S1jñvʂµLÀҏCg›kÒÇ­ƒvœXѐD˜ϽXÎa¤–VÜQKÆÔ zzô½îÁâòÃðÛvdÆü\ij¹È=9éæš÷#K¹
Ën^F%§_¥VÀT॑±AX‡e6•èlã»*åŸ	¸AØÂ'/hÿ¸õ€b¥XVý¦˜‰H4³ù­„ç²h٧RŸ¥ô¦¤ùÍ}™‡e5)â×áâD¯€ƒƒ×óBX‡e
}ñ›ý:7Léh/puÌ47×rߴÖÀ
6íluùEÑÌ釛8va¹h¯S:""M†&×Ï}ëAƒn?…ó±ìJ‡íB¢p.IzÒÄr>B¦^Á­Ì~aPˆ µB2
‰²Q¼…ä ›>¢Ày½ ÁRŽà·!¥8!Ÿ¬	ڄAXê§¢	¨\HB
‹ƒƒ_èX2€S€2!ςí-PŒEӆV*ÐY%"Â'XzAчÔ-’íëAöPSHú_odðÉ*­°î¸Zy…ð>–¯©º®ž†’ÖéC±üˆ—ŠrpÅ!÷iÃôEá8nIÀkXÎê Q+ €4}<c$;0ð$·/‹ ݕ˜…'ŽòH–»îFŽaT¿‹ M@>¸uÀäKyo³žK¼¢ÓÚöHy(î߉Ä`ÅﰜÉéøMsw£‘0"V@£W¼qÞݓÜ>Ôc`.ÛHTMكŽP‚A”£µ£ÜøÏ[ÃX®Žm8ž1+ Ñ:ò˭}FßdWª™ɣ$‡Å¿ÆՎ`(IÄF¸=kù–$³€MÏâ£ÑHÔI(hüuÀ<а<Îmˆ*š¸À)QÿÅ!J9ž7$1Êëý!ã8ŠåGô¥eﴭø¡BÄ!ŒÀԍŸîpî"nÇòöò¥%ÎEÒ*
’&«ª§ÓV1z,å,ÖüÞ\È4D_>Y2U÷Îzt®ó"›°¼ÂPneý
U!a3¿æE,ಂbŽl¸z£)?]!È	ÜüÎûxTQŽêYÈ@.æîã,a:ƒcÒ[F1ˆ»ïðüS]Ì&õVìàQ@’¢޽ö?Üç¼jÆQGW™Í&c˳£fT§0ó ʝPÐá ´Úvռ–ýÃÙÄiDÅå[ü‘±\Ãš(š²õ¡ŠDçw‚|Ðá ¤Io¨›>«齡lçZ¢PÎjÖñcÖó43™&zLݼ¼"iN" ‚ ɒ!MÛóWΪ]WL¯0œÎHrï2ÅýŒÇÀæˆ
D”²(@m¯+ÿéë׌™=¹ç$^a«I“œÉṳ?ppK<9 ¢?ä)¬¢×Ô͌ž±#h@:°ËÑ(2®jâºßÞøµ+/_Nš-¼ÍG4¥œÉh3GßÿÛʙÿ¨YÅЩÂIDh|̲Ä_shÍÒËVÜ5ùì	½‡UªJòÉ6ڼæåÙÛTS-üŠj6u °‘1¡ 1tþ†ÄÁ
e<Œ
ð*Knqک¥eñ"×ó³-õÇþ½õ½¥{›3øN¯øîŃ&639OFçhy&Tðt´wD*§JÄÂÃÃ%<ødÑ.Ņտˆ  ‘“½¨eR„»#^..*Aç"Ѐ‹ß(ÃﬖA“V1¹ÁØ™q\òç‚lj0&qM8v9Yóï\¤‘á‹vªÁO 0m×ցː<“Ö\Áa³¿	\ Q¸k')Ìà)úÎa%A”
äK€6¥Ç4ÄFT…j¤c…gh¤øŒý–&@¢TÀJ€tø¶<ÿS0t¨`Vw,Ž‹ˆ,ÐAŽÐ8ø)Œ£ÿØ}¨ˆ¬0“§*y¨©J	yxЭ
ÁàoW±‡" ~Ëø‡îÈW¤Q†ÜùÆÎ¯ïõUH×í}ú²eÇÚÌ˅|n«‚ ÇVñ섒B÷ù㴓¦ŒYV ÛÄ\pb¯µ¡ðɆ
ÙV@ý¿Ì5ÂÒgÈ⣻³VAa®ú¸˜ç0Ìu½»@Ðf̺7}éÎU€Mg¿!%|±üiÞå2ÞàIEND®B`‚‰PNG


IHDRnàMè¯IDATx^½”±
Ä 'b+ÁFHHH•ÿÿ­Üáä<8²S¬#Êõ3/*O‘‰@$‘À$ºJ ]÷#J$_æb
™8¢$Š”BSª”úWE•Œ™&¥1“|=_éCãê=+uðõ\¥ªç”/‹IÑb,lìÆib'»±±øÅ‰L¡UÊJ£…¬ãÿùíۗâëQFÕS¥ž"T»š®â2ˆW˜ç%øOlÛ?£IEND®B`‚‰PNG


IHDRnàMè7IDATx^ÍԿNÂPÆáßi-mBø7t²3š0‘8Td—I.Êè.wá¬wÀÄ̘ô˜àˉ_
QâÆûNïð§=9ȿ{¹äaÎì2ÁÃÿ¼ÅwŒÛÞ1Q.‡;K„ïˆO´³Ë!¡¢"
棕¡Aő

‘ÜÎGŠŠ(Èm*"ÄDŽDÄ"©Ø\À°y*|“M¢¢M:"”@	 §¡„Á"uà·:´H	0`ßÓM6>Cîe“}Ü:B<›¬ò:‰«|6!v„€:ÉËô€DÐç¦hŸ8ðüHBãŽO‹î‰Ð#áºhBOd¼OSº´ÜñAP´¶§ymŽ(šM¶YùWn³×JµßÆå³ßmJU©•¯%5ª
„ãxø\ácÜ6n{üsf_îsñЫ֞ܗÈIEND®B`‚‰PNG


IHDRnàMè°IDATx^Ó=kQÅñÿÎÍÞ\–I6«.³;!
‰ ˆÄBÐÂFŒˆ…J¢À^°HÀ/ ~-ì´VÔÆJßA|©YÈë›=rafôœb`¸?žæBЊ¶ÍAà6Wp$ÒÂá	¦GÁa2þy‰i‹GP%Ϝ´;þxÅ"Àӓ0•èáúÒù
Y$e"!#	C	‹J’EIò’ädHL±è¦ôéjDÿžRGûžFbQ—¡*!³¤†^¯1à(˜.ºÌ"=¼!U´5~yƒCò¢=Β:Š“ºtjw̒ƒBÌîñîÅcØX²®§t\û£ìg8Å1晡Ý@"Øú>Þ=,ôB¯î°HNŸ9B9EE)ïغ¶¿]¾öùÉ=¡Uí¼g@ZlŸ@¤½¯«+œ¼»ökâ5¥zv‘Pþ©u2͡ý/·Îr„œ¥ћ›B=&%i"mf7NЧKJöüö=Ôޟߏ˜Å5‡§C ñÂÒæÛw÷¯Ÿcž´™´Hp$ñIàqEºøæÅl”:˜ïÑHʉί‘¿¦–»˜±Ó³IEND®B`‚‰PNG


IHDRÄé…cíIDATx^µ–ßKSaÇ;g¹årþH›#‘5”˜Њ.’„¢AWA8ªm×"ô/¨àE‘nº궼½±›åüA,ñκ´å<ÝÄùô|áåeÙ9ǣÑ^Þ¼Ÿó<Ï;Ø"²…³=£ýSJäÅƙN§¯¬®®Þň¹XWþI¡25ÙlöV¹\Noh4÷mŽ0òü3ֱϨ§‘‚L&Ñ˺žœŒSËP55b$̱>??[ˆ”ÓHL]©TÊ$&_âr@ŒëØÇ9œ—‚„sbb"”ÿ•G†¬cçpގD©BeÜSSSÑt.
D؟™™yĒZ‰|=µÌæ¦HÿFÔN&###a|”•D‚O¡PˆÚÛÛqè§Ïç#¿ßOºYOâ_ÐÎÎδYe¢0.æ²Çã¡ÃÃC<M‚ãææ&õõõÑVq‹Œ^—¶§퍏?fA‹AOd‰ xȼjhhµŽD"tpp@š¦Qoo/­¬¬à‹i][G0R¡Pø:::ú„—L^—ìÁûÎÎNŠF£T-FV´¿¿OÉd’ÖÖÖhyy™¸G4==M===¸è9*À4þõ;Y8™¤ë:!ÆÆÆ*t$*•
DÈ¥£T*!…ÃaHbL«¸Kþâ¥Ddq/H	úaXGéУÝÝ]ÚÞÞ&·Û]aÁu¦a(ñ3âñ8Ù
Q.d™‹âÅL‚›™nUUóKKK¶E¼a¼âáÈ0jüyñ2^Çb1ے`0ÉSæSc%Qp@»\®R.—;V°¸¸Á&ÈxÕJԪlÞ%‰c%ƒƒƒ¼eü²ÖÙdÓåp8򳳳¦‚b±H^¯¯ê¾A©Ì$27ÓÆ<c¾3dA
™‹
¨6%²7õ¢lW™Ó}„.æ`šD» 
QxÖ>Qó¶*0oã’Yœ@òÇ?æœ	¸ü¬(f’ÿÎowÏ=O*Ó@IEND®B`‚‰PNG


IHDRÄé…c…IDATxc Œ‚QðÿÿÿšÛ1¤-ab ®YµÊg¢¦E@\
Ä KúúúCùEԲÈj 1ÿ_µjÕL(»$Oq*
Èå ƒ¡†ÿ‡±Aâ y:&ÙØ§ 
˜Á¯¢KœÐ%uÑ<Ÿíb…aЀQ0
“7c$¤j“\IEND®B`‚‰PNG


IHDRnàMèøIDATx^•Ô=hqÇñïÝårIZª&ÍÅ&
hM}ÃB‰‹
qt*)‚ƒ “8«“ Hq¨"8º¨´â¤8ˆ[!“â"Ep¨ƒø%µjúòŽ<K’ú{ٞwÿÿÚuÅÅéTO3îPe’$ž±8ââ“ç Y–ÇT/	9Fš„AP¸™jçD³ªm鐼ßeñ•>N?’ L´Wµ¡1MK’êz$iA,‘ÁíGЉö†¤KFôIÒ3ñŠQR¸8½¤ÀǦ¤F´.éžØÄB<œn²¸ ©Ù!3Qoè¾65-®‘2bç$ÇÜEIëá«Q?¯o’.ˆ¸ꌻ$™b†QΏÆnEýNÔ/KÚQAL1hÄ%ÅÃ:-V™óÚ-Y֢>/郸Bٞ>բZÑu¡÷êÍ]ñ”ý¶‹CŠSeýQ½ÖÏ>䌸BŒx^ם¥ Í	†ðÀ^lã<×JY˔ÈàqIr˜ۅ­w}É9qƒ<I0âà‘!Ï8üæçð]é¿TÙCˆ¡4ÃT˜¯é_¹.)ÙÅ4b§3ÌÞÎjM–m=‘ÿ‹Y’8ÝÄvšàmdÅ
³èù‰v
©0A•“QMr”CqŸ˜�Š¡@ŽA|\è%†\|RVøöË0‚v]ÿ•ÒÓüÆLÝIEND®B`‚‰PNG


IHDRnàMèmIDATx^íÒ1KQÅñÿ›qf×]Ɋ‹£˪ˆšfQÄF­ÄŠVV¢…–BìíR†`aiýZ˜*ú
a"‚	ìÙ׸óöžSÿ¸ï>.zuy#¤bÚê&ƒ|bæ™&Ç(B|Ìÿ‰G̏š†Åm¢²øÉ(U<L61DTójê¯jjeH}*‰3òX–&Ÿˆeö{Ôʬ%+j¨©ªøÍ^ŠØ¾OhU–è“%»nèZÃb‘óD!K㺗tؐ“cIsb8Mb*–4õ<ÿÔÕ`œœKN¶•SqŠ;%¤—)¯~™I>Š#JDîú9Ê|ÞÊ$#b"ûÉEf¢‡_rs!n!ï~2xvη¹Ù_Iˆ1.1„™ôëç)p§RƒöY¸<º`“?(Õ/”ÉáeC@2cԘ–IÞSá!æ¥K覗~lú(Øû"›€Á'¤³­î񿺏F\¸QŠÂ/IEND®B`‚‰PNG


IHDRnàMè©IDATx^Ò=kQÅá߽³3³³“Ýhb–̺DbwƒQ,TÐ"Z¥QÁB,´°²³Õ*¢Xù´°Dý‚/˜€us$s1¹™Hâ9õýþhÇý?âÅ`	ÙE‹–r*ˆ%æq}¬p‡»25¢ú¬è7{¨m‡Ôéj-£b†xkbH诓>	fkÒ`°Næé`ÊÄ_+eöÉÔ¯9À4!S$†€„ÜæŒ#Çr¸_j‹—4óI@Êó£º"»ìȉœ,h¨UM‹OÜ#ÆnCÄÂ!­HZ”#÷sr#‡—ôA3bž³ANwV—´–k*晤“â<‰OêLòäœþHú¦r~©1d–Ô'cxsWÕy!޳×,
2NÙåw•ä¦X¤M¼yäM¦xpµ’ôÄEÆ}âVçxüóc	¼Kôhú#»XRº<½^"·Ä#2L‘¸æ‚/¯äç»ÚCκo‰¡Ãe¾"¿<¤KŠ­"†]æˆ+sd»‰0U,!#Œ3IF'oÆ-w_ÕÄÝtDÝkL­xü;î_øšĤðŸ8IEND®B`‚‰PNG


IHDRnàMè=IDATx^uÒMHTaÇá߽w3Î8S“:~ôadTÐ&*hZVPbµª]›¨E›ˆ‚”¤E‹Š EíŠhUHáFŠÀ̅AԴJ†­qMï¿t@/w˜ÿY¼›÷á!0–Jø«r˜XÓX˜A"00±qãÂÄB¸^áG'a?ÀÄޑøwÂ+,dfú;#Xj¥|áÓQ?ÀzÛæ¯«M®¶kH¹\L.)i`“œ=¥“º¦5iaŠ8¡ið!?:ï)7¾8JUòæHá”HZ"€‹o|r67ö@–z45LŠð*	 \Rï.
ÊÐEýÉÞ8H;@JhìX		l™{ýڠùü¹C4Áò‘r$Q›¹/IÅI6“ÀƐ Â&™}٣Mêæ^"˜"H‚(üŸ¼¸¢´²ÞÀ.ª0‚¤EHÜjÏO,ä'î²·Œ”£‘.4ÐÊZˆc‹2²FèŽV³X?B
I’ÄVVï'½z*æêÚÙÍNÚh$†‹ƒ]ºãéÕÌ÷B¾EhPo.³‰4)jq±0ðeåÆzõëÛá®ÏÏú…ºõû#õDqq°0¡œÔK³_»;ØqõøOÏQH½:€‹á»jT*„Y[ürfëIӚ{Z¨O¹§D1+›Xß6RĉR÷ú¨iv.û˜V%báP‹½„›[§?ŒÜ>±F¢•‰‰…¹üº$i^1ŽSy0,\¢ÔP½ü˭LJ-ÿ÷ ù’
¡²Æ.rÌIEND®B`‚‰PNG


IHDRÄé…cÐIDATxÚì•A
Â0E3Y¸­Ppë	¼‚ôJnô
½A—
¡ÉViãÿeY±Q30ÌLó˜$üHŒÑ|ڬù‚e!˜ÔÇçæKLÒXk
ü?ÃÐ1j=„išÌ8Ž䧶mwŒ¬¹þŠIîâEdŽhØëT
ò@8ò­iˆ‚"ˆ Jro?ðº*¤B*ä!*!Qæ¾Í<…&Åõ‘5׹¿XêÙ]?§;üìœÛàO¹"ßÃWTdI¥úMˆÏü~Œõ"H}©=ߗ( !kíIEND®B`‚‰PNG


IHDRnàMèEIDATx^…бŠÂ@àß.`‘ÖøÚX¨ÍmŒâ4g›W¹{G°s×Xî-ã0xó7Ëÿ\ õ	þ!"¨ëúº†Bôž0ˆϹ5֜sȘÀic¬vÚ{Ú’D‚ßÂòI"@‚ÈJฉzÂÀZׁaŒy"&´X`9,±p¢ *y2ÃüEæ˜9± vF¾€ºhïC袡0âoý¸mÿ%…{Ü~rÄD¶åÝ
#p·m‰´'
	²¦òˆVXá7Ã’¾XäåӚ]‰/Fï­u…)ÆÏõÝ5UgBÅ:ãã®3…Xº3_ŸÂ(ƒã&Œ¦tˆו®I$"P ‰8Dg{‚Ф-Û‚P‚Ô'aÀ	O…ØGy˜?$3Bç¸GIEND®B`‚‰PNG


IHDRnàMè[IDATx^ÍԱJÃPÆñrIri¡´Ғ´d©f*¨¨‹¾€uÑgPñ	tÚWp(®îâìØե«J±øjlʱÆJBCný¾õþ¸çžá"ÿ˜b °pЉÚ(Œlb>øÓGY•M…nk2ì$f¡‚sšÚé^8ê$‰‹Î{‹E™æÝÅD‚˜4ÒÄÀ|õ01Åû£ðý@µ¢°§}…3h¾ý€¶Œ¥“I,J"_Ͻ€â ÎÁûÇÍåÛkç‡ÔÓġ*ҕÉppƒ«3¶÷Ñ^šh<fh,àú˜ŸæñîdH'Mêé MV(R¦ÖmQÂJ“†s4–ÛVpPXh
بl÷ùr¾Iõ»~&F.!ZD/ÀJ$M\YÈ×SßÇÌ&6VÙ`'ê6ë¸PÙD¡©à҈ZǣJ	“yÒÄ@a£u°P1YúïâŽb"IEND®B`‚‰PNG


IHDRnàMèDIDATx^¥Ò1nÂ0à߄”HUh;0!°1°u¥* S9TU[Tê-¨¸C»0MØpŸÚð$«/©ÚúŸüGŸl=ö×)ÜR}Åéêð·ãí>?­õÌh£×3´‰„Áj®ÍÔN­6«9#0xM†‹d≄¯äLôž‘D¼Íä¤m¹@9¯“ÞLà}'
>BDà£3HvjCøPÂ)p…b™iס6N¡b×è1éÑ. փª{Ê“÷#ÿ¿¼÷»ÓNòîm$¹‰ð%=îç){Ü?§є‡|‰nžšƒBçºôūøapƒþrq0i	f¹@ŸZù‡±.úä!;¨Ѕ~z`€JÂ(γ<C̠š0j£Ci3	‡|´(>q^õPe ‘/ËÔvD§rIEND®B`‚‰PNG


IHDRnàMèYIDATx^ÍԱJÃ`Åñÿ—$-”*-ik—j¦‚Šºøm}†
>®Bó
ÅÕ]wÇnNºÅw°­A®i RêÖ{æßpÎp‘gÝ	
ƒIÄÅF£b@†hŒ¤îwü¸…•O6$Q` ߯A›:Ÿ<I€Ù{ÿ˜*kiÄė¹Ü_ТŒZìғéäá”"Z@a}԰P9d séFhöùÔÁEcš¿ct–Ô%Ÿ·W“iŒž»‡þϋ%ì,©IXú¤ÃÁõy…ˉÜ4q©|¿†+µhâßô'Ó^„æRä‰M)hS¥L‘MZ1ò…ˆPύCƒÆ
‘w9_€˜4²Da¡±P/^ì½ÂR‚c졿(ÍÊÄ5ÃYS‡·Œh
xøìrÈQ”=¶ÙÀɐ8X8”¨P£N#ŠƒÎ'
‹IÄA£Öþ]üŠ„EöIEND®B`‚‰PNG


IHDRÄé…c9IDATx^µ“]HSa€;gÙt9—Vs‰1Ãáï͜d7Òՠ‹/¼ŠPÁڕÂP‚ ^™?yvD†ᕻÐy¡cñB6m77Ûy{ßÃËa¸u<½ðpø¾};Ïûó+ 	Žbû"æ!œ¹¬„_X2??o>88x‹ÅÜ��«¦}þ“„¥‘Hdè,N„!8=
ô¤õÑÑÑ0ýN¢ËHÁþþþp"€å†XikƒÞ^zÊkÚ…BŠè2’’±±±»g§§ÇËMMð¹´Â߿ƒ$I¿Óéttg|pŸ*:öx<µt^h)ÏCKK”¹„éKe¥,Âê|$¢ŠB߾ItŽÎk‘yèc0|œš‚¾>¹°H^oôôÀϙ	ÏyPR®"Q^Z†<Dî“q,,,¼¢J~8€™ǨYTU%‹Vìv‰~÷ù|/PR¡&YàµÛíP__O‡~Y,hll„x4š[ÆçÎĤR©W$ψö³©T²»»»U­Ñ#÷ŒF#µ2™ Œ^ápFGGAív­¯¯¿A¥p&Ü"<A^šL&à€ÎÎNÈf³ÇÁétÂÞÞdNN ï;¡uÒëõ¾¥S‘ۥÌàSKKtuuA¾d¯g.—£9Ààà ìîî‚ßï¼Ұ¹¹	.—êêê†PЀÜ*øN¸ŠkÈãææf8Á)fggsp.XDɭ›œœ”…”­©ædù‹ϓðN«ժHh"jÍ(™LB4ƒPCArƒ»BQTrù:00Z‚’ áêê*eêGj9Y¡¨„ÛuiEñp{{´†Ûí&É{ÄÌG‰bƒ¿Îټëïï×,±Ùl$y†T!%jðÁz½þ¿æ[[[$ˆ!6ĈˆjB̫æ#]Ջbdd„$xž<5	φ«qètºõµµ¿
‰˜ÍfºUεJM¢Tc@j^$‚€
ÓH-w@Ô(QfSÁnBìHû9H+bE*¹‚&	#²¨œ¯µ…{^“­os2z¥
í¥"gXZ~ùU*’ÿËÓZY̨ÙÜ2IEND®B`‚‰PNG


IHDRnàMèVIDATx^һJCA€áÿä$'‡p’ˆr#
¦PD°ÓÂFŒˆ…J´´óì¾€øiì´VÄ^o… ^*Q“›Œ›H„Œd¦Xöcf˜E°š)hÉߛ€»œÃÆ×?ñã6joKñõKD*µ»•H!.1‘yi$)‚‚4’AE:ёN:è~µéDE:Q‘NT¤éDGÿ’!A¥­¿gc©dONȄÔKñf˜fœ4a1àó¥Vä\.v#EŒÜÞU’bÀ×óòÚÃñ¾ yù¾!‡‹ƒÝ{–„Hõ)Ÿcjwý½áˆ_^åtKÛKáúãÖ,£¤Ȗ.7)HéO_e€Ha’Q<âg۷R”êÏG‘¶FlB¸†œɖ¯®6æHãéÄÂ×Ҝ¸’iµÅÑë0¡&":iWl×z‘_¼™ñž9ȝóIEND®B`‚‰PNG


IHDR@þ‹ÀèœIDATx^í}hdWÆ/ÀB X†¦M»Ým·Ý6íö
ÂÂÚht붵[kƒÕԵ©ÑÑÑѩÑÔÕÅmWWW«kG£‘±SӎMMnýXݺ²°®ϓž—.37÷¼w%´½<å—÷㜹ï{Ï=÷Ļâý3Ô-@-¨ 4ä9ªՠ	¨ŸŒB»Œý,™w©%J”hÚƒ€ŠÐåõz;”‡Ðߡý
ÿiò¡5è¨ßMXµLJšÐxD>#þoկLÄøéÿ"YÊÄR$1ÿӦæ]°üϓwÌ?ù‹æçih0Ÿ†¦³fì/:øŸ6±6
».öóGæ’QÃÄ4qü%~ßÄ_7öÈDPÎ0¾ÑR§øC'ò•ø¦ëç_÷ïzꂿ7ÿgÿÆɅµ‘CÏq˜Ì)¨uãäKø=ËþîOTý«ƿU2Ÿ{:wÍýߧ}ÿêûNÎ(xjÖ$£u‘Qhº'`?Q¢D‰ºLá©(oôºMáh:á_ûÑݣà' իƿíóš;úÙW§p½vñò¯úÐqÿÆOýfãšû—ÿqlç‘3Qí3þuúOû·Îúw}í¿þ¥7›7<öBȳF°VHíÙø{¿°²~ÝÇç"åïêûžÿ…—úµŠÿë	©UAkŒŸþïýâ_ÈRŒeã3ðÓ!ù˓gþoøä‹5üKü§Oäô5jþÉSü™¿säÃß)‘Ÿ?ÏÀ~sOûŒEüãé›Ož±Òg²w>õ±ÏÜ;ðÔ!ñŸü†ÿ_ý7E~#&̍éž:Îñ—øiŸñߚ}Ã>r¥~O]ý‘ï’!oâÿ«ÄO>¥òàì(àãÐ$“ٿ~âW	b3
ÍîÃ$líyüåy|îÒDLÞ^üçÛü§[/��çèïȳ‘š¿âޯ»òTÐßùðOçľBû ©ËÚD%J”h Û
‚֠]J~×4<ˆ"î§ Êð½ß`á`Ѿ„³×ûäÙ8 è÷ÁW íðÇÑÿÉRÐÔÓÑF”æé4íÃ&ù4•¡,ŠéföO@äÅþ<y£t¿7Ô+䗠c”U¿Î"7©ᱧÛåŸ×täï׬qâÿ¬±ß$/B޶µ‰ÿóÇÂ-¼å¿Ô?©?« _	æß⫁úIžLpü%þ`þêþø`ý*‚§ob§nØY+Ì-mT„èôuþBøjÿãœøßFc7}æ•ó&糖ÿ–ý…ÓÈUXýìÇ<*
ŽŸÔ©ßBµãÁzpÈC5xYW¼ ƒ¸™v>ôÝ\ܢð·|îOe8A&’v?öBÎJø×Jb?¢¶ƒiZöóŽ<uJºâ[¦—Ê
¾j!ìÐ%~W¥ <t€̻@‰õP1ø"äãî0¯äK,7OýžÅëV›]ù<x^|S,{w=ò37ûc³lœ¤ðdp×ìíxà.þ߀†!ÿöp7îêÿ"”#
T„f®Àâ=úäÄò¼æ{¸Yõö<^÷°rÆÝÈÿ¯ˆý4yÔò|YöP\;Ž¿åÿ24±fyhÞ(þ܋ÏznûÒ߼6u§ˆÏìñÿqӼa
\üIhò®üà1›ŸFüâ¿ä_â§øó°U¿.all~Š<>“ø³’áQ»2v!Œð‡¿=‚ùÃjȈeü«Áú}”Ímˆÿ`È2Ì?;kÙoW0ÆÅ>|¶ýÏZþ3×Eñ?¨ëù¹wGñsNÛâÿ°ÍÃNhýäœE£CVƏñÛõçpÍá殺(Ý`2<¿=XŠ«¿ֳ݉.<–µz‘ˆ†ØG'+|Wžƒ!I`·>äÚ|à"iÙwóŸÂÝGM–eÁKþ\tOß[»>ö¼øïªh
ê#³…J”(]Â÷â<ԫä}sñ>‰ǵDŠW
+Ü.|Ž<ìJñà5ÆÃöý:y,ÕGå³PËæQly­ŽÊýÇ5š×Zû¬ÂóíÂ@«xD&«=´Ç0Žö_’æ‡5ªmü̱°ù³Hÿ1~myŽÉÍO4y3ôͬÜÔÉwÈ??ãØ„hp…ïƒZh4íü³V¶³Ϲ%õó”õXq7šË`+!óGì7¬ú=hÛÀ‚÷:ÄOž
ä¢U3A¸	ñ𨲝}Æd×_æܩ~Ò>xú¯©Ÿä9¶¶ÿYϽ€Ï£l™娂¢Hc6x¨ìÈs˳AØ/	ƒn2ªÿ$Aìñ§a_â/*
@w3êøɣñ‘øµw¼g1¸
URò)hL;¼§•è0äCJ¾„ÂÂ}-ÜõõKãà 2y^Р4
”Æ>y*Çâå¸2[F±žzÈkíï@rå‹(,¼0þŒ‚Ïc«ƒä/£ñßاÿÃÒü¹ð(š|lGû¸6Òÿ§5öÉï@ó£ʿďæÃÕÿé·ü“<k[(O߸:xÍý§„Oa5iþ¯€’ü‡ð=°q€nÆÅÆÆj!öÊpÕo3>ƒ9¾nêÇhжxlV¿G#©®õK꯯¬´OÿãôiÛ\W‚æå9«‚gw_5ü²Ò~¬šDޝ‰}¥ÿµ˜ñǷ¯Ÿª “ÃOr
K•d””Ç[ªDG¡%(§äW®ô—œKì?Qñfõ‚×yÜâ¢eÜ	’¯çwÙ7öç!®\hí/@rçî¢%c¿±0:ó\½øQ̝ýÇêO,^ÆbmÐǯ?á5ù[^ÿ>nÎ_Ðø/M¿Û
o€?¥	ðp,–¦þ尟ênø¬­ÿϙúuZiÿrÕõw…€F<C£—ôükä׶ˆ/bærð«ZÿcÚ/Åäæyñº–Ç2pûïƒøFÃb¬«d„žӮÆÉã¬êşZśs¡ˆ9¥á×
_ÂwZiÿ,y~'ãð¼¦ÅáË(b*¹ãÿªÅoiþ´ãw™ü/)ùŠyÛ밆—=®(¨ÜsBæ!6ú×>ôc-ß7úäâƒÈـ’ϛú}>fý]˫ óÌw5&¿‹×à2îšâð…˜|1nüæ®em‹ò'|Kɗv>ü|œù³jaÛì»dLTò±¤îã‚4…¥xU1o
qN*ù7
ÿ’ª€›·†Š˜ÓñíëùBÜø±¤á/‰}¥ÿ-3~…˜ñÏluþ”öÏ~\9ºи‚÷°’‘IÄMà×OÌkù>¬:–ó}J>·þ
¯
`ÎÀ%%_3ü²’¯~Ek«8ö+1ý¯ɦ½-Êß|Ìñ«ÄÏÿ˱æÎ&á3\-?
]´œ‹«»¡]JvŽ{øj&VÄ4ü’9k¤†=]~ِš²­Ää—Pã5&ÏïD~A?ÏIaüJû+f9¿×¼-£çõþ7c6@ý8"e<7ß:ó²Tñ݋©¤R6¬Ô(>²~Dɟ6õwI5᠖yePµ	˜¼Y‚*ky,¡iùŒe¿ µ»­ý¬e?3¥}ß<Â,ň_ˏXþ—¶jþð­
4’ÿAhêøÖJ:aëäc9y¯OiVÃÌw©…1IkxóÁGN2
¾l!0§9ÿ†ð*ûÆÿVLÿyMPåÏðüNd|^x<ËƌH›‰?¦ÿqòNù)‡M±“à·) îãq-dÞ#JĽR¨aZþ ^£ç[sc¸n
wÜIžUð'±	IÞÈ(ö}Ô,>§۸ãÞù5xhAé¿ð
뭅¬†‡}­ÿ=PöÉ*샏ÿ6Ñʼn¿ÖÁþ(4A
~Ž\ⲁ…ݛÍ<jâ)¥<÷ƒ
S{ZæÄÔ*¾˜›Ù?…¤Xep'$o%plSŽ{Ÿ²ÂC5ÌmǽQäë¾ØÇހžü"ì÷*x‰¿®ð?cٯIþÈßÉnÅݨðMð©ñ/pþ(⾪؄»Ýò\±	¸öK`÷a%F½{
ålÿ»%â›x|kNÛqoòe.øþ^Ueñ)AN¬˜eîþgùmPƒ<î8Âø®ó2°cŸwJäˎöÓ³x2~W¾añyGû9¨Ž7äˆð‚£ý,´žñ‡_
êí°ò³LÿqÇ+ñó^†NÒV;^â—Õȶ¹Ž»@ž„Ëwð¿fñ3?mVa˜[ΑL»ñ·珝½2b‘:i?ׁ¯Ò>LÃ[xãR¬Pt˜±_ßÎ~š<ã„có5¦…Glô1݁—7ïü,Y‰cœs<ߋ¹”#÷›h"Gy‰Ÿss	þ;òÏr.Hü5æOkŸ<ìçïFg„ç9'°?¨·ÿúiðžcü%kþ
8°r>Ú8øãàûp ~œ2ï%Jç¥ay2'OŠÔ<ÜoÌ:uã”Hö0ü•æaJù3…v@«</ƒÅ_øˆ›ÓМù+ÂÏÑÿñBÓ/þϓßäзahÆh¼õ÷QNA]!Ïì'¡ªÅ7ȣP°À	Ÿjãÿ6è‹<Šà"›]£Eò\ù1Ëå•6ñ"ï>ïæÑ ÓVӲß^âæ6Ϡ!—"B[6_3þKóS%oíyèÆ#±ªÕÀþ³ó_!ñûsP—•úÂÏÄ>s½`ñóÂóѭøoæBxŽí/1w†¯Ëø“GœÓ<-ÕnáÅòŸsÅö¿*<l–ڜ³ÂïBÍâé=0þôgT˜€˜KòÒó?ա)¶ã—ü³A&/óggç_xŽ1óGû÷ØLDûäÿt(ÿ²ãžڗñ;åy2®ü$ØÐ§ÙyÁÿ“U˜DI¤”ë]‹ŠÃæ×޷ŽyÕsüSiì򯙕‹Š”ˁY8ÿ”Ï͚
~†…GV òøw¨ÿö£7›ÏC]xþ¹

ŢlÛïÆ!ZÒèµkb|,I³Ø
/…Ÿš‚<ðíâ@“¹.Íš]J§5èˆÓô±ÈY…Dìógái?…øƒöS˜3xi|¨2yÄfóô…ŸټÂûð78~vþè?³yæ\xþ.áKâÀ~7ø"¸–Ý0wäÙÙ<æD°i¥Nþ#6áǂ«ø•,û´i?ý)Ê^‹|Çücƒöá°sK?|,kÏ|ç÷XLGûàƒöùwûÂ8{üö×ìG°ߍøeþΡя̊}Œß°iIƕçc$‡7™%JôNtZ}9p£€ã2s7ŽÇß/ãƑϡ̃+BYòøwTþ0ŠâE0
Óø’ÇÊC”“¯óhDÖÁ\€h¿`ÙmžÐÄ<hÿ<óóÔO>äm#Þ}a…‚¶šdý3Ð$”ƣS/ìO
`UjÀت[ö›&ÛÁÓ~»üñ3Ɩ5±ÎۗLþ
o_=Œb®
³*¼ùlHòÂ猯5ˆcײølØüá˜`#hŽ'|3æ@þfžÿæÿvò²zÔÆòƒ°_ cXùe¨Ïڨ–ÿ2´bù¿¥Ë³ø_—ü5­Øv<pZ˜¨öéóq‡òbŸñïÃ\smB8ûhͬê@<p§ØǣP¢D‰þâ÷ϣ)Ǔ¾IEND®B`‚‰PNG


IHDRÄé…c›IDATxÚì”I€ E�l\xŽ€'p	„XۨDQƒ¢›6iÒ0üÇgD¬JD å‚!sö8Eÿ@+i¬t7N¦F.ò IƒwéÈ	÷ø£¥Òf¬s®£2În’öÒPÖÞûÅöí!ð6הí)DkmhÐÀËÌA)eŠ9á9·œ”:“Ïo×ï¯މü]ȏQ€)ý¸Vä°ÚIEND®B`‚‰PNG


IHDRnàMèÙIDATx^½ԽkSQÇñï¹÷¦Ijs1©¥
¦V(ÑIñ¨`G×qí "GÛ(hS¡¦‹…,QðÚÅAÝtÈߊ©IíR¡jÒü<Ak—òãá¹ˇ‡ËsÎAÿ$ Ÿ€ˆ-³ÐI0ca5»>ós~}¦š	0Û<ºJÃ͏54i«¦æçÒqºðÜŒ'77rŠ!l¿¡͍wÃ7	Níi,å„ökJÏm¥…E¥Ó}.bˆ•ÏÕUZ+’lO+®šÊç‰a:‰ObunV(/µ‰ʹЬVçHàw’€äڄÐ3ÑNû[׵¶@’ “DHU‹¡é¦T-’"âœòæ’ë_¾iñ‚›ø$Žf~U&…ESz¡|+-tER)G¯‹bô?È6ï岆tVõ֗ktã;öBÈ=Ñ»}Mè¾V$
Xôõ*q<ÇöÙÍcÇßÏWË‹ã/ïÖ['ÚHŸÎÅ8Î!ý’á0‡lyu»Þº£ïOèÁwždb$H’²ée™׷ꭼ–õ!Gˆ¿ý}±¡›>†]\~úöæÞÁÎ)Žà#Ešƒ¶RDñ¶wퟣ�Û}Œƒ8bððm<`G_˜ß”%×IEND®B`‚‰PNG


IHDRnàMèÜIDATx^½ÔÍKTaÇñï}љçҌ‰i2µ*ú*hÙÖ!ZE¹‰ ÂpW:åآE`ºIp“PA/ › —]-ÜLT–6c"˜ŽÃè¯!jó ´ñþ8<wóáp8Ͻ迳‹dâRgàmÔ<Â]Z_*f»#ƒÞŸú©Îê璆ÕoURõëÔ	êñÝ<§×VsJvÞÒÚêÇNCž›„göV¦sB4 —V­ÂPeúl3¡‹xÄJŠ©UsZYøöfeaÎPB%.ǫ%ÉùÑ¡¼6ŸA¡͏’$¨%!©ʼn>¡b#öŽnjq‚a-©#]ü§˰Šc¤©svyec–å-³üÔä%7±YŽeVfú…¡½RÞº&i*G“‹xÄiy”­V¶îåª:t^åõï½48öBDۃ®ß3¶}õ顿$u	2ôã:	|ÇöÙCÛÁãO{>ÏLõ¼¾_ÖɿH_ÎÃsÜ1"Zh'Ã[}{·lÝ[ÿõŒFçM&N’iKûɼ»SV^³*Ü "Øù{±Ð@3O.Ï>ÿp{_{mGÇIÓÊ!«41ümÄ|b4YÅÀAñŒØÕ?Ì|Ì|liSIEND®B`‚‰PNG


IHDRµú7êˆIDATxڽ‘±
Ã0Deñ Ü_ÉP<h5:–üÿ‡´2EÕҥ/ï]mz|9?èDõŒžߖyaÜqPÿP—΍‚jxgå’* ¬ëՔa©DEV7ÇY¨·uã,ø´·Ð !Þg7“æÉ×<&Ž-¤ù¡z4CH=ÿ᳞ÒÆEQPŠIEND®B`‚‰PNG


IHDRµú7ê©IDATx^¥‘1
„0EÿQ<E®±é]ÅFt½A°±´˜:g°³ÙSˆ…×ÉF÷Á.,C Ã<fÞ$p7ñ38åOœåç[Q	3
ÞªÜ%¼bÆàTС(1@`ëÌßL°FŸˆT9,zF¶}„Dêì@ÂrpÌA‡Îè@óå M¯¹bÚg
A¿ë^ל©–4éW7Z““©Ëìþ©ÿÿÍ‹ƒí;k.J²IEND®B`‚‰PNG


IHDRµú7êFIDATxc #¸8íU&Œý*óâ4éõÓ@J Ò\!x¨äUæM¸b4%7ÁJÀ$\S	Bš°‚Vt$Ao
(ú–pay
ܫðIEND®B`‚‰PNG


IHDRµú7êBIDATxcøORMƒÃ †(UÁ0´ƒIƒ š	0%Š„>„Y¨
 JҤ+4‚#	{“Ȁ¢Cdô°ÈmÁəBIEND®B`‚‰PNG


IHDR

';6,IDATxc`hB€ðè?\ÁC0,!„†ÄԎiV'au<Ü
!ñ­âJIEND®B`‚‰PNG


IHDRµAåZRIDATx^¥Ïa
À @aoà]ß
'è¥Z¬HmâýüDTÚOÇHÁP¤§%ãE#Ð^аŒŠ?c(ãäAȊñ“߭µ÷ _ª镚péož¢lñ¶'IEND®B`‚‰PNG


IHDRµAåZIDATx^…A‚@E{ä&CÉx	<É;&Ï ^d@蜴b7æíúÚä÷FAÏȒè(ljª%±9&Z•ªVž•¬…
ѮID½.…NGG„@Ê„¨³^lŸJu°%•£°°9ýQÊÓËð#ïÂàT rúºŠß@•Tê+µ…Ú^ùSB†³WÌVŸ/þƋÎ{ñoǙÍN8-ð›IEND®B`‚‰PNG


IHDRµAåZœIDATx^}A
ƒ@EsëAŒ 0½„=‘W¬½Èh»°]h5	]”·ËKBò…Œ–ži¥£!۫ª¨I,ށZ¥ªY…g޴pb`¡"Út"Rét.4Z:#ÒJ@ˆZk…ÎúÕaoRÙ‹Ӧ”·—áG>µ¶°púnƒ
P®¯”þJ{åF¯->üƒ/n\±à¿ÑМN»ޚIEND®B`‚‰PNG


IHDRµú7ê–IDATx^•ËˊÂ@…ÁBtHKƒ¢@ x]húÿw›4¤™ßÙÖñ]k­û1‰ϮU{³0:9eÙqùž…› yȒÒ$܄K!Ù`-ŒV.2	h…9°ÎT¤+ÀF©H/l®²T‘·§R#{h$´Je³ÁÁ^ï%üªJîâ³gy×H§³õMû㣯|AIEND®B`‚‰PNG


IHDRµú7ê¬IDATx^•͡‹BAÀᯜEä‚,šžõTL®ٌÚ,>b¾C\}ó§_9,~S3ã=}‰—>tB­¤æËÍÓÞÊÚN–-ëí›pÒ$#ÅÁÓI8–dèîÐ×Ùë9VÉVH@#¬ðQ%aL„5TW¦Â;êÄF´²åQë×U‘dÒ´B§Q°ôp·µ0µñ£ó­fä,þçªñR237öŽ?dw$‹uÐÊIEND®B`‚‰PNG


IHDRµú7êºIDATx•Í!na€Ñg‹F`ê¬ øm8CÛ
O‚ë	8W œ
(Ã!Zƒ B–©!²̾±ßÌh¦-7ÔñһR{=5Ÿ.îÖfæV
…iuû"´™“›¾dãî lSÒuuh+­µl+ÉRȀa†·J2FÀP˜Cåʷ0:VԒ…0Ø+díü9Kz
'ݔì„RŽdêæjiâ˯ҏš¾£xÎYî¥ÌÈØ@ÿ#[Hvæ²aˆIEND®B`‚‰PNG


IHDRµú7ê2IDATxc DýG‚
X )}ՀWA„’„02¢§DW€FªLHd<lïCSç9IEND®B`‚‰PNG


IHDR  Ùs²EIDATx^íÌÑ	 ÄÐÎé4·¹PJ@)
^òÿâ­Æ,Ö.	JT'€€  €`€ Ý@¿à€Û-×4	×dM JIEND®B`‚‰PNG


IHDR@@`¹UpIDATx^íÎÁ
€ À@æt6×	Œ!÷@’¶Üx«êºŸ@,Cç€0‰à€1à$8	@‚à$8	@‚€à€ïÀN @€ @€üßT=Í"ºÉxH!IEND®B`‚‰PNG


IHDRÔôUœIDATxc 
£ ¾¶‡ˆ+€øÿÑP>+µ-â⃠K øŒ
碦e=Pƒ÷±TLćŠ÷RӲ×PC¥Ðĥ ⯩f,ÈðËQn‰6_FCÕiSbÙ5A$àk)j‡®e@~+Ñô°ì'Tü3½|ö…Ÿ&K$æ³딖 Wˆ´è
¸`ŒZàYgIEND®B`‚‰PNG


IHDRÔôUœIDATxc 
£ §o>+Wñ þ¢¡|Vj[ÄÄA–@ñ*ÎEMËz ïb5¨˜ˆ復e¯¡†J¡‰KAÅ_SÍ2XᗣÜm ¾2Œ†ªӦIJk ƒHÀ×(>RÔ]ˀüV þ¢éaÙO¨øgzùì)>M —HÌg×)-A®iÑp	2$À(™‹-¦
´'IEND®B`‚‰PNG


IHDRÔôUœIDATxc 
£ 8·Šˆ+€øÿÑP>+µ-â⃠K øŒ
碦e=Pƒ÷±TLćŠ÷RӲ×PC¥Ðĥ ⯩f,ÈðËQn‰6_FCÕiSbÙ5A$àk)j‡®e@~+Ñô°ì'Tü3½|ö…Ÿ&K$æ³딖 Wˆ´è
¸`Œ“"­{hIEND®B`‚‰PNG


IHDRÔôUœIDATxc 
£àïA&V ®â;@üDCù¬Զˆˆ‚,â?06Tœ‹š–õ@
ÞÄjP1
*ÞKMË^C
•B—‚Š¿¦še° Ã/G¹%Ú@|d!U§M‰e×@‘€¯Q|¤¨º–ù­@üDÓòŸPñÏôòÙR|6š@.‘˜ϮSZ‚\!Ң+àdH€Q0
5@cË͊äIEND®B`‚‰PNG


IHDRÔôUœIDATxc 
£à÷eV ®â;@üDCù¬Զˆˆ‚,â?06Tœ‹š–õ@
ÞÄjP1
*ÞKMË^C
•B—‚Š¿¦še° Ã/G¹%Ú@|d!U§M‰e×@‘€¯Q|¤¨º–ù­@üDÓòŸPñÏôòÙR|6š@.‘˜ϮSZ‚\!Ң+àdH€Q0
P¹7ڃÑIEND®B`‚‰PNG


IHDRÔôUœIDATxc 
£àý.V ®â;@üDCù¬Զˆˆ‚,â?06Tœ‹š–õ@
ÞÄjP1
*ÞKMË^C
•B—‚Š¿¦še° Ã/G¹%Ú@|d!U§M‰e×@‘€¯Q|¤¨º–ù­@üDÓòŸPñÏôòÙR|6š@.‘˜ϮSZ‚\!Ң+àdH€Q0
=tBÊÜÕö;IEND®B`‚‰PNG


IHDR'Ý<Þ§IDATx^•ԱKUaÀá÷x¯aå¢!C2)(hn¬ ªÁÁý4U 5˜!Ys•ƒs:8AC”¦6µTFf_K\Î9œƒÈo:ž÷;>ÞP¬ۨg_løౚ(VD£Ö̺ªþĐ3Â	ӚU츰OS³۔o.(25“–í•óÆÞ"»ãµn±iÍ,ëòR=:ŒY‘¬ӑco
·Y¡Nó’ä¯$™יaG­ê!L:c’9…~s’{"Ӕ"4üԓc«’>!„>ÉjŽõá²"W’ŠO…¶…ÛZ2`A*fÁ@ó4ä[’J[ʰAKáTÅV¿Ýe#¤-³šÏaC£”[7^5,¼3XÊþHÖKY·CášþŠÓ~UœvÅó[þ·Y—Bx¨w¬iMWÜo³÷RiËm֫%BØã«Ãí[²X‚۷¤+»ZnŠÍS·ìd~—lWß5¼rWäٰEufÜ*Û\#¾›ÖQº¹ÎU{²麰_ˀÿÉE3~˜PyVìˆ'>ù-9+Ü0¢!òýê  n‚',‹IEND®B`‚‰PNG


IHDR'Ý<Þ¥IDATx^•ԱKUQÀñŸ„A>
+Ÿ
A’IAAscQ
>È(褩©Áɚƒ¨„èpp>Ð¥i„M-•‚Ái‘Çáp"ßé^øüνpÎ	eÝF½pHøjÃGOµ‰²Z3ëºÚæˆ!ç„S¦Õ[±“ÂuQf¯)ß]R2m&-Û-ZvÂ[ûKvÝbËê9ëôZ-íƬHVŒiϙw†›¬¨ü$ù'Iæudì¸U½"„IgsfB2ç°ÐoNò@dMy$B—_zrfUÒ'„Ð'Y͙C"\õJäIRùT´#ÜÕÈȀ©̂]𼜳$U¶”±AKáLõ¶~k¶ÍÚ|	º*ٸu㭆…÷+Ù_Éz%ëv$ÜÐ_½šßի¹æeˆmÿ۬+!<ֻ
V·¦3„'6Ù©²å&ëÕ!ìóÍÑæ.Y¬@‹Í]ҙŸ·†ÛbëÔ,;-?ovªmº¼q_șaŸŠ֙qG”,ŒøaZ{åÍuQ䧼¼`n
5صI.›ñӄ6Q°¢cžùìä¼pˈ®rýÿ@Ùbp`IEND®B`‚‰PNG


IHDR'Ý<Þ¦IDATx^•ÓMKTQÀáÿ8ch9B´L

Z·¬ ª…2
ú´ª@ja†dÏ:ˆʅ}.‚ E”¦¶jS!˜A œÉpïåN"¿Õ9ðœ8'ë4♃Âë>x¬"ŠшU3®©n.1è¬pҔz+vBد.Šé6雋ŠLń%»Eˎ{c_‘ÝõZ§زz–ux©šmF-K–j˱·†š¬P»9I²!Iæ´gØ1+zþ±	grl\2ëÐgVr_dšôP„šŸºrlEһ9ꕬäX—A®x!r%©8*´#ÜÑȐ~óR1óú3輧!ߢTÚb†
X§ËØzÖë!m›U|ëj¥l̚±V‹…wJÙÉZ)ët8\×W¾›_廹êyˆmßmÆåéÙ«[Õšì½TÚR“õhˆöúêHó•,” …æ+éÈþ·†[bëT-9•ÿo;U·@5¯Üy6䣁ÿ²i·E‘…aßMi+Ý.�…ºÂ
ývm’K¦ý0®"ò¬ØQO|ò[rN¸iXMäûéVK?\IEND®B`‚‰PNG


IHDR¿¾-|B„IDATxÚì\”UÞÇÏÜï0ÌpW`¯ Š¢(Š‚—ÔTòJj¦Ž¶íֶÖ^²,ݴÚÚÞl·rWÓ@±¶ݷԼÞòZY!”Š ¨™Š–7ËÀp}Þÿyæ|g†¹<ç±|—Ïg˜˷ßÿüÎïüÏáa@¨“ÔÔT´bŊŠ¢âà6
nÓà6n“—”P+ƒöQ¦èìS³CÈT(ȗ«7‹5nÃm"ÜnüêTŠÿ¨Ì`©œsÖT†•ɰŸ:u*bÖÙ¢0?"ºf±tѬÌÌL	‡5ŒsRCҬ{©«+Oº’]bžŸêD—˜Ðüšu{#“KËc
µ÷±7\é"ŲéÊ$ìÃÑ?Ïsé
gžŸðß<üEåák¥}FÝË<äc¼&fÝ]™¿dÏÇ%§¢W_^áÏG†$¦"õüC_øžf¤‘ô¼¾_*
Y¸bHÏϩWT;¨SËOSoÃëOqÀòY—¶¯•ÕãsêUý.ªP²ƒ2£ÍõùMê%f=ãL®!fu]º]Ô	`աm%ØFµ©r©s¥jâ¹ÒS¡\°°® +Ç~N­ÐcÖv+K¸jQçRW#RŸƮ?5ý¡ÌL™Zɉ®ÁPÃW€uœ¥«•f¢¶v_ê¼_Ë|cök×õ2[—`;ժ2ѬmY§	“(çÀ{Ç��Y§æŽÉ’É}׸`EJ;뎮̊dj¨èë9€XaÁüúâ.]˜uX[˜ó
½¯>è{Ç:‹ñá¨á¯Y\œ¥¤
OE3¯‚ùµ{CÊba]ày¬kºX9߭ ŠzT´ª`Íåž'гM8|“zm¡(–iÏË:a	œÝ-Zá«ÓéÂà[JÖÝÜ,óJГÿ:Ơ6*R•lj2­ʾ}hˍæ¦F·±X݀ê€%`þ¥†|–ע6¿ËS;WeWÜr£É;–#]öͷ›Qý¸Dþðñªmu‡·\kâN—ýG+ܪ


.¿¿zÕÙm[¶´UÖg]ZµjÕÅ-[¶4ÂÇϙ̌×ÏMW%/,Ênn²Y€Õt±H)–͇*žt…¸Áâ‡îäáý<—ïWWް÷üÏ%ï7Öý‡$=Â#+ô¿yè9K^_²(pæôÌî¤3
³$Sï6.sҞ‘º/ý%Hìb_ãKeˆGÚé‹h–ù›[Bݘ”@týËaèÏp—”ë>
ë’O]4¦uhæ5RݨF!
Àû¬'»£kz¢á!
®ti¢ã‘fڢ‡fþ¦³Z%»óÊߎF/”£Sð•Œo(§.Ý6,ó‰*‰n4›Eoò Šzª)…ÃD¯‚oÕøÊj‚ÖZué:°XÕ A§Ž@‹NüôΪUe>êêÀêðcˆšàñTœR]ðÏн«6ügӖ/X´7nKu#;cùËP1ìÍ?i5­Zcÿ–ë¨Õ3ÏûO_4¶¼Qce8c	€¥±²6·˜VeÝ>´åº'çX—b*Ì/ÐU-,©]4«HY¹4ˣ3AD¼(ôáE£Z¬ókdc›k–VŠT>]ë«y~æð§gùoé–ùâÁÝã`	øÐƒÓg)Ÿ4Ë۳”™gÆÈt¡C¾F¢È	KN‚®MPÃõ>œ¥ØÖéÅV½ÕÐ.8Ե©ٴ*»Š»3"K~Jr½@'?b|(¡ÇkS[®•åH—ÃE"##C¶yóæD™LÃ^LÎyyy7qeee5™ֶMÒcø}† >!¥¡	õÆÁå¯FWÔ_å¾xcEæ‡-nˆc±b™E³ÊV5fáÿÏÇ\vQ¤ù}KÂ[u4×3@ƒ®¨Žä.½¾"óYl]Xiii‚=zàÂê†MñÛd–M}äkô´Ö]]/\w_—XýXºju“]C†…1]JJJ0<Výy E=þnnùË3׷º¯«?£Ëƺn9ÒÅbIàV±{gnἙ™?VÔ{5^µÅÅÅå6]-6]zøHHH‡ùpÃ֬ÈÍÍ=	¾ìNØ;`Õ0¬[¬
9fټuÝ`±ìuãˆ0¬[À*òA—=Ëæy¥Ö��²²²š>ø yþüùƒÁÀÖÈ1«ÝŒ.G,<^…$táÚ1žç̬Üè0—èò•uÓAÚt1º$̯»Xr#ÐKÏߕ‡沣<äJ—£ñRÚՐ‹Œº'yhçy%‰<tPC¡‹<ä$£œäa¹aŸó7¡†µ„r£½·±ËCGs9ˆëñ²��ì³.g}—Ž뜷룚lÞ ”õl\硣ù¥cÍ/u›˜!ڹuó±TÖÝÉüj±Ëy¯óÐhFåK›Wþ}¬|–åãí·ý\æªgÃ,¿›W^A²Ùmðð]éhEtYñÞ·*ªÝÈC2J›’®V¹@öH+t1
	ªkj4½.Ê{-D†n®V–ç}bùËïåÍo]]˜%—¢záéâ/euGèŠöË÷fm¡ÈÎó^Í/¬Kµbó[7²Ù-ËÏÜxDp6/^­ðƧYUï>šVַWüð@žw¿†Ci]+¯PÖ«³(`©eèÄõíYU½Ҥ)ý{ø½Ü
]LJ³‚¼ôF8öÔÐƲ`–@ŒN”o˪
LJÉ
=bnšQêÒÉ)?-‹—1›jæ2ö¡¿U—m¼,ªºÆ#ÂïóŽ*e¨ðÚ֬J¿D`E÷ˆ®뇴öNfi@½>Œޛˆ¶ë¬۬”Œ®PÃ7YޠkØv6ï¨ZŽŠ®oͺÐ?M,Žê¬ÁÀZÏìÍÕ*tmޅܩŸÌ̯·¸ÇR,߼ò¦P6«õŽ7¾‚ñ:ª’¡“׶ѺÄ2ƒ•ÕÖ;!¥þÎ9ÀU؛¿xuy樥s–rH†AÿÊ濂®v–°ºñKõù¼|9ÃÒ%¦I$†±©•UiA½ðiŽ>s8’»ìÆ˙ÝÙ/gNΐ¦¾½ùáß/ûÕv‡¥:ŸwTY[³nH“ˆ †À°zb–Öz¾±ìúŠ̍ž9týÏ-4öWÇÑ,ô}qžº¡"O#ol˺­é—&–zt«·²†޶ ÈZ߀µԇ³”
ã¶âÓÙ
…D†¾»	¬´7p
±‡V1º4è'æ,Å[^S®_¸QQµâ
/ú8«9|`šEÒ5L^·±°.ÍW>³l=Ûíw³?Ÿ8?&(ÚSmA)­ÝS†Ökd½)ðQŒ—ê+7Έ”J%ÊÉÉ	°X,øÒøp›QTT”`4Õ掟UUöOW†.Ι°Óò
ÚMQÂ=²¡蝠abNYRôOW‡YY_۱Dœ²à#±oêóçœô€\¯XÖtwXpŸðÍ9¡—k-ã#?§ªÐN¯Y}ÜaÁóÂày#á9ÂmþØO‹þ¡Ø˜Òásð÷ÓÓÓ٬¹˜Ïë7crò‚¥r“…/‡œ·9ð¼¾0yxÃ]]"x^¸	]˜Յ#]îÔÐ[]ì=ÏÃxÍèŒeçy_taV_Wóˉç=Ñ5ѓŒ²›Ë>—,Û\vG—ΓÜèD—Wž÷Pfõ#8¿l>ô¤†Þæs¹ž·±Fó‡\f”Ê
r‘óžfÔ\_óÐMÏó‡ó¼ÌÃé<äáDÒy¨×(Ñ'æ¨}ì£ܪ¡D®DáKr†úÒbª¥¨'ð¯çu6¿\èê×+ò…œaª–ÈDQ=¾¦J/Š_è}FuÆJ¡YÐ'+öS5aYEoôœjŒPɹÍCë<fÉ÷SµaÙEoè'{h»q›‡kˆ믘%‘r›QtՅfý°ztã67èªÉ.z3€+
t©íXº	Æ^®Xx¯ç¤gCîúÍò‹u¹_VÅ/ÍUYoënÎ;`ÕÂx½¡sUC`©¤+a¿<E±ÃòíǨb<—KŠ‹\éB2º†x._´ͯP«ÝaMÕí´|…`¯ŒvQTÏýeØ8×Ùû¬œ€¾-‡Ñ`€¹œ]ô:íyƒóù¥˜®y6gš®ã™ûnœ947ZÄÙûPuÀ]Ñ[Ÿ͙°Ӓ‡u1¬Uîͧ}[X”7Í+v2—ñ×&¥kÖQËÓóö5Å_)sGW;+Ô;VBg=Únc‰<;#ò¨RÆ$¨BžϙF—›ç64ˆù}r#m€ø³!L¨Á-nöÿª˜©þUӋ’ƒT3¹ϒ­Žì)tƒ5Æ+Îëë}•{,¬ËÏ]K¤wXYnêå)+²W‚<àšÕd«¡]:7XÁÎX°¸¶›L†g.PÛP.EE쳬w£†ó½e™L¦Ìû0Ì:Ta+îÒSL¢†v¬yðzõì‰øbõtåʇq.X=™÷—ø%²âÝdõw“5ÆӌòQ—¿5ìÁ3k&Oãå
Ë×Ü,$,Ç,_uq¤ë¿Åmnp‘Q~¦¬ÿf”‡¬mÌñg޷‰ø\î¾$gèÎzêexÜ#„óÐð|ÎPÍWTÞT>q²ò׍JRy¾8'…fÁfY—kùF3ޘ„DdÆ+òùœ!:…Y¹–<íƒÆDöᐹák°M°Žúå&˦ë¨ÿƒÆNX>÷Qv¬|­ï,wuå»Ðǁ®voh­º’¼`yëÃþž԰_Bò’õ:dɣäÙ[M‰ø±F¼œÓKþ%UÍÌå¯4öuÀršê˜‰öӋ!_P7ÕRo47Z:ÉùIy5Ԋî{-¹Nt»ڛ¾jzžޛ令བE]{Ê:[S {GN|Ôè'xvøj‡½y–ʃs…Ü#–Ÿ¥°Î²98߈sÁZ*9Hµx¨˛³ÌZF³`¼¢Ü?KãÅy”½.ÇgDø2l³Ù<¥Â×bûKϊŠŠބûoQ֏ëðõRø~‡Ó4|ªñºi†ì e0&X®tĚè+K°äÀBVÖNXl]"XÓAW£ki'º†9a­t§†‘¯›¦‚®¬KÏk|¿ãà‹e(ü5S&‹µÌKÁb
õ–…͹—)øPµB·Ÿªñٴ¼]ž°Dö,XX˜7<³·ɠRºôÆ0o½pÂÖ<¼P+•d|Ȱº0oxŠY=Ü`‰9`Íu¡kb'ºVrȺWºH³øô¡ÏeÇr§†>åk.s©«3–3]
5—Çñâ;£~	y¸’ÇÜXyŸæ¼'åkrâù^#3n֙'ãùì嗒!Ùn¾$ÚEQÊ,ó§O&—‡˜¥Üa¦¯ÜÙk1)‡dèIå!°º‹¾"6Ÿ¹ú¡ÆË%˟Å];õò8Y+ÕXçÖ.ÝÐ?RyÈè:ÏÔp7‡¬®X.tq’‡þ½AT—Ÿu¼l¬]¾±\f”½çuCÉùP”œ+Þfþ_I…ç²n˜[ó뮌RËÝëʫÍÿp–Ú´Çò©n¨۬¹!”ÈÐß>¡,§¸`µ÷QT“epêøä
ïͻÂ~Y²Ÿª}´„úæß[M½I­)ëÞ|šœ9€=ìKHJf­dtMsãÀç>Jlw–B’Ŝ¥dÊ].Έ|îÙ]™NuõêÕ ƒ8Úþ´Z-:sæÌjL@Öádž×á¯áû/áûía¯™âËÍäŸSM‘Ïå$Û‹ìÁø26`∵³d
]âeäetS—Ў%ð”þši°Ú@W3èâA
1k
ÃzX™ðïZ†µܞ%’XY¢½4«)⹜Á.j(tÁÊꌅ/K}Ã4¹ÜÊâC
٬»jˆ–Ý;M]Ë[©Çÿx‘ÚÒmIÎP'º|ö<³ˆEàŸèâEó?ÈÑر’]\±"ÖL|Bî„5Æ>4|`Íz€¥u2^£°>èz؁.®Ç+ÊK]¤j8ŠCo¸b]ä†/ã¥õp.»vók¦o¸“‡\±Œ\eÚã….Ÿ2ÊÁx±sƒˌrÅâr~¹ÊCãÏ }É(WºøÎCb5 !Q͖~\õl®|¨ŽŽÀfrӰ£Ô÷y7ÌÓ'?ÄÙ\¾ˇJCœ Xx³ìŸkΗ
îxÅeFùÇÄ	»všó`«æա†Œ®O¬Wژó¥âhM™ã@— bŸåc†U`¿1çÚ]>ëÀò#ŲÓõ-‡¬9ö}ÖîZ—€«¹Ìèb{CC*£°çm,ðüQžçŒ%‹ŠÛ<ϰT¤֯~}âж«–i]S•Êôx©9Ì(g9?¿¡\Öo´o=›¿¢Ó>jWý¡öˏ¬3
m³Ž׌Nz6{s<þA_SU‹WåH­•öç1Kîڛ's̚ïâ,…³}%û܆9KìA
>œ᳔vZ»vm cÐéF£QcUØèѣ»Á}m%%%ïØ.-Ãÿâ¯áûµp°ýsðŠþý’|i[Ð.ó~Mt¼ˆ¹”-˜aÍҥ{¿d£¥¾Ã
"­Ëˡ®áÇÛXo۱ÞvÉÊ*Yï€̄òtŽYÙ렃ñêŒõOwYøj³,’,†uXbw¼á.¥\†?*y¿…~§ùoø¹ðÆ?Ýõ¾ÿLiÉüº'o™'F÷Œ—8ðg,¸èÃããã„YI^°º{ê
;Ö;Ö®ÇË
]Y°‚¹ì‡¤Y#ìXsîS]ÞxãíŸQnÜkV°—9ÿ6<$ZÎqn´³âÖ<äa\œ•÷bÎÐ˩w›)*sáN=ŸdÏê²8g¬hE¡Ï(‹úc_¹ac…/ΏYòTv¬±‰Ü`±Æa–âUKˆÅÖ5–хY	„Yc€Õ,3°ú‘È
–7`tñźêü¹e%Ù{#ôÙöñª]}	ôlμїdn„ß/‡>ä²?ìñBÎP´—΍zÒ,fýz¸¼…š7pš1’¯ÞfѨ橷ᬏÒ)eètiIæÐd„»k¥7,¼_ž¼µ䅂:ꥆzó0’½
³7ÏÂŒ(v˜H¢âeDY﷟9pr¾A„¥¹û|Ã!ËÛñ²Ûî2TEõ¡!C† ÚÚÚlNxrûËñÇàCSñ©ڌ3³¿_ãçQp¿Ãw‹gŒR *Dû©¶Ч׌聩$Xz`Áb‹f=³f8,±•e¯+Þ+;;;€.NY0^ʃÔM`Qþ¿[“æN
m¬üã©NX};céyÆòT—æc4Ãjzú.V‚+o¸Ðå5yŽQúûsÔFýaªXék	ƒœ¹¬xÆëÖh‘ät±X¬Y³FqÏX}8f)˜÷{¹YÕЍ¹ìj¼œéŠ'ÀâZW_Y?×ù5ì>Ï
¬û:7Ö+¬kª·˜ñO|1]ë׮Ñ	ƒ"4¦{ñOÔØ\ò´FEFf¡ÀAðnóÜ‡f—¼!’“ÉÃ
k×è1K¿ËÊ
–XN&£ìuëM±œLFK/
Š„í1ïƬ쒕Y:`!`íbXsÄâ"7[1ÖëxaÏÛXoñ kÃz“c–‚åyڇ6]0¿þ‡‹ö¼>B¨Ýi>€H²lÙûC…ydÖU*kܦ’?’f19¿à\iIo†·ží~é£Ýé¼e=õ˜QwO䣏Ҏ5F„~AùÍj÷ò·ׄEÜëéao®böËê§֤õ4ӥ¿sàö‘·ã¬H+ü÷k‡	'Nœè¯V«Cá¾ڕ+W^¨¯¯ïðü×nðŸ>ƟëÓÓÓ™7„¯ñŸ¼Å÷‡â7
´‡ÝþbÓ%ÕÅÒM­Ü6z$}ü$üþDXÕVÖ̪ŠôHš•F’Õ¬ʨA³GŒŸ$`±.:a…yËR_,ÝL×0jÐ;]œ²`¼~T_ Ç5Æšî^
iÖéӧ1Kï€â‚õ	fՁ7FÔÕpdÓE`}ŒkXm/›ë:ó†]Y;6ojzÿ`iKE
ª4‹UCÎY›6m²—^:^ƒâ¾ÑšÞ»ëyoX¥¥¥eð©tРA]'Mš$c±ÎdEر¸ÖÕ¬‹Nt‘`•ñȺä!+Œ€7.òÈâ4£ÖE;†ò ‹íù:Bsّçëx΍_:ëÂ=ȨˆéM’+„tF
2(D4pRôø"å?V]E—¿NŽ58yPHðÐI1µ"eº\Žê¾~å¾Z3™<ĬÐa“bn•#åRT۴yåû­Îç2=^ÉÀ
VÈÊjܼ2«ÅÂyFÙjž:)ºڪ«ÎºZébj]) Yæ&2¬v]!VÖ(™•µÎ	+ˆ]AC;èZK€Ufóö!x~/’,\CÐÃèªk澆
lÏcoÔZ=_çÂ>ç°ÂGM˜¤ë¨–ËP…‹ùÅYÏ«Sê~†¶wûlå*Ò,fM©yí͕—*kÉÌežú(Oûù0{¯X9ÿ»‰ÖO|ôlհ_ÎV—Î[Û}4yø  	ɲäçK7·6#¤ǠY Ÿo„“b©¬ç‚*ƒÛç6a^².«¬çKìàو¢¨Þø³'N¤ڟ²M™2ÿùÜýøR2æMÅð¿7™7ÃÿÖ1߯Ç„ÇGØ£g§á7†çRŧ)üxc=›ΰŠJ­¬¹¤XáÊ…Y"`•XÜbÕùPCGº†s
tƒ°ƫªªj8þ=ÜNXøßrOXʧ³GÐ54Q§ †½°.7Yװ•K³lºF¸`պ©Ë)Kì~
½fEO˜›$ÚKµ íÔi›7H±æϝ«gþZþ)~?„ùÀJ%ZkeáK_ÇÀ-¿i¦›sÙV =‹T
³³³m,ü'Ð
$u1¬G–;5¬ã@×Ò,Öx±u
ç€ى.ƒިãÒó¤|è„5‚Ïó®‹`nÜÖè«mTŸÍԯNŸ<‘B070+uþ)êWèŠRn­ú\aˆd
›WL=Ž¶Ь½¢H¢>L[Lýšf}ZµÇ«Ž£Һ‚MUŸùÇpßG±ò0ÕȰŸVí#¡‹åÃÔØÀÒo¯ڧ‰&˂>†YA;ªö»¨!=ö†;º8ñ!ËóŸ‘ð<»†sm¬O‰ϯa™…ԓ87„›«öfá썪o¡ægqbšP®$͊æ¡g#ÑÛðٳErÐø’‡žö6\õl’½ͯæÏ
à‹ö§ìÄå?P9§ÍÔ\f¯GŒûåáøÍè&ê4sð(©½ƒrÔ\zo:Žßk‰>E«¨¨¸iʶdɒÑ2™lLaaá'·o߾
ß¿`‰ߘŽ‚n„Úà֨ÕjƒçÀãܾ}ûûì׸¹{ÃYåØÇÊÍõ¨{uJF:ÔX[[K„uk°Æ=v³jÌh’¢&Rºª÷n8­oeÕÖKF³nÑ5TŒ}^»ƒ®rŽXëìY0^´®j+«ùرc7KKK9g	nø^™ñØM`ÅB
ârÈzßû°°’V9!ÖY†…k˜5l,..&¢ëJÙùkR!ªjhE›7HÕðøÙóæuWQÂWЌ—z£ͽԨ‰”®óçÏ×âŸxÁ
¿÷1ŠÔ\.++«±g‘òƆ
j{ì1¬
¿÷^¸)RyȰjØ,R5déb‘<o`Mµ„t­sRCµEj~±<¯aù<_{<O³x΍[„rƒÍÂWZêëjË	yÞƒ>Q€þTXˆ9]ñg`åqÍúàƒÚ=_U‡Æ èA•§ŽºUVJ‘ôÆm3°àÔ%Ǿ©¿Lćµ¶Œ‚uy4~ЕGˆ՞‡t
áÚNû¦ú÷}+ՕuV]*ÐÕp™lFU0º*½Hv.C
/@:ö5G5tÚT›Ûu}CBÛ,Ï]Ov¼Ú=¯"ÄbåFÀ($®EGo?@n~ٲנ¡ָ¶Š“m–zRºjùèE­•îõøìÙÖ9É^½ͺÎzz6[ØFŠUzÕíEû|÷AñŠØÇþ÷x~‘dQ°7—Ozì'AÒXP_x…R{"aùù³*1*‡˜ˆŇ_þø›
…¢æ®_kh ßMì‰'žXšŸŸ9ù<xpøѣGgÚÏþP)7(	*3·¢ä&
uoýÀ†s–XHŒ.šÛР¦6Ô³@–ܦ«

d±jH±°ê;²¸Ð%åQ×],™œÖuÉ̽®»j¯[N³Ziot!9^ «œÓ5L¶±˜•s–Z¡¸º.4Üa'¥ë|³¢éÉR4…º…úþ&ì¥FçHÍeÐЄϘá†ÿ*þó)o@Ð6A˜6@hâËfu8DIՐхS=ˆaQ„kˆYXWÉ2¬f¼ô«†V‡,©–…¥«]6«¡çmºøð¡žñüýTC}q
PӆtÇϜ/ ¬K
kXÂåZԥ©‰xjê[Q,ýS¥¢ˆ´®úÃ4r¤XŒՠ‹f©@×-²ž׀®hz­æ†%uÁj׬“·Ȏ—ÆÆoœ$î;ãEDËóí,à"òްyžx
+šPOÔ»Y™¢˜pn=a@áö·OJÏq€ŸœG”TÑ@PW½ÝZYÃ×ZÉSϦ㰐ºÈÞ ֺLŠÅö_=›Mâ©?$Úc߬®mϷá<„/%$Y}åï
EK¤mHÓM…
)Hí‰RE9ðjKJ2§gÔêի›¼Å½ýú³„„ÿôôô4ø׏5(Jöã;\!uº€ª+<Vƒ)­þ"9VMiA[íI`IÛYmÄta։,¢ºjN«åƒUí˜ÕBÊXM„XV]2žt3ó2^V/5¬‡RÅÇn"}§‚™_n³V¬X‘î.ë»oиË™^+¬F½ð‰>©¢âï
,¶³KüR¬‚‚tìرæ'D³—Å1¬6Y÷«.D*7V+º°çg¯«‰‡Jy/13Çê³ß[Ý@°†XGË…èw©_¡Wžþëê.¤kØÚÙ•¼½cõuÂÞ¶´AÚº¾uu%é<l¡ðʂPùÖÕ¤kH낏kÛVWžËX—šañ¡‹­«ÙÆںú&/º´®[¤óЦë:ùñ63Þ(ÿ”øüR¼Øm{'	ýSþÙê"=+qîb]ҷV­¦~ékŠ“µ’@ÊsEºïmµë{ùê7øÖÕ|z¾Ôx9Q@ÉÏ+‹נ*™ÐzÐFJWmiÕûұãé]Ñi<`øR1AZZšu򑘘(ùöÛoÿ}øðáÏáßñם=Gb@¡5jE³ÐSO=E„…‚
ˆ
3ˆQ+}
\I]ª0RE«…faó#R,i¨I»D|°äÀRDÜŐ`)Ãh/5T€.y„AÂbao tµ0ž'RCx…ƒ.«çé¹Ì1ç,ÿ®¤]ÍwjèÉ\^¾|ùawYµ´OlHúüê]ÙDoTZmœëꞐˆP¯äÀÌHÓÔf
LR>4ø&`‚™l2aXÉ<dtÙœVžjˆî‘.ºls™ƒ’““<ê²u=ý»§aÏ7rõ]ü=š²?8-œ`
i]2‘5ç§>%#¬	0^0jT|š„°.ŠÎy`é¤I	Ï/¬‹®aØÀ4yH{^ߟL
Ùs٦K›HF—Ýü¢uù'¦‰I¯_BF—®?QoٞX¯B š‡6]PC	i]°'j„nÍÒ#%t
'„ ¢g"Ðçi¨†DÏÆÎ
äEèÃ\æc­ރަÇ^”⩷¡xÒ%¼ÏuñÝë±#£(8 e~`Iëêӧ]Z lNBA˰ü{¤¨wïÞÊNϖ‚ƒå2™Œþ3’ðïüugÏé,X1D¿jÚ"Gø¯íHbcc$Xj}°J¤Ãå“þIŠta	µÁJ¤Ӈ`kˆﰈÔP¢Ñ*%Vi]ÀR‰ôúP¶.0"™ªiV]“`!`	:²$u‰õ½ѣG",¥¿V¥†ñ²z¾‚i8ˆøRi•”Ž]­B¦×áŸ;ÈEÿ´Wºˆ°*¤zåôóÚe¡W‹kè_o&5—CtZ¤×ëñ‚‚/¯ÃãE*q֔”„7\ø§(ø2b©܀ÇA—UÇÌ/%A^,›xÒ%·ÓE„¥Õjmºm,RsY£ш€'gjXÇÔPIXfÝÆÿ†ƐÉ
h€lž¯_{zë4šÛ֥÷0,Ð$m˜Õ$¢rú‡G]bcÏe̢¯´	Œéݍ .<^͐½7ð÷D½c	zƒÖ%gj(èJ†ÅÎC£KHˆÅÎ(ÛxI"{G“ž_0^t
¥‘½cHç<èºE’ÅÖ,z¼‚z"†P
™<l–b]ÐOµví݋°.ÁÚDôö·©hù«ãú\#̺¢0þú	á<lfõ6JtÑ=ÀO<¡$‡¬µRA:7H¯Ë,_ý¡Ԯ’“^Slº÷l2uuðÁþ°=yê{el]?þ8VҠdaÏÄ$üži"|҆°«ƒÿ‰²۷o;}bAAAíƍg0~UVV¶Ý̟jP¾…¾CQèø7‰¤Xæú†°¶f 	Q•Ÿ
Æ{MR¬ú††ˆ¶&dHÐ
`Áë2úè&ëq`å¸Ãjе±Ê5Jšè¡.·YõA±]íu544à÷Õ)sõ<oXâ°ØÈ†¥Q¡³xþ]æK\³$wX×5wté<`¹í
Ahl¤¹	EcSÃ`R,IÇÚXžŒ—§¬;oÑÎҥ¤½è¡7Üύ††®­ԯ¥ÕH¬ô¤rã’_l—þ„2†ø¡Ò$?t\`Í
=	V³¥/ jæ×XÅ9Ƴ4̡ÞuVn\äz.Ãë*]6±<tÀ"–‡ÌFA̗7,·Nj9pU³XúP­F­ТŠªÛ\³lºª³®!ý¦ыe
»áë%tÙX•aþè(ª@Ãk嚁H¥}™‰y¾B«BÇP9U-Õ$+›We€ÚÊjThË4ڬÆZbº*µVÖèz¹fD£]×\KÌí,Ð5t­# Ë6—«€uœa%{Àò$7Úk`eaoòžæí
ð¡•%£YY\³X5´ùpäm=¿²¸ö<ËŒ®Ѥ櫆U!ôUwŠMŒԈ÷kµˆ뵒¥«>NC÷Q	õÂugÏóÁóÖef­¼ÄG@¸ß`¯ËÁ|ö6¤z6'¬"ûJçÞ ÑG9ê‰ìõXsÙÛ>ÊW‘=‘]xp¨´ß;ð¤ë:³×#ÂbûP\ZZz%...:111$!!Axäȑ6OÀ?1 ä§¹v÷[œLÒo¶\ð?øSRRR_R¬·ÿ°°mà`ôæ{…'–蓖ô ë•K³pLs’Ij+Nžû¶ìhBjÒCÀ
&¡K5naj%B2)°ÎW–O˜5XRQMEÑÙÐ5<i2ŒYxD^ᴆê±S+¬¬“ë!`K,nu]8¼¢£®‡]ܳÆ-K‡¼QޠNjkìÂ4¬Kl­a>3^¤j8³$5íž'æ
ìÃ[ày1Ôðûo;xƒ«R€ÄRsű¾+Ëëk_D2ªaäÂ	‹ŠÐŕ»7Ê>™’šGj.OŸKg¯¸®ª¢ê셲ËP¿xRy¸p!ÍRBÌ_…œ¿„Y¤ÆX¸iR뺍Eª†Nt™ËÎjØ'>Nxª„sVuårYYlbR߆ÄáÝ~¨(8b!¡ëveŅï+kýB“” 5$)”†¸WêËJëI±ªN–í¨’·õJ®ŒIPÖ©'QC`]Ä,¤VïÄ4B,¬K…Y7O”íhhÖ`©O1“ªae!°TIϵ��	²˜ñzŽѥ]u$rװÚæމ©„kxñ®¡:éÙÖމÃà‚ިĺ€Õf/R>¤uU2º€…=¯V)oT)“×öH%2$¨[K8÷†-¯dT•­Y•šôƒ¿$ñʈ_S®BÆ'öíŸÊךBª·qÂ"¹.ãàÃêÃcoÇg¿pHèÒóÈrÖòÕG…ܬ ;Vžjx™aÝ75¬¬¬¼&^¶lYù֭[ñ¯0ϟ??Lß~ù­T*¥Ç3%%¥B¡ /ÓuðzL˜(¼ɂNjØwÀÿ<š={6}™r~~þÕ%K–Ta–žë±GgGÊètccþO/^R5çdQÃ
æ’տOû«ّkÊQmÛù¹oÿ}Ií´cí,Nu)qÔ=a!þ\¬¿ý}I͔ct
]׹b©
qB`- .äç¾ûö’ÚÀÂådñâÅA`4NYÕÑ	Fü¹ò|þN`հXdX,]U$X*Cœ¨.ÚZCõ…|“ͤX6]òóù&ÖxbÙtå¾ý6­‹œ7íž7½žŸÞÑœÍ/u4x~ôìÇl,’s³êb`¼ÄàùùŸ½õ÷%uSŽ·³Bu•KÖÚn³W*…¡;™ÿ‡OßXRuŒP&%ġ…sfGØç<‰ñb֔h†u…µ¦pž‡v¬ktqʂ¦3ڮ†Àò[üìbíü*I°
¿ÍÿiÚï–ÔôÝTôèW7ÐÈÀa󯠂#&Y`Å0¬›_._ò}ÀƢ²êfm7݌ţëßZË1‹ÖuX{—.ù^,sê<vþ؜sªËÖۀ®ò}^r6àÐeA=€õ°vè£@׭ÀòÛXt±ʂºž?<²֥ý èâíÔ=ˆ‹5^·`¼Îúcè
=°¶“˜ËØ»ÁÀ*ƒö±²HWùþeôx]ªkB=ƒ˜?º¡øH.Ç54Øj¸oíùKf†UÏ1ËVC›çµØó
¨§zÔü‰¨øÈŽuµ{jxn¤©(wNú©é™ùþ¿ýõÃ/.sçü/.¹>£°ÿúh5¥=¬•¤֯«<¬•1ök%Ã"½¯¼m·¯¼J…ué]ì—¹îٜõ6+ˆoðØG‘bñ:—ítÝfXA¿p]÷$¿ûî»+(((8q¢'EQF³Ù<ºgϞí/øá‡„ï7Pî}4ÁãG°a999áðý9p{Èh4Ê4
:sæLo¬É6VII‰5ŠKÖƍ9aðý‡Ï5P‡Í0úkýȱº<—3í¡(ÅAê¦nœ1ŒaÅ1¬‘\²Bž͙.ÜGµ)RåãÛY\èjv,J
,Ýxc¸‹S]ÁÏæÌÀ,ÕAê†]\×ða+øAc(aÖL+`Ü]¬Q×Ðƺî@×(Žue2¬ò€qœúБ.šž¿¡»›5š„ÕVoeṌ>£(´º­kŒ YÃÎI+¨§^€û&-¸;{9õü‡sBä<yØì`M	c±äl]M
æ´q=ɵòxqIŸõW©¬!Ÿ›?VDôsÈêbӵpQ&PhPàû%¯£Ý°Ӝ§äžõ(ֵj(VjP×õ%Ë1K·Ó|TIFfѺ²KV0º0KDˆeÓE³´;Íë
g³]Ë]ßdÉØãE˜%«ËV>!Öd+¼£7¸d…±YÌx½Âx>Ï6w¦³@×ˌ®o¤]{JIÕ{#³Lõ«ãæuýå!f!Ðu²´$¾žÝPÏ횞ˤ÷ì<ä‰Å˞ˆÏýW',â{Xt=Äs
岚=¯‘<zc$ãÅgFýÒóoÖäyóæÉèž3gŽô£>Ÿêrssó333Ï666"¥R‰ÿDh?ƒÁ‹:ù«eðñÔSO«¯·^e‘‘!ûøãGÃk={öhRRÒYƒ¿/…ïxɢð¥q˜RLLץsg¿”t¾²–fÉ––a}ÏKú×
O^w[¹ÀôõÙÃWŸLZÙÜЁ…kxԎ•¬OY’äŒHKѬP"¯ýó•'“þÒÒp—.Ì:ç×w6–6%#¤ù…¿2˔ݯž}éæo“^%¥X¡ÍK>þÚ,WÆD];»t½Æèb{ã(ã埒†Yõre´X?Ýaùꍻ<¬.Àú
X`½ºþ꠆œxXáŒ.ÌZ
º^w «€#Öu×0âê٥×›ô:K×\ÎeöxEaÏ?ž·p’ŽÆ+{¾^¦Œérõ첿uèCNtў</sèùqNæ—×,óóç‰Ôʨy–³Óþ33i{ù.æy™Xq£24ßä~œæ¯Tj!ç¿eå|;kçÎܼ¹33Ïݮ÷-£˜uj³¦äë‹5º¢EÍZ›[þùŸ2?miòM—³õ+aŠ1èürŠêëPhàñÜn¿šù‹Åɺ<`@ÒÙúz3
oi|!çX]=ê¢ÿŽS®a ›ü 1¤éŜcÕu¨‹î»Ü«_Íü+)V°ﰖëu‚ºBA×wk°^ãIןõRްcq©Ëװ+‡Þ`Ïåv–~<Œ—ÕóáÀZ¬ÿá`.;d®0誩Cá0¿ž¯x%óMª™³Œ
Vžº0«¶u‰=•ûûë+2ß5[8Օ¬3˜e˜h}ãß9¿~Ø]ÜÙ;mFæ\ïlºðaìú;=ÀQŽzìóËnïàËZélŸâˆÅyՉ.{¢Îj˜ÿ3×åɾ’È^Žz®öDn°8Û빩‹“þÐ>9œËn÷lԐkϳ÷D|fT>áìå|{w5à,}~Q“Éԕ9›Ÿ‡ËdþUf§Y,–ðZðI<|-´;ãš5ÜËN×LXÂNX,VG¬y°!1`L"ŚúP†pç5ËÃúT½b‡¹0hX†Ò+Ô–<9Ã?h¯e/ÚIQþ;ÍßÁæYéb¼|ҥš¡ÚceiՉ.ŸYÁ{,ûl¬àa
¬pYÊÀ=–ý«À‹³ù…YA��2À5åI׷¼ALW@ŠS]œxƒåC¬KAÊó:«ç?Ã,M®ù¸jH†¿֣6–Ÿ·ù¥ƒ¹üà1ª¨¸Ü<å!çÙ;ã/ÿ1ŋ$޳=ښ-)¶Ÿ$ã5†ÍzçcSÏ>_S—Ð~ª¹Ëë¦Éb©Ï9ŸÊbµëȔ¨Ëk¦¹Â=%=H5u}Ý4U"%³~‰äJþšiŽñºi†,[p—.©B‰º’a-pĂ×çÕõ«X™„YðŊ¸Ã⣆²XÓÄ=úӣ‚;󋫹¼	çé¹,9@5w{Ã4C%çD—ё® WMóåQ§N·Qøl§o=›V{êÔJth—)˜þWäLÁ~ž–Ó<äsÿEPׂÿgº"xô<‰}%_{ØT7Ç+Œð\&YC©½Þ=ôü(žæò=ÍCú¿ø™3gúÂæã_é`”7@|ÂfÅ\ʦ±ǰæ1¬HYó±èò…5œÑ5Ù
V¦¬Tæu\±úq2ºfŸ£¨_ÇN2ö Åʜ’!yõ{Ë3hE©¿ njÇHÕP9$#"h¯e7¾$_ó%UîËkoh‡f„kÿ‚èŠ5ϗùŰöb–ߗÔu`õqC—W,ÿ¡áÀÚÇèêŒ5Ög¼°R2º°uiù«á
7Æ+Ó†ۼYZ7YJ¹—>ÜÓîyWó˖Óþ¹ÙÔ[ ñŠ,z.‹SUúñÆ8G¬Ò3gâÿç2õ¿CÔ-ØÔÎóf#‹uuý̲uýÔZøžÙëw׃„2I@ö™5ø×Ñe©úð×Ló½aš!ji´uµ¦¡^!싍I~j–Ñkýrº¦ˆ¬¬w0tYÂ^3-ð‘å´:B1kO;k¡¬±ìtqZìR×nÞt½ÍbI겫!iֻŒ7€5”ç™ñZÅ̯úàWMÈë>*µ3Vð†3«»(*ëµúÀ.ïšzwXH,C¥gáþG8êm,?‚}¯´³ñr
ò±Ÿw—EtOÄUoã!ë~×É‹½ž§žçŠåGx_™ʓ.¾Yžä¡/ž—vÖGq<—ïEÞs–íxàxÐ\|êVTT4¬pš@_Ñϟh,øÖãƒ.7XøÀZ0tn°æqÄâK×d7t%ù «<‚õÙN“¿^C¬†]š-âç?™ÚöÓ‰œëÍ9A㿶|ŠvÐD7bÞ0
÷€•,¥;¬È^	Ҡçrf©vXÎã«_0+¶sVÖüè.K› ~>g&°.0¬ëÀJuƒ5a¹­KceÍò‚5—ÅR¸«+XJ“墺Üe	A×#Ê–2X^ÍeÌ
Á,–./|¨PºÅk°ÊX>tW×ì¼E)½§#ݹšƒ©!/Úš/¨Ñ5pÅji´ô-k£žéy„º췶h}à·YØ3Ûç×Tyì_MÅNXýFg#÷Y²ðFV´—¢³ŠֺËb<ÿ0Íʥ¨௨+ÿcŠT9ÉÞÀaâ¨ý–
øªÌҿ_´XQR7=ø\Î줃–ý×[¨Eø½Ò\­)ú¡¢ÐÅbeËàŽ.eL‚hõ†œ(ïÝYS°®H†…¯RV6°¢Ýaõ½{Mq¹V
ËEÙXV]ëÝÕÅZ¿Üêèñº[—Aêٺ<Á–]YîzÃÓÞt‰Øãžß]Ï{Éʶ÷¼Pâ6+ÂÝަƒçá¦[Wô~âtcˆ;õÆË%+Øêù
8cFGÿæxQ?_ú(Wž÷Kɐ¾uÞ2—9”ò¹gsŚúPâ²?$Ü÷zÚçi儥sS—G}T‚‡yè¤?��쉼êټÜõç`_é	kûJ¾özxžË÷sn<âã\öD—7óËӌêŸæáoözòХ®ö'Cðà?ÌbMh"@õééé2¸!‘H„z÷îàs!>I;|øp4@F1¿â2>¿ßÙÿ$Ãêጅï·=Î	k¾‡,OuÅܧ,\ÑÌe…>³ÀdŽXpÓÀ}xýt«³¥ýZ’V7Y—4Q/Æì±ìöÐد³Ÿ;`MeXAÎX}QRm™¢>Hµ ØäZŽj4&¸Éêá€èÈópSÅ,ə©˵|…ß,¿‰9fp2钊EhpZºT2ÚØG÷·Ïë¶sšâH—*&LWÈÇãõVÖ×,Vž¬vÏǧ‚.Ð$Šè’ҕ˜ð·ÿ	ØnùÆÆÒYY}¼ðÍZ“¢NLÕ
´ÖPe荴ÀÂWvuyçðþÛ,yvº¼aMš¾µèáÓ9c4ÒÃ4±	¶ƒ¬K¥oLˆ|÷ð“l–΃ææÒ5œüÇsÔ>ùgÔ͠¬¢¨þ3B“˜¦]b¨¡Ú@×P­µêzR»íN
±7`~%ˆ:a%öM@CÞ6Í¢ZñTò u38«蟘5·±4K6ÆØÛÚ\K~ÀcßÎ6õꘑþUÓ2ÙçT#Í:@ëZ­üCN°ºرTã} †¿ØÖÁóù~;»˜éX,ÕAê°ք?—3’ÍR3ÞÀ>ì0¿vj|Ìòî¯åe/耮¥,]Àz/êù;,	°đw<YÊ-–‚Ũø³Ñ͜ǬÀWM/Ê?§,ÌxUàƒD›®@†¥²ÖP©kL½þðCu
wrÞâ>a–ÌÆbt@ø°ø!¡ùE÷F~0^ƒ‡§k!S¢ØkŠ,\Ã;ºP·kTVo„“ùËDökÊHO×e–®F¦†·‚³­ž÷–ëB"”w×ú5Êöa;KuÀ:¿Ài1ƒÓl9ozué٬}ÔÍAÿ.zuÝúœ7{›yŽ×Rñ!ª€•¶RO–%è1«Û¦?–QÔï˜çzÒGyÄœHg¯O}”‡=[/k%)–£ž-ˆ–ÞÍæyXöQvÞàŠårOd—Q\°ú3,)—¹ñ3Ùë:òýWözó|dõ#‘Q.t‘ò<ŸyèÑ^ÃܘÂ#ëg“‡ú¨yÍ/©-7ðëxš‡ß4?híڵ³gÏîŸã?aÿbL3ÜjàÖPXXØҽ{wJ¥¯¦Æ{Z橷‹‹‹Ï.]ºô\nnn«;—¥¹b5666äå嵤¤¤dÖÿs|ɚíèî60h0}f±t	A—Ԟť.†ÕÊԐKV|ޕ'–½®Z¸Õ۱Hy£Ö·w±ΖŸ^ð§¥?ä}–Ûæ«…©¡3]MOCþçËâ‹Â
KWV~“[ç«.ð|=x¾<ϋ_D¿y«MR+Ð5ýOÅï5d-}»ü+ŸYíž	@gŸÄ>‰ûÐ?ڄHŒSA-F×*^ƒY78`a]{äµý©9å7•2Y_sêфwÈÊÒþXüž%kéßn}köÑ󷞻ˆÒþ¾µ0EÑ] V…Ô7¡îlèZ
ºÞñAõM=ê=öz\*C?ÖÖȺv—ˆõªà†fZ—a]øÑZCOuÍ}dv¯ËRYrŸÃèz¼–ÝT7^ª+É3kâSDÂYˆ¹	õhf2³˜ñr[—X¯¬Z´:jöº+ÙÔ¡Õñ*1º!£Ë5'ë¤]º‹%*ÌêÖ|G×u¿ËÅk`¼Þv×óø×pŸ];´yøì•Ù­‚vV¹LŒ.ÕšÝE"¨!°º·³DèºþJ»çkÝB`D-^;´f¨CÖåZÐ%ïje7º±¼qëÖ߫ÜԅYÁ\;t½¬±t°µҬ›PÃKՅÀºtª ðۇ7ÀókªÖ.ý‡ùhn•;,|ð¹xmJíÐÙË+$²q,]4ƫ¶-¬»PÃö<¤_°}¿^]<3略Å[w¸—½k
‡ÔXYã;°$¨¬æD¡Yڵ»¼\gA=E'G¡z
ÑIÈù‹žä<£kèZÁÖ5*ˆPYÔÐ/²»ˆòW…~<}ò ?:§Š7k
ÃÂÞXn7^7¤Pêc…��cÛg%î†{t¾¬_wn¸Z­ž†Îéä[Tá;3’»×Ë*¥¯k%ãùF—µ†¦áhi†?úrÿ5CAbb¢Ì×@bõ|
x~y¹@6î™^èÐ;Ñh
“¿õú
¬‹òVWÈצçÎù—8Y	óZìþ½Vú¤K¯”¡Uï­õ›>svâϬ²g}¬ï}ì[ôó\÷l]™yjßG!‚{6.ϓÒů{µ'"Ʋyƒ•÷›.›7ìç×`ý7þ?íõø`ñ‘¿è<Nð\å!‰¹ìÈó$òð.ÏÛrC¯×<b¹|Çüøøx´hÑ"]ÿþý#“““™–#kOٚÊÊÊꂂ‚+}ôÑÕ-[¶4âwæ÷ôÃÖm`]å‰ŕ.=°"€Äi–M×ýÆ⫆n{cõ‡ý´{˖æ¶fb¬š/Ë*ճ>)з}þQnå¡-ך›8g5U#]ú7è)AMåOⲂ­‡?ÚQs˜S–öáâøÃèÍ3U(L%G—Å5•%êv¶úhGš-W9b‰:Š^È-GôŸ¹¶¡6…ýˆYò˹-‡|×5p@ÿÐO5ɳV–¢gZ„È϶Ĉ(Ô*—XYši–©ÂËñêÛ'ÍXÔ�ÿïۺ%'74£žMˆa5ÝaIj+O©AWó!。ŒŽGÁ3¥ÖFõŸÕ“<˜>Àk»£K,°dµ•%J+Ëä-K,ÕÔEÛcúÏlgµ‹i	`¼ZñxIk+K嗬¬êÃÞyC
,õ´EÛýg¶Æ:ÐÅbIÊ
vç·×øÀòVctÿ‡[b“‡ЇOmȟÅj÷¡â²Õó·½dibâ‘ßÔEÃ,Ѡ+XV]lV«RŠ~K>l<øQnŁ-WP«wºg,VE×],ã
T]YúX[ÁÊêÏ>úú7miö&{™ñJ…ñ¢kh±cA¶-ê…Þ{5¼òƒ¼ü‚[¾ä<£{žÖÕî
!BvA'v'¡åð°6.ÖZ×ÔE©Øóx¼êQÏP9ª=5-��ðñ7ë—m¼ª#ûÏÄ&'†>ìë‡*˜¬çt­ÔXÇ+ýõIý…ÆôdüÚþ¤Öå}ãÑã¿]¤Oì¼àº?²­_<ô6|õØQÀÒ۱ue¹7}Ô÷nùPÅ#‹íùÿÞøï^âùuå¿Þø™‡|ïÍ5¾¬Ëÿ'Àô…ÆÕ3û˜IEND®B`‚‰PNG


IHDRÔôUŽIDATxc 
£ ôb0+Wñ þ¢¡|VZX–²Šÿ ±1­,T‡²5€x/ÔÂ^z­Բ×t‰KXpRà m ¾2Œ†ªӦIJk ƒHÀ×èDµC×2 ¿ˆ?ƒhzXö*þ™^>ûBŠÏFÈ%óÙuJK+DZt\‚	0
F8Ô*¯ß½IEND®B`‚‰PNG


IHDRÔôUŽIDATxc 
£ ña<+Wñ þ¢¡|VZX–²Šÿ ±1­,T‡²5€x/ÔÂ^z­Բ×t‰KXpRà m ¾2Œ†ªӦIJk ƒHÀ×èDµC×2 ¿ˆ?ƒhzXö*þ™^>ûBŠÏFÈ%óÙuJK+DZt\‚	0
FÅ"(WjkIEND®B`‚‰PNG


IHDRÔôUŽIDATxc 
£À÷ +Wñ þ¢¡|VZX–²Šÿ ±1­,T‡²5€x/ÔÂ^z­Բ×t‰KXpRà m ¾2Œ†ªӦIJk ƒHÀ×èDµC×2 ¿ˆ?ƒhzXö*þ™^>ûBŠÏFÈ%óÙuJK+DZt\‚	0
FŠjþ.-‹ˆÕIEND®B`‚‰PNG


IHDR¹åi,IDATx^͔¯JQGÏ]Á	&ƒ ÍfôŸbÁâƒÉ`Õ.cÁ"6ñ,öEA°¹É`’u—ù{?ùÁ–•»² >¾áwœ™1-ZL‘€ãí e”ÎÑÅýùD2‰ö÷I’ ^_ž¸¾ºMx™ªWVé=> œóˆ–ÏX^ZPµ!"ªU–î´Á3¬m…}xY¼÷8=¹TµÆ5e˜ÎW€á̃Æûð\ã|v5"{þá›y@²†Iª¡öa$¬O³¬.%R4%„2òÏY-Y•° R!ª4Èú2ª
(ûß5h0ÈâÊPY•Aèï®ÓG÷Žù¹YbæåXYç즛2!ë[mF03ì÷Е	÷ïþg_‡‰õîÞ6zûIEND®B`‚‰PNG


IHDR¹åiEIDATx^͔=KÄ@†ßًžøY]!(ZV‚à°ÓÊÖF¯´Ñö
m,-¹k[ÿ„¥•¥V–b!Eâ]4ÙqvÂBÈqˆC†g²Ïì’ì3cPa0ÀªŽvW÷m§ٺ¸îT’9ÑæÖæ—´ˆ¢Hyvrêt‚
Ý13=…øå÷7Z3ecvAçeìpp¸ƒáÆ4ˆܣ„B¨C’°¼ï·ÚÞmòÓ‚ÉQh˜@¬ÌÆ0F©	› äġB*$7A’ibka™¬û–±>X˜DŔ~©"åŸUS½DfÓ_éÈ.vÒ\&RÓU3q…Ÿ¶÷žÉm¢$=É.¿
?ÁÖV<q$`€m.Υ©ÈRþ£ãôK×çÐ#áÿÖ/[Y߯ùÕ%úˆ&˜¹}‡w›ô/î³o±yU/A²IEND®B`‚‰PNG


IHDR	=Zà/IDATxc`°døÀð_1h1\ð-ƒƒ?irU£6r8Ñ:WIEND®B`‚‰PNG


IHDRµú7ê6IDATxc DýG‚
X )}ՀWA¨:’„02+T=ò9\	¦DW€FªLHd<•ÂCmr&?IEND®B`‚‰PNG


IHDR

Øâ,÷:IDATx^­ͱ
0ÄÀ_ô„ŒA**D•ÈåFP£ÀÔ0QÔÖ+©Ը½ÄþúA±P
''pð,¤þÉÓxIEND®B`‚‰PNG


IHDR

Øâ,÷:IDATx^­ͱ
0ÄÀ_æõHŒA**D•ÈåFP£ÀÔ0QÔÖ+©Ը½ÄþúA±P
''pð˦L¢IEND®B`‚‰PNG


IHDR

Øâ,÷:IDATx^­ͱ
0ÄÀ_6ñÞŒA**D•ÈåFP£ÀÔ0QÔÖ+©Ը½ÄþúA±P
''pð¾ùá/߸ÝIEND®B`‚‰PNG


IHDR00*lPLTEuuuuuuuuuÃЬtRNS&Kn]ÄÐTIDATx^¥DZ
0˜<£\yÊ/:ä	w~ýçý¼ž¯š˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&f~Ì6³ä¸
%‡IEND®B`‚‰PNG


IHDR00ý1‘IDATxíÍ1 AÔ`=_	‚“b¤š&»~g½ýëfÏêkÄ÷”—@y”g@y”7@y”g@y”g@y”g@y”g@y”g@y	”g@yÜ9¸óq@y”g@y”g@y”g@y”g@y”g@y”g@y”g@y”g@y”7€ý~ÿµÎ*uàÞ#}IEND®B`‚‰PNG


IHDR00ý1‘IDATxíÍ1€0h‰ô|%†bPMÃË]¿³Îþºٳúñ=—ÊC <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <î2(ÿ8 <Ê3 <Ê <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê[ÀüßAh¡bä
IEND®B`‚‰PNG


IHDR00ý1‘IDATxíÍ1€0h‰ô|%†bPMÃË]¿³Îþºٳúñ=—ÊC <Ê3 <Ê3 <Ê3 <î’(ÿ8 <Ê3 <Ê3 <Ê3 <Ê3 <Ê <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê3 <Ê[Àüß¹°ÚûV5éBIEND®B`‚‰PNG


IHDR00*lPLTEuuuuuuuuuÃЬtRNS€Áõ\•TIDATx^¥DZ
0˜<£\yÊ/:ä	w~ýçý¼ž¯š˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&f~Ì6³ä¸
%‡IEND®B`‚‰PNG


IHDR00*lPLTEÿÿÿÿÿÿÿÿÿ8À;¨tRNS&Kn]ÄÐTIDATx^¥DZ
0˜<£\yÊ/:ä	w~ýçý¼ž¯š˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&f~Ì6³ä¸
%‡IEND®B`‚‰PNG


IHDR00ý1IDATxíÍ!À0h‰™ȫà_°ІôåŽ﬿înö¬¾F|Ïa@y	”g@y”g@y”g@y”g@y”g@y”g@y”g@y”g@y”gÀ3GåÇå!PžåPžåPžåPžåPžåPžåPžåPžåPøøüíȆ!I¼LIEND®B`‚‰PNG


IHDR00ý1ŒIDATxíÍ1uÁCc2O€ÇŐj›<KýÎó_÷›çþ(þñfÀå3àòpù¸|\¾.Ÿ—πËgÀå3àòpù¸|\¾._ó–À(Q£F	Œ%0J`”À(Q£F	Œ%0J`”À(Q£F	Œ%0 ýøû_I;Ä/õÿE’IEND®B`‚‰PNG


IHDR00ý1†IDATxíÍ1UPÅÀUóÌ|yWðP €*
góùö_s>¿ŸWç•Ày%p^	œWç•Ày%p^	œWóJ`”À(Q£F	Œ%0J`”À(Q£F	Œ%0J`”À(Q£F	Œ%0J`”À(Q£FD?ÿñª6˜pû©ˆIEND®B`‚‰PNG


IHDR00*lPLTEÿÿÿÿÿÿÿÿÿ8À;¨tRNS€Áõ\•TIDATx^¥DZ
0˜<£\yÊ/:ä	w~ýçý¼ž¯š˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&fÈ©‰²Gjb†쑚˜!{¤&f~Ì6³ä¸
%‡IEND®B`‚‰PNG


IHDR°º¬KþIDATx^½ձÁPÇaρT¼ŠÑÈÐÍj"łxI#£ˆ/b0x%T]ÿ“T4Mªçê=†/éÒóKšæœBmæë˜ÂHçÝá*24˜€"ºÍáúöp~„ƒb°üáüo8Ÿ“€ʩŸhÁÓ@à	v2P”!7(Å+P†¹ï@B@e
Œ@	éQà ØPà$8SÀ\)pxùD{ÁÀú³dt)P@ p‡"ÈR 0ï"ËðßtI.;b\×ʹƒӁGŽ@�YïÇÏÒà}0ײEîÑO†ØÁ<¸DÏ[èCùیa#‰îº	IEND®B`‚‰PNG


IHDRàw=ø½IDATx^Õֽ
Â0@aOb"FaZ"–  HZ†¯̃' aÏn(,"ù
Н½§Dþ3›ӽĢLj+fÈ¥Á¼ eË[Ü IíÀ¢Ø!B4D+p†hVš¢´^;0ÿsà¡ý‹|
ŒŠA{™v)Ð(m´€&§p0Z‡Ý›Y[鸎hóÜÚNÄ&«yeNØÔ™…ûñk,̷%Ϗç‡LjëҌ7†¼Ø1ÎwIEND®B`‚‰PNG


IHDRàw=ø¾IDATx^µÕÏ	Â0ÅñL«£8€W«Kˆxh®.cVh&qL`<¨ê+XZ|‡Ï5_ȟ_Ìòx}þ(ÁZp0ó	Óe8Õ(ÁF öº#kM€X4¼:aƀF£´ê@Tî}à¦Dõõ!7êkZA=´j˜z^9*z’jØ
jèþ4®k0Ўç1yñÃøÃ[Áeâ¶lT<ùËÛâKŸ~‰"<Þ"p°(­ñ@¼ܭAÃÿIEND®B`‚