<commit_before>/**
 * TrackpadScrollEmulator
 * Version: 1.0.2
 * Author: Jonathan Nicol @f6design
 * https://github.com/jnicol/trackpad-scroll-emulator
 *
 * The MIT License
 *
 * Copyright (c) 2012-2013 Jonathan Nicol
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
;(function($) {
  var pluginName = 'TrackpadScrollEmulator';

  function Plugin(element, options) {
    var el = element;
    var $el = $(element);
    var $scrollContentEl;
    var $contentEl = $el.find('.tse-content');
    var $scrollbarEl;
    var $dragHandleEl;
    var dragOffset;
    var flashTimeout;
    var scrollDirection = 'vert';
    var scrollOffsetAttr = 'scrollTop';
    var sizeAttr = 'height';
    var offsetAttr = 'top';

    options = $.extend({}, $.fn[pluginName].defaults, options);

    /**
     * Initialize plugin
     */
    function init() {
      if ($el.hasClass('horizontal')){
        scrollDirection = 'horiz';
        scrollOffsetAttr = 'scrollLeft';
        sizeAttr = 'width';
        offsetAttr = 'left';
      }

      $el.prepend('

');
      $scrollbarEl = $el.find('.tse-scrollbar');
      $dragHandleEl = $el.find('.drag-handle');

      if (options.wrapContent) {
        $contentEl.wrap('
');
      }
      $scrollContentEl = $el.find('.tse-scroll-content');

      resizeScrollContent();

      $el.on('mouseenter', flashScrollbar);
      $dragHandleEl.on('mousedown', startDrag);
      $scrollContentEl.on('scroll', onScrolled);

      resizeScrollbar();

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

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

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

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

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

      // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
      var eventOffset = e.pageY;
      if (scrollDirection === 'horiz') {
        eventOffset = e.pageX;
      }
      var dragPos = eventOffset - $scrollbarEl.offset()[offsetAttr] - dragOffset;
      // Convert the mouse position into a percentage of the scrollbar height/width.
      var dragPerc = dragPos / $scrollbarEl[sizeAttr]();
      // Scroll the content by the same percentage.
      var scrollPos = dragPerc * $contentEl[sizeAttr]();

      $scrollContentEl[scrollOffsetAttr](scrollPos);
    }

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

    /**
     * Scroll callback
     */
    function onScrolled(e) {
      flashScrollbar();
    }

    /**
     * Resize scrollbar
     */
    function resizeScrollbar() {
      var contentSize = $contentEl[sizeAttr]();
      var scrollOffset = $scrollContentEl[scrollOffsetAttr](); // Either scrollTop() or scrollLeft().
      var scrollbarSize = $scrollbarEl[sizeAttr]();
      var scrollbarRatio = scrollbarSize / contentSize;

      // Calculate new height/position of drag handle.
      // Offset of 2px allows for a small top/bottom or left/right margin around handle.
      var handleOffset = Math.round(scrollbarRatio * scrollOffset) + 2;
      var handleSize = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

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

    /**
     * Flash scrollbar visibility
     */
    function flashScrollbar() {
      resizeScrollbar();
      showScrollbar();
    }

    /**
     * Show scrollbar
     */
    function showScrollbar() {
        $dragHandleEl.addClass('visible');

        if (!options.autoHide) {
          return;
        }
        if(typeof flashTimeout === 'number') {
          window.clearTimeout(flashTimeout);
        }
        flashTimeout = window.setTimeout(function() {
            hideScrollbar();
        }, 1000);
    }

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

    /**
     * Resize content element
     */
    function resizeScrollContent() {
      if (scrollDirection === 'vert'){
        $scrollContentEl.width($el.width()+scrollbarWidth());
        $scrollContentEl.height($el.height());
      } else {
        $scrollContentEl.width($el.width());
        $scrollContentEl.height($el.height()+scrollbarWidth());
        $contentEl.height($el.height());
      }
    }

    /**
     * Calculate scrollbar width
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     * Updated to work in Chrome v25.
     */
    function scrollbarWidth() {
      // Append a temporary scrolling element to the DOM, then measure
      // the difference between between its outer and inner elements.
      var tempEl = $('

');
      $('body').append(tempEl);
      var width = $(tempEl).innerWidth();
      var widthMinusScrollbars = $('div', tempEl).innerWidth();
      tempEl.remove();
      return (width - widthMinusScrollbars);
    }

    /**
     * Recalculate scrollbar
     */
    function recalculate() {
      resizeScrollContent();
      resizeScrollbar();
    }

    /**
     * Get/Set plugin option.
     */
    function option (key, val) {
      if (val) {
        options[key] = val;
      } else {
        return options[key];
      }
    }

    /**
     * Destroy plugin.
     */
    function destroy() {
      // Restore the element to its original state.
      $contentEl.insertBefore($scrollbarEl);
      $scrollbarEl.remove();
      $scrollContentEl.remove();
      $contentEl.css({'height': $el.height()+'px', 'overflow-y': 'scroll'});

      hook('onDestroy');
      $el.removeData('plugin_' + pluginName);
    }

    /**
     * Plugin callback hook.
     */
    function hook(hookName) {
      if (options[hookName] !== undefined) {
        options[hookName].call(el);
      }
    }

    init();

    return {
      option: option,
      destroy: destroy,
      recalculate: recalculate
    };
  }

  $.fn[pluginName] = function(options) {
    if (typeof arguments[0] === 'string') {
      var methodName = arguments[0];
      var args = Array.prototype.slice.call(arguments, 1);
      var returnVal;
      this.each(function() {
        if ($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') {
          returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args);
        } else {
          throw new Error('Method ' +  methodName + ' does not exist on jQuery.' + pluginName);
        }
      });
      if (returnVal !== undefined){
        return returnVal;
      } else {
        return this;
      }
    } else if (typeof options === "object" || !options) {
      return this.each(function() {
        if (!$.data(this, 'plugin_' + pluginName)) {
          $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
        }
      });
    }
  };

  $.fn[pluginName].defaults = {
    onInit: function() {},
    onDestroy: function() {},
    wrapContent: true,
    autoHide: true
  };

})(jQuery);<commit_msg>Remove useless event binding when auto hide is disabled.<commit_after>/**
 * TrackpadScrollEmulator
 * Version: 1.0.2
 * Author: Jonathan Nicol @f6design
 * https://github.com/jnicol/trackpad-scroll-emulator
 *
 * The MIT License
 *
 * Copyright (c) 2012-2013 Jonathan Nicol
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
;(function($) {
  var pluginName = 'TrackpadScrollEmulator';

  function Plugin(element, options) {
    var el = element;
    var $el = $(element);
    var $scrollContentEl;
    var $contentEl = $el.find('.tse-content');
    var $scrollbarEl;
    var $dragHandleEl;
    var dragOffset;
    var flashTimeout;
    var scrollDirection = 'vert';
    var scrollOffsetAttr = 'scrollTop';
    var sizeAttr = 'height';
    var offsetAttr = 'top';

    options = $.extend({}, $.fn[pluginName].defaults, options);

    /**
     * Initialize plugin
     */
    function init() {
      if ($el.hasClass('horizontal')){
        scrollDirection = 'horiz';
        scrollOffsetAttr = 'scrollLeft';
        sizeAttr = 'width';
        offsetAttr = 'left';
      }

      $el.prepend('

');
      $scrollbarEl = $el.find('.tse-scrollbar');
      $dragHandleEl = $el.find('.drag-handle');

      if (options.wrapContent) {
        $contentEl.wrap('
');
      }
      $scrollContentEl = $el.find('.tse-scroll-content');

      resizeScrollContent();

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

      $dragHandleEl.on('mousedown', startDrag);
      $scrollContentEl.on('scroll', onScrolled);

      resizeScrollbar();

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

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

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

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

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

      // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
      var eventOffset = e.pageY;
      if (scrollDirection === 'horiz') {
        eventOffset = e.pageX;
      }
      var dragPos = eventOffset - $scrollbarEl.offset()[offsetAttr] - dragOffset;
      // Convert the mouse position into a percentage of the scrollbar height/width.
      var dragPerc = dragPos / $scrollbarEl[sizeAttr]();
      // Scroll the content by the same percentage.
      var scrollPos = dragPerc * $contentEl[sizeAttr]();

      $scrollContentEl[scrollOffsetAttr](scrollPos);
    }

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

    /**
     * Scroll callback
     */
    function onScrolled(e) {
      flashScrollbar();
    }

    /**
     * Resize scrollbar
     */
    function resizeScrollbar() {
      var contentSize = $contentEl[sizeAttr]();
      var scrollOffset = $scrollContentEl[scrollOffsetAttr](); // Either scrollTop() or scrollLeft().
      var scrollbarSize = $scrollbarEl[sizeAttr]();
      var scrollbarRatio = scrollbarSize / contentSize;

      // Calculate new height/position of drag handle.
      // Offset of 2px allows for a small top/bottom or left/right margin around handle.
      var handleOffset = Math.round(scrollbarRatio * scrollOffset) + 2;
      var handleSize = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

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

    /**
     * Flash scrollbar visibility
     */
    function flashScrollbar() {
      resizeScrollbar();
      showScrollbar();
    }

    /**
     * Show scrollbar
     */
    function showScrollbar() {
        $dragHandleEl.addClass('visible');

        if (!options.autoHide) {
          return;
        }
        if(typeof flashTimeout === 'number') {
          window.clearTimeout(flashTimeout);
        }
        flashTimeout = window.setTimeout(function() {
            hideScrollbar();
        }, 1000);
    }

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

    /**
     * Resize content element
     */
    function resizeScrollContent() {
      if (scrollDirection === 'vert'){
        $scrollContentEl.width($el.width()+scrollbarWidth());
        $scrollContentEl.height($el.height());
      } else {
        $scrollContentEl.width($el.width());
        $scrollContentEl.height($el.height()+scrollbarWidth());
        $contentEl.height($el.height());
      }
    }

    /**
     * Calculate scrollbar width
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     * Updated to work in Chrome v25.
     */
    function scrollbarWidth() {
      // Append a temporary scrolling element to the DOM, then measure
      // the difference between between its outer and inner elements.
      var tempEl = $('

');
      $('body').append(tempEl);
      var width = $(tempEl).innerWidth();
      var widthMinusScrollbars = $('div', tempEl).innerWidth();
      tempEl.remove();
      return (width - widthMinusScrollbars);
    }

    /**
     * Recalculate scrollbar
     */
    function recalculate() {
      resizeScrollContent();
      resizeScrollbar();
    }

    /**
     * Get/Set plugin option.
     */
    function option (key, val) {
      if (val) {
        options[key] = val;
      } else {
        return options[key];
      }
    }

    /**
     * Destroy plugin.
     */
    function destroy() {
      // Restore the element to its original state.
      $contentEl.insertBefore($scrollbarEl);
      $scrollbarEl.remove();
      $scrollContentEl.remove();
      $contentEl.css({'height': $el.height()+'px', 'overflow-y': 'scroll'});

      hook('onDestroy');
      $el.removeData('plugin_' + pluginName);
    }

    /**
     * Plugin callback hook.
     */
    function hook(hookName) {
      if (options[hookName] !== undefined) {
        options[hookName].call(el);
      }
    }

    init();

    return {
      option: option,
      destroy: destroy,
      recalculate: recalculate
    };
  }

  $.fn[pluginName] = function(options) {
    if (typeof arguments[0] === 'string') {
      var methodName = arguments[0];
      var args = Array.prototype.slice.call(arguments, 1);
      var returnVal;
      this.each(function() {
        if ($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') {
          returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args);
        } else {
          throw new Error('Method ' +  methodName + ' does not exist on jQuery.' + pluginName);
        }
      });
      if (returnVal !== undefined){
        return returnVal;
      } else {
        return this;
      }
    } else if (typeof options === "object" || !options) {
      return this.each(function() {
        if (!$.data(this, 'plugin_' + pluginName)) {
          $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
        }
      });
    }
  };

  $.fn[pluginName].defaults = {
    onInit: function() {},
    onDestroy: function() {},
    wrapContent: true,
    autoHide: true
  };

})(jQuery);<|endoftext|>


