<commit_before>/*
 * inflates a trial/stimulus/media
 * this function is responsible for inheritance from the sets
 *
 * function inflate(source,type)
 * where source is the script for a component, and type is the type of component (trial/stimulus/media)
 *
 * the function returns an inflated script object (to be parsed by the constuctors)
 */
define(['jquery','./trial/trial_sets','./stimulus/stimulus_sets','./media/media_sets'],function($,trialSets,stimulusSets,mediaSets){

	var customize = function customize(source){
		// check for a custome function and run it if it exists
		if (typeof source.customize === 'function'){
			source.customize.apply(source, [source]);
			// remove customize function so that it gets called only once (don't delete because - performance)
			source.customize = null;
		}
		return source;
	};

	var inflate = function(source,type){

		var sets
			, inherit
			, parent
			, child;

		switch (type) {
			case 'trial': sets = trialSets(); break;
			case 'stimulus': sets = stimulusSets(); break;
			case 'media': sets = mediaSets(); break;
			default:
				throw new Error('Unknown set type ' + type);
		}

		// if we do not need to inherit anything, simply return source
		if (!source.inherit) {
			customize(source);
			return source;
		}

		//if the inherit object is not an abject then it is probably a string and refers to a vanila set
		inherit = $.isPlainObject(source.inherit) ? source.inherit : {set:source.inherit};

		// make sure we know the set we're inheriting from
		if (!sets[inherit.set]) {
			throw new Error('Unknown '+ type +'Set: ' + inherit.set);
		}

		// get parent
		parent = inflate(sets[inherit.set].inherit(inherit),type);

		// create inflated child
		child = $.extend(true,{},source);
		$.each(parent, function(key, value){
			// if this key is not set yet, copy it out of the parent (choose the copy method according to the type of data)
			if (!child[key]){
				// arrays
				if ($.isArray(parent[key])){
					child[key] = $.extend(true, [], value);
				}
				// objects
				else if (typeof parent[key] === 'object'){
					child[key] = $.extend(true, {}, value);
				}
				// primitives
				else {
					child[key] = value;
				}
			}
		});

		// we want to extend the childs data even if it already exists
		if (parent.data){
			child.data = $.extend(true, {}, parent.data, child.data);
		}

		// personal customization functions
		customize(child);

		// return inflated trial
		return child;
	};

	return inflate;
});<commit_msg>customize recursion fix<commit_after>/*
 * inflates a trial/stimulus/media
 * this function is responsible for inheritance from the sets
 *
 * function inflate(source,type)
 * where source is the script for a component, and type is the type of component (trial/stimulus/media)
 *
 * the function returns an inflated script object (to be parsed by the constuctors)
 */
define(['jquery','./trial/trial_sets','./stimulus/stimulus_sets','./media/media_sets'],function($,trialSets,stimulusSets,mediaSets){

	var customize = function customize(source){
		// check for a custom function and run it if it exists
		if (typeof source.customize === 'function'){
			source.customize.apply(source, [source]);
			// remove customize function so that it gets called only once (don't delete because - performance)
			//source.customize = null;
		}
		return source;
	};

	// @param source - object to inflate
	// @param type - trial stimulus or media
	// @param recursive - whether this is a recursive call or not
	var inflate = function(source,type, recursive){

		var sets
			, inherit
			, parent
			, child;

		switch (type) {
			case 'trial': sets = trialSets(); break;
			case 'stimulus': sets = stimulusSets(); break;
			case 'media': sets = mediaSets(); break;
			default:
				throw new Error('Unknown set type ' + type);
		}

		// if we do not need to inherit anything, simply return source
		if (!source.inherit) {
			!recursive && customize(source);
			return source;
		}

		//if the inherit object is not an abject then it is probably a string and refers to a vanila set
		inherit = $.isPlainObject(source.inherit) ? source.inherit : {set:source.inherit};

		// make sure we know the set we're inheriting from
		if (!sets[inherit.set]) {
			throw new Error('Unknown '+ type +'Set: ' + inherit.set);
		}

		// get parent (recursively)
		parent = inflate(sets[inherit.set].inherit(inherit),type, true);

		// create inflated child
		child = $.extend(true,{},source);

		$.each(parent, function(key, value){
			// if this key is not set yet, copy it out of the parent (choose the copy method according to the type of data)
			if (!child[key]){
				// arrays
				if ($.isArray(parent[key])){
					child[key] = $.extend(true, [], value);
				}
				// objects
				else if (typeof parent[key] === 'object'){
					child[key] = $.extend(true, {}, value);
				}
				// primitives
				else {
					child[key] = value;
				}
			}
		});

		// we want to extend the childs data even if it already exists
		if (parent.data){
			child.data = $.extend(true, {}, parent.data, child.data);
		}

		// Personal customization functions - only if this is the last iteration of inflate
		// This way the customize function gets called only once.
		!recursive && customize(child);

		// return inflated trial
		return child;
	};

	return inflate;
});<|endoftext|>


<commit_before>/*eslint no-new-func:0*/
"use strict";
var JSONF = {
  stringify: function(object) {
    return JSON.stringify(object, this._serializer);
  },
  parse: function(jsonString) {
    return JSON.parse(jsonString, this._deserializer);
  },
  _serializer: function(key, value) {
    // Is a FUNCTION or REGEXP ?
    if (typeof (value) === "function" || typeof value.test === "function") {
      return value.toString();
    }
    return value;
  },
  _deserializer: function(key, value) {
    if (key === "" && typeof value === "string" && value.indexOf("function") !== 0 && value.indexOf("/") !== 0) {
      return value;
    }

    if (typeof value === "string") {
      var rfunc = /^function\s*\((.*?)\).*?\{([\s\S]*)\}/m;
      var rregexp = /^\/(.*?)\/$/m;
      var match = value.match(rfunc);

      // Function?
      if (match) {
        var args = match[1].split(',').map(function(arg) {
          return arg.replace(/\s+/, '');
        });
        return new Function(args, match[2].trim());
      }

      // RegEx?
      match = value.match(rregexp);
      if (match) {
        return new RegExp(match[1]);
      }
    }
    return value;
  }
};
<commit_msg>prettify stringify output<commit_after>/*eslint no-new-func:0*/
"use strict";
var JSONF = {
  stringify: function(object) {
    return JSON.stringify(object, this._serializer, 2);
  },
  parse: function(jsonString) {
    return JSON.parse(jsonString, this._deserializer);
  },
  _serializer: function(key, value) {
    // Is a FUNCTION or REGEXP ?
    if (typeof (value) === "function" || typeof value.test === "function") {
      return value.toString();
    }
    return value;
  },
  _deserializer: function(key, value) {
    if (key === "" && typeof value === "string" && value.indexOf("function") !== 0 && value.indexOf("/") !== 0) {
      return value;
    }

    if (typeof value === "string") {
      var rfunc = /^function\s*\((.*?)\).*?\{([\s\S]*)\}/m;
      var rregexp = /^\/(.*?)\/$/m;
      var match = value.match(rfunc);

      // Function?
      if (match) {
        var args = match[1].split(',').map(function(arg) {
          return arg.replace(/\s+/, '');
        });
        return new Function(args, match[2].trim());
      }

      // RegEx?
      match = value.match(rregexp);
      if (match) {
        return new RegExp(match[1]);
      }
    }
    return value;
  }
};
<|endoftext|>


<commit_before>import page from 'page';

page('*', show);
page('*', show404);
page();

const header = document.querySelector('header.main');
const nav = document.querySelector('nav.main');
const body = document.body;

function isNumber(val) {
  return typeof val === 'number' && (parseInt(val) === parseInt(val));
}

function show(ctx, next) {
  let selector = (ctx.pathname === '/')
                 ? ctx.pathname = '#♥'
                 : ctx.pathname.replace('/', '#');

  const target = document.querySelector(selector);

  if (!target) {
    return next();
  }

  let {offsetTop} = target;
  if (body && body.className.indexOf('scrolled') === -1) {
    if (nav && nav.clientHeight) {
      offsetTop -= nav.clientHeight;
    }
  }

  if (isNumber(offsetTop)) {
    window.scrollTo(0, offsetTop);
  } else {
    next();
  }
}

function show404() {
  console.log('404');
}
<commit_msg>replace # in links<commit_after>import page from 'page';

page('*', show);
page('*', show404);
page();

const header = document.querySelector('header.main');
const nav = document.querySelector('nav.main');
const body = document.body;

const allLinks = document.querySelectorAll('a');

Object.keys(allLinks).forEach(key => {
  const link = allLinks[key];
  if (link && link.href) {
    const hrefArray = link.href.split('#');
    if (hrefArray.length) {
      link.href = hrefArray.join('');
    }
  }
});

function isNumber(val) {
  return typeof val === 'number' && (parseInt(val) === parseInt(val));
}

function show(ctx, next) {
  let selector = (ctx.pathname === '/')
                 ? ctx.pathname = '#♥'
                 : ctx.pathname.replace('/', '#');

  const target = document.querySelector(selector);

  if (!target) {
    return next();
  }

  let {offsetTop} = target;
  if (body && body.className.indexOf('scrolled') === -1) {
    if (nav && nav.clientHeight) {
      offsetTop -= nav.clientHeight;
    }
  }

  if (isNumber(offsetTop)) {
    window.scrollTo(0, offsetTop);
  } else {
    next();
  }
}

function show404() {
  console.log('404');
}
<|endoftext|>


