<commit_before>// Import the individual autotrack plugins you want to use.
// import 'autotrack/lib/plugins/clean-url-tracker';
// import 'autotrack/lib/plugins/max-scroll-tracker';
// import 'autotrack/lib/plugins/outbound-link-tracker';
// import 'autotrack/lib/plugins/page-visibility-tracker';
// import 'autotrack/lib/plugins/url-change-tracker';

/* global define, ga, fbq */

/**
 * The tracking ID for your Google Analytics property.
 * https://support.google.com/analytics/answer/1032385
 */
let TRACKING_ID_GA;

let TRACKING_ID_FBQ;

/**
 * Bump this when making backwards incompatible changes to the tracking
 * implementation. This allows you to create a segment or view filter
 * that isolates only data captured with the most recent tracking changes.
 */
let TRACKING_VERSION = '1';

let TRACKING_TIME_ZONE = 'America/Los_Angeles';

/**
 * A default value for dimensions so unset values always are reported as
 * something. This is needed since Google Analytics will drop empty dimension
 * values in reports.
 */
const NULL_VALUE = '(not set)';

/**
 * A mapping between custom dimension names and their indexes.
 */
const dimensions = {
  TRACKING_VERSION: 'dimension1',
  CLIENT_ID: 'dimension2',
  WINDOW_ID: 'dimension3',
  HIT_ID: 'dimension4',
  HIT_TIME: 'dimension5',
  HIT_TYPE: 'dimension6',
  HIT_SOURCE: 'dimension7',
  VISIBILITY_STATE: 'dimension8',
  URL_QUERY_PARAMS: 'dimension9',
};

/**
 * A mapping between custom metric names and their indexes.
 */
const metrics = {
  RESPONSE_END_TIME: 'metric1',
  DOM_LOAD_TIME: 'metric2',
  WINDOW_LOAD_TIME: 'metric3',
  PAGE_VISIBLE: 'metric4',
  MAX_SCROLL_PERCENTAGE: 'metric5',
};

/**
 * Initializes all the analytics setup. Creates trackers and sets initial
 * values on the trackers.
 */
const init = ({
  GA = TRACKING_ID_GA,
  FBQ = TRACKING_ID_FBQ,
  TV = TRACKING_VERSION,
  TZ = TRACKING_TIME_ZONE,
}) => {
  TRACKING_ID_GA = GA;
  TRACKING_ID_FBQ = FBQ;
  TRACKING_VERSION = TV;
  TRACKING_TIME_ZONE = TZ;

  // Initialize the command queue in case analytics.js hasn't loaded yet.
  window.ga = window.ga || ((...args) => (ga.q = ga.q || []).push(args));

  createTracker();
  trackErrors();
  trackCustomDimensions();
  requireAutotrackPlugins();
  sendInitialPageview();
  sendNavigationTimingMetrics();
};

/**
 * Tracks a JavaScript error with optional fields object overrides.
 * This function is exported so it can be used in other parts of the codebase.
 * E.g.:
 *
 *    `fetch('/api.json').catch(trackError);`
 *
 * @param {Error|undefined} err
 * @param {Object=} fieldsObj
 */
const trackError = (err, fieldsObj = {}) => {
  ga('send', 'event', Object.assign({
    eventCategory: 'Error',
    eventAction: err.name,
    eventLabel: `${err.message}\n${err.stack || '(no stack trace)'}`,
    nonInteraction: true,
  }, fieldsObj));
};

/**
 * Creates the trackers and sets the default transport and tracking
 * version fields. In non-production environments it also logs hits.
 */
const createTracker = () => {
  ga('create', TRACKING_ID_GA, 'auto');

  // Ensures all hits are sent via `navigator.sendBeacon()`.
  ga('set', 'transport', 'beacon');

  fbq('init', TRACKING_ID_FBQ);
};

/**
 * Tracks any errors that may have occured on the page prior to analytics being
 * initialized, then adds an event handler to track future errors.
 */
const trackErrors = () => {
  // Errors that have occurred prior to this script running are stored on
  // `window.__e.q`, as specified in `index.html`.
  const loadErrorEvents = window.__e && window.__e.q || [];

  // Use a different eventCategory for uncaught errors.
  const fieldsObj = {eventCategory: 'Uncaught Error'};

  // Replay any stored load error events.
  for (let event of loadErrorEvents) {
    trackError(event.error, fieldsObj);
  }

  // Add a new listener to track event immediately.
  window.addEventListener('error', (event) => {
    trackError(event.error, fieldsObj);
  });
};

/**
 * Sets a default dimension value for all custom dimensions on all trackers.
 */
const trackCustomDimensions = () => {
  // Sets a default dimension value for all custom dimensions to ensure
  // that every dimension in every hit has *some* value. This is necessary
  // because Google Analytics will drop rows with empty dimension values
  // in your reports.
  Object.keys(dimensions).forEach((key) => {
    ga('set', dimensions[key], NULL_VALUE);
  });

  // Adds tracking of dimensions known at page load time.
  ga((tracker) => {
    tracker.set({
      [dimensions.TRACKING_VERSION]: TRACKING_VERSION,
      [dimensions.CLIENT_ID]: tracker.get('clientId'),
      [dimensions.WINDOW_ID]: uuid(),
    });
  });

  // Adds tracking to record each the type, time, uuid, and visibility state
  // of each hit immediately before it's sent.
  ga((tracker) => {
    const originalBuildHitTask = tracker.get('buildHitTask');
    tracker.set('buildHitTask', (model) => {
      const qt = model.get('queueTime') || 0;
      model.set(dimensions.HIT_TIME, String(new Date - qt), true);
      model.set(dimensions.HIT_ID, uuid(), true);
      model.set(dimensions.HIT_TYPE, model.get('hitType'), true);
      model.set(dimensions.VISIBILITY_STATE, document.visibilityState, true);

      originalBuildHitTask(model);
    });
  });
};

/**
 * Requires select autotrack plugins and initializes each one with its
 * respective configuration options.
 */
const requireAutotrackPlugins = () => {
  ga('require', 'cleanUrlTracker', {
    stripQuery: true,
    queryDimensionIndex: getDefinitionIndex(dimensions.URL_QUERY_PARAMS),
    trailingSlash: 'remove',
  });
  ga('require', 'maxScrollTracker', {
    sessionTimeout: 30,
    timeZone: TRACKING_TIME_ZONE,
    maxScrollMetricIndex: getDefinitionIndex(metrics.MAX_SCROLL_PERCENTAGE),
  });
  ga('require', 'outboundLinkTracker', {
    events: ['click', 'contextmenu'],
  });
  ga('require', 'pageVisibilityTracker', {
    visibleMetricIndex: getDefinitionIndex(metrics.PAGE_VISIBLE),
    sessionTimeout: 30,
    timeZone: TRACKING_TIME_ZONE,
    fieldsObj: {[dimensions.HIT_SOURCE]: 'pageVisibilityTracker'},
  });
  ga('require', 'urlChangeTracker', {
    fieldsObj: {[dimensions.HIT_SOURCE]: 'urlChangeTracker'},
  });
};

/**
 * Sends the initial pageview to Google Analytics.
 */
const sendInitialPageview = () => {
  ga('send', 'pageview', {[dimensions.HIT_SOURCE]: 'pageload'});

  fbq('track', 'PageView');
};

/**
 * Gets the DOM and window load times and sends them as custom metrics to
 * Google Analytics via an event hit.
 */
const sendNavigationTimingMetrics = () => {
  // Only track performance in supporting browsers.
  if (!(window.performance && window.performance.timing)) return;

  // If the window hasn't loaded, run this function after the `load` event.
  if (document.readyState != 'complete') {
    window.addEventListener('load', sendNavigationTimingMetrics);
    return;
  }

  const nt = performance.timing;
  const navStart = nt.navigationStart;

  const responseEnd = Math.round(nt.responseEnd - navStart);
  const domLoaded = Math.round(nt.domContentLoadedEventStart - navStart);
  const windowLoaded = Math.round(nt.loadEventStart - navStart);

  // In some edge cases browsers return very obviously incorrect NT values,
  // e.g. 0, negative, or future times. This validates values before sending.
  const allValuesAreValid = (...values) => {
    return values.every((value) => value > 0 && value < 6e6);
  };

  if (allValuesAreValid(responseEnd, domLoaded, windowLoaded)) {
    ga('send', 'event', {
      eventCategory: 'Navigation Timing',
      eventAction: 'track',
      nonInteraction: true,
      [metrics.RESPONSE_END_TIME]: responseEnd,
      [metrics.DOM_LOAD_TIME]: domLoaded,
      [metrics.WINDOW_LOAD_TIME]: windowLoaded,
    });
  }
};

/**
 * Accepts a custom dimension or metric and returns it's numerical index.
 * @param {string} definition The definition string (e.g. 'dimension1').
 * @return {number} The definition index.
 */
const getDefinitionIndex = (definition) => +/\d+$/.exec(definition)[0];

/**
 * Generates a UUID.
 * https://gist.github.com/jed/982883
 * @param {string|undefined=} a
 * @return {string}
 */
const uuid = function b(a) {
  return a ? (a ^ Math.random() * 16 >> a / 4).toString(16) :
      ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, b);
};

const trackEvent = ({
  eventCategory,
  eventAction,
  eventLabel = NULL_VALUE,
}, trackFbq) => {
  ga('send', 'event', {
    eventCategory,
    eventAction,
    eventLabel,
  });

  trackFbq && fbq('trackCustom', eventCategory, {
    eventAction,
    eventLabel,
  });
};

const trackPageview = (pathname) => {
  ga('send', 'pageview', pathname);

  fbq('track', 'PageView');
};

((name, context, definition) => {
  if (typeof exports === 'object'
  && exports
  && typeof exports.nodeName !== 'string') {
    const analytics = definition();
    Object.assign(exports, analytics, {default: analytics});
  } else if (typeof define === 'function' && define.amd) {
    define(definition);
  } else {
    context[name] = definition();
  }
  // eslint-disable-next-line no-invalid-this
})('analytics', this, () => ({init, trackError, trackEvent, trackPageview}));
<commit_msg>added default field to amd<commit_after>// Import the individual autotrack plugins you want to use.
// import 'autotrack/lib/plugins/clean-url-tracker';
// import 'autotrack/lib/plugins/max-scroll-tracker';
// import 'autotrack/lib/plugins/outbound-link-tracker';
// import 'autotrack/lib/plugins/page-visibility-tracker';
// import 'autotrack/lib/plugins/url-change-tracker';

/* global define, ga, fbq */

