<commit_before>/**
  * Riassence Core -- http://rsence.org/
  *
  * Copyright (C) 2008 Juha-Jarmo Heinonen <jjh@riassence.com>
  * Copyright (C) 2006 Helmi Technologies Inc.
  *
  * This file is part of Riassence Core.
  *
  * Riassence Core is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * Riassence Core is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  **/

/*** class: HThemeManager
  **
  ** A single instance class.
  **
  ** The theme manager knows the name of the currently loaded theme and handles
  ** the loading of theme specific markup snippets and style declarations.
  **
  ** vars: Instance variables
  **  themePath - Relative path to the components' top directory.
  **  currentTheme - The name of the theme currently in use. Initially the
  **    default unnamed theme is used.
  **  usesComponentDir - True when the components are separated in their own
  **    directories, usually when using the source/development version. False
  **    when the components are all in same directory. This is the case in the
  **    release build.
  **
  ** See also:
  **  <HView> <HMarkupView>
  ***/

HDefaultThemePath = '/H/themes';
HDefaultThemeName = 'default';
HNoComponentCSS = [];
HNoCommonCSS = [];
HThemeHasIE6GifsInsteadOfPng = [];

/** HDefaultThemeMode:
  *
  *  0 = Pre-built mode
  *  1 = Post-built mode
  *
  */
HThemeMode = 1;

HThemeManager = HClass.extend({

  constructor: null,

  init: function(){

    // Default root path of the themes path, should contain at least the default theme.
    this.themePath = HDefaultThemePath;

    // Hash map of loaded template markup (html templates), by theme.
    // componentName is used as the secondary key.
    this._tmplCache = {};

    // Hash map of loaded css templates, by theme.
    // componentName is used as the secondary key.
    this._cssCache = {};

    // The currently selected default theme name.
    this.currentTheme = HDefaultThemeName;
  },

  setThemePath: function( _path ){
    this.themePath = _path;
  },

  // Error messages, should be refined.
  _errTemplateNotFound: function( _url ) {
    console.log( "ERROR: Template Not Found: '" + _url + "' ");
  },
  _errTemplateFailure: function( _url ) {
    console.log( "ERROR: Template Failure: '" + _url + "' ");
  },
  _errTemplateException: function( _url ) {
    console.log( "ERROR: Template Exception: '" + _url + "' ");
  },

/** method: fetch
  *
  * Loads a template file and returns its contents.
  * If errors occurred, calls the error management functions.
  *
  * Parameters:
  *  _url - A valid local file path or http url pointing to the resource to load.
  *  _contentType - An optional parameter, specifies the content type wanted, defaults to text/html.
  *
  * Returns:
  *  The contents of the path.
  */
  fetch: function( _url, _contentType, _callBack, _async ) {
    if( !_contentType ){
      _contentType = 'text/html; charset=UTF-8';
    }
    if(_async){
      var _callBackFun = function( resp ){
        _callBack( resp.X.responseText );
      };
    }
    else{
      // console.log('WARNING: Fetching synchronously using HThemeManager is not recommended. Use pre-packaged themes instead.');
      var _respText;
      var _callBackFun = function( resp ){
        _respText = resp.X.responseText;
      };
    }
    COMM.request(
      _url, {
        onSuccess:    _callBackFun,
        on404:        function(resp){ HThemeManager._errTemplateNotFound(  resp.url ); },
        onFailure:    function(resp){ HThemeManager._errTemplateFailure(   resp.url ); },
        onException:  function(resp){ HThemeManager._errTemplateException( resp.url ); },
        method: 'GET',
        async: _async
      }
    );
    if(!_async){
      return _respText;
    }
  },

/** method: getThemeGfxPath
  *
  * Returns the theme/component -specific path, called from inside css
  * themes, a bit kludgy approach to tell the theme grapics file paths.
  */
  getThemeGfxPath: function() {
    var _themeName      = this._cssEvalParams[0],
        _componentName  = this._cssEvalParams[1],
        _themePath      = this._cssEvalParams[2],
        _pkgName        = this._cssEvalParams[3],
        _urlPrefix      = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName );
    return this._joinPath( _urlPrefix, 'gfx' );
  },

/** method: getCssFilePath
  *
  * Returns the theme/component -specific graphics file path with proper css wrappers.
  * Used from inside css themes, a bit kludgy approach to tell the file name path.
  *
  * Parameters:
  *  _fileName - The File name to load.
  *
  */
  getCssFilePath: function( _fileName ){
    var _themeName      = this._cssEvalParams[0];
    if((HThemeHasIE6GifsInsteadOfPng.indexOf(_themeName)!==-1) && ELEM._is_ie6){
      return "url('"+this._joinPath( this.getThemeGfxPath(), _fileName.replace('.png','-ie6.gif') )+"')";
    }
    else {
      return "url('"+this._joinPath( this.getThemeGfxPath(), _fileName )+"')";
    }
  },

/** method: loadCSS
  *
  * Loads a css file based on the given url (or file path).
  * Evaluates the css data.
  * Makes sure the browser uses the data for component styles.
  *
  * Parameter:
  *  _url - A valid url that points to a valid css file.
  *
  * Returns:
  *  The source of the url.
  */
  loadCSS: function( _url ) {
    var _contentType = 'text/css',
        _cssFun = function(_cssText){
          // Don't try to do anything with empty or invalid css data:
          if (!_cssText || _cssText === "") {
            return;
          }
          HThemeManager.useCSS( _cssText );
        };
    this.fetch( _url, _contentType, _cssFun, true );
  },

  useCSS: function( _cssText ){
    var _contentType = 'text/css';
    // Evaluate the css text
    _cssText = this._bindCSSVariables( _cssText );

    var _style, _styleSheet, _head;

    if(ELEM._is_ie) {
      // Internet Explorer (at least 6.x; check what 7.x does)
      _style         = document.createStyleSheet();
      _style.cssText = _cssText;
    }

    else {
      // Common, standard <style> tag generation in <head>
      _style        = document.createElement( "style" );
      _style.type   = _contentType;
      _style.media  = "all";

      _head = document.getElementsByTagName('head')[0];
      _head.appendChild(_style);

      if (BROWSER_TYPE.safari) {
        // Work-around for safari
        var _cssTextElement = document.createTextNode(_cssText);
        _style.appendChild(_cssTextElement);
      }
      else {
        // This works for others (add more checks, if problems with new browsers)
        _style.innerHTML = _cssText;
      }
    }

  },

  _addSlash: function( _str ){
    if( _str[ _str.length-1 ] !== '/' ){
      _str += '/';
    }
    return _str;
  },

  _joinPath: function( _str1, _str2 ){
    return this._addSlash( _str1 ) + _str2;
  },

  // Makes a common url prefix for template files
  _urlPrefix: function( _themeName, _componentName, _themePath, _pkgName ) {

    var _path = _themePath;

    // Usually null
    if( _themePath === null ) {
      _path = this.themePath;
    }

    // Pre-Build Path Format
    if( HThemeMode === 0 ) {
      if( _pkgName ){
        _path = this._joinPath( _path, _pkgName );
      }
      // When using a component specific theme path, skip the standard directory
      // structure and use the path directly.
      if( _themePath === null ) {
        _path = this._joinPath( _path, _componentName );
        _path = this._joinPath( _path, 'themes' );
      }
      _path = this._joinPath( _path, _themeName );
    }

    // Post-Build Path Format
    else if( HThemeMode === 1 ) {
      _path = this._joinPath( _path, _themeName );
    }

    return _path;
  },

  // Makes a valid css template url
  _cssUrl: function( _themeName, _componentName, _themePath, _pkgName ) {
    this._cssEvalParams = [_themeName, _componentName, _themePath, _pkgName];
    var _cssPrefix = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName ),
        _cssSuffix = this._joinPath( 'css', _componentName+'.css' ),
        _cssUrl = this._joinPath( _cssPrefix, _cssSuffix );
    return _cssUrl;
  },

  // Makes a valid html template url
  _markupUrl: function( _themeName, _componentName, _themePath, _pkgName ) {
    var _htmlPrefix = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName ),
        _htmlSuffix = this._joinPath( 'html', _componentName+'.html' ),
        _htmlUrl = this._joinPath( _htmlPrefix, _htmlSuffix );
    return _htmlUrl;
  },

/** method: loadMarkup
  *
  * Loads HTML templates of components. Handles caching independently and intelligently.
  *
  * Parameters:
  *  _themeName     - The name of the template to use.
  *  _componentName - The name of the component template (css/html) to load.
  *  _themePath     - (Optional) parameter to override the global theme path.
  *  _pkgPath       - (Optional) parameter to specify the package of the component, useful only in pre-built mode.
  *
  * Returns:
  *  The Pre-Evaluated HTML Template.
  *
  **/
  loadMarkup: function( _themeName, _componentName, _themePath, _pkgName ) {
    if( !this._tmplCache[_themeName] ){
      this._tmplCache[_themeName] = {};
    }
    var _cached = this._tmplCache[_themeName][_componentName];

    if (null === _cached || undefined === _cached) {
      var _markupUrl = this._markupUrl( _themeName, _componentName, _themePath, _pkgName ),
          _markup = this.fetch( _markupUrl, null, null, false );
      // Save an empty string to template cache to prevent repeated failing
      // requests.
      if (null === _markup || undefined === _markup) {
        _markup = "";
      }
      HThemeManager._tmplCache[_themeName][_componentName] = _markup;
      return _markup;
    }
    return _cached;
  },

/** method: getMarkup
  *
  * Loads CSS and HTML templates of components. Called from <HView._loadMarkup>.
  * Returns the HTML Template as text.
  * Manages file caches independently and intelligently.
  *
  * Parameters:
  *  _themeName     - The name of the template to use.
  *  _componentName - The name of the component template (css/html) to load.
  *  _themePath     - (Optional) parameter to override the global theme path.
  *  _pkgPath       - (Optional) parameter to specify the package of the component, useful only in pre-built mode.
  *
  * Returns:
  *  The Pre-Evaluated HTML Template.
  *
  **/
  getMarkup: function( _themeName, _componentName, _themePath, _pkgName ) {
    /* Load Theme-Specific CSS: */
    if(!this._cssCache[_themeName]){
      this._cssCache[_themeName] = {};
      if(HNoCommonCSS.indexOf(_themeName)===-1){
        var _commonCssUrl = this._cssUrl( _themeName, 'common', _themePath, null );
        this.loadCSS( _commonCssUrl );
      }
    }

    /* Load Component-Specific CSS, unless configured to only load the common css: */
    if(HNoComponentCSS.indexOf(_themeName)===-1){
      if (!this._cssCache[_themeName][_componentName]){
        var _componentCssUrl = this._cssUrl( _themeName, _componentName, _themePath, _pkgName );
        this._cssCache[_themeName][_componentName] = true;
        this.loadCSS( _componentCssUrl );
      }
    }

    /* Load/Return Component-Specific HTML: */
    return this.loadMarkup( _themeName, _componentName, _themePath, _pkgName );
  },

/** method: _componentGfxPath
  *
  * Called via HView to determine the valid path prefix to aid
  * finding theme- and component-specific image files.
  *
  * Returns:
  *   A valid path, for example: '/helmi/themes/helmiTheme/gfx/'
  *
  **/
  _componentGfxPath: function( _themeName, _componentName, _themePath, _pkgName ) {
    var _urlPrefix      = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName ),
        _url = this._joinPath( _urlPrefix, 'gfx' );
    return _url;
  },
  _componentGfxFile: function( _themeName, _componentName, _themePath, _pkgName, _fileName ){
    if((HThemeHasIE6GifsInsteadOfPng.indexOf(_themeName)!==-1) && ELEM._is_ie6){
      return this._joinPath( this._componentGfxPath(_themeName, _componentName, _themePath, _pkgName), _fileName.replace('.png','-ie6.gif') );
    }
    return this._joinPath( this._componentGfxPath(_themeName, _componentName, _themePath, _pkgName), _fileName );
  },

  getThemeGfxFile: function( _fileName ) {

    return this.getThemeGfxPath() + _fileName;

  },

/** method: setTheme
  *
  * Sets the active theme.
  *
  * Parameters:
  *  _theme - The name of the theme to be set as the active theme.
  *
  **/
  setTheme: function(_theme) {
    this.currentTheme = _theme;
  },

/** method: restoreDefaultTheme
  *
  * Sets the default theme ( HDefaultTheme ) to be the active theme.
  **/
  restoreDefaultTheme: function() {
    this.setTheme( HDefaultThemeName );
  },