<commit_before>var cryptoUtil = require('../util/crypto');
var InsightStorage = require('./InsightStorage');
var inherits = require('inherits');

function EncryptedInsightStorage(config) {
  InsightStorage.apply(this, [config]);
}
inherits(EncryptedInsightStorage, InsightStorage);

EncryptedInsightStorage.prototype.getItem = function(name, callback) {
  var key = cryptoUtil.kdfbinary(this.password + this.email);
  InsightStorage.prototype.getItem.apply(this, [name,
    function(err, body) {
      if (err) {
        return callback(err);
      }
      var decryptedJson = cryptoUtil.decrypt(key, body);
      if (!decryptedJson) {
        return callback('Internal Error');
      }
      return callback(null, decryptedJson);
    }
  ]);
};

EncryptedInsightStorage.prototype.setItem = function(name, value, callback) {
  var key = cryptoUtil.kdfbinary(this.password + this.email);
  var record = cryptoUtil.encrypt(key, value);
  InsightStorage.prototype.setItem.apply(this, [name, record, callback]);
};

EncryptedInsightStorage.prototype.removeItem = function(name, callback) {
  var key = cryptoUtil.kdfbinary(this.password + this.email);
  InsightStorage.prototype.removeItem.apply(this, [name, callback]);
};

module.exports = EncryptedInsightStorage;
<commit_msg>Use the same kdf for Insight Storage<commit_after>var cryptoUtil = require('../util/crypto');
var InsightStorage = require('./InsightStorage');
var inherits = require('inherits');

function EncryptedInsightStorage(config) {
  InsightStorage.apply(this, [config]);
}
inherits(EncryptedInsightStorage, InsightStorage);

EncryptedInsightStorage.prototype.getItem = function(name, callback) {
  var key = cryptoUtil.kdf(this.password + this.email);
  InsightStorage.prototype.getItem.apply(this, [name,
    function(err, body) {
      if (err) {
        return callback(err);
      }
      var decryptedJson = cryptoUtil.decrypt(key, body);
      if (!decryptedJson) {
        return callback('Internal Error');
      }
      return callback(null, decryptedJson);
    }
  ]);
};

EncryptedInsightStorage.prototype.setItem = function(name, value, callback) {
  var key = cryptoUtil.kdf(this.password + this.email);
  var record = cryptoUtil.encrypt(key, value);
  InsightStorage.prototype.setItem.apply(this, [name, record, callback]);
};

EncryptedInsightStorage.prototype.removeItem = function(name, callback) {
  var key = cryptoUtil.kdf(this.password + this.email);
  InsightStorage.prototype.removeItem.apply(this, [name, callback]);
};

module.exports = EncryptedInsightStorage;
<|endoftext|>


<commit_before>import {
    createExtensionsValidator,
    validateAdapter,
    validateArgs,
    validateCreateExtensionsMethod,
    validateExtra,
    validateHook,
    validateHooks,
    validateMethodName,
    validatePlugins
} from './validation';
import requiredMethods from './requiredMethods';

function upperFirst(string) {
    const firstLetter = string[0];
    const restOfTheString = string.substr(1);

    return `${firstLetter.toUpperCase()}${restOfTheString}`;
}

const passDataThrough = (eventHandlers) => (args) => {
    return eventHandlers.reduce(async (previousValue, handler) => {
        return await handler(await previousValue);
    }, args);
};

function passDataThroughHooks(hooks, event, args) {
    const eventHandlers = hooks[event];
    const resolvedArgs = Promise.resolve(args);

    return Array.isArray(eventHandlers) ? passDataThrough(eventHandlers)(resolvedArgs) : resolvedArgs;
}

export const getPreData = (methodName, args) => {
    validateMethodName(methodName);
    validateArgs(args);

    const hooks = args.cacheInstance.getHooks();
    const event = `pre${upperFirst(methodName)}`;

    return passDataThroughHooks(hooks, event, args);
};

export const getPostData = (methodName, args) => {
    validateMethodName(methodName);
    validateArgs(args);

    const hooks = args.cacheInstance.getHooks();
    const event = `post${upperFirst(methodName)}`;

    return passDataThroughHooks(hooks, event, args);
};

function cloneHooks(hooks) {
    const cloned = {};

    Object.entries(hooks).forEach(([ event, handlers ]) => {
        cloned[event] = handlers.map((handler) => handler);
    });

    return cloned;
}

export function createCache(adapter) {
    validateAdapter(adapter, requiredMethods);

    const cacheInstance = {
        hooks: {},

        addHook(hook) {
            validateHook(hook);

            const { event, handler } = hook;

            this.hooks[event] ? this.hooks[event].push(handler) : (this.hooks[event] = [handler]);
        },

        addHooks(hooks) {
            validateHooks(hooks);

            hooks.forEach(this.addHook.bind(this));
        },

        getHooks() {
            return this.hooks;
        },

        buildKey(key) {
            const preData = getPreData('buildKey', { cacheInstance: this, key });
            const builtKey = adapter.buildKey(preData.key);
            const postData = getPostData('buildKey', { cacheInstance: preData.cacheInstance, key: builtKey });

            return postData.key;
        },

        getItem(key) {
            const preData = getPreData('getItem', { cacheInstance: this, key });
            const item = adapter.getItem(this.buildKey(preData.key));
            const postData = getPostData('getItem', { cacheInstance: preData.cacheInstance, key: preData.key, item });

            return postData.item;
        },

        getExtra(key) {
            const preData = getPreData('getExtra', { cacheInstance: this, key });
            const extra = adapter.getExtra(this.buildKey(preData.key));
            const postData = getPostData('getExtra', { cacheInstance: preData.cacheInstance, key: preData.key, extra });

            return postData.extra;
        },

        setItem(key, value, extra = {}) {
            const preData = getPreData('setItem', { cacheInstance: this, key, value, extra });
            const item = adapter.setItem(this.buildKey(preData.key), preData.value, preData.extra);
            const postData = getPostData('setItem', {
                cacheInstance: preData.cacheInstance,
                key: preData.key,
                value: preData.value,
                extra: preData.extra,
                item
            });

            return postData.item;
        },

        addExtra(key, extra) {
            const preData = getPreData('addExtra', { cacheInstance: this, key, extra });

            validateExtra(preData.extra);

            const addedExtra =
                this.hasItem(preData.key)
                    ? adapter.addExtra(this.buildKey(preData.key), preData.extra)
                    : undefined;
            const postData = getPostData('addExtra', {
                cacheInstance: preData.cacheInstance, key: preData.key, extra: addedExtra });

            return postData.extra;
        },

        setExtra(key, extra) {
            const preData = getPreData('setExtra', { cacheInstance: this, key, extra });

            validateExtra(preData.extra);

            const setExtra =
                this.hasItem(preData.key)
                    ? adapter.setExtra(this.buildKey(preData.key), preData.extra)
                    : undefined;
            const postData = getPostData('setExtra', {
                cacheInstance: preData.cacheInstance, key: preData.key, extra: setExtra });

            return postData.extra;
        },

        hasItem(key) {
            const preData = getPreData('hasItem', { cacheInstance: this, key });
            const result = adapter.hasItem(this.buildKey(preData.key));
            const postData = getPostData('hasItem', { cacheInstance: preData.cacheInstance, key: preData.key, result });

            return postData.result;
        },

        removeItem(key) {
            const preData = getPreData('removeItem', { cacheInstance: this, key });
            const result = adapter.removeItem(this.buildKey(preData.key));
            const postData = getPostData('removeItem', {
                cacheInstance: preData.cacheInstance,
                key: preData.key,
                result
            });

            return postData.result;
        },

        registerPlugins(plugins) {
            validatePlugins(plugins);

            const extendedCacheInstance = plugins.reduce((instance, plugin) => {
                if (plugin.createExtensions) {
                    validateCreateExtensionsMethod(plugin.createExtensions);

                    const extensionsValidator = createExtensionsValidator(instance);
                    const extensionsFromPlugin = plugin.createExtensions({
                        cacheInstance: instance, getPreData, getPostData
                    });

                    extensionsValidator(extensionsFromPlugin);

                    return Object.assign({}, instance, extensionsFromPlugin);
                }

                return instance;
            }, this);
            const hooks = cloneHooks(extendedCacheInstance.getHooks());
            const cacheInstanceWithHooksCopied = Object.assign({}, extendedCacheInstance, { hooks });

            plugins.forEach(({ hooks }) => {
                hooks ? cacheInstanceWithHooksCopied.addHooks(hooks) : null;
            });

            return Object.freeze(cacheInstanceWithHooksCopied);
        }
    };

    return Object.freeze(cacheInstance);
}
<commit_msg>Extract abstract function for getPreData and getPostData ones<commit_after>import {
    createExtensionsValidator,
    validateAdapter,
    validateArgs,
    validateCreateExtensionsMethod,
    validateExtra,
    validateHook,
    validateHooks,
    validateMethodName,
    validatePlugins
} from './validation';
import requiredMethods from './requiredMethods';

