<commit_before>/**
 * Copyright 2015 Vivliostyle Inc.
 * @fileoverview Vivliostyle Viewer class
 */
goog.provide("vivliostyle.viewer");

goog.require("vivliostyle.namespace");
goog.require("vivliostyle.constants");
goog.require("vivliostyle.util");
goog.require("adapt.base");
goog.require("adapt.viewer");

goog.scope(function() {
    /** @const */ var PageProgression = vivliostyle.constants.PageProgression;

    /**
     * Viewer settings that must be passed to Viewer's constructor.
     * - userAgentRootURL: URL of a directory from which viewer resource files (under resources/ directory in the source repository) are served.
     * - viewportElement: An element used as the viewport of the displayed contents.
     * - window: Window object. If omitted, current `window` is used.
     * @dict
     * @typedef {{
     *     userAgentRootURL: string,
     *     viewportElement: !HTMLElement,
     *     window: (!Window|undefined)
     * }}
     */
    vivliostyle.viewer.ViewerSettings;

    /**
     * Viewer options that can be set after the Viewer object is constructed.
     * - autoResize: Run layout again when the window is resized. default: true
     * - fontSize: Default font size (px). default: 16
     * - pageBorderWidth: Width of a border between two pages in a single spread (px). Effective only when spreadView option is true. default: 1
     * - renderAllPages: Render all pages at the document load time. default: true
     * - spreadView: Display two pages in a single spread at a time. default: false
     * - zoom: Zoom factor with which pages are displayed. default: 1
     * @dict
     * @typedef {{
     *     autoResize: (boolean|undefined),
     *     fontSize: (number|undefined),
     *     pageBorderWidth: (number|undefined),
     *     renderAllPages: (boolean|undefined),
     *     spreadView: (boolean|undefined),
     *     zoom: (number|undefined)
     * }}
     */
    vivliostyle.viewer.ViewerOptions;

    /**
     * @returns {!vivliostyle.viewer.ViewerOptions}
     */
    function getDefaultViewerOptions() {
        return {
            "autoResize": true,
            "fontSize": 16,
            "pageBorderWidth": 1,
            "renderAllPages": true,
            "spreadView": false,
            "zoom": 1
        };
    }

    /**
     * @param {!vivliostyle.viewer.ViewerOptions} options
     * @returns {!Object}
     */
    function convertViewerOptions(options) {
        var converted = {};
        Object.keys(options).forEach(function(key) {
            var v = options[key];
            switch (key) {
                case "autoResize":
                    converted["autoresize"] = v;
                    break;
                case "pageBorderWidth":
                    converted["pageBorder"] = v;
                    break;
                default:
                    converted[key] = v;
            }
        });
        return converted;
    }

    /**
     * Options for the displayed document.
     * - documentObject: Document object for the document. If provided, it is used directly without parsing the source again.
     * - fragment: Fragmentation identifier (EPUB CFI) of the location in the document which is to be displayed.
     * - userStyleSheet: An array of user style sheets to be injected. A single stylesheet may be a URL of the style sheet or a text content of the style sheet.
     * @dict
     * @typedef {{
     *     documentObject: (!Document|undefined),
     *     fragment: (string|undefined),
     *     userStyleSheet: (!Array<{url: (string|undefined), text: (string|undefined)}>|undefined)
     * }}
     */
    vivliostyle.viewer.DocumentOptions;

    /**
     * Vivliostyle Viewer class.
     * @param {!vivliostyle.viewer.ViewerSettings} settings
     * @param {!vivliostyle.viewer.ViewerOptions=} opt_options
     * @constructor
     */
    vivliostyle.viewer.Viewer = function(settings, opt_options) {
        /** @const @private */ this.settings = settings;
        /** @const @private */ this.adaptViewer = new adapt.viewer.Viewer(
            settings["window"] || window, settings["viewportElement"], "main", this.dispatcher.bind(this));
        /** @private @type {!vivliostyle.viewer.ViewerOptions} */
        this.options = getDefaultViewerOptions();
        if (opt_options) {
            this.setOptions(opt_options);
        }
        /** @const @private */ this.eventTarget = new adapt.base.SimpleEventTarget();
    };
    /** @const */ var Viewer = vivliostyle.viewer.Viewer;

    /**
     * Set ViewerOptions to the viewer.
     * @param {!vivliostyle.viewer.ViewerOptions} options
     */
    Viewer.prototype.setOptions = function(options) {
        var command = Object.assign({"a": "configure"}, convertViewerOptions(options));
        this.adaptViewer.sendCommand(command);
        Object.assign(this.options, options);
    };

    /**
     * @private
     * @param {!adapt.base.JSON} msg
     */
    Viewer.prototype.dispatcher = function(msg) {
        /** @dict */ var event = {"type": msg["t"]};
        var o = /** @type {!Object} */ (msg);
        Object.keys(o).forEach(function(key) {
            if (key !== "t") {
                event[key] = o[key];
            }
        });
        this.eventTarget.dispatchEvent(event);
    };

    /**
     * Add a listener function, which is invoked when the specified type of event is dispatched.
     * @param {string} type Event type.
     * @param {!function(!{type: string}):void} listener Listener function.
     */
    Viewer.prototype.addListener = function(type, listener) {
        this.eventTarget.addEventListener(type, /** @type {adapt.base.EventListener} */ (listener), false);
    };

    /**
     * Remove an event listener.
     * @param {string} type Event type.
     * @param {!function(!{type: string}):void} listener Listener function.
     */
    Viewer.prototype.removeListener = function(type, listener) {
        this.eventTarget.removeEventListener(type, /** @type {adapt.base.EventListener} */ (listener), false);
    };

    /**
     * Load a HTML or an XML document.
     * @param {string} url
     * @param {!vivliostyle.viewer.DocumentOptions=} opt_documentOptions
     * @param {!vivliostyle.viewer.ViewerOptions=} opt_viewerOptions
     */
    Viewer.prototype.loadDocument = function(url, opt_documentOptions, opt_viewerOptions) {
        if (!url) {
            this.eventTarget.dispatchEvent({"type": "error", "content": "No URL specified"});
        }

        var documentOptions = opt_documentOptions || {};
        var userStyleSheet;
        var uss = documentOptions["userStyleSheet"];
        if (uss) {
            userStyleSheet = uss.map(function(s) {
                return { url: s.url || null, text: s.text || null};
            });
        }

        if (opt_viewerOptions) {
            Object.assign(this.options, opt_viewerOptions);
        }

        var command = Object.assign({
            "a": "loadXML",

            "userAgentRootURL": this.settings["userAgentRootURL"],

            "url": url,
            "document": documentOptions["documentObject"],
            "fragment": documentOptions["fragment"],
            "userStyleSheet": userStyleSheet
        }, convertViewerOptions(this.options));
        this.adaptViewer.initEmbed(command);
    };

    /**
     * Returns the current page progression of the viewer. If no document is loaded, returns null.
     * @returns {?vivliostyle.constants.PageProgression}
     */
    Viewer.prototype.getCurrentPageProgression = function() {
        return this.adaptViewer.getCurrentPageProgression();
    };

    /**
     * @enum {string}
     */
    vivliostyle.viewer.Navigation = {
        PREVIOUS: "previous",
        NEXT: "next",
        LEFT: "left",
        RIGHT: "right",
        FIRST: "first",
        LAST: "last"
    };
    /** @const */ var Navigation = vivliostyle.viewer.Navigation;

    /**
     * @private
     * @param {!vivliostyle.viewer.Navigation} nav
     * @returns {!vivliostyle.viewer.Navigation}
     */
    Viewer.prototype.resolveNavigation = function(nav) {
        switch (nav) {
            case Navigation.LEFT:
                return this.getCurrentPageProgression() === PageProgression.LTR ? Navigation.PREVIOUS : Navigation.NEXT;
            case Navigation.RIGHT:
                return this.getCurrentPageProgression() === PageProgression.LTR ? Navigation.NEXT : Navigation.PREVIOUS;
            default:
                return nav;
        }
    };

    /**
     * Navigate to the specified page.
     * @param {!vivliostyle.viewer.Navigation} nav
     */
    Viewer.prototype.navigateToPage = function(nav) {
        this.adaptViewer.sendCommand({"a": "moveTo", "where": this.resolveNavigation(nav)});
    };

    /**
     * Navigate to the specified internal URL.
     * @param {string} url
     */
    Viewer.prototype.navigateToInternalUrl = function(url) {
        this.adaptViewer.sendCommand({"a": "moveTo", "url": url});
    };

    /**
     * @enum {string}
     */
    vivliostyle.viewer.ZoomType = adapt.viewer.ZoomType;
    /** @const */ var ZoomType = vivliostyle.viewer.ZoomType;

    /**
     * Returns zoom factor corresponding to the specified zoom type.
     * @param {vivliostyle.viewer.ZoomType} type
     * @returns {number}
     */
    Viewer.prototype.queryZoomFactor = function(type) {
        return this.adaptViewer.queryZoomFactor(type);
    };

    vivliostyle.namespace.exportSymbol("vivliostyle.viewer.Viewer", Viewer);
    goog.exportProperty(Viewer.prototype, "setOptions", Viewer.prototype.setOptions);
    goog.exportProperty(Viewer.prototype, "addListener", Viewer.prototype.addListener);
    goog.exportProperty(Viewer.prototype, "removeListener", Viewer.prototype.removeListener);
    goog.exportProperty(Viewer.prototype, "loadDocument", Viewer.prototype.loadDocument);
    goog.exportProperty(Viewer.prototype, "getCurrentPageProgression", Viewer.prototype.getCurrentPageProgression);
    goog.exportProperty(Viewer.prototype, "navigateToPage", Viewer.prototype.navigateToPage);
    goog.exportProperty(Viewer.prototype, "navigateToInternalUrl", Viewer.prototype.navigateToInternalUrl);
    goog.exportProperty(Viewer.prototype, "queryZoomFactor", Viewer.prototype.queryZoomFactor);
    vivliostyle.namespace.exportSymbol("vivliostyle.viewer.ZoomType", ZoomType);
    goog.exportProperty(ZoomType, "FIT_INSIDE_VIEWPORT", ZoomType.FIT_INSIDE_VIEWPORT);
});
<commit_msg>Support EPUB loading - `loadEPUB` method of `Viewer` class loads an unzipped EPUB directory<commit_after>/**
 * Copyright 2015 Vivliostyle Inc.
 * @fileoverview Vivliostyle Viewer class
 */
goog.provide("vivliostyle.viewer");

goog.require("vivliostyle.namespace");
goog.require("vivliostyle.constants");
goog.require("vivliostyle.util");
goog.require("adapt.base");
goog.require("adapt.viewer");