/**
 * The tracking ID for your Google Analytics property.
 * https://support.google.com/analytics/answer/1032385
 */
let TRACKING_ID_GA;

let TRACKING_ID_FBQ;

/**
 * Bump this when making backwards incompatible changes to the tracking
 * implementation. This allows you to create a segment or view filter
 * that isolates only data captured with the most recent tracking changes.
 */
let TRACKING_VERSION = '1';

let TRACKING_TIME_ZONE = 'America/Los_Angeles';

/**
 * A default value for dimensions so unset values always are reported as
 * something. This is needed since Google Analytics will drop empty dimension
 * values in reports.
 */
const NULL_VALUE = '(not set)';

/**
 * A mapping between custom dimension names and their indexes.
 */
const dimensions = {
  TRACKING_VERSION: 'dimension1',
  CLIENT_ID: 'dimension2',
  WINDOW_ID: 'dimension3',
  HIT_ID: 'dimension4',
  HIT_TIME: 'dimension5',
  HIT_TYPE: 'dimension6',
  HIT_SOURCE: 'dimension7',
  VISIBILITY_STATE: 'dimension8',
  URL_QUERY_PARAMS: 'dimension9',
};

/**
 * A mapping between custom metric names and their indexes.
 */
const metrics = {
  RESPONSE_END_TIME: 'metric1',
  DOM_LOAD_TIME: 'metric2',
  WINDOW_LOAD_TIME: 'metric3',
  PAGE_VISIBLE: 'metric4',
  MAX_SCROLL_PERCENTAGE: 'metric5',
};

/**
 * Initializes all the analytics setup. Creates trackers and sets initial
 * values on the trackers.
 */
const init = ({
  GA = TRACKING_ID_GA,
  FBQ = TRACKING_ID_FBQ,
  TV = TRACKING_VERSION,
  TZ = TRACKING_TIME_ZONE,
}) => {
  TRACKING_ID_GA = GA;
  TRACKING_ID_FBQ = FBQ;
  TRACKING_VERSION = TV;
  TRACKING_TIME_ZONE = TZ;

  // Initialize the command queue in case analytics.js hasn't loaded yet.
  window.ga = window.ga || ((...args) => (ga.q = ga.q || []).push(args));

  createTracker();
  trackErrors();
  trackCustomDimensions();
  requireAutotrackPlugins();
  sendInitialPageview();
  sendNavigationTimingMetrics();
};

/**
 * Tracks a JavaScript error with optional fields object overrides.
 * This function is exported so it can be used in other parts of the codebase.
 * E.g.:
 *
 *    `fetch('/api.json').catch(trackError);`
 *
 * @param {Error|undefined} err
 * @param {Object=} fieldsObj
 */
const trackError = (err, fieldsObj = {}) => {
  ga('send', 'event', Object.assign({
    eventCategory: 'Error',
    eventAction: err.name,
    eventLabel: `${err.message}\n${err.stack || '(no stack trace)'}`,
    nonInteraction: true,
  }, fieldsObj));
};

/**
 * Creates the trackers and sets the default transport and tracking
 * version fields. In non-production environments it also logs hits.
 */
const createTracker = () => {
  ga('create', TRACKING_ID_GA, 'auto');

  // Ensures all hits are sent via `navigator.sendBeacon()`.
  ga('set', 'transport', 'beacon');

  fbq('init', TRACKING_ID_FBQ);
};

/**
 * Tracks any errors that may have occured on the page prior to analytics being
 * initialized, then adds an event handler to track future errors.
 */
const trackErrors = () => {
  // Errors that have occurred prior to this script running are stored on
  // `window.__e.q`, as specified in `index.html`.
  const loadErrorEvents = window.__e && window.__e.q || [];

  // Use a different eventCategory for uncaught errors.
  const fieldsObj = {eventCategory: 'Uncaught Error'};

  // Replay any stored load error events.
  for (let event of loadErrorEvents) {
    trackError(event.error, fieldsObj);
  }

  // Add a new listener to track event immediately.
  window.addEventListener('error', (event) => {
    trackError(event.error, fieldsObj);
  });
};

/**
 * Sets a default dimension value for all custom dimensions on all trackers.
 */
const trackCustomDimensions = () => {
  // Sets a default dimension value for all custom dimensions to ensure
  // that every dimension in every hit has *some* value. This is necessary
  // because Google Analytics will drop rows with empty dimension values
  // in your reports.
  Object.keys(dimensions).forEach((key) => {
    ga('set', dimensions[key], NULL_VALUE);
  });

  // Adds tracking of dimensions known at page load time.
  ga((tracker) => {
    tracker.set({
      [dimensions.TRACKING_VERSION]: TRACKING_VERSION,
      [dimensions.CLIENT_ID]: tracker.get('clientId'),
      [dimensions.WINDOW_ID]: uuid(),
    });
  });

  // Adds tracking to record each the type, time, uuid, and visibility state
  // of each hit immediately before it's sent.
  ga((tracker) => {
    const originalBuildHitTask = tracker.get('buildHitTask');
    tracker.set('buildHitTask', (model) => {
      const qt = model.get('queueTime') || 0;
      model.set(dimensions.HIT_TIME, String(new Date - qt), true);
      model.set(dimensions.HIT_ID, uuid(), true);
      model.set(dimensions.HIT_TYPE, model.get('hitType'), true);
      model.set(dimensions.VISIBILITY_STATE, document.visibilityState, true);

      originalBuildHitTask(model);
    });
  });
};

/**
 * Requires select autotrack plugins and initializes each one with its
 * respective configuration options.
 */
const requireAutotrackPlugins = () => {
  ga('require', 'cleanUrlTracker', {
    stripQuery: true,
    queryDimensionIndex: getDefinitionIndex(dimensions.URL_QUERY_PARAMS),
    trailingSlash: 'remove',
  });
  ga('require', 'maxScrollTracker', {
    sessionTimeout: 30,
    timeZone: TRACKING_TIME_ZONE,
    maxScrollMetricIndex: getDefinitionIndex(metrics.MAX_SCROLL_PERCENTAGE),
  });
  ga('require', 'outboundLinkTracker', {
    events: ['click', 'contextmenu'],
  });
  ga('require', 'pageVisibilityTracker', {
    visibleMetricIndex: getDefinitionIndex(metrics.PAGE_VISIBLE),
    sessionTimeout: 30,
    timeZone: TRACKING_TIME_ZONE,
    fieldsObj: {[dimensions.HIT_SOURCE]: 'pageVisibilityTracker'},
  });
  ga('require', 'urlChangeTracker', {
    fieldsObj: {[dimensions.HIT_SOURCE]: 'urlChangeTracker'},
  });
};

/**
 * Sends the initial pageview to Google Analytics.
 */
const sendInitialPageview = () => {
  ga('send', 'pageview', {[dimensions.HIT_SOURCE]: 'pageload'});

  fbq('track', 'PageView');
};

/**
 * Gets the DOM and window load times and sends them as custom metrics to
 * Google Analytics via an event hit.
 */
const sendNavigationTimingMetrics = () => {
  // Only track performance in supporting browsers.
  if (!(window.performance && window.performance.timing)) return;

  // If the window hasn't loaded, run this function after the `load` event.
  if (document.readyState != 'complete') {
    window.addEventListener('load', sendNavigationTimingMetrics);
    return;
  }

  const nt = performance.timing;
  const navStart = nt.navigationStart;

  const responseEnd = Math.round(nt.responseEnd - navStart);
  const domLoaded = Math.round(nt.domContentLoadedEventStart - navStart);
  const windowLoaded = Math.round(nt.loadEventStart - navStart);

  // In some edge cases browsers return very obviously incorrect NT values,
  // e.g. 0, negative, or future times. This validates values before sending.
  const allValuesAreValid = (...values) => {
    return values.every((value) => value > 0 && value < 6e6);
  };

  if (allValuesAreValid(responseEnd, domLoaded, windowLoaded)) {
    ga('send', 'event', {
      eventCategory: 'Navigation Timing',
      eventAction: 'track',
      nonInteraction: true,
      [metrics.RESPONSE_END_TIME]: responseEnd,
      [metrics.DOM_LOAD_TIME]: domLoaded,
      [metrics.WINDOW_LOAD_TIME]: windowLoaded,
    });
  }
};

/**
 * Accepts a custom dimension or metric and returns it's numerical index.
 * @param {string} definition The definition string (e.g. 'dimension1').
 * @return {number} The definition index.
 */
const getDefinitionIndex = (definition) => +/\d+$/.exec(definition)[0];

/**
 * Generates a UUID.
 * https://gist.github.com/jed/982883
 * @param {string|undefined=} a
 * @return {string}
 */
const uuid = function b(a) {
  return a ? (a ^ Math.random() * 16 >> a / 4).toString(16) :
      ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, b);
};

const trackEvent = ({
  eventCategory,
  eventAction,
  eventLabel = NULL_VALUE,
}, trackFbq) => {
  ga('send', 'event', {
    eventCategory,
    eventAction,
    eventLabel,
  });

  trackFbq && fbq('trackCustom', eventCategory, {
    eventAction,
    eventLabel,
  });
};

const trackPageview = (pathname) => {
  ga('send', 'pageview', pathname);

  fbq('track', 'PageView');
};

((name, context, definition) => {
  if (typeof exports === 'object'
  && exports
  && typeof exports.nodeName !== 'string') {
    Object.assign(exports, definition(true));
  } else if (typeof define === 'function' && define.amd) {
    define(definition(true));
  } else {
    context[name] = definition(false);
  }
  // eslint-disable-next-line no-invalid-this
})('analytics', this, (def) => {
  const analytics = {init, trackError, trackEvent, trackPageview};
  if (def) {
    return {...analytics, default: analytics};
  }
  return analytics;
});
<|endoftext|>


<commit_before>var ActiveSupport = null;

if(typeof exports != "undefined"){
    exports.ActiveSupport = ActiveSupport;
}

