<commit_before>const Quote = ({ handle, name, text }) => (

{text}

        {name}
        <a href={`https://twitter.com/${handle}`} className="handle">
          {handle}

)

const QUOTES = [
  {
    handle: '@michaeldick',
    name: 'Dick',
    text:
      "My life just changed; this is exactly the screen capture app I've been needing"
  },
  {
    handle: '@mikeal',
    name: 'Mikeal Rogers',
    text:
      "This is the best screen capture app right now, if you haven't already, check it out"
  },
  {
    handle: '@timothyachumba',
    name: 'Timothy ッ',
    text: 'Kap is a must have. I use it almost every day.'
  },
  {
    handle: '@mxstbr',
    name: 'Max Stoiber',
    text:
      'Extremely impressed with the Kap 1.0 release; this is the best screen recorder ever, built with web technologies! :100:'
  },
  {
    handle: '@maxvoltar',
    name: 'Tim Van Damme',
    text: "New Kap! It's my favorite screen capture app."
  },
  {
    handle: '@michaelschultz',
    name: 'Michael Schultz',
    text: "Kap is maybe the best GIF recorder I've used so far."
  },
  {
    handle: '@ThrivingKings',
    name: 'Daniel Raftery',
    text:
      "I can't recommend Kap enough. Sprinkle your bugs/PRs with animated GIF screen captures. It's seriously awesome."
  },
  {
    handle: '@boogah',
    name: 'Jason Cosper',
    text:
      "Been looking for a nice, easy to use screen recorder. Kap seems to fit the bill. Bonus: it's open source."
  },
  {
    handle: '@jeffreydgroot',
    name: 'Jeffrey de Groot',
    text:
      'Kap makes it really easy to record and export screen captures. And it looks nice :)'
  },
  {
    handle: '@GilliSig',
    name: 'Gilli Sigurdsson',
    text:
      "I think it's safe to say that Kap creates the best gifs of any app I ever used. And best of all it's open source!"
  },
  {
    handle: '@andrewchilds',
    name: 'Andrew Childs',
    text:
      "I've tried many screen capturing tools - getkap.co is by far the easiest to use and results are high-quality 👏 @wulkanocom"
  },
  {
    handle: '@ChrisFerdinandi',
    name: 'Chris Ferdinandi',
    text: "The world's best screen capture software gets even better. getkap.co"
  },
  {
    handle: '@malweene',
    name: 'Malwinei',
    text:
      'Just installed getkap.co via homebew and Cask! Pretty hot combination. 🔥 Very impressed. Try it. Best screen recording! ✨'
  },
  {
    handle: '@cesarzeppini',
    name: 'Cesar Zeppini',
    text:
      "Very well designed screen recording app. And it's open source! getkap.co #design #opensource"
  },
  {
    handle: '@oscrse',
    name: 'Oscar Nilsson',
    text:
      "Kap is soooooo good for quick screen recordings. Can't recommend enough 👏"
  },
  {
    handle: '@mordorinc',
    name: 'Nicolas Prieto',
    text:
      'Much love to small, useful, simple and well thought apps. Thanks @wulkanocom for getkap.co!'
  },
  {
    handle: '@bitandbang',
    name: 'Tierney Cyren',
    text:
      'I use Kap daily for GIF capture, including technical demo GIFs I create for the @NodeSource blog. Highly recommend you gif it a shot! 🙌'
  },
  {
    handle: '@stephenmeszaros',
    name: 'Stephen Meszaros',
    text:
      "My go-to screen recorder for Mac just updated! Trimming, plugins and much more. Don't sleep on this."
  },
  {
    handle: '@slavakim_',
    name: 'Slava',
    text:
      'I *love* stuff like this. Solving one specific problem in a simple and compelling way getkap.co'
  },
  {
    handle: '@_albertogallego',
    name: 'Alberto Gallego',
    text:
      'I spent so much time looking something like getkap.co. The simplest way to record your screen. And easy to export. 😍'
  }
].sort(() => 0.5 - Math.random())

// TODO do this nicer
const split = (quotes, columns) => {
  let ret = []
  let index = 0

  for (let index = 0; index < columns; index++) {
    ret.push([])
  }

  for (const quote of quotes) {
    if (index === columns) index = 0
    ret[index] = [...ret[index], quote]
    index = index + 1
  }

  return ret
}

const Columns = ({ columns, quotes }) => {
  const quoteColumns = split(quotes, columns)
  return (

      {quoteColumns.map((column, index) => (

          {column.map((quote, index) => (
            <Quote key={quote.handle + index} {...quote} />
          ))}

      ))}

  )
}

export default class Quotes extends React.Component {
  state = { columns: null }
  renderColums = () => {
    const { columns } = this.state
    if (!columns) return null
    if (columns === 1) {
      return QUOTES.map((quote, index) => (
        <Quote key={quote.handle + index} {...quote} />
      ))
    }
    return <Columns quotes={QUOTES} columns={columns} />
  }
  componentDidMount() {
    const four = window.matchMedia(`(min-width: 1400px)`)
    const three = window.matchMedia(`(min-width: 1020px)`)
    const two = window.matchMedia(`(min-width: 640px)`)
    const one = window.matchMedia(`(min-width: 320px)`)

    const setColumns = () => {
      if (four.matches) return this.setState({ columns: 4 })
      if (three.matches) return this.setState({ columns: 3 })
      if (two.matches) return this.setState({ columns: 2 })
      if (one.matches) return this.setState({ columns: 1 })
    }
    setColumns()
    four.addListener(setColumns)
    three.addListener(setColumns)
    two.addListener(setColumns)
    one.addListener(setColumns)
  }

  render() {
    return (

        {this.renderColums()}

    )
  }
}
<commit_msg>🐛 Prettier<commit_after>const Quote = ({ handle, name, text }) => (

{text}

        {name}
        <a href={`https://twitter.com/${handle}`} className="handle">
          {handle}

)

const QUOTES = [
  {
    handle: '@michaeldick',
    name: 'Dick',
    text:
      "My life just changed; this is exactly the screen capture app I've been needing"
  },
  {
    handle: '@mikeal',
    name: 'Mikeal Rogers',
    text:
      "This is the best screen capture app right now, if you haven't already, check it out"
  },
  {
    handle: '@timothyachumba',
    name: 'Timothy ッ',
    text: 'Kap is a must have. I use it almost every day.'
  },
  {
    handle: '@mxstbr',
    name: 'Max Stoiber',
    text:
      'Extremely impressed with the Kap 1.0 release; this is the best screen recorder ever, built with web technologies! :100:'
  },
  {
    handle: '@maxvoltar',
    name: 'Tim Van Damme',
    text: "New Kap! It's my favorite screen capture app."
  },
  {
    handle: '@michaelschultz',
    name: 'Michael Schultz',
    text: "Kap is maybe the best GIF recorder I've used so far."
  },
  {
    handle: '@ThrivingKings',
    name: 'Daniel Raftery',
    text:
      "I can't recommend Kap enough. Sprinkle your bugs/PRs with animated GIF screen captures. It's seriously awesome."
  },
  {
    handle: '@boogah',
    name: 'Jason Cosper',
    text:
      "Been looking for a nice, easy to use screen recorder. Kap seems to fit the bill. Bonus: it's open source."
  },
  {
    handle: '@jeffreydgroot',
    name: 'Jeffrey de Groot',
    text:
      'Kap makes it really easy to record and export screen captures. And it looks nice :)'
  },
  {
    handle: '@GilliSig',
    name: 'Gilli Sigurdsson',
    text:
      "I think it's safe to say that Kap creates the best gifs of any app I ever used. And best of all it's open source!"
  },
  {
    handle: '@andrewchilds',
    name: 'Andrew Childs',
    text:
      "I've tried many screen capturing tools - getkap.co is by far the easiest to use and results are high-quality 👏 @wulkanocom"
  },
  {
    handle: '@ChrisFerdinandi',
    name: 'Chris Ferdinandi',
    text: "The world's best screen capture software gets even better. getkap.co"
  },
  {
    handle: '@malweene',
    name: 'Malwinei',
    text:
      'Just installed getkap.co via homebew and Cask! Pretty hot combination. 🔥 Very impressed. Try it. Best screen recording! ✨'
  },
  {
    handle: '@cesarzeppini',
    name: 'Cesar Zeppini',
    text:
      "Very well designed screen recording app. And it's open source! getkap.co #design #opensource"
  },
  {
    handle: '@oscrse',
    name: 'Oscar Nilsson',
    text:
      "Kap is soooooo good for quick screen recordings. Can't recommend enough 👏"
  },
  {
    handle: '@mordorinc',
    name: 'Nicolas Prieto',
    text:
      'Much love to small, useful, simple and well thought apps. Thanks @wulkanocom for getkap.co!'
  },
  {
    handle: '@bitandbang',
    name: 'Tierney Cyren',
    text:
      'I use Kap daily for GIF capture, including technical demo GIFs I create for the @NodeSource blog. Highly recommend you gif it a shot! 🙌'
  },
  {
    handle: '@stephenmeszaros',
    name: 'Stephen Meszaros',
    text:
      "My go-to screen recorder for Mac just updated! Trimming, plugins and much more. Don't sleep on this."
  },
  {
    handle: '@slavakim_',
    name: 'Slava',
    text:
      'I *love* stuff like this. Solving one specific problem in a simple and compelling way getkap.co'
  },
  {
    handle: '@_albertogallego',
    name: 'Alberto Gallego',
    text:
      'I spent so much time looking something like getkap.co. The simplest way to record your screen. And easy to export. 😍'
  }
]

// TODO do this nicer
const split = (quotes, columns) => {
  let ret = []
  let index = 0

  for (let index = 0; index < columns; index++) {
    ret.push([])
  }

  for (const quote of quotes) {
    if (index === columns) index = 0
    ret[index] = [...ret[index], quote]
    index = index + 1
  }

  return ret
}

const Columns = ({ columns, quotes }) => {
  const quoteColumns = split(quotes, columns)
  return (

      {quoteColumns.map((column, index) => (

          {column.map((quote, index) => (
            <Quote key={quote.handle + index} {...quote} />
          ))}

      ))}

  )
}

const ShowAll = ({ onClick }) => (

      Show all

)

export default class Quotes extends React.Component {
  state = { columns: null, showAllMobile: null }
  renderColums = () => {
    const { columns, showAllMobile } = this.state
    if (!columns) return null
    if (columns === 1) {
      const quotes = showAllMobile ? QUOTES : QUOTES.slice(0, 5)
      return (

          {quotes.map((quote, index) => (
            <Quote key={quote.handle + index} {...quote} />
          ))}
          {!showAllMobile && (
            <ShowAll onClick={() => this.setState({ showAllMobile: true })} />
          )}

      )
    }
    return <Columns quotes={QUOTES} columns={columns} />
  }
  componentDidMount() {
    const four = window.matchMedia(`(min-width: 1400px)`)
    const three = window.matchMedia(`(min-width: 1020px)`)
    const two = window.matchMedia(`(min-width: 640px)`)
    const one = window.matchMedia(`(min-width: 320px)`)

    const setColumns = () => {
      if (four.matches) return this.setState({ columns: 4 })
      if (three.matches) return this.setState({ columns: 3 })
      if (two.matches) return this.setState({ columns: 2 })
      if (one.matches) return this.setState({ columns: 1 })
    }
    setColumns()
    four.addListener(setColumns)
    three.addListener(setColumns)
    two.addListener(setColumns)
    one.addListener(setColumns)
  }

  render() {
    return (

        {this.renderColums()}

    )
  }
}
<|endoftext|>