function upperFirst(string) {
    const firstLetter = string[0];
    const restOfTheString = string.substr(1);

    return `${firstLetter.toUpperCase()}${restOfTheString}`;
}

const passDataThrough = (eventHandlers) => (args) => {
    return eventHandlers.reduce(async (previousValue, handler) => {
        return await handler(await previousValue);
    }, args);
};

function passDataThroughHooks(hooks, event, args) {
    const eventHandlers = hooks[event];
    const resolvedArgs = Promise.resolve(args);

    return Array.isArray(eventHandlers) ? passDataThrough(eventHandlers)(resolvedArgs) : resolvedArgs;
}

const getData = (when, methodName, args) => {
    validateMethodName(methodName);
    validateArgs(args);

    const hooks = args.cacheInstance.getHooks();
    const event = `${when}${upperFirst(methodName)}`;

    return passDataThroughHooks(hooks, event, args);
};

export const getPreData = (methodName, args) => getData('pre', methodName, args);
export const getPostData = (methodName, args) => getData('post', methodName, args);

function cloneHooks(hooks) {
    const cloned = {};

    Object.entries(hooks).forEach(([ event, handlers ]) => {
        cloned[event] = handlers.map((handler) => handler);
    });

    return cloned;
}

export function createCache(adapter) {
    validateAdapter(adapter, requiredMethods);

    const cacheInstance = {
        hooks: {},

        addHook(hook) {
            validateHook(hook);

            const { event, handler } = hook;

            this.hooks[event] ? this.hooks[event].push(handler) : (this.hooks[event] = [handler]);
        },

        addHooks(hooks) {
            validateHooks(hooks);

            hooks.forEach(this.addHook.bind(this));
        },

        getHooks() {
            return this.hooks;
        },

        buildKey(key) {
            const preData = getPreData('buildKey', { cacheInstance: this, key });
            const builtKey = adapter.buildKey(preData.key);
            const postData = getPostData('buildKey', { cacheInstance: preData.cacheInstance, key: builtKey });

            return postData.key;
        },

        getItem(key) {
            const preData = getPreData('getItem', { cacheInstance: this, key });
            const item = adapter.getItem(this.buildKey(preData.key));
            const postData = getPostData('getItem', { cacheInstance: preData.cacheInstance, key: preData.key, item });

            return postData.item;
        },

        getExtra(key) {
            const preData = getPreData('getExtra', { cacheInstance: this, key });
            const extra = adapter.getExtra(this.buildKey(preData.key));
            const postData = getPostData('getExtra', { cacheInstance: preData.cacheInstance, key: preData.key, extra });

            return postData.extra;
        },

        setItem(key, value, extra = {}) {
            const preData = getPreData('setItem', { cacheInstance: this, key, value, extra });
            const item = adapter.setItem(this.buildKey(preData.key), preData.value, preData.extra);
            const postData = getPostData('setItem', {
                cacheInstance: preData.cacheInstance,
                key: preData.key,
                value: preData.value,
                extra: preData.extra,
                item
            });

            return postData.item;
        },

        addExtra(key, extra) {
            const preData = getPreData('addExtra', { cacheInstance: this, key, extra });

            validateExtra(preData.extra);

            const addedExtra =
                this.hasItem(preData.key)
                    ? adapter.addExtra(this.buildKey(preData.key), preData.extra)
                    : undefined;
            const postData = getPostData('addExtra', {
                cacheInstance: preData.cacheInstance, key: preData.key, extra: addedExtra });

            return postData.extra;
        },

        setExtra(key, extra) {
            const preData = getPreData('setExtra', { cacheInstance: this, key, extra });

            validateExtra(preData.extra);

            const setExtra =
                this.hasItem(preData.key)
                    ? adapter.setExtra(this.buildKey(preData.key), preData.extra)
                    : undefined;
            const postData = getPostData('setExtra', {
                cacheInstance: preData.cacheInstance, key: preData.key, extra: setExtra });

            return postData.extra;
        },

        hasItem(key) {
            const preData = getPreData('hasItem', { cacheInstance: this, key });
            const result = adapter.hasItem(this.buildKey(preData.key));
            const postData = getPostData('hasItem', { cacheInstance: preData.cacheInstance, key: preData.key, result });

            return postData.result;
        },

        removeItem(key) {
            const preData = getPreData('removeItem', { cacheInstance: this, key });
            const result = adapter.removeItem(this.buildKey(preData.key));
            const postData = getPostData('removeItem', {
                cacheInstance: preData.cacheInstance,
                key: preData.key,
                result
            });

            return postData.result;
        },

        registerPlugins(plugins) {
            validatePlugins(plugins);

            const extendedCacheInstance = plugins.reduce((instance, plugin) => {
                if (plugin.createExtensions) {
                    validateCreateExtensionsMethod(plugin.createExtensions);

                    const extensionsValidator = createExtensionsValidator(instance);
                    const extensionsFromPlugin = plugin.createExtensions({
                        cacheInstance: instance, getPreData, getPostData
                    });

                    extensionsValidator(extensionsFromPlugin);

                    return Object.assign({}, instance, extensionsFromPlugin);
                }

                return instance;
            }, this);
            const hooks = cloneHooks(extendedCacheInstance.getHooks());
            const cacheInstanceWithHooksCopied = Object.assign({}, extendedCacheInstance, { hooks });

            plugins.forEach(({ hooks }) => {
                hooks ? cacheInstanceWithHooksCopied.addHooks(hooks) : null;
            });

            return Object.freeze(cacheInstanceWithHooksCopied);
        }
    };

    return Object.freeze(cacheInstance);
}
<|endoftext|>


<commit_before>'use strict';

const crypto = require('crypto');
const lodash = require('lodash');

class Route {
  constructor(route) {
    this.validate(route);

    this.left = {
      url: this.getUrl(route, 'left'),
      method: this.getParam(route, 'left', 'method', 'GET')
    };

    this.right = {
      url: this.getUrl(route, 'right'),
      method: this.getParam(route, 'right', 'method', 'GET')
    };

    // set optional test properties
    ['before', 'after', 'name'].forEach((prop) => {
      if (prop in route) {
        this[prop] = route[prop];
      }
    });

    // set optional site properties
    ['ignoreBody', 'ignoreHeader', 'status', 'header', 'query'].forEach((prop) => {
      if (!this.left[prop]) {
        const param = this.getParam(route, 'left', prop);
        if (param) {
          this.left[prop] = param;
        }
      }

      if (!this.right[prop]) {
        const param = this.getParam(route, 'right', prop);
        if (param) {
          this.right[prop] = param;
        }
      }
    });

    // set optional route only properties
    ['before', 'after'].forEach((prop) => {
      if (!this.left[prop]) {
        const param = this.getSiteParam(route, 'left', prop);
        if (param) {
          this.left[prop] = param;
        }
      }

      if (!this.right[prop]) {
        const param = this.getSiteParam(route, 'right', prop);
        if (param) {
          this.right[prop] = param;
        }
      }
    });

    this.createId();
    this.createName();
  }

  validate(validateionData) {
    const ALLOWED_SITE_KEYS = [
      'method',
      'hostname', 'url', 'header',
      'query', 'ignoreBody',
      'ignoreHeader', 'status'
    ];

    const ALLOWED_ROUTE_KEYS = [
      'name', 'tag', 'before', 'after'
    ];

    const ALLOWED_METHODS = [
      'GET', 'POST', 'PUT', 'DELETE',
      'HEAD', 'CHECKOUT', 'COPY',
      'LOCK', 'MERGE', 'MKACTIVITY',
      'MKCOL', 'MOVE', 'M-SEARCH',
      'NOTIFY', 'OPTIONS', 'PATCH',
      'PURGE', 'REPORT', 'SEARCH',
      'SUBSCRIBE', 'TRACE',
      'UNLOCK', 'UNSUBSCRIBE'
    ];

    const regAllowedSiteKeys = new RegExp(`^${ALLOWED_SITE_KEYS.join('|')}$`);
    const regAllowedRouteKeys = new RegExp(`^${ALLOWED_ROUTE_KEYS.concat(ALLOWED_SITE_KEYS).join('|')}$`);
    const regAllowedMethods = new RegExp(`^${ALLOWED_METHODS.join('|')}$`);

    const validate = (obj, level) => {
      Object.keys(obj).forEach((key) => {
        if ((key === 'left' || key === 'right') && !level) {
          validate(obj[key], key);
          return;
        }

        const reg = level ? regAllowedSiteKeys : regAllowedRouteKeys;
        if (!reg.test(key)) {
          throw new Error(`Invalid configuration! ${key} not allowed in ${level || 'base'} route`);
        }
      });
    };

    ['method', 'left.method', 'right.method'].forEach((key) => {
      const value = lodash.get(validateionData, key);
      if (value && !regAllowedMethods.test(value)) {
        throw new Error(`Invalid configuration! ${value} is not a valid method in ${key}`);
      }
    });

    validate(validateionData);
  }

  getParam(route, site, param, defaultValue) {
    if (route[site] && route[site][param]) {
      return route[site][param];
    }

    return route[param] || defaultValue;
  }

  getSiteParam(route, site, param, defaultValue) {
    if (route[site] && route[site][param]) {
      return route[site][param];
    }

    return defaultValue;
  }