(function(global_context){

/**
 * @namespace {ActiveSupport} Provides a number of methods from the
 *  Prototype.js framework, without modifying any built in prototypes to
 *  ensure compatibility and portability.
 */
ActiveSupport = {
    /**
     * Returns the global context object (window in most implementations).
     * @alias ActiveSupport.getGlobalContext
     * @return {Object}
     */
    getGlobalContext: function getGlobalContext()
    {
        return global_context;
    },
    /**
     * Returns a class if it exists. If the context (default window / global
     * context) does not contain the class, but does have a __noSuchMethod__
     * property, it will attempt to call context[class_name]() to trigger
     * the __noSuchMethod__ handler.
     * @alias ActiveSupport.getClass
     * @param {String} class_name
     * @param {Object} context
     * @return {Mixed}
     */
    getClass: function getClass(class_name,context)
    {
        context = context || ActiveSupport.getGlobalContext();
        var klass = context[class_name];
        if(!klass)
        {
            var trigger_no_such_method = (typeof(context.__noSuchMethod__) !== 'undefined');
            if(trigger_no_such_method)
            {
                try
                {
                    context[class_name]();
                    klass = context[class_name];
                }
                catch(e)
                {
                    return false;
                }
            }
        }
        return klass;
    },
    /**
     * Logs a message to the available logging resource. Accepts a variable
     * number of arguments.
     * @alias ActiveSupport.log
     */
    log: function log()
    {
        if(typeof(console) !== 'undefined')
        {
            //console.log.apply not supported by IE
            switch(arguments.length)
            {
                case 1: console.log(arguments[0]); break;
                case 2: console.log(arguments[0],arguments[1]); break;
                case 3: console.log(arguments[0],arguments[1],arguments[2]); break;
                case 4: console.log(arguments[0],arguments[1],arguments[2],arguments[3]); break;
                case 5: console.log(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]); break;
            }
        }
    },
    /**
     * Creates an Error object (but does not throw it).
     * @alias ActiveSupport.createError
     * @param {String} message
     * @return {null}
     */
    createError: function createError(message)
    {
        return {
            getErrorString: function getErrorString()
            {
                var output = String(message);
                for(var i = 0; i < arguments.length; ++i)
                {
                    output = output.replace(/\%/,arguments[i].toString ? arguments[i].toString() : String(arguments[i]));
                }
                return output;
            }
        };
    },
    /**
     * Returns an array from an array or array like object.
     * @alias ActiveSupport.arrayFrom
     * @param {Object} object
     *      Any iterable object (Array, NodeList, arguments)
     * @return {Array}
     */
    arrayFrom: function arrayFrom(object)
    {
        if(!object)
        {
            return [];
        }
        var length = object.length || 0;
        var results = new Array(length);
        while (length--)
        {
            results[length] = object[length];
        }
        return results;
    },
    /**
     * @alias ActiveSupport.isArray
     * @param {mixed} object
     * @return {Boolean}
     */
    isArray: function isArray(object)
    {
        return object && typeof(object) == 'object' && 'length' in object && 'splice' in object && 'join' in object;
    },
    /**
     * Emulates Array.indexOf for implementations that do not support it.
     * @alias ActiveSupport.indexOf
     * @param {Array} array
     * @param {mixed} item
     * @return {Number}
     */
    indexOf: function indexOf(array,item,i)
    {
        i = i || (0);
        var length = array.length;
        if(i < 0)
        {
            i = length + i;
        }
        for(; i < length; i++)
        {
            if(array[i] === item)
            {
                return i;
            }
        }
        return -1;
    },
    /**
     * Returns an array without the given item.
     * @alias ActiveSupport.without
     * @param {Array} arr
     * @param {mixed} item to remove
     * @return {Array}
     */
    without: function without(arr)
    {
        var values = ActiveSupport.arrayFrom(arguments).slice(1);
        var response = [];
        for(var i = 0 ; i < arr.length; i++)
        {
            if(!(ActiveSupport.indexOf(values,arr[i]) > -1))
            {
                response.push(arr[i]);
            }
        }
        return response;
    },
    /**
     * Emulates Prototype's Function.prototype.bind.
     * @alias ActiveSupport.bind
     * @param {Function} func
     * @param {Object} object
     *      object will be in scope as "this" when func is called.
     * @return {Function}
     */
    bind: function bind(func,object)
    {
        if(typeof(object) == 'undefined')
        {
            return func;
        }
        if(arguments.length < 3)
        {
            return function bound()
            {
                return func.apply(object,arguments);
            };
        }
        else
        {
            var args = ActiveSupport.arrayFrom(arguments);
            args.shift();
            args.shift();
            return function bound()
            {
                return func.apply(object,args.concat(ActiveSupport.arrayFrom(arguments)));
            }
        }
    },
    /**
     * Emulates Prototype's Function.prototype.curry.
     * @alias ActiveSupport.curry
     * @param {Function} func
     * @return {Function}
     */
    curry: function curry(func)
    {
        if(arguments.length == 1)
        {
            return func;
        }
        var args = ActiveSupport.arrayFrom(arguments).slice(1);
        return function curried()
        {
            return func.apply(this,args.concat(ActiveSupport.arrayFrom(arguments)));
        };
    },
    /**
     * Returns a function wrapped around the original function.
     * @alias ActiveSupport.wrap
     * @param {Function} func
     * @param {Function} wrapper
     * @return {Function} wrapped
     * @example
     *
     *     String.prototype.capitalize = ActiveSupport.wrap(String.prototype.capitalize,
     *     function(proceed, eachWord) {
     *         if (eachWord && this.include(" ")) {
     *             // capitalize each word in the string
     *             return this.split(" ").invoke("capitalize").join(" ");
     *         } else {
     *             // proceed using the original function
     *             return proceed();
     *         }
     *     });
     */
    wrap: function wrap(func,wrapper)
    {
        return function wrapped()
        {
            return wrapper.apply(this,[ActiveSupport.bind(func,this)].concat(ActiveSupport.arrayFrom(arguments)));
        };
    },
    /**
     * Returns an array of keys from an object.
     * @alias ActiveSupport.keys
     * @param {Object} object
     * @return {Array}
     */
    keys: function keys(object)
    {
        var keys_array = [];
        for (var property_name in object)
        {
            keys_array.push(property_name);
        }
        return keys_array;
    },
    /**
     * Emulates Prototype's String.prototype.underscore
     * @alias ActiveSupport.underscore
     * @param {String} str
     * @return {String}
     */
    underscore: function underscore(str)
    {
        return str.replace(/::/g, '/').replace(/([A-Z]+)([A-Z][a-z])/g, function(match){
            match = match.split("");
            return match[0] + '_' + match[1];
        }).replace(/([a-z\d])([A-Z])/g, function(match){
            match = match.split("");
            return match[0] + '_' + match[1];
        }).replace(/-/g, '_').toLowerCase();
    },
    /**
     * Emulates Prototype's String.prototype.camelize
     * @alias ActiveSupport.camelize
     * @param {String} str
     * @param {Boolean} [capitalize]
     * @return {String}
     */
    camelize: function camelize(str, capitalize)
    {
        var camelized,
            parts = str.replace(/\_/g,'-').split('-'), len = parts.length;
        if (len === 1)
        {
            if(capitalize)
            {
                return parts[0].charAt(0).toUpperCase() + parts[0].substring(1);
            }
            else
            {
                return parts[0];
            }
        }
        if(str.charAt(0) === '-')
        {
            camelized = parts[0].charAt(0).toUpperCase() + parts[0].substring(1);
        }
        else
        {
            camelized = parts[0];
        }
        for (var i = 1; i < len; i++)
        {
            camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
        }
        if(capitalize)
        {
            return camelized.charAt(0).toUpperCase() + camelized.substring(1);
        }
        else
        {
            return camelized;
        }
    },
    /**
     * Trim leading and trailing whitespace.
     * @alias ActiveSupport.trim
     * @param {String} str
     * @return {String}
     */
    trim: function(str)
    {
        return (str || "").replace(/^\s+|\s+$/g,"");
    },

    /**
     * Emulates Prototype's Object.extend
     * @alias ActiveSupport.extend
     * @param {Object} destination
     * @param {Object} source
     * @return {Object}
     */
    extend: function extend(destination, source)
    {
        for (var property in source)
        {
            destination[property] = source[property];
        }
        return destination;
    },
    /**
     * Emulates Prototype's Object.clone
     * @alias ActiveSupport.clone
     * @param {Object} object
     * @return {Object}
     */
    clone: function clone(object)
    {
        return ActiveSupport.extend({}, object);
    },

    /**
     * If the value passed is a function the value passed will be returned,
     * otherwise a function returning the value passed will be returned.
     * @alias ActiveSupport.proc
     * @param {mixed} proc
     * @return {Function}
     */
    proc: function proc(proc)
    {
        return typeof(proc) === 'function' ? proc : function(){return proc;};
    },

    /**
     * If the value passed is a function, the function is called and the value
     * returned, otherwise the value passed in is returned.
     * @alias ActiveSupport.value
     * @param {mixed} value
     * @return {scalar}
     */
    value: function value(value)
    {
        return typeof(value) === 'function' ? value() : value;
    }
};

})(this);<commit_msg>added map() and values() to ActiveSupport, remove proc() and value()<commit_after>var ActiveSupport = null;

if(typeof exports != "undefined"){
    exports.ActiveSupport = ActiveSupport;
}

