<commit_before>// ::- Superclass for editor selections.
class Selection {
  // :: number
  // The lower bound of the selection.
  get from() { return this.$from.pos }

  // :: number
  // The upper bound of the selection.
  get to() { return this.$to.pos }

  constructor($from, $to) {
    // :: ResolvedPos
    // The resolved lower bound of the selection
    this.$from = $from
    // :: ResolvedPos
    // The resolved upper bound of the selection
    this.$to = $to
  }

  // :: bool
  // True if the selection is an empty text selection (head an anchor
  // are the same).
  get empty() {
    return this.from == this.to
  }

  // eq:: (other: Selection) → bool
  // Test whether the selection is the same as another selection.

  // map:: (doc: Node, mapping: Mappable) → Selection
  // Map this selection through a [mappable](#transform.Mappable) thing. `doc`
  // should be the new document, to which we are mapping.

  // toJSON:: () → Object
  // Convert the selection to a JSON representation.

  // :: (ResolvedPos, number, ?bool) → ?Selection
  // Find a valid cursor or leaf node selection starting at the given
  // position and searching back if `dir` is negative, and forward if
  // negative. When `textOnly` is true, only consider cursor
  // selections.
  static findFrom($pos, dir, textOnly) {
    let inner = $pos.parent.isTextblock ? new TextSelection($pos)
        : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly)
    if (inner) return inner

    for (let depth = $pos.depth - 1; depth >= 0; depth--) {
      let found = dir < 0
          ? findSelectionIn($pos.node(0), $pos.node(depth), $pos.before(depth + 1), $pos.index(depth), dir, textOnly)
          : findSelectionIn($pos.node(0), $pos.node(depth), $pos.after(depth + 1), $pos.index(depth) + 1, dir, textOnly)
      if (found) return found
    }
  }

  // :: (ResolvedPos, ?number, ?bool) → Selection
  // Find a valid cursor or leaf node selection near the given
  // position. Searches forward first by default, but if `bias` is
  // negative, it will search backwards first.
  static near($pos, bias = 1, textOnly = false) {
    let result = this.findFrom($pos, bias, textOnly) || this.findFrom($pos, -bias, textOnly)
    if (!result) throw new RangeError("Searching for selection in invalid document " + $pos.node(0))
    return result
  }

  // :: (Node, ?bool) → ?Selection
  // Find the cursor or leaf node selection closest to the start of
  // the given document. When `textOnly` is true, only consider cursor
  // selections.
  static atStart(doc, textOnly) {
    return findSelectionIn(doc, doc, 0, 0, 1, textOnly)
  }

  // :: (Node, ?bool) → ?Selection
  // Find the cursor or leaf node selection closest to the end of
  // the given document. When `textOnly` is true, only consider cursor
  // selections.
  static atEnd(doc, textOnly) {
    return findSelectionIn(doc, doc, doc.content.size, doc.childCount, -1, textOnly)
  }

  // :: (ResolvedPos, ResolvedPos, ?number) → Selection
  // Find a selection that spans the given positions, if both are text
  // positions. If not, return some other selection nearby, where
  // `bias` determines whether the method searches forward (default)
  // or backwards (negative number) first.
  static between($anchor, $head, bias) {
    let found = Selection.near($head, bias)
    if (found instanceof TextSelection) {
      let nearAnchor = Selection.findFrom($anchor, $anchor.pos > found.to ? -1 : 1, true)
      found = new TextSelection(nearAnchor.$anchor, found.$head)
    } else if ($anchor.pos < found.from || $anchor.pos > found.to) {
      // If head falls on a node, but anchor falls outside of it, create
      // a text selection between them
      let inv = $anchor.pos > found.to
      let foundAnchor = Selection.findFrom($anchor, inv ? -1 : 1, true)
      let foundHead = Selection.findFrom(inv ? found.$from : found.$to, inv ? 1 : -1, true)
      if (foundAnchor && foundHead)
        found = new TextSelection(foundAnchor.$anchor, foundHead.$head)
    }
    return found
  }

  static mapJSON(json, mapping) {
    if (json.anchor != null)
      return {head: mapping.map(json.head), anchor: mapping.map(json.anchor)}
    else
      return {node: mapping.map(json.node), after: mapping.map(json.after, -1)}
  }

  // :: (Node, Object) → Selection
  // Deserialize a JSON representation of a selection.
  static fromJSON(doc, json) {
    // This is cautious, because the history will blindly map
    // selections and then try to deserialize them, and the endpoints
    // might not point at appropriate positions anymore (though they
    // are guaranteed to be inside of the document's range).
    if (json.head != null) {
      let $anchor = doc.resolve(json.anchor), $head = doc.resolve(json.head)
      if ($anchor.parent.isTextblock && $head.parent.isTextblock) return new TextSelection($anchor, $head)
      else return Selection.between($anchor, $head)
    } else {
      let $pos = doc.resolve(json.node), after = $pos.nodeAfter
      if (after && json.after == json.pos + after.nodeSize && NodeSelection.isSelectable(after)) return new NodeSelection($pos)
      else return Selection.near($pos)
    }
  }
}
exports.Selection = Selection

// ::- A text selection represents a classical editor
// selection, with a head (the moving side) and anchor (immobile
// side), both of which point into textblock nodes. It can be empty (a
// regular cursor position).
class TextSelection extends Selection {
  // :: number
  // The selection's immobile side (does not move when pressing
  // shift-arrow).
  get anchor() { return this.$anchor.pos }
  // :: number
  // The selection's mobile side (the side that moves when pressing
  // shift-arrow).
  get head() { return this.$head.pos }

  // :: (ResolvedPos, ?ResolvedPos)
  // Construct a text selection.
  constructor($anchor, $head = $anchor) {
    let inv = $anchor.pos > $head.pos
    super(inv ? $head : $anchor, inv ? $anchor : $head)
    // :: ResolvedPos The resolved anchor of the selection.
    this.$anchor = $anchor
    // :: ResolvedPos The resolved head of the selection.
    this.$head = $head
  }

  get inverted() { return this.anchor > this.head }

  eq(other) {
    return other instanceof TextSelection && other.head == this.head && other.anchor == this.anchor
  }

  map(doc, mapping) {
    let $head = doc.resolve(mapping.map(this.head))
    if (!$head.parent.isTextblock) return Selection.near($head)
    let $anchor = doc.resolve(mapping.map(this.anchor))
    return new TextSelection($anchor.parent.isTextblock ? $anchor : $head, $head)
  }

  toJSON() {
    return {head: this.head, anchor: this.anchor}
  }

  // :: (Node, number, ?number) → TextSelection
  // Create a text selection from non-resolved positions.
  static create(doc, anchor, head = anchor) {
    let $anchor = doc.resolve(anchor)
    return new this($anchor, head == anchor ? $anchor : doc.resolve(head))
  }
}
exports.TextSelection = TextSelection

// ::- A node selection is a selection that points at a
// single node. All nodes marked [selectable](#model.NodeSpec.selectable)
// can be the target of a node selection. In such an object, `from`
// and `to` point directly before and after the selected node.
class NodeSelection extends Selection {
  // :: (ResolvedPos)
  // Create a node selection. Does not verify the validity of its
  // argument.
  constructor($from) {
    let $to = $from.node(0).resolve($from.pos + $from.nodeAfter.nodeSize)
    super($from, $to)
    // :: Node The selected node.
    this.node = $from.nodeAfter
  }

  eq(other) {
    return other instanceof NodeSelection && this.from == other.from
  }

  map(doc, mapping) {
    let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1)
    let $from = doc.resolve(from.pos), node = $from.nodeAfter
    if (!from.deleted && !to.deleted && node && to.pos == from.pos + node.nodeSize && NodeSelection.isSelectable(node))
      return new NodeSelection($from)
    return Selection.near($from)
  }

  toJSON() {
    return {node: this.from, after: this.to}
  }

  // :: (Node, number, ?number) → TextSelection
  // Create a node selection from non-resolved positions.
  static create(doc, from) {
    return new this(doc.resolve(from))
  }

  // :: (Node) → bool
  // Determines whether the given node may be selected as a node
  // selection.
  static isSelectable(node) {
    return !node.isText && node.type.spec.selectable !== false
  }
}
exports.NodeSelection = NodeSelection

// FIXME we'll need some awareness of text direction when scanning for selections

// Try to find a selection inside the given node. `pos` points at the
// position where the search starts. When `text` is true, only return
// text selections.
function findSelectionIn(doc, node, pos, index, dir, text) {
  if (node.isTextblock) return TextSelection.create(doc, pos)
  for (let i = index - (dir > 0 ? 0 : 1); dir > 0 ? i < node.childCount : i >= 0; i += dir) {
    let child = node.child(i)
    if (!child.isLeaf) {
      let inner = findSelectionIn(doc, child, pos + dir, dir < 0 ? child.childCount : 0, dir, text)
      if (inner) return inner
    } else if (!text && NodeSelection.isSelectable(child)) {
      return NodeSelection.create(doc, pos - (dir < 0 ? child.nodeSize : 0))
    }
    pos += child.nodeSize * dir
  }
}
<commit_msg>Switch check for direct selectability to isAtom<commit_after>// ::- Superclass for editor selections.
class Selection {
  // :: number
  // The lower bound of the selection.
  get from() { return this.$from.pos }

  // :: number
  // The upper bound of the selection.
  get to() { return this.$to.pos }

  constructor($from, $to) {
    // :: ResolvedPos
    // The resolved lower bound of the selection
    this.$from = $from
    // :: ResolvedPos
    // The resolved upper bound of the selection
    this.$to = $to
  }

  // :: bool
  // True if the selection is an empty text selection (head an anchor
  // are the same).
  get empty() {
    return this.from == this.to
  }

  // eq:: (other: Selection) → bool
  // Test whether the selection is the same as another selection.

  // map:: (doc: Node, mapping: Mappable) → Selection
  // Map this selection through a [mappable](#transform.Mappable) thing. `doc`
  // should be the new document, to which we are mapping.

  // toJSON:: () → Object
  // Convert the selection to a JSON representation.

  // :: (ResolvedPos, number, ?bool) → ?Selection
  // Find a valid cursor or leaf node selection starting at the given
  // position and searching back if `dir` is negative, and forward if
  // negative. When `textOnly` is true, only consider cursor
  // selections.
  static findFrom($pos, dir, textOnly) {
    let inner = $pos.parent.isTextblock ? new TextSelection($pos)
        : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly)
    if (inner) return inner

