text:
// @license MIT

/* @author Misha Koryak
 * @projectDescription lock a table header in place while scrolling - without breaking styles or events bound to the header
 *
 * Dependencies:
 * jquery 1.9.0 + [required] OR jquery 1.7.0 + jquery UI core
 *
 * http://mkoryak.github.io/floatThead/
 *
 * Tested on FF13+, Chrome 21+, IE8, IE9, IE10, IE11
 *
 */
(function( $ ) {
  /**
   * provides a default config object. You can modify this after including this script if you want to change the init defaults
   * @type {Object}
   */
  $.floatThead = $.floatThead || {};
  $.floatThead.defaults = {
    headerCellSelector: 'tr:visible:first>*:visible', //thead cells are this.
    zIndex: 89, //zindex of the floating thead (actually a container div)
    position: 'auto', // 'fixed', 'absolute', 'auto'. auto picks the best for your table scrolling type.
    top: 0, //String or function($table) - offset from top of window where the header should not pass above
    bottom: 0, //String or function($table) - offset from the bottom of the table where the header should stop scrolling
    scrollContainer: function($table) { // or boolean 'true' (use offsetParent) | function -> if the table has horizontal scroll bars then this is the container that has overflow:auto and causes those scroll bars
      return $([]);
    },
    responsiveContainer: function($table) { // only valid if scrollContainer is not used (ie window scrolling). this is the container which will control y scrolling at some mobile breakpoints
      return $([]);
    },
    getSizingRow: function($table, $cols, $fthCells){ // this is only called when using IE,
      // override it if the first row of the table is going to contain colgroups (any cell spans greater than one col)
      // it should return a jquery object containing a wrapped set of table cells comprising a row that contains no col spans and is visible
      return $table.find('tbody tr:visible:first>*:visible');
    },
    floatTableClass: 'floatThead-table',
    floatWrapperClass: 'floatThead-wrapper',
    floatContainerClass: 'floatThead-container',
    copyTableClass: true, //copy 'class' attribute from table into the floated table so that the styles match.
    autoReflow: false, //(undocumented) - use MutationObserver api to reflow automatically when internal table DOM changes
    debug: false, //print possible issues (that don't prevent script loading) to console, if console exists.
    support: { //should we bind events that expect these frameworks to be present and/or check for them?
      bootstrap: true,
      datatables: true,
      jqueryUI: true,
      perfectScrollbar: true
    }
  };

  var util = window._ || (function underscoreShim(){
    var that = {};
    var hasOwnProperty = Object.prototype.hasOwnProperty, isThings = ['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'];
    that.has = function(obj, key) {
      return hasOwnProperty.call(obj, key);
    };
    that.keys = Object.keys || function(obj) {
      if (obj !== Object(obj)) throw new TypeError('Invalid object');
      var keys = [];
      for (var key in obj) if (that.has(obj, key)) keys.push(key);
      return keys;
    };
    var idCounter = 0;
    that.uniqueId = function(prefix) {
      var id = ++idCounter + '';
      return prefix ? prefix + id : id;
    };
    $.each(isThings, function(){
      var name = this;
      that['is' + name] = function(obj) {
        return Object.prototype.toString.call(obj) == '[object ' + name + ']';
      };
    });
    that.debounce = function(func, wait, immediate) {
      var timeout, args, context, timestamp, result;
      return function() {
        context = this;
        args = arguments;
        timestamp = new Date();
        var later = function() {
          var last = (new Date()) - timestamp;
          if (last < wait) {
            timeout = setTimeout(later, wait - last);
          } else {
            timeout = null;
            if (!immediate) result = func.apply(context, args);
          }
        };
        var callNow = immediate && !timeout;
        if (!timeout) {
          timeout = setTimeout(later, wait);
        }
        if (callNow) result = func.apply(context, args);
        return result;
      };
    };
    return that;
  })();

  var canObserveMutations = typeof MutationObserver !== 'undefined';

  //browser stuff
  var ieVersion = function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a = 1+a,b.innerHTML="<!--[if gt IE "+ a +"]><i><![endif]-->",c[0];);return 4<a?a:document.documentMode}();
  var isFF = /Gecko\//.test(navigator.userAgent);
  var isWebkit = /WebKit\//.test(navigator.userAgent);

  if(!(ieVersion || isFF || isWebkit)){
    ieVersion = 11; //yey a hack!
  }

  //safari 7 (and perhaps others) reports table width to be parent container's width if max-width is set on table. see: https://github.com/mkoryak/floatThead/issues/108
  var isTableWidthBug = function(){
    if(isWebkit) {
      var $test = $('<div>').css('width', 0).append(
        $('<table>').css('max-width', '100%').append(
          $('<tr>').append(
            $('<th>').append(
              $('<div>').css('min-width', 100).text('X')
            )
          )
        )
      );
      $("body").append($test);
      var ret = ($test.find("table").width() == 0);
      $test.remove();
      return ret;
    }
    return false;
  };

  var createElements = !isFF && !ieVersion; //FF can read width from <col> elements, but webkit cannot

  var $window = $(window);

  if(!window.matchMedia) {
    var _beforePrint = window.onbeforeprint;
    var _afterPrint = window.onafterprint;
    window.onbeforeprint = function () {
      _beforePrint && _beforePrint();
      $window.triggerHandler("beforeprint");
    };
    window.onafterprint = function () {
      _afterPrint && _afterPrint();
      $window.triggerHandler("afterprint");
    };
  }

  /**
   * @param debounceMs
   * @param cb
   */
  function windowResize(eventName, cb){
    if(ieVersion == 8){ //ie8 is crap: https://github.com/mkoryak/floatThead/issues/65
      var winWidth = $window.width();
      var debouncedCb = util.debounce(function(){
        var winWidthNew = $window.width();
        if(winWidth != winWidthNew){
          winWidth = winWidthNew;
          cb();
        }
      }, 1);
      $window.on(eventName, debouncedCb);
    } else {
      $window.on(eventName, util.debounce(cb, 1));
    }
  }

  function getClosestScrollContainer($elem) {
    var elem = $elem[0];
    var parent = elem.parentElement;

    do {
      var pos = window
          .getComputedStyle(parent)
          .getPropertyValue('overflow');

      if (pos != 'visible') break;

    } while (parent = parent.parentElement);

    if(parent == document.body){
      return $([]);
    }
    return $(parent);
  }

  function debug(str){
    window && window.console && window.console.error && window.console.error("jQuery.floatThead: " + str);
  }

  //returns fractional pixel widths
  function getOffsetWidth(el) {
    var rect = el.getBoundingClientRect();
    return rect.width || rect.right - rect.left;
  }

  /**
   * try to calculate the scrollbar width for your browser/os
   * @return {Number}
   */
  function scrollbarWidth() {
    var d = document.createElement("scrolltester");
    d.style.cssText = 'width:100px;height:100px;overflow:scroll!important;position:absolute;top:-9999px;display:block';
    document.body.appendChild(d);
    var result = d.offsetWidth - d.clientWidth;
    document.body.removeChild(d);
    return result;
  }

  /**
   * Check if a given table has been datatableized (http://datatables.net)
   * @param $table
   * @return {Boolean}
   */
  function isDatatable($table){
    if($table.dataTableSettings){
      for(var i = 0; i < $table.dataTableSettings.length; i++){
        var table = $table.dataTableSettings[i].nTable;
        if($table[0] == table){
          return true;
        }
      }
    }
    return false;
  }

  function tableWidth($table, $fthCells, isOuter){
    // see: https://github.com/mkoryak/floatThead/issues/108
    var fn = isOuter ? "outerWidth": "width";
    if(isTableWidthBug && $table.css("max-width")){
      var w = 0;
      if(isOuter) {
        w += parseInt($table.css("borderLeft"), 10);
        w += parseInt($table.css("borderRight"), 10);
      }
      for(var i=0; i < $fthCells.length; i++){
        w += $fthCells.get(i).offsetWidth;
      }
      return w;
    } else {
      return $table[fn]();
    }
  }
  $.fn.floatThead = function(map){
    map = map || {};

    if(ieVersion < 8){
      return this; //no more crappy browser support.
    }

    var mObs = null; //mutation observer lives in here if we can use it / make it

    if(util.isFunction(isTableWidthBug)) {
      isTableWidthBug = isTableWidthBug();
    }

    if(util.isString(map)){
      var command = map;
      var args = Array.prototype.slice.call(arguments, 1);
      var ret = this;
      this.filter('table').each(function(){
        var $this = $(this);
        var opts = $this.data('floatThead-lazy');
        if(opts){
          $this.floatThead(opts);
        }
        var obj = $this.data('floatThead-attached');
        if(obj && util.isFunction(obj[command])){
          var r = obj[command].apply(this, args);
          if(r !== undefined){
            ret = r;
          }
        }
      });
      return ret;
    }
    var opts = $.extend({}, $.floatThead.defaults || {}, map);

    $.each(map, function(key, val){
      if((!(key in $.floatThead.defaults)) && opts.debug){
        debug("Used ["+key+"] key to init plugin, but that param is not an option for the plugin. Valid options are: "+ (util.keys($.floatThead.defaults)).join(', '));
      }
    });
    if(opts.debug){
      var v = $.fn.jquery.split(".");
      if(parseInt(v[0], 10) == 1 && parseInt(v[1], 10) <= 7){
        debug("jQuery version "+$.fn.jquery+" detected! This plugin supports 1.8 or better, or 1.7.x with jQuery UI 1.8.24 -> http://jqueryui.com/resources/download/jquery-ui-1.8.24.zip")
      }
    }

    this.filter(':not(.'+opts.floatTableClass+')').each(function(){
      var floatTheadId = util.uniqueId();
      var $table = $(this);
      if($table.data('floatThead-attached')){
        return true; //continue the each loop
      }
      if(!$table.is('table')){
        throw new Error('jQuery.floatThead must be run on a table element. ex: $("table").floatThead();');
      }
      canObserveMutations = opts.autoReflow && canObserveMutations; //option defaults to false!
      var $header = $table.children('thead:first');
      var $tbody = $table.children('tbody:first');
      if($header.length == 0 || $tbody.length == 0){
        if(opts.debug) {
          if($header.length == 0){
            debug('The thead element is missing.');
          } else{
            debug('The tbody element is missing.');
          }
        }
        $table.data('floatThead-lazy', opts);
        $table.unbind("reflow").one('reflow', function(){
          $table.floatThead(opts);
        });
        return;
      }
      if($table.data('floatThead-lazy')){
        $table.unbind("reflow");
      }
      $table.data('floatThead-lazy', false);

      var headerFloated = true;
      var scrollingTop, scrollingBottom;
      var scrollbarOffset = {vertical: 0, horizontal: 0};
      var scWidth = scrollbarWidth();
      var lastColumnCount = 0; //used by columnNum()

      if(opts.scrollContainer === true){
        opts.scrollContainer = getClosestScrollContainer;
      }

      var $scrollContainer = opts.scrollContainer($table) || $([]); //guard against returned nulls
      var locked = $scrollContainer.length > 0;
      var $responsiveContainer = locked ? $([]) : opts.responsiveContainer($table) || $([]);
      var responsive = isResponsiveContainerActive();

      var useAbsolutePositioning = null;

      if (opts.position == 'auto') {
        useAbsolutePositioning = null;
      } else if (opts.position == 'fixed') {
        useAbsolutePositioning = false;
      } else if (opts.position == 'absolute'){
        useAbsolutePositioning = true;
      } else if (opts.debug) {
        debug('Invalid value given to "position" option, valid is "fixed", "absolute" and "auto". You passed: ', opts.position);
      }

      if(useAbsolutePositioning == null){ //defaults: locked=true, !locked=false
        useAbsolutePositioning = locked;
      }
      var $caption = $table.find("caption");
      var haveCaption = $caption.length == 1;
      if(haveCaption){
        var captionAlignTop = ($caption.css("caption-side") || $caption.attr("align") || "top") === "top";
      }

      var $fthGrp = $('<fthfoot>').css({
        'display': 'table-footer-group',
        'border-spacing': 0,
        'height': 0,
        'border-collapse': 'collapse',
        'visibility': 'hidden'
      });

      var wrappedContainer = false; //used with absolute positioning enabled. did we need to wrap the scrollContainer/table with a relative div?
      var $wrapper = $([]); //used when absolute positioning enabled - wraps the table and the float container
      var absoluteToFixedOnScroll = ieVersion <= 9 && !locked && useAbsolutePositioning; //on IE using absolute positioning doesn't look good with window scrolling, so we change position to fixed on scroll, and then change it back to absolute when done.
      var $floatTable = $("<table/>");
      var $floatColGroup = $("<colgroup/>");
      var $tableColGroup = $table.children('colgroup:first');
      var existingColGroup = true;
      if($tableColGroup.length == 0){
        $tableColGroup = $("<colgroup/>");
        existingColGroup = false;
      }
      var $fthRow = $('<fthtr>').css({ //created unstyled elements (used for sizing the table because chrome can't read <col> width)
        'display': 'table-row',
        'border-spacing': 0,
        'height': 0,
        'border-collapse': 'collapse'
      });
      var $floatContainer = $('<div>').css('overflow', 'hidden').attr('aria-hidden', 'true');
      var floatTableHidden = false; //this happens when the table is hidden and we do magic when making it visible
      var $newHeader = $("<thead/>");
      var $sizerRow = $('<tr class="size-row" aria-hidden="true"/>');
      var $sizerCells = $([]);
      var $tableCells = $([]); //used for sizing - either $sizerCells or $tableColGroup cols. $tableColGroup cols are only created in chrome for borderCollapse:collapse because of a chrome bug.
      var $headerCells = $([]);
      var $fthCells = $([]); //created elements

      $newHeader.append($sizerRow);
      $table.prepend($tableColGroup);
      if(createElements){
        $fthGrp.append($fthRow);
        $table.append($fthGrp);
      }

      $floatTable.append($floatColGroup);
      $floatContainer.append($floatTable);
      if(opts.copyTableClass){
        $floatTable.attr('class', $table.attr('class'));
      }
      $floatTable.attr({ //copy over some deprecated table attributes that people still like to use. Good thing people don't use colgroups...
                         'cellpadding': $table.attr('cellpadding'),
                         'cellspacing': $table.attr('cellspacing'),
                         'border': $table.attr('border')
                       });
      var tableDisplayCss = $table.css('display');
      $floatTable.css({
                        'borderCollapse': $table.css('borderCollapse'),
                        'border': $table.css('border'),
                        'display': tableDisplayCss
                      });
      if(!locked){
        $floatTable.css('width', 'auto');
      }
      if(tableDisplayCss == 'none'){
        floatTableHidden = true;
      }

      $floatTable.addClass(opts.floatTableClass).css({'margin': 0, 'border-bottom-width': 0}); //must have no margins or you won't be able to click on things under floating table

      if(useAbsolutePositioning){
        var makeRelative = function($container, alwaysWrap){
          var positionCss = $container.css('position');
          var relativeToScrollContainer = (positionCss == "relative" || positionCss == "absolute");
          var $containerWrap = $container;
          if(!relativeToScrollContainer || alwaysWrap){
            var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')};
            $floatContainer.css(css);
            $containerWrap = $container.data('floatThead-containerWrap') || $container.wrap(
              $('<div>').addClass(opts.floatWrapperClass).css({
                'position': 'relative',
                'clear': 'both'
              })
            ).parent();
            $container.data('floatThead-containerWrap', $containerWrap); //multiple tables inside one scrolling container - #242
            wrappedContainer = true;
          }
          return $containerWrap;
        };
        if(locked){
          $wrapper = makeRelative($scrollContainer, true);
          $wrapper.prepend($floatContainer);
        } else {
          $wrapper = makeRelative($table);
          $table.before($floatContainer);
        }
      } else {
        $table.before($floatContainer);
      }

      $floatContainer.css({
                            position: useAbsolutePositioning ? 'absolute' : 'fixed',
                            marginTop: 0,
                            top:  useAbsolutePositioning ? 0 : 'auto',
                            zIndex: opts.zIndex,
                            willChange: 'transform'
                          });
      $floatContainer.addClass(opts.floatContainerClass);
      updateScrollingOffsets();

      var layoutFixed = {'table-layout': 'fixed'};
      var layoutAuto = {'table-layout': $table.css('tableLayout') || 'auto'};
      var originalTableWidth = $table[0].style.width || ""; //setting this to auto is bad: #70
      var originalTableMinWidth = $table.css('minWidth') || "";

      function eventName(name){
        return name+'.fth-'+floatTheadId+'.floatTHead'
      }

      function setHeaderHeight(){
        var headerHeight = 0;
        $header.children("tr:visible").each(function(){
          headerHeight += $(this).outerHeight(true);
        });
        if($table.css('border-collapse') == 'collapse') {
          var tableBorderTopHeight = parseInt($table.css('border-top-width'), 10);
          var cellBorderTopHeight = parseInt($table.find("thead tr:first").find(">*:first").css('border-top-width'), 10);
          if(tableBorderTopHeight > cellBorderTopHeight) {
            headerHeight -= (tableBorderTopHeight / 2); //id love to see some docs where this magic recipe is found..
          }
        }
        $sizerRow.outerHeight(headerHeight);
        $sizerCells.outerHeight(headerHeight);
      }

      function setFloatWidth(){
        var tw = tableWidth($table, $fthCells, true);
        var $container = responsive ? $responsiveContainer : $scrollContainer;
        var width = $container.width() || tw;
        var floatContainerWidth = $container.css("overflow-y") != 'hidden' ? width - scrollbarOffset.vertical : width;
        $floatContainer.width(floatContainerWidth);
        if(locked){
          var percent = 100 * tw / (floatContainerWidth);
          $floatTable.css('width', percent+'%');
        } else {
          $floatTable.outerWidth(tw);
        }
      }

      function updateScrollingOffsets(){
        scrollingTop = (util.isFunction(opts.top) ? opts.top($table) : opts.top) || 0;
        scrollingBottom = (util.isFunction(opts.bottom) ? opts.bottom($table) : opts.bottom) || 0;
      }

      /**
       * get the number of columns and also rebuild resizer rows if the count is different than the last count
       */
      function columnNum(){
        var count;
        var $headerColumns = $header.find(opts.headerCellSelector);
        if(existingColGroup){
          count = $tableColGroup.find('col').length;
        } else {
          count = 0;
          $headerColumns.each(function () {
            count += parseInt(($(this).attr('colspan') || 1), 10);
          });
        }
        if(count != lastColumnCount){
          lastColumnCount = count;
          var cells = [], cols = [], psuedo = [], content;
          for(var x = 0; x < count; x++){
            content = $headerColumns.eq(x).text();
            cells.push('<th class="floatThead-col" aria-label="'+content+'"/>');
            cols.push('<col/>');
            psuedo.push(
              $('<fthtd>').css({
                'display': 'table-cell',
                'height': 0,
                'width': 'auto'
              })
            );
          }

          cols = cols.join('');
          cells = cells.join('');

          if(createElements){
            $fthRow.empty();
            $fthRow.append(psuedo);
            $fthCells = $fthRow.find('fthtd');
          }

          $sizerRow.html(cells);
          $sizerCells = $sizerRow.find("th");
          if(!existingColGroup){
            $tableColGroup.html(cols);
          }
          $tableCells = $tableColGroup.find('col');
          $floatColGroup.html(cols);
          $headerCells = $floatColGroup.find("col");

        }
        return count;
      }

      function refloat(){ //make the thing float
        if(!headerFloated){
          headerFloated = true;
          if(useAbsolutePositioning){ //#53, #56
            var tw = tableWidth($table, $fthCells, true);
            var wrapperWidth = $wrapper.width();
            if(tw > wrapperWidth){
              $table.css('minWidth', tw);
            }
          }
          $table.css(layoutFixed);
          $floatTable.css(layoutFixed);
          $floatTable.append($header); //append because colgroup must go first in chrome
          $tbody.before($newHeader);
          setHeaderHeight();
        }
      }
      function unfloat(){ //put the header back into the table
        if(headerFloated){
          headerFloated = false;
          if(useAbsolutePositioning){ //#53, #56
            $table.width(originalTableWidth);
          }
          $newHeader.detach();
          $table.prepend($header);
          $table.css(layoutAuto);
          $floatTable.css(layoutAuto);
          $table.css('minWidth', originalTableMinWidth); //this looks weird, but it's not a bug. Think about it!!
          $table.css('minWidth', tableWidth($table, $fthCells)); //#121
        }
      }
      var isHeaderFloatingLogical = false; //for the purpose of this event, the header is/isnt floating, even though the element
                                           //might be in some other state. this is what the header looks like to the user
      function triggerFloatEvent(isFloating){
        if(isHeaderFloatingLogical != isFloating){
          isHeaderFloatingLogical = isFloating;
          $table.triggerHandler("floatThead", [isFloating, $floatContainer])
        }
      }
      function changePositioning(isAbsolute){
        if(useAbsolutePositioning != isAbsolute){
          useAbsolutePositioning = isAbsolute;
          $floatContainer.css({
            position: useAbsolutePositioning ? 'absolute' : 'fixed'
          });
        }
      }
      function getSizingRow($table, $cols, $fthCells, ieVersion){
        if(createElements){
          return $fthCells;
        } else if(ieVersion) {
          return opts.getSizingRow($table, $cols, $fthCells);
        } else {
          return $cols;
        }
      }

      /**
       * returns a function that updates the floating header's cell widths.
       * @return {Function}
       */
      function reflow(){
        var i;
        var numCols = columnNum(); //if the tables columns changed dynamically since last time (datatables), rebuild the sizer rows and get a new count

        return function(){
          //Cache the current scrollLeft value so that it can be reset post reflow
          var scrollLeft = $floatContainer.scrollLeft();
          $tableCells = $tableColGroup.find('col');
          var $rowCells = getSizingRow($table, $tableCells, $fthCells, ieVersion);

          if($rowCells.length == numCols && numCols > 0){
            if(!existingColGroup){
              for(i=0; i < numCols; i++){
                $tableCells.eq(i).css('width', '');
              }
            }
            unfloat();
            var widths = [];
            for(i=0; i < numCols; i++){
              widths[i] = getOffsetWidth($rowCells.get(i));
            }
            for(i=0; i < numCols; i++){
              $headerCells.eq(i).width(widths[i]);
              $tableCells.eq(i).width(widths[i]);
            }
            refloat();
          } else {
            $floatTable.append($header);
            $table.css(layoutAuto);
            $floatTable.css(layoutAuto);
            setHeaderHeight();
          }
          //Set back the current scrollLeft value on floatContainer
          $floatContainer.scrollLeft(scrollLeft);
          $table.triggerHandler("reflowed", [$floatContainer]);
        };
      }

      function floatContainerBorderWidth(side){
        var border = $scrollContainer.css("border-"+side+"-width");
        var w = 0;
        if (border && ~border.indexOf('px')) {
          w = parseInt(border, 10);
        }
        return w;
      }

      function isResponsiveContainerActive(){
        return $responsiveContainer.css("overflow-x") == 'auto';
      }
      /**
       * first performs initial calculations that we expect to not change when the table, window, or scrolling container are scrolled.
       * returns a function that calculates the floating container's top and left coords. takes into account if we are using page scrolling or inner scrolling
       * @return {Function}
       */
      function calculateFloatContainerPosFn(){
        var scrollingContainerTop = $scrollContainer.scrollTop();

        //this floatEnd calc was moved out of the returned function because we assume the table height doesn't change (otherwise we must reinit by calling calculateFloatContainerPosFn)
        var floatEnd;
        var tableContainerGap = 0;
        var captionHeight = haveCaption ? $caption.outerHeight(true) : 0;
        var captionScrollOffset = captionAlignTop ? captionHeight : -captionHeight;

        var floatContainerHeight = $floatContainer.height();
        var tableOffset = $table.offset();
        var tableLeftGap = 0; //can be caused by border on container (only in locked mode)
        var tableTopGap = 0;
        if(locked){
          var containerOffset = $scrollContainer.offset();
          tableContainerGap = tableOffset.top - containerOffset.top + scrollingContainerTop;
          if(haveCaption && captionAlignTop){
            tableContainerGap += captionHeight;
          }
          tableLeftGap = floatContainerBorderWidth('left');
          tableTopGap = floatContainerBorderWidth('top');
          tableContainerGap -= tableTopGap;
        } else {
          floatEnd = tableOffset.top - scrollingTop - floatContainerHeight + scrollingBottom + scrollbarOffset.horizontal;
        }
        var windowTop = $window.scrollTop();
        var windowLeft = $window.scrollLeft();
        var getScrollContainerLeft = function(){
          return (isResponsiveContainerActive() ?  $responsiveContainer : $scrollContainer).scrollLeft() || 0;
        };
        var scrollContainerLeft = getScrollContainerLeft();

        return function(eventType){
          responsive = isResponsiveContainerActive();

          var isTableHidden = $table[0].offsetWidth <= 0 && $table[0].offsetHeight <= 0;
          if(!isTableHidden && floatTableHidden) {
            floatTableHidden = false;
            setTimeout(function(){
              $table.triggerHandler("reflow");
            }, 1);
            return null;
          }
          if(isTableHidden){ //it's hidden
            floatTableHidden = true;
            if(!useAbsolutePositioning){
              return null;
            }
          }

          if(eventType == 'windowScroll'){
            windowTop = $window.scrollTop();
            windowLeft = $window.scrollLeft();
          } else if(eventType == 'containerScroll'){
            if($responsiveContainer.length){
              if(!responsive){
                return; //we dont care about the event if we arent responsive right now
              }
              scrollContainerLeft = $responsiveContainer.scrollLeft();
            } else {
              scrollingContainerTop = $scrollContainer.scrollTop();
              scrollContainerLeft = $scrollContainer.scrollLeft();
            }
          } else if(eventType != 'init') {
            windowTop = $window.scrollTop();
            windowLeft = $window.scrollLeft();
            scrollingContainerTop = $scrollContainer.scrollTop();
            scrollContainerLeft =  getScrollContainerLeft();
          }
          if(isWebkit && (windowTop < 0 || windowLeft < 0)){ //chrome overscroll effect at the top of the page - breaks fixed positioned floated headers
            return;
          }

          if(absoluteToFixedOnScroll){
            if(eventType == 'windowScrollDone'){
              changePositioning(true); //change to absolute
            } else {
              changePositioning(false); //change to fixed
            }
          } else if(eventType == 'windowScrollDone'){
            return null; //event is fired when they stop scrolling. ignore it if not 'absoluteToFixedOnScroll'
          }

          tableOffset = $table.offset();
          if(haveCaption && captionAlignTop){
            tableOffset.top += captionHeight;
          }
          var top, left;
          var tableHeight = $table.outerHeight();

          if(locked && useAbsolutePositioning){ //inner scrolling, absolute positioning
            if (tableContainerGap >= scrollingContainerTop) {
              var gap = tableContainerGap - scrollingContainerTop + tableTopGap;
              top = gap > 0 ? gap : 0;
              triggerFloatEvent(false);
            } else {
              top = wrappedContainer ? tableTopGap : scrollingContainerTop;
              //headers stop at the top of the viewport
              triggerFloatEvent(true);
            }
            left = tableLeftGap;
          } else if(!locked && useAbsolutePositioning) { //window scrolling, absolute positioning
            if(windowTop > floatEnd + tableHeight + captionScrollOffset){
              top = tableHeight - floatContainerHeight + captionScrollOffset; //scrolled past table
            } else if (tableOffset.top >= windowTop + scrollingTop) {
              top = 0; //scrolling to table
              unfloat();
              triggerFloatEvent(false);
            } else {
              top = scrollingTop + windowTop - tableOffset.top + tableContainerGap + (captionAlignTop ? captionHeight : 0);
              refloat(); //scrolling within table. header floated
              triggerFloatEvent(true);
            }
            left =  scrollContainerLeft;
          } else if(locked && !useAbsolutePositioning){ //inner scrolling, fixed positioning
            if (tableContainerGap > scrollingContainerTop || scrollingContainerTop - tableContainerGap > tableHeight) {
              top = tableOffset.top - windowTop;
              unfloat();
              triggerFloatEvent(false);
            } else {
              top = tableOffset.top + scrollingContainerTop  - windowTop - tableContainerGap;
              refloat();
              triggerFloatEvent(true);
              //headers stop at the top of the viewport
            }
            left = tableOffset.left + scrollContainerLeft - windowLeft;
          } else if(!locked && !useAbsolutePositioning) { //window scrolling, fixed positioning
            if(windowTop > floatEnd + tableHeight + captionScrollOffset){
              top = tableHeight + scrollingTop - windowTop + floatEnd + captionScrollOffset;
              //scrolled past the bottom of the table
            } else if (tableOffset.top > windowTop + scrollingTop) {
              top = tableOffset.top - windowTop;
              refloat();
              triggerFloatEvent(false); //this is a weird case, the header never gets unfloated and i have no no way to know
              //scrolled past the top of the table
            } else {
              //scrolling within the table
              top = scrollingTop;
              triggerFloatEvent(true);
            }
            left = tableOffset.left + scrollContainerLeft - windowLeft;
          }
          return {top: Math.round(top), left: Math.round(left)};
        };
      }
      /**
       * returns a function that caches old floating container position and only updates css when the position changes
       * @return {Function}
       */
      function repositionFloatContainerFn(){
        var oldTop = null;
        var oldLeft = null;
        var oldScrollLeft = null;
        return function(pos, setWidth, setHeight){
          if(pos != null && (oldTop != pos.top || oldLeft != pos.left)){
            if(ieVersion === 8){
              $floatContainer.css({
                top: pos.top,
                left: pos.left
              });
            } else {
              var transform = 'translateX(' + pos.left + 'px) translateY(' + pos.top + 'px)';
              $floatContainer.css({
                '-webkit-transform' : transform,
                '-moz-transform'    : transform,
                '-ms-transform'     : transform,
                '-o-transform'      : transform,
                'transform'         : transform,
                'top': 0,
                'left': 0
              });
            }
            oldTop = pos.top;
            oldLeft = pos.left;
          }
          if(setWidth){
            setFloatWidth();
          }
          if(setHeight){
            setHeaderHeight();
          }
          var scrollLeft = (responsive ? $responsiveContainer : $scrollContainer).scrollLeft();
          if(!useAbsolutePositioning || oldScrollLeft != scrollLeft){
            $floatContainer.scrollLeft(scrollLeft);
            oldScrollLeft = scrollLeft;
          }
        }
      }

      /**
       * checks if THIS table has scrollbars, and finds their widths
       */
      function calculateScrollBarSize(){ //this should happen after the floating table has been positioned
        if($scrollContainer.length){
          if(opts.support && opts.support.perfectScrollbar && $scrollContainer.data().perfectScrollbar){
            scrollbarOffset = {horizontal:0, vertical:0};
          } else {
            if($scrollContainer.css('overflow-x') == 'scroll'){
              scrollbarOffset.horizontal = scWidth;
            } else {
              var sw = $scrollContainer.width(), tw = tableWidth($table, $fthCells);
              var offsetv = sh < th ? scWidth : 0;
              scrollbarOffset.horizontal = sw - offsetv < tw ? scWidth : 0;
            }
            if($scrollContainer.css('overflow-y') == 'scroll'){
              scrollbarOffset.vertical = scWidth;
            } else {
              var sh = $scrollContainer.height(), th = $table.height();
              var offseth = sw < tw ? scWidth : 0;
              scrollbarOffset.vertical = sh - offseth < th ? scWidth : 0;
            }
          }
        }
      }
      //finish up. create all calculation functions and bind them to events
      calculateScrollBarSize();

      var flow;

      var ensureReflow = function(){
        flow = reflow();
        flow();
      };

      ensureReflow();

      var calculateFloatContainerPos = calculateFloatContainerPosFn();
      var repositionFloatContainer = repositionFloatContainerFn();

      repositionFloatContainer(calculateFloatContainerPos('init'), true); //this must come after reflow because reflow changes scrollLeft back to 0 when it rips out the thead

      var windowScrollDoneEvent = util.debounce(function(){
        repositionFloatContainer(calculateFloatContainerPos('windowScrollDone'), false);
      }, 1);

      var windowScrollEvent = function(){
        repositionFloatContainer(calculateFloatContainerPos('windowScroll'), false);
        if(absoluteToFixedOnScroll){
          windowScrollDoneEvent();
        }
      };
      var containerScrollEvent = function(){
        repositionFloatContainer(calculateFloatContainerPos('containerScroll'), false);
      };

      var windowResizeEvent = function(){
        if($table.is(":hidden")){
          return;
        }
        updateScrollingOffsets();
        calculateScrollBarSize();
        ensureReflow();
        calculateFloatContainerPos = calculateFloatContainerPosFn();
        repositionFloatContainer = repositionFloatContainerFn();
        repositionFloatContainer(calculateFloatContainerPos('resize'), true, true);
      };
      var reflowEvent = util.debounce(function(){
        if($table.is(":hidden")){
          return;
        }
        calculateScrollBarSize();
        updateScrollingOffsets();
        ensureReflow();
        calculateFloatContainerPos = calculateFloatContainerPosFn();
        repositionFloatContainer(calculateFloatContainerPos('reflow'), true);
      }, 1);

      /////// printing stuff
      var beforePrint = function(){
        unfloat();
      };
      var afterPrint = function(){
        refloat();
      };
      var printEvent = function(mql){
        //make printing the table work properly on IE10+
        if(mql.matches) {
          beforePrint();
        } else {
          afterPrint();
        }
      };

      var matchMediaPrint;
      if(window.matchMedia && window.matchMedia('print').addListener){
        matchMediaPrint = window.matchMedia("print");
        matchMediaPrint.addListener(printEvent);
      } else {
        $window.on('beforeprint', beforePrint);
        $window.on('afterprint', afterPrint);
      }
      ////// end printing stuff

      if(locked){ //internal scrolling
        if(useAbsolutePositioning){
          $scrollContainer.on(eventName('scroll'), containerScrollEvent);
        } else {
          $scrollContainer.on(eventName('scroll'), containerScrollEvent);
          $window.on(eventName('scroll'), windowScrollEvent);
        }
      } else { //window scrolling
        $responsiveContainer.on(eventName('scroll'), containerScrollEvent);
        $window.on(eventName('scroll'), windowScrollEvent);
      }

      $window.on(eventName('load'), reflowEvent); //for tables with images

      windowResize(eventName('resize'), windowResizeEvent);
      $table.on('reflow', reflowEvent);
      if(opts.support && opts.support.datatables && isDatatable($table)){
        $table
            .on('filter', reflowEvent)
            .on('sort',   reflowEvent)
            .on('page',   reflowEvent);
      }

      if(opts.support && opts.support.bootstrap) {
        $window.on(eventName('shown.bs.tab'), reflowEvent); // people cant seem to figure out how to use this plugin with bs3 tabs... so this :P
      }
      if(opts.support && opts.support.jqueryUI) {
        $window.on(eventName('tabsactivate'), reflowEvent); // same thing for jqueryui
      }

      if (canObserveMutations) {
        var mutationElement = null;
        if(util.isFunction(opts.autoReflow)){
          mutationElement = opts.autoReflow($table, $scrollContainer)
        }
        if(!mutationElement) {
          mutationElement = $scrollContainer.length ? $scrollContainer[0] : $table[0]
        }
        mObs = new MutationObserver(function(e){
          var wasTableRelated = function(nodes){
            return nodes && nodes[0] && (nodes[0].nodeName == "THEAD" || nodes[0].nodeName == "TD"|| nodes[0].nodeName == "TH");
          };
          for(var i=0; i < e.length; i++){
            if(!(wasTableRelated(e[i].addedNodes) || wasTableRelated(e[i].removedNodes))){
              reflowEvent();
              break;
            }
          }
        });
        mObs.observe(mutationElement, {
          childList: true,
          subtree: true
        });
      }

      //attach some useful functions to the table.
      $table.data('floatThead-attached', {
        destroy: function(){
          var ns = '.fth-'+floatTheadId;
          unfloat();
          $table.css(layoutAuto);
          $tableColGroup.remove();
          createElements && $fthGrp.remove();
          if($newHeader.parent().length){ //only if it's in the DOM
            $newHeader.replaceWith($header);
          }
          triggerFloatEvent(false);
          if(canObserveMutations){
            mObs.disconnect();
            mObs = null;
          }
          $table.off('reflow reflowed');
          $scrollContainer.off(ns);
          $responsiveContainer.off(ns);
          if (wrappedContainer) {
            if ($scrollContainer.length) {
              $scrollContainer.unwrap();
            }
            else {
              $table.unwrap();
            }
          }
          if(locked){
            $scrollContainer.data('floatThead-containerWrap', false);
          } else {
            $table.data('floatThead-containerWrap', false);
          }
          $table.css('minWidth', originalTableMinWidth);
          $floatContainer.remove();
          $table.data('floatThead-attached', false);
          $window.off(ns);
          if (matchMediaPrint) {
            matchMediaPrint.removeListener(printEvent);
          }
          beforePrint = afterPrint = function(){};

          return function reinit(){
            return $table.floatThead(opts);
          }
        },
        reflow: function(){
          reflowEvent();
        },
        setHeaderHeight: function(){
          setHeaderHeight();
        },
        getFloatContainer: function(){
          return $floatContainer;
        },
        getRowGroups: function(){
          if(headerFloated){
            return $floatContainer.find('>table>thead').add($table.children("tbody,tfoot"));
          } else {
            return $table.children("thead,tbody,tfoot");
          }
        }
      });
    });
    return this;
  };
})((function(){
  var $ = window.jQuery;
  if(typeof module !== 'undefined' && module.exports && !$) {
    // only use cjs if they dont have a jquery for me to use, and we have commonjs
    $ = require('jquery');
  }
  return $;
})());