goog.scope(function() {
    /** @const */ var PageProgression = vivliostyle.constants.PageProgression;

    /**
     * Viewer settings that must be passed to Viewer's constructor.
     * - userAgentRootURL: URL of a directory from which viewer resource files (under resources/ directory in the source repository) are served.
     * - viewportElement: An element used as the viewport of the displayed contents.
     * - window: Window object. If omitted, current `window` is used.
     * @dict
     * @typedef {{
     *     userAgentRootURL: string,
     *     viewportElement: !HTMLElement,
     *     window: (!Window|undefined)
     * }}
     */
    vivliostyle.viewer.ViewerSettings;

    /**
     * Viewer options that can be set after the Viewer object is constructed.
     * - autoResize: Run layout again when the window is resized. default: true
     * - fontSize: Default font size (px). default: 16
     * - pageBorderWidth: Width of a border between two pages in a single spread (px). Effective only when spreadView option is true. default: 1
     * - renderAllPages: Render all pages at the document load time. default: true
     * - spreadView: Display two pages in a single spread at a time. default: false
     * - zoom: Zoom factor with which pages are displayed. default: 1
     * @dict
     * @typedef {{
     *     autoResize: (boolean|undefined),
     *     fontSize: (number|undefined),
     *     pageBorderWidth: (number|undefined),
     *     renderAllPages: (boolean|undefined),
     *     spreadView: (boolean|undefined),
     *     zoom: (number|undefined)
     * }}
     */
    vivliostyle.viewer.ViewerOptions;

    /**
     * @returns {!vivliostyle.viewer.ViewerOptions}
     */
    function getDefaultViewerOptions() {
        return {
            "autoResize": true,
            "fontSize": 16,
            "pageBorderWidth": 1,
            "renderAllPages": true,
            "spreadView": false,
            "zoom": 1
        };
    }

    /**
     * @param {!vivliostyle.viewer.ViewerOptions} options
     * @returns {!Object}
     */
    function convertViewerOptions(options) {
        var converted = {};
        Object.keys(options).forEach(function(key) {
            var v = options[key];
            switch (key) {
                case "autoResize":
                    converted["autoresize"] = v;
                    break;
                case "pageBorderWidth":
                    converted["pageBorder"] = v;
                    break;
                default:
                    converted[key] = v;
            }
        });
        return converted;
    }

    /**
     * Options for the displayed document.
     * - documentObject: Document object for the document. If provided, it is used directly without parsing the source again.
     * - fragment: Fragmentation identifier (EPUB CFI) of the location in the document which is to be displayed.
     * - userStyleSheet: An array of user style sheets to be injected. A single stylesheet may be a URL of the style sheet or a text content of the style sheet.
     * @dict
     * @typedef {{
     *     documentObject: (!Document|undefined),
     *     fragment: (string|undefined),
     *     userStyleSheet: (!Array<{url: (string|undefined), text: (string|undefined)}>|undefined)
     * }}
     */
    vivliostyle.viewer.DocumentOptions;

    /**
     * Vivliostyle Viewer class.
     * @param {!vivliostyle.viewer.ViewerSettings} settings
     * @param {!vivliostyle.viewer.ViewerOptions=} opt_options
     * @constructor
     */
    vivliostyle.viewer.Viewer = function(settings, opt_options) {
        /** @const @private */ this.settings = settings;
        /** @const @private */ this.adaptViewer = new adapt.viewer.Viewer(
            settings["window"] || window, settings["viewportElement"], "main", this.dispatcher.bind(this));
        /** @private @type {!vivliostyle.viewer.ViewerOptions} */
        this.options = getDefaultViewerOptions();
        if (opt_options) {
            this.setOptions(opt_options);
        }
        /** @const @private */ this.eventTarget = new adapt.base.SimpleEventTarget();
    };
    /** @const */ var Viewer = vivliostyle.viewer.Viewer;

    /**
     * Set ViewerOptions to the viewer.
     * @param {!vivliostyle.viewer.ViewerOptions} options
     */
    Viewer.prototype.setOptions = function(options) {
        var command = Object.assign({"a": "configure"}, convertViewerOptions(options));
        this.adaptViewer.sendCommand(command);
        Object.assign(this.options, options);
    };

    /**
     * @private
     * @param {!adapt.base.JSON} msg
     */
    Viewer.prototype.dispatcher = function(msg) {
        /** @dict */ var event = {"type": msg["t"]};
        var o = /** @type {!Object} */ (msg);
        Object.keys(o).forEach(function(key) {
            if (key !== "t") {
                event[key] = o[key];
            }
        });
        this.eventTarget.dispatchEvent(event);
    };

    /**
     * Add a listener function, which is invoked when the specified type of event is dispatched.
     * @param {string} type Event type.
     * @param {!function(!{type: string}):void} listener Listener function.
     */
    Viewer.prototype.addListener = function(type, listener) {
        this.eventTarget.addEventListener(type, /** @type {adapt.base.EventListener} */ (listener), false);
    };

    /**
     * Remove an event listener.
     * @param {string} type Event type.
     * @param {!function(!{type: string}):void} listener Listener function.
     */
    Viewer.prototype.removeListener = function(type, listener) {
        this.eventTarget.removeEventListener(type, /** @type {adapt.base.EventListener} */ (listener), false);
    };

    /**
     * Load an HTML or XML document.
     * @param {string} url
     * @param {!vivliostyle.viewer.DocumentOptions=} opt_documentOptions
     * @param {!vivliostyle.viewer.ViewerOptions=} opt_viewerOptions
     */
    Viewer.prototype.loadDocument = function(url, opt_documentOptions, opt_viewerOptions) {
        if (!url) {
            this.eventTarget.dispatchEvent({"type": "error", "content": "No URL specified"});
        }
        this.loadDocumentOrEPUB(url, null, opt_documentOptions, opt_viewerOptions);
    };

    /**
     * Load an EPUB document.
     * @param {string} epubUrl
     * @param {!vivliostyle.viewer.DocumentOptions=} opt_documentOptions
     * @param {!vivliostyle.viewer.ViewerOptions=} opt_viewerOptions
     */
    Viewer.prototype.loadEPUB = function(epubUrl, opt_documentOptions, opt_viewerOptions) {
        if (!epubUrl) {
            this.eventTarget.dispatchEvent({"type": "error", "content": "No URL specified"});
        }
        this.loadDocumentOrEPUB(null, epubUrl, opt_documentOptions, opt_viewerOptions);
    };

    /**
     * Load an HTML or XML document, or an EPUB document.
     * @private
     * @param {?string} url
     * @param {?string} epubUrl
     * @param {!vivliostyle.viewer.DocumentOptions=} opt_documentOptions
     * @param {!vivliostyle.viewer.ViewerOptions=} opt_viewerOptions
     */
    Viewer.prototype.loadDocumentOrEPUB = function(url, epubUrl, opt_documentOptions, opt_viewerOptions) {
        var documentOptions = opt_documentOptions || {};
        var userStyleSheet;
        var uss = documentOptions["userStyleSheet"];
        if (uss) {
            userStyleSheet = uss.map(function(s) {
                return { url: s.url || null, text: s.text || null};
            });
        }

        if (opt_viewerOptions) {
            Object.assign(this.options, opt_viewerOptions);
        }

        var command = Object.assign({
            "a": url ? "loadXML" : "loadEPUB",

            "userAgentRootURL": this.settings["userAgentRootURL"],

            "url": url || epubUrl,
            "document": documentOptions["documentObject"],
            "fragment": documentOptions["fragment"],
            "userStyleSheet": userStyleSheet
        }, convertViewerOptions(this.options));
        this.adaptViewer.initEmbed(command);
    };

    /**
     * Returns the current page progression of the viewer. If no document is loaded, returns null.
     * @returns {?vivliostyle.constants.PageProgression}
     */
    Viewer.prototype.getCurrentPageProgression = function() {
        return this.adaptViewer.getCurrentPageProgression();
    };

    /**
     * @enum {string}
     */
    vivliostyle.viewer.Navigation = {
        PREVIOUS: "previous",
        NEXT: "next",
        LEFT: "left",
        RIGHT: "right",
        FIRST: "first",
        LAST: "last"
    };
    /** @const */ var Navigation = vivliostyle.viewer.Navigation;

    /**
     * @private
     * @param {!vivliostyle.viewer.Navigation} nav
     * @returns {!vivliostyle.viewer.Navigation}
     */
    Viewer.prototype.resolveNavigation = function(nav) {
        switch (nav) {
            case Navigation.LEFT:
                return this.getCurrentPageProgression() === PageProgression.LTR ? Navigation.PREVIOUS : Navigation.NEXT;
            case Navigation.RIGHT:
                return this.getCurrentPageProgression() === PageProgression.LTR ? Navigation.NEXT : Navigation.PREVIOUS;
            default:
                return nav;
        }
    };

    /**
     * Navigate to the specified page.
     * @param {!vivliostyle.viewer.Navigation} nav
     */
    Viewer.prototype.navigateToPage = function(nav) {
        this.adaptViewer.sendCommand({"a": "moveTo", "where": this.resolveNavigation(nav)});
    };

    /**
     * Navigate to the specified internal URL.
     * @param {string} url
     */
    Viewer.prototype.navigateToInternalUrl = function(url) {
        this.adaptViewer.sendCommand({"a": "moveTo", "url": url});
    };

    /**
     * @enum {string}
     */
    vivliostyle.viewer.ZoomType = adapt.viewer.ZoomType;
    /** @const */ var ZoomType = vivliostyle.viewer.ZoomType;

    /**
     * Returns zoom factor corresponding to the specified zoom type.
     * @param {vivliostyle.viewer.ZoomType} type
     * @returns {number}
     */
    Viewer.prototype.queryZoomFactor = function(type) {
        return this.adaptViewer.queryZoomFactor(type);
    };

    vivliostyle.namespace.exportSymbol("vivliostyle.viewer.Viewer", Viewer);
    goog.exportProperty(Viewer.prototype, "setOptions", Viewer.prototype.setOptions);
    goog.exportProperty(Viewer.prototype, "addListener", Viewer.prototype.addListener);
    goog.exportProperty(Viewer.prototype, "removeListener", Viewer.prototype.removeListener);
    goog.exportProperty(Viewer.prototype, "loadDocument", Viewer.prototype.loadDocument);
    goog.exportProperty(Viewer.prototype, "getCurrentPageProgression", Viewer.prototype.getCurrentPageProgression);
    goog.exportProperty(Viewer.prototype, "navigateToPage", Viewer.prototype.navigateToPage);
    goog.exportProperty(Viewer.prototype, "navigateToInternalUrl", Viewer.prototype.navigateToInternalUrl);
    goog.exportProperty(Viewer.prototype, "queryZoomFactor", Viewer.prototype.queryZoomFactor);
    vivliostyle.namespace.exportSymbol("vivliostyle.viewer.ZoomType", ZoomType);
    goog.exportProperty(ZoomType, "FIT_INSIDE_VIEWPORT", ZoomType.FIT_INSIDE_VIEWPORT);
});
<|endoftext|>


<commit_before>
let constants = require('./constants'),
    EP = constants.EP,
    EP_CONFIG_DEFAULTS = constants.EP_CONFIG_DEFAULTS,
    PERMISSION_ACCESSOR_NAME = constants.PERMISSION_ACCESSOR_NAME

let _ = require('underscore'),
    path = require('path')

