<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('print_preview', function() {
  'strict';

  /**
   * Creates a PreviewArea object. It represents the area where the preview
   * document is displayed.
   * @constructor
   */
  function PreviewArea() {
    // The embedded pdf plugin object.
    this.pdfPlugin_ = null;

    // @type {HTMLDivElement} A layer on top of |this.pdfPlugin_| used for
    // displaying messages to the user.
    this.overlayLayer = $('overlay-layer');
    // @type {HTMLDivElement} Contains text displayed to the user followed by
    // three animated dots.
    this.customMessageWithDots_ = $('custom-message-with-dots');
    // @type {HTMLDivElement} Contains text displayed to the user.
    this.customMessage_ = $('custom-message');
    // @type {HTMLInputElement} Button associated with a displayed error
    // message.
    this.errorButton = $('error-button');
    // @type {HTMLDivElement} Contains three animated (dancing) dots.
    this.dancingDotsText = $('dancing-dots-text');

    // True if the pdf document is loaded in the preview area.
    this.pdfLoaded_ = false;

    // Contains the zoom level just before a new preview is requested so the
    // same zoom level can be restored.
    this.zoomLevel_ = null;
    // @type {{x: number, y: number}} Contains the page offset values just
    //     before a new preview is requested so that the scroll amount can be
    //     restored later.
    this.pageOffset_ = null;
    // @type {print_preview.Rect} A rectangle describing the postion of the
    // most visible page normalized with respect to the total height and width
    // of the plugin.
    this.pageLocationNormalized = null;

    // @type {EventTracker} Used to keep track of certain event listeners.
    this.eventTracker = new EventTracker();

    this.addEventListeners_();
  }

  cr.addSingletonGetter(PreviewArea);

  PreviewArea.prototype = {
    /**
     * The width of the plugin area in pixels, excluding any visible scrollbars,
     * @type {number}
     */
    get width() {
      return this.widthPercent * this.pdfPlugin_.offsetWidth;
    },

    /**
     * The height of the plugin area in pixels, excluding any visible
     *     scrollbars.
     * @type {number}
     */
    get height() {
      return this.heightPercent * this.pdfPlugin_.offsetHeight;
    },

    /**
     * The width of the plugin area in percent, excluding any visible
     *     scrollbars.
     * @type {number}
     */
    get widthPercent() {
      var width = this.pdfPlugin_.getWidth();
      var scrollbarWidth = this.pdfPlugin_.getVerticalScrollbarThickness();
      return (width - scrollbarWidth) / width;
    },

    /**
     * The height of the plugin area in percent, excluding any visible
     *     scrollbars.
     * @type {number}
     */
    get heightPercent() {
      var height = this.pdfPlugin_.getHeight();
      var scrollbarHeight = this.pdfPlugin_.getHorizontalScrollbarThickness();
      return (height - scrollbarHeight) / height;
    },

    get pdfPlugin() {
      return this.pdfPlugin_;
    },

    get pdfLoaded() {
      return this.pdfLoaded_;
    },

    set pdfLoaded(pdfLoaded) {
      this.pdfLoaded_ = pdfLoaded;
    },

    /**
     * Queries the plugin for the location of the most visible page and updates
     * |this.pageLocationNormalized|.
     */
    update: function() {
      if (!this.pdfLoaded_)
        return;
      var pluginLocation =
          this.pdfPlugin_.getPageLocationNormalized().split(';');
      this.pageLocationNormalized = new print_preview.Rect(
          parseFloat(pluginLocation[0]),
          parseFloat(pluginLocation[1]),
          parseFloat(pluginLocation[2]),
          parseFloat(pluginLocation[3]));
    },

    /**
     * Resets the state variables of |this|.
     */
    resetState: function() {
      if (this.pdfPlugin_) {
        this.zoomLevel_ = this.pdfPlugin_.getZoomLevel();
        this.pageOffset_ = {
            x: this.pdfPlugin_.pageXOffset(),
            y: this.pdfPlugin_.pageYOffset()
        };
      }
      this.pdfLoaded_ = false;
    },

    /**
     * Adds event listeners for various events.
     * @private
     */
    addEventListeners_: function() {
      document.addEventListener(customEvents.PDF_LOADED,
                                this.onPDFLoaded_.bind(this));
    },

    /**
     * Listener executing when a |customEvents.PDF_LOADED| event occurs.
     * @private
     */
    onPDFLoaded_: function() {
      this.pdfPlugin_ = $('pdf-viewer');
      this.pdfLoaded_ = true;
      if (this.zoomLevel_ != null && this.pageOffset_ != null) {
        this.pdfPlugin_.setZoomLevel(this.zoomLevel_);
        this.pdfPlugin_.setPageXOffset(this.pageOffset_.x);
        this.pdfPlugin_.setPageYOffset(this.pageOffset_.y);
      } else {
        this.pdfPlugin_.fitToHeight();
      }
    },

    /**
     * Hides the |this.overlayLayer| and any messages currently displayed.
     */
    hideOverlayLayer: function() {
      this.eventTracker.add(this.overlayLayer, 'webkitTransitionEnd',
          this.hideOverlayLayerCleanup_.bind(this), false);
      if (this.pdfPlugin_)
        this.pdfPlugin_.classList.remove('invisible');
      this.overlayLayer.classList.add('invisible');
    },

    /**
     * Displays the "Preview loading..." animation.
     */
    showLoadingAnimation: function() {
      this.showCustomMessage(localStrings.getString('loading'));
    },

    /**
     * Necessary cleanup so that the dancing dots animation is not being
     * rendered in the background when not displayed.
     */
    hideOverlayLayerCleanup_: function() {
      this.customMessageWithDots_.hidden = true;
      this.eventTracker.remove(this.overlayLayer, 'webkitTransitionEnd');
    },

    /**
     * Displays |message| followed by three dancing dots animation.
     * @param {string} message The message to be displayed.
     */
    showCustomMessage: function(message) {
      this.customMessageWithDots_.innerHTML = message +
          this.dancingDotsText.innerHTML;
      this.customMessageWithDots_.hidden = false;
      if (this.pdfPlugin_)
        this.pdfPlugin_.classList.add('invisible');
      this.overlayLayer.classList.remove('invisible');
    },

    /**
     * Clears the custom message with dots animation.
     */
    clearCustomMessageWithDots: function() {
      this.customMessageWithDots_.innerHTML = '';
      this.customMessageWithDots_.hidden = true;
    },

    /**
     * Display an error message in the center of the preview area.
     * @param {string} errorMessage The error message to be displayed.
     */
    displayErrorMessageAndNotify: function(errorMessage) {
      this.overlayLayer.classList.remove('invisible');
      this.customMessage_.textContent = errorMessage;
      this.customMessage_.hidden = false;
      this.customMessageWithDots_.innerHTML = '';
      this.customMessageWithDots_.hidden = true;
      if (this.pdfPlugin_) {
        $('mainview').removeChild(this.pdfPlugin_);
        this.pdfPlugin_ = null;
      }
      cr.dispatchSimpleEvent(document, customEvents.PDF_GENERATION_ERROR);
    },

    /**
     * Display an error message in the center of the preview area followed by a
     * button.
     * @param {string} errorMessage The error message to be displayed.
     * @param {string} buttonText The text to be displayed within the button.
     * @param {string} buttonListener The listener to be executed when the
     *     button is clicked.
     */
    displayErrorMessageWithButtonAndNotify: function(
        errorMessage, buttonText, buttonListener) {
      this.errorButton.disabled = false;
      this.errorButton.textContent = buttonText;
      this.errorButton.onclick = buttonListener;
      this.errorButton.hidden = false;
      $('system-dialog-throbber').hidden = true;
      $('native-print-dialog-throbber').hidden = true;
      if (cr.isMac)
        $('open-preview-app-throbber').hidden = true;
      this.displayErrorMessageAndNotify(errorMessage);
    }
  };

  return {
    PreviewArea: PreviewArea,
  };
});
<commit_msg>Print Preview: Fixing displaying error messages with HTML content.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('print_preview', function() {
  'strict';

  /**
   * Creates a PreviewArea object. It represents the area where the preview
   * document is displayed.
   * @constructor
   */
  function PreviewArea() {
    // The embedded pdf plugin object.
    this.pdfPlugin_ = null;

    // @type {HTMLDivElement} A layer on top of |this.pdfPlugin_| used for
    // displaying messages to the user.
    this.overlayLayer = $('overlay-layer');
    // @type {HTMLDivElement} Contains text displayed to the user followed by
    // three animated dots.
    this.customMessageWithDots_ = $('custom-message-with-dots');
    // @type {HTMLDivElement} Contains text displayed to the user.
    this.customMessage_ = $('custom-message');
    // @type {HTMLInputElement} Button associated with a displayed error
    // message.
    this.errorButton = $('error-button');
    // @type {HTMLDivElement} Contains three animated (dancing) dots.
    this.dancingDotsText = $('dancing-dots-text');

    // True if the pdf document is loaded in the preview area.
    this.pdfLoaded_ = false;

    // Contains the zoom level just before a new preview is requested so the
    // same zoom level can be restored.
    this.zoomLevel_ = null;
    // @type {{x: number, y: number}} Contains the page offset values just
    //     before a new preview is requested so that the scroll amount can be
    //     restored later.
    this.pageOffset_ = null;
    // @type {print_preview.Rect} A rectangle describing the postion of the
    // most visible page normalized with respect to the total height and width
    // of the plugin.
    this.pageLocationNormalized = null;

    // @type {EventTracker} Used to keep track of certain event listeners.
    this.eventTracker = new EventTracker();

    this.addEventListeners_();
  }

  cr.addSingletonGetter(PreviewArea);

  PreviewArea.prototype = {
    /**
     * The width of the plugin area in pixels, excluding any visible scrollbars,
     * @type {number}
     */
    get width() {
      return this.widthPercent * this.pdfPlugin_.offsetWidth;
    },

    /**
     * The height of the plugin area in pixels, excluding any visible
     *     scrollbars.
     * @type {number}
     */
    get height() {
      return this.heightPercent * this.pdfPlugin_.offsetHeight;
    },

    /**
     * The width of the plugin area in percent, excluding any visible
     *     scrollbars.
     * @type {number}
     */
    get widthPercent() {
      var width = this.pdfPlugin_.getWidth();
      var scrollbarWidth = this.pdfPlugin_.getVerticalScrollbarThickness();
      return (width - scrollbarWidth) / width;
    },

    /**
     * The height of the plugin area in percent, excluding any visible
     *     scrollbars.
     * @type {number}
     */
    get heightPercent() {
      var height = this.pdfPlugin_.getHeight();
      var scrollbarHeight = this.pdfPlugin_.getHorizontalScrollbarThickness();
      return (height - scrollbarHeight) / height;
    },

    get pdfPlugin() {
      return this.pdfPlugin_;
    },

    get pdfLoaded() {
      return this.pdfLoaded_;
    },

    set pdfLoaded(pdfLoaded) {
      this.pdfLoaded_ = pdfLoaded;
    },

    /**
     * Queries the plugin for the location of the most visible page and updates
     * |this.pageLocationNormalized|.
     */
    update: function() {
      if (!this.pdfLoaded_)
        return;
      var pluginLocation =
          this.pdfPlugin_.getPageLocationNormalized().split(';');
      this.pageLocationNormalized = new print_preview.Rect(
          parseFloat(pluginLocation[0]),
          parseFloat(pluginLocation[1]),
          parseFloat(pluginLocation[2]),
          parseFloat(pluginLocation[3]));
    },

    /**
     * Resets the state variables of |this|.
     */
    resetState: function() {
      if (this.pdfPlugin_) {
        this.zoomLevel_ = this.pdfPlugin_.getZoomLevel();
        this.pageOffset_ = {
            x: this.pdfPlugin_.pageXOffset(),
            y: this.pdfPlugin_.pageYOffset()
        };
      }
      this.pdfLoaded_ = false;
    },

    /**
     * Adds event listeners for various events.
     * @private
     */
    addEventListeners_: function() {
      document.addEventListener(customEvents.PDF_LOADED,
                                this.onPDFLoaded_.bind(this));
    },

    /**
     * Listener executing when a |customEvents.PDF_LOADED| event occurs.
     * @private
     */
    onPDFLoaded_: function() {
      this.pdfPlugin_ = $('pdf-viewer');
      this.pdfLoaded_ = true;
      if (this.zoomLevel_ != null && this.pageOffset_ != null) {
        this.pdfPlugin_.setZoomLevel(this.zoomLevel_);
        this.pdfPlugin_.setPageXOffset(this.pageOffset_.x);
        this.pdfPlugin_.setPageYOffset(this.pageOffset_.y);
      } else {
        this.pdfPlugin_.fitToHeight();
      }
    },

    /**
     * Hides the |this.overlayLayer| and any messages currently displayed.
     */
    hideOverlayLayer: function() {
      this.eventTracker.add(this.overlayLayer, 'webkitTransitionEnd',
          this.hideOverlayLayerCleanup_.bind(this), false);
      if (this.pdfPlugin_)
        this.pdfPlugin_.classList.remove('invisible');
      this.overlayLayer.classList.add('invisible');
    },

    /**
     * Displays the "Preview loading..." animation.
     */
    showLoadingAnimation: function() {
      this.showCustomMessage(localStrings.getString('loading'));
    },

    /**
     * Necessary cleanup so that the dancing dots animation is not being
     * rendered in the background when not displayed.
     */
    hideOverlayLayerCleanup_: function() {
      this.customMessageWithDots_.hidden = true;
      this.eventTracker.remove(this.overlayLayer, 'webkitTransitionEnd');
    },

    /**
     * Displays |message| followed by three dancing dots animation.
     * @param {string} message The message to be displayed.
     */
    showCustomMessage: function(message) {
      this.customMessageWithDots_.innerHTML = message +
          this.dancingDotsText.innerHTML;
      this.customMessageWithDots_.hidden = false;
      if (this.pdfPlugin_)
        this.pdfPlugin_.classList.add('invisible');
      this.overlayLayer.classList.remove('invisible');
    },

    /**
     * Clears the custom message with dots animation.
     */
    clearCustomMessageWithDots: function() {
      this.customMessageWithDots_.innerHTML = '';
      this.customMessageWithDots_.hidden = true;
    },

    /**
     * Display an error message in the center of the preview area.
     * @param {string} errorMessage The error message to be displayed.
     */
    displayErrorMessageAndNotify: function(errorMessage) {
      this.overlayLayer.classList.remove('invisible');
      this.customMessage_.innerHTML = errorMessage;
      this.customMessage_.hidden = false;
      this.customMessageWithDots_.innerHTML = '';
      this.customMessageWithDots_.hidden = true;
      if (this.pdfPlugin_) {
        $('mainview').removeChild(this.pdfPlugin_);
        this.pdfPlugin_ = null;
      }
      cr.dispatchSimpleEvent(document, customEvents.PDF_GENERATION_ERROR);
    },

    /**
     * Display an error message in the center of the preview area followed by a
     * button.
     * @param {string} errorMessage The error message to be displayed.
     * @param {string} buttonText The text to be displayed within the button.
     * @param {string} buttonListener The listener to be executed when the
     *     button is clicked.
     */
    displayErrorMessageWithButtonAndNotify: function(
        errorMessage, buttonText, buttonListener) {
      this.errorButton.disabled = false;
      this.errorButton.textContent = buttonText;
      this.errorButton.onclick = buttonListener;
      this.errorButton.hidden = false;
      $('system-dialog-throbber').hidden = true;
      $('native-print-dialog-throbber').hidden = true;
      if (cr.isMac)
        $('open-preview-app-throbber').hidden = true;
      this.displayErrorMessageAndNotify(errorMessage);
    }
  };

  return {
    PreviewArea: PreviewArea,
  };
});
<|endoftext|>