<commit_before>(function (root, factory) {
  /* istanbul ignore next */
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else {
    root.Glry = factory();
  }
}(this, function () {
  'use strict';

  function cssTranslateX(element, positionX, speed) {
    element.style.transform = `translateX(${positionX})`;
    element.style.transition = `transform ${speed}s linear, opacity ${speed}s linear`;
  }

  function cssCenter(element, width, height) {
    Object.assign(element.style, {
      width: `${width}px`,
      height: `${height}px`,
      top: `${(window.innerHeight - height) / 2}px`,
      left: `${(window.innerWidth - width) / 2}px`,
    });
  }

  function GlryTap(elm) {
    elm.addEventListener('touchstart', this);
    elm.addEventListener('touchmove', this);
    elm.addEventListener('touchend', this);
    elm.addEventListener('touchcancel', this);
    elm.addEventListener('mousedown', this);
    elm.addEventListener('mouseup', this);
  }

  GlryTap.prototype.start = function(e) {
    this.moved = false;
    this.startX = e.clientX || e.touches[0].clientX;
    this.startY = e.clientY || e.touches[0].clientY;
  };

  GlryTap.prototype.move = function(e) {
    if (Math.abs(e.touches[0].clientX - this.startX) > 10 || Math.abs(e.touches[0].clientY - this.startY) > 10) {
      this.moved = true;
    }
  };

  GlryTap.prototype.end = function(e) {
    const tap = new CustomEvent('tap', { bubbles: true, cancelable: true });
    if (!this.moved) {
      e.stopPropagation();
      if (!e.target.dispatchEvent(tap)) {
        e.preventDefault();
      }
    }
  };

  GlryTap.prototype.handleEvent = function (e) {
    switch (e.type) {
      case 'touchstart':  this.start(e);  break;
      case 'touchmove':   this.move(e);   break;
      case 'touchend':    this.end(e);    break;
      case 'touchcancel': this.end(e);    break;
      case 'mousedown':   this.start(e);  break;
      case 'mouseup':     this.end(e);    break;
    }
  };

  function Glry(options) {
    const settings = {
      target: '#figure',
      animationSpeed: 250,
      enableKeyboard: true,
      onLoadStart: false,
      onLoadEnd: false,
      load: () => {},
      canNavigate: () => true,
      ...options,
    };
    const elmContainer = typeof settings.target === 'object' ? settings.target : document.querySelector(settings.target);
    const elmNavigation = elmContainer.querySelector('.navigation');
    const elmLoading = elmContainer.querySelector('.loading');
    const elmError = elmContainer.querySelector('.error');
    let image = null;
    let imageWidth = 0;
    let imageHeight = 0;
    let swipeDiff = 0;
    let inProgress = false;

    window.addEventListener('resize', setImage);
    window.addEventListener('touchmove', preventScrolling);

    toggleVisible();

    if (elmNavigation) {
      const glryTap = new GlryTap(window);
      window.addEventListener('tap', handleNavigationToggle);
      elmNavigation.querySelector('.prev').addEventListener('tap', handleNavigationClick.bind(this, 'left'));
      elmNavigation.querySelector('.next').addEventListener('tap', handleNavigationClick.bind(this, 'right'));
    }

    if (settings.enableKeyboard) {
      window.addEventListener('keydown', handleKeyboard);
    }

    function toggleVisible(elmVisible) {
      [elmLoading, elmError].forEach(function (elm) {
        elm.classList.toggle('hidden', elm !== elmVisible);
      });
    }

    function setImage() {
      if (!image) return true;

      window.scrollTo(0, 0);

      const screenWidth = window.innerWidth;
      const screenHeight = window.innerHeight;
      const tmpImage = new Image();

      tmpImage.src = image.src;
      tmpImage.onload = function () {
        imageWidth = tmpImage.width;
        imageHeight = tmpImage.height;

        if (imageWidth > screenWidth || imageHeight > screenHeight) {
          var ratio = imageWidth / imageHeight > screenWidth / screenHeight ? imageWidth / screenWidth : imageHeight / screenHeight;
          imageWidth /= ratio;
          imageHeight /= ratio;
        }

        cssCenter(image, imageWidth, imageHeight);
      };
    }

    function loadImage(direction) {
      if (inProgress) return false;

      const src = settings.load(direction);
      if (!src) return false;

      direction = direction === 'left' ? 1 : direction === 'right' ? -1 : 0;

      if (image) {
        image.style.opacity = 0;
        cssTranslateX(image, `${(100 * direction) - swipeDiff}px`, settings.animationSpeed / 1000);
        setTimeout(removeImage, settings.animationSpeed);
        swipeDiff = 0;
      }

      inProgress = true;
      toggleVisible(elmLoading);
      if (settings.onLoadStart !== false) settings.onLoadStart();

      setTimeout(function () {
        image = document.createElement('img');
        image.src = src;
        image.onload = function () {
          elmContainer.appendChild(image);
          setImage();

          image.style.opacity = 0;
          cssTranslateX(image, `${-100 * direction}px`, 0);
          setTimeout(() => {
            image.style.opacity = 1;
            cssTranslateX(image, '0px', settings.animationSpeed / 1000);
          }, 50);

          setTimeout(function () {
            inProgress = false;
            toggleVisible();
            if (settings.onLoadEnd !== false) settings.onLoadEnd();
          }, settings.animationSpeed);
        };
        image.onerror = function () {
          inProgress = false;
          toggleVisible(elmError);
          if (settings.onLoadEnd !== false) settings.onLoadEnd();
        };

        let swipeStart = 0;
        let swipeEnd = 0;
        let swipeDirection = 0;

        image.addEventListener('touchstart', function (e) {
          e.preventDefault();
          swipeStart = e.pageX || e.touches[0].pageX;
        });

        image.addEventListener('touchmove', function (e) {
          swipeEnd = e.pageX || e.touches[0].pageX;
          swipeDiff = swipeStart - swipeEnd;
          swipeDirection = swipeDiff > 0 ? 'right' : 'left';
          if (settings.canNavigate(swipeDirection)) {
            cssTranslateX(image, -swipeDiff + 'px', 0);
          }
        });

        image.addEventListener('touchend', function () {
          if (Math.abs(swipeDiff) > 50 && settings.canNavigate(swipeDirection)) {
            loadImage(swipeDirection);
          } else {
            cssTranslateX(image, '0px', settings.animationSpeed / 1000);
          }
        });

      }, settings.animationSpeed + 100);
    }

    function removeImage() {
      if (!image || !image.parentNode) return false;
      image.parentNode.removeChild(image);
      image = null;
    }

    function handleKeyboard(e) {
      var left = [37, 65, 97];
      var right = [39, 68, 100];
      if (left.indexOf(e.keyCode) > -1) {
        loadImage('left');
      } else if (right.indexOf(e.keyCode) > -1) {
        loadImage('right');
      }
    }

    function preventScrolling(e) {
      e.preventDefault();
    }

    function handleNavigationToggle(e) {
      e.preventDefault();
      elmNavigation.style.opacity = Number(elmNavigation.style.opacity) ? 0 : 1;
    }

    function handleNavigationClick(direction, e) {
      e.stopPropagation();
      loadImage(direction);
    }

    loadImage();

    return { loadImage };
  }

  return Glry;

}));
<commit_msg>fix(mobile): position image on orientation change<commit_after>(function (root, factory) {
  /* istanbul ignore next */
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else {
    root.Glry = factory();
  }
}(this, function () {
  'use strict';

  function cssTranslateX(element, positionX, speed) {
    element.style.transform = `translateX(${positionX})`;
    element.style.transition = `transform ${speed}s linear, opacity ${speed}s linear`;
  }

  function cssCenter(element, width, height) {
    Object.assign(element.style, {
      width: `${width}px`,
      height: `${height}px`,
      top: `${(window.innerHeight - height) / 2}px`,
      left: `${(window.innerWidth - width) / 2}px`,
    });
  }

  function GlryTap(elm) {
    elm.addEventListener('touchstart', this);
    elm.addEventListener('touchmove', this);
    elm.addEventListener('touchend', this);
    elm.addEventListener('touchcancel', this);
    elm.addEventListener('mousedown', this);
    elm.addEventListener('mouseup', this);
  }

  GlryTap.prototype.start = function(e) {
    this.moved = false;
    this.startX = e.clientX || e.touches[0].clientX;
    this.startY = e.clientY || e.touches[0].clientY;
  };

  GlryTap.prototype.move = function(e) {
    if (Math.abs(e.touches[0].clientX - this.startX) > 10 || Math.abs(e.touches[0].clientY - this.startY) > 10) {
      this.moved = true;
    }
  };

  GlryTap.prototype.end = function(e) {
    const tap = new CustomEvent('tap', { bubbles: true, cancelable: true });
    if (!this.moved) {
      e.stopPropagation();
      if (!e.target.dispatchEvent(tap)) {
        e.preventDefault();
      }
    }
  };

  GlryTap.prototype.handleEvent = function (e) {
    switch (e.type) {
      case 'touchstart':  this.start(e);  break;
      case 'touchmove':   this.move(e);   break;
      case 'touchend':    this.end(e);    break;
      case 'touchcancel': this.end(e);    break;
      case 'mousedown':   this.start(e);  break;
      case 'mouseup':     this.end(e);    break;
    }
  };

  function Glry(options) {
    const settings = {
      target: '#figure',
      animationSpeed: 250,
      enableKeyboard: true,
      onLoadStart: false,
      onLoadEnd: false,
      load: () => {},
      canNavigate: () => true,
      ...options,
    };
    const elmContainer = typeof settings.target === 'object' ? settings.target : document.querySelector(settings.target);
    const elmNavigation = elmContainer.querySelector('.navigation');
    const elmLoading = elmContainer.querySelector('.loading');
    const elmError = elmContainer.querySelector('.error');
    let image = null;
    let imageWidth = 0;
    let imageHeight = 0;
    let swipeDiff = 0;
    let inProgress = false;

    window.addEventListener('orientationchange', setImage);
    window.addEventListener('resize', setImage);
    window.addEventListener('touchmove', preventScrolling);

    toggleVisible();

    if (elmNavigation) {
      const glryTap = new GlryTap(window);
      window.addEventListener('tap', handleNavigationToggle);
      elmNavigation.querySelector('.prev').addEventListener('tap', handleNavigationClick.bind(this, 'left'));
      elmNavigation.querySelector('.next').addEventListener('tap', handleNavigationClick.bind(this, 'right'));
    }

    if (settings.enableKeyboard) {
      window.addEventListener('keydown', handleKeyboard);
    }

    function toggleVisible(elmVisible) {
      [elmLoading, elmError].forEach(function (elm) {
        elm.classList.toggle('hidden', elm !== elmVisible);
      });
    }

    function setImage() {
      if (!image) return true;

      window.scrollTo(0, 0);

      const screenWidth = window.innerWidth;
      const screenHeight = window.innerHeight;
      const tmpImage = new Image();

      tmpImage.src = image.src;
      tmpImage.onload = function () {
        imageWidth = tmpImage.width;
        imageHeight = tmpImage.height;

        if (imageWidth > screenWidth || imageHeight > screenHeight) {
          var ratio = imageWidth / imageHeight > screenWidth / screenHeight ? imageWidth / screenWidth : imageHeight / screenHeight;
          imageWidth /= ratio;
          imageHeight /= ratio;
        }

        cssCenter(image, imageWidth, imageHeight);
      };
    }

    function loadImage(direction) {
      if (inProgress) return false;

      const src = settings.load(direction);
      if (!src) return false;

      direction = direction === 'left' ? 1 : direction === 'right' ? -1 : 0;

      if (image) {
        image.style.opacity = 0;
        cssTranslateX(image, `${(100 * direction) - swipeDiff}px`, settings.animationSpeed / 1000);
        setTimeout(removeImage, settings.animationSpeed);
        swipeDiff = 0;
      }

      inProgress = true;
      toggleVisible(elmLoading);
      if (settings.onLoadStart !== false) settings.onLoadStart();

      setTimeout(function () {
        image = document.createElement('img');
        image.src = src;
        image.onload = function () {
          elmContainer.appendChild(image);
          setImage();

          image.style.opacity = 0;
          cssTranslateX(image, `${-100 * direction}px`, 0);
          setTimeout(() => {
            image.style.opacity = 1;
            cssTranslateX(image, '0px', settings.animationSpeed / 1000);
          }, 50);

          setTimeout(function () {
            inProgress = false;
            toggleVisible();
            if (settings.onLoadEnd !== false) settings.onLoadEnd();
          }, settings.animationSpeed);
        };
        image.onerror = function () {
          inProgress = false;
          toggleVisible(elmError);
          if (settings.onLoadEnd !== false) settings.onLoadEnd();
        };

        let swipeStart = 0;
        let swipeEnd = 0;
        let swipeDirection = 0;

        image.addEventListener('touchstart', function (e) {
          e.preventDefault();
          swipeStart = e.pageX || e.touches[0].pageX;
        });

        image.addEventListener('touchmove', function (e) {
          swipeEnd = e.pageX || e.touches[0].pageX;
          swipeDiff = swipeStart - swipeEnd;
          swipeDirection = swipeDiff > 0 ? 'right' : 'left';
          if (settings.canNavigate(swipeDirection)) {
            cssTranslateX(image, -swipeDiff + 'px', 0);
          }
        });

        image.addEventListener('touchend', function () {
          if (Math.abs(swipeDiff) > 50 && settings.canNavigate(swipeDirection)) {
            loadImage(swipeDirection);
          } else {
            cssTranslateX(image, '0px', settings.animationSpeed / 1000);
          }
        });

      }, settings.animationSpeed + 100);
    }

    function removeImage() {
      if (!image || !image.parentNode) return false;
      image.parentNode.removeChild(image);
      image = null;
    }

    function handleKeyboard(e) {
      var left = [37, 65, 97];
      var right = [39, 68, 100];
      if (left.indexOf(e.keyCode) > -1) {
        loadImage('left');
      } else if (right.indexOf(e.keyCode) > -1) {
        loadImage('right');
      }
    }

    function preventScrolling(e) {
      e.preventDefault();
    }

    function handleNavigationToggle(e) {
      e.preventDefault();
      elmNavigation.style.opacity = Number(elmNavigation.style.opacity) ? 0 : 1;
    }

    function handleNavigationClick(direction, e) {
      e.stopPropagation();
      loadImage(direction);
    }

    loadImage();

    return { loadImage };
  }

  return Glry;

}));
<|endoftext|>