text:
Home/Sports/World Athletics Council cancels China championships
World Athletics Council cancels China championships
By Oviri Kelvin, Sports Editor, Abuja
World Athletics Half Marathon Championships Yangzhou 22 in November 2022 have been cancelled following the pandemic in China.
The world governing body in a meeting with the Local Organising Committee (LOC) and Chinese Athletics Association (CAA), mutually decided in the best interest of the sport and participants to terminate the Yangzhou event.
In a statement by Sebastian Coe, President of World Athletics, the championship cannot be held this year and the Chinese are innocent of any wrongdoing but assured prospective participants that there will be Riga next year to fill up the lapses.
"Unfortunately, the championships can't be held this year, through no fault of the LOC, but our endurance athletes will have the opportunity to compete in Riga next year,'' said Coe. The President commended the LOC and CAA for the excellent job done so far to ensure the event would have been topnotch.
He stressed that the world athletics governing body is amazed at the impressive organisation and have decided to award another athletics event to Yangzhou in 2027.
Read Also: My journey to Fashion world bitter-sweet – Shade
He added, "The Council's decision to award another event to Yangzhou in 2027 indicates its faith in the organizing committee and willingness to return and stage a World Athletics Series Road running event there at the first available opportunity."
Meanwhile, the body has disclosed that the World Athletics Road Running Championships, which will make their debut in Riga, Latvia, on 30 September – 1 October 2023, will incorporate the half marathon championships in future, as well as introduce world 5km championships.
The athletics body added that Mass races will be held alongside the elite championships to allow recreational runners to be part of a global festival of road running.
championships China
7 Amazing facts about hugging
Army says proliferation of small arms, light weapons declining