<commit_before>// Run `node benchmark`

var fs = require('fs')
var steno = require('./')

function benchmark(f) {
  var start = Date.now()
  f(function(str) {
    var end = Date.now()
    console.log(str + '  ' + (end - start) + ' (ms)')
  })
}

var max = 10 * 1000

benchmark(function(done) {
  for (var i = 0; i <= max; i++) fs.writeFileSync('tmp.txt', i)
  done('fs.writeFileSync')
})

benchmark(function(done) {
  var writer = steno('tmp.txt')

  writer.setCallback(function(data, next) {
    if (data === max) done('steno.write     ')
    next()
  })

  for (var i = 0; i <= max; i++) writer.write(i)
})
<commit_msg>Fix benchmark<commit_after>// Run `node benchmark`

var fs = require('fs')
var steno = require('./')

function benchmark(f) {
  var start = Date.now()
  f(function(str) {
    var end = Date.now()
    console.log(str + '  ' + (end - start) + ' (ms)')
  })
}

var max = 10 * 1000

benchmark(function(done) {
  for (var i = 0; i <= max; i++) fs.writeFileSync('tmp.txt', i)
  done('fs.writeFileSync')
})

benchmark(function(done) {
  var writer = steno('tmp.txt')

  writer.setCallback(function(err, data, next) {
    if (data === max) done('steno.write     ')
    next()
  })

  for (var i = 0; i <= max; i++) writer.write(i)
})
<|endoftext|>


<commit_before>import {
    createStore,
    combineReducers,
    applyMiddleware,
    compose,
    bindActionCreators
} from 'redux';
import logger from 'redux-logger';
import { persistStore, persistReducer, createTransform } from 'redux-persist';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
import { createStorage, serialize, deserialize } from './storage';

import 'whatwg-fetch';

const REMOVE = '@@KVP_REMOVE';
const SET = '@@KVP_SET';
const CLEAR = '@@KVP_CLEAR';

// Internal variables and functions
var _verbosity = {
    Network: 1,
    Lookup: 2,
    Values: 3
};

class Store {
    constructor(name) {
        if (_stores[name]) {
            throw name + ' store already exists!';
        }
        this.name = name;
        _stores[name] = this;

        this.debug = false;

        // Base URL of web service
        this.service = undefined;

        // Default parameters (e.g f=json)
        this.defaults = {};

        this.ready = {
            then: function () {
                throw new Error('Call init first!');
            }
        };

        // Registered redux functions
        this._reducers = {};
        this._enhanceReducers = [];
        this._persistKeys = [];
        this._transforms = [];
        this._middleware = [];
        this._enhancers = [];
        this._subscribers = [];
        this._deferActions = [];
        this._thunkHandler = null;

        this._promises = {}; // Save promises to prevent redundant fetches

        this.addReducer(
            'kvp',
            (state, action) => this.kvpReducer(state, action),
            true
        );
    }

    init(opts = {}) {
        var self = this;
        var optlist = [
            'debug',
            'storageFail',

            'service',
            'defaults',
            'fetchFail',
            'ajax',
            'formatKeyword'
        ];
        optlist.forEach(function (opt) {
            if (opts.hasOwnProperty(opt)) {
                self[opt] = opts[opt];
            }
        });
        if (self.debug) {
            for (var level in _verbosity) {
                if (self.debug >= _verbosity[level]) {
                    self['debug' + level] = true;
                }
            }
            self.addMiddleware(logger);
        }

        var storeReady;
        self.ready = new Promise(resolve => (storeReady = resolve));

        var reducer = combineReducers(this._reducers);
        this._enhanceReducers.forEach(enhanceReducer => {
            reducer = enhanceReducer(reducer);
        });
        const enhancers = compose(
            ...this._enhancers,
            applyMiddleware(...this._middleware)
        );

        this.lf = createStorage(this.name);

        const persistConfig = {
            key: 'root',
            storage: this.lf,
            stateReconciler: autoMergeLevel2,
            serialize,
            deserialize,
            transforms: this._transforms,
            whitelist: this._persistKeys,
            writeFailHandler: error => this.storageFail(error)
        };
        const persistedReducer = persistReducer(persistConfig, reducer);
        this._store = createStore(persistedReducer, {}, enhancers);
        this._persistor = persistStore(this._store);
        this._persistor.subscribe(() => {
            const { bootstrapped } = this._persistor.getState();
            if (bootstrapped) {
                storeReady();
            }
        });
        this._subscribers.forEach(fn => this._store.subscribe(fn));
        this._deferActions.forEach(this._store.dispatch);
    }