class Plugin {
  constructor (base, name, description) {
    this.name = name
    this.location = base
    this.description = description
    this._extensions = []
    this._modules = {}
    this._extensionCache = {}
  }

  initializeFromDisk (loader) {
    let base = this.location
    return loader.loadJsonFromModule(base, 'package.json')
      .then((packageJson) => {
        this.description = packageJson.description
        this.name = packageJson.name
        this.api = new PluginAPI(this.name)
        let manifestFile = packageJson.compo
        if (_.isString(manifestFile)) {
          return loader.loadJsonFromModule(base, manifestFile)
        }
      })
      .then((manifest) => {
        this._manifest = manifest
        return this
      })
  }

  get extensions () {
    return this._extensions
  }

  start () {
    // Load the npm module's main
    let plugin = this,
        pluginBase
    if (plugin.isStarted) {
      return
    }
    try {
      pluginBase = require(plugin.location)
      plugin.isStarted = true
    } catch (err) {
      console.error('Cannot start ' + plugin.location)
      console.error(err.stack)
      throw err
    }
    // and give it the plugin api.
    // This is a horrible hack, but it now lets plugins
    // access singletons/permissions through
    // require('.').plugin or require('..').plugin
    pluginBase[PERMISSION_ACCESSOR_NAME] = plugin.api

    // It does not make for pretty code within the main module itself
    // however, because the plugin api will only be accessible after
    // the first run of the module.
    // Instead, you should use exports.plugin within event listeners.
    // It could be usefully argued that the main (activator in OSGi speak)
    // is the most likely candidate for special boiler plate.
  }

  transformManifest (registry) {
    let plugin = this,
        manifest = plugin._manifest

    let manifestTransforms = registry.getExtensionPoint(EP.MANIFEST_TRANSFORM).array

    manifestTransforms.forEach((t) => {
      // Should throw if manifest fails test
      t(manifest)
    })

    let extensionTransforms = registry.getExtensionPoint(EP.EXTENSION_TRANSFORM).objectGroups

    let performTransforms = (remaining, addedExtensions) => {
      let filtered = remaining.filter((ex) => {
        let remove = false
        let transforms = extensionTransforms[ex.epID]
        if (!transforms) {
          return true
        }
        transforms.forEach((t) => {
          t(ex, addedExtensions)
          if (t.replace) {
            replace = true
          }
        })
        return !replace
      })

      return filtered
    }

    let additions = manifest.extensions || []
    let extensions = []

    while (additions.length) {
      let newAdditions = []

      additions = performTransforms(additions, newAdditions)
      additions.forEach((ex) => {
        extensions.push(ex)
      })
      additions = newAdditions

    }
  }

  provisionAPI (registry) {
    let plugin = this,
        manifest = this._manifest,
        api = plugin.api

    // We should now set about constructing the api object
    // so it is ready to go when start creating objects which
    // need access to a fully operational api object.

    // so: permissions, extensionPoints, singletons, extensions

    // `permissions` is asking for access by this plugin
    /*
      {
        permissions: ['prefs']
      }
     */
    plugin.grantPermissions(registry, manifest.permissions)

    // `extensionPoints`: these need to be done before
    {
      let accessibleEPs = api.extensionPoints || {}
      _.each(manifest.extensionPoints, (i, epID) => {
        if (epID.indexOf('internal.') === 0) {
          console.warn('Plugin ' + plugin.name + ' has trying to consume a private extension point: ' + epID)
          return
        }
        let ep = registry.getExtensionPoint(epID)
        let config = manifest.extensionPoints[epID]
        config = _.defaults(config, EP_CONFIG_DEFAULTS)

        // TODO What if more than one plugin wants to use the extension point
        ep.key = config.key
        ep.lazy = config.lazy
        ep.description = config.description

        // This is where the extension point is attached to the plugin object.
        // Current implementation is that we do nothing special with property
        // It's difficult to accidentally share plugins.
        accessibleEPs[epID] = ep
      })
      api.extensionPoints = accessibleEPs
    }

    {
      let singletons = manifest.singletons
      if (_.isObject(singletons)) {
        // Automatically grant permission to access singletons that the
        // plugin registers.
        plugin.grantPermissions(registry, Object.keys(singletons))
      }
    }
  }

  populateSingletons (registry) {
    // `singletons` are objects that this plugin defines
    // and made available to other plugins as permissions
    /*
      {
        singletons: {
          prefs: './lib/app-writeable-files',
          samePrefs: {
            object: './lib/app-writeable-files'
          }
        }
      }
     */
    let plugin = this
    let manifest = plugin._manifest
    let singletons = manifest.singletons
    if (_.isObject(singletons)) {
      _.each(manifest.singletons, (i, id) => {
        let singleton = manifest.singletons[id]
        singleton._id = id
        plugin.register(registry, EP.SINGLETONS, singleton)
      })
    }
  }

  distributeExtensions (registry) {
    let plugin = this
    let manifest = plugin._manifest

    // `extensions`: normalized to an array of objects, with the epID filled in.
      _.each(manifest.extensions, (ex) => {
        let epID = ex.epID
        if (!epID) {
          console.warn('Plugin ' + plugin.name + ' has an extension with no epID')
        } else if (epID.indexOf('internal.') === 0) {
          console.warn('Plugin ' + plugin.name + ' has trying to contribute to a private extension point: ' + epID)
        } else {
          plugin.register(registry, ex.epID, ex)
        }
      })

  }

  register (registry, epID, obj) {
    obj = this._preTreatExtension(obj)
    // TODO what to do about lazy loading?
    obj = this.inflate(obj)
    registry.register(epID, obj)
    obj.__epID = epID
    this._extensions.push(obj)
  }

  grantPermissions (registry, permissions) {
    let ep = registry.getExtensionPoint(EP.SINGLETONS)
    ep.key = '_id'
    let api = this.api
    _.each(permissions, (p) => {
      if (Object.getOwnPropertyDescriptor(api, p)) {
        // Stops the same plugin asking for the same permission more
        // than once.
        return
      }
      Object.defineProperty(api, p, {
        get: function () {
          let obj = ep.object[p]
          if (obj) {
            return obj
          }
          throw new Error('Permission ' + p + ' is granted but no singleton of that name is registered')
        }
      })
    })
  }

  _preTreatExtension (obj) {
    return _.mapObject(obj, (value, key) => {
      // This forces extension developers to be clear that other
      // plugins have access to the values in the manifest.
      if (typeof value === 'string') {
        return value.replace(/\b__dirname\b/, this.location)
      } else {
        return value
      }
    })
  }

  unload (registry) {
    // Unregister all the extensions we've previously registered.
    _.each(this._extensions, (obj) => {
      let epID = obj.__epID
      registry.unregister(epID, obj)
    })

    let doUnload
    if (this.isStarted) {
      let pluginBase = require(this.location)
      if (_.isFunction(pluginBase.unload)) {
        // Good fences in unload().
        try {
          let result = pluginBase.unload()
          doUnload = Promise.resolve(result)
            .catch((e) => {
              console.error('Error calling ' + this.name + '.unload():', e.message)
              throw e
            })
        } catch (e) {
          doUnload = Promise.reject(e)
        }
      }
    }

    if (!doUnload) {
      doUnload = Promise.resolve()
    }

    let unlistenExtensionPoints = () => {
      _.values(this.api.extensionPoints)
       .forEach((ep) => {
        ep._emitter.removeAllListeners()
       })
    }

    let deleteRequireCache = () => {
      // Now, delete all the Javascript from the require.cache.
      // When we load the plugin again, we will
      let requiredPaths = _.keys(require.cache)
      let location = this.location
      _.each(requiredPaths, (modulePath) => {
        if (modulePath.indexOf(location) === 0) {
          delete require.cache[modulePath]
        }
      })
      return this
    }

    return doUnload
      .then(unlistenExtensionPoints)
      .then(deleteRequireCache)
  }

  _loadPluginJavascript (extPath) {
    let plugin = this
    // the extension path is of a form
    // ./relative/module!aProperty
    let cache = plugin._extensionCache

    let moduleName, propertyNames
    {
      let segs = extPath.split('!')
      moduleName = segs.shift()
      propertyNames = segs.length ? segs.join('.').split('.') : []
    }

    if (_.isEmpty(plugin._modules)) {
      plugin.start()
    }

    let moduleExports = plugin._modules[moduleName]
    if (!moduleExports) {
      // Load the extension's module.
      // It is guaranteed* that the require('..') will have the plugin api
      // on it by the time we get to here.
      // * excepting sabotage, it's not secure.
      let modulePath = (moduleName[0] === '.')
        ? path.join(plugin.location, moduleName)
        : moduleName

      try {
        moduleExports = require(modulePath)
        plugin._modules[moduleName] = moduleExports
      } catch (e) {
        console.error(e.stack)
        throw new Error('Error loading ' + modulePath + ': ' + e.message)
      }
    }

    // prop_ is our final result.
    // this_ is the context where we search for the next prop_
    let this_ = null,
        prop_ = moduleExports

    {
      let thisPath = moduleName,
          propertyPath

      for (let propertyName of propertyNames) {
        if (!propertyName) {
          // This is to stop '..' oddities.
          // but also fixes a bug with the join/split leaving empty strings
          continue
        }
        this_ =  prop_

        if (!propertyPath) {
          propertyPath = moduleName + '!' + propertyName
        } else {
          propertyPath += '.' + propertyName
        }

        // Now we know what we're going to call it, let's find it.
        let cached = cache[propertyPath]
        if (cached !== undefined) {
          // We don't cache aggressively, but we check here if
          // we need to do any more work.
          prop_ = cached.object
        } else {
          // We can try to navigate to this property.
          prop_ = this_[propertyName]
        }

        if (prop_ === undefined && _.isFunction(this_)) {
          // So we have an function Ctor, which didn't have the asked for property, method
          // e.g. Ctor.method
          // Here we assume that Ctor is a constructor, and so go ahead and create an object
          // with it. Then look again to see if the property exists (i.e. on the prototype)
          this_ = this._createObject(this_, thisPath)
          prop_ = this_[propertyName]
          if (prop_ !== undefined) {
            // Now we can cache the instance of the constructor
            // so the class is effectively a singleton.
            cache[thisPath] = {
              context: null,
              object: this_,
            }
          }
        }

        if (prop_ === undefined) {
          throw new Error('Cannot find ' + propertyName + ' in ' + thisPath + ' (in ' + extPath + ')')
        }

        thisPath = propertyPath
      }
    }

    cache[extPath] = {
      context: this_,
      object: prop_
    }

    return cache[extPath]
  }

  _createObject (Constructor, errorPath) {
    try {
      return new (Function.prototype.bind.call(Constructor))
    } catch (e) {
      console.error('Error loading ' + errorPath, e.stack)
    }
  }