redpajama_set_name: RedPajamaCommonCrawl


text:
#include "tensorflow/compiler/xla/python/tpu_driver/client/tpu_client.h"

#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "absl/memory/memory.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "mlir/IR/BuiltinOps.h"  // from @llvm-project
#include "tensorflow/compiler/xla/literal.h"
#include "tensorflow/compiler/xla/pjrt/mlir_to_hlo.h"
#include "tensorflow/compiler/xla/pjrt/semaphore.h"
#include "tensorflow/compiler/xla/python/tpu_driver/tpu_driver.h"
#include "tensorflow/compiler/xla/service/computation_placer.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/util.h"
#include "tensorflow/compiler/xla/xla_data.pb.h"
#include "tensorflow/core/platform/threadpool.h"
#include "tensorflow/core/profiler/lib/traceme.h"

namespace xla {

TpuDevice::TpuDevice(int id, int process_index,
                     const std::array<int, 3>& coords, int core_on_chip)
    : id_(id),
      process_index_(process_index),
      coords_(coords),
      core_on_chip_(core_on_chip) {}

std::string TpuDevice::DebugString() const {
  return absl::StrFormat("TPU_%i(host=%i,(%i,%i,%i,%i))", id(), process_index(),
                         coords_[0], coords_[1], coords_[2], core_on_chip_);
}

xla::StatusOr<std::vector<std::shared_ptr<xla::PjRtDevice>>>
TpuDevice::GetTpuDevices(const tpu_driver::SystemInfo& system_info) {
  std::vector<std::shared_ptr<PjRtDevice>> devices;
  for (const auto& chip : system_info.tpu_chip()) {
    auto& coord = chip.chip_coord();
    std::array<int, 3> coords_array = {coord.x(), coord.y(), coord.z()};
    int process_index = chip.host_id();
    for (const auto& core : chip.core()) {
      auto device = std::make_shared<TpuDevice>(
          core.id(), process_index, coords_array, core.core_on_chip_index());
      devices.push_back(device);
    }
  }

  return devices;
}

StatusOr<std::shared_ptr<PyTpuClient>> PyTpuClient::Get(
    const std::string& worker) {
  tpu_driver::TpuDriverConfig driver_config;
  driver_config.set_worker(worker);
  auto client_status = tpu_driver::TpuDriverRegistry::Open(driver_config);
  if (!client_status.ok()) {
    return client_status.status();
  }

  auto client = client_status.ConsumeValueOrDie();

  tpu_driver::SystemInfo system_info;
  client->QuerySystemInfo(&system_info);

  TF_ASSIGN_OR_RETURN(std::vector<std::shared_ptr<PjRtDevice>> devices,
                      TpuDevice::GetTpuDevices(system_info));

  return std::make_shared<PyTpuClient>(TpuPlatform(), std::move(client),
                                       std::move(devices),
                                       system_info.host_id());
}

PyTpuClient::PyTpuClient(std::string platform_name,
                         std::unique_ptr<tpu_driver::TpuDriver> driver,
                         std::vector<std::shared_ptr<PjRtDevice>> devices,
                         int process_index)
    : platform_name_(std::move(platform_name)),
      platform_version_("tpu_driver (deprecated)"),
      driver_(std::move(driver)),
      devices_(std::move(devices)),
      process_index_(process_index) {
  for (const std::shared_ptr<PjRtDevice>& device : devices_) {
    tensorflow::down_cast<TpuDevice*>(device.get())->set_tpu_client(this);
    CHECK(id_to_device_.insert({device->id(), device}).second)
        << "Duplicate device id: " << device->id();

    if (device->process_index() == process_index_) {
      LOG(INFO) << "Detected local device, host id: " << process_index_
                << ". device id: " << device->id();
      local_devices_.push_back(device);
    } else {
      VLOG(2) << "Other devices, device id: " << device->id();
    }
  }
  CHECK_GE(local_devices_.size(), 1);
  LOG(INFO) << "Creating " << local_devices_.size() << " TPU device(s).";

  for (int idx = 0; idx < local_devices_.size(); ++idx) {
    CHECK(local_devices_[idx] != nullptr) << idx;
  }

  // TODO(frankchn): Check if thread pool size needs to be adjusted (perhaps
  // something like min(cores, devices_.size()) might be appropriate depending
  // on the number of devices.
  pool_ = std::make_unique<tensorflow::thread::ThreadPool>(
      tensorflow::Env::Default(), "PyTpuClient", devices_.size());
}

Status PyTpuClient::TransferToInfeed(const LiteralSlice& literal,
                                     int device_id) {
  return Unimplemented("Infeed not implemented.");
}

StatusOr<Literal> PyTpuClient::TransferFromOutfeed(const Shape& shape,
                                                   int device_id) {
  return Unimplemented("Outfeed not implemented.");
}

StatusOr<DeviceAssignment> PyTpuClient::GetDefaultDeviceAssignment(
    int num_replicas, int num_partitions) const {
  if (num_partitions > 1) {
    return InvalidArgument("Num partitions greater than 1, is not supported.");
  }
  if (num_replicas * num_partitions <= local_device_count()) {
    DeviceAssignment assignment(num_replicas, num_partitions);
    for (int replica = 0; replica < num_replicas; ++replica) {
      for (int partition = 0; partition < num_partitions; ++partition) {
        assignment(replica, partition) = local_devices_[replica]->id();
      }
    }
    return assignment;
  }

  // Fallback to default global device assignment if we can't run locally.
  xla::ComputationPlacer placer;
  return placer.AssignDevices(num_replicas, num_partitions);
}

Status PyTpuClient::CheckDeviceId(int device_id,
                                  absl::string_view caller_name) {
  if (device_id < 0 || device_id >= device_count()) {
    return InvalidArgument("%s got bad device_id: %d (num_devices=%d).",
                           caller_name, device_id, device_count());
  }
  return Status::OK();
}

static Status CheckDataType(xla::PrimitiveType dtype) {
  if (dtype == xla::PrimitiveType::F64 || dtype == xla::PrimitiveType::S64 ||
      dtype == xla::PrimitiveType::U64) {
    return InvalidArgument(
        "64-bit data types are not yet supported on the TPU driver API. "
        "Convert inputs to float32/int32_t before using.");
  }
  return Status::OK();
}

/* static */
StatusOr<std::unique_ptr<PyTpuBuffer>> PyTpuBuffer::FromLiterals(
    std::vector<BorrowingLiteral> leaves, const Shape& tuple_shape,
    std::shared_ptr<void> leaves_references,
    std::shared_ptr<PyTpuClient> client, std::shared_ptr<PjRtDevice> device) {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::FromLiterals");
  VLOG(1) << "PyTpuBuffer::FromLiterals: shape: " << tuple_shape.DebugString()
          << " device: " << device->DebugString();
  TF_RETURN_IF_ERROR(
      client->CheckDeviceId(device->id(), "PyTpuBuffer::FromLiterals"));
  tpu_driver::TpuDriver* driver = client->driver();

  if (!tuple_shape.IsTuple()) {
    TF_RET_CHECK(leaves.size() == 1);
    return CreateBuffer(
        tuple_shape,
        [driver, &leaves, &tuple_shape,
         leaves_references](tpu_driver::BufferHandle* handle) {
          auto event =
              driver->TransferToDevice(leaves[0].untyped_data(), handle, {});
          event->AddCallback([leaves_references](Status) {});
          return event;
        },
        std::move(client), std::move(device));
  }

  std::vector<std::unique_ptr<PyTpuBuffer>> child_buffers;
  child_buffers.reserve(leaves.size());
  std::vector<PyTpuBuffer*> child_buffer_ptrs;
  child_buffer_ptrs.reserve(leaves.size());

  auto it_leaf = leaves.begin();
  for (const ShapeUtil::IndexedShape& indexed_shape :
       ShapeUtil::GetLeafShapes(tuple_shape)) {
    TF_RET_CHECK(it_leaf != leaves.end());
    auto& leaf = *it_leaf;
    TF_ASSIGN_OR_RETURN(
        std::unique_ptr<PyTpuBuffer> child_buffer,
        CreateBuffer(
            indexed_shape.shape,
            [driver, &leaf, &indexed_shape](tpu_driver::BufferHandle* handle) {
              return driver->TransferToDevice(leaf.untyped_data(), handle, {});
            },
            client, device));
    child_buffer_ptrs.push_back(child_buffer.get());
    child_buffers.push_back(std::move(child_buffer));
    ++it_leaf;
  }
  TF_RET_CHECK(it_leaf == leaves.end());

  // `MakeTuple` will extract and make the tuple buffer hold onto the
  // `device_buffer_` contained in each `child_buffer`, so it's safe for
  // `child_buffers` to get destroyed before this call returns.
  return MakeTuple(std::move(child_buffer_ptrs), std::move(client),
                   std::move(device));
}

/* static */
StatusOr<std::unique_ptr<PyTpuBuffer>> PyTpuBuffer::MakeTuple(
    absl::Span<PyTpuBuffer* const> buffers, std::shared_ptr<PyTpuClient> client,
    std::shared_ptr<PjRtDevice> device) {
  std::vector<Shape> child_shapes;
  std::vector<std::shared_ptr<TpuSharedBuffer>> child_device_buffers;
  std::vector<tpu_driver::BufferHandle*> child_handle_ptrs;
  std::vector<std::shared_ptr<tpu_driver::Event>> child_events;

  for (const auto& child_buffer : buffers) {
    child_shapes.push_back(child_buffer->on_host_shape());
    std::shared_ptr<TpuSharedBuffer> child_device_buffer =
        child_buffer->DeviceBuffer();
    // Merge all definition events from all children, so that anyone using this
    // tuple must wait for all its children to finish receiving transfers. This
    // works recursively up a nested tuple tree as well.
    for (std::shared_ptr<tpu_driver::Event> child_event :
         child_device_buffer->wait_for_use) {
      child_events.push_back(std::move(child_event));
    }
    child_handle_ptrs.push_back(child_device_buffer->handle.get());
    child_device_buffers.push_back(std::move(child_device_buffer));
  }

  Shape tuple_shape = ShapeUtil::MakeTupleShape(child_shapes);
  std::unique_ptr<tpu_driver::BufferHandle> tuple_handle =
      client->driver()->AllocateTuple(
          device->id(), tpu_driver::MemoryRegion::HBM, child_handle_ptrs, {});
  auto tuple_device_buffer = std::make_shared<TpuSharedBuffer>(
      client->driver(), std::move(tuple_handle), std::move(child_events),
      std::move(device));
  return absl::make_unique<PyTpuBuffer>(
      tuple_shape, std::move(tuple_device_buffer),
      std::move(child_device_buffers), std::move(client));
}

PyTpuBuffer::PyTpuBuffer(
    Shape on_host_shape, std::shared_ptr<TpuSharedBuffer> device_buffer,
    std::vector<std::shared_ptr<TpuSharedBuffer>> child_buffers,
    std::shared_ptr<PyTpuClient> client)
    : client_(std::move(client)),
      on_host_shape_(std::move(on_host_shape)),
      device_(device_buffer->device),
      device_buffer_(std::move(device_buffer)),
      child_buffers_(std::move(child_buffers)) {}

void PyTpuBuffer::Delete() {
  absl::MutexLock lock(&mu_);
  device_buffer_ = nullptr;
  child_buffers_.clear();
  host_value_ = nullptr;
}

Status PyTpuBuffer::CopyToHostAsync() {
  std::vector<std::shared_ptr<tpu_driver::Event>> transfer_events;
  std::shared_ptr<HostValue> host_value = std::make_shared<HostValue>();

  {
    absl::MutexLock lock(&mu_);
    if (!device_buffer_) {
      return InvalidArgument("CopyToHostAsync() called on invalid buffer.");
    }

    if (host_value_) {
      // The host value has already been requested or is available.
      return Status::OK();
    }

    host_value->value = std::make_shared<Literal>(on_host_shape_);
    host_value->pending_ops = std::max(1ul, child_buffers_.size());
    host_value_ = host_value;

    std::vector<tpu_driver::Event*> events;
    for (const auto& e : device_buffer_->wait_for_use) {
      events.push_back(e.get());
    }

    VLOG(1) << "CopyToHostAsync:: host shape: "
            << host_value->value->shape().DebugString();

    if (!on_host_shape_.IsTuple()) {
      CHECK(child_buffers_.empty());
      transfer_events.push_back(client_->driver()->TransferFromDevice(
          device_buffer_->handle.get(), host_value->value->untyped_data(),
          events));
    } else {
      for (int i = 0; i < child_buffers_.size(); ++i) {
        auto& c = child_buffers_[i];
        transfer_events.push_back(client_->driver()->TransferFromDevice(
            c->handle.get(),
            host_value->value->untyped_data(xla::ShapeIndex({i})), events));
      }
    }
  }

  for (auto& t : transfer_events) {
    t->AddCallback([host_value](const xla::Status& status) {
      VLOG(1) << "Device to host transfer finished.";
      if (!status.ok()) {
        host_value->status =
            Status(static_cast<tensorflow::error::Code>(status.code()),
                   status.error_message());
      }

      absl::MutexLock m(&host_value->mutex);
      --host_value->pending_ops;
      if (host_value->pending_ops == 0) {
        VLOG(1) << "Host value done: " << host_value->status;
        host_value->ready.Notify();
      }
    });
  }
  return Status::OK();
}

StatusOr<std::shared_ptr<Literal>> PyTpuBuffer::ToLiteral() {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::ToLiteral");
  TF_RETURN_IF_ERROR(CopyToHostAsync());

  mu_.Lock();
  std::shared_ptr<HostValue> host_value = host_value_;
  mu_.Unlock();

  VLOG(1) << "Waiting for device to host transfer " << host_value.get();
  host_value->ready.WaitForNotification();
  VLOG(1) << "Host copy finished, status:" << host_value->status;
  TF_RETURN_IF_ERROR(host_value->status);

  return host_value->value;
}

std::shared_ptr<TpuSharedBuffer> PyTpuBuffer::DeviceBuffer() const {
  absl::MutexLock lock(&mu_);
  return device_buffer_;
}

StatusOr<std::vector<std::unique_ptr<PyTpuBuffer>>>
PyTpuBuffer::DestructureTuple() {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::DestructureTuple");
  if (!on_host_shape_.IsTuple()) {
    return InvalidArgument(
        "Attempted to destructure a PyTpuBuffer that did not have a tuple "
        "shape; shape: %s.",
        ShapeUtil::HumanString(on_host_shape_));
  }
  if (DeviceBuffer() == nullptr) {
    return InvalidArgument("Attempted to destructure a deleted buffer.");
  }

  absl::MutexLock lock(&mu_);
  int num_children = ShapeUtil::TupleElementCount(on_host_shape_);
  std::vector<std::unique_ptr<PyTpuBuffer>> results;
  results.reserve(num_children);
  for (int i = 0; i < num_children; ++i) {
    results.push_back(absl::make_unique<PyTpuBuffer>(
        on_host_shape_.tuple_shapes(i), child_buffers_.at(i),
        std::vector<std::shared_ptr<TpuSharedBuffer>>(), client_));
  }
  return results;
}

StatusOr<std::unique_ptr<PyTpuBuffer>> PyTpuBuffer::CopyToDevice(
    std::shared_ptr<PjRtDevice> dst_device) {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::CopyToDevice");
  if (on_host_shape_.IsTuple()) {
    return Unimplemented("CopyToDevice for tuples is not supported.");
  }

  std::shared_ptr<TpuSharedBuffer> src_device_buffer = DeviceBuffer();
  if (dst_device->id() == device_->id()) {
    return absl::make_unique<PyTpuBuffer>(
        on_host_shape_, src_device_buffer,
        std::vector<std::shared_ptr<TpuSharedBuffer>>(), client_);
  }

  tpu_driver::TpuDriver* driver = client_->driver();
  TF_ASSIGN_OR_RETURN(
      std::unique_ptr<PyTpuBuffer> dst_buffer,
      CreateBuffer(
          on_host_shape_,
          [driver, src_device_buffer](tpu_driver::BufferHandle* dst_handle) {
            std::vector<tpu_driver::Event*> src_wait_for_use;
            for (auto& event : src_device_buffer->wait_for_use) {
              src_wait_for_use.push_back(event.get());
            }
            return driver->TransferFromDeviceToDevice(
                src_device_buffer->handle.get(), dst_handle, src_wait_for_use);
          },
          client_, std::move(dst_device)));
  // TODO(jiawenhao): This may be too pessimistic: it prevents future readers
  // from reading `src_device_buffer` until the device-to-device copy is done.
  // Should this go into a new `TpuSharedBuffer::wait_for_dealloc` field?
  auto& wait_for_use = dst_buffer->DeviceBuffer()->wait_for_use;
  src_device_buffer->wait_for_use.insert(src_device_buffer->wait_for_use.end(),
                                         wait_for_use.begin(),
                                         wait_for_use.end());
  return dst_buffer;
}

Status PyTpuBuffer::BlockHostUntilReady() {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::BlockHostUntilReady");
  std::shared_ptr<TpuSharedBuffer> device_buffer = DeviceBuffer();
  if (!device_buffer) {
    return InvalidArgument(
        "BlockHostUntilReady() called on deleted or donated buffer");
  }
  return device_buffer->handle->OnReady()->Await();
}

/* static */
StatusOr<std::unique_ptr<PyTpuBuffer>> PyTpuBuffer::AllocateBuffer(
    const Shape& shape, std::shared_ptr<PyTpuClient> client,
    std::shared_ptr<PjRtDevice> device) {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::AllocateBuffer");
  VLOG(1) << "PyTpuBuffer::AllocateBuffer: shape: " << shape.DebugString()
          << " device: " << device->DebugString();

  if (!shape.IsTuple()) {
    return CreateBuffer(shape, absl::nullopt, std::move(client),
                        std::move(device));
  }

  std::vector<std::unique_ptr<PyTpuBuffer>> child_buffers;
  child_buffers.reserve(shape.tuple_shapes().size());
  std::vector<PyTpuBuffer*> child_buffer_ptrs;
  child_buffer_ptrs.reserve(shape.tuple_shapes().size());

  for (const auto& child_shape : shape.tuple_shapes()) {
    TF_ASSIGN_OR_RETURN(std::unique_ptr<PyTpuBuffer> child_buffer,
                        AllocateBuffer(child_shape, client, device));
    child_buffer_ptrs.push_back(child_buffer.get());
    child_buffers.push_back(std::move(child_buffer));
  }

  // `MakeTuple` will extract and make the tuple buffer hold onto the
  // `device_buffer_` contained in each `child_buffer`, so it's safe for
  // `child_buffers` to get destroyed before this call returns.
  return PyTpuBuffer::MakeTuple(child_buffer_ptrs, std::move(client),
                                std::move(device));
}

/*static*/
StatusOr<std::unique_ptr<PyTpuBuffer>> PyTpuBuffer::CreateBuffer(
    const Shape& non_tuple_shape, absl::optional<BufferInitializer> initializer,
    std::shared_ptr<PyTpuClient> client, std::shared_ptr<PjRtDevice> device) {
  tensorflow::profiler::TraceMe traceme("PyTpuBuffer::CreateBuffer");
  VLOG(1) << "PyTpuBuffer::CreateBuffer: shape: "
          << non_tuple_shape.DebugString()
          << " device: " << device->DebugString();
  TF_RET_CHECK(!non_tuple_shape.IsTuple());
  TF_RETURN_IF_ERROR(CheckDataType(non_tuple_shape.element_type()));

  std::unique_ptr<tpu_driver::BufferHandle> handle =
      client->driver()->Allocate(device->id(), tpu_driver::MemoryRegion::HBM,
                                 non_tuple_shape.ToProto(), {});

  // If this buffer needs to be initialized, anyone using this buffer must wait
  // for the initialization event in `wait_for_use` to finish first.
  std::vector<std::shared_ptr<tpu_driver::Event>> wait_for_use;
  if (initializer.has_value()) {
    std::shared_ptr<tpu_driver::Event> init = initializer.value()(handle.get());
    wait_for_use.push_back(std::move(init));
  }
  auto device_buffer = std::make_shared<TpuSharedBuffer>(
      client->driver(), std::move(handle), std::move(wait_for_use),
      std::move(device));

  return absl::make_unique<PyTpuBuffer>(
      non_tuple_shape, std::move(device_buffer),
      std::vector<std::shared_ptr<TpuSharedBuffer>>(), client);
}

static std::shared_ptr<PjRtDevice> LookupDevice(const PyTpuClient& client,
                                                int device_id) {
  auto it = client.id_to_device().find(device_id);
  CHECK(it != client.id_to_device().end())
      << "Unknown device id: " << device_id;
  return it->second;
}

PyTpuExecutable::PyTpuExecutable(
    std::unique_ptr<tpu_driver::CompiledProgramHandle> compiled_program,
    DeviceAssignment device_assignment, std::shared_ptr<PyTpuClient> client,
    xla::Shape result_shape, bool tuple_arguments)
    : client_(std::move(client)),
      device_assignment_(std::move(device_assignment)),
      tuple_arguments_(tuple_arguments),
      result_shape_(std::move(result_shape)) {
  VLOG(1) << "DeviceAssignment. " << device_assignment_.ToString();
  const int num_replicas = device_assignment_.replica_count();
  const int num_partitions = device_assignment_.computation_count();
  CHECK_EQ(num_partitions, 1) << "partition count > 1 is not supported.";
  for (int replica = 0; replica < num_replicas; ++replica) {
    for (int partition = 0; partition < num_partitions; ++partition) {
      int device_id = device_assignment_(replica, partition);
      std::shared_ptr<PjRtDevice> device = LookupDevice(*client_, device_id);
      if (device->process_index() != client_->process_index()) {
        VLOG(3) << "Non-local device: " << device_id;
        continue;
      }
      // TODO(b/147895917): support replica + partition natively.
      CHECK(executables_.find(replica) == executables_.end())
          << "Inserting duplicate replica:" << replica;
      executables_[replica] =
          client_->driver()->LoadProgram(device_id, compiled_program.get(), {});
      local_logical_device_ids_.emplace_back(replica, partition);
      local_devices_.push_back(device);
    }
  }
  CHECK_GE(local_devices_.size(), 1);
  CHECK_LE(executables_.size(), client_->device_count());
  CHECK_LE(local_devices_.size(), client_->local_device_count())
      << "Inconsistent local device count.";
}

PyTpuExecutable::ExecuteResult PyTpuExecutable::ExecuteHelper(
    absl::Span<const std::vector<PyTpuBuffer*>> maybe_tupled_args,
    absl::Span<PyTpuBuffer* const> this_core_arguments, int replica,
    int partition, const RunId& run_id) {
  const int device_id = device_assignment_(replica, partition);
  std::shared_ptr<PjRtDevice> device = LookupDevice(*client_, device_id);
  CHECK_EQ(device->process_index(), client_->process_index());
  tensorflow::profiler::TraceMe traceme("PyTpuExecutable::Execute");
  VLOG(3) << "Replica " << replica << ", partition " << partition
          << " mapped to device id for execution: " << device_id;

  std::unique_ptr<::xla::PyTpuBuffer> output_buffer =
      ::xla::PyTpuBuffer::AllocateBuffer(result_shape_, client_,
                                         std::move(device))
          .ValueOrDie();
  VLOG(1) << "Created output buffer: " << result_shape_.DebugString();

  std::vector<tpu_driver::BufferHandle*> inputs;
  std::vector<tpu_driver::Event*> ready_to_execute;

  std::shared_ptr<tpu_driver::Event> output_buffer_ready =
      output_buffer->DeviceBuffer()->handle->OnReady();

  ready_to_execute.push_back(output_buffer_ready.get());

  for (auto* input_handle : this_core_arguments) {
    inputs.push_back(input_handle->DeviceBuffer()->handle.get());
  }

  for (const auto& core_args : maybe_tupled_args) {
    for (const auto* handle : core_args) {
      for (const auto& pending_event : handle->DeviceBuffer()->wait_for_use) {
        ready_to_execute.push_back(pending_event.get());
      }
    }
  }

  xla::DeviceAssignmentProto device_assignment;
  CHECK(device_assignment_.Serialize(&device_assignment).ok());
  std::shared_ptr<tpu_driver::Event> on_execute_finished =
      client_->driver()->ExecuteProgram(
          executables_.find(replica)->second.get(), inputs,
          {output_buffer->DeviceBuffer()->handle.get()}, device_assignment,
          {ready_to_execute});

  return {std::move(output_buffer), std::move(on_execute_finished)};
}

// Delay before warning about a slow execute call.
static const absl::Duration kWarnExecutionDelay = absl::Seconds(10);

// Delay before terminating a stalled execute call.
static const absl::Duration kMaxExecutionDelay = absl::Minutes(60);

Status WaitForExecuteEvent(tpu_driver::Event* event) {
  absl::optional<Status> opt_status;
  auto start_time = absl::Now();

  while (!opt_status.has_value() &&
         absl::Now() - start_time < kMaxExecutionDelay) {
    opt_status = event->AwaitWithTimeout(kWarnExecutionDelay);
    if (!opt_status.has_value()) {
      LOG(WARNING)
          << "TPU Execute is taking a long time. This might be due to a "
             "deadlock between multiple TPU cores or a very slow program.";
    }
  }

  if (!opt_status.has_value()) {
    return tensorflow::errors::DeadlineExceeded(
        absl::StrFormat("TPU program took more than %d seconds to complete.",
                        absl::ToInt64Seconds(kMaxExecutionDelay)));
  }

  return opt_status.value();
}

StatusOr<std::vector<std::unique_ptr<PyTpuBuffer>>> PyTpuExecutable::Execute(
    absl::Span<PyTpuBuffer* const> argument_handles) {
  if (num_replicas() != 1) {
    return InvalidArgument(
        "Attempted to execute computation with %d replicas using Execute().",
        num_replicas());
  }
  if (num_partitions() != 1) {
    return InvalidArgument(
        "Attempted to execute computation with %d partitions using Execute().",
        num_partitions());
  }

  std::vector<PyTpuBuffer*> maybe_tupled_args;
  std::unique_ptr<PyTpuBuffer> tupled_arguments;
  if (tuple_arguments_) {
    TF_ASSIGN_OR_RETURN(tupled_arguments,
                        PyTpuBuffer::MakeTuple(argument_handles, client_,
                                               local_devices_.front()));
    maybe_tupled_args = {tupled_arguments.get()};
  } else {
    maybe_tupled_args = std::vector<PyTpuBuffer*>(argument_handles.begin(),
                                                  argument_handles.end());
  }
  ExecuteResult result =
      ExecuteHelper(absl::MakeSpan(&maybe_tupled_args, 1), maybe_tupled_args,
                    /*replica=*/0, /*partition=*/0, RunId());

  Status status = WaitForExecuteEvent(result.on_execute_finished.get());

  if (!status.ok()) {
    LOG(ERROR) << "Failed to execute program: " << status;
    return status;
  }

  if (result.buffer->on_host_shape().IsTuple()) {
    return result.buffer->DestructureTuple();
  } else {
    std::vector<std::unique_ptr<PyTpuBuffer>> outputs;
    outputs.push_back(std::move(result.buffer));
    return outputs;
  }
}

StatusOr<std::vector<std::vector<std::unique_ptr<PyTpuBuffer>>>>
PyTpuExecutable::ExecuteOnLocalDevices(
    absl::Span<const std::vector<PyTpuBuffer*>> argument_handles) {
  tensorflow::profiler::TraceMe traceme(
      "PyTpuExecutable::ExecuteOnLocalDevices");

  const int num_local_devices = local_devices_.size();

  if (argument_handles.size() != num_local_devices) {
    return InvalidArgument(
        "Attempted to execute with %d argument lists when local device "
        "count is %d (total replica count: %d, partition count: %d).",
        argument_handles.size(), num_local_devices, num_replicas(),
        num_partitions());
  }

  VLOG(1) << "Executing computation; num_replicas=" << num_replicas()
          << " num_partitions=" << num_partitions()
          << " num_local_devices=" << num_local_devices;

  std::vector<std::unique_ptr<PyTpuBuffer>> tupled_arguments;
  std::vector<std::vector<PyTpuBuffer*>> tupled_argument_pointers;
  if (tuple_arguments_) {
    tupled_arguments.resize(argument_handles.size());
    tupled_argument_pointers.resize(argument_handles.size());
    for (int i = 0; i < num_local_devices; ++i) {
      TF_ASSIGN_OR_RETURN(tupled_arguments[i],
                          PyTpuBuffer::MakeTuple(argument_handles[i], client_,
                                                 local_devices_.at(i)));
      tupled_argument_pointers[i] = {tupled_arguments[i].get()};
    }
    argument_handles = tupled_argument_pointers;
  }

  absl::Mutex results_lock;
  std::vector<ExecuteResult> results(num_local_devices);

  auto* thread_pool = client_->GetThreadPool();

  int failed = 0;
  Status first_failure_status;

  xla::Semaphore execute_semaphore(0);
  for (int i = 0; i < num_local_devices; ++i) {
    // We are scheduling Execute on a thread pool as ExecuteHelper can take a
    // long time and we want all cores to be scheduled in parallel.
    thread_pool->Schedule([this, i, argument_handles, &results, &results_lock,
                           &execute_semaphore]() {
      const int replica = local_logical_device_ids_[i].first;
      const int partition = local_logical_device_ids_[i].second;
      RunId run_id;
      auto result = ExecuteHelper(argument_handles, argument_handles[i],
                                  replica, partition, run_id);
      results[i] = std::move(result);
      execute_semaphore.Release(1);
    });
  }

  execute_semaphore.Acquire(num_local_devices);

  for (int i = 0; i < num_local_devices; ++i) {
    auto s = WaitForExecuteEvent(results[i].on_execute_finished.get());
    if (!s.ok()) {
      if (failed == 0) {
        first_failure_status = Status(
            static_cast<tensorflow::error::Code>(s.code()), s.error_message());
      }
      ++failed;
    }
  }
  if (failed > 0) {
    return first_failure_status;
  }
  VLOG(1) << "Replicated execution complete.";

  std::vector<std::vector<std::unique_ptr<PyTpuBuffer>>> wrapped_results(
      num_local_devices);
  for (int i = 0; i < num_local_devices; ++i) {
    if (results[i].buffer->on_host_shape().IsTuple()) {
      TF_ASSIGN_OR_RETURN(wrapped_results[i],
                          results[i].buffer->DestructureTuple());
    } else {
      wrapped_results[i].push_back(std::move(results[i].buffer));
    }
  }
  return wrapped_results;
}

StatusOr<std::vector<std::vector<std::unique_ptr<PyTpuBuffer>>>>
PyTpuExecutable::ExecuteShardedOnLocalDevices(
    absl::Span<const std::vector<PyTpuBuffer*>> args) {
  std::vector<std::vector<std::unique_ptr<PyTpuBuffer>>> output_buffers;
  TF_RET_CHECK(!args.empty());
  int num_computations = args.front().size();
  for (const auto& arg : args) {
    if (arg.size() != num_computations) {
      return xla::InvalidArgument(
          "Expected args to execute_sharded_on_local_devices to have %d "
          "shards, got: [%s]",
          num_computations,
          absl::StrJoin(
              args, ", ",
              [](std::string* out, const std::vector<PyTpuBuffer*>& arg) {
                out->append(std::to_string(arg.size()));
              }));
    }
  }
  std::vector<std::vector<PyTpuBuffer*>> arg_buffers(num_computations);
  for (int computation = 0; computation < num_computations; ++computation) {
    arg_buffers[computation].resize(args.size());
    absl::c_transform(
        args, arg_buffers[computation].begin(),
        [&](const std::vector<PyTpuBuffer*>& arg) { return arg[computation]; });
  }
  TF_ASSIGN_OR_RETURN(output_buffers, ExecuteOnLocalDevices(arg_buffers));
  int num_output_buffers = output_buffers[0].size();
  std::vector<std::vector<std::unique_ptr<PyTpuBuffer>>> outputs;
  outputs.resize(num_output_buffers);
  for (int buffer_id = 0; buffer_id < num_output_buffers; ++buffer_id) {
    outputs[buffer_id].reserve(num_computations);
    for (int computation = 0; computation < num_computations; ++computation) {
      outputs[buffer_id].push_back(
          std::move(output_buffers[computation][buffer_id]));
    }
  }
  return outputs;
}

/*static*/ StatusOr<std::unique_ptr<PyTpuExecutable>> PyTpuExecutable::Compile(
    const XlaComputation& computation,
    absl::optional<std::vector<Shape>> argument_layouts,
    const ExecutableBuildOptions* build_options,
    std::shared_ptr<PyTpuClient> client, bool tuple_arguments) {
  tensorflow::profiler::TraceMe traceme("PyTpuExecutable::Compile");

  VLOG(1) << "Compile: "
          << computation.GetProgramShape().ValueOrDie().DebugString();

  // TODO(power) -- handle argument layouts
  // TODO(power) -- handle build options
  ExecutableBuildOptions options;
  if (build_options != nullptr) {
    options = *build_options;
  }
  absl::optional<xla::DeviceAssignment> device_assignment;

  // For POD use case, the device_assignment.num_replicas() may be greater than
  // the number of available local devices, where applicable the non-local
  // devices must be filtered out from participating local computation.
  if (options.has_device_assignment()) {
    if (options.device_assignment().replica_count() != options.num_replicas()) {
      return InvalidArgument(
          "Mismatched number of replicas for device "
          "assignment and computation (%d vs %d).",
          options.device_assignment().replica_count(), options.num_replicas());
    } else if (options.device_assignment().computation_count() != 1) {
      return Unimplemented(
          "Only 1 computation per replica supported, %d requested.",
          options.device_assignment().computation_count());
    }
    device_assignment = options.device_assignment();
  } else {
    TF_ASSIGN_OR_RETURN(device_assignment,
                        client->GetDefaultDeviceAssignment(
                            options.num_replicas(), options.num_partitions()));
  }
  CHECK_GE(options.num_replicas(), 1);
  CHECK_EQ(options.num_replicas(), device_assignment->replica_count());
  CHECK(!argument_layouts.has_value());

  // TODO(henrytan): an area for optimization with less buffer copy.
  xla::HloProto hlo_proto;
  *hlo_proto.mutable_hlo_module() = computation.proto();

  // TODO(henrytan): in the future, we want to consider argument Layout
  // information e.g. for linearization.
  std::unique_ptr<tpu_driver::CompiledProgramHandle> compiled_program =
      client->driver()->CompileProgram(hlo_proto, options.num_replicas(), {});

  ::xla::Shape result_layout;
  if (options.result_layout()) {
    result_layout = *options.result_layout();
  } else {
    xla::ProgramShapeProto program_shape_proto;
    auto fetch_metadata_status =
        compiled_program->program_shape(&program_shape_proto);

    if (!fetch_metadata_status.ok()) {
      return Status(
          static_cast<tensorflow::error::Code>(fetch_metadata_status.code()),
          fetch_metadata_status.error_message());
    }
    result_layout = ::xla::Shape(program_shape_proto.result());
  }
  VLOG(1) << "Got result shape: " << result_layout.DebugString();

  return absl::make_unique<PyTpuExecutable>(
      std::move(compiled_program), std::move(*device_assignment),
      std::move(client), std::move(result_layout), tuple_arguments);
}

/*static*/ StatusOr<std::unique_ptr<PyTpuExecutable>>
PyTpuExecutable::CompileMlir(
    mlir::ModuleOp module, absl::optional<std::vector<Shape>> argument_layouts,
    const ExecutableBuildOptions* build_options,
    std::shared_ptr<PyTpuClient> client, bool tuple_arguments) {
  XlaComputation xla_computation;
  TF_RETURN_IF_ERROR(MlirToXlaComputation(module, xla_computation,
                                          /*use_tuple_args=*/tuple_arguments,
                                          /*return_tuple=*/false));
  return Compile(xla_computation, argument_layouts, build_options, client,
                 tuple_arguments);
}

}  // namespace xla