<commit_before>/**
 * Lazy Plugin
 * @version 2.3.4
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;(function($, window, document, undefined) {

	/**
	 * Creates the lazy plugin.
	 * @class The Lazy Plugin
	 * @param {Owl} carousel - The Owl Carousel
	 */
	var Lazy = function(carousel) {

		/**
		 * Reference to the core.
		 * @protected
		 * @type {Owl}
		 */
		this._core = carousel;

		/**
		 * Already loaded items.
		 * @protected
		 * @type {Array.<jQuery>}
		 */
		this._loaded = [];

		/**
		 * Event handlers.
		 * @protected
		 * @type {Object}
		 */
		this._handlers = {
			'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
				if (!e.namespace) {
					return;
				}

				if (!this._core.settings || !this._core.settings.lazyLoad) {
					return;
				}

				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
					var settings = this._core.settings,
						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
						i = ((settings.center && n * -1) || 0),
						position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
						clones = this._core.clones().length,
						load = $.proxy(function(i, v) { this.load(v) }, this);
					//TODO: Need documentation for this new option
					if (settings.lazyLoadEager > 0) {
						n += settings.lazyLoadEager;
						// If the carousel is looping also preload images that are to the "left"
						if (settings.loop) {
              position -= settings.lazyLoadEager;
              n++;
            }
					}

					while (i++ < n) {
						this.load(clones / 2 + this._core.relative(position));
						clones && $.each(this._core.clones(this._core.relative(position)), load);
						position++;
					}
				}
			}, this)
		};

		// set the default options
		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);

		// register event handler
		this._core.$element.on(this._handlers);
	};

	/**
	 * Default options.
	 * @public
	 */
	Lazy.Defaults = {
		lazyLoad: false,
		lazyLoadEager: 0
	};

	/**
	 * Loads all resources of an item at the specified position.
	 * @param {Number} position - The absolute position of the item.
	 * @protected
	 */
	Lazy.prototype.load = function(position) {
		var $item = this._core.$stage.children().eq(position),
			$elements = $item && $item.find('.owl-lazy');

		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
			return;
		}

		$elements.each($.proxy(function(index, element) {
			var $element = $(element), image,
                url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');

			this._core.trigger('load', { element: $element, url: url }, 'lazy');

			if ($element.is('img')) {
				$element.one('load.owl.lazy', $.proxy(function() {
					$element.css('opacity', 1);
					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
				}, this)).attr('src', url);
            } else if ($element.is('source')) {
                $element.one('load.owl.lazy', $.proxy(function() {
                    this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
                }, this)).attr('srcset', url);
			} else {
				image = new Image();
				image.onload = $.proxy(function() {
					$element.css({
						'background-image': 'url("' + url + '")',
						'opacity': '1'
					});
					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
				}, this);
				image.src = url;
			}
		}, this));

		this._loaded.push($item.get(0));
	};

	/**
	 * Destroys the plugin.
	 * @public
	 */
	Lazy.prototype.destroy = function() {
		var handler, property;

		for (handler in this.handlers) {
			this._core.$element.off(handler, this.handlers[handler]);
		}
		for (property in Object.getOwnPropertyNames(this)) {
			typeof this[property] != 'function' && (this[property] = null);
		}
	};

	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;

})(window.Zepto || window.jQuery, window, document);
<commit_msg>#2176 changes from PR - fix lazy loading when using stagepadding<commit_after>/**
 * Lazy Plugin
 * @version 2.3.4
 * @author Bartosz Wojciechowski
 * @author David Deutsch
 * @license The MIT License (MIT)
 */
;(function($, window, document, undefined) {

	/**
	 * Creates the lazy plugin.
	 * @class The Lazy Plugin
	 * @param {Owl} carousel - The Owl Carousel
	 */
	var Lazy = function(carousel) {

		/**
		 * Reference to the core.
		 * @protected
		 * @type {Owl}
		 */
		this._core = carousel;

		/**
		 * Already loaded items.
		 * @protected
		 * @type {Array.<jQuery>}
		 */
		this._loaded = [];

		/**
		 * Event handlers.
		 * @protected
		 * @type {Object}
		 */
		this._handlers = {
			'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
				if (!e.namespace) {
					return;
				}

				if (!this._core.settings || !this._core.settings.lazyLoad) {
					return;
				}

				if ((e.property && e.property.name === 'position') || e.type === 'initialized' || e.type === 'resized') {
					var settings = this._core.settings,
						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
						i = ((settings.center && n * -1) || 0),
						position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
						clones = this._core.clones().length,
						load = $.proxy(function(i, v) { this.load(v) }, this);

					if (settings.lazyLoadEager > 0) {
						n += settings.lazyLoadEager;
						// If the carousel is looping also preload images that are to the "left"
						if (settings.loop) {
              position -= settings.lazyLoadEager;
              n++;
            }
					}

          if (!settings.center && settings.stagePadding) {
						position--;
						n += 2;
          }

					while (i++ < n) {
						this.load(clones / 2 + this._core.relative(position));
						clones && $.each(this._core.clones(this._core.relative(position)), load);
						position++;
					}
				}
			}, this)
		};

		// set the default options
		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);

		// register event handler
		this._core.$element.on(this._handlers);
	};

	/**
	 * Default options.
	 * @public
	 */
	Lazy.Defaults = {
		lazyLoad: false,
		lazyLoadEager: 0
	};

	/**
	 * Loads all resources of an item at the specified position.
	 * @param {Number} position - The absolute position of the item.
	 * @protected
	 */
	Lazy.prototype.load = function(position) {
		var $item = this._core.$stage.children().eq(position),
			$elements = $item && $item.find('.owl-lazy');

		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
			return;
		}

		$elements.each($.proxy(function(index, element) {
			var $element = $(element), image,
                url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');

			this._core.trigger('load', { element: $element, url: url }, 'lazy');

			if ($element.is('img')) {
				$element.one('load.owl.lazy', $.proxy(function() {
					$element.css('opacity', 1);
					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
				}, this)).attr('src', url);
            } else if ($element.is('source')) {
                $element.one('load.owl.lazy', $.proxy(function() {
                    this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
                }, this)).attr('srcset', url);
			} else {
				image = new Image();
				image.onload = $.proxy(function() {
					$element.css({
						'background-image': 'url("' + url + '")',
						'opacity': '1'
					});
					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
				}, this);
				image.src = url;
			}
		}, this));

		this._loaded.push($item.get(0));
	};

	/**
	 * Destroys the plugin.
	 * @public
	 */
	Lazy.prototype.destroy = function() {
		var handler, property;

		for (handler in this.handlers) {
			this._core.$element.off(handler, this.handlers[handler]);
		}
		for (property in Object.getOwnPropertyNames(this)) {
			typeof this[property] != 'function' && (this[property] = null);
		}
	};

	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;

})(window.Zepto || window.jQuery, window, document);
<|endoftext|>


<commit_before>define(function(require, exports) {
    'use strict';
    var $ = require('core/selector'),
        Page = require('base/page'),
        changePage,
        getPrevPage,
        buildPage,
        pages = {},
        firstInitial = true,
        prevPageName,
        $body = $('body'),
        pageClass = {
            help: Page
        };
    changePage = function (pageName, data) {
        var prevPage = getPrevPage(prevPageName),
            pg = pages[pageName];
        if (prevPage) {
            //有上一页则将之隐藏
            prevPage.hide();
        }
        //页面没有创建过
        if (!pg) {
            //写出回调的原因是这个过程可能是异步的，因为代码需要远程加载
            buildPage(pageName, function (page) {
                pg = page;
                pg.render(data);
            });
        } else {
            //页面已经创建，直接显示
            pg.show();
        }
        prevPageName = pageName;
    };
    buildPage = function (pageName, callback) {
        var PageClass = pageClass[pageName],
            createPage = function (pageName, PageClass) {
                var pg;
                //构建页面
                pg = pages[pageName] = new PageClass({
                    name: pageName,
                    tpl: ['page', pageName].join('.'),
                    parent: $body
                });
                pg.on('beforerender', function (evt, page) {
                    //如果要加载的页面没有页面模板，则不清空Body
                    if (page.hasTplContent && firstInitial) {
                        $body.empty();
                    }
                    console.debug('准备渲染页面' + page.getName());
                }).on('afterrender', function (evt, page) {
                    console.debug('成功渲染页面' + page.getName());
                }).on('beforerenderfirstcomponent', function (evt, page) {
                    //如果渲染第一个组件的时候，这个页面是没有加载成功的,hasTplContent = false
                    //这个时候body是没有清空的,需要清空body
                    if (!page.hasTplContent) {
                        if (firstInitial) {
                            $body.empty();
                        }
                        page.empty();
                        //取消第一次初始化的标志
                    } else {
                        page.empty();
                    }
                    firstInitial = false;
                    console.log('渲染第一个组件' + page.getName());
                }).on('pagerendered', function (evt, page) {
                    console.debug('渲染页面' + page.getName() + '结束');
                });
                return pg;
            };
        //没有构建函数
        if (!PageClass) {
            //异步加载组件代码
            require.async('page/' + pageName, function (PageClass) {
                pageClass[pageName] = PageClass;
                if (typeof callback === 'function') {
                    callback(createPage(pageName, PageClass));
                }
            });
        } else {
            //已有构建函数，同步
            if (typeof callback === 'function') {
                callback(createPage(pageName, PageClass));
            }
        }
    };
    getPrevPage = function () {
        return pages[prevPageName];
    };
    exports.changePage = changePage;
});<commit_msg>整个页面渲染结束之后才改变第一次渲染的状态<commit_after>define(function(require, exports) {
    'use strict';
    var $ = require('core/selector'),
        Page = require('base/page'),
        changePage,
        getPrevPage,
        buildPage,
        pages = {},
        firstInitial = true,
        prevPageName,
        $body = $('body'),
        pageClass = {
            help: Page
        };
    changePage = function (pageName, data) {
        var prevPage = getPrevPage(prevPageName),
            pg = pages[pageName];
        if (prevPage) {
            //有上一页则将之隐藏
            prevPage.hide();
        }
        //页面没有创建过
        if (!pg) {
            //写出回调的原因是这个过程可能是异步的，因为代码需要远程加载
            buildPage(pageName, function (page) {
                pg = page;
                pg.render(data);
            });
        } else {
            //页面已经创建，直接显示
            pg.show();
        }
        prevPageName = pageName;
    };
    buildPage = function (pageName, callback) {
        var PageClass = pageClass[pageName],
            createPage = function (pageName, PageClass) {
                var pg;
                //构建页面
                pg = pages[pageName] = new PageClass({
                    name: pageName,
                    tpl: ['page', pageName].join('.'),
                    parent: $body
                });
                pg.on('beforerender', function (evt, page) {
                    //如果要加载的页面没有页面模板，则不清空Body
                    if (page.hasTplContent && firstInitial) {
                        $body.empty();
                    }
                    console.debug('准备渲染页面' + page.getName());
                }).on('afterrender', function (evt, page) {
                    console.debug('成功渲染页面' + page.getName());
                }).on('beforerenderfirstcomponent', function (evt, page) {
                    //如果渲染第一个组件的时候，这个页面是没有加载成功的,hasTplContent = false
                    //这个时候body是没有清空的,需要清空body
                    if (!page.hasTplContent) {
                        if (firstInitial) {
                            $body.empty();
                        }
                        page.empty();
                        //取消第一次初始化的标志
                    } else {
                        page.empty();
                    }
                    console.log('渲染第一个组件' + page.getName());
                }).on('pagerendered', function (evt, page) {
                    console.debug('渲染页面' + page.getName() + '结束');
                    firstInitial = false;
                });
                return pg;
            };
        //没有构建函数
        if (!PageClass) {
            //异步加载组件代码
            require.async('page/' + pageName, function (PageClass) {
                pageClass[pageName] = PageClass;
                if (typeof callback === 'function') {
                    callback(createPage(pageName, PageClass));
                }
            });
        } else {
            //已有构建函数，同步
            if (typeof callback === 'function') {
                callback(createPage(pageName, PageClass));
            }
        }
    };
    getPrevPage = function () {
        return pages[prevPageName];
    };
    exports.changePage = changePage;
});<|endoftext|>