  getUrl(route, site) {
    if (route[site] && route[site].hostname) {
      const hostname = route[site].hostname.replace(/\/$/, '');
      return `${hostname}/${route[site].url || route.url}`;
    }

    if (route.hostname) {
      const hostname = route.hostname.replace(/\/$/, '');
      return `${hostname}/${route[site].url || route.url}`;
    }

    return route[site] && route[site].url ? route[site].url : route.url;
  }

  createId() {
    this.id = crypto.createHash('md5').update(this.toString()).digest('hex');
  }

  createName() {
    if (!this.name) {
      const leftName = this.left.url.replace(/^https?:\/\/.+?\//, '');
      const rightName = this.right.url.replace(/^https?:\/\/.+?\//, '');
      const name = leftName === rightName ? leftName : `${leftName} ↔ ${rightName}`;
      this.name = `${this.left.method} ${name}`;
    }
  }

  toJSON() {
    return this;
  }

  toString() {
    return JSON.stringify(this);
  }
}

module.exports = Route;
<commit_msg>Remove a duplicate /<commit_after>'use strict';

const crypto = require('crypto');
const lodash = require('lodash');

class Route {
  constructor(route) {
    this.validate(route);

    this.left = {
      url: this.getUrl(route, 'left'),
      method: this.getParam(route, 'left', 'method', 'GET')
    };

    this.right = {
      url: this.getUrl(route, 'right'),
      method: this.getParam(route, 'right', 'method', 'GET')
    };

    // set optional test properties
    ['before', 'after', 'name'].forEach((prop) => {
      if (prop in route) {
        this[prop] = route[prop];
      }
    });

    // set optional site properties
    ['ignoreBody', 'ignoreHeader', 'status', 'header', 'query'].forEach((prop) => {
      if (!this.left[prop]) {
        const param = this.getParam(route, 'left', prop);
        if (param) {
          this.left[prop] = param;
        }
      }

      if (!this.right[prop]) {
        const param = this.getParam(route, 'right', prop);
        if (param) {
          this.right[prop] = param;
        }
      }
    });

    // set optional route only properties
    ['before', 'after'].forEach((prop) => {
      if (!this.left[prop]) {
        const param = this.getSiteParam(route, 'left', prop);
        if (param) {
          this.left[prop] = param;
        }
      }

      if (!this.right[prop]) {
        const param = this.getSiteParam(route, 'right', prop);
        if (param) {
          this.right[prop] = param;
        }
      }
    });

    this.createId();
    this.createName();
  }

  validate(validateionData) {
    const ALLOWED_SITE_KEYS = [
      'method',
      'hostname', 'url', 'header',
      'query', 'ignoreBody',
      'ignoreHeader', 'status'
    ];

    const ALLOWED_ROUTE_KEYS = [
      'name', 'tag', 'before', 'after'
    ];

    const ALLOWED_METHODS = [
      'GET', 'POST', 'PUT', 'DELETE',
      'HEAD', 'CHECKOUT', 'COPY',
      'LOCK', 'MERGE', 'MKACTIVITY',
      'MKCOL', 'MOVE', 'M-SEARCH',
      'NOTIFY', 'OPTIONS', 'PATCH',
      'PURGE', 'REPORT', 'SEARCH',
      'SUBSCRIBE', 'TRACE',
      'UNLOCK', 'UNSUBSCRIBE'
    ];

    const regAllowedSiteKeys = new RegExp(`^${ALLOWED_SITE_KEYS.join('|')}$`);
    const regAllowedRouteKeys = new RegExp(`^${ALLOWED_ROUTE_KEYS.concat(ALLOWED_SITE_KEYS).join('|')}$`);
    const regAllowedMethods = new RegExp(`^${ALLOWED_METHODS.join('|')}$`);

    const validate = (obj, level) => {
      Object.keys(obj).forEach((key) => {
        if ((key === 'left' || key === 'right') && !level) {
          validate(obj[key], key);
          return;
        }

        const reg = level ? regAllowedSiteKeys : regAllowedRouteKeys;
        if (!reg.test(key)) {
          throw new Error(`Invalid configuration! ${key} not allowed in ${level || 'base'} route`);
        }
      });
    };

    ['method', 'left.method', 'right.method'].forEach((key) => {
      const value = lodash.get(validateionData, key);
      if (value && !regAllowedMethods.test(value)) {
        throw new Error(`Invalid configuration! ${value} is not a valid method in ${key}`);
      }
    });

    validate(validateionData);
  }

  getParam(route, site, param, defaultValue) {
    if (route[site] && route[site][param]) {
      return route[site][param];
    }

    return route[param] || defaultValue;
  }

  getSiteParam(route, site, param, defaultValue) {
    if (route[site] && route[site][param]) {
      return route[site][param];
    }

    return defaultValue;
  }

  getUrl(route, site) {
    if (route[site] && route[site].hostname) {
      const hostname = route[site].hostname.replace(/\/$/, '');
      return `${hostname}/${route[site].url || route.url}`;
    }

    if (route.hostname) {
      const hostname = route.hostname.replace(/\/$/, '');
      return `${hostname}/${route[site].url || route.url}`;
    }

    return route[site] && route[site].url ? route[site].url : route.url;
  }

  createId() {
    this.id = crypto.createHash('md5').update(this.toString()).digest('hex');
  }

  createName() {
    if (!this.name) {
      const leftName = this.left.url.replace(/^https?:\/\/.+?(\/)+/, '/');
      const rightName = this.right.url.replace(/^https?:\/\/.+?(\/)+/, '/');
      const name = leftName === rightName ? leftName : `${leftName} ↔ ${rightName}`;
      this.name = `${this.left.method} ${name}`;
    }
  }

  toJSON() {
    return this;
  }

  toString() {
    return JSON.stringify(this);
  }
}

module.exports = Route;
<|endoftext|>


<commit_before>var addService = function (serviceName, serviceKeyword) {
    var storage = chrome.storage.sync;
    storage.get("services", function(items) {
        if (typeof items.services === "undefined") {
            // no preferences saved, do nothing
        } else if (typeof items.services.updates === "undefined" ||
                items.services.updates[serviceName] !== "supported"){
            console.log("Adding service " + serviceName);
            var insertIndex = 2;
            if (items.services.enabled.length < 2) {
                insertIndex = 0;
            }
            // insert SkyDrive as the third enabled service
            items.services.enabled.splice(insertIndex, 0, {
                keyword: serviceKeyword,
                name: serviceName
            });
            items.services.updates = items.services.updates || {};
            items.services.updates[serviceName] = "supported";

            storage.set({"services": items.services});
        }
    });
}

var onInit = function (details) {
    console.log("ON_INIT");
    if (details.reason === "update") {
        if (details.previousVersion < "0.6.0.0") {
            // version 0.6.0.0 adds SkyDrive support
            addService("SkyDrive", "SKYDRIVE");
        }
    }
}

chrome.runtime.onInstalled.addListener(onInit);
<commit_msg>testing<commit_after>var addService = function (serviceName, serviceKeyword) {
    console.log("2");
    var storage = chrome.storage.sync;
    storage.get("services", function(items) {
        if (typeof items.services === "undefined") {
            console.log("3");
            // no preferences saved, do nothing
        } else if (typeof items.services.updates === "undefined" ||
                items.services.updates[serviceName] !== "supported"){
            console.log("Adding service " + serviceName);
            var insertIndex = 2;
            if (items.services.enabled.length < 2) {
                insertIndex = 0;
            }
            // insert SkyDrive as the third enabled service
            items.services.enabled.splice(insertIndex, 0, {
                keyword: serviceKeyword,
                name: serviceName
            });
            items.services.updates = items.services.updates || {};
            items.services.updates[serviceName] = "supported";

            storage.set({"services": items.services});
        }
    });
}

var onInit = function (details) {
    console.log("ON_INIT");
    if (details.reason === "update") {
        console.log("1");
        if (details.previousVersion < "0.6.0.0") {
            // version 0.6.0.0 adds SkyDrive support
            addService("SkyDrive", "SKYDRIVE");
        }
    }
}

chrome.runtime.onInstalled.addListener(onInit);
<|endoftext|>


<commit_before>/*******************************************************************************
 * Name: QuizziPedia::Front-End::Controllers::QuestionsManagementController;
 * Description: questa classe permette di gestire le domande utente;
 *
 * Relations with other classes:
 * +
 * +
 *
 * Creation data: 04-05-2016;
 * Author: Alberto Ferrara;
 * License: MIT.
 ********************************************************************************
 * Updates history
 *-------------------------------------------------------------------------------
 * ID: LoginController_20160504
 * Update data: 04-05-2016
 * Description: Creato il controller;
 * Author: Alberto Ferrara.
 *-------------------------------------------------------------------------------
 *******************************************************************************/

app.controller('QuestionsManagementController', QuestionsManagementController);

QuestionsManagementController.$inject = ['$scope', '$rootScope', '$routeParams', 'QuestionsService', '$location', '$mdDialog', 'QuestionItemModel', 'ErrorInfoModel'];

function QuestionsManagementController($scope, $rootScope, $routeParams, QuestionsService, $location, $mdDialog, QuestionItemModel, ErrorInfoModel){
    $scope.$on("userDownloaded", function(event, args) {
        console.log("entra");
        var username = $rootScope.userLogged.getUsername();
        if(username){
        QuestionsService.getUsersQuestions($routeParams.lang)
            .then(function(result){
                console.log(result);
                if(result.data != undefined) {
                    $scope.questions = result.data;
                }
            } ,function (err){
                console.log(err);
                $scope.error = new ErrorInfoModel("8", "Errore", "Caricamento domande non andato a buon fine");
                alert = $mdDialog.alert()
                    .title($scope.error.getTitle())
                    .content($scope.error.getMessage())
                    .ok('Ok');
                $mdDialog
                    .show( alert )
                    .finally(function() {
                        alert = undefined;
                    });
            });
        }
        });

    $scope.editQuestion = function (idQuestion) {
        $location.path('/'+$routeParams.lang+'/QML/' + idQuestion);
    };

    $scope.goToWizardCreation = function(){
        $location.path('/' + $routeParams.lang + '/wizard');
    }

    $scope.goToQMLCreation = function(){
        $location.path('/' + $routeParams.lang + '/QML');
    }

    $scope.uploadImage = function(image){
        QuestionsService.uploadImage(image)
            .success(function(uploadResponse){
                console.log(uploadResponse);
            })
            .error(function(error){
                console.log(error);
            })
    };

}
<commit_msg>aggiunto evento<commit_after>/*******************************************************************************
 * Name: QuizziPedia::Front-End::Controllers::QuestionsManagementController;
 * Description: questa classe permette di gestire le domande utente;
 *
 * Relations with other classes:
 * +
 * +
 *
 * Creation data: 04-05-2016;
 * Author: Alberto Ferrara;
 * License: MIT.
 ********************************************************************************
 * Updates history
 *-------------------------------------------------------------------------------
 * ID: LoginController_20160504
 * Update data: 04-05-2016
 * Description: Creato il controller;
 * Author: Alberto Ferrara.
 *-------------------------------------------------------------------------------
 *******************************************************************************/

app.controller('QuestionsManagementController', QuestionsManagementController);

QuestionsManagementController.$inject = ['$scope', '$rootScope', '$routeParams', 'QuestionsService', '$location', '$mdDialog', 'QuestionItemModel', 'ErrorInfoModel'];

function QuestionsManagementController($scope, $rootScope, $routeParams, QuestionsService, $location, $mdDialog, QuestionItemModel, ErrorInfoModel){
    $rootScope.$on("userDownloaded", function(event, args) {
        console.log("entra");
        var username = $rootScope.userLogged.getUsername();
        if(username){
        QuestionsService.getUsersQuestions($routeParams.lang)
            .then(function(result){
                console.log(result);
                if(result.data != undefined) {
                    $scope.questions = result.data;
                }
            } ,function (err){
                console.log(err);
                $scope.error = new ErrorInfoModel("8", "Errore", "Caricamento domande non andato a buon fine");
                alert = $mdDialog.alert()
                    .title($scope.error.getTitle())
                    .content($scope.error.getMessage())
                    .ok('Ok');
                $mdDialog
                    .show( alert )
                    .finally(function() {
                        alert = undefined;
                    });
            });
        }
        });

    $scope.editQuestion = function (idQuestion) {
        $location.path('/'+$routeParams.lang+'/QML/' + idQuestion);
    };

    $scope.goToWizardCreation = function(){
        $location.path('/' + $routeParams.lang + '/wizard');
    }

    $scope.goToQMLCreation = function(){
        $location.path('/' + $routeParams.lang + '/QML');
    }

    $scope.uploadImage = function(image){
        QuestionsService.uploadImage(image)
            .success(function(uploadResponse){
                console.log(uploadResponse);
            })
            .error(function(error){
                console.log(error);
            })
    };

}
<|endoftext|>


<commit_before>import { merge, createObject } from "../htmlbars-util/object-utils";

/**
  Node classification:

  # Primary Statement Nodes:

  These nodes are responsible for a render node that represents a morph-range.

  * block
  * inline
  * content
  * element
  * component

  # Leaf Statement Nodes:

  This node is responsible for a render node that represents a morph-attr.

  * attribute

  # Expression Nodes:

  These nodes are not directly responsible for any part of the DOM, but are
  eventually passed to a Statement Node.

  * get
  * subexpr
  * concat
*/

var base = {
  accept: function(node, morph, env, scope, template, visitor) {
    // Primitive literals are unambiguously non-array representations of
    // themselves.
    if (typeof node !== 'object') {
      return node;
    }

    switch(node[0]) {
      case 'get': return this.get(node, morph, env, scope);
      case 'subexpr': return this.subexpr(node, morph, env, scope);
      case 'concat': return this.concat(node, morph, env, scope);
      case 'block': return this.block(node, morph, env, scope, template, visitor);
      case 'inline': return this.inline(node, morph, env, scope, visitor);
      case 'content': return this.content(node, morph, env, scope, visitor);
      case 'element': return this.element(node, morph, env, scope, template, visitor);
      case 'attribute': return this.attribute(node, morph, env, scope);
      case 'component': return this.component(node, morph, env, scope, template, visitor);
    }
  },

  acceptParams: function(nodes, morph, env, scope, template) {
    if (morph.linkedParams) {
      return morph.linkedParams.params;
    }

    var arr = new Array(nodes.length);

    for (var i=0, l=nodes.length; i<l; i++) {
      arr[i] =  this.accept(nodes[i], morph, env, scope, template);
    }

    return arr;
  },

  acceptHash: function(pairs, morph, env, scope, template) {
    if (morph.linkedParams) {
      return morph.linkedParams.hash;
    }

    var object = {};

    for (var i=0, l=pairs.length; i<l; i += 2) {
      object[pairs[i]] = this.accept(pairs[i+1], morph, env, scope, template);
    }

    return object;
  },

  // [ 'get', path ]
  get: function(node, morph, env, scope) {
    return env.hooks.get(env, scope, node[1]);
  },

  // [ 'subexpr', path, params, hash ]
  subexpr: function(node, morph, env, scope, template) {
    var path = node[1], params = node[2], hash = node[3];
    return env.hooks.subexpr(env, scope, path,
                             this.acceptParams(params, morph, env, scope, template),
                             this.acceptHash(hash, morph, env, scope, template));
  },

  // [ 'concat', parts ]
  concat: function(node, morph, env, scope, template) {
    return env.hooks.concat(env, this.acceptParams(node[1], morph, env, scope, template));
  }
};

export var AlwaysDirtyVisitor = merge(createObject(base), {
  // [ 'block', path, params, hash, templateId, inverseId ]
  block: function(node, morph, env, scope, template, visitor) {
    var path = node[1], params = node[2], hash = node[3], templateId = node[4], inverseId = node[5];
    env.hooks.block(morph, env, scope, path,
                           this.acceptParams(params, morph, env, scope, template),
                           this.acceptHash(hash, morph, env, scope, template),
                           templateId === null ? null : template.templates[templateId],
                           inverseId === null ? null : template.templates[inverseId],
                           visitor);
  },

  // [ 'inline', path, params, hash ]
  inline: function(node, morph, env, scope, template, visitor) {
    var path = node[1], params = node[2], hash = node[3];
    env.hooks.inline(morph, env, scope, path,
                            this.acceptParams(params, morph, env, scope, template),
                            this.acceptHash(hash, morph, env, scope, template),
                            visitor);
  },

  // [ 'content', path ]
  content: function(node, morph, env, scope, visitor) {
    env.hooks.content(morph, env, scope, node[1], visitor);
  },

  // [ 'element', path, params, hash ]
  element: function(node, morph, env, scope, template, visitor) {
    var path = node[1], params = node[2], hash = node[3];
    env.hooks.element(morph, env, scope, path,
                      this.acceptParams(params, morph, env, scope, template),
                      this.acceptHash(hash, morph, env, scope, template),
                      visitor);
  },

  // [ 'attribute', name, value ]
  attribute: function(node, morph, env, scope, template) {
    env.hooks.attribute(morph, env, node[1],
                        this.acceptParams([node[2]], morph, env, scope, template)[0]);
  },

  // [ 'component', path, attrs, templateId ]
  component: function(node, morph, env, scope, template, visitor) {
    var path = node[1], attrs = node[2], templateId = node[3];
    env.hooks.component(morph, env, scope, path,
                        this.acceptHash(attrs, morph, env, scope, template),
                        template.templates[templateId],
                        visitor);
  }
});

function validateChildMorphs(morph, visitor) {
  var morphList = morph.morphList;
  if (morph.morphList) {
    var current = morphList.firstChildMorph;

    while (current) {
      var next = current.nextMorph;
      current.lastResult.revalidateWith(undefined, undefined, visitor);
      current = next;
    }
  } else if (morph.lastResult) {
    morph.lastResult.revalidateWith(undefined, undefined, visitor);
  } else if (morph.childNodes) {
    // This means that the childNodes were wired up manually
    for (var i=0, l=morph.childNodes.length; i<l; i++) {
      validateChildMorphs(morph.childNodes[i], visitor);
    }
  }
}

export default merge(createObject(base), {
  // [ 'block', path, params, hash, templateId, inverseId ]
  block: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyBlock(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    }

    validateChildMorphs(morph, visitor);
  },

  dirtyBlock: AlwaysDirtyVisitor.block,

  // [ 'inline', path, params, hash ]
  inline: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyInline(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    }

    // TODO: If child morphs were newly created by the `inline` hook
    // (via a keyword), we should not need to revalidate them again.
    validateChildMorphs(morph, visitor);
  },

  dirtyInline: AlwaysDirtyVisitor.inline,

  // [ 'content', path ]
  content: function(node, morph, env, scope, visitor) {
    if (morph.isDirty) {
      env.hooks.content(morph, env, scope, node[1], visitor);
      morph.isDirty = false;
    }

    validateChildMorphs(morph, visitor);
  },

  // [ 'element', path, params, hash ]
  element: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyElement(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    }

    validateChildMorphs(morph, visitor);
  },