    for (let depth = $pos.depth - 1; depth >= 0; depth--) {
      let found = dir < 0
          ? findSelectionIn($pos.node(0), $pos.node(depth), $pos.before(depth + 1), $pos.index(depth), dir, textOnly)
          : findSelectionIn($pos.node(0), $pos.node(depth), $pos.after(depth + 1), $pos.index(depth) + 1, dir, textOnly)
      if (found) return found
    }
  }

  // :: (ResolvedPos, ?number, ?bool) → Selection
  // Find a valid cursor or leaf node selection near the given
  // position. Searches forward first by default, but if `bias` is
  // negative, it will search backwards first.
  static near($pos, bias = 1, textOnly = false) {
    let result = this.findFrom($pos, bias, textOnly) || this.findFrom($pos, -bias, textOnly)
    if (!result) throw new RangeError("Searching for selection in invalid document " + $pos.node(0))
    return result
  }

  // :: (Node, ?bool) → ?Selection
  // Find the cursor or leaf node selection closest to the start of
  // the given document. When `textOnly` is true, only consider cursor
  // selections.
  static atStart(doc, textOnly) {
    return findSelectionIn(doc, doc, 0, 0, 1, textOnly)
  }

  // :: (Node, ?bool) → ?Selection
  // Find the cursor or leaf node selection closest to the end of
  // the given document. When `textOnly` is true, only consider cursor
  // selections.
  static atEnd(doc, textOnly) {
    return findSelectionIn(doc, doc, doc.content.size, doc.childCount, -1, textOnly)
  }

  // :: (ResolvedPos, ResolvedPos, ?number) → Selection
  // Find a selection that spans the given positions, if both are text
  // positions. If not, return some other selection nearby, where
  // `bias` determines whether the method searches forward (default)
  // or backwards (negative number) first.
  static between($anchor, $head, bias) {
    let found = Selection.near($head, bias)
    if (found instanceof TextSelection) {
      let nearAnchor = Selection.findFrom($anchor, $anchor.pos > found.to ? -1 : 1, true)
      found = new TextSelection(nearAnchor.$anchor, found.$head)
    } else if ($anchor.pos < found.from || $anchor.pos > found.to) {
      // If head falls on a node, but anchor falls outside of it, create
      // a text selection between them
      let inv = $anchor.pos > found.to
      let foundAnchor = Selection.findFrom($anchor, inv ? -1 : 1, true)
      let foundHead = Selection.findFrom(inv ? found.$from : found.$to, inv ? 1 : -1, true)
      if (foundAnchor && foundHead)
        found = new TextSelection(foundAnchor.$anchor, foundHead.$head)
    }
    return found
  }

  static mapJSON(json, mapping) {
    if (json.anchor != null)
      return {head: mapping.map(json.head), anchor: mapping.map(json.anchor)}
    else
      return {node: mapping.map(json.node), after: mapping.map(json.after, -1)}
  }

  // :: (Node, Object) → Selection
  // Deserialize a JSON representation of a selection.
  static fromJSON(doc, json) {
    // This is cautious, because the history will blindly map
    // selections and then try to deserialize them, and the endpoints
    // might not point at appropriate positions anymore (though they
    // are guaranteed to be inside of the document's range).
    if (json.head != null) {
      let $anchor = doc.resolve(json.anchor), $head = doc.resolve(json.head)
      if ($anchor.parent.isTextblock && $head.parent.isTextblock) return new TextSelection($anchor, $head)
      else return Selection.between($anchor, $head)
    } else {
      let $pos = doc.resolve(json.node), after = $pos.nodeAfter
      if (after && json.after == json.pos + after.nodeSize && NodeSelection.isSelectable(after)) return new NodeSelection($pos)
      else return Selection.near($pos)
    }
  }
}
exports.Selection = Selection

// ::- A text selection represents a classical editor
// selection, with a head (the moving side) and anchor (immobile
// side), both of which point into textblock nodes. It can be empty (a
// regular cursor position).
class TextSelection extends Selection {
  // :: number
  // The selection's immobile side (does not move when pressing
  // shift-arrow).
  get anchor() { return this.$anchor.pos }
  // :: number
  // The selection's mobile side (the side that moves when pressing
  // shift-arrow).
  get head() { return this.$head.pos }

  // :: (ResolvedPos, ?ResolvedPos)
  // Construct a text selection.
  constructor($anchor, $head = $anchor) {
    let inv = $anchor.pos > $head.pos
    super(inv ? $head : $anchor, inv ? $anchor : $head)
    // :: ResolvedPos The resolved anchor of the selection.
    this.$anchor = $anchor
    // :: ResolvedPos The resolved head of the selection.
    this.$head = $head
  }

  get inverted() { return this.anchor > this.head }

  eq(other) {
    return other instanceof TextSelection && other.head == this.head && other.anchor == this.anchor
  }

  map(doc, mapping) {
    let $head = doc.resolve(mapping.map(this.head))
    if (!$head.parent.isTextblock) return Selection.near($head)
    let $anchor = doc.resolve(mapping.map(this.anchor))
    return new TextSelection($anchor.parent.isTextblock ? $anchor : $head, $head)
  }

  toJSON() {
    return {head: this.head, anchor: this.anchor}
  }

  // :: (Node, number, ?number) → TextSelection
  // Create a text selection from non-resolved positions.
  static create(doc, anchor, head = anchor) {
    let $anchor = doc.resolve(anchor)
    return new this($anchor, head == anchor ? $anchor : doc.resolve(head))
  }
}
exports.TextSelection = TextSelection

// ::- A node selection is a selection that points at a
// single node. All nodes marked [selectable](#model.NodeSpec.selectable)
// can be the target of a node selection. In such an object, `from`
// and `to` point directly before and after the selected node.
class NodeSelection extends Selection {
  // :: (ResolvedPos)
  // Create a node selection. Does not verify the validity of its
  // argument.
  constructor($from) {
    let $to = $from.node(0).resolve($from.pos + $from.nodeAfter.nodeSize)
    super($from, $to)
    // :: Node The selected node.
    this.node = $from.nodeAfter
  }

  eq(other) {
    return other instanceof NodeSelection && this.from == other.from
  }

  map(doc, mapping) {
    let from = mapping.mapResult(this.from, 1), to = mapping.mapResult(this.to, -1)
    let $from = doc.resolve(from.pos), node = $from.nodeAfter
    if (!from.deleted && !to.deleted && node && to.pos == from.pos + node.nodeSize && NodeSelection.isSelectable(node))
      return new NodeSelection($from)
    return Selection.near($from)
  }

  toJSON() {
    return {node: this.from, after: this.to}
  }

  // :: (Node, number, ?number) → TextSelection
  // Create a node selection from non-resolved positions.
  static create(doc, from) {
    return new this(doc.resolve(from))
  }

  // :: (Node) → bool
  // Determines whether the given node may be selected as a node
  // selection.
  static isSelectable(node) {
    return !node.isText && node.type.spec.selectable !== false
  }
}
exports.NodeSelection = NodeSelection

// FIXME we'll need some awareness of text direction when scanning for selections

// Try to find a selection inside the given node. `pos` points at the
// position where the search starts. When `text` is true, only return
// text selections.
function findSelectionIn(doc, node, pos, index, dir, text) {
  if (node.isTextblock) return TextSelection.create(doc, pos)
  for (let i = index - (dir > 0 ? 0 : 1); dir > 0 ? i < node.childCount : i >= 0; i += dir) {
    let child = node.child(i)
    if (!child.isAtom) {
      let inner = findSelectionIn(doc, child, pos + dir, dir < 0 ? child.childCount : 0, dir, text)
      if (inner) return inner
    } else if (!text && NodeSelection.isSelectable(child)) {
      return NodeSelection.create(doc, pos - (dir < 0 ? child.nodeSize : 0))
    }
    pos += child.nodeSize * dir
  }
}
<|endoftext|>


<commit_before>var mysql = require('mysql')
var Q = require('Q')

/*
 * Todo:
 * Add cache, I love redis
 */

var DB = (function() {
	function DB(pool) {
		this.pool = pool

		return this
	}

	DB.prototype.getConnection = function() {
		var defer = Q.defer()

		this.pool.getConnection(function(err, con) {
			if (err) {
				console.log(err)
				return defer.reject(err)
			}

			return defer.resolve(con)
		})

		return defer.promise;
	}

	// This passes arguments directly to mysql.connection.query
	DB.prototype.query = function() {
		var defer = Q.defer()

		var args = Array.prototype.slice.call(arguments)
		args.push(function(err, rows) {
			if (err) {
				console.log(err)
				return defer.reject(err)
			}

			return defer.resolve(rows)
		})

		this.getConnection().then(function(con){
			con.query.apply(con, args);
			return con.end()
		})

		return defer.promise
	}

	DB.prototype.getChannels = function() {
		return this.query("SELECT * FROM Channels;")
	}

	DB.prototype.getFeed = function(id) {
		return this.query("SELECT * FROM Items WHERE channel_id = ?", [id])
	}

	return DB
})()

module.exports = function(config) {
	var pool = mysql.createPool(config)

	var db = new DB(pool)

	return db
}
<commit_msg>Add methods to mark items as read, fetch items and sort returned channels.<commit_after>var mysql = require('mysql')
var Q = require('Q')

/*
 * Todo:
 * Add cache, I love redis
 */

var DB = (function() {
	function DB(pool) {
		this.pool = pool

		return this
	}

	DB.prototype.getConnection = function() {
		var defer = Q.defer()

		this.pool.getConnection(function(err, con) {
			if (err) {
				console.log(err)
				return defer.reject(err)
			}

			return defer.resolve(con)
		})

		return defer.promise;
	}

	// This passes arguments directly to mysql.connection.query
	DB.prototype.query = function() {
		var defer = Q.defer()

		var args = Array.prototype.slice.call(arguments)
		args.push(function(err, rows) {
			if (err) {
				console.log(err)
				return defer.reject(err)
			}

			return defer.resolve(rows)
		})

		this.getConnection().then(function(con){
			con.query.apply(con, args);
			return con.end()
		})

		return defer.promise
	}

	DB.prototype.getChannels = function() {
		return this.query("SELECT * FROM Channels;")
	}

	DB.prototype.getFeed = function(id) {
		return this.query("SELECT * FROM Items WHERE channel_id = ? AND `read` = 0 ORDER BY published", [id])
	}

	DB.prototype.markRead = function(id) {
		return this.query("UPDATE Items SET `read` = 1 WHERE item_id = ?", [id])
	}

	DB.prototype.getFeedItem = function(id) {
		return this.query("SELECT * FROM Items WHERE item_id = ?", [id])
	}

	return DB
})()

module.exports = function(config) {
	var pool = mysql.createPool(config)

	var db = new DB(pool)

	return db
}
<|endoftext|>


<commit_before>import scrollbarWidth from 'scrollbarwidth'
import debounce from 'lodash.debounce'

import './simplebar.css'

export default class SimpleBar {
    constructor(element, options) {
        this.el = element;
        this.track;
        this.scrollbar;
        this.flashTimeout;
        this.contentEl          = this.el;
        this.scrollContentEl    = this.el;
        this.dragOffset         = { x: 0, y: 0 };
        this.isVisible          = { x: true, y: true };
        this.scrollOffsetAttr   = { x: 'scrollLeft', y: 'scrollTop' };
        this.sizeAttr           = { x: 'offsetWidth', y: 'offsetHeight' };
        this.scrollSizeAttr     = { x: 'scrollWidth', y: 'scrollHeight' };
        this.offsetAttr         = { x: 'left', y: 'top' };
        this.observer;
        this.currentAxis;
        this.enabled;

        this.options = Object.assign({}, SimpleBar.defaultOptions, options);
        this.classNames = this.options.classNames;

        this.flashScrollbar = this.flashScrollbar.bind(this);
        this.startScroll = this.startScroll.bind(this);
        this.startDrag = this.startDrag.bind(this);
        this.drag = this.drag.bind(this);
        this.endDrag = this.endDrag.bind(this);

        this.init();

        this.recalculate = debounce(this.recalculate, 100, { leading: true });
    }

    static get defaultOptions() {
        return {
            wrapContent: true,
            autoHide: true,
            forceEnabled: false,
            classNames: {
                content: 'simplebar-content',
                scrollContent: 'simplebar-scroll-content',
                scrollbar: 'simplebar-scrollbar',
                track: 'simplebar-track'
            },
            scrollbarMinSize: 10
        }
    }

    static get htmlAttributes() {
        return {
            autoHide: 'data-simplebar-autohide',
            forceEnabled: 'data-simplebar-force-enabled',
            scrollbarMinSize: 'data-simplebar-scrollbar-min-size'
        }
    }

    static initHtmlApi() {
        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // Mutation observer to observe dynamically added elements
            this.observer = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    Array.from(mutation.addedNodes).forEach(addedNode => {
                        if (addedNode.nodeType === 1) {
                            if (addedNode.hasAttribute('data-simplebar')) {
                                new SimpleBar(addedNode, SimpleBar.getElOptions(addedNode));
                            } else {
                                Array.from(addedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    new SimpleBar(el, SimpleBar.getElOptions(el));
                                });
                            }
                        }
                    });