(function(global_context){

/**
 * @namespace {ActiveSupport} Provides a number of methods from the
 *  Prototype.js framework, without modifying any built in prototypes to
 *  ensure compatibility and portability.
 */
ActiveSupport = {
    /**
     * Returns the global context object (window in most implementations).
     * @alias ActiveSupport.getGlobalContext
     * @return {Object}
     */
    getGlobalContext: function getGlobalContext()
    {
        return global_context;
    },
    /**
     * Returns a class if it exists. If the context (default window / global
     * context) does not contain the class, but does have a __noSuchMethod__
     * property, it will attempt to call context[class_name]() to trigger
     * the __noSuchMethod__ handler.
     * @alias ActiveSupport.getClass
     * @param {String} class_name
     * @param {Object} context
     * @return {Mixed}
     */
    getClass: function getClass(class_name,context)
    {
        context = context || ActiveSupport.getGlobalContext();
        var klass = context[class_name];
        if(!klass)
        {
            var trigger_no_such_method = (typeof(context.__noSuchMethod__) !== 'undefined');
            if(trigger_no_such_method)
            {
                try
                {
                    context[class_name]();
                    klass = context[class_name];
                }
                catch(e)
                {
                    return false;
                }
            }
        }
        return klass;
    },
    /**
     * Logs a message to the available logging resource. Accepts a variable
     * number of arguments.
     * @alias ActiveSupport.log
     */
    log: function log()
    {
        if(typeof(console) !== 'undefined')
        {
            //console.log.apply not supported by IE
            switch(arguments.length)
            {
                case 1: console.log(arguments[0]); break;
                case 2: console.log(arguments[0],arguments[1]); break;
                case 3: console.log(arguments[0],arguments[1],arguments[2]); break;
                case 4: console.log(arguments[0],arguments[1],arguments[2],arguments[3]); break;
                case 5: console.log(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]); break;
            }
        }
    },
    /**
     * Creates an Error object (but does not throw it).
     * @alias ActiveSupport.createError
     * @param {String} message
     * @return {null}
     */
    createError: function createError(message)
    {
        return {
            getErrorString: function getErrorString()
            {
                var output = String(message);
                for(var i = 0; i < arguments.length; ++i)
                {
                    output = output.replace(/\%/,arguments[i].toString ? arguments[i].toString() : String(arguments[i]));
                }
                return output;
            }
        };
    },
    /**
     * Returns an array from an array or array like object.
     * @alias ActiveSupport.arrayFrom
     * @param {Object} object
     *      Any iterable object (Array, NodeList, arguments)
     * @return {Array}
     */
    arrayFrom: function arrayFrom(object)
    {
        if(!object)
        {
            return [];
        }
        var length = object.length || 0;
        var results = new Array(length);
        while (length--)
        {
            results[length] = object[length];
        }
        return results;
    },
    /**
     * @alias ActiveSupport.isArray
     * @param {mixed} object
     * @return {Boolean}
     */
    isArray: function isArray(object)
    {
        return object && typeof(object) == 'object' && 'length' in object && 'splice' in object && 'join' in object;
    },
    /**
     * Emulates Array.indexOf for implementations that do not support it.
     * @alias ActiveSupport.indexOf
     * @param {Array} array
     * @param {mixed} item
     * @return {Number}
     */
    indexOf: function indexOf(array,item,i)
    {
        if(Array.prototype.indexOf)
        {
            return array.indexOf(item,i);
        }
        i = i || (0);
        var length = array.length;
        if(i < 0)
        {
            i = length + i;
        }
        for(; i < length; i++)
        {
            if(array[i] === item)
            {
                return i;
            }
        }
        return -1;
    },
    /**
     * Returns an array without the given item.
     * @alias ActiveSupport.without
     * @param {Array} arr
     * @param {mixed} item to remove
     * @return {Array}
     */
    without: function without(arr)
    {
        var values = ActiveSupport.arrayFrom(arguments).slice(1);
        var response = [];
        for(var i = 0 ; i < arr.length; i++)
        {
            if(!(ActiveSupport.indexOf(values,arr[i]) > -1))
            {
                response.push(arr[i]);
            }
        }
        return response;
    },
    /**
     * Emulates Array.prototype.map.
     * @alias ActiveSupport.map
     * @param {Array} array
     * @param {Function} iterator
     * @param {Function} [context]
     * @return {Array}
     */
    map: function map(array,iterator,context)
    {
        var length = array.length;
        context = context || window;
        var response = new Array(length);
        for(var i = 0; i < length; ++i)
        {
            if(array[i])
            {
                response[i] = iterator.call(context,array[i],i,array);
            }
        }
        return response;
    },
    /**
     * Emulates Prototype's Function.prototype.bind.
     * @alias ActiveSupport.bind
     * @param {Function} func
     * @param {Object} object
     *      object will be in scope as "this" when func is called.
     * @return {Function}
     */
    bind: function bind(func,object)
    {
        if(typeof(object) == 'undefined')
        {
            return func;
        }
        if(arguments.length < 3)
        {
            return function bound()
            {
                return func.apply(object,arguments);
            };
        }
        else
        {
            var args = ActiveSupport.arrayFrom(arguments);
            args.shift();
            args.shift();
            return function bound()
            {
                return func.apply(object,args.concat(ActiveSupport.arrayFrom(arguments)));
            }
        }
    },
    /**
     * Emulates Prototype's Function.prototype.curry.
     * @alias ActiveSupport.curry
     * @param {Function} func
     * @return {Function}
     */
    curry: function curry(func)
    {
        if(arguments.length == 1)
        {
            return func;
        }
        var args = ActiveSupport.arrayFrom(arguments).slice(1);
        return function curried()
        {
            return func.apply(this,args.concat(ActiveSupport.arrayFrom(arguments)));
        };
    },
    /**
     * Returns a function wrapped around the original function.
     * @alias ActiveSupport.wrap
     * @param {Function} func
     * @param {Function} wrapper
     * @return {Function} wrapped
     * @example
     *
     *     String.prototype.capitalize = ActiveSupport.wrap(String.prototype.capitalize,
     *     function(proceed, eachWord) {
     *         if (eachWord && this.include(" ")) {
     *             // capitalize each word in the string
     *             return this.split(" ").invoke("capitalize").join(" ");
     *         } else {
     *             // proceed using the original function
     *             return proceed();
     *         }
     *     });
     */
    wrap: function wrap(func,wrapper)
    {
        return function wrapped()
        {
            return wrapper.apply(this,[ActiveSupport.bind(func,this)].concat(ActiveSupport.arrayFrom(arguments)));
        };
    },
    /**
     * Returns an array of keys from an object.
     * @alias ActiveSupport.keys
     * @param {Object} object
     * @return {Array}
     */
    keys: function keys(object)
    {
        var keys_array = [];
        for (var property_name in object)
        {
            keys_array.push(property_name);
        }
        return keys_array;
    },
    /**
     * Returns an array of values from an object.
     * @alias ActiveSupport.values
     * @param {Object} object
     * @return {Array}
     */
    values: function values(object)
    {
        var values_array = [];
        for (var property_name in object)
        {
            values_array.push(object[property_name]);
        }
        return values_array;
    },
    /**
     * Emulates Prototype's String.prototype.underscore
     * @alias ActiveSupport.underscore
     * @param {String} str
     * @return {String}
     */
    underscore: function underscore(str)
    {
        return str.replace(/::/g, '/').replace(/([A-Z]+)([A-Z][a-z])/g, function(match){
            match = match.split("");
            return match[0] + '_' + match[1];
        }).replace(/([a-z\d])([A-Z])/g, function(match){
            match = match.split("");
            return match[0] + '_' + match[1];
        }).replace(/-/g, '_').toLowerCase();
    },
    /**
     * Emulates Prototype's String.prototype.camelize
     * @alias ActiveSupport.camelize
     * @param {String} str
     * @param {Boolean} [capitalize]
     * @return {String}
     */
    camelize: function camelize(str, capitalize)
    {
        var camelized,
            parts = str.replace(/\_/g,'-').split('-'), len = parts.length;
        if (len === 1)
        {
            if(capitalize)
            {
                return parts[0].charAt(0).toUpperCase() + parts[0].substring(1);
            }
            else
            {
                return parts[0];
            }
        }
        if(str.charAt(0) === '-')
        {
            camelized = parts[0].charAt(0).toUpperCase() + parts[0].substring(1);
        }
        else
        {
            camelized = parts[0];
        }
        for (var i = 1; i < len; i++)
        {
            camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
        }
        if(capitalize)
        {
            return camelized.charAt(0).toUpperCase() + camelized.substring(1);
        }
        else
        {
            return camelized;
        }
    },
    /**
     * Trim leading and trailing whitespace.
     * @alias ActiveSupport.trim
     * @param {String} str
     * @return {String}
     */
    trim: function trim(str)
    {
        return (str || "").replace(/^\s+|\s+$/g,"");
    },
    /**
     * Emulates Prototype's Object.extend
     * @alias ActiveSupport.extend
     * @param {Object} destination
     * @param {Object} source
     * @return {Object}
     */
    extend: function extend(destination, source)
    {
        for (var property in source)
        {
            destination[property] = source[property];
        }
        return destination;
    },
    /**
     * Emulates Prototype's Object.clone
     * @alias ActiveSupport.clone
     * @param {Object} object
     * @return {Object}
     */
    clone: function clone(object)
    {
        return ActiveSupport.extend({}, object);
    }
};

})(this);<|endoftext|>


<commit_before>var CONSTANTS = require('../constants.json');
var utils = require('../utils.js');
var bidfactory = require('../bidfactory.js');
var bidmanager = require('../bidmanager.js');
var adloader = require('../adloader');

var defaultPlacementForBadBid = '';

/**
 * Adapter for requesting bids from Sovrn
 */