  dirtyElement: AlwaysDirtyVisitor.element,

  // [ 'attribute', name, value ]
  attribute: function(node, morph, env, scope, template) {
    if (morph.isDirty) {
      this.dirtyAttribute(node, morph, env, scope, template);
      morph.isDirty = false;
    }
  },

  dirtyAttribute: AlwaysDirtyVisitor.attribute,

  // [ 'component', path, attrs, templateId ]
  component: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyComponent(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    }

    validateChildMorphs(morph, visitor);
  },

  dirtyComponent: AlwaysDirtyVisitor.component
});
<commit_msg>Avoid revalidating children twice<commit_after>import { merge, createObject } from "../htmlbars-util/object-utils";

/**
  Node classification:

  # Primary Statement Nodes:

  These nodes are responsible for a render node that represents a morph-range.

  * block
  * inline
  * content
  * element
  * component

  # Leaf Statement Nodes:

  This node is responsible for a render node that represents a morph-attr.

  * attribute

  # Expression Nodes:

  These nodes are not directly responsible for any part of the DOM, but are
  eventually passed to a Statement Node.

  * get
  * subexpr
  * concat
*/

var base = {
  accept: function(node, morph, env, scope, template, visitor) {
    // Primitive literals are unambiguously non-array representations of
    // themselves.
    if (typeof node !== 'object') {
      return node;
    }

    switch(node[0]) {
      case 'get': return this.get(node, morph, env, scope);
      case 'subexpr': return this.subexpr(node, morph, env, scope);
      case 'concat': return this.concat(node, morph, env, scope);
      case 'block': return this.block(node, morph, env, scope, template, visitor);
      case 'inline': return this.inline(node, morph, env, scope, visitor);
      case 'content': return this.content(node, morph, env, scope, visitor);
      case 'element': return this.element(node, morph, env, scope, template, visitor);
      case 'attribute': return this.attribute(node, morph, env, scope);
      case 'component': return this.component(node, morph, env, scope, template, visitor);
    }
  },

  acceptParams: function(nodes, morph, env, scope, template) {
    if (morph.linkedParams) {
      return morph.linkedParams.params;
    }

    var arr = new Array(nodes.length);

    for (var i=0, l=nodes.length; i<l; i++) {
      arr[i] =  this.accept(nodes[i], morph, env, scope, template);
    }

    return arr;
  },

  acceptHash: function(pairs, morph, env, scope, template) {
    if (morph.linkedParams) {
      return morph.linkedParams.hash;
    }

    var object = {};

    for (var i=0, l=pairs.length; i<l; i += 2) {
      object[pairs[i]] = this.accept(pairs[i+1], morph, env, scope, template);
    }

    return object;
  },

  // [ 'get', path ]
  get: function(node, morph, env, scope) {
    return env.hooks.get(env, scope, node[1]);
  },

  // [ 'subexpr', path, params, hash ]
  subexpr: function(node, morph, env, scope, template) {
    var path = node[1], params = node[2], hash = node[3];
    return env.hooks.subexpr(env, scope, path,
                             this.acceptParams(params, morph, env, scope, template),
                             this.acceptHash(hash, morph, env, scope, template));
  },

  // [ 'concat', parts ]
  concat: function(node, morph, env, scope, template) {
    return env.hooks.concat(env, this.acceptParams(node[1], morph, env, scope, template));
  }
};