                    Array.from(mutation.removedNodes).forEach(removedNode => {
                        if (removedNode.nodeType === 1) {
                            if (removedNode.hasAttribute('data-simplebar')) {
                                removedNode.SimpleBar && removedNode.SimpleBar.unMount();
                            } else {
                                Array.from(removedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    el.SimpleBar && el.SimpleBar.unMount();
                                });
                            }
                        }
                    });
                });
            });

            this.observer.observe(document, { childList: true, subtree: true });
        }

        // Instantiate elements already present on the page
        document.addEventListener('DOMContentLoaded', () => {
            Array.from(document.querySelectorAll('[data-simplebar]')).forEach(el => {
                new SimpleBar(el, SimpleBar.getElOptions(el));
            });
        });
    }

    // Helper function to retrieve options from element attributes
    static getElOptions(el) {
        const options = Object.keys(SimpleBar.htmlAttributes).reduce((acc, obj) => {
            const attribute = SimpleBar.htmlAttributes[obj];
            if (el.hasAttribute(attribute)) {
                acc[obj] = JSON.parse(el.getAttribute(attribute));
            }
            return acc;
        }, {});

        return options;
    }

    static removeObserver() {
        this.observer && this.observer.disconnect();
    }

    init() {
        // Save a reference to the instance, so we know this DOM node has already been instancied
        this.el.SimpleBar = this;

        // If scrollbar is a floating scrollbar, disable the plugin
        this.enabled = scrollbarWidth() !== 0;

        if (!this.enabled && !this.options.forceEnabled) {
            this.el.style.overflow = 'auto';

            return
        }

        this.initDOM();

        this.trackX = this.el.querySelector(`.${this.classNames.track}.horizontal`);
        this.trackY = this.el.querySelector(`.${this.classNames.track}.vertical`);

        this.scrollbarX = this.trackX.querySelector(`.${this.classNames.scrollbar}`);
        this.scrollbarY = this.trackY.querySelector(`.${this.classNames.scrollbar}`);
        this.scrollContentEl = this.el.querySelector('.' + this.classNames.scrollContent);
        this.contentEl = this.el.querySelector('.' + this.classNames.content);

        // Calculate content size
        this.recalculate();

        if (!this.options.autoHide) {
            this.showScrollbar('x');
            this.showScrollbar('y');
        }

        this.initListeners();
    }

    initDOM() {
        if (this.el.querySelectorAll(`.${this.classNames.content}`).length) {
            return;
        }

        // Prepare DOM
        if (this.options.wrapContent) {
            const wrapperScrollContent = document.createElement('div');
            const wrapperContent = document.createElement('div');

            wrapperScrollContent.classList.add(this.classNames.scrollContent);
            wrapperContent.classList.add(this.classNames.content);

            while (this.el.firstChild)
                wrapperContent.appendChild(this.el.firstChild)

            wrapperScrollContent.appendChild(wrapperContent);
            this.el.appendChild(wrapperScrollContent);
        }

        const track = document.createElement('div');
        const scrollbar = document.createElement('div');

        track.classList.add(this.classNames.track);
        scrollbar.classList.add(this.classNames.scrollbar);

        track.appendChild(scrollbar);

        this.trackX = track.cloneNode(true);
        this.trackX.classList.add('horizontal');

        this.trackY = track.cloneNode(true);
        this.trackY.classList.add('vertical');

        this.el.insertBefore(this.trackX, this.el.firstChild);
        this.el.insertBefore(this.trackY, this.el.firstChild);
    }

    initListeners() {
        // Event listeners
        if (this.options.autoHide) {
            this.el.addEventListener('mouseenter', this.flashScrollbar);
        }

        this.scrollbarX.addEventListener('mousedown', (e) => this.startDrag(e, 'x'));
        this.scrollbarY.addEventListener('mousedown', (e) => this.startDrag(e, 'y'));

        this.scrollContentEl.addEventListener('scroll', this.startScroll);

        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // create an observer instance
            this.observer = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    if (mutation.target === this.el || mutation.addedNodes.length) {
                        this.recalculate();
                    }
                });
            });

            // pass in the target node, as well as the observer options
            this.observer.observe(this.el, { attributes: true, childList: true, characterData: true, subtree: true });
        }
    }

    removeListeners() {
        // Event listeners
        if (this.options.autoHide) {
            this.el.removeEventListener('mouseenter', this.flashScrollbar);
        }

        this.scrollbarX.removeEventListener('mousedown', (e) => this.startDrag(e, 'x'));
        this.scrollbarY.removeEventListener('mousedown', (e) => this.startDrag(e, 'y'));

        this.scrollContentEl.removeEventListener('scroll', this.startScroll);

        this.observer && this.observer.disconnect();
    }

    /**
     * Start scrollbar handle drag
     */
    startDrag(e, axis = 'y') {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault()

        let scrollbar = axis === 'y' ? this.scrollbarY : this.scrollbarX;
        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        let eventOffset = axis === 'y' ? e.pageY : e.pageX;

        this.dragOffset[axis] = eventOffset - scrollbar.getBoundingClientRect()[this.offsetAttr[axis]];
        this.currentAxis = axis;

        document.addEventListener('mousemove', this.drag);
        document.addEventListener('mouseup', this.endDrag);
    }

    /**
     * Drag scrollbar handle
     */
    drag(e) {
        e.preventDefault();

        let eventOffset = this.currentAxis === 'y' ? e.pageY : e.pageX;
        let track = this.currentAxis === 'y' ? this.trackY : this.trackX;

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        let dragPos = eventOffset - track.getBoundingClientRect()[this.offsetAttr[this.currentAxis]] - this.dragOffset[this.currentAxis];

        // Convert the mouse position into a percentage of the scrollbar height/width.
        let dragPerc = dragPos / track[this.sizeAttr[this.currentAxis]];

        // Scroll the content by the same percentage.
        let scrollPos = dragPerc * this.contentEl[this.scrollSizeAttr[this.currentAxis]];

        this.scrollContentEl[this.scrollOffsetAttr[this.currentAxis]] = scrollPos;
    }

    /**
     * End scroll handle drag
     */
    endDrag() {
        document.removeEventListener('mousemove', this.drag);
        document.removeEventListener('mouseup', this.endDrag);
    }

    /**
     * Resize scrollbar
     */
    resizeScrollbar(axis = 'y') {
        let track;
        let scrollbar;

        if (axis === 'x') {
            track = this.trackX;
            scrollbar = this.scrollbarX;
        } else { // 'y'
            track = this.trackY;
            scrollbar = this.scrollbarY;
        }

        let contentSize     = this.contentEl[this.scrollSizeAttr[axis]];
        let scrollOffset    = this.scrollContentEl[this.scrollOffsetAttr[axis]]; // Either scrollTop() or scrollLeft().
        let scrollbarSize   = track[this.sizeAttr[axis]];
        let scrollbarRatio  = scrollbarSize / contentSize;
        let scrollPourcent  = scrollOffset / (contentSize - scrollbarSize);
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
        let handleSize      = Math.max(Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2, this.options.scrollbarMinSize);
        let handleOffset    = (scrollbarSize - 4 - handleSize) * scrollPourcent + 2;

        // Set isVisible to false if scrollbar is not necessary (content is shorter than wrapper)
        this.isVisible[axis] = scrollbarSize < contentSize

        if (this.isVisible[axis]) {
            track.style.visibility = 'visible';

            if (axis === 'x') {
                scrollbar.style.left = `${handleOffset}px`;
                scrollbar.style.width = `${handleSize}px`;
            } else {
                scrollbar.style.top = `${handleOffset}px`;
                scrollbar.style.height = `${handleSize}px`;
            }
        } else {
            track.style.visibility = 'hidden';
        }
    }

    /**
     * Resize content element
     */
    resizeScrollContent() {
        const _scrollbarWidth = scrollbarWidth();

        // If no X overflow
        if (this.contentEl.scrollWidth <= this.el.offsetWidth) {
            // If no Y overflow
            if (this.contentEl.scrollHeight <= this.el.offsetHeight) {
                this.scrollContentEl.style.width = 'auto';
                this.scrollContentEl.style.height = 'auto';
            } else { // If no X overflow && Y overflow
                this.scrollContentEl.style.width = `${this.el.offsetWidth + _scrollbarWidth}px`;
                this.scrollContentEl.style.height = `${this.el.offsetHeight}px`;
            }
        } else { // If X overflow
            // If If X overflow && no Y overflow
            if (this.contentEl.scrollHeight <= this.el.offsetHeight) {
                this.scrollContentEl.style.width = 'auto';
                this.scrollContentEl.style.height = `${this.el.offsetHeight + _scrollbarWidth}px`;
            } else { // If X overflow && Y overflow
                this.scrollContentEl.style.height = `${this.el.offsetHeight + _scrollbarWidth}px`;
                this.scrollContentEl.style.width = `${this.el.offsetWidth + _scrollbarWidth}px`;
            }
        }
    }

    /**
     * On scroll event handling
     */
    startScroll() {
        this.flashScrollbar();
    }

    /**
     * Flash scrollbar visibility
     */
    flashScrollbar() {
        this.resizeScrollbar('x');
        this.resizeScrollbar('y');
        this.showScrollbar('x');
        this.showScrollbar('y');
    }

    /**
     * Show scrollbar
     */
    showScrollbar(axis = 'y') {
        if (!this.isVisible[axis]) {
            return
        }

        if (axis === 'x') {
            this.scrollbarX.classList.add('visible');
        } else {
            this.scrollbarY.classList.add('visible');
        }

        if (!this.options.autoHide) {
            return
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout(this.hideScrollbar.bind(this), 1000);
    }

    /**
     * Hide Scrollbar
     */
    hideScrollbar() {
        this.scrollbarX.classList.remove('visible');
        this.scrollbarY.classList.remove('visible');

        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    }

    /**
     * Recalculate scrollbar
     */
    recalculate() {
        if (!this.enabled) return;

        this.resizeScrollContent();
        this.resizeScrollbar('x');
        this.resizeScrollbar('y');
    }

    /**
     * Getter for original scrolling element
     */
    getScrollElement() {
        return this.scrollContentEl;
    }

    /**
     * Getter for content element
     */
    getContentElement() {
        return this.contentEl;
    }

    /**
     * UnMount mutation observer and delete SimpleBar instance from DOM element
     */
    unMount() {
        this.removeListeners();
        this.el.SimpleBar = null;
    }
}

/**
 * HTML API
 */
SimpleBar.initHtmlApi();
<commit_msg>Recalculate when child node has been mutated<commit_after>import scrollbarWidth from 'scrollbarwidth'
import debounce from 'lodash.debounce'

import './simplebar.css'

export default class SimpleBar {
    constructor(element, options) {
        this.el = element;
        this.track;
        this.scrollbar;
        this.flashTimeout;
        this.contentEl          = this.el;
        this.scrollContentEl    = this.el;
        this.dragOffset         = { x: 0, y: 0 };
        this.isVisible          = { x: true, y: true };
        this.scrollOffsetAttr   = { x: 'scrollLeft', y: 'scrollTop' };
        this.sizeAttr           = { x: 'offsetWidth', y: 'offsetHeight' };
        this.scrollSizeAttr     = { x: 'scrollWidth', y: 'scrollHeight' };
        this.offsetAttr         = { x: 'left', y: 'top' };
        this.observer;
        this.currentAxis;
        this.enabled;

        this.options = Object.assign({}, SimpleBar.defaultOptions, options);
        this.classNames = this.options.classNames;

        this.flashScrollbar = this.flashScrollbar.bind(this);
        this.startScroll = this.startScroll.bind(this);
        this.startDrag = this.startDrag.bind(this);
        this.drag = this.drag.bind(this);
        this.endDrag = this.endDrag.bind(this);

        this.init();

        this.recalculate = debounce(this.recalculate, 100, { leading: true });
    }

    static get defaultOptions() {
        return {
            wrapContent: true,
            autoHide: true,
            forceEnabled: false,
            classNames: {
                content: 'simplebar-content',
                scrollContent: 'simplebar-scroll-content',
                scrollbar: 'simplebar-scrollbar',
                track: 'simplebar-track'
            },
            scrollbarMinSize: 10
        }
    }

    static get htmlAttributes() {
        return {
            autoHide: 'data-simplebar-autohide',
            forceEnabled: 'data-simplebar-force-enabled',
            scrollbarMinSize: 'data-simplebar-scrollbar-min-size'
        }
    }

    static initHtmlApi() {
        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // Mutation observer to observe dynamically added elements
            this.observer = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    Array.from(mutation.addedNodes).forEach(addedNode => {
                        if (addedNode.nodeType === 1) {
                            if (addedNode.hasAttribute('data-simplebar')) {
                                new SimpleBar(addedNode, SimpleBar.getElOptions(addedNode));
                            } else {
                                Array.from(addedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    new SimpleBar(el, SimpleBar.getElOptions(el));
                                });
                            }
                        }
                    });