<commit_before>(function(window, vjs, vast) {
  'use strict';

  var extend = function(obj) {
    var arg, i, k;
    for (i = 1; i < arguments.length; i++) {
      arg = arguments[i];
      for (k in arg) {
        if (arg.hasOwnProperty(k)) {
          obj[k] = arg[k];
        }
      }
    }
    return obj;
  },

  defaults = {
    // seconds before skip button shows, negative values to disable skip button altogether
    skip: 5
  },

  Vast = function (player, settings) {

    // return vast plugin
    return {
      createSourceObjects: function (media_files) {
        var sourcesByFormat = {}, i, j, tech;
        var techOrder = player.options().techOrder;
        for (i = 0, j = techOrder.length; i < j; i++) {
          var techName = techOrder[i].charAt(0).toUpperCase() + techOrder[i].slice(1);
          tech = window.videojs[techName];

          // Check if the current tech is defined before continuing
          if (!tech) {
            continue;
          }

          // Check if the browser supports this technology
          if (tech.isSupported()) {
            // Loop through each source object
            for (var a = 0, b = media_files.length; a < b; a++) {
              var media_file = media_files[a];
              var source = {type:media_file.mimeType, src:media_file.fileURL};
              // Check if source can be played with this technology
              if (tech.canPlaySource(source)) {
                if (sourcesByFormat[techOrder[i]] === undefined) {
                  sourcesByFormat[techOrder[i]] = [];
                }
                sourcesByFormat[techOrder[i]].push({
                  type:media_file.mimeType,
                  src: media_file.fileURL,
                  width: media_file.width,
                  height: media_file.height
                });
              }
            }
          }
        }
        // Create sources in preferred format order
        var sources = [];
        for (j = 0; j < techOrder.length; j++) {
          tech = techOrder[j];
          if (sourcesByFormat[tech] !== undefined) {
            for (i = 0; i < sourcesByFormat[tech].length; i++) {
              sources.push(sourcesByFormat[tech][i]);
            }
          }
        }
        return sources;
      },

      getContent: function () {

        // query vast url given in settings
        vast.client.get(settings.url, function(response) {
          if (response) {
            // we got a response, deal with it
            for (var adIdx = 0; adIdx < response.ads.length; adIdx++) {
              var ad = response.ads[adIdx];
              player.vast.companion = undefined;
              for (var creaIdx = 0; creaIdx < ad.creatives.length; creaIdx++) {
                var creative = ad.creatives[creaIdx], foundCreative = false, foundCompanion = false;
                if (creative.type === "linear" && !foundCreative) {

                  if (creative.mediaFiles.length) {

                    player.vast.sources = player.vast.createSourceObjects(creative.mediaFiles);

                    if (!player.vast.sources.length) {
                      player.trigger('adscanceled');
                      return;
                    }

                    player.vastTracker = new vast.tracker(ad, creative);

                    foundCreative = true;
                  }

                } else if (creative.type === "companion" && !foundCompanion) {

                  player.vast.companion = creative;

                  foundCompanion = true;

                }
              }

              if (player.vastTracker) {
                // vast tracker and content is ready to go, trigger event
                player.trigger('vast-ready');
                break;
              } else {
                // Inform ad server we can't find suitable media file for this ad
                vast.util.track(ad.errorURLTemplates, {ERRORCODE: 403});
              }
            }
          }

          if (!player.vastTracker) {
            // No pre-roll, start video
            player.trigger('adscanceled');
          }
        });
      },

      setupEvents: function() {

        var errorOccurred = false,
            canplayFn = function() {
              player.vastTracker.load();
            },
            timeupdateFn = function() {
              if (isNaN(player.vastTracker.assetDuration)) {
                player.vastTracker.assetDuration = player.duration();
              }
              player.vastTracker.setProgress(player.currentTime());
            },
            playFn = function() {
              if (player.ads.state === 'ad-playback') {
                player.vastTracker.setPaused(false);
              }
            },
            pauseFn = function() {
              player.vastTracker.setPaused(true);
            },
            errorFn = function() {
              // Inform ad server we couldn't play the media file for this ad
              vast.util.track(player.vastTracker.ad.errorURLTemplates, {ERRORCODE: 405});
              errorOccurred = true;
              player.trigger('ended');
            };

        player.on('canplay', canplayFn);
        player.on('timeupdate', timeupdateFn);
        player.on('play', playFn);
        player.on('pause', pauseFn);
        player.on('error', errorFn);

        player.one('ended', function() {
          player.off('canplay', canplayFn);
          player.off('timeupdate', timeupdateFn);
          player.off('play', playFn);
          player.off('pause', pauseFn);
          player.off('error', errorFn);
          if (!errorOccurred) {
            player.vastTracker.complete();
          }
        });
      },

      preroll: function() {
        player.ads.startLinearAdMode();
        player.vast.showControls = player.controls();
        if (player.vast.showControls) {
          player.controls(false);
        }

        // load linear ad sources and start playing them
        player.src(player.vast.sources);

        var clickthrough;
        if (player.vastTracker.clickThroughURLTemplate) {
          clickthrough = vast.util.resolveURLTemplates(
            [player.vastTracker.clickThroughURLTemplate],
            {
              CACHEBUSTER: Math.round(Math.random() * 1.0e+10),
              CONTENTPLAYHEAD: player.vastTracker.progressFormated()
            }
          )[0];
        }
        var blocker = window.document.createElement("a");
        blocker.className = "vast-blocker";
        blocker.href = clickthrough || "#";
        blocker.target = "_blank";
        blocker.onclick = function() {
          if (player.paused()) {
            player.play();
            return false;
          }
          var clicktrackers = player.vastTracker.clickTrackingURLTemplate;
          if (clicktrackers) {
            player.vastTracker.trackURLs([clicktrackers]);
          }
          player.trigger("adclick");
        };
        player.vast.blocker = blocker;
        player.el().insertBefore(blocker, player.controlBar.el());

        var skipButton = window.document.createElement("div");
        skipButton.className = "vast-skip-button";
        if (settings.skip < 0) {
          skipButton.style.display = "none";
        }
        player.vast.skipButton = skipButton;
        player.el().appendChild(skipButton);

        player.on("timeupdate", player.vast.timeupdate);

        skipButton.onclick = function(e) {
          if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') >= 0) {
            player.vastTracker.skip();
            player.vast.tearDown();
          }
          if(window.Event.prototype.stopPropagation !== undefined) {
            e.stopPropagation();
          } else {
            return false;
          }
        };

        player.vast.setupEvents();

        player.one('ended', player.vast.tearDown);

        player.trigger('vast-preroll-ready');
      },

      tearDown: function() {
        // remove preroll buttons
        player.vast.skipButton.parentNode.removeChild(player.vast.skipButton);
        player.vast.blocker.parentNode.removeChild(player.vast.blocker);

        // remove vast-specific events
        player.off('timeupdate', player.vast.timeupdate);
        player.off('ended', player.vast.tearDown);

        // end ad mode
        player.ads.endLinearAdMode();

        // show player controls for video
        if (player.vast.showControls) {
          player.controls(true);
        }

        player.trigger('vast-preroll-removed');
      },

      timeupdate: function(e) {
        player.loadingSpinner.el().style.display = "none";
        var timeLeft = Math.ceil(settings.skip - player.currentTime());
        if(timeLeft > 0) {
          player.vast.skipButton.innerHTML = "Skip in " + timeLeft + "...";
        } else {
          if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') === -1){
            player.vast.skipButton.className += " enabled";
            player.vast.skipButton.innerHTML = "Skip";
          }
        }
      }
    };

  },

  vastPlugin = function(options) {
    var player = this;
    var settings = extend({}, defaults, options || {});

    // check that we have the ads plugin
    if (player.ads === undefined) {
      window.console.error('vast video plugin requires videojs-contrib-ads, vast plugin not initialized');
      return null;
    }

    // set up vast plugin, then set up events here
    player.vast = new Vast(player, settings);

    player.on('vast-ready', function () {
      // vast is prepared with content, set up ads and trigger ready function
      player.trigger('adsready');
    });

    player.on('vast-preroll-ready', function () {
      // start playing preroll, note: this should happen this way no matter what, even if autoplay
      //  has been disabled since the preroll function shouldn't run until the user/autoplay has
      //  caused the main video to trigger this preroll function
      player.play();
    });

    player.on('vast-preroll-removed', function () {
      // preroll done or removed, start playing the actual video
      player.play();
    });

    player.on('contentupdate', function(){
      // videojs-ads triggers this when src changes
      player.vast.getContent(settings.url);
    });

    player.on('readyforpreroll', function() {
      // if we don't have a vast url, just bail out
      if (!settings.url) {
        player.trigger('adscanceled');
        return null;
      }
      // set up and start playing preroll
      player.vast.preroll();
    });

    // make an ads request immediately so we're ready when the viewer hits "play"
    if (player.currentSrc()) {
      player.vast.getContent(settings.url);
    }

    // return player to allow this plugin to be chained
    return player;
  };

  vjs.plugin('vast', vastPlugin);

}(window, videojs, DMVAST));
<commit_msg>Cleaning up play/pause events<commit_after>(function(window, vjs, vast) {
  'use strict';

  var extend = function(obj) {
    var arg, i, k;
    for (i = 1; i < arguments.length; i++) {
      arg = arguments[i];
      for (k in arg) {
        if (arg.hasOwnProperty(k)) {
          obj[k] = arg[k];
        }
      }
    }
    return obj;
  },

  defaults = {
    // seconds before skip button shows, negative values to disable skip button altogether
    skip: 5
  },

  Vast = function (player, settings) {

    // return vast plugin
    return {
      createSourceObjects: function (media_files) {
        var sourcesByFormat = {}, i, j, tech;
        var techOrder = player.options().techOrder;
        for (i = 0, j = techOrder.length; i < j; i++) {
          var techName = techOrder[i].charAt(0).toUpperCase() + techOrder[i].slice(1);
          tech = window.videojs[techName];

          // Check if the current tech is defined before continuing
          if (!tech) {
            continue;
          }

          // Check if the browser supports this technology
          if (tech.isSupported()) {
            // Loop through each source object
            for (var a = 0, b = media_files.length; a < b; a++) {
              var media_file = media_files[a];
              var source = {type:media_file.mimeType, src:media_file.fileURL};
              // Check if source can be played with this technology
              if (tech.canPlaySource(source)) {
                if (sourcesByFormat[techOrder[i]] === undefined) {
                  sourcesByFormat[techOrder[i]] = [];
                }
                sourcesByFormat[techOrder[i]].push({
                  type:media_file.mimeType,
                  src: media_file.fileURL,
                  width: media_file.width,
                  height: media_file.height
                });
              }
            }
          }
        }
        // Create sources in preferred format order
        var sources = [];
        for (j = 0; j < techOrder.length; j++) {
          tech = techOrder[j];
          if (sourcesByFormat[tech] !== undefined) {
            for (i = 0; i < sourcesByFormat[tech].length; i++) {
              sources.push(sourcesByFormat[tech][i]);
            }
          }
        }
        return sources;
      },

      getContent: function () {

        // query vast url given in settings
        vast.client.get(settings.url, function(response) {
          if (response) {
            // we got a response, deal with it
            for (var adIdx = 0; adIdx < response.ads.length; adIdx++) {
              var ad = response.ads[adIdx];
              player.vast.companion = undefined;
              for (var creaIdx = 0; creaIdx < ad.creatives.length; creaIdx++) {
                var creative = ad.creatives[creaIdx], foundCreative = false, foundCompanion = false;
                if (creative.type === "linear" && !foundCreative) {

                  if (creative.mediaFiles.length) {

                    player.vast.sources = player.vast.createSourceObjects(creative.mediaFiles);

                    if (!player.vast.sources.length) {
                      player.trigger('adscanceled');
                      return;
                    }

                    player.vastTracker = new vast.tracker(ad, creative);

                    foundCreative = true;
                  }

                } else if (creative.type === "companion" && !foundCompanion) {

                  player.vast.companion = creative;

                  foundCompanion = true;

                }
              }

              if (player.vastTracker) {
                // vast tracker and content is ready to go, trigger event
                player.trigger('vast-ready');
                break;
              } else {
                // Inform ad server we can't find suitable media file for this ad
                vast.util.track(ad.errorURLTemplates, {ERRORCODE: 403});
              }
            }
          }

          if (!player.vastTracker) {
            // No pre-roll, start video
            player.trigger('adscanceled');
          }
        });
      },

      setupEvents: function() {

        var errorOccurred = false,
            canplayFn = function() {
              player.vastTracker.load();
            },
            timeupdateFn = function() {
              if (isNaN(player.vastTracker.assetDuration)) {
                player.vastTracker.assetDuration = player.duration();
              }
              player.vastTracker.setProgress(player.currentTime());
            },
            pauseFn = function() {
              player.vastTracker.setPaused(true);
              player.one('play', function(){
                player.vastTracker.setPaused(false);
              });
            },
            errorFn = function() {
              // Inform ad server we couldn't play the media file for this ad
              vast.util.track(player.vastTracker.ad.errorURLTemplates, {ERRORCODE: 405});
              errorOccurred = true;
              player.trigger('ended');
            };

        player.on('canplay', canplayFn);
        player.on('timeupdate', timeupdateFn);
        player.on('pause', pauseFn);
        player.on('error', errorFn);

        player.one('vast-preroll-removed', function() {
          player.off('canplay', canplayFn);
          player.off('timeupdate', timeupdateFn);
          player.off('pause', pauseFn);
          player.off('error', errorFn);
          if (!errorOccurred) {
            player.vastTracker.complete();
          }
        });
      },

      preroll: function() {
        player.ads.startLinearAdMode();
        player.vast.showControls = player.controls();
        if (player.vast.showControls) {
          player.controls(false);
        }

        // load linear ad sources and start playing them
        player.src(player.vast.sources);

        var clickthrough;
        if (player.vastTracker.clickThroughURLTemplate) {
          clickthrough = vast.util.resolveURLTemplates(
            [player.vastTracker.clickThroughURLTemplate],
            {
              CACHEBUSTER: Math.round(Math.random() * 1.0e+10),
              CONTENTPLAYHEAD: player.vastTracker.progressFormated()
            }
          )[0];
        }
        var blocker = window.document.createElement("a");
        blocker.className = "vast-blocker";
        blocker.href = clickthrough || "#";
        blocker.target = "_blank";
        blocker.onclick = function() {
          if (player.paused()) {
            player.play();
            return false;
          }
          var clicktrackers = player.vastTracker.clickTrackingURLTemplate;
          if (clicktrackers) {
            player.vastTracker.trackURLs([clicktrackers]);
          }
          player.trigger("adclick");
        };
        player.vast.blocker = blocker;
        player.el().insertBefore(blocker, player.controlBar.el());

        var skipButton = window.document.createElement("div");
        skipButton.className = "vast-skip-button";
        if (settings.skip < 0) {
          skipButton.style.display = "none";
        }
        player.vast.skipButton = skipButton;
        player.el().appendChild(skipButton);

        player.on("timeupdate", player.vast.timeupdate);

        skipButton.onclick = function(e) {
          if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') >= 0) {
            player.vastTracker.skip();
            player.vast.tearDown();
          }
          if(window.Event.prototype.stopPropagation !== undefined) {
            e.stopPropagation();
          } else {
            return false;
          }
        };

        player.vast.setupEvents();

        player.one('ended', player.vast.tearDown);

        player.trigger('vast-preroll-ready');
      },

      tearDown: function() {
        // remove preroll buttons
        player.vast.skipButton.parentNode.removeChild(player.vast.skipButton);
        player.vast.blocker.parentNode.removeChild(player.vast.blocker);

        // remove vast-specific events
        player.off('timeupdate', player.vast.timeupdate);
        player.off('ended', player.vast.tearDown);

        // end ad mode
        player.ads.endLinearAdMode();

        // show player controls for video
        if (player.vast.showControls) {
          player.controls(true);
        }

        player.trigger('vast-preroll-removed');
      },

      timeupdate: function(e) {
        player.loadingSpinner.el().style.display = "none";
        var timeLeft = Math.ceil(settings.skip - player.currentTime());
        if(timeLeft > 0) {
          player.vast.skipButton.innerHTML = "Skip in " + timeLeft + "...";
        } else {
          if((' ' + player.vast.skipButton.className + ' ').indexOf(' enabled ') === -1){
            player.vast.skipButton.className += " enabled";
            player.vast.skipButton.innerHTML = "Skip";
          }
        }
      }
    };

  },

  vastPlugin = function(options) {
    var player = this;
    var settings = extend({}, defaults, options || {});

    // check that we have the ads plugin
    if (player.ads === undefined) {
      window.console.error('vast video plugin requires videojs-contrib-ads, vast plugin not initialized');
      return null;
    }

    // set up vast plugin, then set up events here
    player.vast = new Vast(player, settings);

    player.on('vast-ready', function () {
      // vast is prepared with content, set up ads and trigger ready function
      player.trigger('adsready');
    });

    player.on('vast-preroll-ready', function () {
      // start playing preroll, note: this should happen this way no matter what, even if autoplay
      //  has been disabled since the preroll function shouldn't run until the user/autoplay has
      //  caused the main video to trigger this preroll function
      player.play();
    });

    player.on('vast-preroll-removed', function () {
      // preroll done or removed, start playing the actual video
      player.play();
    });

    player.on('contentupdate', function(){
      // videojs-ads triggers this when src changes
      player.vast.getContent(settings.url);
    });

    player.on('readyforpreroll', function() {
      // if we don't have a vast url, just bail out
      if (!settings.url) {
        player.trigger('adscanceled');
        return null;
      }
      // set up and start playing preroll
      player.vast.preroll();
    });

    // make an ads request immediately so we're ready when the viewer hits "play"
    if (player.currentSrc()) {
      player.vast.getContent(settings.url);
    }

    // return player to allow this plugin to be chained
    return player;
  };

  vjs.plugin('vast', vastPlugin);

}(window, videojs, DMVAST));
<|endoftext|>