  inflate (extension) {
    let plugin = this
    // We're expecting extensions to look like
    /*
    {
      "function": "./path/to/module!aFunction"
      "object": "./path/to/module!Ctor"
    }
     */
    let extType, extPath
    {
      for (let t of ['function', 'object']) {
        if (extension[t]) {
          extType = t
          extPath = extension[t]
        }
      }
    }

    if (!extType) {
      // The extension is neither a function nor an object.
      // We should just give it back.
      return extension
    }

    let codeObject = this._loadPluginJavascript(extPath)

    let returnValue = codeObject.object,
        context = codeObject.context
    switch (extType) {
      case 'object':
        if (_.isFunction(returnValue)) {
          codeObject.object = returnValue = this._createObject(returnValue, extPath)
          codeObject.context = context = undefined
        }
        break;
      case 'function':
        if (_.isFunction(returnValue) && context) {
          codeObject.object = returnValue = returnValue.bind(codeObject.context)
          codeObject.context = context = undefined
        }
        break
      default:
        if (_.isFunction(returnValue)) {
          console.warn('Cannot tell if ' + extPath + ' is a constructor or a function. Assuming a function.')
        }
    }

    if (_.isObject(returnValue) && _.isObject(extension)) {
      _.extend(returnValue, extension)
    }

    return returnValue
  }
}

class PluginAPI {
  constructor (name) {
    this.name = name
  }
}

module.exports = {Plugin, PluginAPI}
<commit_msg>More verbose logging on error.<commit_after>
let constants = require('./constants'),
    EP = constants.EP,
    EP_CONFIG_DEFAULTS = constants.EP_CONFIG_DEFAULTS,
    PERMISSION_ACCESSOR_NAME = constants.PERMISSION_ACCESSOR_NAME

let _ = require('underscore'),
    path = require('path')

class Plugin {
  constructor (base, name, description) {
    this.name = name
    this.location = base
    this.description = description
    this._extensions = []
    this._modules = {}
    this._extensionCache = {}
  }

  initializeFromDisk (loader) {
    let base = this.location
    return loader.loadJsonFromModule(base, 'package.json')
      .then((packageJson) => {
        this.description = packageJson.description
        this.name = packageJson.name
        this.api = new PluginAPI(this.name)
        let manifestFile = packageJson.compo
        if (_.isString(manifestFile)) {
          return loader.loadJsonFromModule(base, manifestFile)
        }
      })
      .then((manifest) => {
        this._manifest = manifest
        return this
      })
  }

  get extensions () {
    return this._extensions
  }

  start () {
    // Load the npm module's main
    let plugin = this,
        pluginBase
    if (plugin.isStarted) {
      return
    }
    try {
      pluginBase = require(plugin.location)
      plugin.isStarted = true
    } catch (err) {
      console.error('Cannot start ' + plugin.location)
      console.error(err.stack)
      throw err
    }
    // and give it the plugin api.
    // This is a horrible hack, but it now lets plugins
    // access singletons/permissions through
    // require('.').plugin or require('..').plugin
    pluginBase[PERMISSION_ACCESSOR_NAME] = plugin.api

    // It does not make for pretty code within the main module itself
    // however, because the plugin api will only be accessible after
    // the first run of the module.
    // Instead, you should use exports.plugin within event listeners.
    // It could be usefully argued that the main (activator in OSGi speak)
    // is the most likely candidate for special boiler plate.
  }

  transformManifest (registry) {
    let plugin = this,
        manifest = plugin._manifest

    let manifestTransforms = registry.getExtensionPoint(EP.MANIFEST_TRANSFORM).array

    manifestTransforms.forEach((t) => {
      // Should throw if manifest fails test
      t(manifest)
    })

    let extensionTransforms = registry.getExtensionPoint(EP.EXTENSION_TRANSFORM).objectGroups

    let performTransforms = (remaining, addedExtensions) => {
      let filtered = remaining.filter((ex) => {
        let remove = false
        let transforms = extensionTransforms[ex.epID]
        if (!transforms) {
          return true
        }
        transforms.forEach((t) => {
          t(ex, addedExtensions)
          if (t.replace) {
            replace = true
          }
        })
        return !replace
      })

      return filtered
    }

    let additions = manifest.extensions || []
    let extensions = []

    while (additions.length) {
      let newAdditions = []

      additions = performTransforms(additions, newAdditions)
      additions.forEach((ex) => {
        extensions.push(ex)
      })
      additions = newAdditions

    }
  }

  provisionAPI (registry) {
    let plugin = this,
        manifest = this._manifest,
        api = plugin.api

    // We should now set about constructing the api object
    // so it is ready to go when start creating objects which
    // need access to a fully operational api object.

    // so: permissions, extensionPoints, singletons, extensions

    // `permissions` is asking for access by this plugin
    /*
      {
        permissions: ['prefs']
      }
     */
    plugin.grantPermissions(registry, manifest.permissions)

    // `extensionPoints`: these need to be done before
    {
      let accessibleEPs = api.extensionPoints || {}
      _.each(manifest.extensionPoints, (i, epID) => {
        if (epID.indexOf('internal.') === 0) {
          console.warn('Plugin ' + plugin.name + ' has trying to consume a private extension point: ' + epID)
          return
        }
        let ep = registry.getExtensionPoint(epID)
        let config = manifest.extensionPoints[epID]
        config = _.defaults(config, EP_CONFIG_DEFAULTS)

        // TODO What if more than one plugin wants to use the extension point
        ep.key = config.key
        ep.lazy = config.lazy
        ep.description = config.description

        // This is where the extension point is attached to the plugin object.
        // Current implementation is that we do nothing special with property
        // It's difficult to accidentally share plugins.
        accessibleEPs[epID] = ep
      })
      api.extensionPoints = accessibleEPs
    }

    {
      let singletons = manifest.singletons
      if (_.isObject(singletons)) {
        // Automatically grant permission to access singletons that the
        // plugin registers.
        plugin.grantPermissions(registry, Object.keys(singletons))
      }
    }
  }

  populateSingletons (registry) {
    // `singletons` are objects that this plugin defines
    // and made available to other plugins as permissions
    /*
      {
        singletons: {
          prefs: './lib/app-writeable-files',
          samePrefs: {
            object: './lib/app-writeable-files'
          }
        }
      }
     */
    let plugin = this
    let manifest = plugin._manifest
    let singletons = manifest.singletons
    if (_.isObject(singletons)) {
      _.each(manifest.singletons, (i, id) => {
        let singleton = manifest.singletons[id]
        singleton._id = id
        plugin.register(registry, EP.SINGLETONS, singleton)
      })
    }
  }

  distributeExtensions (registry) {
    let plugin = this
    let manifest = plugin._manifest

    // `extensions`: normalized to an array of objects, with the epID filled in.
      _.each(manifest.extensions, (ex) => {
        let epID = ex.epID
        if (!epID) {
          console.warn('Plugin ' + plugin.name + ' has an extension with no epID')
        } else if (epID.indexOf('internal.') === 0) {
          console.warn('Plugin ' + plugin.name + ' has trying to contribute to a private extension point: ' + epID)
        } else {
          plugin.register(registry, ex.epID, ex)
        }
      })

  }

  register (registry, epID, obj) {
    obj = this._preTreatExtension(obj)
    // TODO what to do about lazy loading?
    obj = this.inflate(obj)
    registry.register(epID, obj)
    obj.__epID = epID
    this._extensions.push(obj)
  }

  grantPermissions (registry, permissions) {
    let ep = registry.getExtensionPoint(EP.SINGLETONS)
    ep.key = '_id'
    let api = this.api
    _.each(permissions, (p) => {
      if (Object.getOwnPropertyDescriptor(api, p)) {
        // Stops the same plugin asking for the same permission more
        // than once.
        return
      }
      Object.defineProperty(api, p, {
        get: function () {
          let obj = ep.object[p]
          if (obj) {
            return obj
          }
          throw new Error('Permission ' + p + ' is granted but no singleton of that name is registered')
        }
      })
    })
  }

  _preTreatExtension (obj) {
    return _.mapObject(obj, (value, key) => {
      // This forces extension developers to be clear that other
      // plugins have access to the values in the manifest.
      if (typeof value === 'string') {
        return value.replace(/\b__dirname\b/, this.location)
      } else {
        return value
      }
    })
  }

  unload (registry) {
    // Unregister all the extensions we've previously registered.
    _.each(this._extensions, (obj) => {
      let epID = obj.__epID
      registry.unregister(epID, obj)
    })

    let doUnload
    if (this.isStarted) {
      let pluginBase = require(this.location)
      if (_.isFunction(pluginBase.unload)) {
        // Good fences in unload().
        try {
          let result = pluginBase.unload()
          doUnload = Promise.resolve(result)
            .catch((e) => {
              console.error('Error calling ' + this.name + '.unload():', e.message)
              throw e
            })
        } catch (e) {
          doUnload = Promise.reject(e)
        }
      }
    }

    if (!doUnload) {
      doUnload = Promise.resolve()
    }

    let unlistenExtensionPoints = () => {
      _.values(this.api.extensionPoints)
       .forEach((ep) => {
        ep._emitter.removeAllListeners()
       })
    }

    let deleteRequireCache = () => {
      // Now, delete all the Javascript from the require.cache.
      // When we load the plugin again, we will
      let requiredPaths = _.keys(require.cache)
      let location = this.location
      _.each(requiredPaths, (modulePath) => {
        if (modulePath.indexOf(location) === 0) {
          delete require.cache[modulePath]
        }
      })
      return this
    }

    return doUnload
      .then(unlistenExtensionPoints)
      .then(deleteRequireCache)
  }

  _loadPluginJavascript (extPath) {
    let plugin = this
    // the extension path is of a form
    // ./relative/module!aProperty
    let cache = plugin._extensionCache

    let moduleName, propertyNames
    {
      let segs = extPath.split('!')
      moduleName = segs.shift()
      propertyNames = segs.length ? segs.join('.').split('.') : []
    }

    if (_.isEmpty(plugin._modules)) {
      plugin.start()
    }

    let moduleExports = plugin._modules[moduleName]
    if (!moduleExports) {
      // Load the extension's module.
      // It is guaranteed* that the require('..') will have the plugin api
      // on it by the time we get to here.
      // * excepting sabotage, it's not secure.
      let modulePath = (moduleName[0] === '.')
        ? path.join(plugin.location, moduleName)
        : moduleName

      try {
        moduleExports = require(modulePath)
        plugin._modules[moduleName] = moduleExports
      } catch (e) {
        console.error(e.stack)
        throw new Error('Error loading ' + modulePath + ': ' + (e.message || e))
      }
    }

    // prop_ is our final result.
    // this_ is the context where we search for the next prop_
    let this_ = null,
        prop_ = moduleExports

    {
      let thisPath = moduleName,
          propertyPath

      for (let propertyName of propertyNames) {
        if (!propertyName) {
          // This is to stop '..' oddities.
          // but also fixes a bug with the join/split leaving empty strings
          continue
        }
        this_ =  prop_

        if (!propertyPath) {
          propertyPath = moduleName + '!' + propertyName
        } else {
          propertyPath += '.' + propertyName
        }

        // Now we know what we're going to call it, let's find it.
        let cached = cache[propertyPath]
        if (cached !== undefined) {
          // We don't cache aggressively, but we check here if
          // we need to do any more work.
          prop_ = cached.object
        } else {
          // We can try to navigate to this property.
          prop_ = this_[propertyName]
        }

        if (prop_ === undefined && _.isFunction(this_)) {
          // So we have an function Ctor, which didn't have the asked for property, method
          // e.g. Ctor.method
          // Here we assume that Ctor is a constructor, and so go ahead and create an object
          // with it. Then look again to see if the property exists (i.e. on the prototype)
          this_ = this._createObject(this_, thisPath)
          prop_ = this_[propertyName]
          if (prop_ !== undefined) {
            // Now we can cache the instance of the constructor
            // so the class is effectively a singleton.
            cache[thisPath] = {
              context: null,
              object: this_,
            }
          }
        }

        if (prop_ === undefined) {
          throw new Error('Cannot find ' + propertyName + ' in ' + thisPath + ' (in ' + extPath + ')')
        }

        thisPath = propertyPath
      }
    }

    cache[extPath] = {
      context: this_,
      object: prop_
    }

    return cache[extPath]
  }

