<commit_before>(function($) {
  'use strict';

  let _defaults = {
    responsiveThreshold: 0, // breakpoint for swipeable
  };

  class Parallax extends Component {

    constructor(el, options) {
      super(Parallax, el, options);

      this.el.M_Parallax = this;

      /**
       * Options for the Parallax
       * @member Parallax#options
       * @prop {Number} responsiveThreshold
       */
      this.options = $.extend({}, Parallax.defaults, options);

      this.$img = this.$el.find('img').first();
      this._enabled = window.innerWidth > this.options.responsiveThreshold;
      this._updateParallax();
      this._setupEventHandlers();
      this._setupStyles();

      Parallax._parallaxes.push(this);
    }

    static get defaults() {
      return _defaults;
    }

    static init(els, options) {
      return super.init(this, els, options);
    }

    /**
     * Get Instance
     */
    static getInstance(el) {
      let domElem = !!el.jquery ? el[0] : el;
      return domElem.M_Parallax;
    }

    /**
     * Teardown component
     */
    destroy() {
      Parallax._parallaxes.splice(Parallax._parallaxes.indexOf(this), 1);
      this.$img[0].style.transform = '';
      this._removeEventHandlers();

      this.$el[0].M_Parallax = undefined;
    }

    static _handleScroll() {
      for (let i = 0; i < Parallax._parallaxes.length; i++) {
        let parallaxInstance = Parallax._parallaxes[i];
        parallaxInstance._updateParallax.call(parallaxInstance);
      }
    }

    static _handleWindowResize() {
      for (let i = 0; i < Parallax._parallaxes.length; i++) {
        let parallaxInstance = Parallax._parallaxes[i];
        parallaxInstance._enabled = window.innerWidth > parallaxInstance.options.responsiveThreshold;
      }
    }

    _setupEventHandlers() {
      this._handleImageLoadBound = this._handleImageLoad.bind(this);
      this.$img[0].addEventListener('load', this._handleImageLoadBound);

      if (Parallax._parallaxes.length === 0) {
        Parallax._handleScrollThrottled = M.throttle(Parallax._handleScroll, 5);
        window.addEventListener('scroll', Parallax._handleScrollThrottled);

        Parallax._handleWindowResizeThrottled = M.throttle(Parallax._handleWindowResize, 5);
        window.addEventListener('resize', Parallax._handleWindowResizeThrottled);
      }
    }

    _removeEventHandlers() {
      this.$img[0].removeEventListener('load', this._handleImageLoadBound);

      if (Parallax._parallaxes.length === 0) {
        window.removeEventListener('scroll', Parallax._handleScrollThrottled);
        window.removeEventListener('resize', Parallax._handleWindowResizeThrottled);
      }
    }

    _setupStyles() {
      this.$img[0].style.opacity = 1;
    }

    _handleImageLoad() {
      this._updateParallax();
      this.$img.each(function() {
        let el = this;
        if (el.complete) $(el).trigger("load");
      });
    }

    _updateParallax() {
      let containerHeight = this.$el.height() > 0 ? this.el.parentNode.offsetHeight : 500;
      let imgHeight = this.$img[0].offsetHeight;
      let parallaxDist = imgHeight - containerHeight;
      let bottom = this.$el.offset().top + containerHeight;
      let top = this.$el.offset().top;
      let scrollTop = M.getDocumentScrollTop();
      let windowHeight = window.innerHeight;
      let windowBottom = scrollTop + windowHeight;
      let percentScrolled = (windowBottom - top) / (containerHeight + windowHeight);
      let parallax = parallaxDist * percentScrolled;

      if (!this._enabled) {
        this.$img[0].style.transform = '';

      } else if (bottom > scrollTop && top < scrollTop + windowHeight) {
        this.$img[0].style.transform = `translate3D(-50%, ${parallax}px, 0)`;
      }
    }
  }

  /**
   * @static
   * @memberof Parallax
   */
  Parallax._parallaxes = [];

  M.Parallax = Parallax;

  if (M.jQueryLoaded) {
    M.initializeJqueryWrapper(Parallax, 'parallax', 'M_Parallax');
  }

})(cash);
<commit_msg>fixed parallax infinite loop<commit_after>(function($) {
  'use strict';

  let _defaults = {
    responsiveThreshold: 0, // breakpoint for swipeable
  };

  class Parallax extends Component {

    constructor(el, options) {
      super(Parallax, el, options);

      this.el.M_Parallax = this;

      /**
       * Options for the Parallax
       * @member Parallax#options
       * @prop {Number} responsiveThreshold
       */
      this.options = $.extend({}, Parallax.defaults, options);
      this._enabled = window.innerWidth > this.options.responsiveThreshold;

      this.$img = this.$el.find('img').first();
      this.$img.each(function() {
        let el = this;
        if (el.complete) $(el).trigger("load");
      });

      this._updateParallax();
      this._setupEventHandlers();
      this._setupStyles();

      Parallax._parallaxes.push(this);
    }

    static get defaults() {
      return _defaults;
    }

    static init(els, options) {
      return super.init(this, els, options);
    }

    /**
     * Get Instance
     */
    static getInstance(el) {
      let domElem = !!el.jquery ? el[0] : el;
      return domElem.M_Parallax;
    }

    /**
     * Teardown component
     */
    destroy() {
      Parallax._parallaxes.splice(Parallax._parallaxes.indexOf(this), 1);
      this.$img[0].style.transform = '';
      this._removeEventHandlers();

      this.$el[0].M_Parallax = undefined;
    }

    static _handleScroll() {
      for (let i = 0; i < Parallax._parallaxes.length; i++) {
        let parallaxInstance = Parallax._parallaxes[i];
        parallaxInstance._updateParallax.call(parallaxInstance);
      }
    }

    static _handleWindowResize() {
      for (let i = 0; i < Parallax._parallaxes.length; i++) {
        let parallaxInstance = Parallax._parallaxes[i];
        parallaxInstance._enabled = window.innerWidth > parallaxInstance.options.responsiveThreshold;
      }
    }

    _setupEventHandlers() {
      this._handleImageLoadBound = this._handleImageLoad.bind(this);
      this.$img[0].addEventListener('load', this._handleImageLoadBound);

      if (Parallax._parallaxes.length === 0) {
        Parallax._handleScrollThrottled = M.throttle(Parallax._handleScroll, 5);
        window.addEventListener('scroll', Parallax._handleScrollThrottled);

        Parallax._handleWindowResizeThrottled = M.throttle(Parallax._handleWindowResize, 5);
        window.addEventListener('resize', Parallax._handleWindowResizeThrottled);
      }
    }

    _removeEventHandlers() {
      this.$img[0].removeEventListener('load', this._handleImageLoadBound);

      if (Parallax._parallaxes.length === 0) {
        window.removeEventListener('scroll', Parallax._handleScrollThrottled);
        window.removeEventListener('resize', Parallax._handleWindowResizeThrottled);
      }
    }

    _setupStyles() {
      this.$img[0].style.opacity = 1;
    }

    _handleImageLoad() {
      this._updateParallax();
    }

    _updateParallax() {
      let containerHeight = this.$el.height() > 0 ? this.el.parentNode.offsetHeight : 500;
      let imgHeight = this.$img[0].offsetHeight;
      let parallaxDist = imgHeight - containerHeight;
      let bottom = this.$el.offset().top + containerHeight;
      let top = this.$el.offset().top;
      let scrollTop = M.getDocumentScrollTop();
      let windowHeight = window.innerHeight;
      let windowBottom = scrollTop + windowHeight;
      let percentScrolled = (windowBottom - top) / (containerHeight + windowHeight);
      let parallax = parallaxDist * percentScrolled;

      if (!this._enabled) {
        this.$img[0].style.transform = '';

      } else if (bottom > scrollTop && top < scrollTop + windowHeight) {
        this.$img[0].style.transform = `translate3D(-50%, ${parallax}px, 0)`;
      }
    }
  }

  /**
   * @static
   * @memberof Parallax
   */
  Parallax._parallaxes = [];

  M.Parallax = Parallax;

  if (M.jQueryLoaded) {
    M.initializeJqueryWrapper(Parallax, 'parallax', 'M_Parallax');
  }

})(cash);
<|endoftext|>


<commit_before>// @flow
import SelectList from 'atom-select-list'
import Repository, { StashCommands } from '../repository'
import type { StashReference, StashCommand } from '../repository'

type ISelectList = { destroy: Function, element: HTMLElement, focus: Function }

class StashListView {
  isAttached = false
  listView: ISelectList
  panel: Panel
  previouslyFocusedElement: ?HTMLElement

  constructor(references: StashReference[], handleSelection: StashReference => void) {
    this.listView = new SelectList({
      items: references,
      emptyMessage: 'Your stash is empty',
      filterKeyForItem: reference => reference.content,
      elementForItem: (reference, options) => {
        const li = document.createElement('li')
        li.textContent = `${reference.index}: ${reference.label}`
        return li
      },
      didCancelSelection: () => {
        this.destroy()
        this.restoreFocus()
      },
      didConfirmSelection: reference => {
        handleSelection(reference)
        this.destroy()
      }
    })
  }

  attach() {
    this.previouslyFocusedElement = document.activeElement
    this.panel = atom.workspace.addModalPanel({ item: this.listView.element })
    this.listView.focus()
    this.isAttached = true
  }

  destroy = () => {
    if (this.isAttached) {
      this.panel.destroy()
      this.listView.destroy()
    }
  }

  restoreFocus = () => {
    this.previouslyFocusedElement && this.previouslyFocusedElement.focus()
  }
}

class StashOptionsView {
  isAttached = false
  listView: ISelectList
  panel: Panel
  previouslyFocusedElement: ?HTMLElement

  constructor(reference: StashReference, handleSelection: StashCommand => any) {
    this.listView = new SelectList({
      items: Object.entries(StashCommands).map(entry => ({ label: entry[0], ...entry[1] })),
      filterKeyForItem: command => command.label,
      elementForItem: (command, options) => {
        const li = document.createElement('li')
        const labelDiv = document.createElement('div')
        labelDiv.classList.add('text-highlight')
        labelDiv.textContent = command.label
        const infoDiv = document.createElement('div')
        infoDiv.classList.add('text-info')
        infoDiv.textContent = reference.label
        li.append(labelDiv, infoDiv)
        return li
      },
      didCancelSelection: this.destroy,
      didConfirmSelection: (command: StashCommand) => {
        handleSelection(command)
        this.destroy()
      }
    })
  }

  attach() {
    this.previouslyFocusedElement = document.activeElement
    this.panel = atom.workspace.addModalPanel({ item: this.listView.element })
    this.listView.focus()
    this.isAttached = true
  }

  focus() {
    if (this.isAttached) this.listView.focus()
  }

  destroy = () => {
    if (this.isAttached) {
      this.panel.destroy()
      this.previouslyFocusedElement && this.previouslyFocusedElement.focus()
      this.listView.destroy()
    }
  }
}