<commit_before>/*!
 * Drawable.Chart.js
 * Version: 0.0.0
 *
 * Copyright 2015 Zach Panzarino
 * Released under the MIT license
 *
 * https://github.com/zachpanz88/Drawable.Chart.js
 */

function DrawableChart(id){

    // get canvas
    this.ctx = document.getElementById(id).getContext("2d");

    // set data
    var data = {
        labels: [],
        datasets: [
            {
                label: "My First dataset",
                fillColor: "rgba(220,220,220,0.2)",
                strokeColor: "rgba(220,220,220,1)",
                pointColor: "rgba(220,220,220,1)",
                pointStrokeColor: "#fff",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: []
            },
        ]
    };

    // special options
    var options = {
        scaleOverride: true,
        scaleSteps: 10,
        scaleStepWidth: 10,
        scaleStartValue: 0,
    };

    // create chart
    this.chart = new Chart(this.ctx).Line(data, options);
}<commit_msg>start updating on click<commit_after>/*!
 * Drawable.Chart.js
 * Version: 0.0.0
 *
 * Copyright 2015 Zach Panzarino
 * Released under the MIT license
 *
 * https://github.com/zachpanz88/Drawable.Chart.js
 */

function DrawableChart(id){

    // get canvas
    this.element = document.getElementById(id);
    this.ctx = this.element.getContext("2d");

    // set data
    var data = {
        labels: [0,10,20],
        datasets: [
            {
                label: "My First dataset",
                fillColor: "rgba(220,0,0,.2)",
                strokeColor: "rgba(220,0,0,1)",
                pointColor: "rgba(220,0,0,1)",
                pointStrokeColor: "#fff",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: [20,40,10]
            },
        ]
    };

    // special options
    var options = {
        scaleOverride: true,
        scaleSteps: 10,
        scaleStepWidth: 10,
        scaleStartValue: 0,
        showTooltips: true,
    };

    // create chart
    this.chart = new Chart(this.ctx).Line(data, options);

    // updating chart
    this.update = function(e){

    };

    // update when clicked
    this.element.addEventListener('click',this.update);

}<|endoftext|>