  _createObject (Constructor, errorPath) {
    try {
      return new (Function.prototype.bind.call(Constructor))
    } catch (e) {
      console.error('Error loading ' + errorPath, e.stack)
    }
  }

  inflate (extension) {
    let plugin = this
    // We're expecting extensions to look like
    /*
    {
      "function": "./path/to/module!aFunction"
      "object": "./path/to/module!Ctor"
    }
     */
    let extType, extPath
    {
      for (let t of ['function', 'object']) {
        if (extension[t]) {
          extType = t
          extPath = extension[t]
        }
      }
    }

    if (!extType) {
      // The extension is neither a function nor an object.
      // We should just give it back.
      return extension
    }

    let codeObject = this._loadPluginJavascript(extPath)

    let returnValue = codeObject.object,
        context = codeObject.context
    switch (extType) {
      case 'object':
        if (_.isFunction(returnValue)) {
          codeObject.object = returnValue = this._createObject(returnValue, extPath)
          codeObject.context = context = undefined
        }
        break;
      case 'function':
        if (_.isFunction(returnValue) && context) {
          codeObject.object = returnValue = returnValue.bind(codeObject.context)
          codeObject.context = context = undefined
        }
        break
      default:
        if (_.isFunction(returnValue)) {
          console.warn('Cannot tell if ' + extPath + ' is a constructor or a function. Assuming a function.')
        }
    }

    if (_.isObject(returnValue) && _.isObject(extension)) {
      _.extend(returnValue, extension)
    }

    return returnValue
  }
}

class PluginAPI {
  constructor (name) {
    this.name = name
  }
}

module.exports = {Plugin, PluginAPI}
<|endoftext|>


<commit_before>module.exports = {
    add: add,
    get: get,
    isSupported: isSupported
};

var rules = {};

// Functions should return the string to be appended to a key to find the pluralized
// form for the count given.
function add(lng, fn) {
    fn.memo = [];
    rules[lng] = function(count) {
        return fn.memo[count] || (fn.memo[count] = fn(count));
    }
}

function get(lng, count) {
    return rules[lng](count);
}

function isSupported(lng) {
    return !!rules[lng];
}

// English and Japanese are added as demonstrations, but you can add your own rules.
// Find more rules at http://translate.sourceforge.net/wiki/l10n/pluralforms
add("en", function(n) { return n != 1 ? "_plural" : ""; });
add("ja", function(n) { return ""; });
<commit_msg>Check before calling a function<commit_after>module.exports = {
    add: add,
    get: get,
    isSupported: isSupported
};

var rules = {};

// Functions should return the string to be appended to a key to find the pluralized
// form for the count given.
function add(lng, fn) {
    fn.memo = [];
    rules[lng] = function(count) {
        return fn.memo[count] || (fn.memo[count] = fn(count));
    }
}

function get(lng, count) {
    return rules[lng] && rules[lng](count);
}

function isSupported(lng) {
    return !!rules[lng];
}

// English and Japanese are added as demonstrations, but you can add your own rules.
// Find more rules at http://translate.sourceforge.net/wiki/l10n/pluralforms
add("en", function(n) { return n != 1 ? "_plural" : ""; });
add("ja", function(n) { return ""; });
<|endoftext|>


<commit_before>const yelp = require('yelp-fusion');
// const ApiSecrets = require('./apisecrets.js');
// const token = ApiSecrets.yelpToken;

let getRestaurantsFromYelp = function(userPref, callback) {
  const id = 1; //hardcoded id for 1st user in the database
  const location = userPref[0].location ? userPref[0].location : 94105;
  const preferences = userPref[0].preferences ? userPref[0].preferences : 'italian, mexican';
  const client = yelp.client(token);

  client.search({
    location: location,
    term: preferences
  }).then(response => {
    let allResults = response.jsonBody.businesses;
    callback(null, allResults);
  }).catch(e => {
    callback(e, null);
  });
};

module.exports.getRestaurantsFromYelp = getRestaurantsFromYelp;<commit_msg>"merging apicall.js"<commit_after>const yelp = require('yelp-fusion');
// const ApiSecrets = require('./apisecrets.js');
// const token = ApiSecrets.yelpToken;

let getRestaurantsFromYelp = function(userPref, callback) {
  const id = 1; //hardcoded id for 1st user in the database
  const location = userPref[0].location ? userPref[0].location : 94105;
  const preferences = userPref[0].preferences ? userPref[0].preferences : 'italian, mexican';
  const client = yelp.client(process.env.token);

  client.search({
    location: location,
    term: preferences
  }).then(response => {
    let allResults = response.jsonBody.businesses;
    callback(null, allResults);
  }).catch(e => {
    callback(e, null);
  });
};

module.exports.getRestaurantsFromYelp = getRestaurantsFromYelp;<|endoftext|>


<commit_before>var exec = require('child_process').exec;
var fs = require('fs');
var path = require('path');
var settings = require('./settings');

var packages;
var currentPackageIndex = 0;
var original_cwd = process.cwd();
var outDir = path.join(original_cwd, settings.get('outputDir'), settings.get('apksDir'));

console.log('apk-bck out dir=' + outDir);

if(!fs.existsSync(outDir)) {
    fs.mkdirSync(outDir);
}

process.chdir(outDir);

exec('adb shell pm list packages', function(error, stdout, stderr) {

    if(error) {
        var errorMsg = error.toString();
        console.error(errorMsg);
        if(errorMsg.search('device not found')) {
            console.log('>>> hint hint: IS THE DEVICE CONNECTED TO THE COMPUTER?');
        }
    } else {

        packages = stdout.split('\r\n');
        processNext();

    }

});

function processNext() {
    var pk = packages[currentPackageIndex];
    currentPackageIndex++;

    var f = pk.replace('package:', '');
    f = f + '-1.apk';

    console.log(f);

    if(fs.existsSync(f)) {

        console.log('\t=> already exists');
        nextStep();

    } else {

        exec('adb pull /data/app/' + f, function(er, sout, serr) {
            nextStep();
        });

    }
}

function nextStep() {
    if(currentPackageIndex < packages.length) {
        process.nextTick(processNext);
    } else {
        finish();
    }
}

function finish() {
    console.log('done');
    exec('cd ' + original_cwd);
}

<commit_msg>trim-avoid processing empty lines :P<commit_after>var exec = require('child_process').exec;
var fs = require('fs');
var path = require('path');
var settings = require('./settings');

var packages;
var currentPackageIndex = 0;
var original_cwd = process.cwd();
var outDir = path.join(original_cwd, settings.get('outputDir'), settings.get('apksDir'));

console.log('apk-bck out dir=' + outDir);

if(!fs.existsSync(outDir)) {
    fs.mkdirSync(outDir);
}

process.chdir(outDir);

exec('adb shell pm list packages', function(error, stdout, stderr) {

    if(error) {
        var errorMsg = error.toString();
        console.error(errorMsg);
        if(errorMsg.search('device not found')) {
            console.log('>>> hint hint: IS THE DEVICE CONNECTED TO THE COMPUTER?');
        }
    } else {

        packages = stdout.trim().split('\r\n');
        processNext();

    }

});

function processNext() {
    var pk = packages[currentPackageIndex];
    currentPackageIndex++;

    var f = pk.replace('package:', '');
    f = f + '-1.apk';

    console.log(f);

    if(fs.existsSync(f)) {

        console.log('\t=> already exists');
        nextStep();

    } else {

        exec('adb pull /data/app/' + f, function(er, sout, serr) {
            nextStep();
        });

    }
}

function nextStep() {
    if(currentPackageIndex < packages.length) {
        process.nextTick(processNext);
    } else {
        finish();
    }
}

function finish() {
    console.log('done');
    exec('cd ' + original_cwd);
}

<|endoftext|>


<commit_before>var TradeOfferManager = require('./index.js');
var ETradeOfferState = TradeOfferManager.ETradeOfferState;
var EOfferFilter = TradeOfferManager.EOfferFilter;
var deepEqual = require('deep-equal');
var clone = require('clone');

TradeOfferManager.prototype.doPoll = function() {
	if(Date.now() - this._lastPoll < 1000) {
		// We last polled less than a second ago, don't spam the API
		// Reset the timer to poll one second after the last one
		this._resetPollTimer(Date.now() - this._lastPoll);
		return;
	}

	this._lastPoll = Date.now();
	clearTimeout(this._pollTimer);

	var offersSince = 0;
	if(this.pollData.offersSince) {
		// It looks like sometimes Steam can be dumb and backdate a modified offer. We need to handle this.
		// Let's add a 5-minute buffer.
		offersSince = this.pollData.offersSince - 300;
	}

	this.emit('debug', 'Doing trade offer poll since ' + offersSince);
	this.getOffers(EOfferFilter.ActiveOnly, new Date(offersSince * 1000), function(err, sent, received) {
		if(err) {
			this.emit('debug', "Error getting trade offers for poll: " + err.message);
			this.emit('pollFailure', err);
			this._resetPollTimer();
			return;
		}

		var origPollData = clone(this.pollData);

		var offers = this.pollData.sent || {};

		sent.forEach(function(offer) {
			if(offers[offer.id] && offer.state != offers[offer.id]) {
				this.emit('sentOfferChanged', offer, offers[offer.id]);
				offers[offer.id] = offer.state;
			} else if(this.cancelTime && offer.state == ETradeOfferState.Active && (Date.now() - offer.created.getTime() >= this.cancelTime)) {
				offer.cancel(function(err) {
					if(!err) {
						this.emit('sentOfferCanceled', offer);
					}
				}.bind(this));
			}

			offers[offer.id] = offer.state;
		}.bind(this));

		this.pollData.sent = offers;
		offers = this.pollData.received || {};

		received.forEach(function(offer) {
			if(!offers[offer.id] && offer.state == ETradeOfferState.Active) {
				this.emit('newOffer', offer);
			} else if(offers[offer.id] && offer.state != offers[offer.id]) {
				this.emit('receivedOfferChanged', offer, offers[offer.id]);
			}

			offers[offer.id] = offer.state;
		}.bind(this));

		this.pollData.received = offers;

		// Find the latest update time
		var latest = this.pollData.offersSince || 0;
		sent.concat(received).forEach(function(offer) {
			var updated = Math.floor(offer.updated.getTime() / 1000);
			if(updated > latest) {
				latest = updated;
			}
		});

		this.pollData.offersSince = latest;

		// Check if any offers which we want to accept are still Active
		if(this.pollData.toAccept) {
			var offer, offerID, lastAttempt;
			for(offerID in this.pollData.toAccept) {
				offer = received.filter(function(item) {
					return item.id == offerID;
				});

				if(!offer[0] || offer[0].state != ETradeOfferState.Active) {
					// It's no longer active, so we're done here
					delete this.pollData.toAccept[offerID];
					continue;
				}

				if(Date.now() - this.pollData.toAccept[offerID] > 60000) {
					// We last tried to accept this offer over a minute ago. Try again.
					this.pollData.toAccept[offerID] = Date.now();
					offer[0].accept();
				}
			}
		}

		this.emit('pollSuccess');

		// If something has changed, emit the event
		if(!deepEqual(origPollData, this.pollData)) {
			this.emit('pollData', this.pollData);
		}

		this._resetPollTimer();
	}.bind(this));
};