    dispatch(action) {
        if (this._store) {
            return this._store.dispatch(action);
        } else {
            this._deferActions.push(action);
        }
    }

    subscribe(fn) {
        this._subscribers.push(fn);
        if (this._store) {
            this._store.subscribe(fn);
        }
    }

    getState() {
        return this._store.getState();
    }

    addReducer(name, reducer, persist, deserialize) {
        this._reducers[name] = reducer;
        if (persist) {
            this.persistKey(name, persist, deserialize);
        }
    }

    addEnhanceReducer(name, enhanceReducer, persist, deserialize) {
        this._enhanceReducers.push(enhanceReducer);
        if (persist) {
            this.persistKey(name, persist, deserialize);
        }
    }

    persistKey(name, serialize, deserialize) {
        this._persistKeys.push(name);
        if (serialize && deserialize) {
            this._transforms.push(
                createTransform(serialize, deserialize, { whitelist: [name] })
            );
        }
    }

    addMiddleware(middleware) {
        this._middleware.push(middleware);
    }

    addEnhancer(enhancer) {
        this._enhancers.push(enhancer);
    }

    bindActionCreators(actions) {
        return bindActionCreators(actions, this.dispatch.bind(this));
    }

    addThunk(name, thunk) {
        if (!this._thunkHandler) {
            throw new Error('@wq/router is required to handle thunks');
        }
        this._thunkHandler(name, thunk);
    }

    setThunkHandler(handler) {
        this._thunkHandler = handler;
    }

    kvpReducer(state = {}, action) {
        if (action.type === REMOVE) {
            state = { ...state };
            delete state[action.payload.key];
        } else if (action.type === SET) {
            state = {
                ...state,
                [action.payload.key]: action.payload.value
            };
        } else if (action.type === CLEAR) {
            state = {};
        }
        return state;
    }

    // Get value from datastore
    async get(query) {
        await this.ready;
        var self = this;
        if (Array.isArray(query)) {
            var promises = query.map(row => self.get(row));
            return Promise.all(promises);
        }
        query = self.normalizeQuery(query);
        var key = self.toKey(query);

        if (self.debugLookup) {
            console.log('looking up ' + key);
        }

        // Check storage first
        const kvp = this.getState().kvp;
        if (kvp[key]) {
            if (self.debugLookup) {
                console.log('in storage');
            }
            return kvp[key];
        } else {
            // Search ends here if query is a simple string
            if (typeof query == 'string') {
                if (self.debugLookup) {
                    console.log('not found');
                }
                return null;
            }

            // More complex queries are assumed to be server requests
            return self.fetch(query, true);
        }
    }

    // Set value
    async set(query, value) {
        var self = this;
        var key = self.toKey(query);
        if (value === null) {
            if (self.debugLookup) {
                console.log('deleting ' + key);
            }
            self.dispatch({
                type: REMOVE,
                payload: { key }
            });
            return;
        } else {
            if (self.debugLookup) {
                console.log('saving new value for ' + key);
                if (self.debugValues) {
                    console.log(value);
                }
            }
            self.dispatch({
                type: SET,
                payload: { key, value }
            });
            return;
        }
    }

    // Callback for localStorage failure - override to inform the user
    storageFail(error) {
        console.warn('Error persisting store:');
        console.warn(error);
    }