<commit_before>(function() {
	/**
	 * Load the list of files asynchronously. This uses recursion in
	 * order to create a queue of files that will be loaded serially.
	 * Each layer, starting at the bottom, loads a file and then loads
	 * the layer on top of it. The very top file on the stack will have
	 * zero files to load, so instead it will be the one to call the
	 * callback to notify the caller that all the content is loaded.
	 *
	 * @param {Object} context function to call this method in the context of
	 * @param {Array.<string>} paths array of strings containing relative paths for required locale data files
	 * @param {Array} results empty array in which to place the resulting json when it is loaded from a file
	 * @param {Object} params An object full of parameters that the caller is passing to this function to help load the files
	 * @param {function(Array.<Object>)} callback callback to call when this function is finished attempting
	 * to load all the files that exist and can be loaded
	 */
	function loadFiles(context, paths, results, params, callback) {
		var root = "resources/";
		if (params && typeof(params.root) !== "undefined") {
			root = params.root + '/';
		}
		if (paths.length > 0) {
			var path = paths.shift();
			var ajax = new enyo.Ajax({url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path), cacheBust: false});
			//console.log("moondemo2: browser/async: attempting to load lib/enyo-ilib/ilib/locale/" + path);
			var resultFunc = function(inSender, json) {
                // console.log("moondemo2: " + (!inSender.failed && json ? "success" : "failed"));
				results.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				if (paths.length > 0) {
					loadFiles(context, paths, results, params, callback);
				} else {
					// only the bottom item on the stack will call
					// the callback
					callback.call(context, results);
				}
			};
			ajax.response(this, resultFunc);
			ajax.error(this, function(inSender, json) {
				// not there? Try the standard place instead
				var file = root + path;
				// console.log("moondemo2: browser/async: attempting to load " + file);
				var ajax2 = new enyo.Ajax({url: file, cacheBust: false});

				ajax2.response(this, resultFunc);
				ajax2.error(this, resultFunc);
				ajax2.go();
			});
			ajax.go();
		}
	}

	ilib.setLoaderCallback(enyo.bind(this, function(paths, sync, params, callback) {
		if (sync) {
			var ret = [];
			var root = "resources/";
			if (params && typeof(params.root) !== "undefined") {
				root = params.root + '/';
			}
			// synchronous
			paths.forEach(function (path) {
				// console.log("browser/sync: attempting to load lib/enyo-ilib/ilib/locale/" + path);
				var ajax = new enyo.Ajax({
					url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path),
					sync: true, cacheBust: false
				});

				var handler = function(inSender, json) {
                    // console.log((!inSender.failed && json ? "success" : "failed"));
					ret.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				};
				ajax.response(this, handler);
				ajax.error(this, function(inSender, json) {
					// console.log("browser/sync: Now attempting to load " + root + path);
					var ajax2 = new enyo.Ajax({
						url: root + path,
						sync: true, cacheBust: false
					});
					ajax2.response(this, handler);
					ajax2.error(this, handler);
					ajax2.go();
				});
				ajax.go();
			});

			if (typeof(callback) === 'function') {
				callback.call(this, ret);
			}
			return ret;
		}

		// asynchronous
		var results = [];
		loadFiles(this, paths, results, params, callback);
	}));

	if (typeof(window.UILocale) !== 'undefined') {
		// this is a hack until GF-1581 is fixed
		ilib.setLocale(window.UILocale);
	}

	// enyo.updateI18NClasses should be called after every setLocale, but there isn't such a callback in current version
    enyo.updateI18NClasses = function updateBodyClasses() {
        var li = new ilib.LocaleInfo(); // for the current locale
        var locale = li.getLocale();
		var base = "enyo-locale-";

        // Remove old style definitions (hack style becouse enyo.dom doesn't have methods like enyo.dom.getBodyClasses, enyo.dom.removeBodyClass)
        if (document && document.body && document.body.className && document.body.className) {
            document.body.className = document.body.className.replace(new RegExp('(^|\\s)'+ base +'[^\\s]*', 'g'), '');
        }

        // We use the non-latin fonts for these languages (even though their scripts are technically considered latin)
        var nonLatinLanguageOverrides = ["cs", "hu", "lv", "lt", "pl", "ro", "sr", "sl", "tr", "vi"];
        // We use the latin fonts (with non-Latin fallback) for these languages (even though their scripts are non-latin)
        var latinLanguageOverrides = ["ko"];
		var scriptName = li.getScript();
		if ((scriptName !== "Latn" || enyo.indexOf(locale.getLanguage(), nonLatinLanguageOverrides) !== -1) &&
			(enyo.indexOf(locale.getLanguage(), latinLanguageOverrides) < 0)) {
			// allow enyo to define other fonts for non-Latin languages, or for certain
			// Latin-based languages where the characters with some accents don't appear in the
			// regular fonts, creating a strange "ransom note" look with a mix of fonts in the
			// same word. So, treat it like a non-Latin language in order to get all the characters
			// to display with the same font.
			enyo.dom.addBodyClass(base + "non-latin");
		}
		if (scriptName !== 'Latn' && scriptName !== 'Cyrl' && scriptName !== 'Grek') {
			// GF-45884: allow enyo to avoid setting italic fonts for those scripts that do not
			// commonly use italics
			enyo.dom.addBodyClass(base + "non-italic");
		}

		// allow enyo to apply right-to-left styles to the app and widgets if necessary
		var script = new ilib.ScriptInfo(scriptName);
		if (script.getScriptDirection() === "rtl") {
			enyo.dom.addBodyClass(base + "right-to-left");
			if (enyo.Control) {
				enyo.Control.prototype.rtl = true;
			}
		}

		// allow enyo or the apps to give CSS classes that are specific to the language, country, or script
		if (locale.getLanguage()) {
			enyo.dom.addBodyClass(base + locale.getLanguage());
			if (locale.getScript()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript());
				if (locale.getRegion()) {
					enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript() + "-" + locale.getRegion());
				}
			} else if (locale.getRegion()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getRegion());
			}
		}
		if (locale.getScript()) {
			enyo.dom.addBodyClass(base + locale.getScript());
		}
		if (locale.getRegion()) {
			enyo.dom.addBodyClass(base + locale.getRegion());
		}
    };
})();

/*
 * Reset the $L function to use ilib instead of the dummy function that enyo
 * comes with by default.
 */
$L = function (string) {
	var str;
	if (!$L.rb) {
		$L.setLocale();
	}
	if (typeof(string) === 'string') {
		if (!$L.rb) {
			return string;
		}
		str = $L.rb.getString(string);
	} else if (typeof(string) === 'object') {
		if (typeof(string.key) !== 'undefined' && typeof(string.value) !== 'undefined') {
			if (!$L.rb) {
				return string.value;
			}
			str = $L.rb.getString(string.value, string.key);
		} else {
			str = "";
		}
	} else {
		str = string;
	}
	return str.toString();
};

/**
 * Set the locale for the strings that $L loads. This may reload the
 * string resources if necessary.
 * @param {string} spec the locale specifier
 */
$L.setLocale = function (spec) {
	var locale = new ilib.Locale(spec);
	if (!$L.rb || spec !== $L.rb.getLocale().getSpec()) {
		$L.rb = new ilib.ResBundle({
			locale: locale,
			type: "html",
			name: "strings",
			sync: true,
			lengthen: true		// if pseudo-localizing, this tells it to lengthen strings
		});
	}
};

/**
 * Override Enyo's toLowerCase and toUpperCase methods with these fancy ones
 * that call iLib's locale-safe case mapper.
 */
enyo.toLowerCase = function(inString) {
	if (typeof(inString) === "undefined" || typeof(inString) === "null") {
		return inString;
	}
	var cm = new ilib.CaseMapper({direction: "tolower"});
	return cm.map(inString);
};
enyo.toUpperCase = function(inString) {
	if (typeof(inString) === "undefined" || typeof(inString) === "null") {
		return inString;
	}
	var cm = new ilib.CaseMapper({direction: "toupper"});
	return cm.map(inString);
};

/**
 * This Enyo hook lets us know that the system locale has changed and gives
 * us a chance to update the iLib locale before Enyo broadcasts its
 * `onlocalechange` signal.
 */
enyo.updateLocale = function() {
	ilib.setLocale(navigator.language);
	$L.setLocale(navigator.language);
	enyo.updateI18NClasses();
};

// we go ahead and run this once during loading of iLib settings are valid
// during the loads of later libraries.
enyo.updateLocale();
<commit_msg>Adding an optimization to reduce the amount of CaseMappers that need to be created, by reusing them until the locale is changed. Enyo-DCO-1.1-Signed-off-by: Blake Stephens <blake.stephens@lge.com><commit_after>(function() {
	/**
	 * Load the list of files asynchronously. This uses recursion in
	 * order to create a queue of files that will be loaded serially.
	 * Each layer, starting at the bottom, loads a file and then loads
	 * the layer on top of it. The very top file on the stack will have
	 * zero files to load, so instead it will be the one to call the
	 * callback to notify the caller that all the content is loaded.
	 *
	 * @param {Object} context function to call this method in the context of
	 * @param {Array.<string>} paths array of strings containing relative paths for required locale data files
	 * @param {Array} results empty array in which to place the resulting json when it is loaded from a file
	 * @param {Object} params An object full of parameters that the caller is passing to this function to help load the files
	 * @param {function(Array.<Object>)} callback callback to call when this function is finished attempting
	 * to load all the files that exist and can be loaded
	 */
	function loadFiles(context, paths, results, params, callback) {
		var root = "resources/";
		if (params && typeof(params.root) !== "undefined") {
			root = params.root + '/';
		}
		if (paths.length > 0) {
			var path = paths.shift();
			var ajax = new enyo.Ajax({url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path), cacheBust: false});
			//console.log("moondemo2: browser/async: attempting to load lib/enyo-ilib/ilib/locale/" + path);
			var resultFunc = function(inSender, json) {
                // console.log("moondemo2: " + (!inSender.failed && json ? "success" : "failed"));
				results.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				if (paths.length > 0) {
					loadFiles(context, paths, results, params, callback);
				} else {
					// only the bottom item on the stack will call
					// the callback
					callback.call(context, results);
				}
			};
			ajax.response(this, resultFunc);
			ajax.error(this, function(inSender, json) {
				// not there? Try the standard place instead
				var file = root + path;
				// console.log("moondemo2: browser/async: attempting to load " + file);
				var ajax2 = new enyo.Ajax({url: file, cacheBust: false});

				ajax2.response(this, resultFunc);
				ajax2.error(this, resultFunc);
				ajax2.go();
			});
			ajax.go();
		}
	}

	ilib.setLoaderCallback(enyo.bind(this, function(paths, sync, params, callback) {
		if (sync) {
			var ret = [];
			var root = "resources/";
			if (params && typeof(params.root) !== "undefined") {
				root = params.root + '/';
			}
			// synchronous
			paths.forEach(function (path) {
				// console.log("browser/sync: attempting to load lib/enyo-ilib/ilib/locale/" + path);
				var ajax = new enyo.Ajax({
					url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path),
					sync: true, cacheBust: false
				});

				var handler = function(inSender, json) {
                    // console.log((!inSender.failed && json ? "success" : "failed"));
					ret.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				};
				ajax.response(this, handler);
				ajax.error(this, function(inSender, json) {
					// console.log("browser/sync: Now attempting to load " + root + path);
					var ajax2 = new enyo.Ajax({
						url: root + path,
						sync: true, cacheBust: false
					});
					ajax2.response(this, handler);
					ajax2.error(this, handler);
					ajax2.go();
				});
				ajax.go();
			});

			if (typeof(callback) === 'function') {
				callback.call(this, ret);
			}
			return ret;
		}

		// asynchronous
		var results = [];
		loadFiles(this, paths, results, params, callback);
	}));

	if (typeof(window.UILocale) !== 'undefined') {
		// this is a hack until GF-1581 is fixed
		ilib.setLocale(window.UILocale);
	}

	// enyo.updateI18NClasses should be called after every setLocale, but there isn't such a callback in current version
    enyo.updateI18NClasses = function updateBodyClasses() {
        var li = new ilib.LocaleInfo(); // for the current locale
        var locale = li.getLocale();
		var base = "enyo-locale-";

        // Remove old style definitions (hack style becouse enyo.dom doesn't have methods like enyo.dom.getBodyClasses, enyo.dom.removeBodyClass)
        if (document && document.body && document.body.className && document.body.className) {
            document.body.className = document.body.className.replace(new RegExp('(^|\\s)'+ base +'[^\\s]*', 'g'), '');
        }

        // We use the non-latin fonts for these languages (even though their scripts are technically considered latin)
        var nonLatinLanguageOverrides = ["cs", "hu", "lv", "lt", "pl", "ro", "sr", "sl", "tr", "vi"];
        // We use the latin fonts (with non-Latin fallback) for these languages (even though their scripts are non-latin)
        var latinLanguageOverrides = ["ko"];
		var scriptName = li.getScript();
		if ((scriptName !== "Latn" || enyo.indexOf(locale.getLanguage(), nonLatinLanguageOverrides) !== -1) &&
			(enyo.indexOf(locale.getLanguage(), latinLanguageOverrides) < 0)) {
			// allow enyo to define other fonts for non-Latin languages, or for certain
			// Latin-based languages where the characters with some accents don't appear in the
			// regular fonts, creating a strange "ransom note" look with a mix of fonts in the
			// same word. So, treat it like a non-Latin language in order to get all the characters
			// to display with the same font.
			enyo.dom.addBodyClass(base + "non-latin");
		}
		if (scriptName !== 'Latn' && scriptName !== 'Cyrl' && scriptName !== 'Grek') {
			// GF-45884: allow enyo to avoid setting italic fonts for those scripts that do not
			// commonly use italics
			enyo.dom.addBodyClass(base + "non-italic");
		}

		// allow enyo to apply right-to-left styles to the app and widgets if necessary
		var script = new ilib.ScriptInfo(scriptName);
		if (script.getScriptDirection() === "rtl") {
			enyo.dom.addBodyClass(base + "right-to-left");
			if (enyo.Control) {
				enyo.Control.prototype.rtl = true;
			}
		}

		// allow enyo or the apps to give CSS classes that are specific to the language, country, or script
		if (locale.getLanguage()) {
			enyo.dom.addBodyClass(base + locale.getLanguage());
			if (locale.getScript()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript());
				if (locale.getRegion()) {
					enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript() + "-" + locale.getRegion());
				}
			} else if (locale.getRegion()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getRegion());
			}
		}
		if (locale.getScript()) {
			enyo.dom.addBodyClass(base + locale.getScript());
		}
		if (locale.getRegion()) {
			enyo.dom.addBodyClass(base + locale.getRegion());
		}
		// Recreate the case mappers to use the just-recently-set locale
	 	enyo.setCaseMappers();
   };
})();