<commit_before>exports.Remote           = require('./remote').Remote;
exports.Request          = require('./request').Request;
exports.Amount           = require('./amount').Amount;
exports.Currency         = require('./currency').Currency;
exports.Base             = require('./base').Base;
exports.UInt160          = require('./amount').UInt160;
exports.Seed             = require('./amount').Seed;
exports.Transaction      = require('./transaction').Transaction;
exports.Meta             = require('./meta').Meta;
exports.SerializedObject = require('./serializedobject').SerializedObject;
exports.RippleError      = require('./rippleerror').RippleError;

exports.binformat        = require('./binformat');
exports.utils            = require('./utils');
exports.Server           = require('./server').Server;

// Important: We do not guarantee any specific version of SJCL or for any
// specific features to be included. The version and configuration may change at
// any time without warning.
//
// However, for programs that are tied to a specific version of ripple.js like
// the official client, it makes sense to expose the SJCL instance so we don't
// have to include it twice.
exports.sjcl      = require('./utils').sjcl;

exports.config    = require('./config');

// vim:sw=2:sts=2:ts=8:et
<commit_msg>API conversion<commit_after>exports.Remote           = require('./remote').Remote;
exports.Request          = require('./request').Request;
exports.Amount           = require('./amount').Amount;
exports.Currency         = require('./currency').Currency;
exports.Base             = require('./base').Base;
exports.UInt160          = require('./amount').UInt160;
exports.Seed             = require('./amount').Seed;
exports.Transaction      = require('./transaction').Transaction;
exports.Meta             = require('./meta').Meta;
exports.SerializedObject = require('./serializedobject').SerializedObject;
exports.RippleError      = require('./rippleerror').RippleError;

exports.binformat        = require('./binformat');
exports.utils            = require('./utils');
exports.Server           = require('./server').Server;

// Important: We do not guarantee any specific version of SJCL or for any
// specific features to be included. The version and configuration may change at
// any time without warning.
//
// However, for programs that are tied to a specific version of ripple.js like
// the official client, it makes sense to expose the SJCL instance so we don't
// have to include it twice.
exports.sjcl   = require('./utils').sjcl;

exports.config = require('./config');

// camelCase to under_scored API conversion
function attachUnderscored(o) {
  Object.keys(o.prototype).forEach(function(key) {
    var UPPERCASE = /([A-Z]{1})[a-z]+/g;

    if (!UPPERCASE.test(key)) return;

    var underscored = key.replace(UPPERCASE, function(c) {
      return '_' + c.toLowerCase();
    });

    o.prototype[underscored] = o.prototype[key];
  });
};

[ exports.Remote,
  exports.Request,
  exports.Transaction
].forEach(attachUnderscored);

// vim:sw=2:sts=2:ts=8:et
<|endoftext|>


<commit_before>var util = require('util'),
    Tab = require('../client/tab').Tab,
    rewriter = require('../util/jsonrewriter');

var HistoryTab = function ()
{
  Tab.call(this);
};

util.inherits(HistoryTab, Tab);

HistoryTab.prototype.mainMenu = 'wallet';

HistoryTab.prototype.generateHtml = function ()
{
  return require('../../jade/tabs/history.jade')();
};

HistoryTab.prototype.angular = function (module) {
  module.controller('HistoryCtrl', ['$scope', 'rpId', 'rpNetwork',
                                     function ($scope, $id, $network)
  {
    if (!$id.loginStatus) return $id.goId();

    var oldHist;

    // History collection
    $scope.historyShow = [];

    // History states
    $scope.$watch('loadState.transactions',function(){
      $scope.historyState = !$scope.loadState.transactions ? 'loading' : 'ready';
    });

    // Open/close states of individual history items
    $scope.details = [];

    //$scope.typeUsage = [];
    //$scope.currencyUsage = [];

    // Currencies from history
    var historyCurrencies = [];

    $scope.types = [
      {
        'name': 'sent',
        'types': ['sent'],
        'checked':true
      }, {
        'name': 'received',
        'types': ['received'],
        'checked':true
      }, {
        'name': 'trusts',
        'types': ['trusting','trusted'],
        'checked':true
      }, {
        'name': 'offers',
        'types': ['offernew','offercancel'],
        'checked':true
      }, {
        'name': 'other',
        'types': ['accountset'],
        'checked':true
      }
    ];

    // Filters
    $scope.filters = {
      'currencies_is_active': false, // we do the currency filter only if this is true, which happens when at least one currency is off
      'currencies': {},
      'types': ['sent','received','trusting','trusted','offernew','offercancel']
    };

    var getDateRangeHistory = function(dateMin,dateMax,callback)
    {
      var completed = false;
      var history = [];

      var getTx = function(offset){
        $network.remote.request_account_tx({
          'account': $id.account,
          'ledger_index_min': -1,
          'descending': true,
          'offset': offset,
          'limit': 200
        })
        .on('success', function(data) {
          if (data.transactions.length) {
            for(var i=0;i<data.transactions.length;i++) {
              var date = (data.transactions[i].tx.date + 0x386D4380) * 1000;

              if(date < dateMin.getTime()) {
                completed = true;
                break;
              }

              if(date > dateMax.getTime())
                continue;

              // Push
              var tx = rewriter.processTxn(data.transactions[i].tx, data.transactions[i].meta, $id.account);
              if (tx) history.push(tx);
            }

            if (completed)
              callback(history);
            else
              getTx(offset+100);
          } else {
            callback(history);
          }
        }).request();
      };

      getTx(0);
    };

    // DateRange filter form
    $scope.submitDateRangeForm = function() {
      $scope.dateMaxView.setDate($scope.dateMaxView.getDate() + 1); // Including last date
      changeDateRange($scope.dateMinView,$scope.dateMaxView);
    };

    var changeDateRange = function(dateMin,dateMax) {
      $scope.history = [];
      $scope.historyState = 'loading';

      getDateRangeHistory(dateMin,dateMax,function(history){
        $scope.$apply(function () {
          $scope.history = history;
          $scope.historyState = 'ready';
        })
      })
    };

    // All the currencies
    $scope.$watch('balances', function(){
      updateCurrencies();
    });

    // Types filter has been changed
    $scope.$watch('types', function(){
      var arr = [];
      for (var i=0;i<$scope.types.length;i++)
        if ($scope.types[i].checked)
          arr = arr.concat($scope.types[i].types);
      $scope.filters.types = arr;
    }, true);

    $scope.$watch('filters.types', function(){
      updateHistory();
    }, true);

    // Currency filter has been changed
    $scope.$watch('filters.currencies', function(){
      updateCurrencies();
      updateHistory();
    }, true);

    // New transactions
    $scope.$watch('history',function(){
      if (oldHist!=$scope.history) {
        updateHistory();

        // Update currencies
        if ($scope.history.length)
          updateCurrencies();

        oldHist = $scope.history;
      }
    },true);

    // Updates the history collection
    var updateHistory = function (){

      //$scope.typeUsage = [];
      //$scope.currencyUsage = [];
      $scope.historyShow = [];

      if ($scope.history.length) {
        var dateMin, dateMax;

        $scope.minLedger = 0;

        var currencies = _.map($scope.filters.currencies,function(obj,key){return obj.checked ? key : false});
        $scope.history.forEach(function(event)
        {
          // Calculate dateMin/dateMax. Used in date filter view
          if (!$scope.dateMinView) {
            if (!dateMin || dateMin > event.date)
              dateMin = event.date;

            if (!dateMax || dateMax < event.date)
              dateMax = event.date;
          }

          // Update currencies
          historyCurrencies = _.union(historyCurrencies, event.affected_currencies); // TODO put in one large array, then union outside of foreach

          // Calculate min ledger. Used in "load more"
          if (!$scope.minLedger || $scope.minLedger > event.ledger_index)
            $scope.minLedger = event.ledger_index;

          // Type filter
          if(event.transaction && !_.contains($scope.filters.types,event.transaction.type))
            return;

          // Some events don't have transactions.. this is a temporary fix for filtering offers
          else if(!event.transaction && !_.contains($scope.filters.types,'offernew'))
            return;

          // Currency filter
          if ($scope.filters.currencies_is_active && !_.intersection(currencies,event.affected_currencies).length > 0)
            return;

          var effects = [];

          if (event.effects) {
            // Show effects
            $.each(event.effects, function(){
              var effect = this;
              if (effect.type == 'offer_funded'
                  || effect.type == 'offer_partially_funded'
                  || effect.type == 'offer_bought'
                  || (effect.type === 'offer_canceled' &&
                  event.transaction.type !== 'offercancel')) {
                effects.push(effect);
              }
            });

            event.showEffects = effects;

            effects = [];

            // Balance changer effects
            $.each(event.effects, function(){
              var effect = this;
              if (effect.type == 'fee'
                  || effect.type == 'balance_change'
                  || effect.type == 'trust_change_balance') {
                effects.push(effect);
              }
            });

            event.balanceEffects = effects;
          }

          // Push events to history collection
          $scope.historyShow.push(event);

          // Type and currency usages
          // TODO offers/trusts
          //if (event.transaction)
          //  $scope.typeUsage[event.transaction.type] = $scope.typeUsage[event.transaction.type] ? $scope.typeUsage[event.transaction.type]+1 : 1;

          //event.affected_currencies.forEach(function(currency){
          //  $scope.currencyUsage[currency] = $scope.currencyUsage[currency]? $scope.currencyUsage[currency]+1 : 1;
          //});
        });

        if ($scope.historyShow.length && !$scope.dateMinView) {
          $scope.dateMinView = new Date(dateMin);
          $scope.dateMaxView = new Date(dateMax);
        }
      }
    };

    // Update the currency list
    var updateCurrencies = function (){
      if (!$.isEmptyObject($scope.balances)) {
        var currencies = _.union(
          ['XRP'],
          _.map($scope.balances,function(obj,key){return key.toUpperCase()}),
          historyCurrencies
        );

        var objCurrencies = {};

        var firstProcess = $.isEmptyObject($scope.filters.currencies);

        $scope.filters.currencies_is_active = false;

        _.each(currencies, function(currency){
          var checked = ($scope.filters.currencies[currency] && $scope.filters.currencies[currency].checked) || firstProcess;
          objCurrencies[currency] = {'checked':checked};

          if (!checked)
            $scope.filters.currencies_is_active = true;
        });

        $scope.filters.currencies = objCurrencies;
      }
    };

    $scope.loadMore = function () {
      var dateMin;

      $scope.historyState = 'loading';

      $network.remote.request_account_tx({
        'account': $id.account,
        'ledger_index_max': $scope.minLedger,
        'descending': true,
        'offset': 0,
        'limit': 100 // TODO why 100?
      })
      .on('success', function(data) {
        $scope.$apply(function () {
          if (data.transactions) {
            var transactions = [];

            data.transactions.forEach(function (e) {
              var tx = rewriter.processTxn(e.tx, e.meta, $id.account);
              if (tx) {
                transactions.push(tx);

                // Min date
                if (!dateMin || tx.date < dateMin)
                  dateMin = tx.date;
              }
            });

            var newHistory = _.uniq($scope.history.concat(transactions),true,function(ev){return ev.hash});

            if ($scope.history.length === newHistory.length)
              $scope.historyState = 'full';
            else
              $scope.historyState = 'ready';

            $scope.history = newHistory;

            $scope.dateMinView = new Date(dateMin);
          }
        });
      }).request();
    }
  }]);
};