export default async () => {
  const repo = await Repository.getCurrent()
  const stash = await repo.getStash()
  const stashListView = new StashListView(stash, reference => {
    const optionsView = new StashOptionsView(reference, async command => {
      repo
        .stash(reference, command)
        .then(() =>
          atom.notifications.addSuccess(
            `stash@{${reference.index}} ${command.pastTense} successfully`,
            {
              detail: reference.label
            }
          )
        )
        .catch(error =>
          atom.notifications.addError(
            `There was an error ${command.presentTense} stash@{${reference.index}}`,
            {
              detail: error
            }
          )
        )
    })
    optionsView.attach()
    optionsView.focus()
  })
  stashListView.attach()
}
<commit_msg>stash views attach themselves<commit_after>// @flow
import SelectList from 'atom-select-list'
import Repository, { StashCommands } from '../repository'
import type { StashReference, StashCommand } from '../repository'

type ISelectList = { destroy: Function, element: HTMLElement, focus: Function }

class StashListView {
  isAttached = false
  listView: ISelectList
  panel: Panel
  previouslyFocusedElement: ?HTMLElement

  constructor(references: StashReference[], handleSelection: StashReference => void) {
    this.listView = new SelectList({
      items: references,
      emptyMessage: 'Your stash is empty',
      filterKeyForItem: reference => reference.content,
      elementForItem: (reference, options) => {
        const li = document.createElement('li')
        li.textContent = `${reference.index}: ${reference.label}`
        return li
      },
      didCancelSelection: () => {
        this.destroy()
        this.restoreFocus()
      },
      didConfirmSelection: reference => {
        handleSelection(reference)
        this.destroy()
      }
    })
    this.attach()
  }

  attach() {
    this.previouslyFocusedElement = document.activeElement
    this.panel = atom.workspace.addModalPanel({ item: this.listView.element })
    this.listView.focus()
    this.isAttached = true
  }

  destroy = () => {
    if (this.isAttached) {
      this.panel.destroy()
      this.listView.destroy()
    }
  }

  restoreFocus = () => {
    this.previouslyFocusedElement && this.previouslyFocusedElement.focus()
  }
}

class StashOptionsView {
  isAttached = false
  listView: ISelectList
  panel: Panel
  previouslyFocusedElement: ?HTMLElement

  constructor(reference: StashReference, handleSelection: StashCommand => any) {
    this.listView = new SelectList({
      items: Object.entries(StashCommands).map(entry => ({ label: entry[0], ...entry[1] })),
      filterKeyForItem: command => command.label,
      elementForItem: (command, options) => {
        const li = document.createElement('li')
        const labelDiv = document.createElement('div')
        labelDiv.classList.add('text-highlight')
        labelDiv.textContent = command.label
        const infoDiv = document.createElement('div')
        infoDiv.classList.add('text-info')
        infoDiv.textContent = reference.label
        li.append(labelDiv, infoDiv)
        return li
      },
      didCancelSelection: this.destroy,
      didConfirmSelection: (command: StashCommand) => {
        handleSelection(command)
        this.destroy()
      }
    })
    this.attach()
  }

  attach() {
    this.previouslyFocusedElement = document.activeElement
    this.panel = atom.workspace.addModalPanel({ item: this.listView.element })
    this.listView.focus()
    this.isAttached = true
  }

  focus() {
    if (this.isAttached) this.listView.focus()
  }

  destroy = () => {
    if (this.isAttached) {
      this.panel.destroy()
      this.previouslyFocusedElement && this.previouslyFocusedElement.focus()
      this.listView.destroy()
    }
  }
}

export default async () => {
  const repo = await Repository.getCurrent()
  const stash = await repo.getStash()
  const stashListView = new StashListView(stash, reference => {
    const optionsView = new StashOptionsView(reference, async command => {
      repo
        .stash(reference, command)
        .then(() =>
          atom.notifications.addSuccess(
            `stash@{${reference.index}} ${command.pastTense} successfully`,
            {
              detail: reference.label
            }
          )
        )
        .catch(error =>
          atom.notifications.addError(
            `There was an error ${command.presentTense} stash@{${reference.index}}`,
            {
              detail: error
            }
          )
        )
    })
    optionsView.focus()
  })
}
<|endoftext|>


<commit_before>/**
 * Hilo
 * Copyright 2015 alibaba.com
 * Licensed under the MIT License
 */

//TODO: 超时timeout，失败重连次数maxTries，更多的下载器Loader，队列暂停恢复等。

/**
 * @language=en
 * @class LoadQueue is a queue-like loader.
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source resource that need to be loaded,could be a single object or array resource.
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections the limited concurrent connections. default value  2.
 */
/**
 * @language=zh
 * @class LoadQueue是一个队列下载工具。
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source 要下载的资源。可以是单个资源对象或多个资源的数组。
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections 同时下载的最大连接数。默认为2。
 */