/*
 * Reset the $L function to use ilib instead of the dummy function that enyo
 * comes with by default.
 */
$L = function (string) {
	var str;
	if (!$L.rb) {
		$L.setLocale();
	}
	if (typeof(string) === 'string') {
		if (!$L.rb) {
			return string;
		}
		str = $L.rb.getString(string);
	} else if (typeof(string) === 'object') {
		if (typeof(string.key) !== 'undefined' && typeof(string.value) !== 'undefined') {
			if (!$L.rb) {
				return string.value;
			}
			str = $L.rb.getString(string.value, string.key);
		} else {
			str = "";
		}
	} else {
		str = string;
	}
	return str.toString();
};

/**
 * Set the locale for the strings that $L loads. This may reload the
 * string resources if necessary.
 * @param {string} spec the locale specifier
 */
$L.setLocale = function (spec) {
	var locale = new ilib.Locale(spec);
	if (!$L.rb || spec !== $L.rb.getLocale().getSpec()) {
		$L.rb = new ilib.ResBundle({
			locale: locale,
			type: "html",
			name: "strings",
			sync: true,
			lengthen: true		// if pseudo-localizing, this tells it to lengthen strings
		});
	}
};

/**
 * Set CaseMapper object references to ilib's current locale (its most recently set, by default)
 */
enyo.setCaseMappers = function() {
	enyo._caseMapperLower = new ilib.CaseMapper({direction: "tolower"});
	enyo._caseMapperUpper = new ilib.CaseMapper({direction: "toupper"});
};

/**
 * Override Enyo's toLowerCase and toUpperCase methods with these fancy ones
 * that call iLib's locale-safe case mapper.
 */
enyo.toLowerCase = function(inString) {
	if (typeof(inString) === "undefined" || typeof(inString) === "null") {
		return inString;
	}
	return enyo._caseMapperLower.map(inString);
};
enyo.toUpperCase = function(inString) {
	if (typeof(inString) === "undefined" || typeof(inString) === "null") {
		return inString;
	}
	return enyo._caseMapperUpper.map(inString);
};

/**
 * This Enyo hook lets us know that the system locale has changed and gives
 * us a chance to update the iLib locale before Enyo broadcasts its
 * `onlocalechange` signal.
 */
enyo.updateLocale = function() {
	ilib.setLocale(navigator.language);
	$L.setLocale(navigator.language);
	enyo.updateI18NClasses();
};

// we go ahead and run this once during loading of iLib settings are valid
// during the loads of later libraries.
enyo.updateLocale();
<|endoftext|>


<commit_before>import Promise from 'bluebird'
import { Evernote } from 'evernote'
import EvermarkError from './EvermarkError'

const debug = require('debug')('evernote')

// Define Evernote API error codes
export const UNKNOWN_ERROR = 1
export const BAD_DATA_FORMAT = 2
export const PERMISSION_DENIED = 3
export const INTERNAL_ERROR = 4
export const DATA_REQUIRED = 5
export const LIMIT_REACHED = 6
export const QUOTA_REACHED = 7
export const INVALID_AUTH = 8
export const AUTH_EXPIRED = 9
export const DATA_CONFLICT = 10
export const ENML_VALIDATION = 11
export const SHARD_UNAVAILABLE = 12
export const LEN_TOO_SHORT = 13
export const LEN_TOO_LONG = 14
export const TOO_FEW = 15
export const TOO_MANY = 16
export const UNSUPPORTED_OPERATION = 17
export const TAKEN_DOWN = 18
export const RATE_LIMIT_REACHED = 19
export const OBJECT_NOT_FOUND = 100

const ERROR_CODES = {
  [UNKNOWN_ERROR]: 'UNKNOWN',
  [BAD_DATA_FORMAT]: 'BAD_DATA_FORMAT',
  [PERMISSION_DENIED]: 'PERMISSION_DENIED',
  [INTERNAL_ERROR]: 'INTERNAL_ERROR',
  [DATA_REQUIRED]: 'DATA_REQUIRED',
  [LIMIT_REACHED]: 'LIMIT_REACHED',
  [QUOTA_REACHED]: 'QUOTA_REACHED',
  [INVALID_AUTH]: 'INVALID_AUTH',
  [AUTH_EXPIRED]: 'AUTH_EXPIRED',
  [DATA_CONFLICT]: 'DATA_CONFLICT',
  [ENML_VALIDATION]: 'ENML_VALIDATION',
  [SHARD_UNAVAILABLE]: 'SHARD_UNAVAILABLE',
  [LEN_TOO_SHORT]: 'LEN_TOO_SHORT',
  [LEN_TOO_LONG]: 'LEN_TOO_LONG',
  [TOO_FEW]: 'TOO_FEW',
  [TOO_MANY]: 'TOO_MANY',
  [UNSUPPORTED_OPERATION]: 'UNSUPPORTED_OPERATION',
  [TAKEN_DOWN]: 'TAKEN_DOWN',
  [RATE_LIMIT_REACHED]: 'RATE_LIMIT_REACHED',
  [OBJECT_NOT_FOUND]: 'OBJECT_NOT_FOUND',
}

// Define Evernote default resource type
export const DEFAULT_RESOURCE_TYPE = 'application/octet-stream'

// Define Evernote resource type mappings
export const RESOURCE_TYPES = {
  '.png': 'image/png',
  '.gif': 'image/gif',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
}

function wrapError(exception) {
  const error = new EvermarkError()

  error.code = exception.errorCode || UNKNOWN_ERROR
  if (exception.identifier) {
    error.code = OBJECT_NOT_FOUND
  }
  const codeStr = ERROR_CODES[error.code] || ERROR_CODES[UNKNOWN_ERROR]
  const message = `Evernote API Error: ${codeStr}`

  if (exception.parameter) {
    error.message = `${message}\n\nThe invalid parameter: ${exception.parameter}`
  }

  if (exception.message) {
    error.message = `${message}\n\n${exception.message}`
  }

  if (exception.identifier) {
    error.message = `${message}\n\nObject not found by identifier ${exception.identifier}`
  }

  return error
}

export default class EvernoteClient {
  constructor({ token, china = true, sandbox = false } = { china: true, sandbox: false }) {
    if (!token) {
      throw new EvermarkError('Missing developer token')
    }

    let serviceHost = china ? 'app.yinxiang.com' : 'www.evernote.com'
    serviceHost = sandbox ? 'sandbox.evernote.com' : serviceHost

    const options = { token, sandbox, serviceHost }
    debug('options: %o', options)
    this.options = options

    const client = new Evernote.Client(options)
    this.noteStore = client.getNoteStore()

    if (!this.noteStore.listNotebooksAsync) {
      Promise.promisifyAll(this.noteStore)
    }
  }

  listNotebooks() {
    return this.noteStore.listNotebooksAsync()
      .catch(e => {
        throw wrapError(e)
      })
  }

  createNotebook(name) {
    const notebook = new Evernote.Notebook()
    notebook.name = name
    return this.noteStore.createNotebookAsync(notebook)
      .catch(e => {
        throw wrapError(e)
      })
  }

  createNote(note) {
    return this.noteStore.createNoteAsync(note)
      .catch(e => {
        throw wrapError(e)
      })
  }

  updateNote(note) {
    return this.noteStore.updateNoteAsync(note)
      .catch(e => {
        throw wrapError(e)
      })
  }

  expungeNote(guid) {
    return this.noteStore.expungeNoteAsync(guid)
      .catch(e => {
        throw wrapError(e)
      })
  }
}
<commit_msg>refactor: improve log message<commit_after>import Promise from 'bluebird'
import { Evernote } from 'evernote'
import EvermarkError from './EvermarkError'

const debug = require('debug')('evernote')

// Define Evernote API error codes
export const UNKNOWN_ERROR = 1
export const BAD_DATA_FORMAT = 2
export const PERMISSION_DENIED = 3
export const INTERNAL_ERROR = 4
export const DATA_REQUIRED = 5
export const LIMIT_REACHED = 6
export const QUOTA_REACHED = 7
export const INVALID_AUTH = 8
export const AUTH_EXPIRED = 9
export const DATA_CONFLICT = 10
export const ENML_VALIDATION = 11
export const SHARD_UNAVAILABLE = 12
export const LEN_TOO_SHORT = 13
export const LEN_TOO_LONG = 14
export const TOO_FEW = 15
export const TOO_MANY = 16
export const UNSUPPORTED_OPERATION = 17
export const TAKEN_DOWN = 18
export const RATE_LIMIT_REACHED = 19
export const OBJECT_NOT_FOUND = 100