module.exports = HistoryTab;
<commit_msg>History tab: Update on new transactions. Fixes #945<commit_after>var util = require('util'),
    Tab = require('../client/tab').Tab,
    rewriter = require('../util/jsonrewriter');

var HistoryTab = function ()
{
  Tab.call(this);
};

util.inherits(HistoryTab, Tab);

HistoryTab.prototype.mainMenu = 'wallet';

HistoryTab.prototype.generateHtml = function ()
{
  return require('../../jade/tabs/history.jade')();
};

HistoryTab.prototype.angular = function (module) {
  module.controller('HistoryCtrl', ['$scope', 'rpId', 'rpNetwork',
                                     function ($scope, $id, $network)
  {
    if (!$id.loginStatus) return $id.goId();

    // Latest transaction
    var latest;

    // History collection
    $scope.historyShow = [];

    // History states
    $scope.$watch('loadState.transactions',function(){
      $scope.historyState = !$scope.loadState.transactions ? 'loading' : 'ready';
    });

    // Open/close states of individual history items
    $scope.details = [];

    //$scope.typeUsage = [];
    //$scope.currencyUsage = [];

    // Currencies from history
    var historyCurrencies = [];

    $scope.types = [
      {
        'name': 'sent',
        'types': ['sent'],
        'checked':true
      }, {
        'name': 'received',
        'types': ['received'],
        'checked':true
      }, {
        'name': 'trusts',
        'types': ['trusting','trusted'],
        'checked':true
      }, {
        'name': 'offers',
        'types': ['offernew','offercancel'],
        'checked':true
      }, {
        'name': 'other',
        'types': ['accountset'],
        'checked':true
      }
    ];

    // Filters
    $scope.filters = {
      'currencies_is_active': false, // we do the currency filter only if this is true, which happens when at least one currency is off
      'currencies': {},
      'types': ['sent','received','trusting','trusted','offernew','offercancel']
    };

    var getDateRangeHistory = function(dateMin,dateMax,callback)
    {
      var completed = false;
      var history = [];

      var getTx = function(offset){
        $network.remote.request_account_tx({
          'account': $id.account,
          'ledger_index_min': -1,
          'descending': true,
          'offset': offset,
          'limit': 200
        })
        .on('success', function(data) {
          if (data.transactions.length) {
            for(var i=0;i<data.transactions.length;i++) {
              var date = (data.transactions[i].tx.date + 0x386D4380) * 1000;

              if(date < dateMin.getTime()) {
                completed = true;
                break;
              }

              if(date > dateMax.getTime())
                continue;

              // Push
              var tx = rewriter.processTxn(data.transactions[i].tx, data.transactions[i].meta, $id.account);
              if (tx) history.push(tx);
            }

            if (completed)
              callback(history);
            else
              getTx(offset+100);
          } else {
            callback(history);
          }
        }).request();
      };

      getTx(0);
    };

    // DateRange filter form
    $scope.submitDateRangeForm = function() {
      $scope.dateMaxView.setDate($scope.dateMaxView.getDate() + 1); // Including last date
      changeDateRange($scope.dateMinView,$scope.dateMaxView);
    };

    var changeDateRange = function(dateMin,dateMax) {
      $scope.history = [];
      $scope.historyState = 'loading';

      getDateRangeHistory(dateMin,dateMax,function(history){
        $scope.$apply(function () {
          $scope.history = history;
          $scope.historyState = 'ready';
        })
      })
    };

    // All the currencies
    $scope.$watch('balances', function(){
      updateCurrencies();
    });

    // Types filter has been changed
    $scope.$watch('types', function(){
      var arr = [];
      for (var i=0;i<$scope.types.length;i++)
        if ($scope.types[i].checked)
          arr = arr.concat($scope.types[i].types);
      $scope.filters.types = arr;
    }, true);

    $scope.$watch('filters.types', function(){
      updateHistory();
    }, true);

    // Currency filter has been changed
    $scope.$watch('filters.currencies', function(){
      updateCurrencies();
      updateHistory();
    }, true);

    // New transactions
    $scope.$watch('history',function(){
      // TODO This function has a double call on a history change. Don't know why
      // This is a temporoary fix.
      if (latest && $scope.history[0] && latest.hash == $scope.history[0].hash)
        return;

      updateHistory();

      // Update currencies
      if ($scope.history.length)
        updateCurrencies();

      latest = $.extend(true, {}, $scope.history[0]);
    },true);

    // Updates the history collection
    var updateHistory = function (){

      //$scope.typeUsage = [];
      //$scope.currencyUsage = [];
      $scope.historyShow = [];

      if ($scope.history.length) {
        var dateMin, dateMax;

        $scope.minLedger = 0;

        var currencies = _.map($scope.filters.currencies,function(obj,key){return obj.checked ? key : false});
        $scope.history.forEach(function(event)
        {
          // Calculate dateMin/dateMax. Used in date filter view
          if (!$scope.dateMinView) {
            if (!dateMin || dateMin > event.date)
              dateMin = event.date;

            if (!dateMax || dateMax < event.date)
              dateMax = event.date;
          }

          // Update currencies
          historyCurrencies = _.union(historyCurrencies, event.affected_currencies); // TODO put in one large array, then union outside of foreach

          // Calculate min ledger. Used in "load more"
          if (!$scope.minLedger || $scope.minLedger > event.ledger_index)
            $scope.minLedger = event.ledger_index;

          // Type filter
          if(event.transaction && !_.contains($scope.filters.types,event.transaction.type))
            return;

          // Some events don't have transactions.. this is a temporary fix for filtering offers
          else if(!event.transaction && !_.contains($scope.filters.types,'offernew'))
            return;

          // Currency filter
          if ($scope.filters.currencies_is_active && !_.intersection(currencies,event.affected_currencies).length > 0)
            return;

          var effects = [];

          if (event.effects) {
            // Show effects
            $.each(event.effects, function(){
              var effect = this;
              if (effect.type == 'offer_funded'
                  || effect.type == 'offer_partially_funded'
                  || effect.type == 'offer_bought'
                  || (effect.type === 'offer_canceled' &&
                  event.transaction.type !== 'offercancel')) {
                effects.push(effect);
              }
            });

            event.showEffects = effects;

            effects = [];

            // Balance changer effects
            $.each(event.effects, function(){
              var effect = this;
              if (effect.type == 'fee'
                  || effect.type == 'balance_change'
                  || effect.type == 'trust_change_balance') {
                effects.push(effect);
              }
            });

            event.balanceEffects = effects;
          }

          // Push events to history collection
          $scope.historyShow.push(event);

          // Type and currency usages
          // TODO offers/trusts
          //if (event.transaction)
          //  $scope.typeUsage[event.transaction.type] = $scope.typeUsage[event.transaction.type] ? $scope.typeUsage[event.transaction.type]+1 : 1;

          //event.affected_currencies.forEach(function(currency){
          //  $scope.currencyUsage[currency] = $scope.currencyUsage[currency]? $scope.currencyUsage[currency]+1 : 1;
          //});
        });

        if ($scope.historyShow.length && !$scope.dateMinView) {
          $scope.dateMinView = new Date(dateMin);
          $scope.dateMaxView = new Date(dateMax);
        }
      }
    };

    // Update the currency list
    var updateCurrencies = function (){
      if (!$.isEmptyObject($scope.balances)) {
        var currencies = _.union(
          ['XRP'],
          _.map($scope.balances,function(obj,key){return key.toUpperCase()}),
          historyCurrencies
        );

        var objCurrencies = {};

        var firstProcess = $.isEmptyObject($scope.filters.currencies);

        $scope.filters.currencies_is_active = false;

        _.each(currencies, function(currency){
          var checked = ($scope.filters.currencies[currency] && $scope.filters.currencies[currency].checked) || firstProcess;
          objCurrencies[currency] = {'checked':checked};

          if (!checked)
            $scope.filters.currencies_is_active = true;
        });

        $scope.filters.currencies = objCurrencies;
      }
    };

    $scope.loadMore = function () {
      var dateMin;

      $scope.historyState = 'loading';

      $network.remote.request_account_tx({
        'account': $id.account,
        'ledger_index_max': $scope.minLedger,
        'descending': true,
        'offset': 0,
        'limit': 100 // TODO why 100?
      })
      .on('success', function(data) {
        $scope.$apply(function () {
          if (data.transactions) {
            var transactions = [];

            data.transactions.forEach(function (e) {
              var tx = rewriter.processTxn(e.tx, e.meta, $id.account);
              if (tx) {
                transactions.push(tx);

                // Min date
                if (!dateMin || tx.date < dateMin)
                  dateMin = tx.date;
              }
            });

            var newHistory = _.uniq($scope.history.concat(transactions),true,function(ev){return ev.hash});

            if ($scope.history.length === newHistory.length)
              $scope.historyState = 'full';
            else
              $scope.historyState = 'ready';

            $scope.history = newHistory;

            $scope.dateMinView = new Date(dateMin);
          }
        });
      }).request();
    }
  }]);
};