redpajama_set_name: RedPajamaGithub


I currently have an Iphone 4 and won't be upgrading in the near future. If I would not be able to sync to a bluetooth device on my workouts, would this even be an appropriate purchase right? Or is it a better idea to buy a HR monitor that is less expensive?
Thanks for your help. Hope this question makes sense. To see more info please visit http://essayhogwarts.com/custom-essay/.


text:
From the January 2005 Issue Subscribe
Working Girls
By Kimberly Jeffries
In this month's feature "'She Had Brains, a Body, and the Ability to Make Men Love Her,'" associate editor Katy Vine delves into the events in Odessa that led to one of the most notorious prostitution-ring busts in Texas history. Here, she discusses getting prostitutes, madams, and police investigators to open up to her.
texasmonthly.com: When and how did you first learn of the events in Odessa?
Katy Vine: I read about the events in one of the bigger papers—the Dallas Morning News, I think—right after the madams were arrested.
texasmonthly.com: How long did you work on this assignment? Did you spend a lot of time in Odessa? How did the residents react to your presence?
KV: Beginning in August, I took a few short trips to Odessa to interview subjects and talk to local folks. Odessans were all very welcoming. I'd been to the city a few times before, and I always found the people to be frank, nonjudgmental, and incredibly friendly.
texasmonthly.com: The prostitution bust seems like it would be a very sore subject for the accused to talk about, as well as a sensitive one for the police. How did you get your sources to speak so candidly with you?
KV: The prostitutes and madams felt misunderstood, and they resented some of the hypocrisy of those who considered them scum. They wanted people to know that they were not bad people and that they didn't mean to hurt anybody. We talked about that a lot. I think each woman from the Healing Touch parlor wanted to explain her role and the situation as she saw it. The police officers wanted to be sure their side was heard because they received some heat from the press. Some critics said the police department was too slow and overly selective with the list of johns.
texasmonthly.com: Were there any sources, such as clients or wives, you wanted to talk to who wouldn't agree to go on the record? If so, where did you turn for the information you wanted?
KV: I called a few of the johns when I started working on the story, but the phone calls to their homes had too much potential to hurt people who were already having difficulties. What if a wife or a child picked up the phone? What would I say? I finally decided that I didn't have to speak to the men. I had spoken to almost everyone who had ever worked at Healing Touch, and I had the information I needed.
texasmonthly.com: Prostitution-ring busts by the police are common occurrences. What sets this case apart from the rest? Is it because drugs were involved, or was there something else that made this case special?
KV: According to the police, Crime Stoppers was overwhelmed with calls about the suspicious activities taking place at the massage parlor.
texasmonthly.com: Executive editor Skip Hollandsworth received some angry feedback from readers after "Good Vibrations," a story about a woman who sold sex toys in Burleson, was published in the October 2004 issue. Are you worried about readers' reactions to your story? What are your thoughts on publishing stories in Texas Monthly that deal with sexual issues—are they just like covering other subjects, or do they require special care?
KV: Well, my story does involve sex, but I wouldn't describe it as racy. I may be wrong, but I think people would be more upset to learn about a woman selling vibrators in a conservative community than they would be to learn about the Healing Touch's prostitutes playing Yahtzee while they waited for johns. I tried to remain as sensitive to the issues in this story as I would any other.
texasmonthly.com: Have you been keeping up with the trial proceedings? What's the latest update on the outcomes and the sentencing considerations?
KV: Kathy and Sharon Joyner received a year and a day for the federal drug offenses and two years for the state prostitution charges. Janet Elaine Lietz (the owner of Middessa Therapy) is set for trial December 14. The women and men facing the class B misdemeanor for prostitution ought to have wrapped up their cases by the end of January.
It's Time to Celebrate Taco Week