const ERROR_CODES = {
  [UNKNOWN_ERROR]: 'UNKNOWN',
  [BAD_DATA_FORMAT]: 'BAD_DATA_FORMAT',
  [PERMISSION_DENIED]: 'PERMISSION_DENIED',
  [INTERNAL_ERROR]: 'INTERNAL_ERROR',
  [DATA_REQUIRED]: 'DATA_REQUIRED',
  [LIMIT_REACHED]: 'LIMIT_REACHED',
  [QUOTA_REACHED]: 'QUOTA_REACHED',
  [INVALID_AUTH]: 'INVALID_AUTH',
  [AUTH_EXPIRED]: 'AUTH_EXPIRED',
  [DATA_CONFLICT]: 'DATA_CONFLICT',
  [ENML_VALIDATION]: 'ENML_VALIDATION',
  [SHARD_UNAVAILABLE]: 'SHARD_UNAVAILABLE',
  [LEN_TOO_SHORT]: 'LEN_TOO_SHORT',
  [LEN_TOO_LONG]: 'LEN_TOO_LONG',
  [TOO_FEW]: 'TOO_FEW',
  [TOO_MANY]: 'TOO_MANY',
  [UNSUPPORTED_OPERATION]: 'UNSUPPORTED_OPERATION',
  [TAKEN_DOWN]: 'TAKEN_DOWN',
  [RATE_LIMIT_REACHED]: 'RATE_LIMIT_REACHED',
  [OBJECT_NOT_FOUND]: 'OBJECT_NOT_FOUND',
}

// Define Evernote default resource type
export const DEFAULT_RESOURCE_TYPE = 'application/octet-stream'

// Define Evernote resource type mappings
export const RESOURCE_TYPES = {
  '.png': 'image/png',
  '.gif': 'image/gif',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
}

function wrapError(exception) {
  const error = new EvermarkError()

  error.code = exception.errorCode || UNKNOWN_ERROR
  if (exception.identifier) {
    error.code = OBJECT_NOT_FOUND
  }
  const codeStr = ERROR_CODES[error.code] || ERROR_CODES[UNKNOWN_ERROR]
  const message = `Evernote API Error: ${codeStr}`

  if (exception.parameter) {
    error.message = `${message}\n\nThe invalid parameter: ${exception.parameter}`
  }

  if (exception.message) {
    error.message = `${message}\n\n${exception.message}`
  }

  if (exception.identifier) {
    error.message = `${message}\n\nObject not found by identifier ${exception.identifier}`
  }

  return error
}

export default class EvernoteClient {
  constructor({ token, china = true, sandbox = false } = { china: true, sandbox: false }) {
    if (!token) {
      throw new EvermarkError('Missing developer token')
    }

    let serviceHost = china ? 'app.yinxiang.com' : 'www.evernote.com'
    serviceHost = sandbox ? 'sandbox.evernote.com' : serviceHost

    const options = { token, sandbox, serviceHost }
    debug('Evernote client options: %o', options)
    this.options = options

    const client = new Evernote.Client(options)
    this.noteStore = client.getNoteStore()

    if (!this.noteStore.listNotebooksAsync) {
      Promise.promisifyAll(this.noteStore)
    }
  }

  listNotebooks() {
    return this.noteStore.listNotebooksAsync()
      .catch(e => {
        throw wrapError(e)
      })
  }

  createNotebook(name) {
    const notebook = new Evernote.Notebook()
    notebook.name = name
    return this.noteStore.createNotebookAsync(notebook)
      .catch(e => {
        throw wrapError(e)
      })
  }

  createNote(note) {
    return this.noteStore.createNoteAsync(note)
      .catch(e => {
        throw wrapError(e)
      })
  }

  updateNote(note) {
    return this.noteStore.updateNoteAsync(note)
      .catch(e => {
        throw wrapError(e)
      })
  }

  expungeNote(guid) {
    return this.noteStore.expungeNoteAsync(guid)
      .catch(e => {
        throw wrapError(e)
      })
  }
}
<|endoftext|>


<commit_before>"use strict";

const Value = require('./Value');

const NAME = '[a-z_]\\w*';
const itemRe = new RegExp('^\\s*(?:' +
            '(?:\\[' +
                '(' + NAME + ')' +   // [1]
                '(?:[:](' + NAME + ')(\\[\\])?)?' +  // [2] optional ":type[]" [3]
            ')' +
            '(?:\\[' +
                '(' + NAME + ')' +   // [4]
                '(?:[:](' + NAME + ')(\\[\\])?)?' +  // [5] optional ":type[]" [6]
                '(?:[=]([^\\]]+))?' +       // [7] optional "=value"
            '\\])' +
        ')\\s*$', 'i');

//const shortHandRe = /^(\[)?([a-z]+[0-9\-_]*)(:(\w+)(=([\w._\-]+))?)?(])?$/i;

/**
 * This class manages a case-insensitive collection of named items for a class. This is
 * used to manage "switches" and "arguments" for Command and "commands" for Commands.
 * @private
 */
class Items {
    static get (owner, name) {
        var key = '_' + name;
        var ret = owner[key];

        if (!owner.hasOwnProperty(key)) {
            let base = Items.get(Object.getPrototypeOf(owner), name);

            owner[key] = ret = new this(owner, base, name);
        }

        return ret;
    }

    constructor (owner, base, kind) {
        this.owner = owner;
        this.base = base || null;
        this.items = base ? base.items.slice() : [];
        this.map = base ? Object.create(base.map) : {};
        this.kind = base ? base.kind : kind;
        this.values = base ? Object.create(base.values) : {};
    }

    add (name, item) {
        if (item) {
            item = this.itemFromValue(item);
        } else {
            item = this.itemFromString(name);
        }

        item.name = name;
        item.loname = name.toLowerCase();

        item = this.wrap(item);

        this.items.push(item);
        this.map[name] = this.map[item.loname] = item;
        this.values[name] = this.values[item.loname] = item.value;
    }

    addAll (all) {
        if (typeof all === 'string' || all instanceof String) {  // TODO instanceof?
            all = all.split(' ');

            all.forEach(part => this.add(part));
        }
        else {
            for (let name in all) {
                this.add(name, all[name]);
            }
        }
    }

    canonicalize (name) {
        var entry = this.lookup(name);

        if (!entry) {
            throw new Error(`${name} matches no ${this.kind} for ${this.owner.title}`);
            // "bar" matches no switches for "git commit"
            // "foo" matches no commands for "git"
        }

        return entry.name;
    }

    /**
     * This method accepts a string and produces an item config object.
     * @param {String} def
     * @return {Object}
     */
    itemFromString (def) {
        let match = itemRe.exec(def);

        if (!match) {
            throw new Error(`Invalid parameter syntax definition: "${def}"`);
        }

        let item = {
            name: match[1] || match[4],
            type: match[2] || match[5] || null
        };

        if (item.type) {
            item.array = !!(match[3] || match[6]);
        }

        if (match[4]) { // if (optional)
            // Only store a value if we have one (this property is detected using
            // the "in" operator):
            if (match[7] != null) {
                item.value = match[7];
            }
        }

        return item;
    }

    itemFromValue (item) {
        if (item.constructor !== Object) {
            item = {
                value: item
            };
        }

        return item;
    }

    lookup (name) {
        var map = this.map,
            entry, first, loname, matches, ret;

        ret = map[name] || map[loname = name.toLowerCase()];

        if (!ret) {
            for (let key in map) {
                entry = map[key];

                if (entry.loname.startsWith(loname)) {
                    if (!ret) {
                        first = key;
                        ret = entry;
                    }
                    else {
                        if (!matches) {
                            matches = [first];
                        }

                        matches.push(key);
                    }
                }
            }

            if (matches) {
                // If we have multiple matches then the name we were given is
                // ambiguous (so throw):
                throw new Error(`"${name}" matches multiple ${this.kind} for ${this.owner.title}: ${matches.join(', ')}`);
                // "bar" matches multiple switches for "git commit"
                // "foo" matches multiple commands for "git"
            }
        }

        return ret || null;
    }

    setDefaults (params) {
        for (let item of this.items) {
            if ('value' in item && !(item.name in params)) {
                item.set(params, item.value);
            }
        }
    }

    validate (params) {
        var missing;

        for (let item of this.items) {
            if (item.required && !(item.name in params)) {
                (missing || (missing = [])).push(item.name);
            }
        }

        if (missing) {
            return `Missing required ${this.kind}: ${missing.join(', ')}`;
        }

        return null;
    }

    wrap (item) {
        return item;
    }
}

module.exports = Items;
<commit_msg>Allow "..." or "[]" to indicate array/vararg parameter<commit_after>"use strict";

const Value = require('./Value');

const NAME = '[a-z_]\\w*';
const VARARG = '((?:\\.\\.\\.)|(?:\\[\\]))?';  // match "type..." or "type[]"
const itemRe = new RegExp('^\\s*(?:' +
            '(?:\\[' +
                '(' + NAME + ')' +   // [1]
                '(?:[:](' + NAME + ')'+VARARG+')?' +  // [2] optional ":type..." [3]
            ')' +
            '(?:\\[' +
                '(' + NAME + ')' +   // [4]
                '(?:[:](' + NAME + ')'+VARARG+')?' +  // [5] optional ":type..." [6]
                '(?:[=]([^\\]]+))?' +       // [7] optional "=value"
            '\\])' +
        ')\\s*$', 'i');

//const shortHandRe = /^(\[)?([a-z]+[0-9\-_]*)(:(\w+)(=([\w._\-]+))?)?(])?$/i;

/**
 * This class manages a case-insensitive collection of named items for a class. This is
 * used to manage "switches" and "arguments" for Command and "commands" for Commands.
 * @private
 */
class Items {
    static get (owner, name) {
        var key = '_' + name;
        var ret = owner[key];

        if (!owner.hasOwnProperty(key)) {
            let base = Items.get(Object.getPrototypeOf(owner), name);

            owner[key] = ret = new this(owner, base, name);
        }

        return ret;
    }

    constructor (owner, base, kind) {
        this.owner = owner;
        this.base = base || null;
        this.items = base ? base.items.slice() : [];
        this.map = base ? Object.create(base.map) : {};
        this.kind = base ? base.kind : kind;
        this.values = base ? Object.create(base.values) : {};
    }

    add (name, item) {
        if (item) {
            item = this.itemFromValue(item);
        } else {
            item = this.itemFromString(name);
        }

        item.name = name;
        item.loname = name.toLowerCase();

        item = this.wrap(item);

        this.items.push(item);
        this.map[name] = this.map[item.loname] = item;
        this.values[name] = this.values[item.loname] = item.value;
    }

    addAll (all) {
        if (typeof all === 'string' || all instanceof String) {  // TODO instanceof?
            all = all.split(' ');

            all.forEach(part => this.add(part));
        }
        else {
            for (let name in all) {
                this.add(name, all[name]);
            }
        }
    }

    canonicalize (name) {
        var entry = this.lookup(name);

        if (!entry) {
            throw new Error(`${name} matches no ${this.kind} for ${this.owner.title}`);
            // "bar" matches no switches for "git commit"
            // "foo" matches no commands for "git"
        }

        return entry.name;
    }

    /**
     * This method accepts a string and produces an item config object.
     * @param {String} def
     * @return {Object}
     */
    itemFromString (def) {
        let match = itemRe.exec(def);

        if (!match) {
            throw new Error(`Invalid parameter syntax definition: "${def}"`);
        }

        let item = {
            name: match[1] || match[4],
            type: match[2] || match[5] || null
        };

        if (item.type) {
            item.array = !!(match[3] || match[6]);
        }

        if (match[4]) { // if (optional)
            // Only store a value if we have one (this property is detected using
            // the "in" operator):
            if (match[7] != null) {
                item.value = match[7];
            }
        }

        return item;
    }

    itemFromValue (item) {
        if (item.constructor !== Object) {
            item = {
                value: item
            };
        }

        return item;
    }