export var AlwaysDirtyVisitor = merge(createObject(base), {
  // [ 'block', path, params, hash, templateId, inverseId ]
  block: function(node, morph, env, scope, template, visitor) {
    var path = node[1], params = node[2], hash = node[3], templateId = node[4], inverseId = node[5];
    env.hooks.block(morph, env, scope, path,
                           this.acceptParams(params, morph, env, scope, template),
                           this.acceptHash(hash, morph, env, scope, template),
                           templateId === null ? null : template.templates[templateId],
                           inverseId === null ? null : template.templates[inverseId],
                           visitor);
  },

  // [ 'inline', path, params, hash ]
  inline: function(node, morph, env, scope, template, visitor) {
    var path = node[1], params = node[2], hash = node[3];
    env.hooks.inline(morph, env, scope, path,
                            this.acceptParams(params, morph, env, scope, template),
                            this.acceptHash(hash, morph, env, scope, template),
                            visitor);
  },

  // [ 'content', path ]
  content: function(node, morph, env, scope, visitor) {
    env.hooks.content(morph, env, scope, node[1], visitor);
  },

  // [ 'element', path, params, hash ]
  element: function(node, morph, env, scope, template, visitor) {
    var path = node[1], params = node[2], hash = node[3];
    env.hooks.element(morph, env, scope, path,
                      this.acceptParams(params, morph, env, scope, template),
                      this.acceptHash(hash, morph, env, scope, template),
                      visitor);
  },

  // [ 'attribute', name, value ]
  attribute: function(node, morph, env, scope, template) {
    env.hooks.attribute(morph, env, node[1],
                        this.acceptParams([node[2]], morph, env, scope, template)[0]);
  },

  // [ 'component', path, attrs, templateId ]
  component: function(node, morph, env, scope, template, visitor) {
    var path = node[1], attrs = node[2], templateId = node[3];
    env.hooks.component(morph, env, scope, path,
                        this.acceptHash(attrs, morph, env, scope, template),
                        template.templates[templateId],
                        visitor);
  }
});

function validateChildMorphs(morph, visitor) {
  var morphList = morph.morphList;
  if (morph.morphList) {
    var current = morphList.firstChildMorph;

    while (current) {
      var next = current.nextMorph;
      current.lastResult.revalidateWith(undefined, undefined, visitor);
      current = next;
    }
  } else if (morph.lastResult) {
    morph.lastResult.revalidateWith(undefined, undefined, visitor);
  } else if (morph.childNodes) {
    // This means that the childNodes were wired up manually
    for (var i=0, l=morph.childNodes.length; i<l; i++) {
      validateChildMorphs(morph.childNodes[i], visitor);
    }
  }
}

export default merge(createObject(base), {
  // [ 'block', path, params, hash, templateId, inverseId ]
  block: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyBlock(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    } else {
      validateChildMorphs(morph, visitor);
    }
  },

  dirtyBlock: AlwaysDirtyVisitor.block,

  // [ 'inline', path, params, hash ]
  inline: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyInline(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    } else {
      validateChildMorphs(morph, visitor);
    }
  },

  dirtyInline: AlwaysDirtyVisitor.inline,

  // [ 'content', path ]
  content: function(node, morph, env, scope, visitor) {
    if (morph.isDirty) {
      env.hooks.content(morph, env, scope, node[1], visitor);
      morph.isDirty = false;
    } else {
      validateChildMorphs(morph, visitor);
    }
  },

  // [ 'element', path, params, hash ]
  element: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyElement(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    } else {
      validateChildMorphs(morph, visitor);
    }
  },

  dirtyElement: AlwaysDirtyVisitor.element,

  // [ 'attribute', name, value ]
  attribute: function(node, morph, env, scope, template) {
    if (morph.isDirty) {
      this.dirtyAttribute(node, morph, env, scope, template);
      morph.isDirty = false;
    }
  },

  dirtyAttribute: AlwaysDirtyVisitor.attribute,

  // [ 'component', path, attrs, templateId ]
  component: function(node, morph, env, scope, template, visitor) {
    if (morph.isDirty) {
      this.dirtyComponent(node, morph, env, scope, template, visitor);
      morph.isDirty = false;
    } else {
      validateChildMorphs(morph, visitor);
    }
  },

  dirtyComponent: AlwaysDirtyVisitor.component
});
<|endoftext|>