text:
Q: Azure DevOps: How to set the value of the Variable in Variable Group I am trying to overwrite the value of the variable from Variable Group in Azure DevOps and it's not working.  It's always showing the original value.
I wrote my Powershell scripts as shown by these links:

*

*Microsoft

*StackOverflow
I added the Variable Group and Link it in my Build pipeline.

I wrote the following scripts in Power Shell Script task.
Write-Host "Original BPOwner = $(BPOwner)"

Write-Host "Changing value of BPOwner to Bright Ran"
Write-Host "##vso[task.setvariable variable=BPOwner;]Bright Ran"

Write-Host "New BPOwner = $(BPOwner)"

However, in the Build, it's always showing the original value and it's never changed to the value I want to set.

Could you please suggest me how I could set this value in the Build Pipeline?

A: The new value available only in the next tasks, not in the same task when you change the value. for example, I added another PS task with Write-Host "New BPOwner = $(BPOwner)":

The above it's the behavior of the logging command ##vso[task.setvariable variable] and not only to the variable group.

redpajama_set_name: RedPajamaStackExchange


text:
Morning update: Heavy traffic on A1 and around Vicarage Road
Heavy traffic on the A1 (Barnet Way)
Here is your morning travel and weather update for the final day of the working week.
Roads are looking clearer than usual this morning. Although heavy traffic is disrupting journeys along the A4178 heading towards Vicarage Road Stadium. It is slowly moving, but travel time through the area could be longer than usual.
There is also heavy traffic queuing on the A1 (Barnet Way) heading southbound towards apex corner.
Also expect slow moving traffic on the A41 heading southbound at M25 J20 (Hemel Hempstead/Watford). Small delays are expected but normal traffic conditions should resume in due course.
There is also heavy traffic in Woodford on the A406 heading towards Redbridge and small delays are to be expected.
Small congestion is also affecting traffic on the A1000 High Street (Barnet), although is starting to move at the A1081 in St Albans Road.
There is also queuing traffic on the A5 Edgware Road (Burnt Oak Broadway) at Deansbrook Road at the Territorial Army traffic lights – and small delays are expected.
There is currently no disruption on any of the lines at the moment, with good service running across the Tube.
Spells of sunshine are expected throughout the morning, with highs of 25c expected today. But showers are expected to develop in the afternoon and low cloud could be around for most of the day.
Regeneration plans to be put to a vote
A second teenager has been arrested in relation to the Preston Park double stabbing
Private childcare's quality of education and support seen as 'outstanding' by Ofsted
Knife crime and domestic violence among council's community safety priorities
A third arrest has been made in connection to Wembley shooting
Morning update: Heavy traffic on M25 and A406
Council urged to reject definition of Islamophobia
There should be a register of domestic abusers, says London Assembly