                    Array.from(mutation.removedNodes).forEach(removedNode => {
                        if (removedNode.nodeType === 1) {
                            if (removedNode.hasAttribute('data-simplebar')) {
                                removedNode.SimpleBar && removedNode.SimpleBar.unMount();
                            } else {
                                Array.from(removedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    el.SimpleBar && el.SimpleBar.unMount();
                                });
                            }
                        }
                    });
                });
            });

            this.observer.observe(document, { childList: true, subtree: true });
        }

        // Instantiate elements already present on the page
        document.addEventListener('DOMContentLoaded', () => {
            Array.from(document.querySelectorAll('[data-simplebar]')).forEach(el => {
                new SimpleBar(el, SimpleBar.getElOptions(el));
            });
        });
    }

    // Helper function to retrieve options from element attributes
    static getElOptions(el) {
        const options = Object.keys(SimpleBar.htmlAttributes).reduce((acc, obj) => {
            const attribute = SimpleBar.htmlAttributes[obj];
            if (el.hasAttribute(attribute)) {
                acc[obj] = JSON.parse(el.getAttribute(attribute));
            }
            return acc;
        }, {});

        return options;
    }

    static removeObserver() {
        this.observer && this.observer.disconnect();
    }

    init() {
        // Save a reference to the instance, so we know this DOM node has already been instancied
        this.el.SimpleBar = this;

        // If scrollbar is a floating scrollbar, disable the plugin
        this.enabled = scrollbarWidth() !== 0;

        if (!this.enabled && !this.options.forceEnabled) {
            this.el.style.overflow = 'auto';

            return
        }

        this.initDOM();

        this.trackX = this.el.querySelector(`.${this.classNames.track}.horizontal`);
        this.trackY = this.el.querySelector(`.${this.classNames.track}.vertical`);

        this.scrollbarX = this.trackX.querySelector(`.${this.classNames.scrollbar}`);
        this.scrollbarY = this.trackY.querySelector(`.${this.classNames.scrollbar}`);
        this.scrollContentEl = this.el.querySelector('.' + this.classNames.scrollContent);
        this.contentEl = this.el.querySelector('.' + this.classNames.content);

        // Calculate content size
        this.recalculate();

        if (!this.options.autoHide) {
            this.showScrollbar('x');
            this.showScrollbar('y');
        }

        this.initListeners();
    }

    initDOM() {
        if (this.el.querySelectorAll(`.${this.classNames.content}`).length) {
            return;
        }

        // Prepare DOM
        if (this.options.wrapContent) {
            const wrapperScrollContent = document.createElement('div');
            const wrapperContent = document.createElement('div');

            wrapperScrollContent.classList.add(this.classNames.scrollContent);
            wrapperContent.classList.add(this.classNames.content);

            while (this.el.firstChild)
                wrapperContent.appendChild(this.el.firstChild)

            wrapperScrollContent.appendChild(wrapperContent);
            this.el.appendChild(wrapperScrollContent);
        }

        const track = document.createElement('div');
        const scrollbar = document.createElement('div');

        track.classList.add(this.classNames.track);
        scrollbar.classList.add(this.classNames.scrollbar);

        track.appendChild(scrollbar);

        this.trackX = track.cloneNode(true);
        this.trackX.classList.add('horizontal');

        this.trackY = track.cloneNode(true);
        this.trackY.classList.add('vertical');

        this.el.insertBefore(this.trackX, this.el.firstChild);
        this.el.insertBefore(this.trackY, this.el.firstChild);
    }

    initListeners() {
        // Event listeners
        if (this.options.autoHide) {
            this.el.addEventListener('mouseenter', this.flashScrollbar);
        }

        this.scrollbarX.addEventListener('mousedown', (e) => this.startDrag(e, 'x'));
        this.scrollbarY.addEventListener('mousedown', (e) => this.startDrag(e, 'y'));

        this.scrollContentEl.addEventListener('scroll', this.startScroll);

        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // create an observer instance
            this.observer = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    if (this.isChildNode(mutation.target) || mutation.addedNodes.length) {
                        this.recalculate();
                    }
                });
            });

            // pass in the target node, as well as the observer options
            this.observer.observe(this.el, { attributes: true, childList: true, characterData: true, subtree: true });
        }
    }

    removeListeners() {
        // Event listeners
        if (this.options.autoHide) {
            this.el.removeEventListener('mouseenter', this.flashScrollbar);
        }

        this.scrollbarX.removeEventListener('mousedown', (e) => this.startDrag(e, 'x'));
        this.scrollbarY.removeEventListener('mousedown', (e) => this.startDrag(e, 'y'));

        this.scrollContentEl.removeEventListener('scroll', this.startScroll);

        this.observer && this.observer.disconnect();
    }

    /**
     * Start scrollbar handle drag
     */
    startDrag(e, axis = 'y') {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault()

        let scrollbar = axis === 'y' ? this.scrollbarY : this.scrollbarX;
        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        let eventOffset = axis === 'y' ? e.pageY : e.pageX;

        this.dragOffset[axis] = eventOffset - scrollbar.getBoundingClientRect()[this.offsetAttr[axis]];
        this.currentAxis = axis;

        document.addEventListener('mousemove', this.drag);
        document.addEventListener('mouseup', this.endDrag);
    }

    /**
     * Drag scrollbar handle
     */
    drag(e) {
        e.preventDefault();

        let eventOffset = this.currentAxis === 'y' ? e.pageY : e.pageX;
        let track = this.currentAxis === 'y' ? this.trackY : this.trackX;

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        let dragPos = eventOffset - track.getBoundingClientRect()[this.offsetAttr[this.currentAxis]] - this.dragOffset[this.currentAxis];

        // Convert the mouse position into a percentage of the scrollbar height/width.
        let dragPerc = dragPos / track[this.sizeAttr[this.currentAxis]];

        // Scroll the content by the same percentage.
        let scrollPos = dragPerc * this.contentEl[this.scrollSizeAttr[this.currentAxis]];

        this.scrollContentEl[this.scrollOffsetAttr[this.currentAxis]] = scrollPos;
    }

    /**
     * End scroll handle drag
     */
    endDrag() {
        document.removeEventListener('mousemove', this.drag);
        document.removeEventListener('mouseup', this.endDrag);
    }

    /**
     * Resize scrollbar
     */
    resizeScrollbar(axis = 'y') {
        let track;
        let scrollbar;

        if (axis === 'x') {
            track = this.trackX;
            scrollbar = this.scrollbarX;
        } else { // 'y'
            track = this.trackY;
            scrollbar = this.scrollbarY;
        }

        let contentSize     = this.contentEl[this.scrollSizeAttr[axis]];
        let scrollOffset    = this.scrollContentEl[this.scrollOffsetAttr[axis]]; // Either scrollTop() or scrollLeft().
        let scrollbarSize   = track[this.sizeAttr[axis]];
        let scrollbarRatio  = scrollbarSize / contentSize;
        let scrollPourcent  = scrollOffset / (contentSize - scrollbarSize);
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
        let handleSize      = Math.max(Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2, this.options.scrollbarMinSize);
        let handleOffset    = (scrollbarSize - 4 - handleSize) * scrollPourcent + 2;

        // Set isVisible to false if scrollbar is not necessary (content is shorter than wrapper)
        this.isVisible[axis] = scrollbarSize < contentSize

        if (this.isVisible[axis]) {
            track.style.visibility = 'visible';

            if (axis === 'x') {
                scrollbar.style.left = `${handleOffset}px`;
                scrollbar.style.width = `${handleSize}px`;
            } else {
                scrollbar.style.top = `${handleOffset}px`;
                scrollbar.style.height = `${handleSize}px`;
            }
        } else {
            track.style.visibility = 'hidden';
        }
    }

    /**
     * Resize content element
     */
    resizeScrollContent() {
        const _scrollbarWidth = scrollbarWidth();

        // If no X overflow
        if (this.contentEl.scrollWidth <= this.el.offsetWidth) {
            // If no Y overflow
            if (this.contentEl.scrollHeight <= this.el.offsetHeight) {
                this.scrollContentEl.style.width = 'auto';
                this.scrollContentEl.style.height = 'auto';
            } else { // If no X overflow && Y overflow
                this.scrollContentEl.style.width = `${this.el.offsetWidth + _scrollbarWidth}px`;
                this.scrollContentEl.style.height = `${this.el.offsetHeight}px`;
            }
        } else { // If X overflow
            // If If X overflow && no Y overflow
            if (this.contentEl.scrollHeight <= this.el.offsetHeight) {
                this.scrollContentEl.style.width = 'auto';
                this.scrollContentEl.style.height = `${this.el.offsetHeight + _scrollbarWidth}px`;
            } else { // If X overflow && Y overflow
                this.scrollContentEl.style.height = `${this.el.offsetHeight + _scrollbarWidth}px`;
                this.scrollContentEl.style.width = `${this.el.offsetWidth + _scrollbarWidth}px`;
            }
        }
    }

    /**
     * On scroll event handling
     */
    startScroll() {
        this.flashScrollbar();
    }

    /**
     * Flash scrollbar visibility
     */
    flashScrollbar() {
        this.resizeScrollbar('x');
        this.resizeScrollbar('y');
        this.showScrollbar('x');
        this.showScrollbar('y');
    }

    /**
     * Show scrollbar
     */
    showScrollbar(axis = 'y') {
        if (!this.isVisible[axis]) {
            return
        }

        if (axis === 'x') {
            this.scrollbarX.classList.add('visible');
        } else {
            this.scrollbarY.classList.add('visible');
        }

        if (!this.options.autoHide) {
            return
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout(this.hideScrollbar.bind(this), 1000);
    }

    /**
     * Hide Scrollbar
     */
    hideScrollbar() {
        this.scrollbarX.classList.remove('visible');
        this.scrollbarY.classList.remove('visible');

        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    }

    /**
     * Recalculate scrollbar
     */
    recalculate() {
        if (!this.enabled) return;

        this.resizeScrollContent();
        this.resizeScrollbar('x');
        this.resizeScrollbar('y');
    }

    /**
     * Getter for original scrolling element
     */
    getScrollElement() {
        return this.scrollContentEl;
    }

    /**
     * Getter for content element
     */
    getContentElement() {
        return this.contentEl;
    }

    /**
     * UnMount mutation observer and delete SimpleBar instance from DOM element
     */
    unMount() {
        this.removeListeners();
        this.el.SimpleBar = null;
    }

    /**
     * Recursively walks up the parent nodes looking for this.el
     */
    isChildNode(el) {
        if (el === null) return false;
        if (el === this.el) return true

        return this.isChildNode(el.parentNode);
    }
}

/**
 * HTML API
 */
SimpleBar.initHtmlApi();
<|endoftext|>