TradeOfferManager.prototype._resetPollTimer = function(time) {
	if(time || this.pollInterval >= 1000) {
		clearTimeout(this._pollTimer);
		this._pollTimer = setTimeout(this.doPoll.bind(this), time || this.pollInterval);
	}
};
<commit_msg>Added a debug log statement<commit_after>var TradeOfferManager = require('./index.js');
var ETradeOfferState = TradeOfferManager.ETradeOfferState;
var EOfferFilter = TradeOfferManager.EOfferFilter;
var deepEqual = require('deep-equal');
var clone = require('clone');

TradeOfferManager.prototype.doPoll = function() {
	if(Date.now() - this._lastPoll < 1000) {
		// We last polled less than a second ago, don't spam the API
		// Reset the timer to poll one second after the last one
		this._resetPollTimer(Date.now() - this._lastPoll);
		return;
	}

	this._lastPoll = Date.now();
	clearTimeout(this._pollTimer);

	var offersSince = 0;
	if(this.pollData.offersSince) {
		// It looks like sometimes Steam can be dumb and backdate a modified offer. We need to handle this.
		// Let's add a 5-minute buffer.
		offersSince = this.pollData.offersSince - 300;
	}

	this.emit('debug', 'Doing trade offer poll since ' + offersSince);
	this.getOffers(EOfferFilter.ActiveOnly, new Date(offersSince * 1000), function(err, sent, received) {
		if(err) {
			this.emit('debug', "Error getting trade offers for poll: " + err.message);
			this.emit('pollFailure', err);
			this._resetPollTimer();
			return;
		}

		var origPollData = clone(this.pollData);

		var offers = this.pollData.sent || {};

		sent.forEach(function(offer) {
			if(offers[offer.id] && offer.state != offers[offer.id]) {
				this.emit('sentOfferChanged', offer, offers[offer.id]);
				offers[offer.id] = offer.state;
			} else if(this.cancelTime && offer.state == ETradeOfferState.Active && (Date.now() - offer.created.getTime() >= this.cancelTime)) {
				offer.cancel(function(err) {
					if(!err) {
						this.emit('sentOfferCanceled', offer);
					}
				}.bind(this));
			}

			offers[offer.id] = offer.state;
		}.bind(this));

		this.pollData.sent = offers;
		offers = this.pollData.received || {};

		received.forEach(function(offer) {
			if(!offers[offer.id] && offer.state == ETradeOfferState.Active) {
				this.emit('newOffer', offer);
			} else if(offers[offer.id] && offer.state != offers[offer.id]) {
				this.emit('receivedOfferChanged', offer, offers[offer.id]);
			}

			offers[offer.id] = offer.state;
		}.bind(this));

		this.pollData.received = offers;

		// Find the latest update time
		var latest = this.pollData.offersSince || 0;
		sent.concat(received).forEach(function(offer) {
			var updated = Math.floor(offer.updated.getTime() / 1000);
			if(updated > latest) {
				latest = updated;
			}
		});

		this.pollData.offersSince = latest;
		this.emit('debug', 'Latest offer modification time is ' + latest);

		// Check if any offers which we want to accept are still Active
		if(this.pollData.toAccept) {
			var offer, offerID, lastAttempt;
			for(offerID in this.pollData.toAccept) {
				offer = received.filter(function(item) {
					return item.id == offerID;
				});

				if(!offer[0] || offer[0].state != ETradeOfferState.Active) {
					// It's no longer active, so we're done here
					delete this.pollData.toAccept[offerID];
					continue;
				}

				if(Date.now() - this.pollData.toAccept[offerID] > 60000) {
					// We last tried to accept this offer over a minute ago. Try again.
					this.pollData.toAccept[offerID] = Date.now();
					offer[0].accept();
				}
			}
		}

		this.emit('pollSuccess');

		// If something has changed, emit the event
		if(!deepEqual(origPollData, this.pollData)) {
			this.emit('pollData', this.pollData);
		}

		this._resetPollTimer();
	}.bind(this));
};

TradeOfferManager.prototype._resetPollTimer = function(time) {
	if(time || this.pollInterval >= 1000) {
		clearTimeout(this._pollTimer);
		this._pollTimer = setTimeout(this.doPoll.bind(this), time || this.pollInterval);
	}
};
<|endoftext|>


<commit_before>var async = require('async');
var path = require('path');
var fs = require('fs');
var stream = require('stream');

var walk = require('walk');

var ignored = [
  '.git',
  '.npm',
  '.tmp',
  'node_modules'
];

var assetPreparerImage = "quay.io/deconst/preparer-asset";

exports.recursivelyPrepare = function (toolbelt, callback) {
  walker = walk.walk(toolbelt.workspacePath(), {
    followLinks: false
  });

  walker.on('directories', function (root, stats, cb) {
    toolbelt.debug("Traversing directories within: %s", root);

    // Don't traverse into dot or common build directories.
    for (var i = stats.length; i--; i >= 0) {
      var name = stats[i].name;
      if (ignored.indexOf(name) !== -1) {
        stats.splice(i, 1);
      }
    }

    cb();
  });

  walker.on('files', function (root, stats, cb) {
    var hasPackageJson = stats.some(function (each) {
      return each.name === 'package.json';
    });

    if (!hasPackageJson) return cb(null);

    var fullPath = path.join(root, 'package.json');

    fs.readFile(fullPath, { encoding: 'utf-8' }, function (err, contents) {
      var pkgInfo;
      try {
        pkg = JSON.parse(contents);
      } catch (e) {
        toolbelt.error("%s contains invalid JSON: %s", fullPath, e.message);
        return cb(null);
      }

      if (! pkg.scripts || ! pkg.scripts['deconst-control-build']) {
        toolbelt.debug("%s does not contain a deconst-control-build entry point.", fullPath);
        return cb(null);
      }

      toolbelt.info("Submitting assets found at %s.", root);
      prepare(toolbelt, root, cb);
    });
  });

  walker.on('errors', function (root, stats, cb) {
    toolbelt.error("Error walking %s.", root, stats.map(function (each) {
      return each.error;
    }));

    cb(null);
  });

  walker.on('end', function () {
    toolbelt.info('All assets from repository uploaded.');

    callback(null);
  });
};

var prepare = function (toolbelt, root, callback) {
  var transientKey = null;
  var status = null;

  var contentService = toolbelt.contentService;
  var docker = toolbelt.docker;

  var issueAPIKey = function (cb) {
    toolbelt.debug('Issuing temporary API key.');

    contentService.issueAPIKey('strider-auto-control', function (err, key) {
      if (err) return cb(err);

      transientKey = key;
      cb(null);
    })
  };

  var runAssetPreparer = function (cb) {
    var env = [
      "CONTENT_STORE_URL=" + toolbelt.config.contentServiceURL,
      "CONTENT_STORE_APIKEY=" + transientKey,
      "TRAVIS_PULL_REQUEST=false"
    ];

    if (toolbelt.config.contentServiceTLSVerify === false) {
      env.push("NODE_TLS_REJECT_UNAUTHORIZED=0");
    }

    var params = {
      Image: assetPreparerImage,
      Env: env,
      mountWorkspaceRoot: root
    };

    docker.runContainer(params, function (err, result) {
      if (err) return cb(err);
      status = result.status;
      cb(null);
    });
  };

  var revokeAPIKey = function (cb) {
    contentService.revokeAPIKey(transientKey, cb);
  };

  async.series([
    issueAPIKey,
    runAssetPreparer,
    revokeAPIKey
  ], function (err) {
    if (err) {
      toolbelt.error("Error running the asset preparer.", err);
      return callback(err, false);
    }

    toolbelt.info("Asset preparer completed.", { status: status });

    callback(null, status === 0);
  });
};
<commit_msg>Use the workspace mount controls.<commit_after>var async = require('async');
var path = require('path');
var fs = require('fs');
var stream = require('stream');

var walk = require('walk');

var ignored = [
  '.git',
  '.npm',
  '.tmp',
  'node_modules'
];

var assetPreparerImage = "quay.io/deconst/preparer-asset";

exports.recursivelyPrepare = function (toolbelt, callback) {
  walker = walk.walk(toolbelt.workspacePath(), {
    followLinks: false
  });

  walker.on('directories', function (root, stats, cb) {
    toolbelt.debug("Traversing directories within: %s", root);

    // Don't traverse into dot or common build directories.
    for (var i = stats.length; i--; i >= 0) {
      var name = stats[i].name;
      if (ignored.indexOf(name) !== -1) {
        stats.splice(i, 1);
      }
    }

    cb();
  });

  walker.on('files', function (root, stats, cb) {
    var hasPackageJson = stats.some(function (each) {
      return each.name === 'package.json';
    });

    if (!hasPackageJson) return cb(null);

    var fullPath = path.join(root, 'package.json');

    fs.readFile(fullPath, { encoding: 'utf-8' }, function (err, contents) {
      var pkgInfo;
      try {
        pkg = JSON.parse(contents);
      } catch (e) {
        toolbelt.error("%s contains invalid JSON: %s", fullPath, e.message);
        return cb(null);
      }

      if (! pkg.scripts || ! pkg.scripts['deconst-control-build']) {
        toolbelt.debug("%s does not contain a deconst-control-build entry point.", fullPath);
        return cb(null);
      }

      toolbelt.info("Submitting assets found at %s.", root);
      prepare(toolbelt, root, cb);
    });
  });

  walker.on('errors', function (root, stats, cb) {
    toolbelt.error("Error walking %s.", root, stats.map(function (each) {
      return each.error;
    }));

    cb(null);
  });

  walker.on('end', function () {
    toolbelt.info('All assets from repository uploaded.');

    callback(null);
  });
};