<commit_before>showChart = function( area, sensor, period, unit ) {
    $( area ).empty();

    var margin = {top: 20, right: 50, bottom: 30, left: 50 },
        width = 700 - margin.left - margin.right,
        height = 250 - margin.top - margin.bottom;

    var parseDate = d3.time.format("%Y-%m-%d %X").parse;

    var x = d3.time.scale()
        .range([0, width]);

    var y = d3.scale.linear()
        .range([height, 0]);

    y.ticks(0.1);

    var xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat( function(d) { return d3.time.format('%H:%M')(d); } )
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .tickSize(-width,0,0)
        .tickFormat( d3.format(',.1f') )
        .orient("left");

    var yAxis2 = d3.svg.axis()
        .scale(y)
        .tickFormat( d3.format(',.1f') )
        .orient("right");

    // interpolate 'smoothens' the line
    var line = d3.svg.line()
        .interpolate("monotone")
        .x(function (d) { return x(d.timestamp); })

    .y(function (d) {
        return y(d.value);
    });

    var svg = d3.select( area ).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    d3.csv("/sensor-data.php?action=csv_data&id="+sensor+"&period="+period, function (error, data) {
        data.forEach(function (d) {
            d.timestamp = parseDate(d.timestamp);
            d.value = +d.value;
        });

        x.domain(d3.extent(data, function (d) {return d.timestamp; }));
        y.domain( [d3.min(data, function (d) {return d.value; })-0.1,d3.max(data, function (d) {return d.value; })+0.1] ).nice();

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

        svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
            .append("text")
            .attr("transform", "rotate(-90) translate(0,-50)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .text(unit);

        svg.append("g")
            .attr("class", "y2 axis")
            .attr("transform", "translate(" + width + " ,0)")
            .call(yAxis2)
            .append("text")
            .attr("transform", "rotate(90) translate(0, -50)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "start")
            .text(unit);

        svg.append("path")
            .datum(data)
            .attr("class", "line")
            .attr("d", line);

        svg.selectAll("dot")
            .data(data)
            .enter().append("circle")
            .style("fill","purple")
            .attr("r", 1.0)
            .attr("cx", function(d) { return x(d.timestamp); })
            .attr("cy", function(d) { return y(d.value); });
    });
};
<commit_msg>Removed data point dots<commit_after>showChart = function( area, sensor, period, unit ) {
    $( area ).empty();

    var margin = {top: 20, right: 50, bottom: 30, left: 50 },
        width = 700 - margin.left - margin.right,
        height = 250 - margin.top - margin.bottom;

    var parseDate = d3.time.format("%Y-%m-%d %X").parse;

    var x = d3.time.scale()
        .range([0, width]);

    var y = d3.scale.linear()
        .range([height, 0]);

    y.ticks(0.1);

    var xAxis = d3.svg.axis()
        .scale(x)
        .tickFormat( function(d) { return d3.time.format('%H:%M')(d); } )
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .tickSize(-width,0,0)
        .tickFormat( d3.format(',.1f') )
        .orient("left");

    var yAxis2 = d3.svg.axis()
        .scale(y)
        .tickFormat( d3.format(',.1f') )
        .orient("right");

    // interpolate 'smoothens' the line
    var line = d3.svg.line()
        .interpolate("monotone")
        .x(function (d) { return x(d.timestamp); })

    .y(function (d) {
        return y(d.value);
    });

    var svg = d3.select( area ).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    d3.csv("/sensor-data.php?action=csv_data&id="+sensor+"&period="+period, function (error, data) {
        data.forEach(function (d) {
            d.timestamp = parseDate(d.timestamp);
            d.value = +d.value;
        });

        x.domain(d3.extent(data, function (d) {return d.timestamp; }));
        y.domain( [d3.min(data, function (d) {return d.value; })-0.1,d3.max(data, function (d) {return d.value; })+0.1] ).nice();

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

        svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
            .append("text")
            .attr("transform", "rotate(-90) translate(0,-50)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .text(unit);

        svg.append("g")
            .attr("class", "y2 axis")
            .attr("transform", "translate(" + width + " ,0)")
            .call(yAxis2)
            .append("text")
            .attr("transform", "rotate(90) translate(0, -50)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "start")
            .text(unit);

        svg.append("path")
            .datum(data)
            .attr("class", "line")
            .attr("d", line);

        // svg.selectAll("dot")
        //     .data(data)
        //     .enter().append("circle")
        //     .style("fill","purple")
        //     .attr("r", 1.0)
        //     .attr("cx", function(d) { return x(d.timestamp); })
        //     .attr("cy", function(d) { return y(d.value); });

    });
};
<|endoftext|>


<commit_before>d3.mapper = function module() {

	var _maps = {};

	function exports() {}

    exports.add = function(_m, _v, _y) {
    	_y = typeof _y !== 'undefined' ? _y : 'null';
      if(!_maps[_v]){_maps[_v] = {}}
      _maps[_v][_y] = _m;
    	return this;
    }

    exports.array = function(_a, _id) {
      if (!arguments.length) return this._getArray;
      _id = typeof _id !== 'undefined' ? _id : 'id';
      //TODO: check if all arrays have the same keys
      //TODO: returns an array representation of the mapper when _a is not specified
      var keys = Object.keys(_a[0]);
      keys.splice(keys.indexOf(_id), 1);

      for (var i = 0; i < keys.length; i++) {
        _v = keys[i];
        _o = {};
        for (var j = 0; j < _a.length; j++) {
          _o[_a[j][_id]] = _a[j][_v];
        };
        _m = d3.map(_o);
        this.add(_m, _v);
      };
      return this;
    }

    exports.get = function(_v, _y){
      // return a specific d3.map
      _y = typeof _y !== 'undefined' ? _y : 'null';
      if(_maps[_v][_y]){return _maps[_v][_y]};
      return this;
    }

	return exports;

}<commit_msg>Module organization<commit_after>d3.mapper = function() {
  var m = new d3_mapper;
  return m;
}

function d3_mapper() {

	var _maps = {};

	function exports() {}

    /**
    * Adds a d3.map to the mapper
    * @param {d3.map} _m - The d3.map to add to the mapper
    * @param {string} _v - The name of the variable mapped in the d3.map
    * @param {d3.map} _y - The year or numerical series oredring of the variable mapped in the d3.map
    * @return {d3.mapper} - The d3.mapper with the d3.map added to it
    **/
    exports.add = function(_m, _v, _y) {
    	_y = typeof _y !== 'undefined' ? _y : 'null';
      if(!_maps[_v]){_maps[_v] = {}}
      _maps[_v][_y] = _m;
    	return this;
    }

    exports.mergeWith = function(_m) {

    }

    exports.array = function(_a, _id) {
      // Create the mapper object from an array representation
      if (!arguments.length) return this._getArray;
      _id = typeof _id !== 'undefined' ? _id : 'id';
      //TODO: check if all arrays have the same keys
      //TODO: returns an array representation of the mapper when _a is not specified
      var keys = Object.keys(_a[0]);
      keys.splice(keys.indexOf(_id), 1);

      for (var i = 0; i < keys.length; i++) {
        _v = keys[i];
        _o = {};
        for (var j = 0; j < _a.length; j++) {
          _o[_a[j][_id]] = _a[j][_v];
        };
        _m = d3.map(_o);
        this.add(_m, _v);
      };
      return this;
    }

    exports.get = function(_v, _y){
      // return a specific d3.map
      _y = typeof _y !== 'undefined' ? _y : 'null';
      if(_maps[_v][_y]){return _maps[_v][_y]};
      return this;
    }

	return exports;

}<|endoftext|>


<commit_before>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * Renders a stats for each workspace
 */
var Statistics = Backbone.View.extend({

    data: {
        resultset: [],
        metadata: []
    },

    initialize: function(args) {
        this.workspace = args.workspace;

        // Create a unique ID for use as the CSS selector
        this.id = _.uniqueId("stats_");
        $(this.el).attr({ id: this.id });

        // Bind table rendering to query result event
        _.bindAll(this, "render", "receive_data", "process_data", "show",
            "setOptions");
        this.workspace.bind('query:result', this.receive_data);

        // Add stats button
        this.add_button();
        this.workspace.querytoolbar.stats = this.show;

        // Listen to adjust event and rerender stats
        this.workspace.bind('workspace:adjust', this.render);

        // Append stats to workspace
        $(this.workspace.el).find('.workspace_results')
            .prepend($(this.el).hide())
    },

    add_button: function() {
        var $stats_button =
            $('')
            .css({  'background-image': "url('js/saiku/plugins/Statistics/sigma.png')",
                    'background-repeat':'no-repeat',
                    'background-position':'50% 50%',
                    'height' : '32px',
                    'margin-top' : '5px'
                });

        var $stats_li = $('

').append($stats_button);
        $(this.workspace.querytoolbar.el).find("ul.table").append($stats_li);
    },

    show: function(event, ui) {
        $(this.workspace.el).find('.workspace_results table').toggle();
        $(this.el).toggle();
        $(event.target).toggleClass('on');

        if ($(event.target).hasClass('on')) {
            this.render();
        } else {
            this.workspace.table.render({ data: this.workspace.query.result.lastresult() });
        }
    },

    setOptions: function(event) {
        var type = $(event.target).attr('href').replace('#', '');
        try {
            this[type]();
        } catch (e) { }

        return false;
    },

    render: function() {
        if (! $(this.workspace.querytoolbar.el).find('.stats').hasClass('on')) {
            return;
        }

        var createRow = function(cells, header){
            var row = "
";
            var ohcell = header?"":"";
            var odcell = header?"":"";
            var ccell = header?"	":"	";
            _.each(cells, function(it, idx){row += ((idx==0)?ohcell:odcell)
					+ "
"
					+ it
					+ "
" + ccell})
            row += "
"
            return row
        }

        var group = function(grid, el, cback){
            var elements = _.filter(_.map(grid, function(it){return it[el]}), function(it){return it});
            return cback(elements).toFixed(3);
        }

        var sum = function(elems){return _.reduce(elems, function(memo, num){ return memo + num }, 0)};
        var average = function(elems){return (sum(elems))/elems.length};
        var stdx = function(elems){
            var m = average(elems)
            return Math.sqrt(sum(_.map(elems, function(it){return Math.pow(m - it,2)}))/elems.length);
        }
        var min = function(elems){return _.min(elems)};
        var max = function(elems){return _.max(elems)};

        $(this.el).empty();
        var grid = this.data.metadata;
        var rs = this.data.resultset;
        var aux = _.filter(grid, function(it){return !it.isHeader && it.colType == 'Numeric'});
        var columns = _.map(aux, function(it){return it.colName});
        var idxs =_.map(columns, function(el){return _.indexOf(_.map(grid, function(it){return it.colName}), el)});

        var $table = $("
");
        var $tbody = $("
").appendTo($table);
        $tbody.append(createRow(['Statistics'].concat(columns), true));
        $tbody.append(createRow(['Min'].concat(_.map(idxs, function(it){return group(rs, it, min)})), false));
        $tbody.append(createRow(['Max'].concat(_.map(idxs, function(it){return group(rs, it, max)})), false));
        $tbody.append(createRow(['Sum'].concat(_.map(idxs, function(it){return group(rs, it, sum)})), false));
        $tbody.append(createRow(['Average'].concat(_.map(idxs, function(it){return group(rs, it, average)})), false));
        $tbody.append(createRow(['Std. Deviation'].concat(_.map(idxs, function(it){return group(rs, it, stdx)})), false));

        $(this.el).append($table);

		Saiku.i18n.translate();
    },

    receive_data: function(args) {
        return _.delay(this.process_data, 0, args);
    },

    process_data: function(args) {
        this.data = {};
        this.data.resultset = [];
        this.data.metadata = [];
        this.data.height = 0;
        this.data.width = 0;

        if (args.data.cellset && args.data.cellset.length > 0) {

            var lowest_level = 0;
            var isHead = true
            var columnNames = new Array()
            for (var row = 0; row < args.data.cellset.length; row++) {
                if (isHead && (args.data.cellset[row][0].type == "ROW_HEADER_HEADER" ||
                    args.data.cellset[row][0].value == "null")) {
                    this.data.metadata = [];
                    for (var field = 0; field < args.data.cellset[row].length; field++) {
                        if (args.data.cellset[row][field].type == "ROW_HEADER_HEADER") {
                            this.data.metadata.shift();
                            lowest_level = field;
                        }
                        if(columnNames[field]){
                            columnNames[field].push(args.data.cellset[row][field].value)
                        }else{
                            columnNames[field] = [args.data.cellset[row][field].value]
                        }
                        if(args.data.cellset[row][0].type == "ROW_HEADER_HEADER"){
                            this.data.metadata.push({
                                colIndex: field,
                                colType: typeof(args.data.cellset[row + 1][field].value) !== "number" &&
                                    isNaN(args.data.cellset[row + 1][field].value
                                    .replace(/[^a-zA-Z 0-9.]+/g,'')) ? "String" : "Numeric",
                                colName: columnNames[field].join(' / '),
                                isHeader: (args.data.cellset[row][field].type == "ROW_HEADER_HEADER")
                            });
                        }
                    }
                } else if (args.data.cellset[row][lowest_level].value !== "null" && args.data.cellset[row][lowest_level].value !== "") {
                    isHead = false
                    var record = [];
                    this.data.width = args.data.cellset[row].length;
                    for (var col = lowest_level; col < args.data.cellset[row].length; col++) {
                        var value = args.data.cellset[row][col].value;
                        // check if the resultset contains the raw value, if not try to parse the given value
                        if (args.data.cellset[row][col].properties.raw && args.data.cellset[row][col].properties.raw !== "null")
                        {
                            value = parseFloat(args.data.cellset[row][col].properties.raw);
                        } else if (typeof(args.data.cellset[row][col].value) !== "number" &&
                            parseFloat(args.data.cellset[row][col].value.replace(/[^a-zA-Z 0-9.]+/g,'')))
                        {
                            value = parseFloat(args.data.cellset[row][col].value.replace(/[^a-zA-Z 0-9.]+/g,''));
                        }
                        if (col == lowest_level) {
                            value += " [" + row + "]";
                        }
                        record.push(value);
                    }
                    this.data.resultset.push(record);
                }
            }
            this.data.height = this.data.resultset.length;
            this.render();
        } else {
            $(this.el).text("No results");
        }
    }
});

/**
 * Start Plugin
 */
 Saiku.events.bind('session:new', function(session) {

        function new_workspace(args) {
            // Add stats element
            if (typeof args.workspace.stats == "undefined") {
                args.workspace.stats = new Statistics({ workspace: args.workspace });
            }
        }

        function clear_workspace(args) {
            if (typeof args.workspace.stats != "undefined" && $(args.workspace.stats.el).is(':visible')) {
                $(args.workspace.stats.el).parents().find('.workspace_results table').show();
                $(args.workspace.stats.el).hide();

                args.workspace.stats.data = {};
                args.workspace.stats.data.resultset = [];
                args.workspace.stats.data.metadata = [];
                args.workspace.stats.data.height = 0;
                args.workspace.stats.data.width = 0;

            }
        }

        // Attach stats to existing tabs
        for(var i = 0; i < Saiku.tabs._tabs.length; i++) {
            var tab = Saiku.tabs._tabs[i];
            new_workspace({
                workspace: tab.content
            });
        };

        // Attach stats to future tabs
        Saiku.session.bind("workspace:new", new_workspace);
        Saiku.session.bind("workspace:clear", clear_workspace);
    });

<commit_msg>check if statistics plugin is actually enabled before processing data and rendering stuff<commit_after>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * Renders a stats for each workspace
 */
var Statistics = Backbone.View.extend({

    data: {
        resultset: [],
        metadata: []
    },

    initialize: function(args) {
        this.workspace = args.workspace;

        // Create a unique ID for use as the CSS selector
        this.id = _.uniqueId("stats_");
        $(this.el).attr({ id: this.id });

        // Bind table rendering to query result event
        _.bindAll(this, "render", "receive_data", "process_data", "show",
            "setOptions");
        this.workspace.bind('query:result', this.receive_data);

        // Add stats button
        this.add_button();
        this.workspace.querytoolbar.stats = this.show;

        // Listen to adjust event and rerender stats
        //this.workspace.bind('workspace:adjust', this.render);

        // Append stats to workspace
        $(this.workspace.el).find('.workspace_results')
            .prepend($(this.el).hide())
    },

    add_button: function() {
        var $stats_button =
            $('')
            .css({  'background-image': "url('js/saiku/plugins/Statistics/sigma.png')",
                    'background-repeat':'no-repeat',
                    'background-position':'50% 50%',
                    'height' : '32px',
                    'margin-top' : '5px'
                });

        var $stats_li = $('

').append($stats_button);
        $(this.workspace.querytoolbar.el).find("ul.table").append($stats_li);
    },

    show: function(event, ui) {
        $(this.workspace.el).find('.workspace_results table').toggle();
        $(this.el).toggle();
        $(event.target).toggleClass('on');

        if ($(event.target).hasClass('on')) {
            this.process_data({ data: this.workspace.query.result.lastresult() });
        } else {
            this.workspace.table.render({ data: this.workspace.query.result.lastresult() });
        }
    },

    setOptions: function(event) {
        var type = $(event.target).attr('href').replace('#', '');
        try {
            this[type]();
        } catch (e) { }

        return false;
    },

    render: function() {
        if (! $(this.workspace.querytoolbar.el).find('.stats').hasClass('on') || !$(this.el).is(':visible')) {
            return;
        }

        var createRow = function(cells, header){
            var row = "
";
            var ohcell = header?"":"";
            var odcell = header?"":"";
            var ccell = header?"	":"	";
            _.each(cells, function(it, idx){row += ((idx==0)?ohcell:odcell)
					+ "
"
					+ it
					+ "
" + ccell})
            row += "
"
            return row
        }

        var group = function(grid, el, cback){
            var elements = _.filter(_.map(grid, function(it){return it[el]}), function(it){return it});
            return cback(elements).toFixed(3);
        }

        var sum = function(elems){return _.reduce(elems, function(memo, num){ return memo + num }, 0)};
        var average = function(elems){return (sum(elems))/elems.length};
        var stdx = function(elems){
            var m = average(elems)
            return Math.sqrt(sum(_.map(elems, function(it){return Math.pow(m - it,2)}))/elems.length);
        }
        var min = function(elems){return _.min(elems)};
        var max = function(elems){return _.max(elems)};

        $(this.el).empty();
        var grid = this.data.metadata;
        var rs = this.data.resultset;
        var aux = _.filter(grid, function(it){return !it.isHeader && it.colType == 'Numeric'});
        var columns = _.map(aux, function(it){return it.colName});
        var idxs =_.map(columns, function(el){return _.indexOf(_.map(grid, function(it){return it.colName}), el)});

        var $table = $("
");
        var $tbody = $("
").appendTo($table);
        $tbody.append(createRow(['Statistics'].concat(columns), true));
        $tbody.append(createRow(['Min'].concat(_.map(idxs, function(it){return group(rs, it, min)})), false));
        $tbody.append(createRow(['Max'].concat(_.map(idxs, function(it){return group(rs, it, max)})), false));
        $tbody.append(createRow(['Sum'].concat(_.map(idxs, function(it){return group(rs, it, sum)})), false));
        $tbody.append(createRow(['Average'].concat(_.map(idxs, function(it){return group(rs, it, average)})), false));
        $tbody.append(createRow(['Std. Deviation'].concat(_.map(idxs, function(it){return group(rs, it, stdx)})), false));

        $(this.el).append($table);

		Saiku.i18n.translate();
    },

    receive_data: function(args) {

        return _.delay(this.process_data, 0, args);
    },

    process_data: function(args) {
        this.data = {};
        this.data.resultset = [];
        this.data.metadata = [];
        this.data.height = 0;
        this.data.width = 0;

        if (typeof args == "undefined" || typeof args.data == "undefined" || !$(this.el).is(':visible')) {
            return;
        }
        if (args.data != null && args.data.error != null) {
            return this.error(args);
        }

        // Check to see if there is data
        if (args.data == null || (args.data.cellset && args.data.cellset.length === 0)) {
            return this.no_results(args);
        }

        if (args.data && args.data.cellset && args.data.cellset.length > 0) {

            var lowest_level = 0;
            var isHead = true
            var columnNames = new Array()
            for (var row = 0; row < args.data.cellset.length; row++) {
                if (isHead && (args.data.cellset[row][0].type == "ROW_HEADER_HEADER" ||
                    args.data.cellset[row][0].value == "null")) {
                    this.data.metadata = [];
                    for (var field = 0; field < args.data.cellset[row].length; field++) {
                        if (args.data.cellset[row][field].type == "ROW_HEADER_HEADER") {
                            this.data.metadata.shift();
                            lowest_level = field;
                        }
                        if(columnNames[field]){
                            columnNames[field].push(args.data.cellset[row][field].value)
                        }else{
                            columnNames[field] = [args.data.cellset[row][field].value]
                        }
                        if(args.data.cellset[row][0].type == "ROW_HEADER_HEADER"){
                            this.data.metadata.push({
                                colIndex: field,
                                colType: typeof(args.data.cellset[row + 1][field].value) !== "number" &&
                                    isNaN(args.data.cellset[row + 1][field].value
                                    .replace(/[^a-zA-Z 0-9.]+/g,'')) ? "String" : "Numeric",
                                colName: columnNames[field].join(' / '),
                                isHeader: (args.data.cellset[row][field].type == "ROW_HEADER_HEADER")
                            });
                        }
                    }
                } else if (args.data.cellset[row][lowest_level].value !== "null" && args.data.cellset[row][lowest_level].value !== "") {
                    isHead = false
                    var record = [];
                    this.data.width = args.data.cellset[row].length;
                    for (var col = lowest_level; col < args.data.cellset[row].length; col++) {
                        var value = args.data.cellset[row][col].value;
                        // check if the resultset contains the raw value, if not try to parse the given value
                        if (args.data.cellset[row][col].properties.raw && args.data.cellset[row][col].properties.raw !== "null")
                        {
                            value = parseFloat(args.data.cellset[row][col].properties.raw);
                        } else if (typeof(args.data.cellset[row][col].value) !== "number" &&
                            parseFloat(args.data.cellset[row][col].value.replace(/[^a-zA-Z 0-9.]+/g,'')))
                        {
                            value = parseFloat(args.data.cellset[row][col].value.replace(/[^a-zA-Z 0-9.]+/g,''));
                        }
                        if (col == lowest_level) {
                            value += " [" + row + "]";
                        }
                        record.push(value);
                    }
                    this.data.resultset.push(record);
                }
            }
            this.data.height = this.data.resultset.length;
            this.render();
        } else {
            this.no_results();
        }
    },

    no_results: function(args) {
        $(this.el).text("No results");
    },

    error: function(args) {
        $(this.el).text(safe_tags_replace(args.data.error));
    }
});

/**
 * Start Plugin
 */
 Saiku.events.bind('session:new', function(session) {

        function new_workspace(args) {
            // Add stats element
            if (typeof args.workspace.stats == "undefined") {
                args.workspace.stats = new Statistics({ workspace: args.workspace });
            }
        }

        function clear_workspace(args) {
            if (typeof args.workspace.stats != "undefined" && $(args.workspace.stats.el).is(':visible')) {
                $(args.workspace.stats.el).parents().find('.workspace_results table').show();
                $(args.workspace.stats.el).hide();

                args.workspace.stats.data = {};
                args.workspace.stats.data.resultset = [];
                args.workspace.stats.data.metadata = [];
                args.workspace.stats.data.height = 0;
                args.workspace.stats.data.width = 0;

            }
        }

        // Attach stats to existing tabs
        for(var i = 0; i < Saiku.tabs._tabs.length; i++) {
            var tab = Saiku.tabs._tabs[i];
            new_workspace({
                workspace: tab.content
            });
        };

        // Attach stats to future tabs
        Saiku.session.bind("workspace:new", new_workspace);
        Saiku.session.bind("workspace:clear", clear_workspace);
    });

<|endoftext|>