/** regexp: _variable_match
  *
  * A regular expression to match the template evaluation syntax: #{stuff_to_evaluate}
  **/
  _variable_match: new RegExp(/#\{([^\}]*)\}/),

/** method: _bindCSSVariables
  *
  * Evaluates the _variable_match regular expression for the string _markup.
  *
  * Parameters:
  *  _cssTmpl - The css template file to be evaluated.
  *
  * Returns:
  *  An evaluated CSS Template.
  **/
  _bindCSSVariables: function( _cssTmpl ) {
    while ( this._variable_match.test( _cssTmpl ) ) {
      _cssTmpl = _cssTmpl.replace(  this._variable_match, eval( RegExp.$1 )  );
    }
    return _cssTmpl;
  }

});
<commit_msg>Making jslint happy...<commit_after>/**
  * Riassence Core -- http://rsence.org/
  *
  * Copyright (C) 2008 Juha-Jarmo Heinonen <jjh@riassence.com>
  * Copyright (C) 2006 Helmi Technologies Inc.
  *
  * This file is part of Riassence Core.
  *
  * Riassence Core is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * Riassence Core is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  **/

/*** class: HThemeManager
  **
  ** A single instance class.
  **
  ** The theme manager knows the name of the currently loaded theme and handles
  ** the loading of theme specific markup snippets and style declarations.
  **
  ** vars: Instance variables
  **  themePath - Relative path to the components' top directory.
  **  currentTheme - The name of the theme currently in use. Initially the
  **    default unnamed theme is used.
  **  usesComponentDir - True when the components are separated in their own
  **    directories, usually when using the source/development version. False
  **    when the components are all in same directory. This is the case in the
  **    release build.
  **
  ** See also:
  **  <HView> <HMarkupView>
  ***/

HDefaultThemePath = '/H/themes';
HDefaultThemeName = 'default';
HNoComponentCSS = [];
HNoCommonCSS = [];
HThemeHasIE6GifsInsteadOfPng = [];

/** HDefaultThemeMode:
  *
  *  0 = Pre-built mode
  *  1 = Post-built mode
  *
  */
HThemeMode = 1;

HThemeManager = HClass.extend({

  constructor: null,

  init: function(){

    // Default root path of the themes path, should contain at least the default theme.
    this.themePath = HDefaultThemePath;

    // Hash map of loaded template markup (html templates), by theme.
    // componentName is used as the secondary key.
    this._tmplCache = {};

    // Hash map of loaded css templates, by theme.
    // componentName is used as the secondary key.
    this._cssCache = {};

    // The currently selected default theme name.
    this.currentTheme = HDefaultThemeName;
  },

  setThemePath: function( _path ){
    this.themePath = _path;
  },

  // Error messages, should be refined.
  _errTemplateNotFound: function( _url ) {
    console.log( "ERROR: Template Not Found: '" + _url + "' ");
  },
  _errTemplateFailure: function( _url ) {
    console.log( "ERROR: Template Failure: '" + _url + "' ");
  },
  _errTemplateException: function( _url ) {
    console.log( "ERROR: Template Exception: '" + _url + "' ");
  },

/** method: fetch
  *
  * Loads a template file and returns its contents.
  * If errors occurred, calls the error management functions.
  *
  * Parameters:
  *  _url - A valid local file path or http url pointing to the resource to load.
  *  _contentType - An optional parameter, specifies the content type wanted, defaults to text/html.
  *
  * Returns:
  *  The contents of the path.
  */
  fetch: function( _url, _contentType, _callBack, _async ) {
    var _callBackFun;
    if( !_contentType ){
      _contentType = 'text/html; charset=UTF-8';
    }
    if(_async){
      _callBackFun = function( resp ){
        _callBack( resp.X.responseText );
      };
    }
    else{
      // console.log('WARNING: Fetching synchronously using HThemeManager is not recommended. Use pre-packaged themes instead.');
      var _respText;
      _callBackFun = function( resp ){
        _respText = resp.X.responseText;
      };
    }
    COMM.request(
      _url, {
        onSuccess:    _callBackFun,
        on404:        function(resp){ HThemeManager._errTemplateNotFound(  resp.url ); },
        onFailure:    function(resp){ HThemeManager._errTemplateFailure(   resp.url ); },
        onException:  function(resp){ HThemeManager._errTemplateException( resp.url ); },
        method: 'GET',
        async: _async
      }
    );
    if(!_async){
      return _respText;
    }
  },

/** method: getThemeGfxPath
  *
  * Returns the theme/component -specific path, called from inside css
  * themes, a bit kludgy approach to tell the theme grapics file paths.
  */
  getThemeGfxPath: function() {
    var _themeName      = this._cssEvalParams[0],
        _componentName  = this._cssEvalParams[1],
        _themePath      = this._cssEvalParams[2],
        _pkgName        = this._cssEvalParams[3],
        _urlPrefix      = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName );
    return this._joinPath( _urlPrefix, 'gfx' );
  },

/** method: getCssFilePath
  *
  * Returns the theme/component -specific graphics file path with proper css wrappers.
  * Used from inside css themes, a bit kludgy approach to tell the file name path.
  *
  * Parameters:
  *  _fileName - The File name to load.
  *
  */
  getCssFilePath: function( _fileName ){
    var _themeName      = this._cssEvalParams[0];
    if((HThemeHasIE6GifsInsteadOfPng.indexOf(_themeName)!==-1) && ELEM._is_ie6){
      return "url('"+this._joinPath( this.getThemeGfxPath(), _fileName.replace('.png','-ie6.gif') )+"')";
    }
    else {
      return "url('"+this._joinPath( this.getThemeGfxPath(), _fileName )+"')";
    }
  },

/** method: loadCSS
  *
  * Loads a css file based on the given url (or file path).
  * Evaluates the css data.
  * Makes sure the browser uses the data for component styles.
  *
  * Parameter:
  *  _url - A valid url that points to a valid css file.
  *
  * Returns:
  *  The source of the url.
  */
  loadCSS: function( _url ) {
    var _contentType = 'text/css',
        _cssFun = function(_cssText){
          // Don't try to do anything with empty or invalid css data:
          if (!_cssText || _cssText === "") {
            return;
          }
          HThemeManager.useCSS( _cssText );
        };
    this.fetch( _url, _contentType, _cssFun, true );
  },

  useCSS: function( _cssText ){
    var _contentType = 'text/css';
    // Evaluate the css text
    _cssText = this._bindCSSVariables( _cssText );

    var _style, _styleSheet, _head;

    if(ELEM._is_ie) {
      // Internet Explorer (at least 6.x; check what 7.x does)
      _style         = document.createStyleSheet();
      _style.cssText = _cssText;
    }

    else {
      // Common, standard <style> tag generation in <head>
      _style        = document.createElement( "style" );
      _style.type   = _contentType;
      _style.media  = "all";

      _head = document.getElementsByTagName('head')[0];
      _head.appendChild(_style);

      if (BROWSER_TYPE.safari) {
        // Work-around for safari
        var _cssTextElement = document.createTextNode(_cssText);
        _style.appendChild(_cssTextElement);
      }
      else {
        // This works for others (add more checks, if problems with new browsers)
        _style.innerHTML = _cssText;
      }
    }

  },

  _addSlash: function( _str ){
    if( _str[ _str.length-1 ] !== '/' ){
      _str += '/';
    }
    return _str;
  },

  _joinPath: function( _str1, _str2 ){
    return this._addSlash( _str1 ) + _str2;
  },

  // Makes a common url prefix for template files
  _urlPrefix: function( _themeName, _componentName, _themePath, _pkgName ) {

    var _path = _themePath;

    // Usually null
    if( _themePath === null ) {
      _path = this.themePath;
    }

    // Pre-Build Path Format
    if( HThemeMode === 0 ) {
      if( _pkgName ){
        _path = this._joinPath( _path, _pkgName );
      }
      // When using a component specific theme path, skip the standard directory
      // structure and use the path directly.
      if( _themePath === null ) {
        _path = this._joinPath( _path, _componentName );
        _path = this._joinPath( _path, 'themes' );
      }
      _path = this._joinPath( _path, _themeName );
    }

    // Post-Build Path Format
    else if( HThemeMode === 1 ) {
      _path = this._joinPath( _path, _themeName );
    }

    return _path;
  },

  // Makes a valid css template url
  _cssUrl: function( _themeName, _componentName, _themePath, _pkgName ) {
    this._cssEvalParams = [_themeName, _componentName, _themePath, _pkgName];
    var _cssPrefix = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName ),
        _cssSuffix = this._joinPath( 'css', _componentName+'.css' ),
        _cssUrl = this._joinPath( _cssPrefix, _cssSuffix );
    return _cssUrl;
  },

  // Makes a valid html template url
  _markupUrl: function( _themeName, _componentName, _themePath, _pkgName ) {
    var _htmlPrefix = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName ),
        _htmlSuffix = this._joinPath( 'html', _componentName+'.html' ),
        _htmlUrl = this._joinPath( _htmlPrefix, _htmlSuffix );
    return _htmlUrl;
  },

/** method: loadMarkup
  *
  * Loads HTML templates of components. Handles caching independently and intelligently.
  *
  * Parameters:
  *  _themeName     - The name of the template to use.
  *  _componentName - The name of the component template (css/html) to load.
  *  _themePath     - (Optional) parameter to override the global theme path.
  *  _pkgPath       - (Optional) parameter to specify the package of the component, useful only in pre-built mode.
  *
  * Returns:
  *  The Pre-Evaluated HTML Template.
  *
  **/
  loadMarkup: function( _themeName, _componentName, _themePath, _pkgName ) {
    if( !this._tmplCache[_themeName] ){
      this._tmplCache[_themeName] = {};
    }
    var _cached = this._tmplCache[_themeName][_componentName];

    if (null === _cached || undefined === _cached) {
      var _markupUrl = this._markupUrl( _themeName, _componentName, _themePath, _pkgName ),
          _markup = this.fetch( _markupUrl, null, null, false );
      // Save an empty string to template cache to prevent repeated failing
      // requests.
      if (null === _markup || undefined === _markup) {
        _markup = "";
      }
      HThemeManager._tmplCache[_themeName][_componentName] = _markup;
      return _markup;
    }
    return _cached;
  },

/** method: getMarkup
  *
  * Loads CSS and HTML templates of components. Called from <HView._loadMarkup>.
  * Returns the HTML Template as text.
  * Manages file caches independently and intelligently.
  *
  * Parameters:
  *  _themeName     - The name of the template to use.
  *  _componentName - The name of the component template (css/html) to load.
  *  _themePath     - (Optional) parameter to override the global theme path.
  *  _pkgPath       - (Optional) parameter to specify the package of the component, useful only in pre-built mode.
  *
  * Returns:
  *  The Pre-Evaluated HTML Template.
  *
  **/
  getMarkup: function( _themeName, _componentName, _themePath, _pkgName ) {
    /* Load Theme-Specific CSS: */
    if(!this._cssCache[_themeName]){
      this._cssCache[_themeName] = {};
      if(HNoCommonCSS.indexOf(_themeName)===-1){
        var _commonCssUrl = this._cssUrl( _themeName, 'common', _themePath, null );
        this.loadCSS( _commonCssUrl );
      }
    }

    /* Load Component-Specific CSS, unless configured to only load the common css: */
    if(HNoComponentCSS.indexOf(_themeName)===-1){
      if (!this._cssCache[_themeName][_componentName]){
        var _componentCssUrl = this._cssUrl( _themeName, _componentName, _themePath, _pkgName );
        this._cssCache[_themeName][_componentName] = true;
        this.loadCSS( _componentCssUrl );
      }
    }

    /* Load/Return Component-Specific HTML: */
    return this.loadMarkup( _themeName, _componentName, _themePath, _pkgName );
  },

/** method: _componentGfxPath
  *
  * Called via HView to determine the valid path prefix to aid
  * finding theme- and component-specific image files.
  *
  * Returns:
  *   A valid path, for example: '/helmi/themes/helmiTheme/gfx/'
  *
  **/
  _componentGfxPath: function( _themeName, _componentName, _themePath, _pkgName ) {
    var _urlPrefix      = this._urlPrefix( _themeName, _componentName, _themePath, _pkgName ),
        _url = this._joinPath( _urlPrefix, 'gfx' );
    return _url;
  },
  _componentGfxFile: function( _themeName, _componentName, _themePath, _pkgName, _fileName ){
    if((HThemeHasIE6GifsInsteadOfPng.indexOf(_themeName)!==-1) && ELEM._is_ie6){
      return this._joinPath( this._componentGfxPath(_themeName, _componentName, _themePath, _pkgName), _fileName.replace('.png','-ie6.gif') );
    }
    return this._joinPath( this._componentGfxPath(_themeName, _componentName, _themePath, _pkgName), _fileName );
  },

  getThemeGfxFile: function( _fileName ) {

    return this.getThemeGfxPath() + _fileName;

  },