var prepare = function (toolbelt, root, callback) {
  var transientKey = null;
  var status = null;

  var contentService = toolbelt.contentService;
  var docker = toolbelt.docker;

  var issueAPIKey = function (cb) {
    toolbelt.debug('Issuing temporary API key.');

    contentService.issueAPIKey('strider-auto-control', function (err, key) {
      if (err) return cb(err);

      transientKey = key;
      cb(null);
    })
  };

  var runAssetPreparer = function (cb) {
    var env = [
      "CONTENT_STORE_URL=" + toolbelt.config.contentServiceURL,
      "CONTENT_STORE_APIKEY=" + transientKey,
      "TRAVIS_PULL_REQUEST=false"
    ];

    if (toolbelt.config.contentServiceTLSVerify === false) {
      env.push("NODE_TLS_REJECT_UNAUTHORIZED=0");
    }

    var params = {
      Image: assetPreparerImage,
      Env: env,
      workspace: {
        root: root,
        rootEnvVar: 'CONTROL_ROOT',
        containerRoot: '/var/control-repo'
      }
    };

    docker.runContainer(params, function (err, result) {
      if (err) return cb(err);
      status = result.status;
      cb(null);
    });
  };

  var revokeAPIKey = function (cb) {
    contentService.revokeAPIKey(transientKey, cb);
  };

  async.series([
    issueAPIKey,
    runAssetPreparer,
    revokeAPIKey
  ], function (err) {
    if (err) {
      toolbelt.error("Error running the asset preparer.", err);
      return callback(err, false);
    }

    toolbelt.info("Asset preparer completed.", { status: status });

    callback(null, status === 0);
  });
};
<|endoftext|>


<commit_before>"use strict";

const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;

function dumpln(s) { dump(s + "\n"); }

// content script for e10s support

// This is a frame script, so it may be running in a content process.
// In any event, it is targeted at a specific "tab", so we listen for
// the DOMWindowCreated event to be notified about content windows
// being created in this context.

function DOMFuzzHelperManager() {
  addEventListener("DOMWindowCreated", this, false);
}

DOMFuzzHelperManager.prototype = {
  handleEvent: function handleEvent(aEvent) {
    var window = aEvent.target.defaultView;
    window.wrappedJSObject.fuzzPriv = makeDOMFuzzHelper(window);
    window.addEventListener("load", maybeInjectScript, false);
  }
};

var domfuzzhelpermanager = new DOMFuzzHelperManager();

/*****************************
 * FUZZPRIV OBJECT INJECTION *
 *****************************/

// Create deeply fresh objects so windows don't influence each other.

function makeDOMFuzzHelper(aWindow) {
  dumpln("DOMFuzzHelper created");

  return {
      toString: function() { return "[DOMFuzzHelper]"; },

      quitApplication: function() {
        sendAsyncMessage('DOMFuzzHelper.quitApplication', {});
      },

      quitApplicationSoon: function() {
        sendAsyncMessage('DOMFuzzHelper.quitApplicationSoon', {});
      },

      closeTabThenQuit: function () {
        // Somehow async messages get lost in close().
        sendSyncMessage('DOMFuzzHelper.quitApplicationSoon', {});

        // This frame-script stops running immediately after close().
        content.close();
      },

      quitWithLeakCheck: function () {
        sendAsyncMessage('DOMFuzzHelper.quitWithLeakCheck', {});
      },

      setGCZeal: function(zeal) {
        sendSyncMessage("DOMFuzzHelper.setGCZeal", {'zeal' : zeal});
      },

      runSoon: runSoon.bind(this),

      enableAccessibility: enableAccessibility.bind(this),

      GC: function() { Cu.forceGC(); },

      CC: cycleCollect(aWindow),

      MP: sendMemoryPressureNotification.bind(this),

      fontList: fontList.bind(this),

      reftestList: reftestList.bind(this),

      printToFile: printToFile(aWindow),

      openAboutMemory: function() {
        content.open("about:memory");
      },

      __exposedProps__: {
        'toString': 'r',
        'quitApplication': 'r',
        'quitApplicationSoon': 'r',
        'closeTabThenQuit': 'r',
        'quitWithLeakCheck': 'r',
        'setGCZeal': 'r',
        'runSoon': 'r',
        'enableAccessibility': 'r',
        'GC': 'r',
        'CC': 'r',
        'MP': 'r',
        'fontList': 'r',
        'printToFile': 'r',
        'openAboutMemory': 'r',
        'reftestList': 'r'
      }
  };
};

/***********************************************
 * MISC PRIVILEGED FUNCTIONS - CONTENT PROCESS *
 ***********************************************/

function runSoon(f)
{
  var tm = Cc["@mozilla.org/thread-manager;1"]
             .getService(Ci.nsIThreadManager);

  tm.mainThread.dispatch({
    run: function() {
      f();
    }
  }, Ci.nsIThread.DISPATCH_NORMAL);
}

function enableAccessibility()
{
  try {
    Components.classes["@mozilla.org/accessibilityService;1"]
      .getService(Components.interfaces.nsIAccessibleRetrieval);
    dump("Enabled accessibility!\n");
  } catch(e) {
    dump("Couldn't enable accessibility: " + e + "\n");
  }
}

function sendMemoryPressureNotification()
{
  var os = Components.classes["@mozilla.org/observer-service;1"]
           .getService(Components.interfaces.nsIObserverService);
  os.notifyObservers(null, "memory-pressure", "heap-minimize");
}

function cycleCollect(window)
{
  return function cycleCollectInner() {
    window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
          .getInterface(Components.interfaces.nsIDOMWindowUtils)
          .cycleCollect();
  }
}

/*
function setZoomLevel(window)
{
  return function setZoomLevelInner(textOrFull, factor) {
    var viewer = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                       .getInterface(Components.interfaces.nsIWebNavigation)
                       .QueryInterface(Components.interfaces.nsIDocShell)
                       .contentViewer
                       .QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);

    if (textOrFull == "text")
      viewer.textZoom = +factor;
    else if (textOrFull == "full")
      viewer.fullZoom = +factor;
  }
}
*/

function printToFile(window)
{
  // Oddly asynchronous, at least on Linux.

  // Linux: works for PDF and PS.
  // Windows: works for PDF at least. Text may be invisible (bug 653336).
  // Mac: tested, printToFile is ignored and it goes to a printer!
  var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
                             .getService(Components.interfaces.nsIXULRuntime);
  dumpln("xulRuntime.OS: " + xulRuntime.OS);
  if (xulRuntime.OS != "Linux" && xulRuntime.OS != "WINNT") return function() { };

  var fired = false;

  return function printToFileInner(showHeaders, showBGColor, showBGImages, ps) {
    runSoon(function() {
        // Don't print more than once, it gets messy fast.
        if (fired) { return false; }
        fired = true;

        // Based on https://addons.mozilla.org/en-US/firefox/addon/5971/ by pavlov (Stuart Parmenter) and bho

        var webBrowserPrint = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
        .getInterface(Components.interfaces.nsIWebBrowserPrint);

        var nsIPrintSettings = Components.interfaces.nsIPrintSettings;

        var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
        .getService(Components.interfaces.nsIPrintSettingsService);

        var printSettings = PSSVC.newPrintSettings;

        var file = profileDirectory();
        file.append(ps ? "fuzzout.ps" : "fuzzout.pdf");
        dumpln("Printing to: " + file.path);

        printSettings.printToFile = true;
        printSettings.toFileName  = file.path;
        printSettings.printSilent = true;
        printSettings.outputFormat = ps ? nsIPrintSettings.kOutputFormatPS : nsIPrintSettings.kOutputFormatPDF;
        printSettings.printBGColors   = !!showBGColor;
        printSettings.printBGImages   = !!showBGImages;
        if (!showHeaders) {
            printSettings.footerStrCenter = '';
            printSettings.footerStrLeft   = '';
            printSettings.footerStrRight  = '';
            printSettings.headerStrCenter = '';
            printSettings.headerStrLeft   = '';
            printSettings.headerStrRight  = '';
        }

        webBrowserPrint.print(printSettings, null);
    });
  }
}

function cycleCollect()
{
  return function cycleCollectInner() {
      try {
        content.QueryInterface(Ci.nsIInterfaceRequestor)
              .getInterface(Ci.nsIDOMWindowUtils)
              .cycleCollect();
      }

      catch(e) {
        dumpln("cycle collect failed " + e);
      }
  }
}

function fontList()
{
    return Components.classes["@mozilla.org/gfx/fontenumerator;1"]
            .createInstance(Components.interfaces.nsIFontEnumerator)
            .EnumerateAllFonts({})
            .join("\n");
}

function reftestList()
{
  var dir = extensionLocation().parent;
  dir.append("automation");
  return readFile(indir(dir, "urls-reftests"));
}

/**********************
 * FILESYSTEM HELPERS *
 **********************/

function profileDirectory()
{
  var fn = sendSyncMessage('DOMFuzzHelper.getProfileDirectory', {})[0];
  var d = Components.classes["@mozilla.org/file/local;1"]
                    .createInstance(Components.interfaces.nsILocalFile);
  d.initWithPath(fn);
  return d;
}

function extensionLocation()
{
  var d = profileDirectory();
  d.append("extensions");
  d.append("domfuzz@squarefree.com");

  var extensionLocation = readFile(d).replace(/\s*$/, "");

  var f = Components.classes["@mozilla.org/file/local;1"]
                    .createInstance(Components.interfaces.nsILocalFile);
  f.initWithPath(extensionLocation);
  return f;
}

// readFile function from logan
// http://www.gozer.org/mozilla/userChrome.js/scripts/userScripts.uc.js
// |file| must be an nsIFile.
// Returns the contents of the file as a string.
function readFile(file)
{
  var content = '';

  var stream = Components.classes['@mozilla.org/network/file-input-stream;1']
                    .createInstance(Components.interfaces.nsIFileInputStream);
  stream.init(file, 0x01, 0, 0);

  var script = Components.classes['@mozilla.org/scriptableinputstream;1']
              .createInstance(Components.interfaces.nsIScriptableInputStream);
  script.init(stream);

  if (stream.available()) {
    var data = script.read(4096);

    while (data.length > 0) {
      content += data;
      data = script.read(4096);
    }
  }

  stream.close();
  script.close();

  return content;
}

function indir(dir, filename)
{
  var d = dir.clone();
  d.append(filename);
  return d;
}

/*************************
 * FUZZ SCRIPT INJECTION *
 *************************/