We are now at the advanced level of teaching with an iPad and it's a perfect time for you to learn to create your own custom content and share it with your class. This content creation in the form of creating your own book will put you in the driving seat and give you great command over your class. Till now, we discussed downloading and reading books on the iPad, but in this recipe you will learn to create, share, and publish your own books that can be read on your iPad.


.: Technotrade Engg Co. :.
Welcome to Technotrade Engg. Co.
Since our inception in 1962 as a small manufacturing company in the field of Scientific Instruments, we are today one of the leading suppliers of all types of Instruments. With a team of dedicated Engineers, skilled worker and Enterprising Marketing Executives, we ensure the best quality of Products and timely delivery.
Over the years, we have successfully supplied materials to various Government Organisation & OEM's. We also have a wide range of dealers and suppliers. Some of our esteemed clients include Railway, NTPC, TISCO, Kesoram Rayon, Laopala, Balarampur Chini Mills, AIMIL etc. Our range of dealers include M/S Hiten Bros (Mumbai), M/S Bharat Educational Stores (Delhi), M/S Lab Equipments & Chemicals (kolkata), M/S Testing Instruments Manufacturing Co (kolkata).
Besides marketing Instruments manufactured by us under the brand name of Truheat, we are also selling instruments of such well known brands as Zeal, Braigo, Huger, Raytek, Lutron, Sunvic, EGO, Philips, Mitutoyo, CIE, TES.