module.exports = HistoryTab;
<|endoftext|>


<commit_before>var Prism = require('prismjs')

Prism.languages.scss = Prism.languages.extend("css", {
        comment: {
            pattern: /(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,
            lookbehind: !0
        },
        atrule: {
            pattern: /@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,
            inside: {
                rule: /@[\w-]+/
            }
        },
        url: /(?:[-a-z]+-)*url(?=\()/i,
        selector: {
            pattern: /(?=\S)[^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,
            inside: {
                parent: {
                    pattern: /&/,
                    alias: "important"
                },
                placeholder: /%[-_\w]+/,
                variable: /\$[-_\w]+|#\{\$[-_\w]+\}/
            }
        }
    }), Prism.languages.insertBefore("scss", "atrule", {
        keyword: [/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i, {
            pattern: /( +)(?:from|through)(?= )/,
            lookbehind: !0
        }]
    }), Prism.languages.scss.property = {
        pattern: /(?:[\w-]|\$[-_\w]+|#\{\$[-_\w]+\})+(?=\s*:)/i,
        inside: {
            variable: /\$[-_\w]+|#\{\$[-_\w]+\}/
        }
    }, Prism.languages.insertBefore("scss", "important", {
        variable: /\$[-_\w]+|#\{\$[-_\w]+\}/
    }), Prism.languages.insertBefore("scss", "function", {
        placeholder: {
            pattern: /%[-_\w]+/,
            alias: "selector"
        },
        statement: {
            pattern: /\B!(?:default|optional)\b/i,
            alias: "keyword"
        },
        "boolean": /\b(?:true|false)\b/,
        "null": /\bnull\b/,
        operator: {
            pattern: /(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,
            lookbehind: !0
        }
    }), Prism.languages.scss.atrule.inside.rest = Prism.util.clone(Prism.languages.scss)

module.exports = Prism
<commit_msg>Add bash to prism highlighting<commit_after>var Prism = require('prismjs')

Prism.languages.scss = Prism.languages.extend(
    "css",
    {
        comment: {
            pattern: /(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,
            lookbehind: !0
        },
        atrule: {
            pattern: /@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,
            inside: {
                rule: /@[\w-]+/
            }
        },
        url: /(?:[-a-z]+-)*url(?=\()/i,
        selector: {
            pattern: /(?=\S)[^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/m,
            inside: {
                parent: {
                    pattern: /&/,
                    alias: "important"
                },
                placeholder: /%[-_\w]+/,
                variable: /\$[-_\w]+|#\{\$[-_\w]+\}/
            }
        }
    }), Prism.languages.insertBefore("scss", "atrule", {
        keyword: [/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i, {
            pattern: /( +)(?:from|through)(?= )/,
            lookbehind: !0
        }]
    }), Prism.languages.scss.property = {
        pattern: /(?:[\w-]|\$[-_\w]+|#\{\$[-_\w]+\})+(?=\s*:)/i,
        inside: {
            variable: /\$[-_\w]+|#\{\$[-_\w]+\}/
        }
    }, Prism.languages.insertBefore("scss", "important", {
        variable: /\$[-_\w]+|#\{\$[-_\w]+\}/
    }), Prism.languages.insertBefore("scss", "function", {
        placeholder: {
            pattern: /%[-_\w]+/,
            alias: "selector"
        },
        statement: {
            pattern: /\B!(?:default|optional)\b/i,
            alias: "keyword"
        },
        "boolean": /\b(?:true|false)\b/,
        "null": /\bnull\b/,
        operator: {
            pattern: /(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,
            lookbehind: !0
        }
    }
), Prism.languages.scss.atrule.inside.rest = Prism.util.clone(Prism.languages.scss)

! function(e) {
    var t = {
        variable: [{
            pattern: /\$?\(\([\s\S]+?\)\)/,
            inside: {
                variable: [{
                    pattern: /(^\$\(\([\s\S]+)\)\)/,
                    lookbehind: !0
                }, /^\$\(\(/],
                number: /\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,
                operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
                punctuation: /\(\(?|\)\)?|,|;/
            }
        }, {
            pattern: /\$\([^)]+\)|`[^`]+`/,
            inside: {
                variable: /^\$\(|^`|\)$|`$/
            }
        }, /\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i]
    };
    e.languages.bash = {
        shebang: {
            pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,
            alias: "important"
        },
        comment: {
            pattern: /(^|[^"{\\])#.*/,
            lookbehind: !0
        },
        string: [{
            pattern: /((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,
            lookbehind: !0,
            greedy: !0,
            inside: t
        }, {
            pattern: /(["'])(?:\\\\|\\?[^\\])*?\1/g,
            greedy: !0,
            inside: t
        }],
        variable: t.variable,
        "function": {
            pattern: /(^|\s|;|\||&)(?:alias|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,
            lookbehind: !0
        },
        keyword: {
            pattern: /(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,
            lookbehind: !0
        },
        "boolean": {
            pattern: /(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,
            lookbehind: !0
        },
        operator: /&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,
        punctuation: /\$?\(\(?|\)\)?|\.\.|[{}[\];]/
    };
    var a = t.variable[1].inside;
    a["function"] = e.languages.bash["function"], a.keyword = e.languages.bash.keyword, a.boolean = e.languages.bash.boolean, a.operator = e.languages.bash.operator, a.punctuation = e.languages.bash.punctuation
}(Prism);

module.exports = Prism
<|endoftext|>


<commit_before>import {
	BufferGeometry, Float32BufferAttribute,
	FaceColors, Mesh,
	MeshLambertMaterial
} from '../../../../three.js/src/Three';

var unselectedMaterial = new MeshLambertMaterial( { color: 0x444444, vertexColors: FaceColors } );

function sortGroups ( a, b ) {

	if ( a.materialIndex !== b.materialIndex ) {

		return a.materialIndex - b.materialIndex;

	} else {

		return a.start - b.start;

	}

}

function mergeGroups ( groups ) {

	var group;
	var lastGroup = groups[ 0 ];
	var groupIndex = 1;

	for ( var i = 1, l = groups.length; i < l; i++ ) {

		group = groups[ i ];

		if ( group.materialIndex === lastGroup.materialIndex && lastGroup.start + lastGroup.count === group.start ) {

			lastGroup.count += group.count;

		} else {

			groups[ groupIndex++ ] = group;
			lastGroup = group;

		}

	}

	groups.length = groupIndex; // truncate

	return groups;

}

function Walls ( layer ) {

	var geometry = new BufferGeometry();

	Mesh.call( this, geometry, unselectedMaterial );

	this.layers.set( layer );
	this.type = 'Walls';

	return this;

}

Walls.prototype = Object.create( Mesh.prototype );

Walls.prototype.constructor = Walls;

Walls.prototype.addWalls = function ( vertices, indices, indexRuns ) {

	var geometry = this.geometry;

	var position = geometry.getAttribute( 'position' );

	if ( position === undefined ) {

		var positions = new Float32BufferAttribute( vertices.length * 3, 3 );

		geometry.addAttribute( 'position', positions.copyVector3sArray( vertices ) );

		geometry.setIndex( indices );

	} else {

		// FIXME: alllocate new buffer of old + new length, adjust indexs and append old data after new data.

		console.error( 'Walls: appending not yet implemented' );

	}

	geometry.computeVertexNormals();
	geometry.computeBoundingBox();

	this.indexRuns = indexRuns;

	return this;

};

Walls.prototype.setShading = function ( selectedRuns, selectedMaterial ) {

	var geometry = this.geometry;

	geometry.clearGroups();

	var indexRuns = this.indexRuns;

	if ( selectedRuns.size && indexRuns ) {

		this.material = [ selectedMaterial, unselectedMaterial ];

		for ( var run = 0, l = indexRuns.length; run < l; run++ ) {

			var indexRun = indexRuns[ run ];

			geometry.addGroup( indexRun.start, indexRun.count, selectedRuns.has( indexRun.survey ) ? 0 : 1 );

		}

		geometry.groups = mergeGroups( geometry.groups.sort( sortGroups ) );

	} else {

		this.material = selectedMaterial;

	}

};

Walls.prototype.cutRuns = function ( selectedRuns ) {

	var indexRuns = this.indexRuns;

	var geometry = this.geometry;

	var vertices = geometry.getAttribute( 'position' );
	var indices = geometry.index;

	var newIndices = [];
	var newVertices = [];

	var newIndexRuns = [];

	var fp = 0;

	var vMap = new Map();
	var index, newIndex;
	var newVertexIndex = 0;
	var offset;

	for ( var run = 0, l = indexRuns.length; run < l; run++ ) {

		var indexRun = indexRuns[ run ];

		if ( selectedRuns.has( indexRun.survey ) ) {

			var start = indexRun.start;
			var count = indexRun.count;

			var end = start + count;

			var itemSize = vertices.itemSize;
			var oldVertices = vertices.array;

			for ( var i = start; i < end; i++ ) {

				index = indices.getX( i );

				newIndex = vMap.get( index );

				if ( newIndex === undefined ) {

					newIndex = newVertexIndex++;

					vMap.set( index, newIndex );

					offset = index * itemSize;

					newVertices.push( oldVertices[ offset ], oldVertices[ offset + 1 ], oldVertices[ offset + 2 ] );

				}

				newIndices.push( newIndex );

			}

			indexRun.start = fp;

			fp += count;

			newIndexRuns.push( indexRun );

		}

	}

	if ( newIndices.length === 0 ) return false;

	// replace position and index attributes - dispose of old attributes
	geometry.index.setArray( new indices.array.constructor( newIndices ) );
	geometry.index.needsUpdate = true;

	vertices.setArray( new Float32Array( newVertices ) );
	vertices.needsUpdate = true;

	geometry.computeVertexNormals();
	geometry.computeBoundingBox();

	this.indexRuns = newIndexRuns;

	return true;

};

export { Walls };
<commit_msg>move merging into single loop<commit_after>import {
	BufferGeometry, Float32BufferAttribute,
	FaceColors, Mesh,
	MeshLambertMaterial
} from '../../../../three.js/src/Three';

var unselectedMaterial = new MeshLambertMaterial( { color: 0x444444, vertexColors: FaceColors } );

function Walls ( layer ) {

	var geometry = new BufferGeometry();

	Mesh.call( this, geometry, unselectedMaterial );

	this.layers.set( layer );
	this.type = 'Walls';

	return this;

}

Walls.prototype = Object.create( Mesh.prototype );

Walls.prototype.constructor = Walls;

Walls.prototype.addWalls = function ( vertices, indices, indexRuns ) {

	var geometry = this.geometry;

	var position = geometry.getAttribute( 'position' );

	if ( position === undefined ) {

		var positions = new Float32BufferAttribute( vertices.length * 3, 3 );

		geometry.addAttribute( 'position', positions.copyVector3sArray( vertices ) );

		geometry.setIndex( indices );

	} else {

		// FIXME: alllocate new buffer of old + new length, adjust indexs and append old data after new data.

		console.error( 'Walls: appending not yet implemented' );

	}

	geometry.computeVertexNormals();
	geometry.computeBoundingBox();

	this.indexRuns = indexRuns;

	return this;

};

Walls.prototype.setShading = function ( selectedRuns, selectedMaterial ) {

	var geometry = this.geometry;

	geometry.clearGroups();

	var indexRuns = this.indexRuns;

	var lastMaterial = 0;
	var currentMaterial;

	if ( selectedRuns.size && indexRuns ) {

		this.material = [ selectedMaterial, unselectedMaterial ];

		var indexRun = indexRuns[ 0 ];

		var start = indexRun.start;
		var count = indexRun.count;

		var lastMaterial = selectedRuns.has( indexRun.survey ) ? 0 : 1

		// merge adjacent runs with shared material.

		for ( var run = 1, l = indexRuns.length; run < l; run++ ) {

			indexRun = indexRuns[ run ];

			currentMaterial = selectedRuns.has( indexRun.survey ) ? 0 : 1;

			if ( currentMaterial === lastMaterial && indexRun.start === start + count ) {

				count += indexRun.count;

			} else {

				geometry.addGroup( start, count, lastMaterial );

				start = indexRun.start;
				count = indexRun.count;

				lastMaterial = currentMaterial;

			}

		}

		geometry.addGroup( start, count, lastMaterial );

	} else {

		this.material = selectedMaterial;

	}

};

Walls.prototype.cutRuns = function ( selectedRuns ) {

	var indexRuns = this.indexRuns;

	var geometry = this.geometry;

	var vertices = geometry.getAttribute( 'position' );
	var indices = geometry.index;

	var newIndices = [];
	var newVertices = [];

	var newIndexRuns = [];

	var fp = 0;

	var vMap = new Map();
	var index, newIndex;
	var newVertexIndex = 0;
	var offset;

	for ( var run = 0, l = indexRuns.length; run < l; run++ ) {

		var indexRun = indexRuns[ run ];

		if ( selectedRuns.has( indexRun.survey ) ) {

			var start = indexRun.start;
			var count = indexRun.count;

			var end = start + count;

			var itemSize = vertices.itemSize;
			var oldVertices = vertices.array;

			for ( var i = start; i < end; i++ ) {

				index = indices.getX( i );

				newIndex = vMap.get( index );

				if ( newIndex === undefined ) {

					newIndex = newVertexIndex++;

					vMap.set( index, newIndex );

					offset = index * itemSize;

					newVertices.push( oldVertices[ offset ], oldVertices[ offset + 1 ], oldVertices[ offset + 2 ] );

				}

				newIndices.push( newIndex );

			}

			indexRun.start = fp;

			fp += count;

			newIndexRuns.push( indexRun );

		}

	}

	if ( newIndices.length === 0 ) return false;

	// replace position and index attributes - dispose of old attributes
	geometry.index.setArray( new indices.array.constructor( newIndices ) );
	geometry.index.needsUpdate = true;

	vertices.setArray( new Float32Array( newVertices ) );
	vertices.needsUpdate = true;

	geometry.computeVertexNormals();
	geometry.computeBoundingBox();

	this.indexRuns = newIndexRuns;

	return true;

};

export { Walls };
<|endoftext|>


<commit_before>/*
 * gui-builder - A simple WYSIWYG HTML5 app creator
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 */
"use strict";

// Layout view widget

(function($, undefined) {

    $.widget('gb.layoutView', {

        options: {
            model: null,
            iframe: null,
            contentDocument: null,
            customHeaders: {
                'meta': [
                    '<meta http-equiv="cache-control" content="no-cache">'
                ],
                'script': [
                    '',
                    ''
                ],
                'link': [
                    '<link href="src/css/composer.css" rel="stylesheet">'
                ]
            }
        },

        _create: function() {
            var o = this.options,
                e = this.element;

            o.designReset = this._designResetHandler;
            o.selectionChanged = this._selectionChangedHandler;
            o.activePageChanged = this._activePageChangedHandler;
            o.modelUpdated = this._modelUpdatedHandler;

            // FIXME: This should work, but $.extend of options seems to be
            //        creating a copy of the ADM, which will not containt the
            //        same nodes and events as the master
            //o.model = o.model || ADM || undefined;
            if (o.model) {
                this._bindADMEvents(o.model);
            }

            this.options.iframe = this.element.find('iframe');
            if (!this.options.iframe.length) {
                this.options.iframe = $('');
            }

            this.options.iframe.addClass(this.widgetName)
                .addClass('flex1')
                .appendTo(this.element);

            this.options.primaryTools = this._createPrimaryTools();
            this.options.secondaryTools = this._createSecondaryTools();

            this.options.contentDocument =
                $(this.options.iframe[0].contentDocument);

            $(window).resize(this, function(event) {
                var el = event.data.element,
                    doc = event.data.options.contentDocument,
                    iframe = event.data.options.iframe;
                // Force resize of the stage when containing window resizes
                el.height(el.parent().height());
                el.find('div').height(el.parent().height());
                // Force resize of the iframe when containing window resizes
                iframe.height(doc.height());
                iframe.css('min-height',
                            el.height() - 2
                            - parseFloat(iframe.css('margin-top'))
                            - parseFloat(iframe.css('margin-bottom'))
                            - parseFloat(iframe.css('padding-bottom'))
                            - parseFloat(iframe.css('padding-bottom')));
            });

            this.refresh(null, this);

            return this;
        },

        _setOption: function(key, value) {
            switch (key) {
                // Should this REALLY be done here, or plugin registration in
                // the "host"... using the functions mapped in widget options?
                case 'model':
                    this._unbindADMEvents();
                    this._bindADMEvents(value);
                    this._createDocument();
                    this.options.iframe.load(this, this._iframeLoaded);
                    break;
                default:
                    break;
            }
        },

        destroy: function() {
            // TODO: unbind any ADM event handlers
            $(this.element).find('.'+this.widgetName).remove();
            this.options.primaryTools.remove();
            this.options.secondaryTools.remove();
        },

        refresh: function(event, widget) {
            var name;
            widget = widget || event && event.data || this;
            name = (event)?(event.name)?event.name:event.type:'';

            if (!widget.loaded) return;

            if (!event) {
                widget._serializeADMDesignToDOM();
            } else if (event.type === 'load') {
                widget._serializeADMDesignToDOM();
            } else if (event.name === 'designReset') {
                widget._serializeADMDesignToDOM();
            } else if (event.name === 'modelUpdated') {
                widget._serializeADMDesignToDOM();
/* FIXME: Calling serializeADMSubtreeToDom is not actually forcing the
          the DOM to update, but it should work...

                switch (event.type) {
                    case 'nodeAdded':
                    case 'nodeRemoved':
                        serializeADMSubtreeToDOM(event.parent, null,
                                                 widget._renderer);
                        break;
                    case 'nodeMoved':
                        serializeADMSubtreeToDOM(event.oldParent, null,
                                                 widget._renderer);
                        serializeADMSubtreeToDOM(event.newParent, null,
                                                 widget._renderer);
                        break;
                    case 'propertyChanged':
                        serializeADMSubtreeToDOM(event.node, null,
                                                 widget._renderer);
                        break;
                    default:
                        console.warn(widget.widgetName,
                                     ':: Unexpected modelUpdate type:',
                                     event.type);
                        return;
                        break;
                }
*/
            } else {
                console.warn(widget.widgetName,':: Unexpected event:',name);
                return;
            }

            if (widget.options.contentDocument.length) {
                widget.options.contentDocument[0].defaultView
                    .postMessage('reload', '*');
            } else {
                console.error(widget.widgetName, ':: Missing contentDocument');
            }

            // Refresh our cache of iframe sortables
            widget._refreshSortables();
        },

        // Private functions
        _getSortables: function(update) {
            if (update) {
                this._sortables = this.options.contentDocument
                                      .find('.nrc-sortable-container');
            } else {
                this._sortables = this._sortables||this.options.contentDocument
                                      .find('.nrc-sortable-container');
            }
            return this._sortables;
        },

        _refreshSortables: function() {
            // Force a re-search for sortables in the iframe doc
            var s = this._getSortables(true);

            // Associate the palette items with these sortables
            $(':gb-paletteView .ui-draggable').draggable('option', {
                connectToSortable: s,
            });
        },

        _iframeLoaded: function(event) {
            event.data.loaded = true;
            event.data.refresh(null, event.data);
        },

        _createPrimaryTools: function() {
            var doc, html, classes, selector,
                commands = ['undo', 'redo', 'cut', 'copy', 'paste'];

            classes = "buttonStyle primary-tools ui-state-default";
            html = $('
').addClass('hbox').hide();
            $.each(commands, function (index, command) {
                $('<button/>').addClass(classes)
                    .attr('id', 'btn' + command)
                    .appendTo(html);
            });

            doc = $((this.element)[0].ownerDocument);
            selector = "button.primary-tools"
            doc.delegate(selector, "click", jQuery.proxy(function (event) {
                var model = this.options.model;
                if (model) {
                    switch (event.currentTarget.id) {
                    case "btnundo":  model.undo();  break;
                    case "btnredo":  model.redo();  break;
                    case "btncut":   model.cut();   break;
                    case "btncopy":  model.copy();  break;
                    case "btnpaste": model.paste(); break;
                    default:
                        console.warn("Unhandled click on primary tool");
                        break;
                    }
                }
                else {
                    console.warn("No model while attempting undo");
                }
            }, this));

            return html;
        },

        _createSecondaryTools: function() {
            return $(null);
        },

        _bindADMEvents: function(a) {
            var o = this.options,
                d = this.designRoot;

            if (a) {
                o.model = a;

                if (o.designReset) {
                    a.bind("designReset", o.designReset, this);
                }
                if (o.selectionChanged) {
                    a.bind("selectionChanged", o.selectionChanged, this);
                }
                if (o.activePageChanged) {
                    a.bind("activePageChanged", o.activePageChanged, this);
                }

                // Since model changed, need to call our designReset hander
                // to sync up the ADMDesign modelUpdated event handler
                if (o.designReset) {
                    o.designReset({design: a.getDesignRoot()}, this);
                }
            }
        },

        _unbindADMEvents: function() {
            var o = this.options,
                a = this.options.model,
                d = this.designRoot;

            // First unbind our ADMDesign modelUpdated handler, if any...
            if (d && o.modelUpdated) {
                d.designRoot.unbind("modelUpdated", o.modelUpdated, this);
            }

            // Now unbind all ADM model event handlers, if any...
            if (a) {
                if (o.designReset) {
                    a.unbind("designReset", o.designReset, this);
                }
                if (o.selectionChanged) {
                    a.unbind("selectionChanged", o.selectionChanged, this);
                }
                if (o.activePageChanged) {
                    a.unbind("activePageChanged", o.activePageChanged, this);
                }
            }
        },

        _designResetHandler: function(event, widget) {
            var d = event && event.design, o;

            widget = widget || this;
            o = widget.options;
            d = d || o.model.getDesignRoot();

            // Do nothing if the new ADMDesign equals our currently cached one
            if (d === widget.designRoot) {
                return;
            }

            // First, unbind existing modelUpdated hander, if any...
            if (widget.designRoot && o.modelUpdated) {
                widget.designRoot.unbind("modelUpdated", o.modelUpdated,widget);
            }

            // Next, bind to modelUpdated events from new ADMDesign, if any...
            if (d && o.modelUpdated) {
                d.bind("modelUpdated", o.modelUpdated, widget);
            }

            // Then, cache the new ADMDesign reference with this instance
            widget.designRoot = d;

            // Finally, redraw our view since the ADMDesign root has changed
            widget.refresh(event, widget);
        },

        _selectionChangedHandler: function(event, widget) {
            var uid;
            widget = widget || this;

            // Always un-style currently selected nodes
            widget.options.contentDocument.find('.ui-selected')
                .removeClass('ui-selected');

            // Only apply selection style changes on valid nodes
            if (!event || (!event.uid && !event.node)) {
                return;
            }

            // Normally, ADM node id is provided in event.uid
            uid = event && event.uid;
            // Fallback is to try event.node.getUid()
            uid = uid || (event.node)?event.node.getUid():null;

            if (uid) {
                widget.options.contentDocument
                    .find('.adm-node[data-uid=\''+uid+'\']')
                    .not('[data-role=\'page\']')
                    .addClass('ui-selected').first().each(function() {
                        // Scroll selected node into view
                        this.scrollIntoViewIfNeeded();
                    });
            }
        },

        _activePageChangedHandler: function(event, widget) {
            var id, win,
                newPage = event && event.page, curPage;

            widget = widget || this;

            // Only change if new page is valid
            if (!newPage) {
                return;
            }
            id = newPage.getProperty('id');
            curPage = widget.options.model.getActivePage();

            // Only change if new page not the current page
            if (curPage && curPage.getUid() === id) {
                return;
            }

            win = widget.options.contentDocument[0].defaultView;

            if (win && win.$ && win.$.mobile) {
                win.$.mobile.changePage("#"+id, {transition: "none"});
            }
        },

        _modelUpdatedHandler: function(event, widget) {
            var win;

            widget = widget || this;

            widget.refresh(event, widget);

            win = widget.options.contentDocument[0].defaultView;
            if (win && win.$ && win.$.mobile) {
                win.$.mobile.activePage.page('destroy');
                win.$.mobile.activePage.page();
            } else {
                console.error(widget.widgetName, ':: Missing contentDocument');
            }
        },

        _createDocument: function() {
            var contents, doc;

            if (!this.designRoot) return;

            doc = this.options.contentDocument[0];
            doc.open();
            contents = this._serializeFramework(this.designRoot);
            doc.writeln(contents);
            doc.close();
        },

        _serializeFramework: function() {
            var start, end, ret, headers;

            headers = this._getCustomHeaders();

            start = '<!DOCTYPE html>\n <title>Page Title</title>\n';
            end = "\n\n\n";

            if (headers && headers.length > 0) {
                ret = start + headers.join('\n') + end;
            } else {
                ret = start + end;
            }

            return ret;
        },

        // Great assumptions are being made here that the incoming default
        // headers are already "sorted" and in the order in which they should
        // be inserted into the  node of the document being created...
        _getCustomHeaders: function() {
            var dh = $.gb.getDefaultHeaders(),   // default headers
                ch = this.options.customHeaders, // our custom headers
                m, s;

            $.each(dh, function(idx) {
                if (/<meta/.test(this)) {
                    m = idx+1; // Insert our Meta after LAST one
                    return;
                }
                if (/',
                    ''
                ],
                'link': [
                    '<link href="src/css/composer.css" rel="stylesheet">'
                ]
            }
        },

        _create: function() {
            var o = this.options,
                e = this.element;

            o.designReset = this._designResetHandler;
            o.selectionChanged = this._selectionChangedHandler;
            o.activePageChanged = this._activePageChangedHandler;
            o.modelUpdated = this._modelUpdatedHandler;

            // FIXME: This should work, but $.extend of options seems to be
            //        creating a copy of the ADM, which will not containt the
            //        same nodes and events as the master
            //o.model = o.model || ADM || undefined;
            if (o.model) {
                this._bindADMEvents(o.model);
            }

            this.options.iframe = this.element.find('iframe');
            if (!this.options.iframe.length) {
                this.options.iframe = $('');
            }

            this.options.iframe.addClass(this.widgetName)
                .addClass('flex1')
                .appendTo(this.element);

            this.options.primaryTools = this._createPrimaryTools();
            this.options.secondaryTools = this._createSecondaryTools();

            this.options.contentDocument =
                $(this.options.iframe[0].contentDocument);

            $(window).resize(this, function(event) {
                var el = event.data.element,
                    doc = event.data.options.contentDocument,
                    iframe = event.data.options.iframe;
                // Force resize of the stage when containing window resizes
                el.height(el.parent().height());
                el.find('div').height(el.parent().height());
                // Force resize of the iframe when containing window resizes
                iframe.height(doc.height());
                iframe.css('min-height',
                            el.height() - 2
                            - parseFloat(iframe.css('margin-top'))
                            - parseFloat(iframe.css('margin-bottom'))
                            - parseFloat(iframe.css('padding-bottom'))
                            - parseFloat(iframe.css('padding-bottom')));
            });

            this.refresh(null, this);

            return this;
        },

        _setOption: function(key, value) {
            switch (key) {
                // Should this REALLY be done here, or plugin registration in
                // the "host"... using the functions mapped in widget options?
                case 'model':
                    this._unbindADMEvents();
                    this._bindADMEvents(value);
                    this._createDocument();
                    this.options.iframe.load(this, this._iframeLoaded);
                    break;
                default:
                    break;
            }
        },

        destroy: function() {
            // TODO: unbind any ADM event handlers
            $(this.element).find('.'+this.widgetName).remove();
            this.options.primaryTools.remove();
            this.options.secondaryTools.remove();
        },

        refresh: function(event, widget) {
            var name;
            widget = widget || event && event.data || this;
            name = (event)?(event.name)?event.name:event.type:'';

            if (!widget.loaded) return;

            if (!event) {
                widget._serializeADMDesignToDOM();
            } else if (event.type === 'load') {
                widget._serializeADMDesignToDOM();
            } else if (event.name === 'designReset') {
                widget._serializeADMDesignToDOM();
            } else if (event.name === 'modelUpdated') {
                widget._serializeADMDesignToDOM();
/* FIXME: Calling serializeADMSubtreeToDom is not actually forcing the
          the DOM to update, but it should work...

                switch (event.type) {
                    case 'nodeAdded':
                    case 'nodeRemoved':
                        serializeADMSubtreeToDOM(event.parent, null,
                                                 widget._renderer);
                        break;
                    case 'nodeMoved':
                        serializeADMSubtreeToDOM(event.oldParent, null,
                                                 widget._renderer);
                        serializeADMSubtreeToDOM(event.newParent, null,
                                                 widget._renderer);
                        break;
                    case 'propertyChanged':
                        serializeADMSubtreeToDOM(event.node, null,
                                                 widget._renderer);
                        break;
                    default:
                        console.warn(widget.widgetName,
                                     ':: Unexpected modelUpdate type:',
                                     event.type);
                        return;
                        break;
                }
*/
            } else {
                console.warn(widget.widgetName,':: Unexpected event:',name);
                return;
            }

            if (widget.options.contentDocument.length) {
                widget.options.contentDocument[0].defaultView
                    .postMessage('reload', '*');
            } else {
                console.error(widget.widgetName, ':: Missing contentDocument');
            }

            // Refresh our cache of iframe sortables
            widget._refreshSortables();
        },

        // Private functions
        _getSortables: function(update) {
            if (update) {
                this._sortables = this.options.contentDocument
                                      .find('.nrc-sortable-container');
            } else {
                this._sortables = this._sortables||this.options.contentDocument
                                      .find('.nrc-sortable-container');
            }
            return this._sortables;
        },

        _refreshSortables: function() {
            // Force a re-search for sortables in the iframe doc
            var s = this._getSortables(true);

            // Associate the palette items with these sortables
            $(':gb-paletteView .ui-draggable').draggable('option', {
                connectToSortable: s,
            });
        },

        _iframeLoaded: function(event) {
            event.data.loaded = true;
            event.data.refresh(null, event.data);
        },

        _createPrimaryTools: function() {
            var doc, html, classes, selector,
                commands = ['undo', 'redo', 'cut', 'copy', 'paste'];

            classes = "buttonStyle primary-tools ui-state-default";
            html = $('
').addClass('hbox').hide();
            $.each(commands, function (index, command) {
                $('<button/>').addClass(classes)
                    .attr('id', 'btn' + command)
                    .appendTo(html);
            });

            doc = $((this.element)[0].ownerDocument);
            selector = "button.primary-tools"
            doc.delegate(selector, "click", jQuery.proxy(function (event) {
                var model = this.options.model;
                if (model) {
                    switch (event.currentTarget.id) {
                    case "btnundo":  model.undo();  break;
                    case "btnredo":  model.redo();  break;
                    case "btncut":   model.cut();   break;
                    case "btncopy":  model.copy();  break;
                    case "btnpaste": model.paste(); break;
                    default:
                        console.warn("Unhandled click on primary tool");
                        break;
                    }
                }
                else {
                    console.warn("No model while attempting undo");
                }
            }, this));

            return html;
        },

        _createSecondaryTools: function() {
            return $(null);
        },

        _bindADMEvents: function(a) {
            var o = this.options,
                d = this.designRoot;

            if (a) {
                o.model = a;

                if (o.designReset) {
                    a.bind("designReset", o.designReset, this);
                }
                if (o.selectionChanged) {
                    a.bind("selectionChanged", o.selectionChanged, this);
                }
                if (o.activePageChanged) {
                    a.bind("activePageChanged", o.activePageChanged, this);
                }

                // Since model changed, need to call our designReset hander
                // to sync up the ADMDesign modelUpdated event handler
                if (o.designReset) {
                    o.designReset({design: a.getDesignRoot()}, this);
                }
            }
        },

        _unbindADMEvents: function() {
            var o = this.options,
                a = this.options.model,
                d = this.designRoot;

            // First unbind our ADMDesign modelUpdated handler, if any...
            if (d && o.modelUpdated) {
                d.designRoot.unbind("modelUpdated", o.modelUpdated, this);
            }

            // Now unbind all ADM model event handlers, if any...
            if (a) {
                if (o.designReset) {
                    a.unbind("designReset", o.designReset, this);
                }
                if (o.selectionChanged) {
                    a.unbind("selectionChanged", o.selectionChanged, this);
                }
                if (o.activePageChanged) {
                    a.unbind("activePageChanged", o.activePageChanged, this);
                }
            }
        },

        _designResetHandler: function(event, widget) {
            var d = event && event.design, o;

            widget = widget || this;
            o = widget.options;
            d = d || o.model.getDesignRoot();

            // Do nothing if the new ADMDesign equals our currently cached one
            if (d === widget.designRoot) {
                return;
            }

            // First, unbind existing modelUpdated hander, if any...
            if (widget.designRoot && o.modelUpdated) {
                widget.designRoot.unbind("modelUpdated", o.modelUpdated,widget);
            }

            // Next, bind to modelUpdated events from new ADMDesign, if any...
            if (d && o.modelUpdated) {
                d.bind("modelUpdated", o.modelUpdated, widget);
            }

            // Then, cache the new ADMDesign reference with this instance
            widget.designRoot = d;

            // Finally, redraw our view since the ADMDesign root has changed
            widget.refresh(event, widget);
        },

        _selectionChangedHandler: function(event, widget) {
            var uid;
            widget = widget || this;

            // Always un-style currently selected nodes
            widget.options.contentDocument.find('.ui-selected')
                .removeClass('ui-selected');

            // Only apply selection style changes on valid nodes
            if (!event || (!event.uid && !event.node)) {
                return;
            }

            // Normally, ADM node id is provided in event.uid
            uid = event && event.uid;
            // Fallback is to try event.node.getUid()
            uid = uid || (event.node)?event.node.getUid():null;

            if (uid) {
                widget.options.contentDocument
                    .find('.adm-node[data-uid=\''+uid+'\']')
                    .not('[data-role=\'page\']')
                    .addClass('ui-selected').first().each(function() {
                        // Scroll selected node into view
                        this.scrollIntoViewIfNeeded();
                    });
            }
        },

        _activePageChangedHandler: function(event, widget) {
            var id, win,
                newPage = event && event.page, curPage;

            widget = widget || this;

            // Only change if new page is valid
            if (!newPage) {
                return;
            }
            id = newPage.getUid();
            curPage = widget.options.model.getActivePage();

            // Only change if new page not the current page
            if (curPage && curPage.getUid() === id) {
                return;
            }

            win = widget.options.contentDocument[0].defaultView;

            if (win && win.$ && win.$.mobile) {
                win.$.mobile.changePage("#"+id, {transition: "none"});
            }
        },

        _modelUpdatedHandler: function(event, widget) {
            var win;

            widget = widget || this;

            widget.refresh(event, widget);

            win = widget.options.contentDocument[0].defaultView;
            if (win && win.$ && win.$.mobile) {
                win.$.mobile.activePage.page('destroy');
                win.$.mobile.activePage.page();
            } else {
                console.error(widget.widgetName, ':: Missing contentDocument');
            }
        },

        _createDocument: function() {
            var contents, doc;

            if (!this.designRoot) return;

            doc = this.options.contentDocument[0];
            doc.open();
            contents = this._serializeFramework(this.designRoot);
            doc.writeln(contents);
            doc.close();
        },

        _serializeFramework: function() {
            var start, end, ret, headers;

            headers = this._getCustomHeaders();

            start = '<!DOCTYPE html>\n <title>Page Title</title>\n';
            end = "\n\n\n";

            if (headers && headers.length > 0) {
                ret = start + headers.join('\n') + end;
            } else {
                ret = start + end;
            }

            return ret;
        },

        // Great assumptions are being made here that the incoming default
        // headers are already "sorted" and in the order in which they should
        // be inserted into the  node of the document being created...
        _getCustomHeaders: function() {
            var dh = $.gb.getDefaultHeaders(),   // default headers
                ch = this.options.customHeaders, // our custom headers
                m, s;

            $.each(dh, function(idx) {
                if (/<meta/.test(this)) {
                    m = idx+1; // Insert our Meta after LAST one
                    return;
                }
                if (/