    lookup (name) {
        var map = this.map,
            entry, first, loname, matches, ret;

        ret = map[name] || map[loname = name.toLowerCase()];

        if (!ret) {
            for (let key in map) {
                entry = map[key];

                if (entry.loname.startsWith(loname)) {
                    if (!ret) {
                        first = key;
                        ret = entry;
                    }
                    else {
                        if (!matches) {
                            matches = [first];
                        }

                        matches.push(key);
                    }
                }
            }

            if (matches) {
                // If we have multiple matches then the name we were given is
                // ambiguous (so throw):
                throw new Error(`"${name}" matches multiple ${this.kind} for ${this.owner.title}: ${matches.join(', ')}`);
                // "bar" matches multiple switches for "git commit"
                // "foo" matches multiple commands for "git"
            }
        }

        return ret || null;
    }

    setDefaults (params) {
        for (let item of this.items) {
            if ('value' in item && !(item.name in params)) {
                item.set(params, item.value);
            }
        }
    }

    validate (params) {
        var missing;

        for (let item of this.items) {
            if (item.required && !(item.name in params)) {
                (missing || (missing = [])).push(item.name);
            }
        }

        if (missing) {
            return `Missing required ${this.kind}: ${missing.join(', ')}`;
        }

        return null;
    }

    wrap (item) {
        return item;
    }
}

module.exports = Items;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';

class FacebookPlayer extends Component {
  static propTypes = {
    id: PropTypes.string,
    className: PropTypes.string,
    appId: PropTypes.string.isRequired,
    videoId: PropTypes.string.isRequired,
    width: PropTypes.number,
    allowfullscreen: PropTypes.string,
    autoplay: PropTypes.string,
    showText: PropTypes.string,
    showCaptions: PropTypes.string,
    onReady: PropTypes.func,
    onStartedPlaying: PropTypes.func,
    onPaused: PropTypes.func,
    onFinishedPlaying: PropTypes.func,
    onStartedBuffering: PropTypes.func,
    onFinishedBuffering: PropTypes.func,
    onError: PropTypes.func,
  };

  constructor(props) {
    super(props);

    /**
     * Set events that will be added to listen list.
     * REF: https://developers.facebook.com/docs/plugins/embedded-video-player/api#event-reference
     */
    this.eventsToListen = [
      {
        event: 'startedPlaying',
        listener: (player) => this.props.onStartedPlaying(this.props.id),
      },
      {
        event: 'paused',
        listener: () => this.props.onPaused(this.props.id),
      },
      {
        event: 'finishedPlaying',
        listener: () => this.props.onFinishedPlaying(this.props.id),
      },
      {
        event: 'startedBuffering',
        listener: () => this.props.onStartedBuffering(this.props.id),
      },
      {
        event: 'finishedBuffering',
        listener: () => this.props.onFinishedBuffering(this.props.id),
      },
      {
        event: 'error',
        listener: () => this.props.onError(this.props.id),
      },
    ];

    this.FB = null;
    this.videoPlayer = null;
    this.eventHandlers = null;
  }

  /**
   * Load Facebook SDK and set FB to global vars
   */
  componentDidMount() {
    const {
      videoId,
    } = this.props;

    if (typeof window !== "undefined") {
      this.loadFB()
        .then(res => {
          if (res) {
            this.FB = res;
            this.createPlayer(videoId);
          }
        });
    }
  }

  /**
   * Refresh component if a new video id is set,
   */
  componentWillReceiveProps(newProps) {
    if (this.FB && newProps.videoId !== this.props.videoId) {
      this.createPlayer(newProps.videoId);
    }
  }

  /**
   * Kill all event listeners
   */
  componentWillUnmount() {
    // this.unsubscribe();
  }

  /**
   * Load Facebook SDK if it is not loaded already.
   */
  loadFB = () => {
    if(window.FB) {
      return new Promise(resolve => resolve(window.FB));
    }

    return new Promise(resolve => {
      window.fbAsyncInit = function() {
        return resolve(window.FB);
      };
      (function(d, s, id){
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) {return;}
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3";
        js.onload = function() {
          return resolve(window.FB);
        }
        fjs.parentNode.insertBefore(js, fjs);
      }(document, 'script', 'facebook-jssdk'));
    });
  }

  /**
   * Create player.
   *
   * @param {string} Facebook video id
   */
  createPlayer = (videoId) => {
    const {
      id,
      appId,
      allowfullscreen,
      autoplay,
      width,
      showText,
      showCaptions,
      onReady,
    } = this.props;
    const FB = this.FB;

    const playerId = id + '--player';

    // Clear
    this.container.innerHTML = '';
    // this.unsubscribe();

    const playerDiv = document.createElement('div');
    playerDiv.classList.add('fb-video');
    playerDiv.id = playerId;
    playerDiv.setAttribute('data-href', 'https://www.facebook.com/facebook/videos/' + videoId);
    playerDiv.setAttribute('data-allowfullscreen', allowfullscreen || 'false');
    playerDiv.setAttribute('data-autoplay', autoplay || 'false');
    playerDiv.setAttribute('data-width', width || 'auto');
    playerDiv.setAttribute('data-show-text', showText || 'false');
    playerDiv.setAttribute('data-show-captions', showCaptions || 'false');

    this.container.appendChild(playerDiv);

    FB.init({
      appId      : appId,
      xfbml      : true,
      version    : 'v2.5'
    });

    FB.Event.subscribe('xfbml.ready', msg => {
      window.msg = msg;
      if (msg.type === 'video' &&
          (
            (id && msg.id === playerId) ||
            !id
          )
          ) {
        this.videoPlayer = msg.instance;

        // Dispatch ready event
        if (onReady) onReady(id, this.videoPlayer);

        // Subscribe to events
        this.subscribe();
      }
    });
  }

  /**
   * Listen to events based on eventsToListen var.
   */
  subscribe = () => {
    this.eventHandlers = [];
    this.eventsToListen.map(ev => {
      if (ev.listener) {
        const handler = this.videoPlayer.subscribe(ev.event, ev.listener);
        this.eventHandlers.push({
          event: ev.event,
          handler,
        })
      };
    });
  }

  /**
   * Stop listening to events.
   */
  unsubscribe = () => {
    if (this.eventHandlers && this.eventHandlers.length) {
      this.eventHandlers.map(ev => {
        if (ev.handler.removeListener) ev.handler.removeListener(ev.event);
      });
    }
  }

  /**
   * Set container var to reuse as DOM object.
   */
  refContainer = (container) => {
    this.container = container;
  }

  render() {
    const { id, className } = this.props;

    return (

    );
  }
}

export default FacebookPlayer;
<commit_msg>Update FacebookPlayer.js<commit_after>import React from 'react';
import { string, number, func } from 'prop-types';

class FacebookPlayer extends React.Component {
  static propTypes = {
    id: string,
    className: string,
    appId: string.isRequired,
    videoId: string.isRequired,
    width: number,
    allowfullscreen: string,
    autoplay: string,
    showText: string,
    showCaptions: string,
    onReady: func,
    onStartedPlaying: func,
    onPaused: func,
    onFinishedPlaying: func,
    onStartedBuffering: func,
    onFinishedBuffering: func,
    onError: func
  };

  constructor(props) {
    super(props);

    /**
     * Set events that will be added to listen list.
     * REF: https://developers.facebook.com/docs/plugins/embedded-video-player/api#event-reference
     */
    this.eventsToListen = [
      {
        event: 'startedPlaying',
        listener: (player) => this.props.onStartedPlaying(this.props.id),
      },
      {
        event: 'paused',
        listener: () => this.props.onPaused(this.props.id),
      },
      {
        event: 'finishedPlaying',
        listener: () => this.props.onFinishedPlaying(this.props.id),
      },
      {
        event: 'startedBuffering',
        listener: () => this.props.onStartedBuffering(this.props.id),
      },
      {
        event: 'finishedBuffering',
        listener: () => this.props.onFinishedBuffering(this.props.id),
      },
      {
        event: 'error',
        listener: () => this.props.onError(this.props.id),
      },
    ];

    this.FB = null;
    this.videoPlayer = null;
    this.eventHandlers = null;
  }

  /**
   * Load Facebook SDK and set FB to global vars
   */
  componentDidMount() {
    const {
      videoId,
    } = this.props;

    if (typeof window !== "undefined") {
      this.loadFB()
        .then(res => {
          if (res) {
            this.FB = res;
            this.createPlayer(videoId);
          }
        });
    }
  }

  /**
   * Refresh component if a new video id is set,
   */
  componentWillReceiveProps(newProps) {
    if (this.FB && newProps.videoId !== this.props.videoId) {
      this.createPlayer(newProps.videoId);
    }
  }

  /**
   * Kill all event listeners
   */
  componentWillUnmount() {
    // this.unsubscribe();
  }

  /**
   * Load Facebook SDK if it is not loaded already.
   */
  loadFB = () => {
    if(window.FB) {
      return new Promise(resolve => resolve(window.FB));
    }

    return new Promise(resolve => {
      window.fbAsyncInit = function() {
        return resolve(window.FB);
      };
      (function(d, s, id){
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) {return;}
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.3";
        js.onload = function() {
          return resolve(window.FB);
        }
        fjs.parentNode.insertBefore(js, fjs);
      }(document, 'script', 'facebook-jssdk'));
    });
  }

  /**
   * Create player.
   *
   * @param {string} Facebook video id
   */
  createPlayer = (videoId) => {
    const {
      id,
      appId,
      allowfullscreen,
      autoplay,
      width,
      showText,
      showCaptions,
      onReady,
    } = this.props;
    const FB = this.FB;

    const playerId = id + '--player';

    // Clear
    this.container.innerHTML = '';
    // this.unsubscribe();

    const playerDiv = document.createElement('div');
    playerDiv.classList.add('fb-video');
    playerDiv.id = playerId;
    playerDiv.setAttribute('data-href', 'https://www.facebook.com/facebook/videos/' + videoId);
    playerDiv.setAttribute('data-allowfullscreen', allowfullscreen || 'false');
    playerDiv.setAttribute('data-autoplay', autoplay || 'false');
    playerDiv.setAttribute('data-width', width || 'auto');
    playerDiv.setAttribute('data-show-text', showText || 'false');
    playerDiv.setAttribute('data-show-captions', showCaptions || 'false');

    this.container.appendChild(playerDiv);

    FB.init({
      appId      : appId,
      xfbml      : true,
      version    : 'v2.5'
    });

    FB.Event.subscribe('xfbml.ready', msg => {
      window.msg = msg;
      if (msg.type === 'video' &&
          (
            (id && msg.id === playerId) ||
            !id
          )
          ) {
        this.videoPlayer = msg.instance;

        // Dispatch ready event
        if (onReady) onReady(id, this.videoPlayer);

        // Subscribe to events
        this.subscribe();
      }
    });
  }

  /**
   * Listen to events based on eventsToListen var.
   */
  subscribe = () => {
    this.eventHandlers = [];
    this.eventsToListen.map(ev => {
      if (ev.listener) {
        const handler = this.videoPlayer.subscribe(ev.event, ev.listener);
        this.eventHandlers.push({
          event: ev.event,
          handler,
        })
      };
    });
  }

  /**
   * Stop listening to events.
   */
  unsubscribe = () => {
    if (this.eventHandlers && this.eventHandlers.length) {
      this.eventHandlers.map(ev => {
        if (ev.handler.removeListener) ev.handler.removeListener(ev.event);
      });
    }
  }

  /**
   * Set container var to reuse as DOM object.
   */
  refContainer = (container) => {
    this.container = container;
  }

  render() {
    const { id, className } = this.props;

    return (

    );
  }
}

export default FacebookPlayer;
<|endoftext|>