A GIANT, 7-foot hoodwinker sunfish washed ashore in California this week! The fish certainly looks odd and is a loooong way from it's native waters. The fish has never been seen in North American waters and can usually be found in Australia, New Zealand, South Africa and Chile.
A typical sunfish can grow to 10 feet long and weigh up to TWO TONS!


text:
Aleyrodes latus es un hemíptero de la familia Aleyrodidae, con una subfamilia: Aleyrodinae.

Fue descrita científicamente por primera vez por Hempel en 1922.

Referencias

latus

redpajama_set_name: RedPajamaWikipedia


So this morning i wanted to share with you something a little different - it may look like a beautiful, open plan apartment-office, but this is in fact the interior of HAY store in Copenhagen! Look at all the beautiful woods and pinks!
I've still not managed to visit one of their stores, despite having featured them before in a post but i just love their styling. You can see lots more beautiful photos like where this one is from over at Joelix.com.


Get the gang together for a real-deal summer holiday. We'll supply the beach pass, the picnic + the lounge chairs, a spot to keep your bevvies cool, plus your overnight stay. All you have to remember is the sunscreen.
*Available June through Sept, 2019 for new reservations. 2 night min stay required. Not applicable to groups, corporate-negotiated, or 3rd party rates. Not valid with other promotion or offers. Subject to availability + blackout dates. Taxes + gratuities not included.
Explore the County by day, taking plenty of Polaroid memories as you go. Then enjoy an incredible lunch or dinner with drinks at our award-winning, lakeside dining room at Drake Devonshire. Wrap up your dreamy outing in PEC back at Drake Motor Inn for the night.
*This limited-time offer is available for new reservations. Not applicable to groups, corporate-negotiated, or 3rd party rates. Cannot be combined with any other promotion or offers. Subject to availability + blackout dates. Taxes + gratuities are not included.
Drake picnic basket service $20 per person. Perfect for sunny day snacking at the beach, or lunching while afternoon winery touring. Our picnic menu options change regularly, so we'll share our current food & drink options with you to choose from at the time of booking.
++Anything else you can dream up!