var SovrnAdapter = function SovrnAdapter() {
	var sovrnUrl = 'ap.lijit.com/rtb/bid';

	function _callBids(params) {
		var sovrnBids = params.bids || [];
		// De-dupe by tagid then issue single bid request for all bids
		_requestBids(_getUniqueTagids(sovrnBids));
	}

	// filter bids to de-dupe them?
	function _getUniqueTagids(bids) {
		var key;
		var map = {};
		var Tagids = [];
		bids.forEach(function(bid) {
			map[utils.getBidIdParamater('tagid', bid.params)] = bid;
		});
		for (key in map) {
			if (map.hasOwnProperty(key)) {
				Tagids.push(map[key]);
			}
		}
		return Tagids;
	}

	function _requestBids(bidReqs) {
		// build bid request object
		var domain = window.location.host;
		var page = window.location.pathname + location.search + location.hash;

		var sovrnImps = [];
		//assign the first adUnit (placement) for bad bids;
		defaultPlacementForBadBid  = bidReqs[0].placementCode;

		//build impression array for sovrn
		utils._each(bidReqs, function(bid)
		{
			var tagId = utils.getBidIdParamater('tagid', bid.params);
			var bidFloor = utils.getBidIdParamater('bidfloor', bid.params);
			var adW=0,adH=0;

			//sovrn supports only one size per tagid, so we just take the first size if there are more
			//if we are a 2 item array of 2 numbers, we must be a SingleSize array
			var sizeArrayLength = bid.sizes.length;
			if (sizeArrayLength === 2 && typeof bid.sizes[0] === 'number' && typeof bid.sizes[1] === 'number') {
					adW=bid.sizes[0];
					adH=bid.sizes[1];
				}
			else
				{
					adW=bid.sizes[0][0];
					adH=bid.sizes[0][1];
				}
			imp =
				{
					id: utils.getUniqueIdentifierStr(),
					banner: {
						w: adW,
						h: adH
					},
					tagid: tagId,
					bidfloor: bidFloor
				};
			sovrnImps.push(imp);
			bidmanager.pbCallbackMap[imp.id] = bid;
		});

		// build bid request with impressions
		var sovrnBidReq = {
			id: utils.getUniqueIdentifierStr(),
			imp: sovrnImps,
			site:{
				domain: domain,
				page: page
			}
		};

		var scriptUrl = '//'+sovrnUrl+'?callback=window.pbjs.sovrnResponse' +
			'&br=' + encodeURIComponent(JSON.stringify(sovrnBidReq));
		adloader.loadScript(scriptUrl, null);
	}

	//expose the callback to the global object:
	pbjs.sovrnResponse = function(sovrnResponseObj) {
		var bid = {};
		// valid object?
		if (sovrnResponseObj && sovrnResponseObj.id) {
			// valid object w/ bid responses?
			if (sovrnResponseObj.seatbid && sovrnResponseObj.seatbid.length !==0 && sovrnResponseObj.seatbid[0].bid && sovrnResponseObj.seatbid[0].bid.length !== 0) {

				sovrnResponseObj.seatbid[0].bid.forEach(function(sovrnBid){

					var responseCPM;
					var placementCode = '';
					var id = sovrnBid.impid;

					// try to fetch the bid request we sent Sovrn
					var	bidObj = bidmanager.getPlacementIdByCBIdentifer(id);
					if (bidObj){
						placementCode = bidObj.placementCode;
						bidObj.status = CONSTANTS.STATUS.GOOD;

						//place ad response on bidmanager._adResponsesByBidderId
						responseCPM = parseFloat(sovrnBid.price);

						if(responseCPM !== 0) {
							sovrnBid.placementCode = placementCode;
							sovrnBid.size = bidObj.sizes;
							var responseAd = sovrnBid.adm;

							// build impression url from response
							var responseNurl = '';

							//store bid response
							//bid status is good (indicating 1)
							bid = bidfactory.createBid(1);
							bid.creative_id = sovrnBid.Id;
							bid.bidderCode = 'sovrn';
							bid.cpm = responseCPM;

							//set ad content + impression url
							// sovrn returns


<commit_before>;
var elements = [];
var loadedImages = [];
(function () {
	"use strict"

	function passiveOnScroll(elem, fn) {
		// Test via a getter in the options object to see if the passive property is accessed
		var supportsPassive = false;
		try {
			var opts = Object.defineProperty({}, 'passive', {
				get: function () {
					supportsPassive = true;
				}
			});
			window.addEventListener("test", null, opts);
		} catch (e) {}
		// Use our detect's results. passive applied if supported, capture will be false either way.
		elem.addEventListener('scroll', fn, supportsPassive ? {
			passive: true
		} : false);
	}

	//checks if element passed in the argument is inside the viewport. Returns a boolean value.
	function inViewPort(media, threshold) {
		var coordinates = media.getBoundingClientRect();
		return (
			coordinates.bottom + threshold >= 0 &&
			coordinates.left >= 0 &&
			coordinates.top - threshold <= (window.innerHeight || document.documentElement.clientHeight) &&
			coordinates.right <= (window.innerWidth || document.documentElement.clientWidth)
		);
	};

	//replaces 'data-src' with 'src' for the elements found.
	function loadMedia() {
		if (elements.length === 0) return;

		elements = elements.reduce(function (arr, item) {
			var src = item.getAttribute("data-src");
			var hasSize = false;
			var sizedSrc = item.getAttribute("data-sized-src"); // when image sizes are know this path will be used
			var currentSrc = item.getAttribute("data-current-src");

			if (src && currentSrc && src === currentSrc) {
				return arr;
			}

			if (!inViewPort(item, 1000)) {

				arr.push(item);
				return arr;
			}
			var height = item.clientHeight;
			var width = item.clientWidth;
			if (sizedSrc && height && width) {
				//console.log(`D: ${height}x${width}`);

				hasSize = true;
				src = sizedSrc.replace("#height#", height).replace("#width#", width);
			}

			switch (item.tagName) {
				case "IMG":
				case "IFRAME":
					item.setAttribute("data-current-src", src)
					item.src = src;
					break;
				case "DIV":
					preloadImg(item, src);
					item.setAttribute("data-current-src", src);
					break;
				default:
					arr.push(item);
			}

			return arr;
		}, []);
	};

	// display preload image

	function preloadImg(item, src) {
		var newSrc = "url(" + src + ")";
		if (item.style.backgroundImage === newSrc) return;

		if (loadedImages.indexOf(src) === -1) {
			var bgImg = new Image();
			var $item = item.innerHTML = '

';
			item.style.opacity = 0.7;

			bgImg.onload = function () {
				loadedImages.push(src);
				item.innerHTML = "";
				item.style.opacity = 1;
			};
			bgImg.src = src;
			item.style.backgroundImage = newSrc;
		} else {
			item.style.backgroundImage = newSrc;
		}
	}

	// scan for data-src

	//gets all img(s), iframe(s) with the 'data-src' attribute and changes it to 'src'
	function refreshElements(element) {

		//fetch all image elements inside the current element
		//fetch all iframe elements inside the current element
		// fetch all divs inside the current element

		elements = elements.concat(Array.prototype.slice.call(element.querySelectorAll('img[data-src], iframe[data-src], div[data-src], div[data-sized-src], img[data-sized-src]')));
		//if images and videos were found call loadMedia
		if (elements.length > 0) {
			loadMedia();
		}
	}

	var app = angular.module('angular-lazy-loader', [])
		.directive('angularLazyLoad', ['$window', '$timeout', '$rootScope', '$q', function ($window, $timeout, $rootScope, $q) {
			return {
				restrict: 'EA',

				//child scope instead of isolate scope because need to listen for ng-include load events from other scopes
				scope: true,
				link: function (scope, element, attrs) {
					var noInitOnLoad = attrs.initOnLoad === 'false' || false;

					var reloadTimer = null;
					var reloadMediaTimer = null;

					function reloadElements() {
						if (reloadTimer) {
							$timeout.cancel(reloadTimer);
						}
						reloadTimer = $timeout(function () {
							refreshElements(element[0]);
						}, 100);
					}

					function reloadMedia() {
						if (reloadMediaTimer) {
							$timeout.cancel(reloadMediaTimer);
						}
						reloadMediaTimer = $timeout(loadMedia, 100);
					}
					if (!noInitOnLoad) {
						reloadElements();
					}

					//listens for partials loading events using ng-include
					scope.$on('$includeContentLoaded', reloadElements);

					//listens for selective loading, that is, if the developer using this directive wants to load the elements programmatically he can emit a selectiveLoad event
					$rootScope.$on('selectiveLoad', reloadElements);

					if (!window._ll_cb) {
						console.log("Registrering window callbacks");
						//calls loadMedia for each window scroll event
						//angular.element($window).bind('scroll', reloadMedia);
						passiveOnScroll($window, reloadMedia);

						//calls loadMedia for each window scroll event
						angular.element($window).bind('resize', reloadMedia);

						//calls loadMedia for each element scroll event
						//angular.element(element).bind('scroll', reloadMedia);
						window._ll_cb = true;
					}
				}
			}
		}])
})();<commit_msg>Fix loading image using img tag<commit_after>;
var elements = [];
var loadedImages = [];
(function () {
	"use strict"

	function passiveOnScroll(elem, fn) {
		// Test via a getter in the options object to see if the passive property is accessed
		var supportsPassive = false;
		try {
			var opts = Object.defineProperty({}, 'passive', {
				get: function () {
					supportsPassive = true;
				}
			});
			window.addEventListener("test", null, opts);
		} catch (e) {}
		// Use our detect's results. passive applied if supported, capture will be false either way.
		elem.addEventListener('scroll', fn, supportsPassive ? {
			passive: true
		} : false);
	}

	//checks if element passed in the argument is inside the viewport. Returns a boolean value.
	function inViewPort(media, threshold) {
		var coordinates = media.getBoundingClientRect();
		return (
			coordinates.bottom + threshold >= 0 &&
			coordinates.left >= 0 &&
			coordinates.top - threshold <= (window.innerHeight || document.documentElement.clientHeight) &&
			coordinates.right <= (window.innerWidth || document.documentElement.clientWidth)
		);
	};

	//replaces 'data-src' with 'src' for the elements found.
	function loadMedia() {
		if (elements.length === 0) return;

		elements = elements.reduce(function (arr, item) {
			var src = item.getAttribute("data-src");
			var hasSize = false;
			var sizedSrc = item.getAttribute("data-sized-src"); // when image sizes are know this path will be used
			var currentSrc = item.getAttribute("data-current-src");

			if (src && currentSrc && src === currentSrc) {
				return arr;
			}

			if (!inViewPort(item, 1000)) {

				arr.push(item);
				return arr;
			}
			var height = item.clientHeight;
			var width = item.clientWidth;
			if (sizedSrc && height && width) {
				//console.log(`D: ${height}x${width}`);

				hasSize = true;
				src = sizedSrc.replace("#height#", height).replace("#width#", width);
			}

			switch (item.tagName) {
				case "IMG":
				case "IFRAME":
					preloadImg(item, src);
					item.src = src;
					break;
				case "DIV":
					preloadImg(item, src);
					break;
				default:
					arr.push(item);
			}

			return arr;
		}, []);
	};

	// display preload image

	function preloadImg(item, src) {
		var newSrc = "url(" + src + ")";
		if (item.style.backgroundImage === newSrc) return;

		if (loadedImages.indexOf(src) === -1) {
			var bgImg = new Image();
			var $item = item.innerHTML = '

';
			item.style.opacity = 0.7;

			bgImg.onload = function () {
				loadedImages.push(src);
				item.setAttribute("data-current-src", src);
				item.innerHTML = "";
				item.style.opacity = 1;
			};
			bgImg.src = src;
			item.style.backgroundImage = newSrc;
		} else {
			item.style.backgroundImage = newSrc;
		}
	}

	// scan for data-src

	//gets all img(s), iframe(s) with the 'data-src' attribute and changes it to 'src'
	function refreshElements(element) {

		//fetch all image elements inside the current element
		//fetch all iframe elements inside the current element
		// fetch all divs inside the current element

		elements = elements.concat(Array.prototype.slice.call(element.querySelectorAll('img[data-src], iframe[data-src], div[data-src], div[data-sized-src], img[data-sized-src]')));
		//if images and videos were found call loadMedia
		if (elements.length > 0) {
			loadMedia();
		}
	}

	var app = angular.module('angular-lazy-loader', [])
		.directive('angularLazyLoad', ['$window', '$timeout', '$rootScope', '$q', function ($window, $timeout, $rootScope, $q) {
			return {
				restrict: 'EA',

				//child scope instead of isolate scope because need to listen for ng-include load events from other scopes
				scope: true,
				link: function (scope, element, attrs) {
					var noInitOnLoad = attrs.initOnLoad === 'false' || false;

					var reloadTimer = null;
					var reloadMediaTimer = null;

					function reloadElements() {
						if (reloadTimer) {
							$timeout.cancel(reloadTimer);
						}
						reloadTimer = $timeout(function () {
							refreshElements(element[0]);
						}, 100);
					}

					function reloadMedia() {
						if (reloadMediaTimer) {
							$timeout.cancel(reloadMediaTimer);
						}
						reloadMediaTimer = $timeout(loadMedia, 100);
					}
					if (!noInitOnLoad) {
						reloadElements();
					}

					//listens for partials loading events using ng-include
					scope.$on('$includeContentLoaded', reloadElements);

					//listens for selective loading, that is, if the developer using this directive wants to load the elements programmatically he can emit a selectiveLoad event
					$rootScope.$on('selectiveLoad', reloadElements);

					if (!window._ll_cb) {
						console.log("Registrering window callbacks");
						//calls loadMedia for each window scroll event
						//angular.element($window).bind('scroll', reloadMedia);
						passiveOnScroll($window, reloadMedia);

						//calls loadMedia for each window scroll event
						angular.element($window).bind('resize', reloadMedia);

						//calls loadMedia for each element scroll event
						//angular.element(element).bind('scroll', reloadMedia);
						window._ll_cb = true;
					}
				}
			}
		}])
})();<|endoftext|>


<commit_before>/**
 * 动画主类, 调度和管理所有动画控制器
 *
 * @module zrender/animation/Animation
 * @author pissang(https://github.com/pissang)
 */
// TODO Additive animation
// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
// https://developer.apple.com/videos/wwdc2014/#236
define(function(require) {

    'use strict';

    var util = require('../core/util');
    var Dispatcher = require('../core/event').Dispatcher;

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

    var Animator = require('./Animator');
    /**
     * @typedef {Object} IZRenderStage
     * @property {Function} update
     */

    /**
     * @alias module:zrender/animation/Animation
     * @constructor
     * @param {Object} [options]
     * @param {Function} [options.onframe]
     * @param {IZRenderStage} [options.stage]
     * @example
     *     var animation = new Animation();
     *     var obj = {
     *         x: 100,
     *         y: 100
     *     };
     *     animation.animate(node.position)
     *         .when(1000, {
     *             x: 500,
     *             y: 500
     *         })
     *         .when(2000, {
     *             x: 100,
     *             y: 100
     *         })
     *         .start('spline');
     */
    var Animation = function (options) {

        options = options || {};

        this.stage = options.stage || {};

        this.onframe = options.onframe || function() {};

        // private properties
        this._clips = [];

        this._running = false;

        this._time;

        this._pausedTime;

        this._pauseStart;

        this._paused = false;

        Dispatcher.call(this);
    };

    Animation.prototype = {

        constructor: Animation,
        /**
         * 添加 clip
         * @param {module:zrender/animation/Clip} clip
         */
        addClip: function (clip) {
            this._clips.push(clip);
        },
        /**
         * 添加 animator
         * @param {module:zrender/animation/Animator} animator
         */
        addAnimator: function (animator) {
            animator.animation = this;
            var clips = animator.getClips();
            for (var i = 0; i < clips.length; i++) {
                this.addClip(clips[i]);
            }
        },
        /**
         * 删除动画片段
         * @param {module:zrender/animation/Clip} clip
         */
        removeClip: function(clip) {
            var idx = util.indexOf(this._clips, clip);
            if (idx >= 0) {
                this._clips.splice(idx, 1);
            }
        },

        /**
         * 删除动画片段
         * @param {module:zrender/animation/Animator} animator
         */
        removeAnimator: function (animator) {
            var clips = animator.getClips();
            for (var i = 0; i < clips.length; i++) {
                this.removeClip(clips[i]);
            }
            animator.animation = null;
        },

        _update: function() {

            var time = new Date().getTime() - this._pausedTime;
            var delta = time - this._time;
            var clips = this._clips;
            var len = clips.length;

            var deferredEvents = [];
            var deferredClips = [];
            for (var i = 0; i < len; i++) {
                var clip = clips[i];
                var e = clip.step(time);
                // Throw out the events need to be called after
                // stage.update, like destroy
                if (e) {
                    deferredEvents.push(e);
                    deferredClips.push(clip);
                }
            }

            // Remove the finished clip
            for (var i = 0; i < len;) {
                if (clips[i]._needsRemove) {
                    clips[i] = clips[len - 1];
                    clips.pop();
                    len--;
                }
                else {
                    i++;
                }
            }

            len = deferredEvents.length;
            for (var i = 0; i < len; i++) {
                deferredClips[i].fire(deferredEvents[i]);
            }

            this._time = time;

            this.onframe(delta);

            this.trigger('frame', delta);

            if (this.stage.update) {
                this.stage.update();
            }
        },

        _startLoop: function () {
            var self = this;

            this._running = true;

            function step() {
                if (self._running) {

                    requestAnimationFrame(step);

                    !self._paused && self._update();
                }
            }

            requestAnimationFrame(step);
        },

        /**
         * 开始运行动画
         */
        start: function () {

            this._time = new Date().getTime();
            this._pausedTime = 0;

            this._startLoop();
        },
        /**
         * 停止运行动画
         */
        stop: function () {
            this._running = false;
        },

        /**
         * Pause
         */
        pause: function () {
            if (!this._paused) {
                this._pauseStart = new Date().getTime();
                this._paused = true;
            }
        },

        /**
         * Resume
         */
        resume: function () {
            if (this._paused) {
                this._pausedTime += (new Date().getTime()) - this._pauseStart;
                this._paused = false;
            }
        },

        /**
         * 清除所有动画片段
         */
        clear: function () {
            this._clips = [];
        },
        /**
         * 对一个目标创建一个animator对象，可以指定目标中的属性使用动画
         * @param  {Object} target
         * @param  {Object} options
         * @param  {boolean} [options.loop=false] 是否循环播放动画
         * @param  {Function} [options.getter=null]
         *         如果指定getter函数，会通过getter函数取属性值
         * @param  {Function} [options.setter=null]
         *         如果指定setter函数，会通过setter函数设置属性值
         * @return {module:zrender/animation/Animation~Animator}
         */
        // TODO Gap
        animate: function (target, options) {
            options = options || {};
            var animator = new Animator(
                target,
                options.loop,
                options.getter,
                options.setter
            );

            return animator;
        }
    };

    util.mixin(Animation, Dispatcher);

    return Animation;
});
<commit_msg>tweak<commit_after>/**
 * 动画主类, 调度和管理所有动画控制器
 *
 * @module zrender/animation/Animation
 * @author pissang(https://github.com/pissang)
 */
// TODO Additive animation
// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
// https://developer.apple.com/videos/wwdc2014/#236
define(function(require) {

    'use strict';

    var util = require('../core/util');
    var Dispatcher = require('../core/event').Dispatcher;

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

    var Animator = require('./Animator');
    /**
     * @typedef {Object} IZRenderStage
     * @property {Function} update
     */

    /**
     * @alias module:zrender/animation/Animation
     * @constructor
     * @param {Object} [options]
     * @param {Function} [options.onframe]
     * @param {IZRenderStage} [options.stage]
     * @example
     *     var animation = new Animation();
     *     var obj = {
     *         x: 100,
     *         y: 100
     *     };
     *     animation.animate(node.position)
     *         .when(1000, {
     *             x: 500,
     *             y: 500
     *         })
     *         .when(2000, {
     *             x: 100,
     *             y: 100
     *         })
     *         .start('spline');
     */
    var Animation = function (options) {

        options = options || {};

        this.stage = options.stage || {};

        this.onframe = options.onframe || function() {};

        // private properties
        this._clips = [];

        this._running = false;

        this._time;

        this._pausedTime;

        this._pauseStart;

        this._paused = false;

        Dispatcher.call(this);
    };

    Animation.prototype = {

        constructor: Animation,
        /**
         * 添加 clip
         * @param {module:zrender/animation/Clip} clip
         */
        addClip: function (clip) {
            this._clips.push(clip);
        },
        /**
         * 添加 animator
         * @param {module:zrender/animation/Animator} animator
         */
        addAnimator: function (animator) {
            animator.animation = this;
            var clips = animator.getClips();
            for (var i = 0; i < clips.length; i++) {
                this.addClip(clips[i]);
            }
        },
        /**
         * 删除动画片段
         * @param {module:zrender/animation/Clip} clip
         */
        removeClip: function(clip) {
            var idx = util.indexOf(this._clips, clip);
            if (idx >= 0) {
                this._clips.splice(idx, 1);
            }
        },

        /**
         * 删除动画片段
         * @param {module:zrender/animation/Animator} animator
         */
        removeAnimator: function (animator) {
            var clips = animator.getClips();
            for (var i = 0; i < clips.length; i++) {
                this.removeClip(clips[i]);
            }
            animator.animation = null;
        },

        _update: function() {

            var time = new Date().getTime() - this._pausedTime;
            var delta = time - this._time;
            var clips = this._clips;
            var len = clips.length;

            var deferredEvents = [];
            var deferredClips = [];
            for (var i = 0; i < len; i++) {
                var clip = clips[i];
                var e = clip.step(time);
                // Throw out the events need to be called after
                // stage.update, like destroy
                if (e) {
                    deferredEvents.push(e);
                    deferredClips.push(clip);
                }
            }

            // Remove the finished clip
            for (var i = 0; i < len;) {
                if (clips[i]._needsRemove) {
                    clips[i] = clips[len - 1];
                    clips.pop();
                    len--;
                }
                else {
                    i++;
                }
            }

            len = deferredEvents.length;
            for (var i = 0; i < len; i++) {
                deferredClips[i].fire(deferredEvents[i]);
            }

            this._time = time;

            this.onframe(delta);

            this.trigger('frame', delta);

            if (this.stage.update) {
                this.stage.update();
            }
        },

        _startLoop: function () {
            var self = this;

            this._running = true;

            function step() {
                if (self._running) {

                    requestAnimationFrame(step);

                    !self._paused && self._update();
                }
            }

            requestAnimationFrame(step);
        },

        /**
         * 开始运行动画
         */
        start: function () {

            this._time = new Date().getTime();
            this._pausedTime = 0;

            this._startLoop();
        },
        /**
         * 停止运行动画
         */
        stop: function () {
            this._running = false;
        },

        /**
         * Pause
         */
        pause: function () {
            if (!this._paused) {
                this._pauseStart = new Date().getTime();
                this._paused = true;
            }
        },

        /**
         * Resume
         */
        resume: function () {
            if (this._paused) {
                this._pausedTime += (new Date().getTime()) - this._pauseStart;
                this._paused = false;
            }
        },

        /**
         * 清除所有动画片段
         */
        clear: function () {
            this._clips = [];
        },
        /**
         * 对一个目标创建一个animator对象，可以指定目标中的属性使用动画
         * @param  {Object} target
         * @param  {Object} options
         * @param  {boolean} [options.loop=false] 是否循环播放动画
         * @param  {Function} [options.getter=null]
         *         如果指定getter函数，会通过getter函数取属性值
         * @param  {Function} [options.setter=null]
         *         如果指定setter函数，会通过setter函数设置属性值
         * @return {module:zrender/animation/Animation~Animator}
         */
        // TODO Gap
        animate: function (target, options) {
            options = options || {};

            var animator = new Animator(
                target,
                options.loop,
                options.getter,
                options.setter
            );

            this.addAnimator(animator);

            return animator;
        }
    };

    util.mixin(Animation, Dispatcher);

    return Animation;
});
<|endoftext|>


<commit_before>/**
 * angular-locker
 *
 * A simple abstraction for local/session storage in angular projects.
 *
 * @link https://github.com/tymondesigns/angular-locker
 * @author Sean Tymon @tymondesigns
 * @license MIT License, http://www.opensource.org/licenses/MIT
 */

(function(window, angular, undefined) {

	'use strict';

	angular.module('angular-locker', [])

	.provider('locker', function locker() {

		/**
		 * set some defaults
		 */
		var storage = window.localStorage,
		separator = '.',
		namespace = 'locker',
		prefix = namespace === '' ? '' : namespace + separator,

		/**
		 * _setItem - set the item in storage - try to stringify if not a string (object/array)
		 *
		 * @param {String} key
		 * @param {Mixed} value
		 */
		_setItem = function (key, value) {
			if (typeof value !== 'string') {
				value = _serializeValue(value);
			}

			try {
				storage[prefix + key] = value;
			} catch (e) {
				if (['QUOTA_EXCEEDED_ERR', 'NS_ERROR_DOM_QUOTA_REACHED', 'QuotaExceededError'].indexOf(e.name) !== -1) {
					console.warn('locker - Your browser storage quota has been exceeded');
				} else {
					console.warn('locker - Could not add item with key "' + key + '"', e);
				}
			}
		},

		/**
		 * _serializeValue - try to encode value as json, or just return the value upon failure
		 *
		 * @param  {Mixed} value
		 * @return {Mixed}
		 */
		_serializeValue = function (value) {
			try {
				return JSON.stringify(value);
			} catch (e) {
				return value;
			}
		},

		/**
		 * _unserializeValue - try to parse value as json, if it fails then it probably isn't json so just return it
		 *
		 * @param  {String} value
		 * @return {Object|String}
		 */
		_unserializeValue = function (value) {
			try {
				return JSON.parse(value);
			} catch (e) {
				return value;
			}
		},

		/**
		 * _itemExists - check whether the item exists in storage
		 *
		 * @param  {String} key
		 * @return {Boolean}
		 */
		_itemExists = function (key) {
			return storage.hasOwnProperty(prefix + key);
		},

		/**
		 * _parseFn - if value is a function then execute, otherwise just return
		 *
		 * @param  {Mixed} value
		 * @return {Mixed}
		 */
		_parseFn = function (value) {
			return typeof value === 'function' ? value() : value;
		},

		/**
		 * _removeItem - remove the specified entry from storage
		 *
		 * @param  {String} key
		 * @return {void|Boolean}
		 */
		_removeItem = function (key) {
			if (!_itemExists(key)) return false;
			delete storage[prefix + key];
			return true;
		},

		/**
		 * _setStorageDriver - set the storage driver (session or local)
		 *
		 * @param  {String} value
		 * @return {Object}
		 */
		_setStorageDriver = function (value) {
			value = _parseFn(value);
			storage = value === 'session' ? window.sessionStorage : window.localStorage;
			return this;
		},

		/**
		 * _getStorageDriver - returns the storage driver that is currently set
		 *
		 * @return {String}
		 */
		_getStorageDriver = function () {
			return storage === localStorage ? 'local' : 'session';
		},

		/**
		 * setNamespace - set the namespace
		 *
		 * @param {String} value
		 */
		_setNamespace = function (value) {
			namespace = _parseFn(value);
			prefix = namespace === '' ? '' : namespace + separator;
			return this;
		},

		/**
		 * _getNamespace - returns the namespace that is currently set
		 *
		 * @return {String}
		 */
		_getNamespace = function () {
			return namespace;
		};

		return {

			/**
			 * setStorageDriver - allow setting of default storage driver via `lockerProvider`
			 * e.g. lockerProvider.setStorageDriver('session');
			 */
			setStorageDriver: _setStorageDriver,

			/**
			 * getStorageDriver
			 */
			getStorageDriver: _getStorageDriver,

			/**
			 * setNamespace - allow setting of default namespace via `lockerProvider`
			 * e.g. lockerProvider.setNamespace('myAppName');
			 */
			setNamespace: _setNamespace,

			/**
			 * getNamespace
			 */
			getNamespace: _getNamespace,

			/**
			 * the locker service
			 */
			$get: function() {
				return {

					/**
					 * put - add a new item to storage (even if it already exists)
					 * an object can be passed as the first param to set multiple items in one go
					 *
					 * @param  {Mixed} key
					 * @param  {Mixed} value
					 * @return {Object}
					 */
					put: function (key, value) {
						if (!key) return false;
						if (!angular.isObject(key)) {
							if (!value) return false;
							value = _parseFn(value);
							_setItem(key, value);
						} else {
							for (var k in key) {
								_setItem(k, key[k]);
							}
						}
						return this;
					},

					/**
					 * add - adds an item to storage if it doesn't already exists
					 * @todo doesn't handle passing object as key yet
					 *
					 * @param  {Mixed} key
					 * @param  {Mixed} value
					 * @return {Boolean}
					 */
					add: function (key, value) {
						if (!this.has(key)) {
							this.put(key, value);
							return true;
						}
						return false;
					},

					/**
					 * get - retrieve the specified item from storage
					 *
					 * @param  {String} key
					 * @param  {Mixed}  def
					 * @return {Mixed}
					 */
					get: function (key, def) {
						if (!this.has(key)) return def || void 0;
						return _unserializeValue(storage[prefix + key]);
					},

					/**
					 * has - determine whether a particular item exists in storage
					 *
					 * @param  {String}  key
					 * @return {Boolean}
					 */
					has: _itemExists,

					/**
					 * pull - retrieve the specified item from storage and then remove it
					 *
					 * @param  {String} key
					 * @param  {Mixed}  def
					 * @return {Mixed}
					 */
					pull: function (key, def) {
						var value = this.get(key, def);
						this.remove(key);
						return value;
					},

					/**
					 * all - return all items in storage within the current namespace
					 *
					 * @return {Object}
					 */
					all: function () {
						var items = {};
						for (var key in storage) {
							var split = key.split('.');
							if (split.length > 1 && split[0] === namespace) {
								split.splice(0, 1);
								key = split.join('');
							}
							if (this.get(key)) items[key] = this.get(key);
						}
						return items;
					},

					/**
					 * remove - remove a specified item(s) from storage
					 *
					 * @param  {String|Array} key
					 * @return {Object}
					 */
					remove: function (key) {
						if (!angular.isArray(key)) {
							_removeItem(key);
						} else {
							key.forEach(function(k) {
								_removeItem(k);
							});
						}
						return this;
					},

					/**
					 * clean - removes all items set within the current namespace - defaults to `locker`
					 *
					 * @param  {String} namespace
					 * @return {Object}
					 */
					clean: function () {
						for (var key in storage) {
							_removeItem(key);
						}
						return this;
					},

					/**
					 * empty - empties the current storage driver completely. careful now
					 *
					 * @return {Object}
					 */
					empty: function () {
						storage.clear();
						return this;
					},

					/**
					 * setStorageDriver - same as above. Added here so that it can be chained on the fly
					 * e.g. locker.setStorageDriver('session').put('sessionVar', 'I am volatile');
					 *
					 * @return {Object}
					 */
					setStorageDriver: _setStorageDriver,

					/**
					 * setNamespace - same as above. Added here so that it can be chained on the fly
					 * e.g. locker.setNamespace('myAppName').put('appVar', 'someVar);
					 *
					 * @return {Object}
					 */
					setNamespace: _setNamespace
				};
			}
		};

	});

})(window, window.angular);
<commit_msg>removing hardcoded separator<commit_after>/**
 * angular-locker
 *
 * A simple abstraction for local/session storage in angular projects.
 *
 * @link https://github.com/tymondesigns/angular-locker
 * @author Sean Tymon @tymondesigns
 * @license MIT License, http://www.opensource.org/licenses/MIT
 */

(function(window, angular, undefined) {

	'use strict';

	angular.module('angular-locker', [])

	.provider('locker', function locker() {

		/**
		 * set some defaults
		 */
		var storage = window.localStorage,
		separator = '.',
		namespace = 'locker',
		prefix = namespace === '' ? '' : namespace + separator,

		/**
		 * _setItem - set the item in storage - try to stringify if not a string (object/array)
		 *
		 * @param {String} key
		 * @param {Mixed} value
		 */
		_setItem = function (key, value) {
			if (typeof value !== 'string') {
				value = _serializeValue(value);
			}

			try {
				storage[prefix + key] = value;
			} catch (e) {
				if (['QUOTA_EXCEEDED_ERR', 'NS_ERROR_DOM_QUOTA_REACHED', 'QuotaExceededError'].indexOf(e.name) !== -1) {
					console.warn('locker - Your browser storage quota has been exceeded');
				} else {
					console.warn('locker - Could not add item with key "' + key + '"', e);
				}
			}
		},

		/**
		 * _serializeValue - try to encode value as json, or just return the value upon failure
		 *
		 * @param  {Mixed} value
		 * @return {Mixed}
		 */
		_serializeValue = function (value) {
			try {
				return JSON.stringify(value);
			} catch (e) {
				return value;
			}
		},

		/**
		 * _unserializeValue - try to parse value as json, if it fails then it probably isn't json so just return it
		 *
		 * @param  {String} value
		 * @return {Object|String}
		 */
		_unserializeValue = function (value) {
			try {
				return JSON.parse(value);
			} catch (e) {
				return value;
			}
		},

		/**
		 * _itemExists - check whether the item exists in storage
		 *
		 * @param  {String} key
		 * @return {Boolean}
		 */
		_itemExists = function (key) {
			return storage.hasOwnProperty(prefix + key);
		},

		/**
		 * _parseFn - if value is a function then execute, otherwise just return
		 *
		 * @param  {Mixed} value
		 * @return {Mixed}
		 */
		_parseFn = function (value) {
			return typeof value === 'function' ? value() : value;
		},

		/**
		 * _removeItem - remove the specified entry from storage
		 *
		 * @param  {String} key
		 * @return {void|Boolean}
		 */
		_removeItem = function (key) {
			if (!_itemExists(key)) return false;
			delete storage[prefix + key];
			return true;
		},

		/**
		 * _setStorageDriver - set the storage driver (session or local)
		 *
		 * @param  {String} value
		 * @return {Object}
		 */
		_setStorageDriver = function (value) {
			value = _parseFn(value);
			storage = value === 'session' ? window.sessionStorage : window.localStorage;
			return this;
		},

		/**
		 * _getStorageDriver - returns the storage driver that is currently set
		 *
		 * @return {String}
		 */
		_getStorageDriver = function () {
			return storage === localStorage ? 'local' : 'session';
		},

		/**
		 * setNamespace - set the namespace
		 *
		 * @param {String} value
		 */
		_setNamespace = function (value) {
			namespace = _parseFn(value);
			prefix = namespace === '' ? '' : namespace + separator;
			return this;
		},

		/**
		 * _getNamespace - returns the namespace that is currently set
		 *
		 * @return {String}
		 */
		_getNamespace = function () {
			return namespace;
		};

		return {

			/**
			 * setStorageDriver - allow setting of default storage driver via `lockerProvider`
			 * e.g. lockerProvider.setStorageDriver('session');
			 */
			setStorageDriver: _setStorageDriver,

			/**
			 * getStorageDriver
			 */
			getStorageDriver: _getStorageDriver,

			/**
			 * setNamespace - allow setting of default namespace via `lockerProvider`
			 * e.g. lockerProvider.setNamespace('myAppName');
			 */
			setNamespace: _setNamespace,

			/**
			 * getNamespace
			 */
			getNamespace: _getNamespace,

			/**
			 * the locker service
			 */
			$get: function() {
				return {

					/**
					 * put - add a new item to storage (even if it already exists)
					 * an object can be passed as the first param to set multiple items in one go
					 *
					 * @param  {Mixed} key
					 * @param  {Mixed} value
					 * @return {Object}
					 */
					put: function (key, value) {
						if (!key) return false;
						if (!angular.isObject(key)) {
							if (!value) return false;
							value = _parseFn(value);
							_setItem(key, value);
						} else {
							for (var k in key) {
								_setItem(k, key[k]);
							}
						}
						return this;
					},

					/**
					 * add - adds an item to storage if it doesn't already exists
					 * @todo doesn't handle passing object as key yet
					 *
					 * @param  {Mixed} key
					 * @param  {Mixed} value
					 * @return {Boolean}
					 */
					add: function (key, value) {
						if (!this.has(key)) {
							this.put(key, value);
							return true;
						}
						return false;
					},

					/**
					 * get - retrieve the specified item from storage
					 *
					 * @param  {String} key
					 * @param  {Mixed}  def
					 * @return {Mixed}
					 */
					get: function (key, def) {
						if (!this.has(key)) return def || void 0;
						return _unserializeValue(storage[prefix + key]);
					},

					/**
					 * has - determine whether a particular item exists in storage
					 *
					 * @param  {String}  key
					 * @return {Boolean}
					 */
					has: _itemExists,

					/**
					 * pull - retrieve the specified item from storage and then remove it
					 *
					 * @param  {String} key
					 * @param  {Mixed}  def
					 * @return {Mixed}
					 */
					pull: function (key, def) {
						var value = this.get(key, def);
						this.remove(key);
						return value;
					},

					/**
					 * all - return all items in storage within the current namespace
					 *
					 * @return {Object}
					 */
					all: function () {
						var items = {};
						for (var key in storage) {
							var split = key.split(separator);
							if (split.length > 1 && split[0] === namespace) {
								split.splice(0, 1);
								key = split.join('');
							}
							if (this.get(key)) items[key] = this.get(key);
						}
						return items;
					},

					/**
					 * remove - remove a specified item(s) from storage
					 *
					 * @param  {String|Array} key
					 * @return {Object}
					 */
					remove: function (key) {
						if (!angular.isArray(key)) {
							_removeItem(key);
						} else {
							key.forEach(function(k) {
								_removeItem(k);
							});
						}
						return this;
					},

					/**
					 * clean - removes all items set within the current namespace - defaults to `locker`
					 *
					 * @param  {String} namespace
					 * @return {Object}
					 */
					clean: function () {
						for (var key in storage) {
							_removeItem(key);
						}
						return this;
					},

					/**
					 * empty - empties the current storage driver completely. careful now
					 *
					 * @return {Object}
					 */
					empty: function () {
						storage.clear();
						return this;
					},

					/**
					 * setStorageDriver - same as above. Added here so that it can be chained on the fly
					 * e.g. locker.setStorageDriver('session').put('sessionVar', 'I am volatile');
					 *
					 * @return {Object}
					 */
					setStorageDriver: _setStorageDriver,

					/**
					 * setNamespace - same as above. Added here so that it can be chained on the fly
					 * e.g. locker.setNamespace('myAppName').put('appVar', 'someVar);
					 *
					 * @return {Object}
					 */
					setNamespace: _setNamespace
				};
			}
		};

	});

})(window, window.angular);
<|endoftext|>


<commit_before>angular.module('inbox', []).
  provider('$inbox', function() {
    var config = {
      baseUrl: null,
      http: {
        headers: {},
        withCredentials: false
      }
    };

    this.baseUrl = function(value) {
      if (arguments.length >= 1) {
        config.baseUrl = typeof value === 'string' ? value : null;
        return this;
      }
      return config.baseUrl;
    };

    this.appId = function(value) {
      if (arguments.length >= 1) {
        config.appId = '' + value;
        return this;
      }
      return config.appId;
    };

    this.withCredentials = function(value) {
      if (!arguments.length) {
        return config.http.withCredentials;
      }
      config.http.withCredentials = !!value;
      return this;
    };

    this.setRequestHeader = function(header, value) {
      if (arguments.length > 1) {
        header = ('' + header).toLowerCase();
        if (HEADER_REGEXP.test(header)) {
          config.http.headers[header] = value;
        }
      }
      return this;
    };

    this.$get = ['$q', function($q) {
      var tempConfig;
      var Promise = function(resolver) {
        if (typeof resolver !== 'function') {
          throw new TypeError('resolver must be a function');
        }
        var deferred = $q.defer();
        resolver(function(value) {
          deferred.resolve(value);
        }, function(reason) {
          deferred.reject(reason);
        });
        return deferred.promise;
      };
      tempConfig = angular.extend({promise: Promise}, config);
      return new InboxAPI(tempConfig);
    }];
  });
<commit_msg>feat(api) expose components to the outside world for testing<commit_after>angular.module('inbox', []).
  provider('$inbox', function() {
    var config = {
      baseUrl: null,
      http: {
        headers: {},
        withCredentials: false
      }
    };

    this.baseUrl = function(value) {
      if (arguments.length >= 1) {
        config.baseUrl = typeof value === 'string' ? value : null;
        return this;
      }
      return config.baseUrl;
    };

    this.appId = function(value) {
      if (arguments.length >= 1) {
        config.appId = '' + value;
        return this;
      }
      return config.appId;
    };

    this.withCredentials = function(value) {
      if (!arguments.length) {
        return config.http.withCredentials;
      }
      config.http.withCredentials = !!value;
      return this;
    };

    this.setRequestHeader = function(header, value) {
      if (arguments.length > 1) {
        header = ('' + header).toLowerCase();
        if (HEADER_REGEXP.test(header)) {
          config.http.headers[header] = value;
        }
      }
      return this;
    };

    this.InboxAPI = InboxAPI;
    InboxAPI.INContact = INContact;
    InboxAPI.INDraft = INDraft;
    InboxAPI.INFile = INFile;
    InboxAPI.INMessage = INMessage;
    InboxAPI.INNamespace = INNamespace;
    InboxAPI.INTag = INTag;
    InboxAPI.INThread = INThread;

    this.$get = ['$q', function($q) {
      var tempConfig;
      var Promise = function(resolver) {
        if (typeof resolver !== 'function') {
          throw new TypeError('resolver must be a function');
        }
        var deferred = $q.defer();
        resolver(function(value) {
          deferred.resolve(value);
        }, function(reason) {
          deferred.reject(reason);
        });
        return deferred.promise;
      };
      tempConfig = angular.extend({promise: Promise}, config);
      return new InboxAPI(tempConfig);
    }];
  });
<|endoftext|>


<commit_before>// vi: sw=2 sts=2 et
(function main () {
  const makeExchangeData = function (tickerData)
      Object.keys(tickerData).reduce(function (o, k) {
          if (k !== "timestamp") {
              o[k] = Object.keys(tickerData[k]);
          }
          return o;
      }, {});

  if (this['ARGV'] !== undefined) {
    const Soup = imports.gi.Soup;
    const _httpSession = new Soup.SessionAsync();
    const url = "https://api.bitcoinaverage.com/exchanges/all";
    _httpSession.queue_message(
      Soup.Message.new("GET", url),
      function (session, message) {
        let json = message.response_body.data;
        let data = makeExchangeData(JSON.parse(json));
        print("/* generated by util/MakeExchangeData.js */");
        print("const ExchangeData = " + JSON.stringify(data, null, 4) + ";");
        imports.mainloop.quit("main");
      }
    );

    imports.mainloop.run("main");
  }
})()
<commit_msg>MakeExchangeData: sort by exchange volume<commit_after>// vi: sw=2 sts=2 et
(function main () {
  const makeExchangeData = function (tickerData)
      Object.keys(tickerData).reduce(function (o, k) {
          if (k !== "timestamp") {
              o[k] = Object.keys(tickerData[k]).sort(function (a, b)
                tickerData[k][b].volume_btc - tickerData[k][a].volume_btc
              );
          }
          return o;
      }, {});

  if (this['ARGV'] !== undefined) {
    const Soup = imports.gi.Soup;
    const _httpSession = new Soup.SessionAsync();
    const url = "https://api.bitcoinaverage.com/exchanges/all";
    _httpSession.queue_message(
      Soup.Message.new("GET", url),
      function (session, message) {
        let json = message.response_body.data;
        let data = makeExchangeData(JSON.parse(json));
        print("/* generated by util/MakeExchangeData.js */");
        print("const ExchangeData = " + JSON.stringify(data, null, 4) + ";");
        imports.mainloop.quit("main");
      }
    );

    imports.mainloop.run("main");
  }
})()
<|endoftext|>