    // Convert "/url" to {'url': "url"} (simplify common use case)
    normalizeQuery(query) {
        if (typeof query === 'string' && query.charAt(0) == '/') {
            query = { url: query.replace(/^\//, '') };
        }
        return query;
    }

    // Helper to allow simple objects to be used as keys
    toKey(query) {
        var self = this;
        query = self.normalizeQuery(query);
        if (!query) {
            throw 'Invalid query!';
        }
        if (typeof query == 'string') {
            return query;
        } else {
            return new URLSearchParams(query).toString();
        }
    }

    // Helper to check existence of a key without loading the object
    exists(query) {
        var self = this;
        var key = self.toKey(query);
        return self.keys().then(function (keys) {
            var found = false;
            keys.forEach(function (k) {
                if (k === key) {
                    found = true;
                }
            });
            return found;
        });
    }

    // Fetch data from server
    fetch(query, cache) {
        var self = this;
        query = self.normalizeQuery(query);
        var key = self.toKey(query);
        var data = { ...self.defaults, ...query };
        var url = self.service;
        if (data.hasOwnProperty('url')) {
            url = url + '/' + data.url;
            delete data.url;
        }
        if (data.format && !self.formatKeyword) {
            url += '.' + data.format;
            delete data.format;
        }

        if (this._promises[key]) {
            return this._promises[key];
        }

        if (self.debugNetwork) {
            console.log('fetching ' + key);
        }

        var promise = self.ajax(url, data, 'GET');
        this._promises[key] = promise.then(
            async data => {
                delete this._promises[key];
                if (!data) {
                    self.fetchFail(query, 'Error parsing data!');
                    return;
                }
                if (self.debugNetwork) {
                    console.log('received result for ' + key);
                    if (self.debugValues) {
                        console.log(data);
                    }
                }
                if (cache) {
                    await self.set(query, data);
                }
                return data;
            },
            error => {
                delete this._promises[key];
                console.error(error);
                self.fetchFail(query, 'Error parsing data!');
            }
        );
        return this._promises[key];
    }

    // Hook to allow full AJAX customization
    ajax(url, data, method, headers) {
        var urlObj = new URL(url, window.location);
        if (!method) {
            method = 'GET';
        } else {
            method = method.toUpperCase();
        }
        if (method == 'GET') {
            Object.entries(data || {}).forEach(([key, value]) =>
                urlObj.searchParams.append(key, value)
            );
            data = null;
        }
        return fetch(urlObj, {
            method: method,
            body: data,
            headers: headers
        }).then(response => {
            if (response.ok) {
                if (response.status === 204) {
                    return null;
                } else {
                    return response.json();
                }
            } else {
                return response.text().then(result => {
                    var error = new Error();
                    try {
                        error.json = JSON.parse(result);
                    } catch (e) {
                        error.text = result;
                    }
                    error.status = response.status;
                    throw error;
                });
            }
        });
    }

    // Callback for fetch() failures - override to inform the user
    fetchFail(query, error) {
        var self = this;
        var key = self.toKey(query);
        console.warn('Error loading ' + key + ': ' + error);
    }

    // Helper function for prefetching data
    prefetch(query) {
        var self = this;
        return self.fetch(query, true);
    }

    // Clear local caches
    async reset() {
        this.dispatch({ type: CLEAR });
        await this._persistor.purge();
    }

    // List storage keys matching this store's key prefix
    async keys() {
        return Object.keys(this.getState().kvp);
    }
}

var _stores = {};

// Hybrid module object provides/is a singleton instance...
var ds = new Store('main');

// ... and a way to retrieve/autoinit other stores
ds.getStore = getStore;
function getStore(name) {
    if (_stores[name]) {
        return _stores[name];
    } else {
        return new Store(name);
    }
}

export default ds;
export { getStore, Store };
<commit_msg>return unsubscribe function from subscribe()<commit_after>import {
    createStore,
    combineReducers,
    applyMiddleware,
    compose,
    bindActionCreators
} from 'redux';
import logger from 'redux-logger';
import { persistStore, persistReducer, createTransform } from 'redux-persist';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
import { createStorage, serialize, deserialize } from './storage';

import 'whatwg-fetch';

const REMOVE = '@@KVP_REMOVE';
const SET = '@@KVP_SET';
const CLEAR = '@@KVP_CLEAR';

// Internal variables and functions
var _verbosity = {
    Network: 1,
    Lookup: 2,
    Values: 3
};

class Store {
    constructor(name) {
        if (_stores[name]) {
            throw name + ' store already exists!';
        }
        this.name = name;
        _stores[name] = this;

        this.debug = false;

        // Base URL of web service
        this.service = undefined;

        // Default parameters (e.g f=json)
        this.defaults = {};

        this.ready = {
            then: function () {
                throw new Error('Call init first!');
            }
        };

        // Registered redux functions
        this._reducers = {};
        this._enhanceReducers = [];
        this._persistKeys = [];
        this._transforms = [];
        this._middleware = [];
        this._enhancers = [];
        this._subscribers = [];
        this._deferActions = [];
        this._thunkHandler = null;

        this._promises = {}; // Save promises to prevent redundant fetches

        this.addReducer(
            'kvp',
            (state, action) => this.kvpReducer(state, action),
            true
        );
    }

    init(opts = {}) {
        var self = this;
        var optlist = [
            'debug',
            'storageFail',

            'service',
            'defaults',
            'fetchFail',
            'ajax',
            'formatKeyword'
        ];
        optlist.forEach(function (opt) {
            if (opts.hasOwnProperty(opt)) {
                self[opt] = opts[opt];
            }
        });
        if (self.debug) {
            for (var level in _verbosity) {
                if (self.debug >= _verbosity[level]) {
                    self['debug' + level] = true;
                }
            }
            self.addMiddleware(logger);
        }

        var storeReady;
        self.ready = new Promise(resolve => (storeReady = resolve));

        var reducer = combineReducers(this._reducers);
        this._enhanceReducers.forEach(enhanceReducer => {
            reducer = enhanceReducer(reducer);
        });
        const enhancers = compose(
            ...this._enhancers,
            applyMiddleware(...this._middleware)
        );

        this.lf = createStorage(this.name);

        const persistConfig = {
            key: 'root',
            storage: this.lf,
            stateReconciler: autoMergeLevel2,
            serialize,
            deserialize,
            transforms: this._transforms,
            whitelist: this._persistKeys,
            writeFailHandler: error => this.storageFail(error)
        };
        const persistedReducer = persistReducer(persistConfig, reducer);
        this._store = createStore(persistedReducer, {}, enhancers);
        this._persistor = persistStore(this._store);
        this._persistor.subscribe(() => {
            const { bootstrapped } = this._persistor.getState();
            if (bootstrapped) {
                storeReady();
            }
        });
        this._unsubscribers = this._subscribers.map(fn =>
            this._store.subscribe(fn)
        );
        this._deferActions.forEach(this._store.dispatch);
    }

    dispatch(action) {
        if (this._store) {
            return this._store.dispatch(action);
        } else {
            this._deferActions.push(action);
        }
    }

    subscribe(fn) {
        this._subscribers.push(fn);
        if (this._store) {
            return this._store.subscribe(fn);
        } else {
            const index = this._subscribers.length - 1;
            return () => {
                if (!this._unsubscribers) {
                    throw new Error('Store was never fully initialized!');
                }
                this._unsubscribers[index]();
            };
        }
    }

    getState() {
        return this._store.getState();
    }

    addReducer(name, reducer, persist, deserialize) {
        this._reducers[name] = reducer;
        if (persist) {
            this.persistKey(name, persist, deserialize);
        }
    }

    addEnhanceReducer(name, enhanceReducer, persist, deserialize) {
        this._enhanceReducers.push(enhanceReducer);
        if (persist) {
            this.persistKey(name, persist, deserialize);
        }
    }

    persistKey(name, serialize, deserialize) {
        this._persistKeys.push(name);
        if (serialize && deserialize) {
            this._transforms.push(
                createTransform(serialize, deserialize, { whitelist: [name] })
            );
        }
    }

    addMiddleware(middleware) {
        this._middleware.push(middleware);
    }

    addEnhancer(enhancer) {
        this._enhancers.push(enhancer);
    }

    bindActionCreators(actions) {
        return bindActionCreators(actions, this.dispatch.bind(this));
    }

    addThunk(name, thunk) {
        if (!this._thunkHandler) {
            throw new Error('@wq/router is required to handle thunks');
        }
        this._thunkHandler(name, thunk);
    }

    setThunkHandler(handler) {
        this._thunkHandler = handler;
    }

    kvpReducer(state = {}, action) {
        if (action.type === REMOVE) {
            state = { ...state };
            delete state[action.payload.key];
        } else if (action.type === SET) {
            state = {
                ...state,
                [action.payload.key]: action.payload.value
            };
        } else if (action.type === CLEAR) {
            state = {};
        }
        return state;
    }

    // Get value from datastore
    async get(query) {
        await this.ready;
        var self = this;
        if (Array.isArray(query)) {
            var promises = query.map(row => self.get(row));
            return Promise.all(promises);
        }
        query = self.normalizeQuery(query);
        var key = self.toKey(query);

        if (self.debugLookup) {
            console.log('looking up ' + key);
        }

        // Check storage first
        const kvp = this.getState().kvp;
        if (kvp[key]) {
            if (self.debugLookup) {
                console.log('in storage');
            }
            return kvp[key];
        } else {
            // Search ends here if query is a simple string
            if (typeof query == 'string') {
                if (self.debugLookup) {
                    console.log('not found');
                }
                return null;
            }

            // More complex queries are assumed to be server requests
            return self.fetch(query, true);
        }
    }

    // Set value
    async set(query, value) {
        var self = this;
        var key = self.toKey(query);
        if (value === null) {
            if (self.debugLookup) {
                console.log('deleting ' + key);
            }
            self.dispatch({
                type: REMOVE,
                payload: { key }
            });
            return;
        } else {
            if (self.debugLookup) {
                console.log('saving new value for ' + key);
                if (self.debugValues) {
                    console.log(value);
                }
            }
            self.dispatch({
                type: SET,
                payload: { key, value }
            });
            return;
        }
    }

    // Callback for localStorage failure - override to inform the user
    storageFail(error) {
        console.warn('Error persisting store:');
        console.warn(error);
    }

    // Convert "/url" to {'url': "url"} (simplify common use case)
    normalizeQuery(query) {
        if (typeof query === 'string' && query.charAt(0) == '/') {
            query = { url: query.replace(/^\//, '') };
        }
        return query;
    }

    // Helper to allow simple objects to be used as keys
    toKey(query) {
        var self = this;
        query = self.normalizeQuery(query);
        if (!query) {
            throw 'Invalid query!';
        }
        if (typeof query == 'string') {
            return query;
        } else {
            return new URLSearchParams(query).toString();
        }
    }

    // Helper to check existence of a key without loading the object
    exists(query) {
        var self = this;
        var key = self.toKey(query);
        return self.keys().then(function (keys) {
            var found = false;
            keys.forEach(function (k) {
                if (k === key) {
                    found = true;
                }
            });
            return found;
        });
    }

    // Fetch data from server
    fetch(query, cache) {
        var self = this;
        query = self.normalizeQuery(query);
        var key = self.toKey(query);
        var data = { ...self.defaults, ...query };
        var url = self.service;
        if (data.hasOwnProperty('url')) {
            url = url + '/' + data.url;
            delete data.url;
        }
        if (data.format && !self.formatKeyword) {
            url += '.' + data.format;
            delete data.format;
        }

        if (this._promises[key]) {
            return this._promises[key];
        }

        if (self.debugNetwork) {
            console.log('fetching ' + key);
        }

        var promise = self.ajax(url, data, 'GET');
        this._promises[key] = promise.then(
            async data => {
                delete this._promises[key];
                if (!data) {
                    self.fetchFail(query, 'Error parsing data!');
                    return;
                }
                if (self.debugNetwork) {
                    console.log('received result for ' + key);
                    if (self.debugValues) {
                        console.log(data);
                    }
                }
                if (cache) {
                    await self.set(query, data);
                }
                return data;
            },
            error => {
                delete this._promises[key];
                console.error(error);
                self.fetchFail(query, 'Error parsing data!');
            }
        );
        return this._promises[key];
    }

    // Hook to allow full AJAX customization
    ajax(url, data, method, headers) {
        var urlObj = new URL(url, window.location);
        if (!method) {
            method = 'GET';
        } else {
            method = method.toUpperCase();
        }
        if (method == 'GET') {
            Object.entries(data || {}).forEach(([key, value]) =>
                urlObj.searchParams.append(key, value)
            );
            data = null;
        }
        return fetch(urlObj, {
            method: method,
            body: data,
            headers: headers
        }).then(response => {
            if (response.ok) {
                if (response.status === 204) {
                    return null;
                } else {
                    return response.json();
                }
            } else {
                return response.text().then(result => {
                    var error = new Error();
                    try {
                        error.json = JSON.parse(result);
                    } catch (e) {
                        error.text = result;
                    }
                    error.status = response.status;
                    throw error;
                });
            }
        });
    }

    // Callback for fetch() failures - override to inform the user
    fetchFail(query, error) {
        var self = this;
        var key = self.toKey(query);
        console.warn('Error loading ' + key + ': ' + error);
    }

    // Helper function for prefetching data
    prefetch(query) {
        var self = this;
        return self.fetch(query, true);
    }

    // Clear local caches
    async reset() {
        this.dispatch({ type: CLEAR });
        await this._persistor.purge();
    }

    // List storage keys matching this store's key prefix
    async keys() {
        return Object.keys(this.getState().kvp);
    }
}

var _stores = {};

// Hybrid module object provides/is a singleton instance...
var ds = new Store('main');

// ... and a way to retrieve/autoinit other stores
ds.getStore = getStore;
function getStore(name) {
    if (_stores[name]) {
        return _stores[name];
    } else {
        return new Store(name);
    }
}

export default ds;
export { getStore, Store };
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
A hook to add R.java to the draw activiy in Android platform.
*/

var fs = require('fs');
var path = require('path');

var rootdir = process.argv[2];

function replace_string_in_file(filename, to_replace, replace_with) {
    var data = fs.readFileSync(filename, 'utf8');
    var result = data.replace(to_replace, replace_with);
    fs.writeFileSync(filename, result, 'utf8');
}

var target = "stage";
if (process.env.TARGET) {
    target = process.env.TARGET;
}

    var ourconfigfile = path.join( "plugins", "android.json");
    var configobj = JSON.parse(fs.readFileSync(ourconfigfile, 'utf8'));
  // Add java files where you want to add R.java imports in the following array

    var filestoreplace = [
        "platforms/android/src/com/giants/imagepicker/GApp.java",
        "platforms/android/src/com/giants/imagepicker/GlideImageLoader.java",
        "platforms/android/src/com/giants/imagepicker/ImageDataSource.java",
        "platforms/android/src/com/giants/imagepicker/PicassoImageLoader.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImageFolderAdapter.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImageGridAdapter.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImagePageAdapter.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImageRecyclerAdapter.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImageBaseActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImageCropActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImageGridActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImagePreviewActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImagePreviewBaseActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImagePreviewDelActivity.java",
        "platforms/android/src/com/giants/imagepicker/view/CropImageView.java",
        "platforms/android/src/com/giants/imagepicker/view/FolderPopUpWindow.java",

    ];
    filestoreplace.forEach(function(val, index, array) {
        if (fs.existsSync(val)) {
          console.log("Android platform available !");
          //Getting the package name from the android.json file,replace with your plugin's id
          var packageName = configobj.installed_plugins["cordova-plugin-ImagePicker"]["PACKAGE_NAME"];
          console.log("With the package name: "+packageName);
          console.log("change com.your.package.name for "+packageName);
            replace_string_in_file(val,"/com.your.package.name/g",packageName);

        } else {
            console.log("No android platform found! :(");
        }
    });
<commit_msg>Automatic configuration package name，java compile environment for sourceCompatibility 1.7<commit_after>#!/usr/bin/env node
/*
A hook to add R.java to the draw activiy in Android platform.
*/

var fs = require('fs');
var path = require('path');

var rootdir = process.argv[2];

function replace_string_in_file(filename, to_replace, replace_with) {
    var data = fs.readFileSync(filename, 'utf8');
    var result = data.replace(to_replace, replace_with);
    fs.writeFileSync(filename, result, 'utf8');
}

var target = "stage";
if (process.env.TARGET) {
    target = process.env.TARGET;
}

    var ourconfigfile = path.join( "plugins", "android.json");
    var configobj = JSON.parse(fs.readFileSync(ourconfigfile, 'utf8'));
  // Add java files where you want to add R.java imports in the following array

    var filestoreplace = [
        "platforms/android/src/com/giants/imagepicker/GApp.java",
        "platforms/android/src/com/giants/imagepicker/GlideImageLoader.java",
        "platforms/android/src/com/giants/imagepicker/ImageDataSource.java",
        "platforms/android/src/com/giants/imagepicker/PicassoImageLoader.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImageFolderAdapter.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImageGridAdapter.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImagePageAdapter.java",
        "platforms/android/src/com/giants/imagepicker/adapter/ImageRecyclerAdapter.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImageBaseActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImageCropActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImageGridActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImagePreviewActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImagePreviewBaseActivity.java",
        "platforms/android/src/com/giants/imagepicker/ui/ImagePreviewDelActivity.java",
        "platforms/android/src/com/giants/imagepicker/view/CropImageView.java",
        "platforms/android/src/com/giants/imagepicker/view/FolderPopUpWindow.java",

    ];
    filestoreplace.forEach(function(val, index, array) {
        if (fs.existsSync(val)) {
          console.log("Android platform available !");
          //Getting the package name from the android.json file,replace with your plugin's id
          var packageName = configobj.installed_plugins["cordova-plugin-ImagePicker"]["PACKAGE_NAME"];
          console.log("With the package name: "+packageName);
          console.log("change com.your.package.name for "+packageName);
            replace_string_in_file(val,"/com.your.package.name/g",packageName);

        } else {
            console.log("No android platform found! :(");
        }
    });
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import Panel from './CodeMirrorPanel';
import { parse } from 'react-docgen';

import 'codemirror/lib/codemirror.css';
import './react-docgen.less';

const codeSample = `import React, { Component } from 'react';
import PropTypes from 'prop-types';

/**
 * General component description.
 */
class MyComponent extends Component {
  render() {
    // ...
  }
}

MyComponent.propTypes = {
  /**
   * Description of prop "foo".
   */
  foo: PropTypes.number.isRequired,
  /**
   * Description of prop "bar" (a custom validation function).
   */
  bar: function(props, propName, componentName) {
    // ...
  },
  baz: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string
  ]),
};

MyComponent.defaultProps = {
  foo: 42,
  bar: 21
};

export default MyComponent;
`;

class App extends React.Component {
  constructor() {
    super();
    this._jsonRef = React.createRef();
    this.state = {
      value: this.compile(codeSample),
      mode: 'application/json',
      content: codeSample,
    };
  }

  compile(value) {
    return JSON.stringify(parse(value), null, 2);
  }

  handleChange = value => {
    let result;
    let mode = 'text/plain';

    try {
      result = this.compile(value);
      mode = 'application/json';
    } catch (err) {
      result = String(err);
    }
    this.setState({ value: result, mode, content: value });
  };

  render() {
    return (
      <>
        <Panel
          value={this.state.content}
          mode="text/jsx"
          codeSample={codeSample}
          onChange={this.handleChange}
        />
        <Panel
          readOnly={true}
          ref={this._jsonRef}
          value={this.state.value}
          mode={this.state.mode}
        />
      </>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<commit_msg>Updated example with valid isRequired (#373)<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import Panel from './CodeMirrorPanel';
import { parse } from 'react-docgen';

import 'codemirror/lib/codemirror.css';
import './react-docgen.less';

const codeSample = `import React, { Component } from 'react';
import PropTypes from 'prop-types';

/**
 * General component description.
 */
class MyComponent extends Component {
  render() {
    // ...
  }
}

MyComponent.propTypes = {
  /**
   * Description of prop "foo".
   */
  foo: PropTypes.number,
  /**
   * Description of prop "bar" (a custom validation function).
   */
  bar: function(props, propName, componentName) {
    // ...
  },
  baz: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string
  ]).isRequired,
};

MyComponent.defaultProps = {
  foo: 42,
  bar: 21
};

export default MyComponent;
`;

class App extends React.Component {
  constructor() {
    super();
    this._jsonRef = React.createRef();
    this.state = {
      value: this.compile(codeSample),
      mode: 'application/json',
      content: codeSample,
    };
  }

  compile(value) {
    return JSON.stringify(parse(value), null, 2);
  }

  handleChange = value => {
    let result;
    let mode = 'text/plain';

    try {
      result = this.compile(value);
      mode = 'application/json';
    } catch (err) {
      result = String(err);
    }
    this.setState({ value: result, mode, content: value });
  };

  render() {
    return (
      <>
        <Panel
          value={this.state.content}
          mode="text/jsx"
          codeSample={codeSample}
          onChange={this.handleChange}
        />
        <Panel
          readOnly={true}
          ref={this._jsonRef}
          value={this.state.value}
          mode={this.state.mode}
        />
      </>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<|endoftext|>


<commit_before>/* DO NOT MODIFY */
const createTemplate = module.parent.createTemplate;
/* END OF DO NOT MODIFY */

const templatePackage = createTemplate`
{
  "name": "${(args) => args.appName}",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "gluestick start",
    "test": "gluestick test",
    "flow": "flow",
    "lint": "eslint src"
  },
  "dependencies": {
    "babel-core": "6.22.1",
    "babel-loader": "6.2.10",
    "babel-plugin-gluestick": "0.0.1",
    "babel-plugin-transform-decorators-legacy": "1.3.4",
    "babel-preset-es2015": "6.22.0",
    "babel-preset-react": "6.22.0",
    "babel-preset-stage-0": "6.22.0",
    "css-loader": "0.26.1",
    "file-loader": "0.9.0",
    ${(args) => Object.keys(args.gluestickDependencies).reduce(
      (prev, key, i, arr) => prev.concat(
        `"${key}": "file:${args.gluestickDependencies[key]}",${i === arr.length - 1 ? '' : '\n    '}`,
      ),
      '',
    )}
    "image-webpack-loader": "3.1.0",
    "normalize.css": "^5.0.0",
    "react": "15.4.2",
    "react-dom": "15.4.2",
    "react-helmet": "4.0.0",
    "react-redux": "5.0.2",
    "react-router": "3.0.2",
    "redux": "3.6.0",
    "sass-loader": "4.1.1",
    "style-loader": "0.13.1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-eslint": "7.1.1",
    "babel-jest": "18.0.0",
    "babel-plugin-react-transform": "2.0.2",
    "enzyme": "2.7.1",
    "eslint": "3.14.1",
    "eslint-plugin-react": "6.9.0",
    "flow-bin": "0.38.0",
    "flow-typed": "^2.0.0",
    "react-addons-test-utils": "15.4.2",
    "react-hot-loader": "1.3.1",
    "react-transform-catch-errors": "1.0.2",
    "react-transform-hmr": "1.0.4",
    "redbox-react": "1.3.3",
    "webpack-hot-middleware": "2.15.0"
  }
}
`;

module.exports = ({ gluestickDependencies, appName }) => ({
  entries: [
    {
      path: '/',
      filename: 'package.json',
      template: templatePackage,
      args: {
        gluestickDependencies,
        appName,
      },
    },
  ],
});
<commit_msg>reverse gluestick* dependencies<commit_after>/* DO NOT MODIFY */
const createTemplate = module.parent.createTemplate;
/* END OF DO NOT MODIFY */

const templatePackage = createTemplate`
{
  "name": "${(args) => args.appName}",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "gluestick start",
    "test": "gluestick test",
    "flow": "flow",
    "lint": "eslint src"
  },
  "dependencies": {
    "babel-core": "6.22.1",
    "babel-loader": "6.2.10",
    "babel-plugin-gluestick": "0.0.1",
    "babel-plugin-transform-decorators-legacy": "1.3.4",
    "babel-preset-es2015": "6.22.0",
    "babel-preset-react": "6.22.0",
    "babel-preset-stage-0": "6.22.0",
    "css-loader": "0.26.1",
    "file-loader": "0.9.0",
    ${(args) => Object.keys(args.gluestickDependencies).reverse().reduce(
      (prev, key, i, arr) => prev.concat(
        `"${key}": "file:${args.gluestickDependencies[key]}",${i === arr.length - 1 ? '' : '\n    '}`,
      ),
      '',
    )}
    "image-webpack-loader": "3.1.0",
    "normalize.css": "^5.0.0",
    "react": "15.4.2",
    "react-dom": "15.4.2",
    "react-helmet": "4.0.0",
    "react-redux": "5.0.2",
    "react-router": "3.0.2",
    "redux": "3.6.0",
    "sass-loader": "4.1.1",
    "style-loader": "0.13.1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-eslint": "7.1.1",
    "babel-jest": "18.0.0",
    "babel-plugin-react-transform": "2.0.2",
    "enzyme": "2.7.1",
    "eslint": "3.14.1",
    "eslint-plugin-react": "6.9.0",
    "flow-bin": "0.38.0",
    "flow-typed": "^2.0.0",
    "react-addons-test-utils": "15.4.2",
    "react-hot-loader": "1.3.1",
    "react-transform-catch-errors": "1.0.2",
    "react-transform-hmr": "1.0.4",
    "redbox-react": "1.3.3",
    "webpack-hot-middleware": "2.15.0"
  }
}
`;

module.exports = ({ gluestickDependencies, appName }) => ({
  entries: [
    {
      path: '/',
      filename: 'package.json',
      template: templatePackage,
      args: {
        gluestickDependencies,
        appName,
      },
    },
  ],
});
<|endoftext|>


<commit_before>const schedule = require('node-schedule');
const fs = require('fs');
const nodemailer = require('nodemailer');
const monitor = require('./lib/monitor.js');

const interval = {
  service: process.env.SERVICE_INTERVAL || '*/15 * * * *',
  site: process.env.SITE_INTERVAL || '1 * * * *',
};

const transporter = nodemailer.createTransport({
  service: 'Mailgun',
  auth: {
    user: process.env.MAILGUN_USER || '',
    pass: process.env.MAILGUN_PASS || '',
  },
});

const metadata = JSON.parse(fs.readFileSync('package.json', 'utf8'));

/**
 * Overwatch - Enhanced Monitoring
 * @module Overwatch
 */

console.log('launching overwatch...');

// Run service checks every 30 minutes
const services = schedule.scheduleJob(interval.service, () => {
  monitor.serviceChecks(handleCheck);
});

// Run website checks once an hour
const sites = schedule.scheduleJob(interval.site, () => {
  monitor.siteChecks(handleCheck);
});

function handleCheck(err, changes) {
  if (err) {
    console.error(err);
  }

  if (changes) {
    const message = buildMsg(changes);
    sendMsg(message);
  }
}

function sendMsg(msg) {
  const mail = {
    from: process.env.FROM_ADDRESS || '',
    to: process.env.TO_ADDRESS || '',
    subject: `${metadata.name.toUppercase()} alert`,
    text: msg,
    html: `<pre>${msg}</pre>`,
  };

  transporter.sendMail(mail, (err, info) => {
    if (err) {
      console.log(err);
    } else {
      console.log(`Alert sent: ${info.response}`);
    }
  });
}

function buildMsg(changes) {
  const msg = [`Overwatch has detected a change on the following monitored property.\n`];
  if (changes.added) {
    changes.added.forEach((e) => {
      msg.push(`Up: ${e.resolved || e.url}\n`);
    });
  }

  if (changes.removed) {
    changes.removed.forEach((e) => {
      msg.push(`Down: ${e.resolved || e.url}\n`);
    });
  }

  msg.push('\nAll changes reported.\n');
  return msg.join('');
}

/**
 * Handle uncaught exceptions
 */
process.on('uncaughtException', (err) => {
  console.error('caught exception:');
  console.error(err);
  console.trace();
});
<commit_msg>Cleanup<commit_after>const schedule = require('node-schedule');
const nodemailer = require('nodemailer');
const monitor = require('./lib/monitor.js');

const interval = {
  service: process.env.SERVICE_INTERVAL || '*/15 * * * *',
  site: process.env.SITE_INTERVAL || '1 * * * *',
};

const transporter = nodemailer.createTransport({
  service: 'Mailgun',
  auth: {
    user: process.env.MAILGUN_USER || '',
    pass: process.env.MAILGUN_PASS || '',
  },
});

/**
 * Overwatch - Enhanced Monitoring
 * @module Overwatch
 */

console.log('launching Overwatch...');

// Run service checks every 30 minutes
schedule.scheduleJob(interval.service, () => {
  monitor.serviceChecks(handleCheck);
});

// Run website checks once an hour
schedule.scheduleJob(interval.site, () => {
  monitor.siteChecks(handleCheck);
});

function handleCheck(err, changes) {
  if (err) {
    console.error(err);
  }

  if (changes) {
    sendMsg(buildMsg(changes));
  }
}

function sendMsg(msg) {
  const mail = {
    from: process.env.FROM_ADDRESS || '',
    to: process.env.TO_ADDRESS || '',
    subject: 'Overwatch alert',
    text: msg,
    html: `<pre>${msg}</pre>`,
  };

  transporter.sendMail(mail, (err, info) => {
    if (err) {
      console.log(err);
    } else {
      console.log(`Alert sent: ${info.response}`);
    }
  });
}

function buildMsg(changes) {
  const msg = [`Overwatch has detected a change on the following monitored property.\n`];
  if (changes.added) {
    changes.added.forEach((e) => {
      msg.push(`Up: ${e.resolved || e.url}\n`);
    });
  }

  if (changes.removed) {
    changes.removed.forEach((e) => {
      msg.push(`Down: ${e.resolved || e.url}\n`);
    });
  }

  msg.push('\nAll changes reported.\n');
  return msg.join('');
}

/**
 * Handle uncaught exceptions
 */
process.on('uncaughtException', (err) => {
  console.error('caught exception:');
  console.error(err);
  console.trace();
});
<|endoftext|>


<commit_before>  function CartoTooltip(latlng, map) { this.latlng_ = latlng; this.markers_; this.offsetVertical_ = -20; this.offsetHorizontal_ = 0; this.height_ = 22; this.setMap(map); }

  CartoTooltip.prototype = new google.maps.OverlayView();

  CartoTooltip.prototype.draw = function() {
      var me = this;

      var div = this.div_;
      if (!div) {
          div = this.div_ = document.createElement('DIV');
          div.setAttribute('class','marker_tooltip');

          $(div).append('
1 point
iex');

          $(div).find('a.info').click(function(ev){
              ev.preventDefault();
              me.hide();
              carto_map.over_marker_ = true;
              carto_map.info_window_.open(me.markers_);
          });

          $(div).find('a.edit').click(function(ev){
              ev.preventDefault();
              me.hide();
              carto_map.createFakeGeometry(me.markers_);
          });

          $(div).hover(
              function(){
                carto_map.over_marker_ = true;
              },
              function(){
                carto_map.over_marker_ = false;
                setTimeout(function(){
                    if (!carto_map.over_marker_) me.hide();
                },100);
              }
          );

          var panes = this.getPanes();
          panes.floatPane.appendChild(div);
          $(div).css({opacity:0});
      }

      // Position the overlay
      var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
      if (pixPosition) {
          div.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
          div.style.height = this.height_ + "px";
          div.style.top = (pixPosition.y + this.offsetVertical_) + "px";
      }
  };

  CartoTooltip.prototype.remove = function() {
      if (this.div_) {
          this.div_.parentNode.removeChild(this.div_);
          this.div_ = null;
      }
  };

  CartoTooltip.prototype.open = function(latlng,marker) {
      if (this.div_) {
        var div = this.div_;
        var me = this;

        // App status
        var is_query = $('body').attr('query_mode') === 'true';

        if (!is_query) {
          div.style.width = '48px';
          $(div).find('a.info', 'a.edit').show();
          $(div).find('p').hide();
          $(div).find('a.delete_geometry').unbind('click');
          $(div).find('a.delete_geometry').click(function(ev){
            ev.preventDefault();
            carto_map.over_marker_ = true;
            me.hide();
            carto_map.delete_window_.open(me.latlng_,marker);
          });
        } else {
          div.style.width = '14px';
          $(div).find('a.info').show();
          $(div).find('a.delete_geometry').hide();
          $(div).find('a.edit').hide();
          $(div).find('p').hide();
        }

        this.markers_ = marker;
        this.latlng_ = latlng;
        var pixPosition = this.getProjection().fromLatLngToDivPixel(latlng);
        if (pixPosition) {
          div.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
          div.style.top = (pixPosition.y + this.offsetVertical_ - 7) + "px";
        }
        this.show();
      }
  }

  CartoTooltip.prototype.openPolgyon = function(latlng,markers) {
      if (this.div_) {
          var div = this.div_;
          var me = this;
          var total_markers = _.size(markers);
          $(div).find('a.info').hide();
          $(div).find('p').text(total_markers + ((total_markers==1)?' point':' points')).show();
          $(div).find('a.delete_geometry').unbind('click');
          $(div).find('a.delete_geometry').click(function(ev){
            ev.preventDefault();
            me.hide();
            carto_map.removeGeometries(me.markers_);
          });
          var p_width = 	$(div).find('p').width();
          div.style.width = 21 + p_width + 'px';

          this.markers_ = markers;
          this.latlng_ = latlng;
          var pixPosition = this.getProjection().fromLatLngToDivPixel(latlng);
          if (pixPosition) {
              div.style.left = (pixPosition.x + this.offsetHorizontal_ - 7) + "px";
              div.style.top = (pixPosition.y + this.offsetVertical_ + 5) + "px";
          }
          this.show();
      }
  }

  CartoTooltip.prototype.hide = function() {
      if (this.div_) {
          var div = this.div_;
          div.style.visibility = "hidden";
      }
  }

  CartoTooltip.prototype.show = function() {
      if (this.div_) {
          var div = this.div_;
          div.style.visibility = "visible";
          div.style.opacity = 1;
      }
  }

  CartoTooltip.prototype.isVisible = function() {
      if (this.div_) {
          var div = this.div_;

          if ($(div).css('visibility')=='visible') {
              return true;
          } else {
              return false;
          }
      }
  }<commit_msg>tooltip bug in query mode fixed<commit_after>  function CartoTooltip(latlng, map) { this.latlng_ = latlng; this.markers_; this.offsetVertical_ = -20; this.offsetHorizontal_ = 0; this.height_ = 22; this.setMap(map); }

  CartoTooltip.prototype = new google.maps.OverlayView();

  CartoTooltip.prototype.draw = function() {
      var me = this;

      var div = this.div_;
      if (!div) {
          div = this.div_ = document.createElement('DIV');
          div.setAttribute('class','marker_tooltip');

          $(div).append('
1 point
iex');

          $(div).find('a.info').click(function(ev){
              ev.preventDefault();
              me.hide();
              carto_map.over_marker_ = true;
              carto_map.info_window_.open(me.markers_);
          });

          $(div).find('a.edit').click(function(ev){
              ev.preventDefault();
              me.hide();
              carto_map.createFakeGeometry(me.markers_);
          });

          $(div).hover(
              function(){
                carto_map.over_marker_ = true;
              },
              function(){
                carto_map.over_marker_ = false;
                setTimeout(function(){
                    if (!carto_map.over_marker_) me.hide();
                },100);
              }
          );

          var panes = this.getPanes();
          panes.floatPane.appendChild(div);
          $(div).css({opacity:0});
      }

      // Position the overlay
      var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
      if (pixPosition) {
          div.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
          div.style.height = this.height_ + "px";
          div.style.top = (pixPosition.y + this.offsetVertical_) + "px";
      }
  };

  CartoTooltip.prototype.remove = function() {
      if (this.div_) {
          this.div_.parentNode.removeChild(this.div_);
          this.div_ = null;
      }
  };

  CartoTooltip.prototype.open = function(latlng,marker) {
      if (this.div_) {
        var div = this.div_;
        var me = this;

        // App status
        var is_query = $('body').attr('query_mode') === 'true';

        if (!is_query) {
          div.style.width = '48px';
          $(div).find('a.info', 'a.edit').show();
          $(div).find('p').hide();
          $(div).find('a.delete_geometry').unbind('click');
          $(div).find('a.delete_geometry').click(function(ev){
            ev.preventDefault();
            carto_map.over_marker_ = true;
            me.hide();
            carto_map.delete_window_.open(me.latlng_,marker);
          });
        } else {
          div.style.width = '14px';
          $(div).find('a.info').show();
          $(div).find('a.delete_geometry').hide();
          $(div).find('a.edit').hide();
          $(div).find('p').hide();
        }

        this.markers_ = marker;
        this.latlng_ = latlng;
        var pixPosition = this.getProjection().fromLatLngToDivPixel(latlng);
        if (pixPosition) {
          div.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
          div.style.top = (pixPosition.y + this.offsetVertical_ - 7) + "px";
        }
        this.show();
      }
  }

  CartoTooltip.prototype.hide = function() {
      if (this.div_) {
          var div = this.div_;
          div.style.visibility = "hidden";
      }
  }

  CartoTooltip.prototype.show = function() {
      if (this.div_) {
          var div = this.div_;
          div.style.visibility = "visible";
          div.style.opacity = 1;
      }
  }

  CartoTooltip.prototype.isVisible = function() {
      if (this.div_) {
          var div = this.div_;

          if ($(div).css('visibility')=='visible') {
              return true;
          } else {
              return false;
          }
      }
  }<|endoftext|>


<commit_before>/*
 * jQuery UI Spinner @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Spinner
 *
 * Depends:
 *  jquery.ui.core.js
 *  jquery.ui.widget.js
 */
(function( $ ) {

$.widget( "ui.spinner", {
	version: "@VERSION",
	defaultElement: "<input>",
	widgetEventPrefix: "spin",
	options: {
		incremental: true,
		max: null,
		min: null,
		numberFormat: null,
		page: 10,
		step: null,
		value: null
	},

	_create: function() {
		this._markupOptions();
		this._draw();
		this._mousewheel();
		this._aria();
	},

	// TODO: should we use _getCreateOptions() now?
	// would increase overhead of init when options are specified,
	// but would move the defaults to the right location
	// and use our API the way it's meant to be used
	_markupOptions: function() {
		var that = this;
		$.each({
			min: -Number.MAX_VALUE,
			max: Number.MAX_VALUE,
			step: 1
		}, function( attr, defaultValue ) {
			if ( that.options[ attr ] === null ) {
				var value = that.element.attr( attr );
				that.options[ attr ] = typeof value === "string" && value.length > 0 ?
					that._parse( value ) :
					defaultValue;
			}
		});
		this.value( this.options.value !== null ? this.options.value : this.element.val() || 0 );
	},

	_draw: function() {
		var uiSpinner = this.uiSpinner = this.element
			.addClass( "ui-spinner-input" )
			.attr( "autocomplete", "off" )
			.wrap( this._uiSpinnerHtml() )
			.parent()
				// add buttons
				.append( this._buttonHtml() )
				// add behaviors
				.disableSelection();
		this._hoverable( uiSpinner );

		this.element.attr( "role", "spinbutton" );
		this._bind({
			keydown: function( event ) {
				if ( this._start( event ) && this._keydown( event ) ) {
					event.preventDefault();
				}
			},
			keyup: function( event ) {
				if ( this.spinning ) {
					this._stop( event );
					this._change( event );
				}
			},
			focus: function() {
				uiSpinner.addClass( "ui-state-active" );
			},
			blur: function( event ) {
				// don't clear invalid values on blur
				var value = this.element.val(),
					parsed = this._parse( value );
				this.option( "value", parsed );
				if ( parsed === null ) {
					this.element.val( value );
				}
				// TODO: is this really correct or just the simplest
				// way to keep the active class when pressing the buttons?
				// if the mosue is over the text field and the user tabs out
				// shouldn't the active class get removed?
				if ( !uiSpinner.hasClass( "ui-state-hover" ) ) {
					uiSpinner.removeClass( "ui-state-active" );
				}
			}
		});

		// button bindings
		this.buttons = uiSpinner.find( ".ui-spinner-button" )
			.attr( "tabIndex", -1 )
			.button()
			.removeClass( "ui-corner-all" );
		this._bind( this.buttons, {
			mousedown: function( event ) {
				if ( this._start( event ) === false ) {
					return;
				}

				this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
			},
			mouseup: function( event ) {
				if ( this.spinning ) {
					this._stop( event );
					// TODO: don't trigger change until the field is blurred
					this._change( event );
				}
			},
			mouseenter: function( event ) {
				// button will add ui-state-active if mouse was down while mouseleave and kept down
				if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
					return;
				}

				if ( this._start( event ) === false ) {
					return false;
				}
				this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
			},
			// TODO: do we really want to consider this a stop?
			// shouldn't we just stop the repeater and wait until mouseup before
			// we trigger the stop event?
			mouseleave: function() {
				if ( this.spinning ) {
					this._stop( event );
					this._change( event );
				}
			}
		});

		// disable spinner if element was already disabled
		if ( this.options.disabled ) {
			this.disable();
		}
	},

	_keydown: function( event ) {
		var options = this.options,
			keyCode = $.ui.keyCode;

		switch ( event.keyCode ) {
		case keyCode.UP:
			this._repeat( null, 1, event );
			return true;
		case keyCode.DOWN:
			this._repeat( null, -1, event );
			return true;
		case keyCode.PAGE_UP:
			this._repeat( null, options.page, event );
			return true;
		case keyCode.PAGE_DOWN:
			this._repeat( null, -options.page, event );
			return true;
		case keyCode.ENTER:
			this.value( this.element.val() );
		}

		return false;
	},

	_mousewheel: function() {
		// need the delta normalization that mousewheel plugin provides
		if ( !$.fn.mousewheel ) {
			return;
		}
		this._bind({
			mousewheel: function( event, delta ) {
				if ( !delta ) {
					return;
				}
				if ( !this.spinning && !this._start( event ) ) {
					return false;
				}

				this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
				clearTimeout( this.timeout );
				this.timeout = setTimeout(function() {
					if ( this.spinning ) {
						this._stop( event );
						// TODO: don't trigger change until the field is blurred
						this._change( event );
					}
				}, 100 );
				event.preventDefault();
			}
		});
	},

	_uiSpinnerHtml: function() {
		return "";
	},

	_buttonHtml: function() {
		return "" +
			"" +
				"▲" +
			"" +
			"" +
				"▼" +
			"";
	},

	_start: function( event ) {
		if ( !this.spinning && this._trigger( "start", event ) === false ) {
			return false;
		}

		if ( !this.counter ) {
			this.counter = 1;
		}
		this.spinning = true;
		return true;
	},

	_repeat: function( i, steps, event ) {
		var that = this;
		i = i || 500;

		clearTimeout( this.timer );
		this.timer = setTimeout(function() {
			that._repeat( 40, steps, event );
		}, i );

		this._spin( steps * this.options.step, event );
	},

	_spin: function( step, event ) {
		if ( !this.counter ) {
			this.counter = 1;
		}

		// TODO refactor, maybe figure out some non-linear math
		var newVal = this.value() + step * (this.options.incremental &&
			this.counter > 20
				? this.counter > 100
					? this.counter > 200
						? 100
						: 10
					: 2
				: 1);

		// clamp the new value
		newVal = this._trimValue( newVal );

		if ( this._trigger( "spin", event, { value: newVal } ) !== false) {
			this.value( newVal );
			this.counter++;
		}
	},

	_trimValue: function( value ) {
		var options = this.options;

		if ( value > options.max) {
			return options.max;
		}

		if ( value < options.min ) {
			return options.min;
		}

		return value;
	},

	_stop: function( event ) {
		clearTimeout( this.timer );
		this.counter = 0;
		this.element.focus();
		this.spinning = false;
		this._trigger( "stop", event );
	},

	_change: function( event ) {
		this._trigger( "change", event );
	},

	_setOption: function( key, value ) {
		if ( key === "value") {
			value = this._trimValue( this._parse(value) );
		}

		if ( key === "disabled" ) {
			if ( value ) {
				this.element.prop( "disabled", true );
				this.buttons.button( "disable" );
			} else {
				this.element.prop( "disabled", false );
				this.buttons.button( "enable" );
			}
		}

		this._super( "_setOption", key, value );
	},

	_setOptions: function( options ) {
		this._super( "_setOptions", options );
		if ( "value" in options ) {
			this._format( this.options.value );
		}
		this._aria();
	},

	_aria: function() {
		this.element.attr({
			"aria-valuemin": this.options.min,
			"aria-valuemax": this.options.max,
			"aria-valuenow": this.options.value
		});
	},

	_parse: function( val ) {
		if ( typeof val === "string" ) {
			val = $.global && this.options.numberFormat ? $.global.parseFloat( val ) : +val;
		}
		return isNaN( val ) ? null : val;
	},

	_format: function( num ) {
		this.element.val( $.global && this.options.numberFormat ? $.global.format( num, this.options.numberFormat ) : num );
	},

	destroy: function() {
		this.element
			.removeClass( "ui-spinner-input" )
			.prop( "disabled", false )
			.removeAttr( "autocomplete" )
			.removeAttr( "role" )
			.removeAttr( "aria-valuemin" )
			.removeAttr( "aria-valuemax" )
			.removeAttr( "aria-valuenow" );
		this._super( "destroy" );
		this.uiSpinner.replaceWith( this.element );
	},

	stepUp: function( steps ) {
		this._spin( (steps || 1) * this.options.step );
	},

	stepDown: function( steps ) {
		this._spin( (steps || 1) * -this.options.step );
	},

	pageUp: function( pages ) {
		this.stepUp( (pages || 1) * this.options.page );
	},

	pageDown: function( pages ) {
		this.stepDown( (pages || 1) * this.options.page );
	},

	value: function( newVal ) {
		if ( !arguments.length ) {
			return this._parse( this.element.val() );
		}
		this.option( "value", newVal );
	},

	widget: function() {
		return this.uiSpinner;
	}
});

}( jQuery ) );
<commit_msg>Spinner: Keep the focus on the text field even when using the buttons.<commit_after>/*
 * jQuery UI Spinner @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Spinner
 *
 * Depends:
 *  jquery.ui.core.js
 *  jquery.ui.widget.js
 */
(function( $ ) {

$.widget( "ui.spinner", {
	version: "@VERSION",
	defaultElement: "<input>",
	widgetEventPrefix: "spin",
	options: {
		incremental: true,
		max: null,
		min: null,
		numberFormat: null,
		page: 10,
		step: null,
		value: null
	},

	_create: function() {
		this._markupOptions();
		this._draw();
		this._mousewheel();
		this._aria();
	},

	// TODO: should we use _getCreateOptions() now?
	// would increase overhead of init when options are specified,
	// but would move the defaults to the right location
	// and use our API the way it's meant to be used
	_markupOptions: function() {
		var that = this;
		$.each({
			min: -Number.MAX_VALUE,
			max: Number.MAX_VALUE,
			step: 1
		}, function( attr, defaultValue ) {
			if ( that.options[ attr ] === null ) {
				var value = that.element.attr( attr );
				that.options[ attr ] = typeof value === "string" && value.length > 0 ?
					that._parse( value ) :
					defaultValue;
			}
		});
		this.value( this.options.value !== null ? this.options.value : this.element.val() || 0 );
	},

	_draw: function() {
		var uiSpinner = this.uiSpinner = this.element
			.addClass( "ui-spinner-input" )
			.attr( "autocomplete", "off" )
			.wrap( this._uiSpinnerHtml() )
			.parent()
				// add buttons
				.append( this._buttonHtml() );
		this._hoverable( uiSpinner );

		this.element.attr( "role", "spinbutton" );
		this._bind({
			keydown: function( event ) {
				if ( this._start( event ) && this._keydown( event ) ) {
					event.preventDefault();
				}
			},
			keyup: function( event ) {
				if ( this.spinning ) {
					this._stop( event );
					this._change( event );
				}
			},
			focus: function() {
				uiSpinner.addClass( "ui-state-active" );
			},
			blur: function( event ) {
				// don't clear invalid values on blur
				var value = this.element.val(),
					parsed = this._parse( value );
				this.option( "value", parsed );
				if ( parsed === null ) {
					this.element.val( value );
				}
				// TODO: is this really correct or just the simplest
				// way to keep the active class when pressing the buttons?
				// if the mosue is over the text field and the user tabs out
				// shouldn't the active class get removed?
				if ( !uiSpinner.hasClass( "ui-state-hover" ) ) {
					uiSpinner.removeClass( "ui-state-active" );
				}
			}
		});

		// button bindings
		this.buttons = uiSpinner.find( ".ui-spinner-button" )
			.attr( "tabIndex", -1 )
			.button()
			.removeClass( "ui-corner-all" );
		this._bind( this.buttons, {
			mousedown: function( event ) {
				// ensure focus is on (or stays on) the text field
				event.preventDefault();
				if ( document.activeElement !== this.element[ 0 ] ) {
					this.element.focus();
				}

				if ( this._start( event ) === false ) {
					return;
				}

				this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
			},
			mouseup: function( event ) {
				if ( this.spinning ) {
					this._stop( event );
					// TODO: don't trigger change until the field is blurred
					this._change( event );
				}
			},
			mouseenter: function( event ) {
				// button will add ui-state-active if mouse was down while mouseleave and kept down
				if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
					return;
				}

				if ( this._start( event ) === false ) {
					return false;
				}
				this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
			},
			// TODO: do we really want to consider this a stop?
			// shouldn't we just stop the repeater and wait until mouseup before
			// we trigger the stop event?
			mouseleave: function() {
				if ( this.spinning ) {
					this._stop( event );
					this._change( event );
				}
			}
		});

		// disable spinner if element was already disabled
		if ( this.options.disabled ) {
			this.disable();
		}
	},

	_keydown: function( event ) {
		var options = this.options,
			keyCode = $.ui.keyCode;

		switch ( event.keyCode ) {
		case keyCode.UP:
			this._repeat( null, 1, event );
			return true;
		case keyCode.DOWN:
			this._repeat( null, -1, event );
			return true;
		case keyCode.PAGE_UP:
			this._repeat( null, options.page, event );
			return true;
		case keyCode.PAGE_DOWN:
			this._repeat( null, -options.page, event );
			return true;
		case keyCode.ENTER:
			this.value( this.element.val() );
		}

		return false;
	},

	_mousewheel: function() {
		// need the delta normalization that mousewheel plugin provides
		if ( !$.fn.mousewheel ) {
			return;
		}
		this._bind({
			mousewheel: function( event, delta ) {
				if ( !delta ) {
					return;
				}
				if ( !this.spinning && !this._start( event ) ) {
					return false;
				}

				this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
				clearTimeout( this.timeout );
				this.timeout = setTimeout(function() {
					if ( this.spinning ) {
						this._stop( event );
						// TODO: don't trigger change until the field is blurred
						this._change( event );
					}
				}, 100 );
				event.preventDefault();
			}
		});
	},

	_uiSpinnerHtml: function() {
		return "";
	},

	_buttonHtml: function() {
		return "" +
			"" +
				"▲" +
			"" +
			"" +
				"▼" +
			"";
	},

	_start: function( event ) {
		if ( !this.spinning && this._trigger( "start", event ) === false ) {
			return false;
		}

		if ( !this.counter ) {
			this.counter = 1;
		}
		this.spinning = true;
		return true;
	},

	_repeat: function( i, steps, event ) {
		var that = this;
		i = i || 500;

		clearTimeout( this.timer );
		this.timer = setTimeout(function() {
			that._repeat( 40, steps, event );
		}, i );

		this._spin( steps * this.options.step, event );
	},

	_spin: function( step, event ) {
		if ( !this.counter ) {
			this.counter = 1;
		}

		// TODO refactor, maybe figure out some non-linear math
		var newVal = this.value() + step * (this.options.incremental &&
			this.counter > 20
				? this.counter > 100
					? this.counter > 200
						? 100
						: 10
					: 2
				: 1);

		// clamp the new value
		newVal = this._trimValue( newVal );

		if ( this._trigger( "spin", event, { value: newVal } ) !== false) {
			this.value( newVal );
			this.counter++;
		}
	},

	_trimValue: function( value ) {
		var options = this.options;

		if ( value > options.max) {
			return options.max;
		}

		if ( value < options.min ) {
			return options.min;
		}

		return value;
	},

	_stop: function( event ) {
		clearTimeout( this.timer );
		this.counter = 0;
		this.element.focus();
		this.spinning = false;
		this._trigger( "stop", event );
	},

	_change: function( event ) {
		this._trigger( "change", event );
	},

	_setOption: function( key, value ) {
		if ( key === "value") {
			value = this._trimValue( this._parse(value) );
		}

		if ( key === "disabled" ) {
			if ( value ) {
				this.element.prop( "disabled", true );
				this.buttons.button( "disable" );
			} else {
				this.element.prop( "disabled", false );
				this.buttons.button( "enable" );
			}
		}

		this._super( "_setOption", key, value );
	},

	_setOptions: function( options ) {
		this._super( "_setOptions", options );
		if ( "value" in options ) {
			this._format( this.options.value );
		}
		this._aria();
	},

	_aria: function() {
		this.element.attr({
			"aria-valuemin": this.options.min,
			"aria-valuemax": this.options.max,
			"aria-valuenow": this.options.value
		});
	},

	_parse: function( val ) {
		if ( typeof val === "string" ) {
			val = $.global && this.options.numberFormat ? $.global.parseFloat( val ) : +val;
		}
		return isNaN( val ) ? null : val;
	},

	_format: function( num ) {
		this.element.val( $.global && this.options.numberFormat ? $.global.format( num, this.options.numberFormat ) : num );
	},

	destroy: function() {
		this.element
			.removeClass( "ui-spinner-input" )
			.prop( "disabled", false )
			.removeAttr( "autocomplete" )
			.removeAttr( "role" )
			.removeAttr( "aria-valuemin" )
			.removeAttr( "aria-valuemax" )
			.removeAttr( "aria-valuenow" );
		this._super( "destroy" );
		this.uiSpinner.replaceWith( this.element );
	},

	stepUp: function( steps ) {
		this._spin( (steps || 1) * this.options.step );
	},

	stepDown: function( steps ) {
		this._spin( (steps || 1) * -this.options.step );
	},

	pageUp: function( pages ) {
		this.stepUp( (pages || 1) * this.options.page );
	},

	pageDown: function( pages ) {
		this.stepDown( (pages || 1) * this.options.page );
	},

	value: function( newVal ) {
		if ( !arguments.length ) {
			return this._parse( this.element.val() );
		}
		this.option( "value", newVal );
	},

	widget: function() {
		return this.uiSpinner;
	}
});

}( jQuery ) );
<|endoftext|>


<commit_before>var deviceSets = [
    {
        name : 'Default Devices',
        devices : [
            { name: 'iphone 4', w: 320, h:416, type:'phone' },
            { name: 'Nexus 4', w: 382, h:592, type:'phone' },
            { name: 'Samsung Galaxy SII', w: 480, h:480, type:'phone' },
        ]
    },
    {
        name : 'Breakpoints',
        devices : [
            { name: 'Phone', w: 320, h: 480, type:'phone' },
            { name: 'Small Tablet', w: 600, h: 1000, type:'phone' },
            { name: 'Tablet', w: 760, h: 1024 },
            { name: 'Desktop', w: 1024, h: 768 },
        ]
    }
];<commit_msg>updated device sets<commit_after>var deviceSets = [
    {
        name : 'Simple Devices',
        devices : [
            { name: 'Phone', w: 320, h:480, type:'phone', rotated: { w:416, h:320} },
            { name: 'Small Tablet', w: 600, h: 1000, type:'tablet' },
            { name: 'Tablet', w: 760, h: 1024, type:'tablet' },
            { name: '17"', w: 1024, h:768, type:'laptop' },
        ]
    },
    {
        name : 'Common Devices',
        devices : [
            { name: 'iPhone 4', w: 320, h:480, type:'phone', rotated: { w:416, h:320} },
            { name: 'iPhone 5', w: 320, h:568, type:'phone', rotated: { w:568, h:320} },
            { name: 'BlackBerry Curve', w: 480, h:360, type:'phone' },
            { name: 'Nexus 4', w: 382, h:592, type:'phone', rotated: { w:416, h:320} },
            { name: 'Apple iPad', w: 768, h:1024, type:'tablet' },
            { name: '17"', w: 1024, h:768, type:'laptop' },
        ]
    },
    {
        name : 'Breakpoints',
        devices : [
            { name: '1', w: 320, h: 480, type:'phone' },
            { name: '2', w: 600, h: 1000, type:'tablet' },
            { name: '3', w: 760, h: 1024 },
            { name: '4', w: 1024, h: 768 },
        ]
    }
];<|endoftext|>