The Sour Service Award goes to Hola Café in Plettenberg Bay. I had such good memories of the coffee shop that operated there before, now it is an Internet café, more than half of the interior bring a computer shop! The waitress confirmed that the strawberry juice is freshly squeezed on the premises (but there is no kitchen to be seen). The aggressive Argentinian owner came over and said it comes from a bottle, and could I not see it listed under 'Other Juices' on the menu! The heading above is 'Fresh Juices', and strawberry would have been listed there if it is freshly squeezed, she said! I then ordered an orange juice from the Fresh Juices list, and she had to come back to me to say that the juices are seasonal, and oranges are not in season!


text:
Q: AJAX request fails in Firefox, works in IE (server returns 200 in both cases) I am testing locally. I have IIS serving JS and HTML on localhost:50972 and Java/Jersey acting as an application server on localhost:8080.
The following AJAX request succeeds in Internet Explorer, but fails in Chrome and Firefox, even though the server shows 200 OK:
public getTest() {
    var settings: JQueryAjaxSettings = {
        url: "http://localhost:8080/getData",
        type: "GET",
        crossDomain: true,
        dataType: "text",
    };

    jQuery.ajax(settings).done(function (o) {
        alert(o);
    }).fail(function (request) {
        alert(request);
    });
}

The code on the Java side looks like this:
@GET
@Path("/getData")
public Response getData() {

    NewCookie cookie = new NewCookie("test", "key:val", "/", null, "comment", 100, false );
    return Response.status(Response.Status.OK).entity("Hello World").cookie(cookie).build();
}

Below are the relevant HTTP Requests/Responses from IE and Firefox:
Internet Explorer Request (Succeeds)
GET http://localhost:8080/getData?_=1451863561652 HTTP/1.1
Referer: http://localhost:50972/
Accept: text/plain, */*; q=0.01
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
DNT: 1
Host: localhost:8080

Firefox Request (Fails)
GET http://localhost:8080/getData?_=1451863686206 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/plain, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:50972/
Origin: http://localhost:50972
Connection: keep-alive

Response from server (sent to both)
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: test=key:val;Version=1;Comment=comment;Path=/
Content-Type: text/plain
Content-Length: 11
Date: Sun, 03 Jan 2016 23:26:07 GMT

Hello World

I have also tried this with the response as {} and dataType: json instead of Hello World and dataType: text, but with no change. I have also tried with crossDomain: true and with crossDomain: false Help?

A: The observed behavior is because Firefox (and Chrome, etc.) correctly consider a different port to establish a different origin; IE does not.
See MDN - Same Origin Policy:

Two pages have the same origin if the protocol, port (if one is specified), and host are the same for both pages..
..[but] IE doesn't include port into Same Origin components, therefore http://company.com:81/index.html and http://company.com/index.html are considered from same origin and no restrictions are applied.

Use CORS - enabled on the server - for the request to succeed in all browsers.


text:
Rising weekend temps could result in fog, icy roads
Ken DeCoster Staff writer @DeCosterKen
ROCKFORD — The arctic cold that hammered the Midwest this week is finally giving way to rising temperatures and the possibility of a different set of weather-related challenges.
"We're a little concerned about fog as well as some icy conditions because we're coming out of such a bitter cold air mass, the ground is still quite frozen," National Weather Service meteorologist Ben Deubelbeiss said. "The pavement temperatures are going to be below zero even as our temperatures rise above freezing."
Saturday's projected high of 37 degrees in Rockford would mark a swing of 68 degrees from Thursday morning. Temperatures are expected to top 40 degrees on Sunday and Monday.
Rockford hasn't had temperatures above freezing since Jan. 17.
Large temperature swings during the cold season are relatively common for Rockford and the upper Midwest, according to Deubelbeiss.
"The past several days we've been looking at an arctic air mass that had settled over the area, bringing us those bitterly cold temperatures," he said. "Certainly that was a little bit unusual, but now we're moderating back into a more regular pattern here with our air masses originating in the eastern Pacific and coming across the desert southwest into our area."
Temperatures in Rockford were below zero from 4:29 p.m. Tuesday until approximately 2 a.m. Friday, a string of 57 consecutive hours.
That's the ninth-longest such streak for Rockford in 90 years and it included the city's record cold temperature of minus 31 Thursday morning.
"The last time that this sort of thing has happened shows just how rare it is and it speaks to the significance of it," Deubelbeiss said.
In fact, you'd have to go back 23 years for a longer streak of consecutive hours below zero in the Forest City.
The mercury was below zero in Rockford for a record-setting 128 consecutive hours — five days and eight hours — between Jan. 30 and Feb. 5, 1996.
Ken DeCoster: 815-987-1391; kdecoster@rrstar.com; @DeCosterKen


The Hartford Symphony Orchestra's musicians, who were asked to accept a 40 percent cut in pay and benefits cuts by management under threat of a shutdown, agreed to a 36 percent cut—but only after Carolyn Kuan, the music director and conductor, agreed to give up a commensurate proportion of her own salary.
"It has been a privilege to work with the Hartford Symphony musicians, who are not only tremendous artists, but are also passionate, caring and beautiful human beings—on whom I can depend and for whom, I can be there. Together, along with our incredibly dedicated staff, it has been an honor to make a difference in our community. Making a difference: that has been what drives us as an organization, and I have always believed that if we do the right thing—serve the community—support will come.
"In the past five years, we brought awareness to issues of conservation and environment with Life: A Journey through Time. When Governor Malloy talked about Connecticut having a greater presence in China, Yellow River Cantata brought the China Consulate General to our stage, and the news of Hartford Symphony's performances was broadcast throughout China. We actively seek to serve and collaborate with local organizations from The Wadsworth (Coney Island exhibit, Sunday serenades and a variety of other programming), Hartford Stage (A Midsummer Night's Dream), Hartford Chorale, Goodspeed Opera, Nutmeg Ballet, The Hartt School, University of Connecticut, Farmington High School, Arthur Murray Dance Studios and countless others. We perform masterworks as well as introduce world-class artists of unusual instruments such as sheng, koto, kamancheh, bagpipe, beatboxing, and more. In our desire to serve Hartford, Playing with Food was created in response to Mayor Segarra's call for more people to visit downtown restaurants.
"In ways both big and small, and with impacts ranging from artistic to societal, Hartford Symphony makes a difference in our community. It is our highest aspiration to continue our service: we want to do more and we can do more.
"But first we must resolve our present contract challenges.
"Given the urgency of the situation, I want to personally recognize the substantial cuts being asked of the musicians of the HSO and offer publicly to share their sacrifice by reducing my salary commensurately. I had intended to do this privately, but I am hopeful that making this gesture public might help, in a small way, to resolve the present crisis.


A generic image of hot chips.
AUSTRALIA's consumer watchdog has set its sights on two opposing industries that appear to have one thing in common - their franchises are potentially rife with dodgy dealings.
The ACCC will use its auditing powers to ensure that those operating inside both the fitness and fast-food sectors are abiding by the law.
At a convention on Sunday, ACCC Deputy Chairman Dr Michael Schaper said the power would be used to rein in industries that are a common cause of complaint.
"In the ACCC's next round of audits, we will be looking at franchisors from the take-away food and health and fitness industries, however our audits will not be restricted to these two sectors."
The focused scrutiny comes after Dr Schaper told the convention the ACCC received more than 160,000 complaints and queries overall in the past year, which led to 550 investigations, of which 60 ended with either court action or some other enforcement.
The ACCC will also soon call for interest in its franchising consultative committee, an arm of the ACCC that keeps an eye on how it handles franchises.