function maybeInjectScript(event)
{
  var doc = event.originalTarget;
  if (doc.nodeName != "#document")
    return;

  var hash = doc.location.hash;

  var r = hash.split(",");

  if (r[0] != "#squarefree-af") {
    return;
  }
  if (!(/^[a-zA-Z0-9\-.]*$/.test(r[1]))) {
    dump("Sketchy fuzzer filename!\n");
    return;
  }

  var dir = extensionLocation().parent;
  dir.append("fuzzers");

  var scriptToInject =
    readFile(indir(dir, "fuzz.js")) + "\n"
  + readFile(indir(dir, r[1])) + "\n"
  + readFile(indir(dir, "fuzz-finish-auto.js")) + "\n"
  + "document.getElementById('fuzz1').parentNode.removeChild(document.getElementById('fuzz1'));\n"
  + "fuzzSettings = [" + r.slice(2).join(",") + "];\n"
  + "setTimeout(fuzzOnload, 400);\n";

  var insertionPoint = doc.getElementsByTagName("head")[0] || doc.documentElement;

  if (!insertionPoint)
    return;

  var script = doc.createElementNS("http://www.w3.org/1999/xhtml", "script");
  script.setAttribute("id", "fuzz1");
  script.setAttribute("type", "text/javascript");
  script.textContent = scriptToInject;
  insertionPoint.appendChild(script);
}
<commit_msg>Restore ps check<commit_after>"use strict";

const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;

function dumpln(s) { dump(s + "\n"); }

// content script for e10s support

// This is a frame script, so it may be running in a content process.
// In any event, it is targeted at a specific "tab", so we listen for
// the DOMWindowCreated event to be notified about content windows
// being created in this context.

function DOMFuzzHelperManager() {
  addEventListener("DOMWindowCreated", this, false);
}

DOMFuzzHelperManager.prototype = {
  handleEvent: function handleEvent(aEvent) {
    var window = aEvent.target.defaultView;
    window.wrappedJSObject.fuzzPriv = makeDOMFuzzHelper(window);
    window.addEventListener("load", maybeInjectScript, false);
  }
};

var domfuzzhelpermanager = new DOMFuzzHelperManager();

/*****************************
 * FUZZPRIV OBJECT INJECTION *
 *****************************/

// Create deeply fresh objects so windows don't influence each other.

function makeDOMFuzzHelper(aWindow) {
  dumpln("DOMFuzzHelper created");

  return {
      toString: function() { return "[DOMFuzzHelper]"; },

      quitApplication: function() {
        sendAsyncMessage('DOMFuzzHelper.quitApplication', {});
      },

      quitApplicationSoon: function() {
        sendAsyncMessage('DOMFuzzHelper.quitApplicationSoon', {});
      },

      closeTabThenQuit: function () {
        // Somehow async messages get lost in close().
        sendSyncMessage('DOMFuzzHelper.quitApplicationSoon', {});

        // This frame-script stops running immediately after close().
        content.close();
      },

      quitWithLeakCheck: function () {
        sendAsyncMessage('DOMFuzzHelper.quitWithLeakCheck', {});
      },

      setGCZeal: function(zeal) {
        sendSyncMessage("DOMFuzzHelper.setGCZeal", {'zeal' : zeal});
      },

      runSoon: runSoon.bind(this),

      enableAccessibility: enableAccessibility.bind(this),

      GC: function() { Cu.forceGC(); },

      CC: cycleCollect(aWindow),

      MP: sendMemoryPressureNotification.bind(this),

      fontList: fontList.bind(this),

      reftestList: reftestList.bind(this),

      printToFile: printToFile(aWindow),

      openAboutMemory: function() {
        content.open("about:memory");
      },

      __exposedProps__: {
        'toString': 'r',
        'quitApplication': 'r',
        'quitApplicationSoon': 'r',
        'closeTabThenQuit': 'r',
        'quitWithLeakCheck': 'r',
        'setGCZeal': 'r',
        'runSoon': 'r',
        'enableAccessibility': 'r',
        'GC': 'r',
        'CC': 'r',
        'MP': 'r',
        'fontList': 'r',
        'printToFile': 'r',
        'openAboutMemory': 'r',
        'reftestList': 'r'
      }
  };
};

/***********************************************
 * MISC PRIVILEGED FUNCTIONS - CONTENT PROCESS *
 ***********************************************/

function runSoon(f)
{
  var tm = Cc["@mozilla.org/thread-manager;1"]
             .getService(Ci.nsIThreadManager);

  tm.mainThread.dispatch({
    run: function() {
      f();
    }
  }, Ci.nsIThread.DISPATCH_NORMAL);
}

function enableAccessibility()
{
  try {
    Components.classes["@mozilla.org/accessibilityService;1"]
      .getService(Components.interfaces.nsIAccessibleRetrieval);
    dump("Enabled accessibility!\n");
  } catch(e) {
    dump("Couldn't enable accessibility: " + e + "\n");
  }
}

function sendMemoryPressureNotification()
{
  var os = Components.classes["@mozilla.org/observer-service;1"]
           .getService(Components.interfaces.nsIObserverService);
  os.notifyObservers(null, "memory-pressure", "heap-minimize");
}

function cycleCollect(window)
{
  return function cycleCollectInner() {
    window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
          .getInterface(Components.interfaces.nsIDOMWindowUtils)
          .cycleCollect();
  }
}

/*
function setZoomLevel(window)
{
  return function setZoomLevelInner(textOrFull, factor) {
    var viewer = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                       .getInterface(Components.interfaces.nsIWebNavigation)
                       .QueryInterface(Components.interfaces.nsIDocShell)
                       .contentViewer
                       .QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);

    if (textOrFull == "text")
      viewer.textZoom = +factor;
    else if (textOrFull == "full")
      viewer.fullZoom = +factor;
  }
}
*/

function printToFile(window)
{
  // Oddly asynchronous, at least on Linux.

  // Linux: works for PDF and PS.
  // Windows: works for PDF at least. Text may be invisible (bug 653336).
  // Mac: tested, printToFile is ignored and it goes to a printer!
  var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
                             .getService(Components.interfaces.nsIXULRuntime);
  dumpln("xulRuntime.OS: " + xulRuntime.OS);
  if (xulRuntime.OS != "Linux" && xulRuntime.OS != "WINNT") return function() { };

  var fired = false;

  return function printToFileInner(showHeaders, showBGColor, showBGImages, ps) {
    runSoon(function() {
        // Don't print more than once, it gets messy fast.
        if (fired) { return false; }
        fired = true;

        ps = ps && xulRuntime.OS != "WINNT"; // Windows gets confused when trying to print to ps, and tosses up a *.xps filepicker outside the Firefox process!?

        // Based on https://addons.mozilla.org/en-US/firefox/addon/5971/ by pavlov (Stuart Parmenter) and bho

        var webBrowserPrint = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
        .getInterface(Components.interfaces.nsIWebBrowserPrint);

        var nsIPrintSettings = Components.interfaces.nsIPrintSettings;

        var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
        .getService(Components.interfaces.nsIPrintSettingsService);

        var printSettings = PSSVC.newPrintSettings;

        var file = profileDirectory();
        file.append(ps ? "fuzzout.ps" : "fuzzout.pdf");
        dumpln("Printing to: " + file.path);

        printSettings.printToFile = true;
        printSettings.toFileName  = file.path;
        printSettings.printSilent = true;
        printSettings.outputFormat = ps ? nsIPrintSettings.kOutputFormatPS : nsIPrintSettings.kOutputFormatPDF;
        printSettings.printBGColors   = !!showBGColor;
        printSettings.printBGImages   = !!showBGImages;
        if (!showHeaders) {
            printSettings.footerStrCenter = '';
            printSettings.footerStrLeft   = '';
            printSettings.footerStrRight  = '';
            printSettings.headerStrCenter = '';
            printSettings.headerStrLeft   = '';
            printSettings.headerStrRight  = '';
        }

        webBrowserPrint.print(printSettings, null);
    });
  }
}

function cycleCollect()
{
  return function cycleCollectInner() {
      try {
        content.QueryInterface(Ci.nsIInterfaceRequestor)
              .getInterface(Ci.nsIDOMWindowUtils)
              .cycleCollect();
      }

      catch(e) {
        dumpln("cycle collect failed " + e);
      }
  }
}

function fontList()
{
    return Components.classes["@mozilla.org/gfx/fontenumerator;1"]
            .createInstance(Components.interfaces.nsIFontEnumerator)
            .EnumerateAllFonts({})
            .join("\n");
}

function reftestList()
{
  var dir = extensionLocation().parent;
  dir.append("automation");
  return readFile(indir(dir, "urls-reftests"));
}

/**********************
 * FILESYSTEM HELPERS *
 **********************/

function profileDirectory()
{
  var fn = sendSyncMessage('DOMFuzzHelper.getProfileDirectory', {})[0];
  var d = Components.classes["@mozilla.org/file/local;1"]
                    .createInstance(Components.interfaces.nsILocalFile);
  d.initWithPath(fn);
  return d;
}

function extensionLocation()
{
  var d = profileDirectory();
  d.append("extensions");
  d.append("domfuzz@squarefree.com");

  var extensionLocation = readFile(d).replace(/\s*$/, "");

  var f = Components.classes["@mozilla.org/file/local;1"]
                    .createInstance(Components.interfaces.nsILocalFile);
  f.initWithPath(extensionLocation);
  return f;
}

// readFile function from logan
// http://www.gozer.org/mozilla/userChrome.js/scripts/userScripts.uc.js
// |file| must be an nsIFile.
// Returns the contents of the file as a string.
function readFile(file)
{
  var content = '';

  var stream = Components.classes['@mozilla.org/network/file-input-stream;1']
                    .createInstance(Components.interfaces.nsIFileInputStream);
  stream.init(file, 0x01, 0, 0);

  var script = Components.classes['@mozilla.org/scriptableinputstream;1']
              .createInstance(Components.interfaces.nsIScriptableInputStream);
  script.init(stream);

  if (stream.available()) {
    var data = script.read(4096);

    while (data.length > 0) {
      content += data;
      data = script.read(4096);
    }
  }

  stream.close();
  script.close();

  return content;
}

function indir(dir, filename)
{
  var d = dir.clone();
  d.append(filename);
  return d;
}

/*************************
 * FUZZ SCRIPT INJECTION *
 *************************/

function maybeInjectScript(event)
{
  var doc = event.originalTarget;
  if (doc.nodeName != "#document")
    return;

  var hash = doc.location.hash;

  var r = hash.split(",");

  if (r[0] != "#squarefree-af") {
    return;
  }
  if (!(/^[a-zA-Z0-9\-.]*$/.test(r[1]))) {
    dump("Sketchy fuzzer filename!\n");
    return;
  }

  var dir = extensionLocation().parent;
  dir.append("fuzzers");

  var scriptToInject =
    readFile(indir(dir, "fuzz.js")) + "\n"
  + readFile(indir(dir, r[1])) + "\n"
  + readFile(indir(dir, "fuzz-finish-auto.js")) + "\n"
  + "document.getElementById('fuzz1').parentNode.removeChild(document.getElementById('fuzz1'));\n"
  + "fuzzSettings = [" + r.slice(2).join(",") + "];\n"
  + "setTimeout(fuzzOnload, 400);\n";

  var insertionPoint = doc.getElementsByTagName("head")[0] || doc.documentElement;

  if (!insertionPoint)
    return;

  var script = doc.createElementNS("http://www.w3.org/1999/xhtml", "script");
  script.setAttribute("id", "fuzz1");
  script.setAttribute("type", "text/javascript");
  script.textContent = scriptToInject;
  insertionPoint.appendChild(script);
}
<|endoftext|>