<commit_before>;(function (factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        // Register as an anonymous AMD module:
        define(['jquery'], factory($, window, document, undefined));
    } else if (typeof exports === 'object') {
        // Node/CommonJS:
        factory(require('jquery'), window, document, undefined);
    } else {
        // Browser globals:
        factory(window.jQuery, window, document, undefined);
    }
}(function ( $, window, document, undefined ) {

    /**
     * Calculate scrollbar width
     *
     * Called only once as a constant variable: we assume that scrollbar width never change
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     */
    var SCROLLBAR_WIDTH = scrollbarWidth();

    function scrollbarWidth () {
        // Append a temporary scrolling element to the DOM, then measure
        // the difference between its outer and inner elements.
        var tempEl  = $('

'),
            width   = 0,
            widthMinusScrollbars = 0;

        $('body').append(tempEl);

        width = $(tempEl).innerWidth(),
        widthMinusScrollbars = $('div', tempEl).innerWidth();

        tempEl.remove();

        return (width - widthMinusScrollbars);
    }

    // SimpleBar Constructor
    function SimpleBar (element, options) {
        this.el = element,
        this.$el = $(element),
        this.$track,
        this.$scrollbar,
        this.dragOffset,
        this.flashTimeout,
        this.$contentEl         = this.$el,
        this.$scrollContentEl   = this.$el,
        this.scrollDirection    = 'vert',
        this.scrollOffsetAttr   = 'scrollTop',
        this.sizeAttr           = 'height',
        this.scrollSizeAttr     = 'scrollHeight',
        this.offsetAttr         = 'top';

        this.options = $.extend({}, SimpleBar.DEFAULTS, options);
        this.theme   = this.options.css;

        this.init();
    }

    SimpleBar.DEFAULTS = {
        wrapContent: true,
        autoHide: true,
        css: {
          container: 'simplebar',
          content: 'simplebar-content',
          scrollContent: 'simple-bar-scroll-content',
          scrollbar: 'simplebar-scrollbar',
          scrollbarTrack: 'simplebar-track'
        }
    };

    SimpleBar.prototype.init = function () {
        // If scrollbar is a floating scrollbar, disable the plugin
        if(SCROLLBAR_WIDTH === 0) {
          this.$el.css('overflow', 'auto');

          return;
        }

        if (this.$el.data('simplebar-direction') === 'horizontal' || this.$el.hasClass(this.theme.container + ' horizontal')){
            this.scrollDirection    = 'horiz';
            this.scrollOffsetAttr   = 'scrollLeft';
            this.sizeAttr           = 'width';
            this.scrollSizeAttr     = 'scrollWidth';
            this.offsetAttr         = 'left';
        }

        if (this.options.wrapContent) {
            this.$el.wrapInner('

');
        }

        this.$contentEl = this.$el.find('.' + this.theme.content);

        this.$el.prepend('

');
        this.$track = this.$el.find('.' + this.theme.scrollbarTrack);
        this.$scrollbar = this.$el.find('.' + this.theme.scrollbar);

        this.$scrollContentEl = this.$el.find('.' + this.theme.scrollContent);

        this.resizeScrollContent();

        if (this.options.autoHide) {
            this.$el.on('mouseenter', $.proxy(this.flashScrollbar, this));
        }

        this.$scrollbar.on('mousedown', $.proxy(this.startDrag, this));
        this.$scrollContentEl.on('scroll', $.proxy(this.startScroll, this));

        this.resizeScrollbar();

        if (!this.options.autoHide) {
            this.showScrollbar();
        }
    };

    /**
     * Start scrollbar handle drag
     */
    SimpleBar.prototype.startDrag = function (e) {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        var eventOffset = e.pageY;
        if (this.scrollDirection === 'horiz') {
            eventOffset = e.pageX;
        }
        this.dragOffset = eventOffset - this.$scrollbar.offset()[this.offsetAttr];

        $(document).on('mousemove', $.proxy(this.drag, this));
        $(document).on('mouseup', $.proxy(this.endDrag, this));
    };

    /**
     * Drag scrollbar handle
     */
    SimpleBar.prototype.drag = function (e) {
        e.preventDefault();

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        var eventOffset = e.pageY,
            dragPos     = null,
            dragPerc    = null,
            scrollPos   = null;

        if (this.scrollDirection === 'horiz') {
          eventOffset = e.pageX;
        }

        dragPos = eventOffset - this.$track.offset()[this.offsetAttr] - this.dragOffset;
        // Convert the mouse position into a percentage of the scrollbar height/width.
        dragPerc = dragPos / this.$track[this.sizeAttr]();
        // Scroll the content by the same percentage.
        scrollPos = dragPerc * this.$contentEl[0][this.scrollSizeAttr];

        this.$scrollContentEl[this.scrollOffsetAttr](scrollPos);
    };

    /**
     * End scroll handle drag
     */
    SimpleBar.prototype.endDrag = function () {
        $(document).off('mousemove', this.drag);
        $(document).off('mouseup', this.endDrag);
    };

    /**
     * Resize scrollbar
     */
    SimpleBar.prototype.resizeScrollbar = function () {
        if(SCROLLBAR_WIDTH === 0) {
            return;
        }

        var contentSize     = this.$contentEl[0][this.scrollSizeAttr],
            scrollOffset    = this.$scrollContentEl[this.scrollOffsetAttr](), // Either scrollTop() or scrollLeft().
            scrollbarSize   = this.$track[this.sizeAttr](),
            scrollbarRatio  = scrollbarSize / contentSize,
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
            handleOffset    = Math.round(scrollbarRatio * scrollOffset) + 2,
            handleSize      = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

        if (scrollbarSize < contentSize) {
            if (this.scrollDirection === 'vert'){
                this.$scrollbar.css({'top': handleOffset, 'height': handleSize});
            } else {
                this.$scrollbar.css({'left': handleOffset, 'width': handleSize});
            }
            this.$track.show();
        } else {
            this.$track.hide();
        }
    };

    /**
     * On scroll event handling
     */
    SimpleBar.prototype.startScroll = function(e) {
        // Simulate event bubbling to root element
        this.$el.trigger(e);

        this.flashScrollbar();
    };

    /**
     * Flash scrollbar visibility
     */
    SimpleBar.prototype.flashScrollbar = function () {
        this.resizeScrollbar();
        this.showScrollbar();
    };

    /**
     * Show scrollbar
     */
    SimpleBar.prototype.showScrollbar = function () {
        this.$scrollbar.addClass('visible');

        if (!this.options.autoHide) {
            return;
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout($.proxy(this.hideScrollbar, this), 1000);
    };

    /**
     * Hide Scrollbar
     */
    SimpleBar.prototype.hideScrollbar = function () {
        this.$scrollbar.removeClass('visible');
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    };

    /**
     * Resize content element
     */
    SimpleBar.prototype.resizeScrollContent = function () {
        var is_firefox = /firefox/i.test(navigator.userAgent);
        if (! is_firefox) {
            return;
        }
        if (this.scrollDirection === 'vert'){
            this.$scrollContentEl.width(this.$el.width()+SCROLLBAR_WIDTH);
            this.$scrollContentEl.height(this.$el.height());
        } else {
            this.$scrollContentEl.width(this.$el.width());
            this.$scrollContentEl.height(this.$el.height()+SCROLLBAR_WIDTH);
        }
    };

    /**
     * Recalculate scrollbar
     */
    SimpleBar.prototype.recalculate = function () {
        this.resizeScrollContent();
        this.resizeScrollbar();
    };

    /**
     * Getter for original scrolling element
     */
    SimpleBar.prototype.getScrollElement = function () {
        return this.$scrollContentEl;
    };

    /**
     * Getter for content element
     */
    SimpleBar.prototype.getContentElement = function () {
        return this.$contentEl;
    };

    /**
     * Data API
     */
    $(window).on('load', function () {
        $('[data-simplebar-direction]').each(function () {
            $(this).simplebar();
        });
    });

    /**
     * Plugin definition
     */
    var old = $.fn.simplebar;

    $.fn.simplebar = function (options) {
        var args = arguments,
            returns;

        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === 'undefined' || typeof options === 'object') {
            return this.each(function () {

                // Only allow the plugin to be instantiated once,
                // so we check that the element has no plugin instantiation yet
                if (!$.data(this, 'simplebar')) { $.data(this, 'simplebar', new SimpleBar(this, options)); }
            });

        // If the first parameter is a string
        // treat this as a call to a public method.
        } else if (typeof options === 'string') {
            this.each(function () {
                var instance = $.data(this, 'simplebar');

                // Tests that there's already a plugin-instance
                // and checks that the requested public method exists
                if (instance instanceof SimpleBar && typeof instance[options] === 'function') {

                    // Call the method of our plugin instance,
                    // and pass it the supplied arguments.
                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
                }

                // Allow instances to be destroyed via the 'destroy' method
                if (options === 'destroy') {
                  $.data(this, 'simplebar', null);
                }
            });

            // If the earlier cached method
            // gives a value back return the value,
            // otherwise return this to preserve chainability.
            return returns !== undefined ? returns : this;
        }
    };

    $.fn.simplebar.Constructor = SimpleBar;

    /**
     * No conflict
     */
    $.fn.simplebar.noConflict = function () {
        $.fn.simplebar = old;
        return this;
    };

}));
<commit_msg>Fixes class-name "simplebar-content"<commit_after>;(function (factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        // Register as an anonymous AMD module:
        define(['jquery'], factory($, window, document, undefined));
    } else if (typeof exports === 'object') {
        // Node/CommonJS:
        factory(require('jquery'), window, document, undefined);
    } else {
        // Browser globals:
        factory(window.jQuery, window, document, undefined);
    }
}(function ( $, window, document, undefined ) {

    /**
     * Calculate scrollbar width
     *
     * Called only once as a constant variable: we assume that scrollbar width never change
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     */
    var SCROLLBAR_WIDTH = scrollbarWidth();

    function scrollbarWidth () {
        // Append a temporary scrolling element to the DOM, then measure
        // the difference between its outer and inner elements.
        var tempEl  = $('

'),
            width   = 0,
            widthMinusScrollbars = 0;

        $('body').append(tempEl);

        width = $(tempEl).innerWidth(),
        widthMinusScrollbars = $('div', tempEl).innerWidth();

        tempEl.remove();

        return (width - widthMinusScrollbars);
    }

    // SimpleBar Constructor
    function SimpleBar (element, options) {
        this.el = element,
        this.$el = $(element),
        this.$track,
        this.$scrollbar,
        this.dragOffset,
        this.flashTimeout,
        this.$contentEl         = this.$el,
        this.$scrollContentEl   = this.$el,
        this.scrollDirection    = 'vert',
        this.scrollOffsetAttr   = 'scrollTop',
        this.sizeAttr           = 'height',
        this.scrollSizeAttr     = 'scrollHeight',
        this.offsetAttr         = 'top';

        this.options = $.extend({}, SimpleBar.DEFAULTS, options);
        this.theme   = this.options.css;

        this.init();
    }

    SimpleBar.DEFAULTS = {
        wrapContent: true,
        autoHide: true,
        css: {
          container: 'simplebar',
          content: 'simplebar-content',
          scrollContent: 'simplebar-scroll-content',
          scrollbar: 'simplebar-scrollbar',
          scrollbarTrack: 'simplebar-track'
        }
    };

    SimpleBar.prototype.init = function () {
        // If scrollbar is a floating scrollbar, disable the plugin
        if(SCROLLBAR_WIDTH === 0) {
          this.$el.css('overflow', 'auto');

          return;
        }

        if (this.$el.data('simplebar-direction') === 'horizontal' || this.$el.hasClass(this.theme.container + ' horizontal')){
            this.scrollDirection    = 'horiz';
            this.scrollOffsetAttr   = 'scrollLeft';
            this.sizeAttr           = 'width';
            this.scrollSizeAttr     = 'scrollWidth';
            this.offsetAttr         = 'left';
        }

        if (this.options.wrapContent) {
            this.$el.wrapInner('

');
        }

        this.$contentEl = this.$el.find('.' + this.theme.content);

        this.$el.prepend('

');
        this.$track = this.$el.find('.' + this.theme.scrollbarTrack);
        this.$scrollbar = this.$el.find('.' + this.theme.scrollbar);

        this.$scrollContentEl = this.$el.find('.' + this.theme.scrollContent);

        this.resizeScrollContent();

        if (this.options.autoHide) {
            this.$el.on('mouseenter', $.proxy(this.flashScrollbar, this));
        }

        this.$scrollbar.on('mousedown', $.proxy(this.startDrag, this));
        this.$scrollContentEl.on('scroll', $.proxy(this.startScroll, this));

        this.resizeScrollbar();

        if (!this.options.autoHide) {
            this.showScrollbar();
        }
    };

    /**
     * Start scrollbar handle drag
     */
    SimpleBar.prototype.startDrag = function (e) {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        var eventOffset = e.pageY;
        if (this.scrollDirection === 'horiz') {
            eventOffset = e.pageX;
        }
        this.dragOffset = eventOffset - this.$scrollbar.offset()[this.offsetAttr];

        $(document).on('mousemove', $.proxy(this.drag, this));
        $(document).on('mouseup', $.proxy(this.endDrag, this));
    };

    /**
     * Drag scrollbar handle
     */
    SimpleBar.prototype.drag = function (e) {
        e.preventDefault();

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        var eventOffset = e.pageY,
            dragPos     = null,
            dragPerc    = null,
            scrollPos   = null;

        if (this.scrollDirection === 'horiz') {
          eventOffset = e.pageX;
        }

        dragPos = eventOffset - this.$track.offset()[this.offsetAttr] - this.dragOffset;
        // Convert the mouse position into a percentage of the scrollbar height/width.
        dragPerc = dragPos / this.$track[this.sizeAttr]();
        // Scroll the content by the same percentage.
        scrollPos = dragPerc * this.$contentEl[0][this.scrollSizeAttr];

        this.$scrollContentEl[this.scrollOffsetAttr](scrollPos);
    };

    /**
     * End scroll handle drag
     */
    SimpleBar.prototype.endDrag = function () {
        $(document).off('mousemove', this.drag);
        $(document).off('mouseup', this.endDrag);
    };

    /**
     * Resize scrollbar
     */
    SimpleBar.prototype.resizeScrollbar = function () {
        if(SCROLLBAR_WIDTH === 0) {
            return;
        }

        var contentSize     = this.$contentEl[0][this.scrollSizeAttr],
            scrollOffset    = this.$scrollContentEl[this.scrollOffsetAttr](), // Either scrollTop() or scrollLeft().
            scrollbarSize   = this.$track[this.sizeAttr](),
            scrollbarRatio  = scrollbarSize / contentSize,
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
            handleOffset    = Math.round(scrollbarRatio * scrollOffset) + 2,
            handleSize      = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

        if (scrollbarSize < contentSize) {
            if (this.scrollDirection === 'vert'){
                this.$scrollbar.css({'top': handleOffset, 'height': handleSize});
            } else {
                this.$scrollbar.css({'left': handleOffset, 'width': handleSize});
            }
            this.$track.show();
        } else {
            this.$track.hide();
        }
    };

    /**
     * On scroll event handling
     */
    SimpleBar.prototype.startScroll = function(e) {
        // Simulate event bubbling to root element
        this.$el.trigger(e);

        this.flashScrollbar();
    };

    /**
     * Flash scrollbar visibility
     */
    SimpleBar.prototype.flashScrollbar = function () {
        this.resizeScrollbar();
        this.showScrollbar();
    };

    /**
     * Show scrollbar
     */
    SimpleBar.prototype.showScrollbar = function () {
        this.$scrollbar.addClass('visible');

        if (!this.options.autoHide) {
            return;
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout($.proxy(this.hideScrollbar, this), 1000);
    };

    /**
     * Hide Scrollbar
     */
    SimpleBar.prototype.hideScrollbar = function () {
        this.$scrollbar.removeClass('visible');
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    };

    /**
     * Resize content element
     */
    SimpleBar.prototype.resizeScrollContent = function () {
        var is_firefox = /firefox/i.test(navigator.userAgent);
        if (! is_firefox) {
            return;
        }
        if (this.scrollDirection === 'vert'){
            this.$scrollContentEl.width(this.$el.width()+SCROLLBAR_WIDTH);
            this.$scrollContentEl.height(this.$el.height());
        } else {
            this.$scrollContentEl.width(this.$el.width());
            this.$scrollContentEl.height(this.$el.height()+SCROLLBAR_WIDTH);
        }
    };

    /**
     * Recalculate scrollbar
     */
    SimpleBar.prototype.recalculate = function () {
        this.resizeScrollContent();
        this.resizeScrollbar();
    };

    /**
     * Getter for original scrolling element
     */
    SimpleBar.prototype.getScrollElement = function () {
        return this.$scrollContentEl;
    };

    /**
     * Getter for content element
     */
    SimpleBar.prototype.getContentElement = function () {
        return this.$contentEl;
    };

    /**
     * Data API
     */
    $(window).on('load', function () {
        $('[data-simplebar-direction]').each(function () {
            $(this).simplebar();
        });
    });

    /**
     * Plugin definition
     */
    var old = $.fn.simplebar;

    $.fn.simplebar = function (options) {
        var args = arguments,
            returns;

        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === 'undefined' || typeof options === 'object') {
            return this.each(function () {

                // Only allow the plugin to be instantiated once,
                // so we check that the element has no plugin instantiation yet
                if (!$.data(this, 'simplebar')) { $.data(this, 'simplebar', new SimpleBar(this, options)); }
            });

        // If the first parameter is a string
        // treat this as a call to a public method.
        } else if (typeof options === 'string') {
            this.each(function () {
                var instance = $.data(this, 'simplebar');

                // Tests that there's already a plugin-instance
                // and checks that the requested public method exists
                if (instance instanceof SimpleBar && typeof instance[options] === 'function') {

                    // Call the method of our plugin instance,
                    // and pass it the supplied arguments.
                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
                }

                // Allow instances to be destroyed via the 'destroy' method
                if (options === 'destroy') {
                  $.data(this, 'simplebar', null);
                }
            });

            // If the earlier cached method
            // gives a value back return the value,
            // otherwise return this to preserve chainability.
            return returns !== undefined ? returns : this;
        }
    };

    $.fn.simplebar.Constructor = SimpleBar;

    /**
     * No conflict
     */
    $.fn.simplebar.noConflict = function () {
        $.fn.simplebar = old;
        return this;
    };

}));
<|endoftext|>


<commit_before>var gpio0 = 0;
var gpio1 = gpio0+32;
var gpio2 = gpio1+32;
var gpio3 = gpio2+32;

exports.bone =
{
    P8_1: { name: "DGND" },
    P8_2: { name: "DGND" },
    P8_3: { name: "GPIO1_6", gpio: gpio1+6, mux: "gpmc_ad6", eeprom: 26 },
    P8_4: { name: "GPIO1_7", gpio: gpio1+7, mux: "gpmc_ad7", eeprom: 27 },
    P8_5: { name: "GPIO1_2", gpio: gpio1+2, mux: "gpmc_ad2", eeprom: 22 },
    P8_6: { name: "GPIO1_3", gpio: gpio1+3, mux: "gpmc_ad3", eeprom: 23 },
    P8_7: { name: "TIMER4", gpio: gpio2+2, mux: "gpmc_advn_ale", eeprom: 41 },
    P8_8: { name: "TIMER7", gpio: gpio2+3, mux: "gpmc_oen_ren", eeprom: 44 },
    P8_9: { name: "TIMER5", gpio: gpio2+5, mux: "gpmc_ben0_cle", eeprom: 42 },
    P8_10: { name: "TIMER6", gpio: gpio2+4, mux: "gpmc_wen", eeprom: 43 },
    P8_11: { name: "GPIO1_13", gpio: gpio1+13, mux: "gpmc_ad13", eeprom: 29 },
    P8_12: { name: "GPIO1_12", gpio: gpio1+12, mux: "gpmc_ad12", eeprom: 28 },
    P8_13: { name: "EHRPWM2B", gpio: gpio0+23, mux: "gpmc_ad9", eeprom: 15 },
    P8_14: { name: "GPIO0_26", gpio: gpio0+26, mux: "gpmc_ad10", eeprom: 16 },
    P8_15: { name: "GPIO1_15", gpio: gpio1+15, mux: "gpmc_ad15", eeprom: 31 },
    P8_16: { name: "GPIO1_14", gpio: gpio1+14, mux: "gpmc_ad14", eeprom: 30 },
    P8_17: { name: "GPIO0_27", gpio: gpio0+27, mux: "gpmc_ad11", eeprom: 17 },
    P8_18: { name: "GPIO2_1", gpio: gpio2+1, mux: "gpmc_clk", eeprom: 40 },
    P8_19: { name: "EHRPWM2A", gpio: gpio0+22, mux: "gpmc_ad8", eeprom: 14 },
    P8_20: { name: "GPIO1_31", gpio: gpio1+31, mux: "gpmc_csn2", eeprom: 39 },
    P8_21: { name: "GPIO1_30", gpio: gpio1+30, mux: "gpmc_csn1", eeprom: 38 },
    P8_22: { name: "GPIO1_5", gpio: gpio1+5, mux: "gpmc_ad5", eeprom: 25 },
    P8_23: { name: "GPIO1_4", gpio: gpio1+4, mux: "gpmc_ad4", eeprom: 24 },
    P8_24: { name: "GPIO1_1", gpio: gpio1+1, mux: "gpmc_ad1", eeprom: 21 },
    P8_25: { name: "GPIO1_0", gpio: gpio1+0, mux: "gpmc_ad0", eeprom: 20 },
    P8_26: { name: "GPIO1_29", gpio: gpio1+29, mux: "gpmc_csn0", eeprom: 37 },
    P8_27: { name: "GPIO2_22", gpio: gpio2+22, mux: "lcd_vsync", eeprom: 57 },
    P8_28: { name: "GPIO2_24", gpio: gpio2+24, mux: "lcd_pclk", eeprom: 59 },
    P8_29: { name: "GPIO2_23", gpio: gpio2+23, mux: "lcd_hclk", eeprom: 58 },
    P8_30: { name: "GPIO2_25", gpio: gpio2+25, mux: "lcd_ac_bias_en", eeprom: 60 },
    P8_31: { name: "UART5_CTSN", gpio: gpio0+10, mux: "lcd_data14", eeprom: 7 },
    P8_32: { name: "UART5_RTSN", gpio: gpio0+11, mux: "lcd_data15", eeprom: 8 },
    P8_33: { name: "UART4_RTSN", gpio: gpio0+9, mux: "lcd_data13", eeprom: 6 },
    P8_34: { name: "UART3_RTSN", gpio: gpio2+17, mux: "lcd_data11", eeprom: 56 },
    P8_35: { name: "UART4_CTSN", gpio: gpio0+8, mux: "lcd_data12", eeprom: 5 },
    P8_36: { name: "UART3_CTSN", gpio: gpio2+16, mux: "lcd_data10", eeprom: 55 },
    P8_37: { name: "UART5_TXD", gpio: gpio2+14, mux: "lcd_data8", eeprom: 53 },
    P8_38: { name: "UART5_RXD", gpio: gpio2+15, mux: "lcd_data9", eeprom: 54 },
    P8_39: { name: "GPIO2_12", gpio: gpio2+12, mux: "lcd_data6", eeprom: 51 },
    P8_40: { name: "GPIO2_13", gpio: gpio2+13, mux: "lcd_data7", eeprom: 52 },
    P8_41: { name: "GPIO2_10", gpio: gpio2+10, mux: "lcd_data4", eeprom: 49 },
    P8_42: { name: "GPIO2_11", gpio: gpio2+11, mux: "lcd_data5", eeprom: 50 },
    P8_43: { name: "GPIO2_8", gpio: gpio2+8, mux: "lcd_data2", eeprom: 47 },
    P8_44: { name: "GPIO2_9", gpio: gpio2+9, mux: "lcd_data3", eeprom: 48 },
    P8_45: { name: "GPIO2_6", gpio: gpio2+6, mux: "lcd_data0", eeprom: 45 },
    P8_46: { name: "GPIO2_7", gpio: gpio2+7, mux: "lcd_data1", eeprom: 46 },
    P9_1: { name: "DGND" },
    P9_2: { name: "DGND" },
    P9_3: { name: "VDD_3V3" },
    P9_4: { name: "VDD_3V3" },
    P9_5: { name: "VDD_5V" },
    P9_6: { name: "VDD_5V" },
    P9_7: { name: "SYS_5V" },
    P9_8: { name: "SYS_5V" },
    P9_9: { name: "PWR_BUT" },
    P9_10: { name: "SYS_RESETn" },
    P9_11: { name: "UART4_RXD", gpio: gpio0+30, mux: "gpmc_wait0", eeprom: 18 },
    P9_12: { name: "GPIO1_28", gpio: gpio1+28, mux: "gpmc_ben1", eeprom: 36 },
    P9_13: { name: "UART4_TXD", gpio: gpio0+31, mux: "gpmc_wpn", eeprom: 19 },
    P9_14: { name: "EHRPWM1A", gpio: gpio1+18, mux: "gpmc_a2", eeprom: 34 },
    P9_15: { name: "UART3_RXD", gpio: gpio2+18, mux: "mii1_rxd3", eeprom: 32 },
    P9_16: { name: "EHRPWM1B", gpio: gpio1+19, mux: "gpmc_a3", eeprom: 35 },
    P9_17: { name: "I2C1_SCL", gpio: gpio0+5, mux: "spi0_cs0", eeprom: 3 },
    P9_18: { name: "I2C1_SDA", gpio: gpio0+4, mux: "spi0_d1", eeprom: 2 },
    P9_19: { name: "I2C2_SCL", gpio: gpio0+13, mux: "uart1_rtsn", eeprom: 9 },
    P9_20: { name: "I2C2_SDA", gpio: gpio0+12, mux: "uart1_ctsn", eeprom: 10 },
    P9_21: { name: "UART2_TXD", gpio: gpio0+3, mux: "spi0_d0", eeprom: 1 },
    P9_22: { name: "UART2_RXD", gpio: gpio0+2, mux: "spi0_sclk", eeprom: 0 },
    P9_23: { name: "UART3_TXD", gpio: gpio0+7, mux: "ecap0_in_pwm0_out", eeprom: 33 },
    P9_24: { name: "UART1_TXD", gpio: gpio0+15, mux: "uart1_txd", eeprom: 12 },
    P9_25: { name: "GPIO3_21", gpio: gpio3+21, mux: "mcasp0_ahclkx", eeprom: 66 },
    P9_26: { name: "UART1_RXD", gpio: gpio0+14, mux: "uart1_rxd", eeprom: 11 },
    P9_27: { name: "GPIO3_19", gpio: gpio3+19, mux: "mcasp0_fsr", eeprom: 64 },
    P9_28: { name: "SPI1_CS0", gpio: gpio3+17, mux: "mcasp0_ahclkr", eeprom: 63 },
    P9_29: { name: "SPI1_D0", gpio: gpio3+15, mux: "mcasp0_fsx", eeprom: 61 },
    P9_30: { name: "SPI1_D1", gpio: gpio3+16, mux: "mcasp0_axr0", eeprom: 62 },
    P9_31: { name: "SPI1_SCLK", gpio: gpio3+14, mux: "mcasp0_aclkx", eeprom: 65 },
    P9_32: { name: "VDD_ADC" },
    P9_33: { name: "AIN4", eeprom: 71 },
    P9_34: { name: "GNDA_ADC" },
    P9_35: { name: "AIN6", eeprom: 73 },
    P9_36: { name: "AIN5", eeprom: 72 },
    P9_37: { name: "AIN2", eeprom: 69 },
    P9_38: { name: "AIN3", eeprom: 70 },
    P9_39: { name: "AIN0", eeprom: 67 },
    P9_40: { name: "AIN1", eeprom: 68 },
    P9_41: { name: "CLKOUT2", gpio: gpio0+20, mux: "xdma_event_intr1", eeprom: 13 },
    P9_42: { name: "GPIO0_7", gpio: gpio0+7, mux: "ecap0_in_pwm0_out", eeprom: 4 },
    P9_43: { name: "DGND" },
    P9_44: { name: "DGND" },
    P9_45: { name: "DGND" },
    P9_46: { name: "DGND" },
    USR0: { name: "USR0", gpio: gpio1+21, led: "usr0", mux: "gpmc_a5" },
    USR1: { name: "USR1", gpio: gpio1+22, led: "usr1", mux: "gpmc_a6" },
    USR2: { name: "USR2", gpio: gpio1+23, led: "usr2", mux: "gpmc_a7" },
    USR3: { name: "USR3", gpio: gpio1+24, led: "usr3", mux: "gpmc_a8" }
};
<commit_msg>bonescript: fix P8_29 mux name<commit_after>var gpio0 = 0;
var gpio1 = gpio0+32;
var gpio2 = gpio1+32;
var gpio3 = gpio2+32;

exports.bone =
{
    P8_1: { name: "DGND" },
    P8_2: { name: "DGND" },
    P8_3: { name: "GPIO1_6", gpio: gpio1+6, mux: "gpmc_ad6", eeprom: 26 },
    P8_4: { name: "GPIO1_7", gpio: gpio1+7, mux: "gpmc_ad7", eeprom: 27 },
    P8_5: { name: "GPIO1_2", gpio: gpio1+2, mux: "gpmc_ad2", eeprom: 22 },
    P8_6: { name: "GPIO1_3", gpio: gpio1+3, mux: "gpmc_ad3", eeprom: 23 },
    P8_7: { name: "TIMER4", gpio: gpio2+2, mux: "gpmc_advn_ale", eeprom: 41 },
    P8_8: { name: "TIMER7", gpio: gpio2+3, mux: "gpmc_oen_ren", eeprom: 44 },
    P8_9: { name: "TIMER5", gpio: gpio2+5, mux: "gpmc_ben0_cle", eeprom: 42 },
    P8_10: { name: "TIMER6", gpio: gpio2+4, mux: "gpmc_wen", eeprom: 43 },
    P8_11: { name: "GPIO1_13", gpio: gpio1+13, mux: "gpmc_ad13", eeprom: 29 },
    P8_12: { name: "GPIO1_12", gpio: gpio1+12, mux: "gpmc_ad12", eeprom: 28 },
    P8_13: { name: "EHRPWM2B", gpio: gpio0+23, mux: "gpmc_ad9", eeprom: 15 },
    P8_14: { name: "GPIO0_26", gpio: gpio0+26, mux: "gpmc_ad10", eeprom: 16 },
    P8_15: { name: "GPIO1_15", gpio: gpio1+15, mux: "gpmc_ad15", eeprom: 31 },
    P8_16: { name: "GPIO1_14", gpio: gpio1+14, mux: "gpmc_ad14", eeprom: 30 },
    P8_17: { name: "GPIO0_27", gpio: gpio0+27, mux: "gpmc_ad11", eeprom: 17 },
    P8_18: { name: "GPIO2_1", gpio: gpio2+1, mux: "gpmc_clk", eeprom: 40 },
    P8_19: { name: "EHRPWM2A", gpio: gpio0+22, mux: "gpmc_ad8", eeprom: 14 },
    P8_20: { name: "GPIO1_31", gpio: gpio1+31, mux: "gpmc_csn2", eeprom: 39 },
    P8_21: { name: "GPIO1_30", gpio: gpio1+30, mux: "gpmc_csn1", eeprom: 38 },
    P8_22: { name: "GPIO1_5", gpio: gpio1+5, mux: "gpmc_ad5", eeprom: 25 },
    P8_23: { name: "GPIO1_4", gpio: gpio1+4, mux: "gpmc_ad4", eeprom: 24 },
    P8_24: { name: "GPIO1_1", gpio: gpio1+1, mux: "gpmc_ad1", eeprom: 21 },
    P8_25: { name: "GPIO1_0", gpio: gpio1+0, mux: "gpmc_ad0", eeprom: 20 },
    P8_26: { name: "GPIO1_29", gpio: gpio1+29, mux: "gpmc_csn0", eeprom: 37 },
    P8_27: { name: "GPIO2_22", gpio: gpio2+22, mux: "lcd_vsync", eeprom: 57 },
    P8_28: { name: "GPIO2_24", gpio: gpio2+24, mux: "lcd_pclk", eeprom: 59 },
    P8_29: { name: "GPIO2_23", gpio: gpio2+23, mux: "lcd_vsync", eeprom: 58 },
    P8_30: { name: "GPIO2_25", gpio: gpio2+25, mux: "lcd_ac_bias_en", eeprom: 60 },
    P8_31: { name: "UART5_CTSN", gpio: gpio0+10, mux: "lcd_data14", eeprom: 7 },
    P8_32: { name: "UART5_RTSN", gpio: gpio0+11, mux: "lcd_data15", eeprom: 8 },
    P8_33: { name: "UART4_RTSN", gpio: gpio0+9, mux: "lcd_data13", eeprom: 6 },
    P8_34: { name: "UART3_RTSN", gpio: gpio2+17, mux: "lcd_data11", eeprom: 56 },
    P8_35: { name: "UART4_CTSN", gpio: gpio0+8, mux: "lcd_data12", eeprom: 5 },
    P8_36: { name: "UART3_CTSN", gpio: gpio2+16, mux: "lcd_data10", eeprom: 55 },
    P8_37: { name: "UART5_TXD", gpio: gpio2+14, mux: "lcd_data8", eeprom: 53 },
    P8_38: { name: "UART5_RXD", gpio: gpio2+15, mux: "lcd_data9", eeprom: 54 },
    P8_39: { name: "GPIO2_12", gpio: gpio2+12, mux: "lcd_data6", eeprom: 51 },
    P8_40: { name: "GPIO2_13", gpio: gpio2+13, mux: "lcd_data7", eeprom: 52 },
    P8_41: { name: "GPIO2_10", gpio: gpio2+10, mux: "lcd_data4", eeprom: 49 },
    P8_42: { name: "GPIO2_11", gpio: gpio2+11, mux: "lcd_data5", eeprom: 50 },
    P8_43: { name: "GPIO2_8", gpio: gpio2+8, mux: "lcd_data2", eeprom: 47 },
    P8_44: { name: "GPIO2_9", gpio: gpio2+9, mux: "lcd_data3", eeprom: 48 },
    P8_45: { name: "GPIO2_6", gpio: gpio2+6, mux: "lcd_data0", eeprom: 45 },
    P8_46: { name: "GPIO2_7", gpio: gpio2+7, mux: "lcd_data1", eeprom: 46 },
    P9_1: { name: "DGND" },
    P9_2: { name: "DGND" },
    P9_3: { name: "VDD_3V3" },
    P9_4: { name: "VDD_3V3" },
    P9_5: { name: "VDD_5V" },
    P9_6: { name: "VDD_5V" },
    P9_7: { name: "SYS_5V" },
    P9_8: { name: "SYS_5V" },
    P9_9: { name: "PWR_BUT" },
    P9_10: { name: "SYS_RESETn" },
    P9_11: { name: "UART4_RXD", gpio: gpio0+30, mux: "gpmc_wait0", eeprom: 18 },
    P9_12: { name: "GPIO1_28", gpio: gpio1+28, mux: "gpmc_ben1", eeprom: 36 },
    P9_13: { name: "UART4_TXD", gpio: gpio0+31, mux: "gpmc_wpn", eeprom: 19 },
    P9_14: { name: "EHRPWM1A", gpio: gpio1+18, mux: "gpmc_a2", eeprom: 34 },
    P9_15: { name: "UART3_RXD", gpio: gpio2+18, mux: "mii1_rxd3", eeprom: 32 },
    P9_16: { name: "EHRPWM1B", gpio: gpio1+19, mux: "gpmc_a3", eeprom: 35 },
    P9_17: { name: "I2C1_SCL", gpio: gpio0+5, mux: "spi0_cs0", eeprom: 3 },
    P9_18: { name: "I2C1_SDA", gpio: gpio0+4, mux: "spi0_d1", eeprom: 2 },
    P9_19: { name: "I2C2_SCL", gpio: gpio0+13, mux: "uart1_rtsn", eeprom: 9 },
    P9_20: { name: "I2C2_SDA", gpio: gpio0+12, mux: "uart1_ctsn", eeprom: 10 },
    P9_21: { name: "UART2_TXD", gpio: gpio0+3, mux: "spi0_d0", eeprom: 1 },
    P9_22: { name: "UART2_RXD", gpio: gpio0+2, mux: "spi0_sclk", eeprom: 0 },
    P9_23: { name: "UART3_TXD", gpio: gpio0+7, mux: "ecap0_in_pwm0_out", eeprom: 33 },
    P9_24: { name: "UART1_TXD", gpio: gpio0+15, mux: "uart1_txd", eeprom: 12 },
    P9_25: { name: "GPIO3_21", gpio: gpio3+21, mux: "mcasp0_ahclkx", eeprom: 66 },
    P9_26: { name: "UART1_RXD", gpio: gpio0+14, mux: "uart1_rxd", eeprom: 11 },
    P9_27: { name: "GPIO3_19", gpio: gpio3+19, mux: "mcasp0_fsr", eeprom: 64 },
    P9_28: { name: "SPI1_CS0", gpio: gpio3+17, mux: "mcasp0_ahclkr", eeprom: 63 },
    P9_29: { name: "SPI1_D0", gpio: gpio3+15, mux: "mcasp0_fsx", eeprom: 61 },
    P9_30: { name: "SPI1_D1", gpio: gpio3+16, mux: "mcasp0_axr0", eeprom: 62 },
    P9_31: { name: "SPI1_SCLK", gpio: gpio3+14, mux: "mcasp0_aclkx", eeprom: 65 },
    P9_32: { name: "VDD_ADC" },
    P9_33: { name: "AIN4", eeprom: 71 },
    P9_34: { name: "GNDA_ADC" },
    P9_35: { name: "AIN6", eeprom: 73 },
    P9_36: { name: "AIN5", eeprom: 72 },
    P9_37: { name: "AIN2", eeprom: 69 },
    P9_38: { name: "AIN3", eeprom: 70 },
    P9_39: { name: "AIN0", eeprom: 67 },
    P9_40: { name: "AIN1", eeprom: 68 },
    P9_41: { name: "CLKOUT2", gpio: gpio0+20, mux: "xdma_event_intr1", eeprom: 13 },
    P9_42: { name: "GPIO0_7", gpio: gpio0+7, mux: "ecap0_in_pwm0_out", eeprom: 4 },
    P9_43: { name: "DGND" },
    P9_44: { name: "DGND" },
    P9_45: { name: "DGND" },
    P9_46: { name: "DGND" },
    USR0: { name: "USR0", gpio: gpio1+21, led: "usr0", mux: "gpmc_a5" },
    USR1: { name: "USR1", gpio: gpio1+22, led: "usr1", mux: "gpmc_a6" },
    USR2: { name: "USR2", gpio: gpio1+23, led: "usr2", mux: "gpmc_a7" },
    USR3: { name: "USR3", gpio: gpio1+24, led: "usr3", mux: "gpmc_a8" }
};
<|endoftext|>


<commit_before>function removeOverlayipb336310() {
    var a = document.getElementById("ovipb336310");
    a && (a.style.opacity = 0, a.parentNode.removeChild(document.getElementById("ovipb336310")))
}
if (!document.getElementById("ovipb336310")) {
    var o = document.createElement("div");
    o.setAttribute("id", "ovipb336310");
    var textStyle = "-webkit-text-size-adjust: none; font-family: Helvetica, Arial, sans-serif; font-weight: bold; line-height: 1.0; letter-spacing: normal; font-variant: normal; font-style: normal;";
    o.setAttribute("style", "position: fixed; z-index: 2147483647; left: 0; top: 0; width: 100%; height: 100%; font-size: 25px; opacity: 0.9; -webkit-transition: opacity 0.25s linear; text-align: center; padding: 200px 0 0 0; margin: 0; background-color: #333; color: #F2F2F2; " + textStyle);
    var o1 = document.createElement("span");
    o1.setAttribute("id", "omipb336310");
    o1.setAttribute("style", textStyle);
    o1.appendChild(document.createTextNode("VidCast " + String.fromCharCode(8594)));
    o.appendChild(o1);
    o1 = document.createElement("div");
    o1.setAttribute("id", "ocipb336310");
    o1.setAttribute("style", "cursor:pointer;margin: 35px auto; width: 120px; font-size: 15px; padding: 10px; color: #ccc; background-color: black; border: 1px solid #aaa;");
    o1.setAttribute("onclick", "removeOverlayipb336310();");
    o1.appendChild(document.createTextNode("Cancel"));
    o.appendChild(o1);
    document.body.appendChild(o);
    Array.prototype.clean = function(a) {
        for (var b = 0; b < this.length; b++) this[b] == a && (this.splice(b, 1), b--);
        return this
    };
    var pattern = RegExp("(https:\/\/redirector.googlevideo.com\/videoplayback)[A-Za-z0-9%?=&:/._-].*", "ig"),
        matches = [],
        matches = document.documentElement.innerHTML.match(pattern);
    if (-1 != window.location.href.indexOf("ted.com")) {
        var ted_pattern = RegExp("(http)(.){5}(download.ted.com)(.){2}(talks)(.){2}[A-Za-z0-9_?.=&]*(.mp4)[A-Za-z0-9_?.=&]*",
                "ig"),
            ted_matches = document.documentElement.innerHTML.match(ted_pattern);
        ted_matches && (matches = matches.concat(ted_matches))
    }
    if (-1 != window.location.href.indexOf("dailymotion.com")) {
        var dm_html = document.documentElement.innerHTML,
            dm_html = unescape(dm_html),
            dm_html = unescape(dm_html);
        (dm_matches = dm_html.match(pattern)) && (matches = matches.concat(dm_matches))
    }
    if (-1 != window.location.href.indexOf("khanacademy.org")) {
        var khan_pattern = RegExp("(https:\/\/redirector.googlevideo.com\/videoplayback)[A-Za-z0-9%?=&:/._-].*",
                "ig"),
            khan_matches = document.documentElement.innerHTML.match(khan_pattern);
        khan_matches && (matches = matches.concat(khan_matches))
    }
    var priority = [];
    if (matches && 0 < matches.length) {
        for (i = 0; i < matches.length; i++)
            if (-1 != matches[i].indexOf("facebook.com%5C%2F")) {
                var fb_pattern = RegExp("(http(s)?)[A-Za-z0-9%?=&:\\/._-]*[.]{1}(mp4|webm|ogg)([?]{1}[A-Za-z0-9%?=&:/.-_;-]*)?", "ig"),
                    fb_matches = [],
                    decoded_match = decodeURIComponent(matches[i]),
                    decoded_match = decoded_match.replace(/\\/g, "");
                (fb_matches = decoded_match.match(fb_pattern)) &&
                0 < fb_matches.length ? priority[0] = fb_matches[0] : priority[5] = matches[i]
            } else -1 != matches[i].indexOf("lookbackvideo") ? (fb_pattern = RegExp("(http(s)?)[A-Za-z0-9%?=&:\\/._-]*[.]{1}(mp4|webm|ogg)([?]{1}[A-Za-z0-9?=&:/.-_;-]*)?", "ig"), fb_matches = [], decoded_match = decodeURIComponent(matches[i]), decoded_match = decoded_match.replace(/\\/g, ""), (fb_matches = decoded_match.match(fb_pattern)) && 0 < fb_matches.length ? priority[0] = fb_matches[0] : priority[5] = matches[i]) : -1 != matches[i].indexOf("download.ted.com") ? priority[0] =
                matches[i].replace(/\\/g, "") : -1 != matches[i].indexOf("1080") ? priority[1] = matches[i] : -1 != matches[i].indexOf("720") ? priority[2] = matches[i] : -1 != matches[i].indexOf("480") ? priority[3] = matches[i] : priority[5] = matches[i];
        priority.clean(void 0);
        var match = priority[0]; - 1 != match.indexOf("phncdn.com") && (match = match.replace(/&/g, "&"));
        window.location = "https://vidcast.dabble.me/?video_link=" + encodeURIComponent(match)
    } else document.getElementById("omipb336310").innerHTML = "No MP4, WEBM, or OGG files found on this page",
        setTimeout(function() {
            removeOverlayipb336310()
        }, 1800)
};
<commit_msg>changed<commit_after>function removeOverlayipb336310() {
    var a = document.getElementById("ovipb336310");
    a && (a.style.opacity = 0, a.parentNode.removeChild(document.getElementById("ovipb336310")))
}
if (!document.getElementById("ovipb336310")) {
    var o = document.createElement("div");
    o.setAttribute("id", "ovipb336310");
    var textStyle = "-webkit-text-size-adjust: none; font-family: Helvetica, Arial, sans-serif; font-weight: bold; line-height: 1.0; letter-spacing: normal; font-variant: normal; font-style: normal;";
    o.setAttribute("style", "position: fixed; z-index: 2147483647; left: 0; top: 0; width: 100%; height: 100%; font-size: 25px; opacity: 0.9; -webkit-transition: opacity 0.25s linear; text-align: center; padding: 200px 0 0 0; margin: 0; background-color: #333; color: #F2F2F2; " + textStyle);
    var o1 = document.createElement("span");
    o1.setAttribute("id", "omipb336310");
    o1.setAttribute("style", textStyle);
    o1.appendChild(document.createTextNode("VidCast " + String.fromCharCode(8594)));
    o.appendChild(o1);
    o1 = document.createElement("div");
    o1.setAttribute("id", "ocipb336310");
    o1.setAttribute("style", "cursor:pointer;margin: 35px auto; width: 120px; font-size: 15px; padding: 10px; color: #ccc; background-color: black; border: 1px solid #aaa;");
    o1.setAttribute("onclick", "removeOverlayipb336310();");
    o1.appendChild(document.createTextNode("Cancel"));
    o.appendChild(o1);
    document.body.appendChild(o);
    Array.prototype.clean = function(a) {
        for (var b = 0; b < this.length; b++) this[b] == a && (this.splice(b, 1), b--);
        return this
    };
    var pattern = RegExp("(https:\/\/redirector.googlevideo.com\/videoplayback)[A-Za-z0-9%?=&:/._-].*[^" jw\-played=">]", "ig"),
        matches = [],
        matches = document.documentElement.innerHTML.match(pattern);
    if (-1 != window.location.href.indexOf("ted.com")) {
        var ted_pattern = RegExp("(http)(.){5}(download.ted.com)(.){2}(talks)(.){2}[A-Za-z0-9_?.=&]*(.mp4)[A-Za-z0-9_?.=&]*",
                "ig"),
            ted_matches = document.documentElement.innerHTML.match(ted_pattern);
        ted_matches && (matches = matches.concat(ted_matches))
    }
    if (-1 != window.location.href.indexOf("dailymotion.com")) {
        var dm_html = document.documentElement.innerHTML,
            dm_html = unescape(dm_html),
            dm_html = unescape(dm_html);
        (dm_matches = dm_html.match(pattern)) && (matches = matches.concat(dm_matches))
    }
    if (-1 != window.location.href.indexOf("khanacademy.org")) {
        var khan_pattern = RegExp("(https:\/\/redirector.googlevideo.com\/videoplayback)[A-Za-z0-9%?=&:/._-].*",
                "ig"),
            khan_matches = document.documentElement.innerHTML.match(khan_pattern);
        khan_matches && (matches = matches.concat(khan_matches))
    }
    var priority = [];
    if (matches && 0 < matches.length) {
        for (i = 0; i < matches.length; i++)
            if (-1 != matches[i].indexOf("facebook.com%5C%2F")) {
                var fb_pattern = RegExp("(http(s)?)[A-Za-z0-9%?=&:\\/._-]*[.]{1}(mp4|webm|ogg)([?]{1}[A-Za-z0-9%?=&:/.-_;-]*)?", "ig"),
                    fb_matches = [],
                    decoded_match = decodeURIComponent(matches[i]),
                    decoded_match = decoded_match.replace(/\\/g, "");
                (fb_matches = decoded_match.match(fb_pattern)) &&
                0 < fb_matches.length ? priority[0] = fb_matches[0] : priority[5] = matches[i]
            } else -1 != matches[i].indexOf("lookbackvideo") ? (fb_pattern = RegExp("(http(s)?)[A-Za-z0-9%?=&:\\/._-]*[.]{1}(mp4|webm|ogg)([?]{1}[A-Za-z0-9?=&:/.-_;-]*)?", "ig"), fb_matches = [], decoded_match = decodeURIComponent(matches[i]), decoded_match = decoded_match.replace(/\\/g, ""), (fb_matches = decoded_match.match(fb_pattern)) && 0 < fb_matches.length ? priority[0] = fb_matches[0] : priority[5] = matches[i]) : -1 != matches[i].indexOf("download.ted.com") ? priority[0] =
                matches[i].replace(/\\/g, "") : -1 != matches[i].indexOf("1080") ? priority[1] = matches[i] : -1 != matches[i].indexOf("720") ? priority[2] = matches[i] : -1 != matches[i].indexOf("480") ? priority[3] = matches[i] : priority[5] = matches[i];
        priority.clean(void 0);
        var match = priority[0]; - 1 != match.indexOf("phncdn.com") && (match = match.replace(/&/g, "&"));
        window.location = "https://vidcast.dabble.me/?video_link=" + encodeURIComponent(match)
    } else document.getElementById("omipb336310").innerHTML = "No MP4, WEBM, or OGG files found on this page",
        setTimeout(function() {
            removeOverlayipb336310()
        }, 1800)
};
<|endoftext|>