var LoadQueue = Class.create(/** @lends LoadQueue.prototype */{
    Mixes: EventMixin,
    constructor: function(source){
        this._source = [];
        this.add(source);
    },

    maxConnections: 2, //TODO: 应该是每个host的最大连接数。

    _source: null,
    _loaded: 0,
    _connections: 0,
    _currentIndex: -1,

    /**
     * @language=en
     * Add desired resource,could be a single object or array resource.
     * @param {Object|Array} source ,a single object or array resource. Each resource contains properties like below:
     *

     *
id - resource identifier

     *
src - resource url

     *
type - resource type. By default, we automatically identify resource by file suffix and choose the relevant loader for you

     *
loader - specified resource loader. If you specify this,we abandon choosing loader inside

     *
noCache - a tag that set on or off to prevent cache,implemented by adding timestamp inside

     *
size - predicted resource size, help calculating loading progress

     *
crossOrigin - Whether cross-domain is needed, default is false

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    /**
     * @language=zh
     * 增加要下载的资源。可以是单个资源对象或多个资源的数组。
     * @param {Object|Array} source 资源对象或资源对象数组。每个资源对象包含以下属性：
     *

     *
id - 资源的唯一标识符。可用于从下载队列获取目标资源。

     *
src - 资源的地址url。

     *
type - 指定资源的类型。默认会根据资源文件的后缀来自动判断类型，不同的资源类型会使用不同的加载器来加载资源。

     *
loader - 指定资源的加载器。默认会根据资源类型来自动选择加载器，若指定loader，则会使用指定的loader来加载资源。

     *
noCache - 指示加载资源时是否增加时间标签以防止缓存。

     *
size - 资源对象的预计大小。可用于预估下载进度。

     *
crossOrigin - 是否需要跨域，默认否。

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    add: function(source){
        var me = this;
        if(source){
            source = source instanceof Array ? source : [source];
            me._source = me._source.concat(source);
        }
        return me;
    },

    /**
     * @language=en
     * get resource object by id or src
     * @param {String}  specified id or src
     * @returns {Object} resource object
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源对象。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源对象。
     */
    get: function(id){
        if(id){
            var source = this._source;
            for(var i = 0; i < source.length; i++){
                var item = source[i];
                if(item.id === id || item.src === id){
                    return item;
                }
            }
        }
        return null;
    },

    /**
     * @language=en
     * get resource object content  by id or src
     * @param {String} specified id or src
     * @returns {Object} resource object content
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源内容。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源内容。
     */
    getContent: function(id){
        var item = this.get(id);
        return item && item.content;
    },
    /**
     * @language=en
     * remove resource object content  by id or src
     * @param {String} specified id or src
     */
    /**
     * @language=zh
     * 根据id或src地址删除资源内容。
     * @param {String} id 指定资源的id或src。
     */
    removeContent: function(id){
        if(id){
            var source = this._source;
            for(var i = 0; i < source.length; i++){
                var item = source[i];
                if(item.id === id || item.src === id){
                    source.splice(i, 1);
                    return;
                }
            }
        }
    },

    /**
     * @language=en
     * start loading
     * @returns {LoadQueue} the loading instance
     */
    /**
     * @language=zh
     * 开始下载队列。
     * @returns {LoadQueue} 下载队列实例本身。
     */
    start: function(){
        var me = this;
        me._loadNext();
        return me;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _loadNext: function(){
        var me = this, source = me._source, len = source.length;

        //all items loaded
        if(me._loaded >= len){
            me.fire('complete');
            return;
        }

        if(me._currentIndex < len - 1 && me._connections < me.maxConnections){
            var index = ++me._currentIndex;
            var item = source[index];
            var loader = me._getLoader(item);

            if(loader){
                var onLoad = loader.onLoad, onError = loader.onError;

                loader.onLoad = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    var content = onLoad && onLoad.call(loader, e) || e.target;
                    me._onItemLoad(index, content);
                };
                loader.onError = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    onError && onError.call(loader, e);
                    me._onItemError(index, e);
                };
                me._connections++;
            }

            me._loadNext();
            loader && loader.load(item);
        }
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _getLoader: function(item){
        var loader = item.loader;
        if(loader) return loader;

        var type = item.type || getExtension(item.src);

        switch(type){
            case 'png':
            case 'jpg':
            case 'jpeg':
            case 'gif':
            case 'webp':
                loader = new ImageLoader();
                break;
            case 'js':
            case 'jsonp':
                loader = new ScriptLoader();
                break;
        }

        return loader;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemLoad: function(index, content){
        var me = this, item = me._source[index];
        item.loaded = true;
        item.content = content;
        me._connections--;
        me._loaded++;
        me.fire('load', item);
        me._loadNext();
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemError: function(index, e){
        var me = this, item = me._source[index];
        item.error = e;
        me._connections--;
        me._loaded++;
        me.fire('error', item);
        me._loadNext();
    },

    /**
     * @language=en
     *  get resource size, loaded or all.
     * @param {Boolean} identify loaded or all resource. default is false, return all resource size. when set true, return loaded resource size.
     * @returns {Number} resource size.
     */
    /**
     * @language=zh
     * 获取全部或已下载的资源的字节大小。
     * @param {Boolean} loaded 指示是已下载的资源还是全部资源。默认为全部。
     * @returns {Number} 指定资源的字节大小。
     */
    getSize: function(loaded){
        var size = 0, source = this._source;
        for(var i = 0; i < source.length; i++){
            var item = source[i];
            size += (loaded ? item.loaded && item.size : item.size) || 0;
        }
        return size;
    },

    /**
     * @language=en
     * get loaded resource count
     * @returns {Uint} loaded resource count
     */
    /**
     * @language=zh
     * 获取已下载的资源数量。
     * @returns {Uint} 已下载的资源数量。
     */
    getLoaded: function(){
        return this._loaded;
    },

    /**
     * @language=en
     * get all resource count
     * @returns {Uint} all resource count
     */
    /**
     * @language=zh
     * 获取所有资源的数量。
     * @returns {Uint} 所有资源的数量。
     */
    getTotal: function(){
        return this._source.length;
    }

});

/**
 * @language=en
 * @private
 */
/**
 * @language=zh
 * @private
 */
function getExtension(src){
    var extRegExp = /\/?[^/]+\.(\w+)(\?\S+)?$/i, match, extension;
    if(match = src.match(extRegExp)){
        extension = match[1].toLowerCase();
    }
    return extension || null;
}<commit_msg>fix: get extension regexp pattern (#174)<commit_after>/**
 * Hilo
 * Copyright 2015 alibaba.com
 * Licensed under the MIT License
 */

//TODO: 超时timeout，失败重连次数maxTries，更多的下载器Loader，队列暂停恢复等。

/**
 * @language=en
 * @class LoadQueue is a queue-like loader.
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source resource that need to be loaded,could be a single object or array resource.
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections the limited concurrent connections. default value  2.
 */
/**
 * @language=zh
 * @class LoadQueue是一个队列下载工具。
 * @mixes EventMixin
 * @borrows EventMixin#on as #on
 * @borrows EventMixin#off as #off
 * @borrows EventMixin#fire as #fire
 * @param {Object} source 要下载的资源。可以是单个资源对象或多个资源的数组。
 * @module hilo/loader/LoadQueue
 * @requires hilo/core/Class
 * @requires hilo/event/EventMixin
 * @requires hilo/loader/ImageLoader
 * @requires hilo/loader/ScriptLoader
 * @property {Int} maxConnections 同时下载的最大连接数。默认为2。
 */
var LoadQueue = Class.create(/** @lends LoadQueue.prototype */{
    Mixes: EventMixin,
    constructor: function(source){
        this._source = [];
        this.add(source);
    },

    maxConnections: 2, //TODO: 应该是每个host的最大连接数。

    _source: null,
    _loaded: 0,
    _connections: 0,
    _currentIndex: -1,

    /**
     * @language=en
     * Add desired resource,could be a single object or array resource.
     * @param {Object|Array} source ,a single object or array resource. Each resource contains properties like below:
     *

     *
id - resource identifier

     *
src - resource url

     *
type - resource type. By default, we automatically identify resource by file suffix and choose the relevant loader for you

     *
loader - specified resource loader. If you specify this,we abandon choosing loader inside

     *
noCache - a tag that set on or off to prevent cache,implemented by adding timestamp inside

     *
size - predicted resource size, help calculating loading progress

     *
crossOrigin - Whether cross-domain is needed, default is false

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    /**
     * @language=zh
     * 增加要下载的资源。可以是单个资源对象或多个资源的数组。
     * @param {Object|Array} source 资源对象或资源对象数组。每个资源对象包含以下属性：
     *

     *
id - 资源的唯一标识符。可用于从下载队列获取目标资源。

     *
src - 资源的地址url。

     *
type - 指定资源的类型。默认会根据资源文件的后缀来自动判断类型，不同的资源类型会使用不同的加载器来加载资源。

     *
loader - 指定资源的加载器。默认会根据资源类型来自动选择加载器，若指定loader，则会使用指定的loader来加载资源。

     *
noCache - 指示加载资源时是否增加时间标签以防止缓存。

     *
size - 资源对象的预计大小。可用于预估下载进度。

     *
crossOrigin - 是否需要跨域，默认否。

     *

     * @returns {LoadQueue} 下载队列实例本身。
     */
    add: function(source){
        var me = this;
        if(source){
            source = source instanceof Array ? source : [source];
            me._source = me._source.concat(source);
        }
        return me;
    },

    /**
     * @language=en
     * get resource object by id or src
     * @param {String}  specified id or src
     * @returns {Object} resource object
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源对象。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源对象。
     */
    get: function(id){
        if(id){
            var source = this._source;
            for(var i = 0; i < source.length; i++){
                var item = source[i];
                if(item.id === id || item.src === id){
                    return item;
                }
            }
        }
        return null;
    },

    /**
     * @language=en
     * get resource object content  by id or src
     * @param {String} specified id or src
     * @returns {Object} resource object content
     */
    /**
     * @language=zh
     * 根据id或src地址获取资源内容。
     * @param {String} id 指定资源的id或src。
     * @returns {Object} 资源内容。
     */
    getContent: function(id){
        var item = this.get(id);
        return item && item.content;
    },
    /**
     * @language=en
     * remove resource object content  by id or src
     * @param {String} specified id or src
     */
    /**
     * @language=zh
     * 根据id或src地址删除资源内容。
     * @param {String} id 指定资源的id或src。
     */
    removeContent: function(id){
        if(id){
            var source = this._source;
            for(var i = 0; i < source.length; i++){
                var item = source[i];
                if(item.id === id || item.src === id){
                    source.splice(i, 1);
                    return;
                }
            }
        }
    },

    /**
     * @language=en
     * start loading
     * @returns {LoadQueue} the loading instance
     */
    /**
     * @language=zh
     * 开始下载队列。
     * @returns {LoadQueue} 下载队列实例本身。
     */
    start: function(){
        var me = this;
        me._loadNext();
        return me;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _loadNext: function(){
        var me = this, source = me._source, len = source.length;

        //all items loaded
        if(me._loaded >= len){
            me.fire('complete');
            return;
        }

        if(me._currentIndex < len - 1 && me._connections < me.maxConnections){
            var index = ++me._currentIndex;
            var item = source[index];
            var loader = me._getLoader(item);

            if(loader){
                var onLoad = loader.onLoad, onError = loader.onError;

                loader.onLoad = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    var content = onLoad && onLoad.call(loader, e) || e.target;
                    me._onItemLoad(index, content);
                };
                loader.onError = function(e){
                    loader.onLoad = onLoad;
                    loader.onError = onError;
                    onError && onError.call(loader, e);
                    me._onItemError(index, e);
                };
                me._connections++;
            }

            me._loadNext();
            loader && loader.load(item);
        }
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _getLoader: function(item){
        var loader = item.loader;
        if(loader) return loader;

        var type = item.type || getExtension(item.src);

        switch(type){
            case 'png':
            case 'jpg':
            case 'jpeg':
            case 'gif':
            case 'webp':
                loader = new ImageLoader();
                break;
            case 'js':
            case 'jsonp':
                loader = new ScriptLoader();
                break;
        }

        return loader;
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemLoad: function(index, content){
        var me = this, item = me._source[index];
        item.loaded = true;
        item.content = content;
        me._connections--;
        me._loaded++;
        me.fire('load', item);
        me._loadNext();
    },

    /**
     * @language=en
     * @private
     */
    /**
     * @language=zh
     * @private
     */
    _onItemError: function(index, e){
        var me = this, item = me._source[index];
        item.error = e;
        me._connections--;
        me._loaded++;
        me.fire('error', item);
        me._loadNext();
    },

    /**
     * @language=en
     *  get resource size, loaded or all.
     * @param {Boolean} identify loaded or all resource. default is false, return all resource size. when set true, return loaded resource size.
     * @returns {Number} resource size.
     */
    /**
     * @language=zh
     * 获取全部或已下载的资源的字节大小。
     * @param {Boolean} loaded 指示是已下载的资源还是全部资源。默认为全部。
     * @returns {Number} 指定资源的字节大小。
     */
    getSize: function(loaded){
        var size = 0, source = this._source;
        for(var i = 0; i < source.length; i++){
            var item = source[i];
            size += (loaded ? item.loaded && item.size : item.size) || 0;
        }
        return size;
    },

    /**
     * @language=en
     * get loaded resource count
     * @returns {Uint} loaded resource count
     */
    /**
     * @language=zh
     * 获取已下载的资源数量。
     * @returns {Uint} 已下载的资源数量。
     */
    getLoaded: function(){
        return this._loaded;
    },

    /**
     * @language=en
     * get all resource count
     * @returns {Uint} all resource count
     */
    /**
     * @language=zh
     * 获取所有资源的数量。
     * @returns {Uint} 所有资源的数量。
     */
    getTotal: function(){
        return this._source.length;
    }

});

/**
 * @language=en
 * @private
 */
/**
 * @language=zh
 * @private
 */
function getExtension(src){
    var extRegExp = /\/?[^/]+?\.(\w+)\??(\?\S+)?$/i, match, extension;
    if(match = src.match(extRegExp)){
        extension = match[1].toLowerCase();
    }
    return extension || null;
}
<|endoftext|>


<commit_before>ReadiumSDK.Plugins.loadPlugin("annotations", function (api, plugin) {
    var _annotationsManager, _annotationsApi, _initialized = false, _initializedLate = false;

    _annotationsApi = function() {
        var self = this;
        _.extend(self, Backbone.Events);

        function isInitialized() {
            if (!_initialized) {
                plugin.warn('Not initialized!')
            }
            return _initialized;
        }

        this.initialize = function(options){
            if (_initialized) {
                plugin.warn('Already initialized!');
                return;
            }

            _annotationsManager = new ReadiumSDK.Views.AnnotationsManager(self, options);

            if (_initializedLate) {
                plugin.warn('Unable to attach to currently loaded content document.\n' +
                    'Initialize the plugin before loading a content document.');
            }

            _initialized = true;
        };

        /**
         * Returns current selection partial Cfi, useful for workflows that need to check whether the user has selected something.
         *
         * @method getCurrentSelectionCfi
         * @returns {object | undefined} partial cfi object or undefined if nothing is selected
         *
         */
        this.getCurrentSelectionCfi =  function() {
            if (!isInitialized()) { return }

            return _annotationsManager.getCurrentSelectionCfi();
        };

        /**
         * Creates a higlight based on given parameters
         *
         * @method addHighlight
         * @param {string} spineIdRef spine idref that defines the partial Cfi
         * @param {string} CFI partial CFI (withouth the indirection step) relative to the spine index
         * @param {string} id id of the highlight. must be unique
         * @param {string} type currently "highlight" only
         *
         * @returns {object | undefined} partial cfi object of the created highlight
         *
         */
        this.addHighlight = function(spineIdRef, Cfi, id, type, styles) {
            if (!isInitialized()) { return }

            return _annotationsManager.addHighlight(spineIdRef, Cfi, id, type, styles) ;
        };

        /**
         * Creates a higlight based on current selection
         *
         * @method addSelectionHighlight
         * @param {string} id id of the highlight. must be unique
         * @param {string} type currently "highlight" only
         *
         * @returns {object | undefined} partial cfi object of the created highlight
         *
         */
        this.addSelectionHighlight =  function(id, type) {
            if (!isInitialized()) { return }

            return _annotationsManager.addSelectionHighlight(id,type);
        };

        /**
         * Removes given highlight
         *
         * @method removeHighlight
         * @param {string} id id of the highlight.
         *
         * @returns {undefined}
         *
         */
        this.removeHighlight = function(id) {
            if (!isInitialized()) { return }

            return _annotationsManager.removeHighlight(id);
        };

    };

    api.reader.on(ReadiumSDK.Events.CONTENT_DOCUMENT_LOADED, function ($iframe, spineItem) {
        if (_initialized) {
            _annotationsManager.attachAnnotations($iframe, spineItem);
        } else {
            _initializedLate = true;
        }
    });

    // Extend the Reader API with the Annotations API under its own namespace
    api.extendReader(new _annotationsApi());
});<commit_msg>Update annotations_plugin.js<commit_after>ReadiumSDK.Plugins.loadPlugin("annotations", function (api) {
    var _annotationsManager, _annotationsApi, _initialized = false, _initializedLate = false;

    _annotationsApi = function() {
        var self = this;
        _.extend(self, Backbone.Events);

        function isInitialized() {
            if (!_initialized) {
                api.plugin.warn('Not initialized!')
            }
            return _initialized;
        }

        this.initialize = function(options){
            if (_initialized) {
                api.plugin.warn('Already initialized!');
                return;
            }

            _annotationsManager = new ReadiumSDK.Views.AnnotationsManager(self, options);

            if (_initializedLate) {
                api.plugin.warn('Unable to attach to currently loaded content document.\n' +
                    'Initialize the plugin before loading a content document.');
            }

            _initialized = true;
        };

        /**
         * Returns current selection partial Cfi, useful for workflows that need to check whether the user has selected something.
         *
         * @method getCurrentSelectionCfi
         * @returns {object | undefined} partial cfi object or undefined if nothing is selected
         *
         */
        this.getCurrentSelectionCfi =  function() {
            if (!isInitialized()) { return }

            return _annotationsManager.getCurrentSelectionCfi();
        };

        /**
         * Creates a higlight based on given parameters
         *
         * @method addHighlight
         * @param {string} spineIdRef spine idref that defines the partial Cfi
         * @param {string} CFI partial CFI (withouth the indirection step) relative to the spine index
         * @param {string} id id of the highlight. must be unique
         * @param {string} type currently "highlight" only
         *
         * @returns {object | undefined} partial cfi object of the created highlight
         *
         */
        this.addHighlight = function(spineIdRef, Cfi, id, type, styles) {
            if (!isInitialized()) { return }

            return _annotationsManager.addHighlight(spineIdRef, Cfi, id, type, styles) ;
        };

        /**
         * Creates a higlight based on current selection
         *
         * @method addSelectionHighlight
         * @param {string} id id of the highlight. must be unique
         * @param {string} type currently "highlight" only
         *
         * @returns {object | undefined} partial cfi object of the created highlight
         *
         */
        this.addSelectionHighlight =  function(id, type) {
            if (!isInitialized()) { return }

            return _annotationsManager.addSelectionHighlight(id,type);
        };

        /**
         * Removes given highlight
         *
         * @method removeHighlight
         * @param {string} id id of the highlight.
         *
         * @returns {undefined}
         *
         */
        this.removeHighlight = function(id) {
            if (!isInitialized()) { return }

            return _annotationsManager.removeHighlight(id);
        };

    };

    api.reader.on(ReadiumSDK.Events.CONTENT_DOCUMENT_LOADED, function ($iframe, spineItem) {
        if (_initialized) {
            _annotationsManager.attachAnnotations($iframe, spineItem);
        } else {
            _initializedLate = true;
        }
    });

    // Extend the Reader API with the Annotations API under its own namespace
    api.extendReader(new _annotationsApi());
});
<|endoftext|>


<commit_before>'use strict';

var app = app || {};

(function (module){

  const genView= {};

  genView.init = function (){
  $('.survey').hide();
  $('.generator').show();
  genView.populateSlots();
  };

  //  This function will repopulate slots when user clicks re-roll button
  $("#re-roll").click(function(){
    app.genView.populateSlots()
  });

  // append our app.words.slotArray to the DOM
  genView.appendWords = function () {
    app.words.slotArray.forEach( function ( arrayEle, currentIndex, array) {
      let idName = '#slot' + (currentIndex+1);
      let concatType = 'snakeCase';

      //If data-saved isn't true, append to DOM
      if ( $(idName).attr('data-saved') !== 'true' ) {
        switch (concatType) {
          case 'camelCase':
            if (currentIndex > 0) {
              let newElement = arrayEle.split('');
              newElement[0] = newElement[0].toUpperCase();
              $(idName).text(newElement.join(''));
              break;
            } else {
              $(idName).text(arrayEle);
              break;
            }
          case 'hyphenated':
            if (currentIndex > 0) {
              $(idName).text('-' + arrayEle);
              break;
            } else {
              $(idName).text(arrayEle);
              break;
            }
          case 'snakeCase':
            if (currentIndex > 0) {
              $(idName).text('_' + arrayEle);
              break;
            } else {
              $(idName).text(arrayEle);
              break;
            }
          case 'none':
              $(idName).text(arrayEle);
        }

        // $(idName).text(arrayEle);
      }

      // Update currentHandle with current displayed handle
      app.words.currentHandle = '';
      for (let i = 0; i < $('.slots').children().length; i++){
        if (app.words.currentHandle === ''){
          app.words.currentHandle += $('.slots').children().eq(i).text();
        } else {
          app.words.currentHandle += '-' + $('.slots').children().eq(i).text();
        }

      }

      //Add event listener to toggle "data-saved" status
      $(idName).off('click');
      $(idName).on('click',function(){
        $(idName).attr('data-saved') === 'true' ? $(idName).attr('data-saved', false) : $(idName).attr('data-saved', true);
        console.log(idName,'is clicked. data-saved value is',$(idName).attr('data-saved'))
        })

    });
  }

  // populates our slots.
  genView.populateSlots = function() {
    app.words.randomizeAll()
    genView.appendWords()
  }

module.genView = genView

})(app);<commit_msg>add small changes. branch still unfinished<commit_after>'use strict';

var app = app || {};

(function (module){

  const genView= {};

  genView.init = function (){
  $('.survey').hide();
  $('.generator').show();
  genView.populateSlots();
  };

  //  This function will repopulate slots when user clicks re-roll button
  $("#re-roll").click(function(){
    app.genView.populateSlots()
  });

  // append our app.words.slotArray to the DOM
  genView.appendWords = function () {
    app.words.slotArray.forEach( function ( arrayEle, currentIndex, array) {
      let idName = '#slot' + (currentIndex+1);
      let concatType = 'camelCase';

      //If data-saved isn't true, append to DOM
      if ( $(idName).attr('data-saved') !== 'true' ) {
        switch (concatType) {
          case 'camelCase':
            if (currentIndex > 0) {
              let newElement = arrayEle.split('');
              newElement[0] = newElement[0].toUpperCase();
              $(idName).text(newElement.join(''));
              break;
            } else {
              $(idName).text(arrayEle);
              break;
            }
          case 'hyphenated':
            if (currentIndex > 0) {
              $(idName).text('-' + arrayEle);
              break;
            } else {
              $(idName).text(arrayEle);
              break;
            }
          case 'snakeCase':
            if (currentIndex > 0) {
              $(idName).text('_' + arrayEle);
              break;
            } else {
              $(idName).text(arrayEle);
              break;
            }
          case 'none':
              $(idName).text(arrayEle);
        }

      }

      // Update currentHandle with current displayed handle
      app.words.currentHandle = '';
      for (let i = 0; i < $('.slots').children().length; i++){
          app.words.currentHandle += $('.slots').children().eq(i).text();
      }

      //Add event listener to toggle "data-saved" status
      $(idName).off('click');
      $(idName).on('click',function(){
        $(idName).attr('data-saved') === 'true' ? $(idName).attr('data-saved', false) : $(idName).attr('data-saved', true);
        console.log(idName,'is clicked. data-saved value is',$(idName).attr('data-saved'))
        })

    });
  }

  // populates our slots.
  genView.populateSlots = function() {
    app.words.randomizeAll()
    genView.appendWords()
  }

module.genView = genView

})(app);<|endoftext|>


<commit_before>/**
 * Created by apizzimenti on 1/2/17.
 */

/**
 * @module tools
 */

var paramExist = require("./Globals").paramExist,
    Error = require("./Error").Error;

/**
 * @author Anthony Pizzimenti
 *
 * @desc Maps the argstring's properties based on the config object's options.
 *
 * @param args {object} An argstring.
 * @param config {object} Specified desired property names and their possible parameters in the argstring.
 *
 * @constructor
 *
 * @property args {object} An argstring.
 * @property config {object} Specified desired property names and their possible parameters in the argstring.
 *
 * @class Args
 */

function Args (args, config) {

    if (paramExist(args, "object")) {
        this.args = args;
    } else {
        this.args = {};
    }

    if (paramExist(config, "object")) {
        this.config = config;
    } else {
        this.config = {};
    }

    this._configure();
}

/**
 * @author Anthony Pizzimenti
 *
 * @desc For each argument and argument list in the property config, see if any exist in the argstring; if so, create a
 * new property with the desired name in the flattened object, and break.
 *
 * @property flattened {object} Properties from the argstring mapped to the provided property names in the config.
 *
 * @this Args
 *
 * @private
 */

Args.prototype._configure = function () {

    var name;

    this.flattened = {};

    // for each argument in the config object,
    for (var arg in this.config) {

        if (this.config.hasOwnProperty(arg)) {

            // take its list of properties,
            for (var i = 0; i < this.config[arg].length; i++) {

                name = this.config[arg][i];

                // and if any of them exist on the argstring, apply that property to flatten, but hash it with the
                // desired property name from the config object.

                if (this.args[name]) {
                    this.flattened[arg] = Object.keys(this.args[name]).length == 0 ? null : this.args[name];
                    break;
                }
            }
        }
    }
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Return the desired property value if it exists; otherwise return null.
 *
 * @param arg {string} The property to search for.
 *
 * @this Args
 *
 * @returns {object | null}
 */

Args.prototype.get = function (arg) {

    var msg = "No argument supplied.",
        e = new Error(msg);

    if (paramExist(arg, "string")) {
        return this.flattened[arg] ? this.flattened[arg] : null;
    } else {
        e.throw();
    }
};

module.exports = {
    Args: Args
};
<commit_msg>revert<commit_after>/**
 * Created by apizzimenti on 1/2/17.
 */

/**
 * @module tools
 */

var paramExist = require("./Globals").paramExist,
    Error = require("./Error").Error;

/**
 * @author Anthony Pizzimenti
 *
 * @desc Maps the argstring's properties based on the config object's options.
 *
 * @param args {object} An argstring.
 * @param config {object} Specified desired property names and their possible parameters in the argstring.
 *
 * @constructor
 *
 * @property args {object} An argstring.
 * @property config {object} Specified desired property names and their possible parameters in the argstring.
 *
 * @class Args
 */

function Args (args, config) {

    if (paramExist(args, "object")) {
        this.args = args;
    } else {
        this.args = {};
    }

    if (paramExist(config, "object")) {
        this.config = config;
    } else {
        this.config = {};
    }

    this._configure();
}

/**
 * @author Anthony Pizzimenti
 *
 * @desc For each argument and argument list in the property config, see if any exist in the argstring; if so, create a
 * new property with the desired name in the flattened object, and break.
 *
 * @property flattened {object} Properties from the argstring mapped to the provided property names in the config.
 *
 * @this Args
 *
 * @private
 */

Args.prototype._configure = function () {

    var name;

    this.flattened = {};

    // for each argument in the config object,
    for (var arg in this.config) {

        if (this.config.hasOwnProperty(arg)) {

            // take its list of properties,
            for (var i = 0; i < this.config[arg].length; i++) {

                name = this.config[arg][i];

                // and if any of them exist on the argstring, apply that property to flatten, but hash it with the
                // desired property name from the config object.

                if (this.args[name]) {
                    this.flattened[arg] = this.args[name];
                    break;
                }
            }
        }
    }
};

/**
 * @author Anthony Pizzimenti
 *
 * @desc Return the desired property value if it exists; otherwise return null.
 *
 * @param arg {string} The property to search for.
 *
 * @this Args
 *
 * @returns {object | null}
 */

Args.prototype.get = function (arg) {

    var msg = "No argument supplied.",
        e = new Error(msg);

    if (paramExist(arg, "string")) {
        return this.flattened[arg] ? this.flattened[arg] : null;
    } else {
        e.throw();
    }
};

module.exports = {
    Args: Args
};
<|endoftext|>


<commit_before>/*
 * inline-images
 * @version 1.0
 * @author Manuel Alabor (manuel@alabor.me)
 *
 * If a user posts a URL to an image, that image gets rendered directly
 * inside of Candy.
 */

var CandyShop = (function(self) { return self; }(CandyShop || {}));

CandyShop.InlineImages = (function(self, Candy, $) {

	var _fileExtensions = ['png','jpg','jpeg','gif']
		,_originalLinkify = Candy.Util.Parser.linkify
		,_maxImageSize = 100;

	/** Function: init
	 * Initializes the inline-images plugin with the default settings.
	 */
	self.init = function() {
		Candy.View.Event.Message.beforeShow = handleBeforeShow;
		Candy.View.Event.Message.onShow = handleOnShow;
		Candy.Util.Parser.linkify = linkify;
	};

	/** Function: initWithFileExtensions
	 * Initializes the inline-images plugin with the possibility to pass an
	 * array with all the file extensions you want to display as image.
	 *
	 * Parameters:
	 *   (String array) fileExtensions - Array with extensions (jpg, png, ...)
	 */
	self.initWithFileExtensions = function(fileExtensions) {
		_fileExtensions = fileExtensions;
		init();
	};

	/** Function: initWithMaxImageSize
	 * Initializes the inline-images plugin with the possibility to pass the
	 * maximum image size for displayed images.
	 *
	 * Parameters:
	 *   (int) maxImageSize - Maximum edge size for images
	 */
	self.initWithMaxImageSize = function(maxImageSize) {
		_maxImageSize = maxImageSize;
		init();
	};

	/** Function: initWithFileExtensionsAndMaxImageSize
	 * Initializes the inline-images plugin with the possibility to pass an
	 * array with all the file extensions you want to display as image and
	 * the maximum image size for displayed images.
	 *
	 * Parameters:
	 *   (String array) fileExtensions - Array with extensions (jpg, png, ...)
	 *   (int) maxImageSize - Maximum edge size for images
	 */
	self.initWithFileExtensionsAndMaxImageSize = function(fileExtensions, maxImageSize) {
		_fileExtensions = fileExtensions;
		_maxImageSize = maxImageSize;
		init();
	};

	/** Function: handleBeforeShow
	 * Handles the beforeShow event of a message.
	 *
	 * Paramteres:
	 *   (String) message - the message to process
	 *
	 * Returns:
	 *   (String)
	 */
	var handleBeforeShow = function(message) {
		var processed = message.replace(/(^|[^\/])(www\.[^\.]+\.[\S]+(\b|$))/gi, '$1http://$2');
		processed = processed.replace(/\b(https?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, replaceCallback);

		return processed;
	};

	/** Function: handleOnShow
	 * Each time a message gets displayed, this method checks for possible
	 * image loaders (created by buildImageLoaderSource).
	 * If there is one, the image "behind" the loader gets loaded in the
	 * background. As soon as the image is loaded, the image loader gets
	 * replaced by proper scaled image.
	 *
	 * Parameters:
	 *   (Array) args
	 */
	var handleOnShow = function(args) {
		$('.inlineimages-loader').each(function(index, element) {
			$(element).removeClass('inlineimages-loader');
			var url = $(element).attr('longdesc');
			var imageLoader = new Image();

			$(imageLoader).load(function() {
				var origWidth = this.width;
				var origHeight = this.height;
				var ratio = Math.min(_maxImageSize / origWidth, _maxImageSize / origHeight);
				var width = Math.round(ratio * origWidth);
				var height = Math.round(ratio * origHeight);

				$(element).replaceWith(buildImageSource(url, width, height))
			});

			imageLoader.src = url;
		});
	}

	/** Function: linkify
	 * Is used to overwrite the original Candy.Util.Parser.linkify.
	 * This implementation prevents the parsing of URL's by the Candy core.
	 * inline-images handles this on itself by handleBeforeShow.
	 *
	 * Parameters:
	 *   (String) text - text to process
	 *
	 * Returns:
	 *   (String)
	 */
	var linkify = function(text) {
		return text;
	}

	/** Function: replaceCallback
	 * This callback handles matches from the URL regex.
	 * If the callback detects an image URL, it returns an image with a loading
	 * indicator. If it is just a common URL, a link-tag gets returned.
	 *
	 * Paramters:
	 *   (String) match - matched URL
	 *
	 * Returns:
	 *   (String)
	 */
	var replaceCallback = function(match) {
		var result = match;

		var dotPosition = match.lastIndexOf(".");
		if(dotPosition > -1) {
			if(_fileExtensions.indexOf(match.substr(dotPosition+1)) != -1) {
				result = buildImageLoaderSource(match);
			} else {
				result = buildLinkSource(match);
			}
		}

		return result;
	}

	/** Function: buildImageLoaderSource
	 * Returns a loader indicator. The handleOnShow method fullfills afterwards
	 * the effective image loading.
	 *
	 * Parameters:
	 *   (String) url - image url
	 *
	 * Returns:
	 *   (String)
	 */
	var buildImageLoaderSource = function(url) {
		return ''
	}

	/** Function: buildImageSource
	 * Returns HTML source to show a URL as an image.
	 *
	 * Parameters:
	 *   (String) url - image url
	 *
	 * Returns:
	 *   (String)
	 */
	var buildImageSource = function(url, width, height) {
		return '';
	}

	/** Function: buildLinkSource
	 * Returns HTML source to show a URL as a link.
	 *
	 * Parameters:
	 *   (String) url - url
	 *
	 * Returns:
	 *   (String)
	 */
	var buildLinkSource = function(url) {
		return '' + url + '';
	}

	return self;
}(CandyShop.InlineImages || {}, Candy, jQuery));
<commit_msg>Update inline-images/candy.js<commit_after>/*
 * inline-images
 * @version 1.0
 * @author Manuel Alabor (manuel@alabor.me)
 *
 * If a user posts a URL to an image, that image gets rendered directly
 * inside of Candy.
 */

var CandyShop = (function(self) { return self; }(CandyShop || {}));

CandyShop.InlineImages = (function(self, Candy, $) {

	var _fileExtensions = ['png','jpg','jpeg','gif']
		,_originalLinkify = Candy.Util.Parser.linkify
		,_maxImageSize = 100;

	/** Function: init
	 * Initializes the inline-images plugin with the default settings.
	 */
	self.init = function() {
		Candy.View.Event.Message.beforeShow = handleBeforeShow;
		Candy.View.Event.Message.onShow = handleOnShow;
		Candy.Util.Parser.linkify = linkify;
	};

	/** Function: initWithFileExtensions
	 * Initializes the inline-images plugin with the possibility to pass an
	 * array with all the file extensions you want to display as image.
	 *
	 * Parameters:
	 *   (String array) fileExtensions - Array with extensions (jpg, png, ...)
	 */
	self.initWithFileExtensions = function(fileExtensions) {
		_fileExtensions = fileExtensions;
		init();
	};

	/** Function: initWithMaxImageSize
	 * Initializes the inline-images plugin with the possibility to pass the
	 * maximum image size for displayed images.
	 *
	 * Parameters:
	 *   (int) maxImageSize - Maximum edge size for images
	 */
	self.initWithMaxImageSize = function(maxImageSize) {
		_maxImageSize = maxImageSize;
		init();
	};

	/** Function: initWithFileExtensionsAndMaxImageSize
	 * Initializes the inline-images plugin with the possibility to pass an
	 * array with all the file extensions you want to display as image and
	 * the maximum image size for displayed images.
	 *
	 * Parameters:
	 *   (String array) fileExtensions - Array with extensions (jpg, png, ...)
	 *   (int) maxImageSize - Maximum edge size for images
	 */
	self.initWithFileExtensionsAndMaxImageSize = function(fileExtensions, maxImageSize) {
		_fileExtensions = fileExtensions;
		_maxImageSize = maxImageSize;
		init();
	};

	/** Function: handleBeforeShow
         * Handles the beforeShow event of a message.
         *
         * Paramteres:
         *   (Object) args - {roomJid, element, nick, message}
         *
         * Returns:
         *   (String)
         */
        var handleBeforeShow = function(args) {
                var message = args.message;
                var processed = message.replace(/\|[^\|]+\|/, "");
                processed = processed.replace(/(^|[^\/])(www\.[^\.]+\.[\S]+(\b|$))/gi, '$1http://$2');
                processed = processed.replace(/\b(https?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, replaceCallback);
                return processed;
        };

	/** Function: handleOnShow
	 * Each time a message gets displayed, this method checks for possible
	 * image loaders (created by buildImageLoaderSource).
	 * If there is one, the image "behind" the loader gets loaded in the
	 * background. As soon as the image is loaded, the image loader gets
	 * replaced by proper scaled image.
	 *
	 * Parameters:
	 *   (Array) args
	 */
	var handleOnShow = function(args) {
		$('.inlineimages-loader').each(function(index, element) {
			$(element).removeClass('inlineimages-loader');
			var url = $(element).attr('longdesc');
			var imageLoader = new Image();

			$(imageLoader).load(function() {
				var origWidth = this.width;
				var origHeight = this.height;
				var ratio = Math.min(_maxImageSize / origWidth, _maxImageSize / origHeight);
				var width = Math.round(ratio * origWidth);
				var height = Math.round(ratio * origHeight);

				$(element).replaceWith(buildImageSource(url, width, height))
			});

			imageLoader.src = url;
		});
	}

	/** Function: linkify
	 * Is used to overwrite the original Candy.Util.Parser.linkify.
	 * This implementation prevents the parsing of URL's by the Candy core.
	 * inline-images handles this on itself by handleBeforeShow.
	 *
	 * Parameters:
	 *   (String) text - text to process
	 *
	 * Returns:
	 *   (String)
	 */
	var linkify = function(text) {
		return text;
	}

	/** Function: replaceCallback
	 * This callback handles matches from the URL regex.
	 * If the callback detects an image URL, it returns an image with a loading
	 * indicator. If it is just a common URL, a link-tag gets returned.
	 *
	 * Paramters:
	 *   (String) match - matched URL
	 *
	 * Returns:
	 *   (String)
	 */
	var replaceCallback = function(match) {
		var result = match;

		var dotPosition = match.lastIndexOf(".");
		if(dotPosition > -1) {
			if(_fileExtensions.indexOf(match.substr(dotPosition+1)) != -1) {
				result = buildImageLoaderSource(match);
			} else {
				result = buildLinkSource(match);
			}
		}

		return result;
	}

	/** Function: buildImageLoaderSource
	 * Returns a loader indicator. The handleOnShow method fullfills afterwards
	 * the effective image loading.
	 *
	 * Parameters:
	 *   (String) url - image url
	 *
	 * Returns:
	 *   (String)
	 */
	var buildImageLoaderSource = function(url) {
		return ''
	}

	/** Function: buildImageSource
	 * Returns HTML source to show a URL as an image.
	 *
	 * Parameters:
	 *   (String) url - image url
	 *
	 * Returns:
	 *   (String)
	 */
	var buildImageSource = function(url, width, height) {
		return '';
	}

	/** Function: buildLinkSource
	 * Returns HTML source to show a URL as a link.
	 *
	 * Parameters:
	 *   (String) url - url
	 *
	 * Returns:
	 *   (String)
	 */
	var buildLinkSource = function(url) {
		return '' + url + '';
	}

	return self;
}(CandyShop.InlineImages || {}, Candy, jQuery));
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var MergeXHRSettings = require('./MergeXHRSettings');

/**
 * Creates a new XMLHttpRequest (xhr) object based on the given File and XHRSettings
 * and starts the download of it. It uses the Files own XHRSettings and merges them
 * with the global XHRSettings object to set the xhr values before download.
 *
 * @function Phaser.Loader.XHRLoader
 * @since 3.0.0
 *
 * @param {Phaser.Loader.File} file - The File to download.
 * @param {Phaser.Types.Loader.XHRSettingsObject} globalXHRSettings - The global XHRSettings object.
 *
 * @return {XMLHttpRequest} The XHR object.
 */
var XHRLoader = function (file, globalXHRSettings)
{
    var config = MergeXHRSettings(globalXHRSettings, file.xhrSettings);

    var xhr = new XMLHttpRequest();

    xhr.open('GET', file.src, config.async, config.user, config.password);

    xhr.responseType = file.xhrSettings.responseType;
    xhr.timeout = config.timeout;

    if (config.header && config.headerValue)
    {
        xhr.setRequestHeader(config.header, config.headerValue);
    }

    if (config.requestedWith)
    {
        xhr.setRequestHeader('X-Requested-With', config.requestedWith);
    }

    if (config.overrideMimeType)
    {
        xhr.overrideMimeType(config.overrideMimeType);
    }

    // After a successful request, the xhr.response property will contain the requested data as a DOMString, ArrayBuffer, Blob, or Document (depending on what was set for responseType.)

    xhr.onload = file.onLoad.bind(file, xhr);
    xhr.onerror = file.onError.bind(file, xhr);
    xhr.onprogress = file.onProgress.bind(file);

    //  This is the only standard method, the ones above are browser additions (maybe not universal?)
    // xhr.onreadystatechange

    xhr.send();

    return xhr;
};

module.exports = XHRLoader;
<commit_msg>`XHRLoader` will now use the `XHRSettings.withCredentials` as set in the file or global loader config.<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var MergeXHRSettings = require('./MergeXHRSettings');

/**
 * Creates a new XMLHttpRequest (xhr) object based on the given File and XHRSettings
 * and starts the download of it. It uses the Files own XHRSettings and merges them
 * with the global XHRSettings object to set the xhr values before download.
 *
 * @function Phaser.Loader.XHRLoader
 * @since 3.0.0
 *
 * @param {Phaser.Loader.File} file - The File to download.
 * @param {Phaser.Types.Loader.XHRSettingsObject} globalXHRSettings - The global XHRSettings object.
 *
 * @return {XMLHttpRequest} The XHR object.
 */
var XHRLoader = function (file, globalXHRSettings)
{
    var config = MergeXHRSettings(globalXHRSettings, file.xhrSettings);

    var xhr = new XMLHttpRequest();

    xhr.open('GET', file.src, config.async, config.user, config.password);

    xhr.responseType = file.xhrSettings.responseType;
    xhr.timeout = config.timeout;

    if (config.header && config.headerValue)
    {
        xhr.setRequestHeader(config.header, config.headerValue);
    }

    if (config.requestedWith)
    {
        xhr.setRequestHeader('X-Requested-With', config.requestedWith);
    }

    if (config.overrideMimeType)
    {
        xhr.overrideMimeType(config.overrideMimeType);
    }

    if (config.withCredentials)
    {
        xhr.withCredentials = true;
    }

    // After a successful request, the xhr.response property will contain the requested data as a DOMString, ArrayBuffer, Blob, or Document (depending on what was set for responseType.)

    xhr.onload = file.onLoad.bind(file, xhr);
    xhr.onerror = file.onError.bind(file, xhr);
    xhr.onprogress = file.onProgress.bind(file);

    //  This is the only standard method, the ones above are browser additions (maybe not universal?)
    // xhr.onreadystatechange

    xhr.send();

    return xhr;
};

module.exports = XHRLoader;
<|endoftext|>


<commit_before>
var key = "";
var challenge = "";
var count = 0;
var isEntered = false;
var cResponse = "";
var vowels = "AEIOU";
var siteNames = ['google', 'facebook', 'youtube', 'baidu', 'yahoo', 'amazon', 'wikipedia', 'twitter', 'google',
                 'taobao', 'live', 'sina', 'linkedin', 'yahoo', 'weibo', 'ebay', 'google', 'yandex', 'vk', 'bing',
                 'google', 'msn', 'instagram', 'amazon', 'aliexpress', 'apple', 'blogspot', 'pinterest', 'ask', 'wordpress',
                 'tmall', 'reddit', 'mail', 'paypal', 'onclickads', 'tumblr', 'sohu', 'imgur', 'microsoft', 'imdb', 'gmw',
                 'netflix', 'amazon', 'googleadservices', 'go', 'alibaba', 'stackoverflow', 'craigslist', 'ok', 'tianya',
                 'rakuten', 'amazon', 'blogger', 'naver', 'espn', 'soso', 'cnn', 'outbrain', 'nicovideo', 'kat', 'dropbox',
                 'bbc', 'flipkart', 'github', 'diply', 'googleusercontent', 'adcash', 'xinhuanet',  'popads', 'dailymotion',
                 'pixnet', 'nytimes', 'ebay', 'sogou', 'booking', 'bbc', 'jd', 'dailymail', 'livedoor', 'adobe', 'wikia',
                 'adnetworkperformance', 'chase', 'china', 'indiatimes', 'uol', 'china', 'coccoc', 'huffingtonpost', 'alipay',
                 'directrev', 'buzzfeed', 'dmm', 'youku', 'amazon', 'cntv', 'blogspot', 'google', 'google', 'ameblo', 'google',
                 'amazon', 'microsoftonline', 'theguardian', 'amazonaws', 'bankofamerica', 'google', 'chinadaily', 'walmart',
                 'slideshare', 'cnet', 'etsy', 'daum', 'yelp', 'ettoday', 'globo', 'twitch', 'tudou', 'stackexchange', 'aol',
                 'quora', 'whatsapp', 'indeed', 'flickr', 'weather', 'google', 'tradeadexchange', 'office', 'amazon', 'naver',
                 'redtube', 'soundcloud', 'adf', 'ilividnewtab', 'snapdeal', 'reimageplus', 'bp', 'tubecup', 'forbes', 'wellsfargo',
                 'douban', 'zillow', 'office365', 'google', 'vice', 'gmail', 'leboncoin', 'google', 'godaddy', 'ikea', 'salesforce',
                 'vimeo', 'google', 'kakaku', 'detail', 'target', 'goo', 'about', 'tripadvisor', 'livejournal', 'avito', 'bestbuy',
                 'allegro', 'foxnews', 'wordpress', 'feedly', 'theladbible', 'themeforest', 'adplxmd', 'deviantart', '9gag',
                 'w3schools', 'nfl', 'washingtonpost', 'nih', 'wikihow', 'doublepimp', 'files', 'businessinsider', 'google',
                 'skype', 'gfycat', 'trackingclick', 'taboola', 'telegraph', 'softonic', 'google', 'avg', 'mozilla', 'nametests',
                 'mediafire', 'onet', 'americanexpress', 'pixiv', 'mystart', 'zol', 'ups', 'google', 'people', 'wix', 'amazon',
                 'hclips', 'homedepot', 'archive', 'doorblog', 'huanqiu', 'weebly', 'google', 'secureserver', 'usps', 'google',
                 'comcast', 'akamaihd', 'force', 'steamcommunity', 'wikimedia', 'bitauto', 'zhihu', 'addthis', 'ndtv', 'google',
                 'google', 'ebay-kleinanzeigen', 'mercadolivre', 'shutterstock', 'gamer', 'loading-delivery2', 'terrapops', 'xywy',
                 'detik', 'ifeng', 'web', 'bilibili', 'google', 'popcash', 'github', 'bild', 'usatoday', 'mailchimp', 'steampowered',
                 'sourceforge', 'orange', 'answers', 'hdfcbank', 'uptodown', 'fbcdn', 'gmx', 'xfinity', 'speedtest', 'dmm', 'varzesh3',
                 'google', 'webmd', 'wordreference', 'pconline', 'google', 'att', 'hootsuite', 'rambler', 'groupon', 'stumbleupon',
                 'terraclicks', 'goodreads', 'life', 'spiegel', 'bloomberg', 'wp', 'livejasmin', 'capitalone', 'icicibank', 'blog',
                 'youm7', 'google', 'caijing', 't-online', 'fedex', 'google', 'engadget', 'haiwainet', 'amazon', 'mashable',
                 'thesaurus', 'adidas', 'spotify', 'blogfa', 'nownews', '2ch', 'samsung', 'wsj', 'xuite', 'accuweather', 'watsons',
                 'pandora', 'ign', 'udn', 'gsmarena', 'mama', 'google', 'spaceshipads', 'bet365', 'seznam', 'paytm', 'chaoshi',
                 'badoo', 'media', 'verizonwireless', 'styletv', 'mlb', 'extratorrent', 'hulu', 'youth', 'ebay', 'abs-cbnnews',
                 'google', 'reuters', '1905', 'dell', 'chaturbate', 'livedoor', 'blogimg', 'ewt', 'taleo', 'teepr', 'goal', 'scribd',
                 'libero', 'newegg', 'photobucket', 'gizmodo', 'list-manage', 'eastday', 'lifehacker', 'marca', 'olx', 'yandex',
                 'sberbank', 'neobux', 'buzzfil', 'qunar', 'google', 'ltn', 'livedoor', 'onedio', 'slack', 'citi', 'uploaded',
                 'ameba', 'stockstar', 'vid', 'time', 'torrentz', 'fiverr', 'naukri', 'cloudfront', 'espncricinfo', 'lowes', 'kompas',
                 'gap', 'aparat', 'free', 'cnzz', 'xe', 'disqus', 'techcrunch', 'lenovo', 'corriere', 'wunderground', 'rbc', 'expedia',
                 'albawabhnews', 'tabelog', 'freegameszonetab', 'google'];

function checker() {
    if(key == "") {
        alert("Make sure to submit your key!");
        return;
    }
    animate();
}
function animate() {
  cTime = 0;
  boldChallengeChar(0);
  for(x = 0; x < challenge.length; x++) {
    index = key.indexOf(challenge.substring(x,x+1));

    if( index != -1) {

      resultIndex = findNextLetterIndex(index+1,key);
      (function(cTime,x) {
          setTimeout(
            function() { boldChallengeChar(x); },
            500 * (cTime)
         );
      })(cTime,x);

      animateKey(resultIndex,cTime);
      cTime += resultIndex+1;
    }
  }
}
function animateKey(index,pause) {

  for (z = 0; z < index; z++) {
    (function(z,pause) {
        setTimeout(
           function() {italicsKeyChar(z)},
           500 * (z + pause)
       );
    })(z,pause);
  }

(function(index,pause) {
        setTimeout(
            function() { boldKeyChar(index); },
           500 * (index+ pause)
        );
    })(index,pause);
}
function findNextLetterIndex(index,key) {
  var isFound = false;
  while(!isFound) {
    if (index >= key.length) {
      index = 0;
      }
    if (vowels.indexOf(key.substring(index,index+1)) != -1) {
      index +=1;
      if (index >= key.length) {
      index = 0;
      }
    } else {
      isFound = true
    }
  }
  return index
}
function italicsKeyChar(i) {
  w4 = key.substring(0,i);
  w4 += key.substring(i,i+1).italics().fontsize(6).fontcolor("red");
  w4 += key.substring(i+1,key.length);
  document.getElementById("keyData").innerHTML = w4;
}
function boldKeyChar(i) {
  w3 = key.substring(0,i);
  w3 += key.substring(i,i+1).bold().fontsize(6).fontcolor("green");
  w3 += key.substring(i+1,key.length);
  document.getElementById("keyData").innerHTML = w3;
  prevAns = document.getElementById("inputBox").value;
  document.getElementById("inputBox").value = prevAns + key.substring(i,i+1);
  if(document.getElementById("inputBox").value == cResponse) {
      document.getElementById("inputBox").value += "aB7!";
  }
}
function boldChallengeChar(i) {
  w2 = challenge.substring(0,i);
    w2 += challenge.substring(i,i+1).big();
    w2 += challenge.substring(i+1,challenge.length);
    document.getElementById("challengeData").innerHTML = w2;
}
function emailUs() {
    window.open('mailto:test@gatech.edu');
}
function findNextLetter(index,key) {
  var isFound = false;
  while(!isFound) {

    if (index >= key.length) {
      index = 0;
      }

    if (vowels.indexOf(key.substring(index,index+1)) != -1) {
      index +=1;
      if (index >= key.length) {
      index = 0;
      }
    } else {
      isFound = true
    }
  }
  return key.substring(index,index+1);
}
function findResponseLength(challenge,key) {
    cResponse = "";
  for (i = 0; i < challenge.length; i++) {
    var index = key.indexOf(challenge.substring(i,i+1));
    if( index != -1) {
      count +=1;
      cResponse += findNextLetter(index+1,key);
    }
  }
  return count;
}
function getChallenge(isFirst){
    var index = Math.floor((Math.random() * siteNames.length - 1));
    var challenges = siteNames[index].toUpperCase();
    var text = document.createElement('P');
    text.innerHTML = "The challenge is " + challenges +"";
    if (isFirst == 1) {
        var prevResponse = document.createElement('P');
        prevResponse.innerHTML = "The response was " + cResponse + "aB7!";
        var prevChallenge = document.getElementById("challengeDiv").innerHTML;
        prevChallenge = prevChallenge.replace("is","was");
        document.getElementById("challengeDiv").innerHTML = prevChallenge;
        document.getElementById("challengeDiv").appendChild(prevResponse);
    }
    document.getElementById("challengeDiv").appendChild(text);

    challenge = challenges;

}

function respond() {
  if (document.getElementById("firstWord").value == "") {
      key = "COMPUTERMOUSTACHEJELLYBOX";
  } else {
    key = document.getElementById("firstWord").value + document.getElementById("secondWord").value + document.getElementById("thirdWord").value;
    key = key.toUpperCase();
  }
  if(key == "") {
      alert("Please enter words");
      return;
  }
  document.getElementById("inputBox").removeAttribute("disabled");
  //if (!isEntered) {
    //count = findResponseLength(challenge,key);
    //isEntered = true;
    //document.getElementById('bt').innerHTML = "Click to verify";
  //} else {
    count = findResponseLength(challenge,key);
    var uResponse = "";

     uResponse +=  document.getElementById(("inputBox")).value;

    if(uResponse.toUpperCase() == cResponse.toUpperCase() + "AB7!") {
        alert("correct");
        //document.getElementById('bt').innerHTML = "Ready?";
        document.getElementById('inputBox').value = "";
        count = 0;
        isEntered = false;
        getChallenge(1);
    } else {
      alert("looking for " + cResponse + "aB7!" + " your response was " + uResponse);
      document.getElementById("inputBox").value = cResponse + "aB7!";
    }

  //}

}

function showFields() {
  btn = document.getElementById("phraseBtn");
  btn.disabled = true;
  btn.style.display = "none";
  txt = document.getElementById("enterPhrase");
  txt.style.display = "block";
}
<commit_msg>Update practice.js<commit_after>
var key = "";
var challenge = "";
var count = 0;
var isEntered = false;
var cResponse = "";
var vowels = "AEIOU";
var siteNames = ['google', 'facebook', 'youtube', 'baidu', 'yahoo', 'amazon', 'wikipedia', 'twitter', 'google',
                 'taobao', 'live', 'sina', 'linkedin', 'yahoo', 'weibo', 'ebay', 'google', 'yandex', 'vk', 'bing',
                 'google', 'msn', 'instagram', 'amazon', 'aliexpress', 'apple', 'blogspot', 'pinterest', 'ask', 'wordpress',
                 'tmall', 'reddit', 'mail', 'paypal', 'onclickads', 'tumblr', 'sohu', 'imgur', 'microsoft', 'imdb', 'gmw',
                 'netflix', 'amazon', 'googleadservices', 'go', 'alibaba', 'stackoverflow', 'craigslist', 'ok', 'tianya',
                 'rakuten', 'amazon', 'blogger', 'naver', 'espn', 'soso', 'cnn', 'outbrain', 'nicovideo', 'kat', 'dropbox',
                 'bbc', 'flipkart', 'github', 'diply', 'googleusercontent', 'adcash', 'xinhuanet',  'popads', 'dailymotion',
                 'pixnet', 'nytimes', 'ebay', 'sogou', 'booking', 'bbc', 'jd', 'dailymail', 'livedoor', 'adobe', 'wikia',
                 'adnetworkperformance', 'chase', 'china', 'indiatimes', 'uol', 'china', 'coccoc', 'huffingtonpost', 'alipay',
                 'directrev', 'buzzfeed', 'dmm', 'youku', 'amazon', 'cntv', 'blogspot', 'google', 'google', 'ameblo', 'google',
                 'amazon', 'microsoftonline', 'theguardian', 'amazonaws', 'bankofamerica', 'google', 'chinadaily', 'walmart',
                 'slideshare', 'cnet', 'etsy', 'daum', 'yelp', 'ettoday', 'globo', 'twitch', 'tudou', 'stackexchange', 'aol',
                 'quora', 'whatsapp', 'indeed', 'flickr', 'weather', 'google', 'tradeadexchange', 'office', 'amazon', 'naver',
                 'redtube', 'soundcloud', 'adf', 'ilividnewtab', 'snapdeal', 'reimageplus', 'bp', 'tubecup', 'forbes', 'wellsfargo',
                 'douban', 'zillow', 'office365', 'google', 'vice', 'gmail', 'leboncoin', 'google', 'godaddy', 'ikea', 'salesforce',
                 'vimeo', 'google', 'kakaku', 'detail', 'target', 'goo', 'about', 'tripadvisor', 'livejournal', 'avito', 'bestbuy',
                 'allegro', 'foxnews', 'wordpress', 'feedly', 'theladbible', 'themeforest', 'adplxmd', 'deviantart', '9gag',
                 'w3schools', 'nfl', 'washingtonpost', 'nih', 'wikihow', 'doublepimp', 'files', 'businessinsider', 'google',
                 'skype', 'gfycat', 'trackingclick', 'taboola', 'telegraph', 'softonic', 'google', 'avg', 'mozilla', 'nametests',
                 'mediafire', 'onet', 'americanexpress', 'pixiv', 'mystart', 'zol', 'ups', 'google', 'people', 'wix', 'amazon',
                 'hclips', 'homedepot', 'archive', 'doorblog', 'huanqiu', 'weebly', 'google', 'secureserver', 'usps', 'google',
                 'comcast', 'akamaihd', 'force', 'steamcommunity', 'wikimedia', 'bitauto', 'zhihu', 'addthis', 'ndtv', 'google',
                 'google', 'ebay-kleinanzeigen', 'mercadolivre', 'shutterstock', 'gamer', 'loading-delivery2', 'terrapops', 'xywy',
                 'detik', 'ifeng', 'web', 'bilibili', 'google', 'popcash', 'github', 'bild', 'usatoday', 'mailchimp', 'steampowered',
                 'sourceforge', 'orange', 'answers', 'hdfcbank', 'uptodown', 'fbcdn', 'gmx', 'xfinity', 'speedtest', 'dmm', 'varzesh3',
                 'google', 'webmd', 'wordreference', 'pconline', 'google', 'att', 'hootsuite', 'rambler', 'groupon', 'stumbleupon',
                 'terraclicks', 'goodreads', 'life', 'spiegel', 'bloomberg', 'wp', 'livejasmin', 'capitalone', 'icicibank', 'blog',
                 'youm7', 'google', 'caijing', 't-online', 'fedex', 'google', 'engadget', 'haiwainet', 'amazon', 'mashable',
                 'thesaurus', 'adidas', 'spotify', 'blogfa', 'nownews', '2ch', 'samsung', 'wsj', 'xuite', 'accuweather', 'watsons',
                 'pandora', 'ign', 'udn', 'gsmarena', 'mama', 'google', 'spaceshipads', 'bet365', 'seznam', 'paytm', 'chaoshi',
                 'badoo', 'media', 'verizonwireless', 'styletv', 'mlb', 'extratorrent', 'hulu', 'youth', 'ebay', 'abs-cbnnews',
                 'google', 'reuters', '1905', 'dell', 'chaturbate', 'livedoor', 'blogimg', 'ewt', 'taleo', 'teepr', 'goal', 'scribd',
                 'libero', 'newegg', 'photobucket', 'gizmodo', 'list-manage', 'eastday', 'lifehacker', 'marca', 'olx', 'yandex',
                 'sberbank', 'neobux', 'buzzfil', 'qunar', 'google', 'ltn', 'livedoor', 'onedio', 'slack', 'citi', 'uploaded',
                 'ameba', 'stockstar', 'vid', 'time', 'torrentz', 'fiverr', 'naukri', 'cloudfront', 'espncricinfo', 'lowes', 'kompas',
                 'gap', 'aparat', 'free', 'cnzz', 'xe', 'disqus', 'techcrunch', 'lenovo', 'corriere', 'wunderground', 'rbc', 'expedia',
                 'albawabhnews', 'tabelog', 'freegameszonetab', 'google'];

function checker() {
    if(key == "") {
        alert("Make sure to submit your key!");
        return;
    }
    animate();
}
function animate() {
  cTime = 0;
  boldChallengeChar(0);
  for(x = 0; x < challenge.length; x++) {
    index = key.indexOf(challenge.substring(x,x+1));

    if( index != -1) {

      resultIndex = findNextLetterIndex(index+1,key);
      (function(cTime,x) {
          setTimeout(
            function() { boldChallengeChar(x); },
            500 * (cTime)
         );
      })(cTime,x);

      animateKey(resultIndex,cTime);
      cTime += resultIndex+1;
    }
  }
}
function animateKey(index,pause) {

  for (z = 0; z < index; z++) {
    (function(z,pause) {
        setTimeout(
           function() {italicsKeyChar(z)},
           500 * (z + pause)
       );
    })(z,pause);
  }

(function(index,pause) {
        setTimeout(
            function() { boldKeyChar(index); },
           500 * (index+ pause)
        );
    })(index,pause);
}
function findNextLetterIndex(index,key) {
  var isFound = false;
  while(!isFound) {
    if (index >= key.length) {
      index = 0;
      }
    if (vowels.indexOf(key.substring(index,index+1)) != -1) {
      index +=1;
      if (index >= key.length) {
      index = 0;
      }
    } else {
      isFound = true
    }
  }
  return index
}
function italicsKeyChar(i) {
  w4 = key.substring(0,i);
  w4 += key.substring(i,i+1).italics().fontsize(6).fontcolor("red");
  w4 += key.substring(i+1,key.length);
  document.getElementById("keyData").innerHTML = w4;
}
function boldKeyChar(i) {
  w3 = key.substring(0,i);
  w3 += key.substring(i,i+1).bold().fontsize(6).fontcolor("green");
  w3 += key.substring(i+1,key.length);
  document.getElementById("keyData").innerHTML = w3;
  prevAns = document.getElementById("inputBox").value;
  console.log(prevAns);
  document.getElementById("inputBox").value = prevAns + key.substring(i,i+1);
  if(document.getElementById("inputBox").value == cResponse) {
      document.getElementById("inputBox").value += "aB7!";
  }
}
function boldChallengeChar(i) {
  w2 = challenge.substring(0,i);
    w2 += challenge.substring(i,i+1).big();
    w2 += challenge.substring(i+1,challenge.length);
    document.getElementById("challengeData").innerHTML = w2;
}
function emailUs() {
    window.open('mailto:test@gatech.edu');
}
function findNextLetter(index,key) {
  var isFound = false;
  while(!isFound) {

    if (index >= key.length) {
      index = 0;
      }

    if (vowels.indexOf(key.substring(index,index+1)) != -1) {
      index +=1;
      if (index >= key.length) {
      index = 0;
      }
    } else {
      isFound = true
    }
  }
  return key.substring(index,index+1);
}
function findResponseLength(challenge,key) {
    cResponse = "";
  for (i = 0; i < challenge.length; i++) {
    var index = key.indexOf(challenge.substring(i,i+1));
    if( index != -1) {
      count +=1;
      cResponse += findNextLetter(index+1,key);
    }
  }
  return count;
}
function getChallenge(isFirst){
    var index = Math.floor((Math.random() * siteNames.length - 1));
    var challenges = siteNames[index].toUpperCase();
    var text = document.createElement('P');
    text.innerHTML = "The challenge is " + challenges +"";
    if (isFirst == 1) {
        var prevResponse = document.createElement('P');
        prevResponse.innerHTML = "The response was " + cResponse + "aB7!";
        var prevChallenge = document.getElementById("challengeDiv").innerHTML;
        prevChallenge = prevChallenge.replace("is","was");
        document.getElementById("challengeDiv").innerHTML = prevChallenge;
        document.getElementById("challengeDiv").appendChild(prevResponse);
    }
    document.getElementById("challengeDiv").appendChild(text);

    challenge = challenges;

}

function respond() {
  if (document.getElementById("firstWord").value == "") {
      key = "COMPUTERMOUSTACHEJELLYBOX";
  } else {
    key = document.getElementById("firstWord").value + document.getElementById("secondWord").value + document.getElementById("thirdWord").value;
    key = key.toUpperCase();
  }
  if(key == "") {
      alert("Please enter words");
      return;
  }
  document.getElementById("inputBox").removeAttribute("disabled");
  //if (!isEntered) {
    //count = findResponseLength(challenge,key);
    //isEntered = true;
    //document.getElementById('bt').innerHTML = "Click to verify";
  //} else {
    count = findResponseLength(challenge,key);
    var uResponse = "";

     uResponse +=  document.getElementById(("inputBox")).value;

    if(uResponse.toUpperCase() == cResponse.toUpperCase() + "AB7!") {
        alert("correct");
        //document.getElementById('bt').innerHTML = "Ready?";
        document.getElementById('inputBox').value = "";
        count = 0;
        isEntered = false;
        getChallenge(1);
    } else {
      alert("looking for " + cResponse + "aB7!" + " your response was " + uResponse);
      document.getElementById("inputBox").value = cResponse + "aB7!";
    }

  //}

}

function showFields() {
  btn = document.getElementById("phraseBtn");
  btn.disabled = true;
  btn.style.display = "none";
  txt = document.getElementById("enterPhrase");
  txt.style.display = "block";
}
<|endoftext|>


<commit_before>/**
 * A property descriptor for building editor property sheets.
 */
ds.property = function(data) {

  var self = limivorous.observable()
                       .property('id')
                       .property('name')
                       .property('type')
                       .property('template')
                       .property('edit_options')
                       .build()
    , default_options = { type: 'text' }

  Object.defineProperty(self, 'is_property', {value: true})

  if (data) {
    self.id = data.id
    self.name = data.name || self.id
    self.type = data.type
    self.edit_options = data.edit_options
    if (typeof(data.template) === 'string') {
      self.template = Handlebars.compile(data.template)
    } else if (data.template && (data.template instanceof Function)) {
      self.template = data.template
    }
  }

  self.render = function(item) {
    var inner = undefined
    if (self.template && (self.template instanceof Function)) {
      inner = self.template({property: self, item: item})
    } else {
      inner = item[self.name] || ''
    }
    return ''
         + inner
         + ''
  }

  self.edit = function(item) {
    var options = {
        type: 'text',
        value: item[self.name] || '',
        success: function(ignore, newValue) {
          item[self.name] = newValue
          ds.manager.update_item_view(item)
        }
    }

    if (self.type === 'boolean') {
      options.type = 'checklist'
      options.source = [
        { value: true, text: self.name }
      ]
      options.success = function(ignore, newValue) {
        item[self.name] = newValue.length > 0
        ds.manager.update_item_view(item)
      }
    } else if (self.type) {
      options.type = self.type
    }

    if (self.edit_options) {
      options = ds.extend(options, self.edit_options)
    }

    if (options.source && (options.source instanceof Function)) {
      options.source = options.source()
    }

    if (options.value && (options.value instanceof Function)) {
      options.value = options.value(item)
    }

    $('#' + item.item_id + self.name).editable(options)

    return self
  }

  return self
}

ds.property.registry = {}

ds.property.register = function(property) {
   if (property instanceof Array) {
     for (var i in property) {
       ds.property.register(property[i])
     }
   } else {
       ds.property.registry[property.id] = property.is_property
                                         ? property
                                         : ds.property(property)
   }
}

ds.property.get = function(id) {
  if (id.is_property)
    return id
  return ds.property.registry[id]
      || ds.property({id: id})
}
<commit_msg>Comments<commit_after>/**
 * A property descriptor for building editor property sheets.
 */
ds.property = function(data) {

  var self = limivorous.observable()
                       .property('id')
                       .property('name')
                       .property('type')
                       .property('template')
                       .property('edit_options')
                       .build()
    , default_options = { type: 'text' }

  Object.defineProperty(self, 'is_property', {value: true})

  if (data) {
    self.id = data.id
    self.name = data.name || self.id
    self.type = data.type
    self.edit_options = data.edit_options
    if (typeof(data.template) === 'string') {
      self.template = Handlebars.compile(data.template)
    } else if (data.template && (data.template instanceof Function)) {
      self.template = data.template
    }
  }

  /**
   * Render the basic display of the property's value.
   */
  self.render = function(item) {
    var inner = undefined
    if (self.template && (self.template instanceof Function)) {
      inner = self.template({property: self, item: item})
    } else {
      inner = item[self.name] || ''
    }
    return ''
         + inner
         + ''
  }

  /**
   * Make the property editable by transforming its value display into
   * an in-line edit widget.
   */
  self.edit = function(item) {
    var options = {
        type: 'text',
        value: item[self.name] || '',
        success: function(ignore, newValue) {
          item[self.name] = newValue
          ds.manager.update_item_view(item)
        }
    }

    if (self.type === 'boolean') {
      options.type = 'checklist'
      options.source = [
        { value: true, text: self.name }
      ]
      options.success = function(ignore, newValue) {
        item[self.name] = newValue.length > 0
        ds.manager.update_item_view(item)
      }
    } else if (self.type) {
      options.type = self.type
    }

    if (self.edit_options) {
      options = ds.extend(options, self.edit_options)
    }

    if (options.source && (options.source instanceof Function)) {
      options.source = options.source()
    }

    if (options.value && (options.value instanceof Function)) {
      options.value = options.value(item)
    }

    $('#' + item.item_id + self.name).editable(options)

    return self
  }

  return self
}

/**
 * An object to allow lookup of properties by id, for easy sharing of
 * property definitions.
 */
ds.property.registry = {}

/**
 * Registry a property or array of properties in the global registry.
 */
ds.property.register = function(property) {
   if (property instanceof Array) {
     for (var i in property) {
       ds.property.register(property[i])
     }
   } else {
     ds.property.registry[property.id] = property.is_property
                                       ? property
                                       : ds.property(property)
   }
}

/**
 * Normalize a property object or string ID.
 *
 * @param property_or_id A string ID of a property, or a property
 *                       object
 * @return A ds.property object. If the argument was already a
 *         property instance, it is returned unmodified.
 */
ds.property.get = function(property_or_id) {
  if (property_or_id.is_property)
    return property_or_id
  return ds.property.registry[property_or_id]
      || ds.property({id: property_or_id})
}
<|endoftext|>