/** method: setTheme
  *
  * Sets the active theme.
  *
  * Parameters:
  *  _theme - The name of the theme to be set as the active theme.
  *
  **/
  setTheme: function(_theme) {
    this.currentTheme = _theme;
  },

/** method: restoreDefaultTheme
  *
  * Sets the default theme ( HDefaultTheme ) to be the active theme.
  **/
  restoreDefaultTheme: function() {
    this.setTheme( HDefaultThemeName );
  },

/** regexp: _variable_match
  *
  * A regular expression to match the template evaluation syntax: #{stuff_to_evaluate}
  **/
  _variable_match: new RegExp(/#\{([^\}]*)\}/),

/** method: _bindCSSVariables
  *
  * Evaluates the _variable_match regular expression for the string _markup.
  *
  * Parameters:
  *  _cssTmpl - The css template file to be evaluated.
  *
  * Returns:
  *  An evaluated CSS Template.
  **/
  _bindCSSVariables: function( _cssTmpl ) {
    while ( this._variable_match.test( _cssTmpl ) ) {
      _cssTmpl = _cssTmpl.replace(  this._variable_match, eval( RegExp.$1 )  );
    }
    return _cssTmpl;
  }

});
<|endoftext|>


<commit_before>'use strict';

// Hades Ex
[{
  zoneRegex: {
    en: /^The Minstrel's Ballad: Hades's Elegy$/,
    cn: /^哈迪斯孤念歼灭战$/,
    ko: /^극 하데스 토벌전$/,
  },
  damageWarn: {
    'HadesEx Shadow Spread 2': '47AA',
    'HadesEx Shadow Spread 3': '47E4',
    'HadesEx Shadow Spread 4': '47E5',
    'HadesEx Bad Faith 1': '47AD',
    'HadesEx Bad Faith 2': '47B0',
    'HadesEx Bad Faith 3': '47AE',
    'HadesEx Bad Faith 4': '47AF',
    'HadesEx Broken Faith': '47B2',
    'HadesEx Magic Spear': '47B6',
    'HadesEx Magic Chakram': '47B5',
    'HadesEx Forked Lightning': '47C9',
    'HadesEx Dark Current 1': '47F1',
    'HadesEx Dark Current 2': '47F2',
  },
  damageFail: {
    'HadesEx Comet': '47B9', // missed tower
    'HadesEx Ancient Eruption': '47D3',
    'HadesEx Purgation 1': '47EC',
    'HadesEx Purgation 2': '47ED',
    'HadesEx Shadow Stream': '47EA',
    'HadesEx Dead Space': '47EE',
  },
  triggers: [
    {
      id: 'HadesEx Shadow Spread Initial',
      damageRegex: '47A9',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Ravenous Assault',
      damageRegex: '(?:47A6|47A7)',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'fail', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Dark II Tether',
      regex: / 23:\y{ObjectId}:Shadow of the Ancients:\y{ObjectId}:(\y{Name}):....:....:0011:/,
      run: function(e, data, matches) {
        data.hasDark = data.hasDark || [];
        data.hasDark.push(matches[1]);
      },
    },
    {
      id: 'HadesEx Dark II',
      damageRegex: '47BA',
      condition: function(e, data) {
        // Don't blame people who don't have tethers.
        return e.type != '15' && data.me in data.hasDark;
      },
      mistake: function(e, data) {
        return { type: 'fail', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Dark Flame 1',
      damageRegex: '47C6',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Dark Freeze 1',
      damageRegex: '47C4',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Boss Tether',
      regex: / 23:\y{ObjectId}:(?:Igeyorhm's Shade|Lahabrea's Shade):\y{ObjectId}:(?:Igeyorhm's Shade|Lahabrea's Shade):....:....:000E:/,
      mistake: {
        type: 'warn',
        text: {
          en: 'Bosses Too Close',
          cn: 'BOSS靠太近了',
          ko: '쫄들이 너무 가까움',
        },
      },
    },
    {
      id: 'HadesEx Death Shriek',
      damageRegex: '47CB',
      condition: function(e, data) {
        return e.damage > 0;
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Beyond Death Track',
      gainsEffectRegex: gLang.kEffect.BeyondDeath,
      losesEffectRegex: gLang.kEffect.BeyondDeath,
      run: function(e, data) {
        data.hasBeyondDeath = data.hasBeyondDeath || {};
        data.hasBeyondDeath[e.targetName] = e.gains;
      },
    },
    {
      id: 'HadesEx Beyond Death',
      gainsEffectRegex: gLang.kEffect.BeyondDeath,
      delaySeconds: function(e) {
        return e.durationSeconds - 0.5;
      },
      deathReason: function(e, data) {
        if (!data.hasBeyondDeath)
          return;
        if (!data.hasBeyondDeath[e.targetName])
          return;
        return {
          name: e.targetName,
          reason: e.effectName,
        };
      },
    },
    {
      id: 'HadesEx Doom Track',
      gainsEffectRegex: gLang.kEffect.Doom,
      losesEffectRegex: gLang.kEffect.Doom,
      run: function(e, data) {
        data.hasDoom = data.hasDoom || {};
        data.hasDoom[e.targetName] = e.gains;
      },
    },
    {
      id: 'HadesEx Doom',
      gainsEffectRegex: gLang.kEffect.Doom,
      delaySeconds: function(e) {
        return e.durationSeconds - 0.5;
      },
      deathReason: function(e, data) {
        if (!data.hasDoom)
          return;
        if (!data.hasDoom[e.targetName])
          return;
        return {
          name: e.targetName,
          reason: e.effectName,
        };
      },
    },
    {
      id: 'HadesEx Dark Freeze 2',
      damageRegex: '47DF',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
  ],
}];
<commit_msg>oopsy: Don't warn when stacking for Bad Faith<commit_after>'use strict';

// Hades Ex
[{
  zoneRegex: {
    en: /^The Minstrel's Ballad: Hades's Elegy$/,
    cn: /^哈迪斯孤念歼灭战$/,
    ko: /^극 하데스 토벌전$/,
  },
  damageWarn: {
    'HadesEx Shadow Spread 2': '47AA',
    'HadesEx Shadow Spread 3': '47E4',
    'HadesEx Shadow Spread 4': '47E5',
    // Everybody stacks in good faith for Bad Faith, so don't call it a mistake.
    // 'HadesEx Bad Faith 1': '47AD',
    // 'HadesEx Bad Faith 2': '47B0',
    // 'HadesEx Bad Faith 3': '47AE',
    // 'HadesEx Bad Faith 4': '47AF',
    'HadesEx Broken Faith': '47B2',
    'HadesEx Magic Spear': '47B6',
    'HadesEx Magic Chakram': '47B5',
    'HadesEx Forked Lightning': '47C9',
    'HadesEx Dark Current 1': '47F1',
    'HadesEx Dark Current 2': '47F2',
  },
  damageFail: {
    'HadesEx Comet': '47B9', // missed tower
    'HadesEx Ancient Eruption': '47D3',
    'HadesEx Purgation 1': '47EC',
    'HadesEx Purgation 2': '47ED',
    'HadesEx Shadow Stream': '47EA',
    'HadesEx Dead Space': '47EE',
  },
  triggers: [
    {
      id: 'HadesEx Shadow Spread Initial',
      damageRegex: '47A9',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Ravenous Assault',
      damageRegex: '(?:47A6|47A7)',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'fail', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Dark II Tether',
      regex: / 23:\y{ObjectId}:Shadow of the Ancients:\y{ObjectId}:(\y{Name}):....:....:0011:/,
      run: function(e, data, matches) {
        data.hasDark = data.hasDark || [];
        data.hasDark.push(matches[1]);
      },
    },
    {
      id: 'HadesEx Dark II',
      damageRegex: '47BA',
      condition: function(e, data) {
        // Don't blame people who don't have tethers.
        return e.type != '15' && data.me in data.hasDark;
      },
      mistake: function(e, data) {
        return { type: 'fail', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Dark Flame 1',
      damageRegex: '47C6',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Dark Freeze 1',
      damageRegex: '47C4',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Boss Tether',
      regex: / 23:\y{ObjectId}:(?:Igeyorhm's Shade|Lahabrea's Shade):\y{ObjectId}:(?:Igeyorhm's Shade|Lahabrea's Shade):....:....:000E:/,
      mistake: {
        type: 'warn',
        text: {
          en: 'Bosses Too Close',
          cn: 'BOSS靠太近了',
          ko: '쫄들이 너무 가까움',
        },
      },
    },
    {
      id: 'HadesEx Death Shriek',
      damageRegex: '47CB',
      condition: function(e, data) {
        return e.damage > 0;
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
    {
      id: 'HadesEx Beyond Death Track',
      gainsEffectRegex: gLang.kEffect.BeyondDeath,
      losesEffectRegex: gLang.kEffect.BeyondDeath,
      run: function(e, data) {
        data.hasBeyondDeath = data.hasBeyondDeath || {};
        data.hasBeyondDeath[e.targetName] = e.gains;
      },
    },
    {
      id: 'HadesEx Beyond Death',
      gainsEffectRegex: gLang.kEffect.BeyondDeath,
      delaySeconds: function(e) {
        return e.durationSeconds - 0.5;
      },
      deathReason: function(e, data) {
        if (!data.hasBeyondDeath)
          return;
        if (!data.hasBeyondDeath[e.targetName])
          return;
        return {
          name: e.targetName,
          reason: e.effectName,
        };
      },
    },
    {
      id: 'HadesEx Doom Track',
      gainsEffectRegex: gLang.kEffect.Doom,
      losesEffectRegex: gLang.kEffect.Doom,
      run: function(e, data) {
        data.hasDoom = data.hasDoom || {};
        data.hasDoom[e.targetName] = e.gains;
      },
    },
    {
      id: 'HadesEx Doom',
      gainsEffectRegex: gLang.kEffect.Doom,
      delaySeconds: function(e) {
        return e.durationSeconds - 0.5;
      },
      deathReason: function(e, data) {
        if (!data.hasDoom)
          return;
        if (!data.hasDoom[e.targetName])
          return;
        return {
          name: e.targetName,
          reason: e.effectName,
        };
      },
    },
    {
      id: 'HadesEx Dark Freeze 2',
      damageRegex: '47DF',
      condition: function(e, data) {
        // Double taps only.
        return e.type != '15';
      },
      mistake: function(e, data) {
        return { type: 'warn', blame: e.targetName, text: e.abilityName };
      },
    },
  ],
}];
<|endoftext|>


<commit_before>/**
 * This module adds Shared ID support to the User ID module
 * The {@link module:modules/userId} module is required.
 * @module modules/sharedIdSystem
 * @requires module:modules/userId
 */

import * as utils from '../src/utils.js'
import {ajax} from '../src/ajax.js';
import {submodule} from '../src/hook.js';

const MODULE_NAME = 'sharedId';
const ID_SVC = 'https://id.sharedid.org/id';
const DEFAULT_24_HOURS = 86400;
const OPT_OUT_VALUE = '00000000000000000000000000';
// These values should NEVER change. If
// they do, we're no longer making ulids!
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
const ENCODING_LEN = ENCODING.length;
const TIME_MAX = Math.pow(2, 48) - 1;
const TIME_LEN = 10;
const RANDOM_LEN = 16;
const id = factory();
/**
 * Constructs cookie value
 * @param value
 * @param needsSync
 * @returns {string}
 */
function constructCookieValue(value, needsSync) {
  const cookieValue = {};
  cookieValue.id = value;
  cookieValue.ts = utils.timestamp();
  if (needsSync) {
    cookieValue.ns = true;
  }
  utils.logInfo('SharedId: cookie Value: ' + JSON.stringify(cookieValue));
  return cookieValue;
}

/**
 * Checks if id needs to be synced
 * @param configParams
 * @param storedId
 * @returns {boolean}
 */
function isIdSynced(configParams, storedId) {
  const needSync = storedId.ns;
  if (needSync) {
    return true;
  }
  if (!configParams || typeof configParams.syncTime !== 'number') {
    utils.logInfo('SharedId: Sync time is not configured or is not a number');
  }
  let syncTime = (!configParams || typeof configParams.syncTime !== 'number') ? DEFAULT_24_HOURS : configParams.syncTime;
  if (syncTime > DEFAULT_24_HOURS) {
    syncTime = DEFAULT_24_HOURS;
  }
  const cookieTimestamp = storedId.ts;
  if (cookieTimestamp) {
    var secondBetweenTwoDate = timeDifferenceInSeconds(utils.timestamp(), cookieTimestamp);
    return secondBetweenTwoDate >= syncTime;
  }
  return false;
}

/**
 * Gets time difference in secounds
 * @param date1
 * @param date2
 * @returns {number}
 */
function timeDifferenceInSeconds(date1, date2) {
  const diff = (date1 - date2) / 1000;
  return Math.abs(Math.round(diff));
}

/**
 * id generation call back
 * @param result
 * @param callback
 * @returns {{success: success, error: error}}
 */
function idGenerationCallback(callback) {
  return {
    success: function (responseBody) {
      let value = {};
      if (responseBody) {
        try {
          let responseObj = JSON.parse(responseBody);
          utils.logInfo('SharedId: Generated SharedId: ' + responseObj.sharedId);
          value = constructCookieValue(responseObj.sharedId, false);
        } catch (error) {
          utils.logError(error);
        }
      }
      callback(value);
    },
    error: function (statusText, responseBody) {
      const value = constructCookieValue(id(), true);
      utils.logInfo('SharedId: Ulid Generated SharedId: ' + value.id);
      callback(value);
    }
  }
}

/**
 * existing id generation call back
 * @param result
 * @param callback
 * @returns {{success: success, error: error}}
 */
function existingIdCallback(storedId, callback) {
  return {
    success: function (responseBody) {
      utils.logInfo('SharedId: id to be synced: ' + storedId.id);
      if (responseBody) {
        try {
          let responseObj = JSON.parse(responseBody);
          storedId = constructCookieValue(responseObj.sharedId, false);
          utils.logInfo('SharedId: Older SharedId: ' + storedId.id);
        } catch (error) {
          utils.logError(error);
        }
      }
      callback(storedId);
    },
    error: function () {
      utils.logInfo('SharedId: Sync error for id : ' + storedId.id);
      callback(storedId);
    }
  }
}

/**
 * Encode the id
 * @param value
 * @returns {string|*}
 */
function encodeId(value) {
  const result = {};
  const sharedId = (value && typeof value['id'] === 'string') ? value['id'] : undefined;
  if (sharedId == OPT_OUT_VALUE) {
    return undefined;
  }
  if (sharedId) {
    const bidIds = {
      id: sharedId,
    }
    const ns = (value && typeof value['ns'] === 'boolean') ? value['ns'] : undefined;
    if (ns == undefined) {
      bidIds.third = sharedId;
    }
    result.sharedid = bidIds;
    utils.logInfo('SharedId: Decoded value ' + JSON.stringify(result));
    return result;
  }
  return sharedId;
}

/**
 * the factory to generate unique identifier based on time and current pseudorandom number
 * @param {string} the current pseudorandom number generator
 * @returns {function(*=): *}
 */
function factory(currPrng) {
  if (!currPrng) {
    currPrng = detectPrng();
  }
  return function ulid(seedTime) {
    if (isNaN(seedTime)) {
      seedTime = Date.now();
    }
    return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, currPrng);
  };
}

/**
 * creates and logs the error message
 * @function
 * @param {string} error message
 * @returns {Error}
 */
function createError(message) {
  utils.logError(message);
  const err = new Error(message);
  err.source = 'sharedId';
  return err;
}

/**
 * gets a a random charcter from generated pseudorandom number
 * @param {string} the generated pseudorandom number
 * @returns {string}
 */
function randomChar(prng) {
  let rand = Math.floor(prng() * ENCODING_LEN);
  if (rand === ENCODING_LEN) {
    rand = ENCODING_LEN - 1;
  }
  return ENCODING.charAt(rand);
}

/**
 * encodes the time based on the length
 * @param now
 * @param len
 * @returns {string} encoded time.
 */
function encodeTime (now, len) {
  if (isNaN(now)) {
    throw new Error(now + ' must be a number');
  }

  if (Number.isInteger(now) === false) {
    throw createError('time must be an integer');
  }

  if (now > TIME_MAX) {
    throw createError('cannot encode time greater than ' + TIME_MAX);
  }
  if (now < 0) {
    throw createError('time must be positive');
  }

  if (Number.isInteger(len) === false) {
    throw createError('length must be an integer');
  }
  if (len < 0) {
    throw createError('length must be positive');
  }

  let mod;
  let str = '';
  for (; len > 0; len--) {
    mod = now % ENCODING_LEN;
    str = ENCODING.charAt(mod) + str;
    now = (now - mod) / ENCODING_LEN;
  }
  return str;
}

/**
 * encodes random character
 * @param len
 * @param prng
 * @returns {string}
 */
function encodeRandom (len, prng) {
  let str = '';
  for (; len > 0; len--) {
    str = randomChar(prng) + str;
  }
  return str;
}

/**
 * detects the pseudorandom number generator and generates the random number
 * @function
 * @param {string} error message
 * @returns {string} a random number
 */
function detectPrng(root) {
  if (!root) {
    root = typeof window !== 'undefined' ? window : null;
  }
  const browserCrypto = root && (root.crypto || root.msCrypto);
  if (browserCrypto) {
    return () => {
      const buffer = new Uint8Array(1);
      browserCrypto.getRandomValues(buffer);
      return buffer[0] / 0xff;
    };
  }
  return () => Math.random();
}

/** @type {Submodule} */
export const sharedIdSubmodule = {
  /**
   * used to link submodule with config
   * @type {string}
   */
  name: MODULE_NAME,

  /**
   * decode the stored id value for passing to bid requests
   * @function
   * @param {string} value
   * @returns {{sharedid:{ id: string, third:string}} or undefined if value doesn't exists
   */
  decode(value) {
    return (value) ? encodeId(value) : undefined;
  },

  /**
   * performs action to obtain id and return a value.
   * @function
   * @param {SubmoduleConfig} [config]
   * @returns {sharedId}
   */
  getId(config) {
    const resp = function (callback) {
      utils.logInfo('SharedId: Sharedid doesnt exists, new cookie creation');
      ajax(ID_SVC, idGenerationCallback(callback), undefined, {method: 'GET', withCredentials: true});
    };
    return {callback: resp};
  },

  /**
   * performs actions even if the id exists and returns a value
   * @param config
   * @param storedId
   * @returns {{callback: *}}
   */
  extendId(config, storedId) {
    const configParams = (config && config.params) || {};
    utils.logInfo('SharedId: Existing shared id ' + storedId.id);
    const resp = function (callback) {
      const needSync = isIdSynced(configParams, storedId);
      if (needSync) {
        utils.logInfo('SharedId: Existing shared id ' + storedId + ' is not synced');
        const sharedIdPayload = {};
        sharedIdPayload.sharedId = storedId.id;
        const payloadString = JSON.stringify(sharedIdPayload);
        ajax(ID_SVC, existingIdCallback(storedId, callback), payloadString, {method: 'POST', withCredentials: true});
      }
    };
    return {callback: resp};
  }
};

// Register submodule for userId
submodule('userId', sharedIdSubmodule);
<commit_msg>Update sharedIdSystem.js with GVLID (#5988)<commit_after>/**
 * This module adds Shared ID support to the User ID module
 * The {@link module:modules/userId} module is required.
 * @module modules/sharedIdSystem
 * @requires module:modules/userId
 */

import * as utils from '../src/utils.js'
import {ajax} from '../src/ajax.js';
import {submodule} from '../src/hook.js';

const MODULE_NAME = 'sharedId';
const ID_SVC = 'https://id.sharedid.org/id';
const DEFAULT_24_HOURS = 86400;
const OPT_OUT_VALUE = '00000000000000000000000000';
// These values should NEVER change. If
// they do, we're no longer making ulids!
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
const ENCODING_LEN = ENCODING.length;
const TIME_MAX = Math.pow(2, 48) - 1;
const TIME_LEN = 10;
const RANDOM_LEN = 16;
const id = factory();
const GVLID = 887;
/**
 * Constructs cookie value
 * @param value
 * @param needsSync
 * @returns {string}
 */
function constructCookieValue(value, needsSync) {
  const cookieValue = {};
  cookieValue.id = value;
  cookieValue.ts = utils.timestamp();
  if (needsSync) {
    cookieValue.ns = true;
  }
  utils.logInfo('SharedId: cookie Value: ' + JSON.stringify(cookieValue));
  return cookieValue;
}

/**
 * Checks if id needs to be synced
 * @param configParams
 * @param storedId
 * @returns {boolean}
 */
function isIdSynced(configParams, storedId) {
  const needSync = storedId.ns;
  if (needSync) {
    return true;
  }
  if (!configParams || typeof configParams.syncTime !== 'number') {
    utils.logInfo('SharedId: Sync time is not configured or is not a number');
  }
  let syncTime = (!configParams || typeof configParams.syncTime !== 'number') ? DEFAULT_24_HOURS : configParams.syncTime;
  if (syncTime > DEFAULT_24_HOURS) {
    syncTime = DEFAULT_24_HOURS;
  }
  const cookieTimestamp = storedId.ts;
  if (cookieTimestamp) {
    var secondBetweenTwoDate = timeDifferenceInSeconds(utils.timestamp(), cookieTimestamp);
    return secondBetweenTwoDate >= syncTime;
  }
  return false;
}

/**
 * Gets time difference in secounds
 * @param date1
 * @param date2
 * @returns {number}
 */
function timeDifferenceInSeconds(date1, date2) {
  const diff = (date1 - date2) / 1000;
  return Math.abs(Math.round(diff));
}

/**
 * id generation call back
 * @param result
 * @param callback
 * @returns {{success: success, error: error}}
 */
function idGenerationCallback(callback) {
  return {
    success: function (responseBody) {
      let value = {};
      if (responseBody) {
        try {
          let responseObj = JSON.parse(responseBody);
          utils.logInfo('SharedId: Generated SharedId: ' + responseObj.sharedId);
          value = constructCookieValue(responseObj.sharedId, false);
        } catch (error) {
          utils.logError(error);
        }
      }
      callback(value);
    },
    error: function (statusText, responseBody) {
      const value = constructCookieValue(id(), true);
      utils.logInfo('SharedId: Ulid Generated SharedId: ' + value.id);
      callback(value);
    }
  }
}

/**
 * existing id generation call back
 * @param result
 * @param callback
 * @returns {{success: success, error: error}}
 */
function existingIdCallback(storedId, callback) {
  return {
    success: function (responseBody) {
      utils.logInfo('SharedId: id to be synced: ' + storedId.id);
      if (responseBody) {
        try {
          let responseObj = JSON.parse(responseBody);
          storedId = constructCookieValue(responseObj.sharedId, false);
          utils.logInfo('SharedId: Older SharedId: ' + storedId.id);
        } catch (error) {
          utils.logError(error);
        }
      }
      callback(storedId);
    },
    error: function () {
      utils.logInfo('SharedId: Sync error for id : ' + storedId.id);
      callback(storedId);
    }
  }
}

/**
 * Encode the id
 * @param value
 * @returns {string|*}
 */
function encodeId(value) {
  const result = {};
  const sharedId = (value && typeof value['id'] === 'string') ? value['id'] : undefined;
  if (sharedId == OPT_OUT_VALUE) {
    return undefined;
  }
  if (sharedId) {
    const bidIds = {
      id: sharedId,
    }
    const ns = (value && typeof value['ns'] === 'boolean') ? value['ns'] : undefined;
    if (ns == undefined) {
      bidIds.third = sharedId;
    }
    result.sharedid = bidIds;
    utils.logInfo('SharedId: Decoded value ' + JSON.stringify(result));
    return result;
  }
  return sharedId;
}

/**
 * the factory to generate unique identifier based on time and current pseudorandom number
 * @param {string} the current pseudorandom number generator
 * @returns {function(*=): *}
 */
function factory(currPrng) {
  if (!currPrng) {
    currPrng = detectPrng();
  }
  return function ulid(seedTime) {
    if (isNaN(seedTime)) {
      seedTime = Date.now();
    }
    return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, currPrng);
  };
}

/**
 * creates and logs the error message
 * @function
 * @param {string} error message
 * @returns {Error}
 */
function createError(message) {
  utils.logError(message);
  const err = new Error(message);
  err.source = 'sharedId';
  return err;
}

/**
 * gets a a random charcter from generated pseudorandom number
 * @param {string} the generated pseudorandom number
 * @returns {string}
 */
function randomChar(prng) {
  let rand = Math.floor(prng() * ENCODING_LEN);
  if (rand === ENCODING_LEN) {
    rand = ENCODING_LEN - 1;
  }
  return ENCODING.charAt(rand);
}

/**
 * encodes the time based on the length
 * @param now
 * @param len
 * @returns {string} encoded time.
 */
function encodeTime (now, len) {
  if (isNaN(now)) {
    throw new Error(now + ' must be a number');
  }

  if (Number.isInteger(now) === false) {
    throw createError('time must be an integer');
  }

  if (now > TIME_MAX) {
    throw createError('cannot encode time greater than ' + TIME_MAX);
  }
  if (now < 0) {
    throw createError('time must be positive');
  }

  if (Number.isInteger(len) === false) {
    throw createError('length must be an integer');
  }
  if (len < 0) {
    throw createError('length must be positive');
  }

  let mod;
  let str = '';
  for (; len > 0; len--) {
    mod = now % ENCODING_LEN;
    str = ENCODING.charAt(mod) + str;
    now = (now - mod) / ENCODING_LEN;
  }
  return str;
}

/**
 * encodes random character
 * @param len
 * @param prng
 * @returns {string}
 */
function encodeRandom (len, prng) {
  let str = '';
  for (; len > 0; len--) {
    str = randomChar(prng) + str;
  }
  return str;
}

/**
 * detects the pseudorandom number generator and generates the random number
 * @function
 * @param {string} error message
 * @returns {string} a random number
 */
function detectPrng(root) {
  if (!root) {
    root = typeof window !== 'undefined' ? window : null;
  }
  const browserCrypto = root && (root.crypto || root.msCrypto);
  if (browserCrypto) {
    return () => {
      const buffer = new Uint8Array(1);
      browserCrypto.getRandomValues(buffer);
      return buffer[0] / 0xff;
    };
  }
  return () => Math.random();
}

/** @type {Submodule} */
export const sharedIdSubmodule = {
  /**
   * used to link submodule with config
   * @type {string}
   */
  name: MODULE_NAME,

  /**
   * Vendor id of Prebid
   * @type {Number}
   */
  gvlid: GVLID,
  /**
   * decode the stored id value for passing to bid requests
   * @function
   * @param {string} value
   * @returns {{sharedid:{ id: string, third:string}} or undefined if value doesn't exists
   */
  decode(value) {
    return (value) ? encodeId(value) : undefined;
  },

  /**
   * performs action to obtain id and return a value.
   * @function
   * @param {SubmoduleConfig} [config]
   * @returns {sharedId}
   */
  getId(config) {
    const resp = function (callback) {
      utils.logInfo('SharedId: Sharedid doesnt exists, new cookie creation');
      ajax(ID_SVC, idGenerationCallback(callback), undefined, {method: 'GET', withCredentials: true});
    };
    return {callback: resp};
  },

  /**
   * performs actions even if the id exists and returns a value
   * @param config
   * @param storedId
   * @returns {{callback: *}}
   */
  extendId(config, storedId) {
    const configParams = (config && config.params) || {};
    utils.logInfo('SharedId: Existing shared id ' + storedId.id);
    const resp = function (callback) {
      const needSync = isIdSynced(configParams, storedId);
      if (needSync) {
        utils.logInfo('SharedId: Existing shared id ' + storedId + ' is not synced');
        const sharedIdPayload = {};
        sharedIdPayload.sharedId = storedId.id;
        const payloadString = JSON.stringify(sharedIdPayload);
        ajax(ID_SVC, existingIdCallback(storedId, callback), payloadString, {method: 'POST', withCredentials: true});
      }
    };
    return {callback: resp};
  }
};

// Register submodule for userId
submodule('userId', sharedIdSubmodule);
<|endoftext|>


<commit_before>/**
 * Created by truthlighting on 9/20/2016.
 */
var proto = {
    /**
     * The creep for this role
     *
     * @type creep
     */
    creep: null,

    /**
     * Set the creep for this role
     *
     * @param {Creep} creep
     */
    setCreep: function(creep)
    {
        this.creep = creep;
        return this;
    },

    run: function()
    {
        if(this.creep.memory.onSpawned == undefined) {
            this.onSpawn();
            this.creep.memory.onSpawned = true;
        }

        this.action(this.creep);

        if(this.creep.ticksToLive == 1)
            this.beforeAge();
    },

    handleEvents: function()
    {
        if(this.creep.memory.onSpawned == undefined) {
            this.onSpawnStart();
            this.onSpawn();
            this.creep.memory.onSpawned = true;
        }

        if(this.creep.memory.onSpawnEnd == undefined && !this.creep.spawning) {
            this.onSpawnEnd();
            this.creep.memory.onSpawnEnd = true;
        }
    },

    getParts: function() {
        //var _ = require('lodash');

        var extensions = Game.getRoom('1-1').find(Game.MY_STRUCTURES, {
            filter: function(structure)
            {
                return (structure.structureType == Game.STRUCTURE_EXTENSION && structure.energy >= 200);
            }
        }).length;

        var parts = _.cloneDeep(this.parts);
        if(typeof parts[0] != "object")
            return this.parts;

        parts.reverse();

        for(var i in parts)
        {
            if((parts[i].length - 5) <= extensions) {
                return parts[i];
            }
        }
    },

    action: function() { },

    onSpawn: function() { },

    onSpawnStart: function() { },

    onSpawnEnd: function() { },

    beforeAge: function() { },

    /**
     * All credit goes to Djinni
     * @url https://bitbucket.org/Djinni/screeps/
     */
    rest: function(civilian)
    {
        var creep = this.creep;

        var distance = 4;
        var restTarget = creep.pos.findNearest(Game.MY_SPAWNS);

        if(!civilian) {
            var flags = Game.flags;
            for (var i in flags) {
                var flag = flags[i];
                if (creep.pos.inRangeTo(flag, distance) || creep.pos.findPathTo(flag).length > 0) {
                    restTarget = flag;
                    break;
                }
            }
        }

//		var flag = Game.flags['Flag1'];
//		if(flag !== undefined && civilian !== true)
//			restTarget = flag;
//
//		var flag2 = Game.flags['Flag2'];
//		if(flag !== undefined && civilian !== true && !creep.pos.inRangeTo(flag, distance) && !creep.pos.findPathTo(flag).length)
//			restTarget = flag2;

        if (creep.getActiveBodyparts(Game.HEAL)) {
//			distance = distance - 1;
        }
        else if (creep.getActiveBodyparts(Game.RANGED_ATTACK)) {
//			distance = distance - 1;
        }
        if (creep.pos.findPathTo(restTarget).length > distance) {
            creep.moveTo(restTarget);
        }
    },

    /**
     * All credit goes to Djinni
     * @url https://bitbucket.org/Djinni/screeps/
     */
    rangedAttack: function(target) {
        var creep = this.creep;

        if(!target)
            target = creep.pos.findNearest(Game.HOSTILE_CREEPS);

        if(target) {
            if (target.pos.inRangeTo(creep.pos, 3) ) {
                creep.rangedAttack(target);
                return target;
            }
        }
        return null;
    },

    keepAwayFromEnemies: function()
    {
        var creep = this.creep;

        var target = creep.pos.findNearest(Game.HOSTILE_CREEPS);
        if(target !== null && target.pos.inRangeTo(creep.pos, 3))
            creep.moveTo(creep.pos.x + creep.pos.x - target.pos.x, creep.pos.y + creep.pos.y - target.pos.y );
    },

    /**
     * All credit goes to Djinni
     * @url https://bitbucket.org/Djinni/screeps/
     */
    kite: function(target) {
        var creep = this.creep;

        if (target.pos.inRangeTo(creep.pos, 2)) {
            creep.moveTo(creep.pos.x + creep.pos.x - target.pos.x, creep.pos.y + creep.pos.y - target.pos.y );
            return true;
        } else if (target.pos.inRangeTo(creep.pos, 3)) {
            return true;
        }
        else {
            creep.moveTo(target);
            return true;
        }

        return false;
    },

    getRangedTarget: function()
    {
        var creep = this.creep;

        var closeArchers = creep.pos.findNearest(Game.HOSTILE_CREEPS, {
            filter: function(enemy)
            {
                return enemy.getActiveBodyparts(Game.RANGED_ATTACK) > 0
                    && creep.pos.inRangeTo(enemy, 3);
            }
        });

        if(closeArchers != null)
            return closeArchers;

        var closeMobileMelee = creep.pos.findNearest(Game.HOSTILE_CREEPS, {
            filter: function(enemy)
            {
                return enemy.getActiveBodyparts(Game.ATTACK) > 0
                    && enemy.getActiveBodyparts(Game.MOVE) > 0
                    && creep.pos.inRangeTo(enemy, 3);
            }
        });

        if(closeMobileMelee != null)
            return closeMobileMelee;

        var closeHealer = creep.pos.findNearest(Game.HOSTILE_CREEPS, {
            filter: function(enemy)
            {
                return enemy.getActiveBodyparts(Game.HEAL) > 0
                    && enemy.getActiveBodyparts(Game.MOVE) > 0
                    && creep.pos.inRangeTo(enemy, 3);
            }
        });

        if(closeHealer != null)
            return closeHealer;

        return creep.pos.findNearest(Game.HOSTILE_CREEPS);
    }
};

module.exports = proto;<commit_msg>Starting the long process of fixing old code<commit_after>/**
 * Created by truthlighting on 9/20/2016.
 */
var proto = {
    /**
     * The creep for this role
     *
     * @type creep
     */
    creep: null,

    /**
     * Set the creep for this role
     *
     * @param {Creep} creep
     */
    setCreep: function(creep)
    {
        this.creep = creep;
        return this;
    },

    run: function()
    {
        if(this.creep.memory.onSpawned == undefined) {
            this.onSpawn();
            this.creep.memory.onSpawned = true;
        }

        this.action(this.creep);

        if(this.creep.ticksToLive == 1)
            this.beforeAge();
    },

    handleEvents: function()
    {
        if(this.creep.memory.onSpawned == undefined) {
            this.onSpawnStart();
            this.onSpawn();
            this.creep.memory.onSpawned = true;
        }

        if(this.creep.memory.onSpawnEnd == undefined && !this.creep.spawning) {
            this.onSpawnEnd();
            this.creep.memory.onSpawnEnd = true;
        }
    },

    getParts: function() {
        //var _ = require('lodash');

        var extensions = Game.rooms['W2N48'].find(FIND_MY_STRUCTURES, {
            filter: function(structure)
            {
                return (structure.structureType == Game.STRUCTURE_EXTENSION && structure.energy >= 200);
            }
        }).length;

        var parts = _.cloneDeep(this.parts);
        if(typeof parts[0] != "object")
            return this.parts;

        parts.reverse();

        for(var i in parts)
        {
            if((parts[i].length - 5) <= extensions) {
                return parts[i];
            }
        }
    },

    action: function() { },

    onSpawn: function() { },

    onSpawnStart: function() { },

    onSpawnEnd: function() { },

    beforeAge: function() { },

    /**
     * All credit goes to Djinni
     * @url https://bitbucket.org/Djinni/screeps/
     */
    rest: function(civilian)
    {
        var creep = this.creep;

        var distance = 4;
        var restTarget = creep.pos.findNearest(Game.MY_SPAWNS);

        if(!civilian) {
            var flags = Game.flags;
            for (var i in flags) {
                var flag = flags[i];
                if (creep.pos.inRangeTo(flag, distance) || creep.pos.findPathTo(flag).length > 0) {
                    restTarget = flag;
                    break;
                }
            }
        }

//		var flag = Game.flags['Flag1'];
//		if(flag !== undefined && civilian !== true)
//			restTarget = flag;
//
//		var flag2 = Game.flags['Flag2'];
//		if(flag !== undefined && civilian !== true && !creep.pos.inRangeTo(flag, distance) && !creep.pos.findPathTo(flag).length)
//			restTarget = flag2;

        if (creep.getActiveBodyparts(Game.HEAL)) {
//			distance = distance - 1;
        }
        else if (creep.getActiveBodyparts(Game.RANGED_ATTACK)) {
//			distance = distance - 1;
        }
        if (creep.pos.findPathTo(restTarget).length > distance) {
            creep.moveTo(restTarget);
        }
    },

    /**
     * All credit goes to Djinni
     * @url https://bitbucket.org/Djinni/screeps/
     */
    rangedAttack: function(target) {
        var creep = this.creep;

        if(!target)
            target = creep.pos.findNearest(Game.HOSTILE_CREEPS);

        if(target) {
            if (target.pos.inRangeTo(creep.pos, 3) ) {
                creep.rangedAttack(target);
                return target;
            }
        }
        return null;
    },

    keepAwayFromEnemies: function()
    {
        var creep = this.creep;

        var target = creep.pos.findNearest(Game.HOSTILE_CREEPS);
        if(target !== null && target.pos.inRangeTo(creep.pos, 3))
            creep.moveTo(creep.pos.x + creep.pos.x - target.pos.x, creep.pos.y + creep.pos.y - target.pos.y );
    },

    /**
     * All credit goes to Djinni
     * @url https://bitbucket.org/Djinni/screeps/
     */
    kite: function(target) {
        var creep = this.creep;

        if (target.pos.inRangeTo(creep.pos, 2)) {
            creep.moveTo(creep.pos.x + creep.pos.x - target.pos.x, creep.pos.y + creep.pos.y - target.pos.y );
            return true;
        } else if (target.pos.inRangeTo(creep.pos, 3)) {
            return true;
        }
        else {
            creep.moveTo(target);
            return true;
        }

        return false;
    },

    getRangedTarget: function()
    {
        var creep = this.creep;

        var closeArchers = creep.pos.findNearest(Game.HOSTILE_CREEPS, {
            filter: function(enemy)
            {
                return enemy.getActiveBodyparts(Game.RANGED_ATTACK) > 0
                    && creep.pos.inRangeTo(enemy, 3);
            }
        });

        if(closeArchers != null)
            return closeArchers;

        var closeMobileMelee = creep.pos.findNearest(Game.HOSTILE_CREEPS, {
            filter: function(enemy)
            {
                return enemy.getActiveBodyparts(Game.ATTACK) > 0
                    && enemy.getActiveBodyparts(Game.MOVE) > 0
                    && creep.pos.inRangeTo(enemy, 3);
            }
        });

        if(closeMobileMelee != null)
            return closeMobileMelee;

        var closeHealer = creep.pos.findNearest(Game.HOSTILE_CREEPS, {
            filter: function(enemy)
            {
                return enemy.getActiveBodyparts(Game.HEAL) > 0
                    && enemy.getActiveBodyparts(Game.MOVE) > 0
                    && creep.pos.inRangeTo(enemy, 3);
            }
        });

        if(closeHealer != null)
            return closeHealer;

        return creep.pos.findNearest(Game.HOSTILE_CREEPS);
    }
};

module.exports = proto;<|endoftext|>


<commit_before>var locastyle = locastyle || {};
locastyle.collapse = (function() {
  'use strict';

  // general config
  var config = {
    trigger: '[data-ls-module="collapse"]',
    classes: {
      header        : '.ls-collapse-header',
      content       : '.ls-collapse-body',
      groupContainer: '.ls-collapse-group',
      open          : 'ls-collapse-open',
      close         : 'ls-collapse-close',
      opened        : 'ls-collapse-opened',
      alwaysOpened  : 'ls-collapse-opened-always'
    }
  };

  function init() {
    // set attributes from all collapses on load
    $(config.classes.header).each(function() {
      ariaCollapse($(this));
    });
    bind();
  }

  function bind() {
    $(config.trigger).each(function(index, element) {
      if (!$(element).hasClass(config.classes.alwaysOpened)) {
        $(element).on('click.ls', function() {
          groupCollapse($(this));
          // get target
          var target = $(this).data('target');
          toggle(target);
          console.log(target);
          console.log($(this));
          // set aria's attributes
          ariaCollapse($(this));

          eventsHandler($(this),target);
        });
        // if click on ck-collapse-body no action happens
        $(config.classes.content).on('click.ls', function(event) {
          event.stopPropagation();
        });
      }
    });
  }

  // if have collapses in group "accordeon"
  function groupCollapse($collapse) {
    var $group = $($collapse).parents(config.classes.groupContainer);
    if ($group[0]) {
      $group.find(config.trigger).not($($collapse)).removeClass(config.classes.opened).find(config.classes.content).slideUp();
    }
  }

  function toggle(target) {
    $(target).slideToggle(function() {
      $(target).parent().toggleClass(config.classes.opened);
    });
  }

  function eventsHandler(el, target) {
    if($(el).hasClass(config.classes.opened)) {
      $.event.trigger('collapse:opened', [$(this), $(target)]);
    } else {
      $.event.trigger('collapse:closed', [$(this), $(target)]);
    }
  }

  function ariaCollapse(elem) {
    if($(elem).hasClass('ls-collapse-open')){
      $(config.classes.header).attr({ 'aria-expanded' : true });
      $(config.classes.content).attr({ 'aria-hidden' : false });
    }else{
      $(config.classes.header).attr({ 'aria-expanded' : false });
      $(config.classes.content).attr({ 'aria-hidden' : true });
    }
  }

  return {
    init: init,
    toggle: toggle
  };

}());
<commit_msg>fix events of collapse<commit_after>var locastyle = locastyle || {};
locastyle.collapse = (function() {
  'use strict';

  // general config
  var config = {
    trigger: '[data-ls-module="collapse"]',
    classes: {
      header        : '.ls-collapse-header',
      content       : '.ls-collapse-body',
      groupContainer: '.ls-collapse-group',
      open          : 'ls-collapse-open',
      close         : 'ls-collapse-close',
      opened        : 'ls-collapse-opened',
      alwaysOpened  : 'ls-collapse-opened-always'
    }
  };

  function init() {
    // set attributes from all collapses on load
    $(config.classes.header).each(function() {
      ariaCollapse($(this));
    });
    bind();
  }

  function bind() {
    $(config.trigger).each(function(index, element) {
      if (!$(element).hasClass(config.classes.alwaysOpened)) {
        $(element).on('click.ls', function() {
          groupCollapse($(this));
          // get target
          var target = $(this).data('target');
          toggle(target);
          console.log(target);
          // set aria's attributes
          ariaCollapse($(this));

          eventsHandler(target);

        });
        // if click on ck-collapse-body no action happens
        $(config.classes.content).on('click.ls', function(event) {
          event.stopPropagation();
        });
      }
    });
  }

  // if have collapses in group "accordeon"
  function groupCollapse($collapse) {
    var $group = $($collapse).parents(config.classes.groupContainer);
    if ($group[0]) {
      $group.find(config.trigger).not($($collapse)).removeClass(config.classes.opened).find(config.classes.content).slideUp();
    }
  }

  function toggle(target) {
    $(target).slideToggle(function() {
      $(target).parent().toggleClass(config.classes.opened);
      // eventsHandler(target);
    });
  }

  function eventsHandler(target) {
    if($(target).parents(config.trigger).hasClass(config.classes.opened)) {
      $.event.trigger('collapse:opened', [$(target)]);
    } else {
      $.event.trigger('collapse:closed', [$(target)]);
    }
  }

  function ariaCollapse(elem) {
    if($(elem).hasClass('ls-collapse-open')){
      $(config.classes.header).attr({ 'aria-expanded' : true });
      $(config.classes.content).attr({ 'aria-hidden' : false });
    }else{
      $(config.classes.header).attr({ 'aria-expanded' : false });
      $(config.classes.content).attr({ 'aria-hidden' : true });
    }
  }

  return {
    init: init,
    toggle: toggle
  };

}());
<|endoftext|>


<commit_before>/*

dlInfo.js

*/

var nitro = require('./nitroSdk');
var xmlToJson = require('jgeXml/xml2json');

var pid = process.argv[2]; // a version PID (vPID) e.g. b01r5278

var config = require('./config.json');
var mediaSet = config.nitro.mediaset;

if (process.argv.length>3) {
  mediaSet = process.argv[3]; // override the config mediaset
}

var q1 = nitro.newQuery();

// http://www.bbc.co.uk/mediaselector/3/auth/iplayer_streaming_http_mp4/b0094yrk
// http://www.bbc.co.uk/mediaselector/3/stream/check/iplayer?pid=PID
// http://www.bbc.co.uk/mediaselector/4/mtis/stream/{vpid}
// http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/vpid/{vpid}/format/json/mediaset/{mediaSet}/proto/http
// http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/vpid/b006v299/format/json/mediaset/pc/proto/http
// http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/vpid/bbc_two_england/mediaset/pc/atk/ce6cf9bb4e462e3f6128b168891a0010b06ba663/asn/1/

var options = {};
options.headers = {'Accept':'application/xml'};
nitro.make_request('www.bbc.co.uk','/mediaselector/4/mtis/stream/'+pid,'',q1,options,function(obj){
	console.log(JSON.stringify(xmlToJson.xml2json(obj),null,2));
});

function mediaselector5(proto){
	nitro.make_request('open.live.bbc.co.uk','/mediaselector/5/select/version/2.0/vpid/'+pid+
		'/format/json/mediaset/'+mediaSet+'/proto/'+proto,'',q1,{},function(obj){

		for (var i in obj.media) {
			var media = obj.media[i];
			console.log(media);
		}
		console.log();
	});
}

mediaselector5('http');
mediaselector5('rtmp');

// http://www.prweb.com/releases/2016/04/prweb13347368.htm
// http://open.live.bbc.co.uk/axs/open/authxml?media_set=pc&version_pid=b006v299&format=xml
// https://av-media-sslgate.live.bbc.co.uk/saml/axs/open/authxml?media_set=%s&version_pid=%s&format=base64
// https://open.live.bbc.co.uk/drmauth/1/version/1.0/mediaset/%s/vpid/%s/ (returns 403)
/*

MANIFEST

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Unified Streaming Platform(version=1.7.9) -->
<SmoothStreamingMedia Duration="28864000000" TimeScale="10000000" MinorVersion="0" MajorVersion="2">
<StreamIndex TimeScale="10000000" Url="QualityLevels({bitrate})/Fragments(audio={start time})" Chunks="451" Name="audio" QualityLevels="1" Type="audio">
<QualityLevel FourCC="AACL" AudioTag="255" PacketSize="4" BitsPerSample="16" Channels="2" SamplingRate="48000" CodecPrivateData="1190" Bitrate="320000" Index="0"/>
<c t="0" d="64000000"/>
<c d="64000000"/>
...
<c d="64000000"/>
</StreamIndex>
<Protection>
<ProtectionHeader SystemID="9A04F079-9840-4286-AB92-E65BE0885F95">mgIAAAEAAQCQAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AKwBwAG4AaQBJADAALwBVAFMAUQBLAE0AOAA2AGMATwB5AGcAaQArAGwAZwA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgArAFUASgB0ACsATgBrADAAMQBSAGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAOgAvAC8AcwBsAGQAcgBtAC4AbABpAGMAZQBuAHMAZQBrAGUAeQBzAGUAcgB2AGUAcgAuAGMAbwBtAC8AYwBvAHIAZQAvAHIAaQBnAGgAdABzAG0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</ProtectionHeader>
</Protection>
</SmoothStreamingMedia>

*/

/*

<WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.0.0.0"><DATA><PROTECTINFO><KEYLEN>16</KEYLEN><ALGID>AESCTR</ALGID></PROTECTINFO><KID>+pniI0/USQKM86cOygi+lg==</KID><CHECKSUM>+UJt+Nk01Rg=</CHECKSUM><LA_URL>http://sldrm.licensekeyserver.com/core/rightsmanager.asmx</LA_URL></DATA></WRMHEADER>

http://sldrm.licensekeyserver.com/core/rightsmanager.asmx?wsdl

*/

var q2 = nitro.newQuery();
q2.add('media_set',mediaSet)
	.add('version_pid',pid)
	.add('format','xml'); // or base64

nitro.make_request('open.live.bbc.co.uk','/axs/open/authxml','',q2,
	{headers:{Accept: 'text/html,application/xhtml+xml,application/xml'}},function(obj){
	console.log('Converted from XML');
	console.log(JSON.stringify(xmlToJson.xml2json(obj),null,2));
});

<commit_msg>dlInfo; fix require jgexml<commit_after>/*

dlInfo.js

*/

var nitro = require('./nitroSdk');
var xmlToJson = require('jgexml/xml2json');

var pid = process.argv[2]; // a version PID (vPID) e.g. b01r5278

var config = require('./config.json');
var mediaSet = config.nitro.mediaset;

if (process.argv.length>3) {
  mediaSet = process.argv[3]; // override the config mediaset
}

var q1 = nitro.newQuery();

// http://www.bbc.co.uk/mediaselector/3/auth/iplayer_streaming_http_mp4/b0094yrk
// http://www.bbc.co.uk/mediaselector/3/stream/check/iplayer?pid=PID
// http://www.bbc.co.uk/mediaselector/4/mtis/stream/{vpid}
// http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/vpid/{vpid}/format/json/mediaset/{mediaSet}/proto/http
// http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/vpid/b006v299/format/json/mediaset/pc/proto/http
// http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/vpid/bbc_two_england/mediaset/pc/atk/ce6cf9bb4e462e3f6128b168891a0010b06ba663/asn/1/

var options = {};
options.headers = {'Accept':'application/xml'};
nitro.make_request('www.bbc.co.uk','/mediaselector/4/mtis/stream/'+pid,'',q1,options,function(obj){
	console.log(JSON.stringify(xmlToJson.xml2json(obj),null,2));
});

function mediaselector5(proto){
	nitro.make_request('open.live.bbc.co.uk','/mediaselector/5/select/version/2.0/vpid/'+pid+
		'/format/json/mediaset/'+mediaSet+'/proto/'+proto,'',q1,{},function(obj){

		for (var i in obj.media) {
			var media = obj.media[i];
			console.log(media);
		}
		console.log();
	});
}

mediaselector5('http');
mediaselector5('rtmp');

// http://www.prweb.com/releases/2016/04/prweb13347368.htm
// http://open.live.bbc.co.uk/axs/open/authxml?media_set=pc&version_pid=b006v299&format=xml
// https://av-media-sslgate.live.bbc.co.uk/saml/axs/open/authxml?media_set=%s&version_pid=%s&format=base64
// https://open.live.bbc.co.uk/drmauth/1/version/1.0/mediaset/%s/vpid/%s/ (returns 403)
/*

MANIFEST

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Unified Streaming Platform(version=1.7.9) -->
<SmoothStreamingMedia Duration="28864000000" TimeScale="10000000" MinorVersion="0" MajorVersion="2">
<StreamIndex TimeScale="10000000" Url="QualityLevels({bitrate})/Fragments(audio={start time})" Chunks="451" Name="audio" QualityLevels="1" Type="audio">
<QualityLevel FourCC="AACL" AudioTag="255" PacketSize="4" BitsPerSample="16" Channels="2" SamplingRate="48000" CodecPrivateData="1190" Bitrate="320000" Index="0"/>
<c t="0" d="64000000"/>
<c d="64000000"/>
...
<c d="64000000"/>
</StreamIndex>
<Protection>
<ProtectionHeader SystemID="9A04F079-9840-4286-AB92-E65BE0885F95">mgIAAAEAAQCQAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AKwBwAG4AaQBJADAALwBVAFMAUQBLAE0AOAA2AGMATwB5AGcAaQArAGwAZwA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgArAFUASgB0ACsATgBrADAAMQBSAGcAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAOgAvAC8AcwBsAGQAcgBtAC4AbABpAGMAZQBuAHMAZQBrAGUAeQBzAGUAcgB2AGUAcgAuAGMAbwBtAC8AYwBvAHIAZQAvAHIAaQBnAGgAdABzAG0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</ProtectionHeader>
</Protection>
</SmoothStreamingMedia>

*/

/*

<WRMHEADER xmlns="http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader" version="4.0.0.0"><DATA><PROTECTINFO><KEYLEN>16</KEYLEN><ALGID>AESCTR</ALGID></PROTECTINFO><KID>+pniI0/USQKM86cOygi+lg==</KID><CHECKSUM>+UJt+Nk01Rg=</CHECKSUM><LA_URL>http://sldrm.licensekeyserver.com/core/rightsmanager.asmx</LA_URL></DATA></WRMHEADER>

http://sldrm.licensekeyserver.com/core/rightsmanager.asmx?wsdl

*/

var q2 = nitro.newQuery();
q2.add('media_set',mediaSet)
	.add('version_pid',pid)
	.add('format','xml'); // or base64

nitro.make_request('open.live.bbc.co.uk','/axs/open/authxml','',q2,
	{headers:{Accept: 'text/html,application/xhtml+xml,application/xml'}},function(obj){
	console.log('Converted from XML');
	console.log(JSON.stringify(xmlToJson.xml2json(obj),null,2));
});

<|endoftext|>


<commit_before>
const tape = require('tape');
const tcase = require('tape-case');

const m = require('../index.js');

const rank_A = [
  {rank:'A', type:'H'},
  {rank:'4', type:'H'},
  {rank:'J', type:'S'},
  {rank:'Q', type:'D'},
  {rank:'9', type:'C'}
];

const pair_of_Q = [
  {rank:'2', type:'H'},
  {rank:'4', type:'H'},
  {rank:'Q', type:'S'},
  {rank:'Q', type:'D'},
  {rank:'9', type:'C'}
];

const pair_of_3 = [
  {rank:'3', type:'H'},
  {rank:'4', type:'H'},
  {rank:'3', type:'S'},
  {rank:'Q', type:'D'},
  {rank:'9', type:'C'}

];

const doublePair_of_9 = [
  {rank:'3', type:'H'},
  {rank:'9', type:'H'},
  {rank:'3', type:'S'},
  {rank:'9', type:'D'},
  {rank:'A', type:'C'}
];

const threeOfAKind_of_J = [
  {rank:'J', type:'H'},
  {rank:'9', type:'D'},
  {rank:'J', type:'S'},
  {rank:'J', type:'C'},
  {rank:'5', type:'C'}
];

const stright_of_9 = [
  {rank:'6', type:'H'},
  {rank:'7', type:'D'},
  {rank:'9', type:'S'},
  {rank:'8', type:'C'},
  {rank:'5', type:'C'}
];

const stright_of_A_top = [
  {rank:'K', type:'H'},
  {rank:'J', type:'D'},
  {rank:'A', type:'S'},
  {rank:'10', type:'C'},
  {rank:'Q', type:'C'}
];

const stright_of_A_bottom = [
  {rank:'3', type:'H'},
  {rank:'4', type:'D'},
  {rank:'2', type:'S'},
  {rank:'5', type:'C'},
  {rank:'A', type:'C'}
];

const flush_of_J = [
  {rank:'3', type:'H'},
  {rank:'4', type:'H'},
  {rank:'2', type:'H'},
  {rank:'5', type:'H'},
  {rank:'J', type:'H'}
];

const flush_of_5 = [
  {rank:'2', type:'D'},
  {rank:'4', type:'D'},
  {rank:'2', type:'D'},
  {rank:'5', type:'D'},
  {rank:'4', type:'D'}
];

const full_of_7 = [
  {rank:'7', type:'D'},
  {rank:'7', type:'S'},
  {rank:'2', type:'D'},
  {rank:'7', type:'H'},
  {rank:'2', type:'C'}
];

const full_of_3 = [
  {rank:'3', type:'D'},
  {rank:'3', type:'S'},
  {rank:'A', type:'D'},
  {rank:'3', type:'H'},
  {rank:'A', type:'C'}
];

const poker_of_A = [
  {rank:'A', type:'H'},
  {rank:'9', type:'D'},
  {rank:'A', type:'S'},
  {rank:'A', type:'C'},
  {rank:'A', type:'D'}
];

const strightFlush_of_9 = [
  {rank:'6', type:'H'},
  {rank:'7', type:'H'},
  {rank:'9', type:'H'},
  {rank:'8', type:'H'},
  {rank:'5', type:'H'}
];

const strightFlush_of_A_bottom = [
  {rank:'3', type:'D'},
  {rank:'4', type:'D'},
  {rank:'2', type:'D'},
  {rank:'5', type:'D'},
  {rank:'A', type:'D'}
];

const royalStrightFlush = [
  {rank:'K', type:'C'},
  {rank:'J', type:'C'},
  {rank:'A', type:'C'},
  {rank:'10', type:'C'},
  {rank:'Q', type:'C'}
];

tape('poker-has:', function(t) { t.end(); });

tape('check interface', function(t) {

  t.equal(typeof m.hasHighestCard, 'function', 'has-highest-card is a function');
  t.equal(typeof m.hasPair, 'function', 'has-pair is a function');
  t.equal(typeof m.hasDoublePair, 'function', 'has-double-pair is a function');
  t.equal(typeof m.hasThreeOfAKind, 'function', 'has-three-of-a-kind is a function');
  t.equal(typeof m.hasStraight, 'function', 'has-straight is a function');
  t.equal(typeof m.hasFlush, 'function', 'has-flush is a function');
  t.equal(typeof m.hasFullHouse, 'function', 'has-full-house is a function');
  t.equal(typeof m.hasPoker, 'function', 'has-poker is a function');
  t.equal(typeof m.hasStraightFlush, 'function', 'has-straight-flush is a function');
  t.equal(typeof m.hasRoyalStraightFlush, 'function', 'has-royal-straight-flush is a function');

  t.end();

});

/*
 * hasHighestCard
 */

tcase([
  { description: 'has-highest-card', args: [rank_A], result: { strength: 0, rank: 'A' } },
  { args: [pair_of_Q], result: { strength: 0, rank: 'Q' } },
  { args: [pair_of_3], result: { strength: 0, rank: 'Q' } }
], function(cards) {

  return m.hasHighestCard(cards);

});

/*
 * hasPair
 */

tcase([
  { description: 'has-pair', args: [rank_A], result: false },
  { args: [pair_of_Q], result: { strength: 1, rank: 'Q' } },
  { args: [pair_of_3], result: { strength: 1, rank: '3' } },
  { args: [doublePair_of_9], result: false },
  { args: [threeOfAKind_of_J], result: false },
  { args: [poker_of_A], result: false }
], function(cards) {

  return m.hasPair(cards);

});
<commit_msg>use test case<commit_after>
const tape = require('tape');
const tcase = require('tape-case');

const m = require('../index.js');

const rank_A = [
  {rank:'A', type:'H'},
  {rank:'4', type:'H'},
  {rank:'J', type:'S'},
  {rank:'Q', type:'D'},
  {rank:'9', type:'C'}
];

const pair_of_Q = [
  {rank:'2', type:'H'},
  {rank:'4', type:'H'},
  {rank:'Q', type:'S'},
  {rank:'Q', type:'D'},
  {rank:'9', type:'C'}
];

const pair_of_3 = [
  {rank:'3', type:'H'},
  {rank:'4', type:'H'},
  {rank:'3', type:'S'},
  {rank:'Q', type:'D'},
  {rank:'9', type:'C'}

];

const doublePair_of_9 = [
  {rank:'3', type:'H'},
  {rank:'9', type:'H'},
  {rank:'3', type:'S'},
  {rank:'9', type:'D'},
  {rank:'A', type:'C'}
];

const threeOfAKind_of_J = [
  {rank:'J', type:'H'},
  {rank:'9', type:'D'},
  {rank:'J', type:'S'},
  {rank:'J', type:'C'},
  {rank:'5', type:'C'}
];

const stright_of_9 = [
  {rank:'6', type:'H'},
  {rank:'7', type:'D'},
  {rank:'9', type:'S'},
  {rank:'8', type:'C'},
  {rank:'5', type:'C'}
];

const stright_of_A_top = [
  {rank:'K', type:'H'},
  {rank:'J', type:'D'},
  {rank:'A', type:'S'},
  {rank:'10', type:'C'},
  {rank:'Q', type:'C'}
];

const stright_of_A_bottom = [
  {rank:'3', type:'H'},
  {rank:'4', type:'D'},
  {rank:'2', type:'S'},
  {rank:'5', type:'C'},
  {rank:'A', type:'C'}
];

const flush_of_J = [
  {rank:'3', type:'H'},
  {rank:'4', type:'H'},
  {rank:'2', type:'H'},
  {rank:'5', type:'H'},
  {rank:'J', type:'H'}
];

const flush_of_8 = [
  {rank:'2', type:'D'},
  {rank:'3', type:'D'},
  {rank:'8', type:'D'},
  {rank:'5', type:'D'},
  {rank:'6', type:'D'}
];

const full_of_7 = [
  {rank:'7', type:'D'},
  {rank:'7', type:'S'},
  {rank:'2', type:'D'},
  {rank:'7', type:'H'},
  {rank:'2', type:'C'}
];

const full_of_3 = [
  {rank:'3', type:'D'},
  {rank:'3', type:'S'},
  {rank:'A', type:'D'},
  {rank:'3', type:'H'},
  {rank:'A', type:'C'}
];

const poker_of_A = [
  {rank:'A', type:'H'},
  {rank:'9', type:'D'},
  {rank:'A', type:'S'},
  {rank:'A', type:'C'},
  {rank:'A', type:'D'}
];

const strightFlush_of_9 = [
  {rank:'6', type:'H'},
  {rank:'7', type:'H'},
  {rank:'9', type:'H'},
  {rank:'8', type:'H'},
  {rank:'5', type:'H'}
];

const strightFlush_of_A_bottom = [
  {rank:'3', type:'D'},
  {rank:'4', type:'D'},
  {rank:'2', type:'D'},
  {rank:'5', type:'D'},
  {rank:'A', type:'D'}
];

const royalStrightFlush = [
  {rank:'K', type:'C'},
  {rank:'J', type:'C'},
  {rank:'A', type:'C'},
  {rank:'10', type:'C'},
  {rank:'Q', type:'C'}
];

tape('poker-has:', function(t) { t.end(); });

tape('check interface', function(t) {

  t.equal(typeof m.hasHighestCard, 'function', 'has-highest-card is a function');
  t.equal(typeof m.hasPair, 'function', 'has-pair is a function');
  t.equal(typeof m.hasDoublePair, 'function', 'has-double-pair is a function');
  t.equal(typeof m.hasThreeOfAKind, 'function', 'has-three-of-a-kind is a function');
  t.equal(typeof m.hasStraight, 'function', 'has-straight is a function');
  t.equal(typeof m.hasFlush, 'function', 'has-flush is a function');
  t.equal(typeof m.hasFullHouse, 'function', 'has-full-house is a function');
  t.equal(typeof m.hasPoker, 'function', 'has-poker is a function');
  t.equal(typeof m.hasStraightFlush, 'function', 'has-straight-flush is a function');
  t.equal(typeof m.hasRoyalStraightFlush, 'function', 'has-royal-straight-flush is a function');

  t.end();

});

/*
 * hasHighestCard
 */

tcase([
  { description: 'has-highest-card', args: [rank_A], result: { strength: 0, rank: 'A' } },
  { args: [pair_of_Q], result: { strength: 0, rank: 'Q' } },
  { args: [pair_of_3], result: { strength: 0, rank: 'Q' } },
  { args: [doublePair_of_9], result: { strength: 0, rank: 'A' } },
  { args: [threeOfAKind_of_J], result: { strength: 0, rank: 'J' } },
  { args: [stright_of_9], result: { strength: 0, rank: '9' } },
  { args: [stright_of_A_top], result: { strength: 0, rank: 'A' } },
  { args: [stright_of_A_bottom], result: { strength: 0, rank: 'A' } },
  { args: [flush_of_J], result: { strength: 0, rank: 'J' } },
  { args: [flush_of_8], result: { strength: 0, rank: '8' } },
  { args: [full_of_7], result: { strength: 0, rank: '7' } },
  { args: [full_of_3], result: { strength: 0, rank: 'A' } },
  { args: [poker_of_A], result: { strength: 0, rank: 'A' } },
  { args: [strightFlush_of_9], result: { strength: 0, rank: '9' } },
  { args: [strightFlush_of_A_bottom], result: { strength: 0, rank: 'A' } },
  { args: [royalStrightFlush], result: { strength: 0, rank: 'A' } }
], function(cards) {

  return m.hasHighestCard(cards);

});

/*
 * hasPair
 */

tcase([
  { description: 'has-pair', args: [rank_A], result: false },
  { args: [pair_of_Q], result: { strength: 1, rank: 'Q' } },
  { args: [pair_of_3], result: { strength: 1, rank: '3' } },
  { args: [doublePair_of_9], result: false },
  { args: [threeOfAKind_of_J], result: false },
  { args: [stright_of_9], result: false },
  { args: [stright_of_A_top], result: false },
  { args: [stright_of_A_bottom], result: false },
  { args: [flush_of_J], result: false },
  { args: [flush_of_8], result: false },
  { args: [full_of_7], result: false },
  { args: [full_of_3], result: false },
  { args: [poker_of_A], result: false },
  { args: [strightFlush_of_9], result: false },
  { args: [strightFlush_of_A_bottom], result: false },
  { args: [royalStrightFlush], result: false }
], function(cards) {

  return m.hasPair(cards);

});
<|endoftext|>


<commit_before>/* eslint no-unused-expressions: 0 */
import React from 'react'
import { mount } from 'enzyme'
import { spy } from 'sinon'
import chai, { expect } from 'chai'
import ContainerDimensions from '../src/index'

chai.use(require('chai-enzyme')())
const MyComponent = ({ width, height }) => {width}, {height} // eslint-disable-line

describe('react-container-dimensions', () => {

    it('should throw without children', () => {
        expect(() => mount(
<ContainerDimensions />
))
            .to.throw('Expected children to be one of function or React.Element')
    })

    it('calls componentDidMount', (done) => {
        spy(ContainerDimensions.prototype, 'componentDidMount')
        spy(ContainerDimensions.prototype, 'componentWillUnmount')
        const wrapper = mount(

                <ContainerDimensions>
                    <MyComponent />
                </ContainerDimensions>

        , { attachTo: document.body })
        expect(wrapper.find('div').length).to.eq(1)
        expect(ContainerDimensions.prototype.componentDidMount.calledOnce).to.be.true
        ContainerDimensions.prototype.componentDidMount.restore()
        setTimeout(() => {
            wrapper.unmount()
            expect(ContainerDimensions.prototype.componentWillUnmount.calledOnce).to.be.true
            ContainerDimensions.prototype.componentWillUnmount.restore()
            done()
        }, 0)
    })

    it('calls onResize on mount', () => {
        spy(ContainerDimensions.prototype, 'onResize')
        mount(

                <ContainerDimensions>
                    <MyComponent />
                </ContainerDimensions>

        )
        expect(ContainerDimensions.prototype.onResize.calledOnce).to.be.true
        ContainerDimensions.prototype.onResize.restore()
    })

    it('calls onResize when parent has been resized', (done) => {
        spy(ContainerDimensions.prototype, 'onResize')
        const wrapper = mount(

                <ContainerDimensions>
                    <MyComponent />
                </ContainerDimensions>

        , { attachTo: document.body })
        const el = wrapper.render()
        el.css('width', 10)
        setTimeout(() => {
            el.css('width', 100)
            expect(ContainerDimensions.prototype.onResize.calledTwice).to.be.true
            ContainerDimensions.prototype.onResize.restore()
            done()
        }, 0)
    })

    it('should pass width and height as props to its children', () => {
        const wrapper = mount(
            <ContainerDimensions>
                <MyComponent />
            </ContainerDimensions>
        )
        wrapper.setState({
            width: 100,
            height: 200
        })
        expect(wrapper.find(MyComponent)).to.have.length(1)
        expect(wrapper.find(MyComponent)).to.have.prop('width', 100)
        expect(wrapper.find(MyComponent)).to.have.prop('height', 200)
    })

    it('should pass width and height as function arguments', () => {
        const wrapper = mount(
            <ContainerDimensions>
                {
                    ({ width, height }) => <MyComponent width={width + 10} height={height + 10} /> // eslint-disable-line
                }
            </ContainerDimensions>
        )
        wrapper.setState({
            width: 100,
            height: 200
        })
        expect(wrapper.find(MyComponent)).to.have.length(1)
        expect(wrapper.find(MyComponent)).to.have.prop('width', 110)
        expect(wrapper.find(MyComponent)).to.have.prop('height', 210)
    })

    it('should work with SVG elements', () => {
        const wrapper = mount(
            <ContainerDimensions>
                <rect />
            </ContainerDimensions>
        )
        wrapper.setState({
            width: 100,
            height: 200
        })
        expect(wrapper.find('rect')).to.have.length(1)
        expect(wrapper.find('rect')).to.have.prop('width', 100)
        expect(wrapper.find('rect')).to.have.prop('height', 200)
    })

    it('should not create a DOM element for itself', () => {
        const wrapper = mount(

                <ContainerDimensions>
                    Test
                </ContainerDimensions>

        )
        expect(wrapper.html()).to.eql('
Test

')
    })
})
<commit_msg>add tests<commit_after>/* eslint no-unused-expressions: 0 */
import React from 'react'
import { mount } from 'enzyme'
import { spy } from 'sinon'
import chai, { expect } from 'chai'
import ContainerDimensions from '../src/index'

chai.use(require('chai-enzyme')())
const MyComponent = ({ width, height }) => {width}, {height} // eslint-disable-line

describe('react-container-dimensions', () => {

    it('should throw without children', () => {
        expect(() => mount(
<ContainerDimensions />
))
            .to.throw('Expected children to be one of function or React.Element')
    })

    it('calls componentDidMount', (done) => {
        spy(ContainerDimensions.prototype, 'componentDidMount')
        spy(ContainerDimensions.prototype, 'componentWillUnmount')
        const wrapper = mount(

                <ContainerDimensions>
                    <MyComponent />
                </ContainerDimensions>

        , { attachTo: document.body })
        expect(wrapper.find('div').length).to.eq(1)
        expect(ContainerDimensions.prototype.componentDidMount.calledOnce).to.be.true
        ContainerDimensions.prototype.componentDidMount.restore()
        setTimeout(() => {
            wrapper.unmount()
            expect(ContainerDimensions.prototype.componentWillUnmount.calledOnce).to.be.true
            ContainerDimensions.prototype.componentWillUnmount.restore()
            done()
        }, 0)
    })

    it('calls onResize on mount', () => {
        spy(ContainerDimensions.prototype, 'onResize')
        mount(

                <ContainerDimensions>
                    <MyComponent />
                </ContainerDimensions>

        )
        expect(ContainerDimensions.prototype.onResize.calledOnce).to.be.true
        ContainerDimensions.prototype.onResize.restore()
    })

    it('calls onResize when parent has been resized', (done) => {
        spy(ContainerDimensions.prototype, 'onResize')
        const wrapper = mount(

                <ContainerDimensions>
                    <MyComponent />
                </ContainerDimensions>

        , { attachTo: document.body })
        const el = wrapper.render()
        el.css('width', 10)
        setTimeout(() => {
            el.css('width', 100)
            expect(ContainerDimensions.prototype.onResize.calledTwice).to.be.true
            ContainerDimensions.prototype.onResize.restore()
            done()
        }, 0)
    })

    it('should initially render an empty placeholder', () => {
        const wrapper = mount(
            <ContainerDimensions>
                <MyComponent />
            </ContainerDimensions>
        )

        wrapper.setState({
            initiated: false
        })

        expect(wrapper.find(ContainerDimensions)).to.have.exactly(1).descendants('div')
        expect(wrapper.find(ContainerDimensions)).to.have.html('

')
        expect(wrapper.find(ContainerDimensions)).to.not.contain(<MyComponent />)
    })

    it('should pass width and height as props to its children', () => {
        const wrapper = mount(
            <ContainerDimensions>
                <MyComponent />
            </ContainerDimensions>
        )
        wrapper.setState({
            width: 100,
            height: 200
        })
        expect(wrapper.find(MyComponent)).to.have.length(1)
        expect(wrapper.find(MyComponent)).to.have.prop('width', 100)
        expect(wrapper.find(MyComponent)).to.have.prop('height', 200)
    })

    it('should pass width and height as function arguments', () => {
        const wrapper = mount(
            <ContainerDimensions>
                {
                    ({ width, height }) => <MyComponent width={width + 10} height={height + 10} /> // eslint-disable-line
                }
            </ContainerDimensions>
        )
        wrapper.setState({
            width: 100,
            height: 200
        })
        expect(wrapper.find(MyComponent)).to.have.length(1)
        expect(wrapper.find(MyComponent)).to.have.prop('width', 110)
        expect(wrapper.find(MyComponent)).to.have.prop('height', 210)
    })

    it('should work with SVG elements', () => {
        const wrapper = mount(
            <ContainerDimensions>
                <rect />
            </ContainerDimensions>
        )
        wrapper.setState({
            width: 100,
            height: 200
        })
        expect(wrapper.find('rect')).to.have.length(1)
        expect(wrapper.find('rect')).to.have.prop('width', 100)
        expect(wrapper.find('rect')).to.have.prop('height', 200)
    })

    it('should not create a DOM element for itself', () => {
        const wrapper = mount(

                <ContainerDimensions>
                    Test
                </ContainerDimensions>

        )
        expect(wrapper.html()).to.eql('
Test

')
    })
})
<|endoftext|>