<commit_before>import * as React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { create } from 'jss';
import rtlPlugin from 'stylis-plugin-rtl';
import rtlPluginSc from 'stylis-plugin-rtl-sc';
import createCache from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import { StyleSheetManager } from 'styled-components';
import { jssPreset, StylesProvider } from '@material-ui/styles';
import { useTheme, styled, createTheme, ThemeProvider } from '@material-ui/core/styles';
import rtl from 'jss-rtl';
import DemoErrorBoundary from 'docs/src/modules/components/DemoErrorBoundary';
import { useTranslate } from 'docs/src/modules/utils/i18n';

function FramedDemo(props) {
  const { children, document } = props;

  const theme = useTheme();
  React.useEffect(() => {
    document.body.dir = theme.direction;
  }, [document, theme.direction]);

  const { jss, sheetsManager } = React.useMemo(() => {
    return {
      jss: create({
        plugins: [...jssPreset().plugins, rtl()],
        insertionPoint: document.head,
      }),
      sheetsManager: new Map(),
    };
  }, [document]);

  const cache = React.useMemo(
    () =>
      createCache({
        key: `iframe-demo-${theme.direction}`,
        prepend: true,
        container: document.head,
        stylisPlugins: theme.direction === 'rtl' ? [rtlPlugin] : [],
      }),
    [document, theme.direction],
  );

  const getWindow = React.useCallback(() => document.defaultView, [document]);

  return (
    <StylesProvider jss={jss} sheetsManager={sheetsManager}>
      <StyleSheetManager
        target={document.head}
        stylisPlugins={theme.direction === 'rtl' ? [rtlPluginSc] : []}
      >
        <CacheProvider value={cache}>
          {React.cloneElement(children, {
            window: getWindow,
          })}
        </CacheProvider>
      </StyleSheetManager>
    </StylesProvider>
  );
}
FramedDemo.propTypes = {
  children: PropTypes.node,
  document: PropTypes.object.isRequired,
};

const Frame = styled('iframe')(({ theme }) => ({
  backgroundColor: theme.palette.background.default,
  flexGrow: 1,
  height: 400,
  border: 0,
  boxShadow: theme.shadows[1],
}));

function DemoFrame(props) {
  const { children, name, ...other } = props;
  const title = `${name} demo`;
  /**
   * @type {import('react').Ref<HTMLIFrameElement>}
   */
  const frameRef = React.useRef(null);

  // If we portal content into the iframe before the load event then that content
  // is dropped in firefox.
  const [iframeLoaded, onLoad] = React.useReducer(() => true, false);

  React.useEffect(() => {
    const document = frameRef.current.contentDocument;
    // When we hydrate the iframe then the load event is already dispatched
    // once the iframe markup is parsed (maybe later but the important part is
    // that it happens before React can attach event listeners).
    // We need to check the readyState of the document once the iframe is mounted
    // and "replay" the missed load event.
    // See https://github.com/facebook/react/pull/13862 for ongoing effort in React
    // (though not with iframes in mind).
    if (document != null && document.readyState === 'complete' && !iframeLoaded) {
      onLoad();
    }
  }, [iframeLoaded]);

  const document = frameRef.current?.contentDocument;
  return (
    <React.Fragment>
      <Frame onLoad={onLoad} ref={frameRef} title={title} {...other} />
      {iframeLoaded !== false
        ? ReactDOM.createPortal(
            <FramedDemo document={document}>{children}</FramedDemo>,
            document.body,
          )
        : null}
    </React.Fragment>
  );
}

DemoFrame.propTypes = {
  children: PropTypes.node.isRequired,
  name: PropTypes.string.isRequired,
};

// Use the default MUI theme for the demos
const theme = createTheme();
const darkModeTheme = createTheme({ palette: { mode: 'dark' } });

/**
 * Isolates the demo component as best as possible. Additional props are spread
 * to an `iframe` if `iframe={true}`.
 */
function DemoSandboxed(props) {
  const { component: Component, iframe, name, onResetDemoClick, ...other } = props;
  const Sandbox = iframe ? DemoFrame : React.Fragment;
  const sandboxProps = iframe ? { name, ...other } : {};

  const t = useTranslate();

  return (
    <DemoErrorBoundary name={name} onResetDemoClick={onResetDemoClick} t={t}>
      <Sandbox {...sandboxProps}>
        <ThemeProvider
          theme={(outerTheme) => (outerTheme?.palette?.mode === 'dark' ? darkModeTheme : theme)}
        >
          <Component />
        </ThemeProvider>
      </Sandbox>
    </DemoErrorBoundary>
  );
}

DemoSandboxed.propTypes = {
  component: PropTypes.elementType.isRequired,
  iframe: PropTypes.bool,
  name: PropTypes.string.isRequired,
  onResetDemoClick: PropTypes.func.isRequired,
};

export default React.memo(DemoSandboxed);
<commit_msg>[docs] Fix rtl issue on the demos (#27865)<commit_after>import * as React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { create } from 'jss';
import rtlPlugin from 'stylis-plugin-rtl';
import rtlPluginSc from 'stylis-plugin-rtl-sc';
import createCache from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import { StyleSheetManager } from 'styled-components';
import { jssPreset, StylesProvider } from '@material-ui/styles';
import { useTheme, styled, createTheme, ThemeProvider } from '@material-ui/core/styles';
import rtl from 'jss-rtl';
import DemoErrorBoundary from 'docs/src/modules/components/DemoErrorBoundary';
import { useTranslate } from 'docs/src/modules/utils/i18n';

function FramedDemo(props) {
  const { children, document } = props;

  const theme = useTheme();
  React.useEffect(() => {
    document.body.dir = theme.direction;
  }, [document, theme.direction]);

  const { jss, sheetsManager } = React.useMemo(() => {
    return {
      jss: create({
        plugins: [...jssPreset().plugins, rtl()],
        insertionPoint: document.head,
      }),
      sheetsManager: new Map(),
    };
  }, [document]);

  const cache = React.useMemo(
    () =>
      createCache({
        key: `iframe-demo-${theme.direction}`,
        prepend: true,
        container: document.head,
        stylisPlugins: theme.direction === 'rtl' ? [rtlPlugin] : [],
      }),
    [document, theme.direction],
  );

  const getWindow = React.useCallback(() => document.defaultView, [document]);

  return (
    <StylesProvider jss={jss} sheetsManager={sheetsManager}>
      <StyleSheetManager
        target={document.head}
        stylisPlugins={theme.direction === 'rtl' ? [rtlPluginSc] : []}
      >
        <CacheProvider value={cache}>
          {React.cloneElement(children, {
            window: getWindow,
          })}
        </CacheProvider>
      </StyleSheetManager>
    </StylesProvider>
  );
}
FramedDemo.propTypes = {
  children: PropTypes.node,
  document: PropTypes.object.isRequired,
};

const Frame = styled('iframe')(({ theme }) => ({
  backgroundColor: theme.palette.background.default,
  flexGrow: 1,
  height: 400,
  border: 0,
  boxShadow: theme.shadows[1],
}));

function DemoFrame(props) {
  const { children, name, ...other } = props;
  const title = `${name} demo`;
  /**
   * @type {import('react').Ref<HTMLIFrameElement>}
   */
  const frameRef = React.useRef(null);

  // If we portal content into the iframe before the load event then that content
  // is dropped in firefox.
  const [iframeLoaded, onLoad] = React.useReducer(() => true, false);

  React.useEffect(() => {
    const document = frameRef.current.contentDocument;
    // When we hydrate the iframe then the load event is already dispatched
    // once the iframe markup is parsed (maybe later but the important part is
    // that it happens before React can attach event listeners).
    // We need to check the readyState of the document once the iframe is mounted
    // and "replay" the missed load event.
    // See https://github.com/facebook/react/pull/13862 for ongoing effort in React
    // (though not with iframes in mind).
    if (document != null && document.readyState === 'complete' && !iframeLoaded) {
      onLoad();
    }
  }, [iframeLoaded]);

  const document = frameRef.current?.contentDocument;
  return (
    <React.Fragment>
      <Frame onLoad={onLoad} ref={frameRef} title={title} {...other} />
      {iframeLoaded !== false
        ? ReactDOM.createPortal(
            <FramedDemo document={document}>{children}</FramedDemo>,
            document.body,
          )
        : null}
    </React.Fragment>
  );
}

DemoFrame.propTypes = {
  children: PropTypes.node.isRequired,
  name: PropTypes.string.isRequired,
};

// Use the default MUI theme for the demos
const theme = createTheme();
const darkModeTheme = createTheme({ palette: { mode: 'dark' } });

const getTheme = (outerTheme) => {
  const resultTheme = outerTheme?.palette?.mode === 'dark' ? darkModeTheme : theme;
  resultTheme.direction = outerTheme?.direction;
  return resultTheme;
};

/**
 * Isolates the demo component as best as possible. Additional props are spread
 * to an `iframe` if `iframe={true}`.
 */
function DemoSandboxed(props) {
  const { component: Component, iframe, name, onResetDemoClick, ...other } = props;
  const Sandbox = iframe ? DemoFrame : React.Fragment;
  const sandboxProps = iframe ? { name, ...other } : {};

  const t = useTranslate();

  return (
    <DemoErrorBoundary name={name} onResetDemoClick={onResetDemoClick} t={t}>
      <Sandbox {...sandboxProps}>
        <ThemeProvider theme={(outerTheme) => getTheme(outerTheme)}>
          <Component />
        </ThemeProvider>
      </Sandbox>
    </DemoErrorBoundary>
  );
}

DemoSandboxed.propTypes = {
  component: PropTypes.elementType.isRequired,
  iframe: PropTypes.bool,
  name: PropTypes.string.isRequired,
  onResetDemoClick: PropTypes.func.isRequired,
};

export default React.memo(DemoSandboxed);
<|endoftext|>


<commit_before>var Model = {
    inherited:function ()
    {

    },

    created:function ()
    {

    },

    prototype:{
        init:function ()
        {

        }
    },

    //  Return new object inherited from Model
    create:   function ()
    {
        var object = Object.create(this);
        object.parent = this;
        object.prototype = object.fn = Object.create(this.prototype);

        object.created();
        this.inherited(object);
        return object;
    },

    // Returns new Model
    init:     function ()
    {
        var instance = Object.create(this.prototype);
        instance.parent = this;
        instance.init.apply(instance, arguments);
        return instance;
    },

    // Extend the actual class
    extend:   function (o)
    {
        var extended = o.extended;
        jQuery.extend(this, o);
        if (extended)
        {
            extended(this);
        }
    },

    // Extend instance
    include:  function (o)
    {
        var included = o.included;
        jQuery.extend(this.prototype, o);
        if (included)
        {
            included(this);
        }
    },

    find:function (id)
    {
        var record = this.records[id];
        if (!record)
        {
            throw ('Unknown record');
        }
        return record.dup();
    },

    populate:function (values)
    {
        this.records = {};
        for (var i = 0, il = values.length; i < il; i++)
        {
            var record = this.init(values[i]);
            record.newRecord = false;
            this.records[record.id] = record;
        }
    },

    select:function (callback)
    {
        var result = [];

        for (var key in this.records)
        {
            if (callback(this.records[key]))
            {
                result.push(this.records[key]);
            }
        }

        return this.dupArray(result);
    },

    destroy:function (id)
    {
        this.find(id).destroy();
    },

    all:          function ()
    {
        return this.dupArray(this.recordsValues());
    },
    recordsValues:function ()
    {
        var result = [];
        for (var key in this.records)
        {@
            result.push(this.records[key]);
        }
        return result;
    },

    dupArray:function (array)
    {
        return array.map(function (item)
        {
            return item.dup();
        });
    },
    count:   function ()
    {
        return this.recordsValues().length;
    }

};
Model.records = {};

Model.include({
    newRecord:true,

    init:function (atts)
    {

        if (atts)
        {
            this.load(atts);
        }
    },

    validate:function ()
    {
    },

    load:function (attributes)
    {
        for (var name in attributes)
        {
            this[name] = attributes[name];
        }
    },

    create:function ()
    {
        this.trigger("beforeCreate");
        this.newRecord = false;
        this.parent.records[this.id] = this.dup();
        this.trigger("afterCreate");
        this.trigger("create");
    },

    updateAttribute:function (name, value)
    {
        this[name] = value;
        return this.save();
    },

    updateAttributes:function (attributes)
    {
        this.load(attributes);
        return this.save();
    },

    trigger:function (channel)
    {
        this.parent.trigger(channel, this);
    },

    update:function ()
    {
        this.trigger("beforeUpdate");
        this.parent.records[this.id] = this.dup();
        this.trigger("afterUpdate");
        this.trigger("update");
    },

    destroy:function ()
    {
        this.trigger("beforeDestroy");
        delete this.parent.records[this.id];
        this.trigger("afterDestroy");
        this.trigger("destroy");
    },

    dup:function ()
    {
        return jQuery.extend(true, {}, this);
    },

    save:function ()
    {
        this.trigger("beforeSave");
        this.newRecord ? this.create() : this.update();
        this.trigger("afterSave");
        this.trigger("save");
    },

    attributes:function ()
    {
        var result = {};
        for (var i in this.parent.attributes)
        {
            var attr = this.parent.attributes[i];
            result[attr] = this[attr];
        }
        result.id = this.id;
        return result;
    },

    toJSON:function ()
    {
        return (this.attributes);
    },

    createRemote:function (url, callback)
    {
        $.post(url, this.attributes(), callback);
    },

    updateRemote:function (url, callback)
    {
        $.ajax({
            url:    url,
            data:   this.attributes(),
            success:callback,
            type:   'POST'
        });
    }
});

Model.extend({
    created:function ()
    {
        this.records = {};
        this.attributes = {};
    },

    saveLocal:function (name)
    {
        var result = [];
        for (var i in this.records)
        {
            result.push(this.records[i].attributes());
        }
        localStorage[name] = JSON.stringify(result);
    },

    loadLocal:function (name)
    {
        if (localStorage[name])
        {
            var result = JSON.parse(localStorage[name]);
            this.populate(result);
        }
    }
});

Model.extend(Events);
<commit_msg>Removed @<commit_after>var Model = {
    inherited:function ()
    {

    },

    created:function ()
    {

    },

    prototype:{
        init:function ()
        {

        }
    },

    //  Return new object inherited from Model
    create:   function ()
    {
        var object = Object.create(this);
        object.parent = this;
        object.prototype = object.fn = Object.create(this.prototype);

        object.created();
        this.inherited(object);
        return object;
    },

    // Returns new Model
    init:     function ()
    {
        var instance = Object.create(this.prototype);
        instance.parent = this;
        instance.init.apply(instance, arguments);
        return instance;
    },

    // Extend the actual class
    extend:   function (o)
    {
        var extended = o.extended;
        jQuery.extend(this, o);
        if (extended)
        {
            extended(this);
        }
    },

    // Extend instance
    include:  function (o)
    {
        var included = o.included;
        jQuery.extend(this.prototype, o);
        if (included)
        {
            included(this);
        }
    },

    find:function (id)
    {
        var record = this.records[id];
        if (!record)
        {
            throw ('Unknown record');
        }
        return record.dup();
    },

    populate:function (values)
    {
        this.records = {};
        for (var i = 0, il = values.length; i < il; i++)
        {
            var record = this.init(values[i]);
            record.newRecord = false;
            this.records[record.id] = record;
        }
    },

    select:function (callback)
    {
        var result = [];

        for (var key in this.records)
        {
            if (callback(this.records[key]))
            {
                result.push(this.records[key]);
            }
        }

        return this.dupArray(result);
    },

    destroy:function (id)
    {
        this.find(id).destroy();
    },

    all:          function ()
    {
        return this.dupArray(this.recordsValues());
    },
    recordsValues:function ()
    {
        var result = [];
        for (var key in this.records)
        {
            result.push(this.records[key]);
        }
        return result;
    },

    dupArray:function (array)
    {
        return array.map(function (item)
        {
            return item.dup();
        });
    },
    count:   function ()
    {
        return this.recordsValues().length;
    }

};
Model.records = {};

Model.include({
    newRecord:true,

    init:function (atts)
    {

        if (atts)
        {
            this.load(atts);
        }
    },

    validate:function ()
    {
    },

    load:function (attributes)
    {
        for (var name in attributes)
        {
            this[name] = attributes[name];
        }
    },

    create:function ()
    {
        this.trigger("beforeCreate");
        this.newRecord = false;
        this.parent.records[this.id] = this.dup();
        this.trigger("afterCreate");
        this.trigger("create");
    },

    updateAttribute:function (name, value)
    {
        this[name] = value;
        return this.save();
    },

    updateAttributes:function (attributes)
    {
        this.load(attributes);
        return this.save();
    },

    trigger:function (channel)
    {
        this.parent.trigger(channel, this);
    },

    update:function ()
    {
        this.trigger("beforeUpdate");
        this.parent.records[this.id] = this.dup();
        this.trigger("afterUpdate");
        this.trigger("update");
    },

    destroy:function ()
    {
        this.trigger("beforeDestroy");
        delete this.parent.records[this.id];
        this.trigger("afterDestroy");
        this.trigger("destroy");
    },

    dup:function ()
    {
        return jQuery.extend(true, {}, this);
    },

    save:function ()
    {
        this.trigger("beforeSave");
        this.newRecord ? this.create() : this.update();
        this.trigger("afterSave");
        this.trigger("save");
    },

    attributes:function ()
    {
        var result = {};
        for (var i in this.parent.attributes)
        {
            var attr = this.parent.attributes[i];
            result[attr] = this[attr];
        }
        result.id = this.id;
        return result;
    },

    toJSON:function ()
    {
        return (this.attributes);
    },

    createRemote:function (url, callback)
    {
        $.post(url, this.attributes(), callback);
    },

    updateRemote:function (url, callback)
    {
        $.ajax({
            url:    url,
            data:   this.attributes(),
            success:callback,
            type:   'POST'
        });
    }
});

Model.extend({
    created:function ()
    {
        this.records = {};
        this.attributes = {};
    },

    saveLocal:function (name)
    {
        var result = [];
        for (var i in this.records)
        {
            result.push(this.records[i].attributes());
        }
        localStorage[name] = JSON.stringify(result);
    },

    loadLocal:function (name)
    {
        if (localStorage[name])
        {
            var result = JSON.parse(localStorage[name]);
            this.populate(result);
        }
    }
});

Model.extend(Events);
<|endoftext|>


<commit_before>/*
==================================================================================================
  Jasy - JavaScript Tooling Refined
  Copyright 2010 Sebastian Werner
==================================================================================================
*/

(function(global)
{
  var declare = function(namespace, object)
  {
    var splits = namespace.split(".");
    var current = global;
    var length = splits.length-1;
    var i = 0;
    var test;

    // Fast-check for existing segments
    while(test=current[splits[i]]) {
      current = test;
      i++;
    }

    // Create missing segments
    while(i<length) {
      current = current[splits[i++]] = {};
    }

    // Store Object
    return current[splits[i]] = object;
  };

  var globalEval = (function()
  {
    var isIndirectEvalGlobal = (function()
    {
      eval("var Object=1");

      try
      {
        // Does `Object` resolve to a local variable, or to a global, built-in `Object`,
        // reference to which we passed as a first argument?
        return global.eval('Object') === global.Object;
      }
      catch(err)
      {
        // if indirect eval errors out (as allowed per ES3), then just bail out with `false`
        return false;
      }
    })();

    if (isIndirectEvalGlobal)
    {
      // if indirect eval executes code globally, use it
      return function(expression) {
        return global.eval(expression);
      };
    }
    else if (global.execScript != null)
    {
      // if `window.execScript exists`, use it
      return function(expression) {
        return global.execScript(expression);
      };
    }

    // otherwise, globalEval is `undefined` since nothing is returned
  })();

  // Finally create namespace
  declare("Core",
  {
    /**
     * Declares the given namespace and stores the given object onto it.
     *
     * @param namespace {String} Namespace/Package e.g. foo.bar.baz
     * @param object {Object} Any object
     */
    declare : declare,

    /**
     * Executes the given code in global context
     *
     * Via:
     * http://perfectionkills.com/global-eval-what-are-the-options/#feature_testing_based_approach
     *
     * @param expression {String} Code to execute
     * @return {var} Return value of executed code
     */
    globalEval : globalEval,

    /**
     * Loads the script at the given URI.
     *
     * @param uri {String} URI of script source to load
     */
    loadScript : LAB.script
  });
})(this);
<commit_msg>Minor tweaks<commit_after>/*
==================================================================================================
  Jasy - JavaScript Tooling Refined
  Copyright 2010 Sebastian Werner
==================================================================================================
*/

(function(global)
{
  var declare = function(namespace, object)
  {
    var splits = namespace.split(".");
    var current = global;
    var length = splits.length-1;
    var i = 0;
    var test;

    // Fast-check for existing segments
    while(test=current[splits[i]]) {
      current = test;
      i++;
    }

    // Create missing segments
    while(i<length) {
      current = current[splits[i++]] = {};
    }

    // Store Object
    return current[splits[i]] = object;
  };

  var globalEval = (function()
  {
    var isIndirectEvalGlobal = (function()
    {
      eval("var Object=1");

      try
      {
        // Does `Object` resolve to a local variable, or to a global, built-in `Object`,
        // reference to which we passed as a first argument?
        return global.eval('Object') === global.Object;
      }
      catch(err)
      {
        // if indirect eval errors out (as allowed per ES3), then just bail out with `false`

        // wpbasti: not needed as it is just check for being falsy and so "undefined" is OK
        // return false;
      }
    })();

    if (isIndirectEvalGlobal)
    {
      // if indirect eval executes code globally, use it
      return function(expression) {
        return global.eval(expression);
      };
    }
    else if (global.execScript != null)
    {
      // if `window.execScript exists`, use it
      return function(expression) {
        return global.execScript(expression);
      };
    }

    // otherwise, globalEval is `undefined` since nothing is returned
  })();

  // ========================================================================================
  // Finally create namespace
  // ========================================================================================

  declare("Core",
  {
    /**
     * Declares the given namespace and stores the given object onto it.
     *
     * @param namespace {String} Namespace/Package e.g. foo.bar.baz
     * @param object {Object} Any object
     */
    declare : declare,

    /**
     * Executes the given code in global context
     *
     * Via:
     * http://perfectionkills.com/global-eval-what-are-the-options/#feature_testing_based_approach
     *
     * @param expression {String} Code to execute
     * @return {var} Return value of executed code
     */
    globalEval : globalEval,

    /**
     * Loads the script at the given URI.
     *
     * @param uri {String} URI of script source to load
     */
    loadScript : LAB.script
  });
})(this);
<|endoftext|>


<commit_before>var HashTable, HashMap;
 HashTable = HashMap = (function() {
	function HashTable() {
		this.pairs = [];
		this.orderedPairs = [];
	}
	function KeyValuePair(hash, key, val) {
		this.hash = hash;
		this.key = key;
		this.val = val;
	}

    var hasher = function (value) {
        return (typeof value) + ' ' + (value instanceof Object ? (value.__hash || (value.__hash = ++arguments.callee.current)) : value.toString());
    };
    hasher.current = 0;

    HashTable.prototype.hashObject = hasher;
	KeyValuePair.prototype.containsKey = function (key) { return this.key === key; };
	KeyValuePair.prototype.containsVal = function (val) { return this.val === val; };
	HashTable.prototype.add = function (newKey, newVal) {
		var hash = this.hashObject(newKey);
		if (!this.containsKey(newKey)) {
			this.pairs[hash] = new KeyValuePair(hash, newKey, newVal);
			this.orderedPairs.push(this.pairs[hash]);
		} else {
			this.pairs[hash].val = newVal;
		}
	};
	HashTable.prototype.put  = this.add;
	HashTable.prototype.get = function (key) {
		var hash = this.hashObject(key);
		if (this.pairs[hash] !== null) { return this.pairs[hash].val; }
		return null;
	};
	HashTable.prototype.remove = function (key) {
		var i, hash;
		if (this.containsKey(key)) {
			hash = this.hashObject(key);
			for (i = 0; i < this.orderedPairs.length; i++) {
				if (this.orderedPairs[i] === this.pairs[hash]) {
					this.orderedPairs.splice(i, 1);
					this.pairs[hash] = null;
					return;
				}
			}
			throw new Error("contain returned true, but key not found");
		}
	};
	HashTable.prototype.containsKey = function (key) {
		var hash = this.hashObject(key);
		return (this.pairs[hash] && (this.pairs[hash] instanceof KeyValuePair)) ? true : false;
	};
	HashTable.prototype.containsValue = function (val) {
		var ret = false;
		this.orderedPairs.map(function (item) {
			ret = ret || item.val === val;
		});
		return ret;
	};
	HashTable.prototype.isEmpty = function () {
        return this.size() === 0;
    };
	HashTable.prototype.size = function () {
        return this.orderedPairs.length;
    };
	//pass in function(key,val)
	HashTable.prototype.foreachInSet = function (theirFunction) {
		this.orderedPairs.map(function (item) {
			theirFunction(item.key, item.val);
		});
	};
	return HashTable;
}());<commit_msg>Multi threaded and iteration save delete<commit_after>/*
 * Hash table developed by Anthony Corbin
//*/
var HashTable, HashMap;
 HashTable = HashMap = (function() {
	function HashTable() {
		this.pairs = [];
		this.orderedPairs = [];
	}
	function KeyValuePair(hash, key, val) {
		this.hash = hash;
		this.key = key;
		this.val = val;
        this.markedForDel = false;
	}

    var hasher = function (value) {
        return (typeof value) + ' ' + (value instanceof Object ? (value.__hash || (value.__hash = ++arguments.callee.current)) : value.toString());
    };
    hasher.current = 0;

    this.numOfActiveIterations = 0;

    HashTable.prototype.hashObject = hasher;
	KeyValuePair.prototype.containsKey = function (key) { return this.key === key; };
	KeyValuePair.prototype.containsVal = function (val) { return this.val === val; };
	HashTable.prototype.add = function (newKey, newVal) {
		var hash = this.hashObject(newKey);
		if (!this.containsKey(newKey)) {
			this.pairs[hash] = new KeyValuePair(hash, newKey, newVal);
			this.orderedPairs.push(this.pairs[hash]);
		} else {
			this.pairs[hash].val = newVal;
		}
	};
	HashTable.prototype.put  = this.add;
	HashTable.prototype.get = function (key) {
		var hash = this.hashObject(key);
		if (this.pairs[hash] !== null) { return this.pairs[hash].val; }
		return null;
	};
	HashTable.prototype.remove = function (key) {
		var i, hash;
		if (this.containsKey(key)) {
			hash = this.hashObject(key);
            this.pairs[hash].markedForDel = true;
            var del = function del() {
                if(this.numOfActiveIterations > 0) {
                    setTimeout(del,10);
                    return;
                }
                for (i = 0; i < this.orderedPairs.length; i++) {
                    if (this.orderedPairs[i] === this.pairs[hash]) {
                        this.orderedPairs.splice(i, 1);
                        this.pairs[hash] = null;
                        return;
                    }
                }
                throw new Error("contain returned true, but key not found");
            };
		}
	};
	HashTable.prototype.containsKey = function (key) {
		var hash = this.hashObject(key);
		return (this.pairs[hash] && (this.pairs[hash] instanceof KeyValuePair)) ? true : false;
	};
	HashTable.prototype.containsValue = function (val) {
		var ret = false;
		this.orderedPairs.map(function (item) {
			ret = ret || item.val === val;
		});
		return ret;
	};
	HashTable.prototype.isEmpty = function () { return this.size() === 0; };
	HashTable.prototype.size = function () { return this.orderedPairs.length; };
	//pass in function(key,val)
	HashTable.prototype.foreachInSet = function (theirFunction) {
        this.numOfActiveIterations++;
		this.orderedPairs.map(function (item) {
            if(!item.markedForDel) {
                theirFunction(item.key, item.val);
            }
		});
        this.numOfActiveIterations--;
	};
	return HashTable;
}());<|endoftext|>


<commit_before>#!/usr/bin/env node

var validations = require('./lib/common/validations'),
    manifestTools = require('./lib/manifestTools'),
    projectBuilder = require('./lib/projectBuilder'),
    projectTools = require('./lib/projectTools'),
    platformUtils = require('./lib/platformUtils'),
    version = require('./lib/common/version'),
    url = require('url'),
    log = require('loglevel'),
    path = require('path'),
    fs = require('fs');

version.checkForUpdate(function (err, updateAvailable) {
  if (!err && updateAvailable) {
    console.log();
    console.log('*******************************************************************************');
    console.log('A new version of ManifoldJS is available (v' + updateAvailable + ').');
    console.log('We recommend that you upgrade.');
    console.log('*******************************************************************************');
    console.log();
  }
});

function checkParameters(program) {
  if (program.args.length > 0) {
    var unknownArgs = 0;
    var command = program.args[0].toLowerCase();
    switch (command) {
      case 'run':
        if (program.args.length < 2) {
          return 'ERROR: You must specify a platform (windows | android).';
        }

        if (!validations.platformToRunValid(program.args[1])) {
          return 'ERROR: Invalid platform specified - [' + program.args[1] + '].';
        }

        unknownArgs = 2;
        program.run = true;
        break;
      case 'package':
        if (program.args.length < 2) {
          return 'ERROR: You must specify a content directory.';
        }

        if (program.args.length < 3) {
          return 'ERROR: You must specify an output package path.';
        }

        unknownArgs = 3;
        program.package = true;
        break;
      case 'visualstudio':
      default:
        unknownArgs = 1;
        program.visualstudio = true;
        break;
    }
  } else {
    if (!program.manifest) {
      return 'ERROR: You must specify either the web site URL or the location of a W3C manifest (-m | --manifest).';
    }
  }

  if (program.args.length > unknownArgs) {
    return 'ERROR: Unexpected parameters - [' + program.args.slice(unknownArgs).join() + '].';
  }

  // check platforms
  if (program.platforms) {
    var platforms = program.platforms.split(/[\s,]+/);
    if (!validations.platformsValid(platforms)) {
      return 'ERROR: Invalid platform(s) specified.';
    }
  }

  // check log level
  if (program.loglevel) {
    if (!validations.logLevelValid(program.loglevel)) {
      return 'ERROR: Invalid loglevel specified. Valid values are: debug, trace, info, warn, error';
    }
  }
}

function getW3cManifest(siteUrl, manifestLocation, callback) {
  function resolveStartURL(err, manifestInfo) {
    if (err) {
      return callback(err, manifestInfo);
    }

    return manifestTools.validateAndNormalizeStartUrl(siteUrl, manifestInfo, callback);
  }

  if (siteUrl) {
    var parsedSiteUrl = url.parse(siteUrl);
    if (!parsedSiteUrl.hostname) {
      return callback(new Error('The site URL is not a valid URL.'));
    }
  }

  if (manifestLocation) {
    var parsedManifestUrl = url.parse(manifestLocation);
    if (parsedManifestUrl && parsedManifestUrl.host) {
      // download manifest from remote location
      log.info('Downloading manifest from ' + manifestLocation + '...');
      manifestTools.downloadManifestFromUrl(manifestLocation, resolveStartURL);
    } else {
      // read local manifest file
      log.info('Reading manifest file ' + manifestLocation + '...');
      manifestTools.getManifestFromFile(manifestLocation, resolveStartURL);
    }
  } else if (siteUrl) {
    // scan a site to retrieve its manifest
    log.info('Scanning ' + siteUrl + ' for manifest...');
    manifestTools.getManifestFromSite(siteUrl, resolveStartURL);
  } else {
    return callback(new Error('A site URL or manifest should be specified.'));
  }
}

var program = require('commander')
             .usage('<website-url> [options]\n' +
                    '  -or-\n' +
                    '         manifoldjs -m <manifest-location> [options]\n' +
                    '  -or-\n' +
                    '         manifoldjs package <content-directory> <output-package-path>\n' +
                    '  -or-\n' +
                    '         manifoldjs run <windows|android>\n' +
                    '  -or-\n' +
                    '         manifoldjs visualstudio')
             .option('-d, --directory <app-dir>', 'path to the generated project files')
             .option('-s, --shortname <short-name>', 'application short name')
             .option('-l, --loglevel <log-level>', 'debug|info|warn|error', 'warn')
             .option('-p, --platforms <platforms>', '[windows][,windows10][,android][,ios]\n                                    ' +
                                                    '[,chrome][,web][,firefox]', 'windows,windows10,android,ios,chrome,web,firefox')
             .option('-b, --build', 'forces the building process', false)
             .option('-m, --manifest <manifest-location>', 'location of the W3C Web App manifest\n                                    ' +
                                                    'file (URL or local path)')
             .option('-c, --crosswalk', 'enable Crosswalk for Android', false)
             .option('-w, --webAppToolkit', 'adds the Web App Toolkit cordova plugin', false)
             .parse(process.argv);

if (!process.argv.slice(2).length) {
  program.help();
}

var validationResult = checkParameters(program);
if (validationResult) {
  console.log(validationResult);
  process.exit(1);
}

global.logLevel = program.loglevel;
log.setLevel(global.logLevel);

if (program.run) {
  // Run the app for the specified platform

  var platform = program.args[1];
  projectTools.runApp(platform, function (err) {
    if (err) {
      log.error('ERROR: ' + err.message);
    }
  });

} else if (program.visualstudio) {

  projectTools.openVisualStudio(function (err) {
    if (err) {
      log.error('ERROR: ' + err.message);
    } else {
      log.info('The Visual Studio project was opened successfully!');
    }
  });

} else if (program.package) {
  // creates App Store packages for publishing - currently supports Windows 10 only
  log.info('Creating a Windows Store AppX package for the Windows 10 hosted app project...');
  var directory = program.args[1];
  var outputPath = program.args[2];
  platformUtils.makeAppx(directory, outputPath, function (err) {
    if (err) {
      log.error('ERROR: ' + err.message);
      return;
    }

    log.info('The app store package was created successfully!');
  });
} else {
  var siteUrl = program.args[0];
  var rootDir = program.directory ? path.resolve(program.directory) : process.cwd();
  var platforms = program.platforms.split(/[\s,]+/);

  // remove windows as default platform if run on Linux or MacOS
  // Fix for issue # 115: https://github.com/manifoldjs/ManifoldJS/issues/115
  // it should be removed once cordova adds support for Windows on Linux and MacOS
  if (!platformUtils.isWindows &&
       program.rawArgs.indexOf('-p') === -1 &&
       program.rawArgs.indexOf('--platforms')  === -1) {
    platforms.splice(platforms.indexOf('windows'), 1);
  }

  getW3cManifest(siteUrl, program.manifest, function (err, manifestInfo) {
    if (err) {
      log.error('ERROR: ' + err.message);
      return;
    }

    // if specified as a parameter, override the app's short name
    if (program.shortname) {
      manifestInfo.content.short_name = program.shortname;
    }

    log.debug('Manifest contents:');
    log.debug(JSON.stringify(manifestInfo.content, null, 4));

    // add generatedFrom value to manifestInfo for telemetry
    manifestInfo.generatedFrom = 'CLI';

    // Create the apps for the specified platforms
    projectBuilder.createApps(manifestInfo, rootDir, platforms, program, function (err) {
      if (err) {
        var errmsg = err.message;
        if (global.logLevel !== 'debug') {
          errmsg += ' For more information, run manifoldjs with the diagnostics level set to debug (e.g. manifoldjs [...] -l debug)';
        }

        log.error(errmsg);
        return;
      }

      log.info('The application(s) are ready!');
    });
  });
}
<commit_msg>Fixed command line parsing issue<commit_after>#!/usr/bin/env node

var validations = require('./lib/common/validations'),
    manifestTools = require('./lib/manifestTools'),
    projectBuilder = require('./lib/projectBuilder'),
    projectTools = require('./lib/projectTools'),
    platformUtils = require('./lib/platformUtils'),
    version = require('./lib/common/version'),
    url = require('url'),
    log = require('loglevel'),
    path = require('path'),
    fs = require('fs');

version.checkForUpdate(function (err, updateAvailable) {
  if (!err && updateAvailable) {
    console.log();
    console.log('*******************************************************************************');
    console.log('A new version of ManifoldJS is available (v' + updateAvailable + ').');
    console.log('We recommend that you upgrade.');
    console.log('*******************************************************************************');
    console.log();
  }
});

function checkParameters(program) {
  if (program.args.length > 0) {
    var unknownArgs = 0;
    var command = program.args[0].toLowerCase();
    switch (command) {
      case 'run':
        if (program.args.length < 2) {
          return 'ERROR: You must specify a platform (windows | android).';
        }

        if (!validations.platformToRunValid(program.args[1])) {
          return 'ERROR: Invalid platform specified - [' + program.args[1] + '].';
        }

        unknownArgs = 2;
        program.run = true;
        break;
      case 'package':
        if (program.args.length < 2) {
          return 'ERROR: You must specify a content directory.';
        }

        if (program.args.length < 3) {
          return 'ERROR: You must specify an output package path.';
        }

        unknownArgs = 3;
        program.package = true;
        break;
      case 'visualstudio':
        program.visualstudio = true;
      default:
        unknownArgs = 1;
        break;
    }
  } else {
    if (!program.manifest) {
      return 'ERROR: You must specify either the web site URL or the location of a W3C manifest (-m | --manifest).';
    }
  }

  if (program.args.length > unknownArgs) {
    return 'ERROR: Unexpected parameters - [' + program.args.slice(unknownArgs).join() + '].';
  }

  // check platforms
  if (program.platforms) {
    var platforms = program.platforms.split(/[\s,]+/);
    if (!validations.platformsValid(platforms)) {
      return 'ERROR: Invalid platform(s) specified.';
    }
  }

  // check log level
  if (program.loglevel) {
    if (!validations.logLevelValid(program.loglevel)) {
      return 'ERROR: Invalid loglevel specified. Valid values are: debug, trace, info, warn, error';
    }
  }
}

function getW3cManifest(siteUrl, manifestLocation, callback) {
  function resolveStartURL(err, manifestInfo) {
    if (err) {
      return callback(err, manifestInfo);
    }

    return manifestTools.validateAndNormalizeStartUrl(siteUrl, manifestInfo, callback);
  }

  if (siteUrl) {
    var parsedSiteUrl = url.parse(siteUrl);
    if (!parsedSiteUrl.hostname) {
      return callback(new Error('The site URL is not a valid URL.'));
    }
  }

  if (manifestLocation) {
    var parsedManifestUrl = url.parse(manifestLocation);
    if (parsedManifestUrl && parsedManifestUrl.host) {
      // download manifest from remote location
      log.info('Downloading manifest from ' + manifestLocation + '...');
      manifestTools.downloadManifestFromUrl(manifestLocation, resolveStartURL);
    } else {
      // read local manifest file
      log.info('Reading manifest file ' + manifestLocation + '...');
      manifestTools.getManifestFromFile(manifestLocation, resolveStartURL);
    }
  } else if (siteUrl) {
    // scan a site to retrieve its manifest
    log.info('Scanning ' + siteUrl + ' for manifest...');
    manifestTools.getManifestFromSite(siteUrl, resolveStartURL);
  } else {
    return callback(new Error('A site URL or manifest should be specified.'));
  }
}

var program = require('commander')
             .usage('<website-url> [options]\n' +
                    '  -or-\n' +
                    '         manifoldjs -m <manifest-location> [options]\n' +
                    '  -or-\n' +
                    '         manifoldjs package <content-directory> <output-package-path>\n' +
                    '  -or-\n' +
                    '         manifoldjs run <windows|android>\n' +
                    '  -or-\n' +
                    '         manifoldjs visualstudio')
             .option('-d, --directory <app-dir>', 'path to the generated project files')
             .option('-s, --shortname <short-name>', 'application short name')
             .option('-l, --loglevel <log-level>', 'debug|info|warn|error', 'warn')
             .option('-p, --platforms <platforms>', '[windows][,windows10][,android][,ios]\n                                    ' +
                                                    '[,chrome][,web][,firefox]', 'windows,windows10,android,ios,chrome,web,firefox')
             .option('-b, --build', 'forces the building process', false)
             .option('-m, --manifest <manifest-location>', 'location of the W3C Web App manifest\n                                    ' +
                                                    'file (URL or local path)')
             .option('-c, --crosswalk', 'enable Crosswalk for Android', false)
             .option('-w, --webAppToolkit', 'adds the Web App Toolkit cordova plugin', false)
             .parse(process.argv);

if (!process.argv.slice(2).length) {
  program.help();
}

var validationResult = checkParameters(program);
if (validationResult) {
  console.log(validationResult);
  process.exit(1);
}

global.logLevel = program.loglevel;
log.setLevel(global.logLevel);

if (program.run) {
  // Run the app for the specified platform

  var platform = program.args[1];
  projectTools.runApp(platform, function (err) {
    if (err) {
      log.error('ERROR: ' + err.message);
    }
  });

} else if (program.visualstudio) {

  projectTools.openVisualStudio(function (err) {
    if (err) {
      log.error('ERROR: ' + err.message);
    } else {
      log.info('The Visual Studio project was opened successfully!');
    }
  });

} else if (program.package) {
  // creates App Store packages for publishing - currently supports Windows 10 only
  log.info('Creating a Windows Store AppX package for the Windows 10 hosted app project...');
  var directory = program.args[1];
  var outputPath = program.args[2];
  platformUtils.makeAppx(directory, outputPath, function (err) {
    if (err) {
      log.error('ERROR: ' + err.message);
      return;
    }

    log.info('The app store package was created successfully!');
  });
} else {
  var siteUrl = program.args[0];
  var rootDir = program.directory ? path.resolve(program.directory) : process.cwd();
  var platforms = program.platforms.split(/[\s,]+/);

  // remove windows as default platform if run on Linux or MacOS
  // Fix for issue # 115: https://github.com/manifoldjs/ManifoldJS/issues/115
  // it should be removed once cordova adds support for Windows on Linux and MacOS
  if (!platformUtils.isWindows &&
       program.rawArgs.indexOf('-p') === -1 &&
       program.rawArgs.indexOf('--platforms')  === -1) {
    platforms.splice(platforms.indexOf('windows'), 1);
  }

  getW3cManifest(siteUrl, program.manifest, function (err, manifestInfo) {
    if (err) {
      log.error('ERROR: ' + err.message);
      return;
    }

    // if specified as a parameter, override the app's short name
    if (program.shortname) {
      manifestInfo.content.short_name = program.shortname;
    }

    log.debug('Manifest contents:');
    log.debug(JSON.stringify(manifestInfo.content, null, 4));

    // add generatedFrom value to manifestInfo for telemetry
    manifestInfo.generatedFrom = 'CLI';

    // Create the apps for the specified platforms
    projectBuilder.createApps(manifestInfo, rootDir, platforms, program, function (err) {
      if (err) {
        var errmsg = err.message;
        if (global.logLevel !== 'debug') {
          errmsg += ' For more information, run manifoldjs with the diagnostics level set to debug (e.g. manifoldjs [...] -l debug)';
        }

        log.error(errmsg);
        return;
      }

      log.info('The application(s) are ready!');
    });
  });
}
<|endoftext|>


<commit_before>/*
 * Windows Native Settings Handler
 *
 * Deals with individual settings that are only accessible throught isolated
 * API calls.
 *
 * Copyright 2018 Raising the Floor - International
 *
 * Licensed under the New BSD license. You may not use this file except in
 * compliance with this License.
 *
 * The research leading to these results has received funding from the European Union's
 * Seventh Framework Programme (FP7/2007-2013)
 * under grant agreement no. 289016.
 *
 * You may obtain a copy of the License at
 * https://github.com/GPII/universal/blob/master/LICENSE.txt
 */

"use strict";

var fluid = require("gpii-universal"),
    gpii = fluid.registerNamespace("gpii"),
    windows = fluid.registerNamespace("gpii.windows");

require("../../WindowsUtilities/WindowsUtilities.js");

fluid.registerNamespace("gpii.windows.nativeSettingsHandler");

var hndName = "nativeSettingsHandler";

/**
 * Gets the current double click time for mouse.
 *
 * @return {Number} The current system double click time for mouse.
 */
windows.nativeSettingsHandler.GetDoubleClickTime = function () {
    var result = windows.user32.GetDoubleClickTime();

    return fluid.toPromise(result);
};

/**
 * Sets the current double click time for mouse.
 *
 * @param {Number} num The double click time to set in the system.
 * @return {Object} Object with the error information.
 */
windows.nativeSettingsHandler.SetDoubleClickTime = function (num) {
    var pRes = fluid.promise();

    var retVal = windows.user32.SetDoubleClickTime(num);
    if (retVal !== 0) {
        pRes.resolve();
    } else {
        var lastErr = windows.kernel32.GetLastError();
        var lastErrMsg = windows.translateLastError(lastErr);

        pRes.reject({code: lastErr, msg: lastErrMsg});
    }

    return pRes;
};

windows.nativeSettingsHandler.functions = {
    DoubleClickTime: {
        set: windows.nativeSettingsHandler.SetDoubleClickTime,
        get: windows.nativeSettingsHandler.GetDoubleClickTime
    }
};

/**
 * Helper function that converts a error to string, so the rejection from the
 * settings handler only holds a message.
 *
 * @param {Object} err The error to be stringified.
 * @return {String} The error message.
 */
windows.nativeSettingsHandler.errorInfo = function (err) {
    return "With error - '" + JSON.stringify(err) + "'";
};

/**
 * Setter for the nativeSettingsHandler.
 *
 * The payload should have the following format:
 *
 * {
 *      "functionName": "FunctionName",
 *      "setParam": val
 * }
 *
 * The first two items:
 *   - function: Function name for the function to be used to set/get the value.
 *   - setParam: Parameter to be passed to the 'set' function.
 *
 * @param {Object} payload The payload.
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.setImpl = function (payload) {
    var pRes = fluid.promise();

    var setFn = windows.nativeSettingsHandler.functions[payload.options.functionName].set;
    var getFn = windows.nativeSettingsHandler.functions[payload.options.functionName].get;

    var results = {};
    var settingsArray = fluid.makeArray(payload.settings);

    var uniqueSetting = settingsArray[0];
    // Get the payload value to set.
    var settingKey = fluid.keys(uniqueSetting)[0];
    var valueToSet = fluid.values(uniqueSetting)[0].value;

    // Create object for storing setting results.
    results[settingKey] = {};
    // Get the current values for the setting.
    var pGetOld = getFn();

    pGetOld.then(
        function (oldVal) {
            // Store the current value in results.
            fluid.set(results[settingKey], "oldValue.value", oldVal);

            var pSet = setFn(valueToSet);

            pSet.then(
                function () {
                    var pGetNew = getFn();

                    pGetNew.then(
                        function (newVal) {
                            fluid.set(results[settingKey], "newValue.value", newVal);

                            pRes.resolve(results);
                        },
                        function (err) {
                            var operation = ": Getting new value for setting '" + settingKey + "' failed.";
                            var getNewValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

                            pRes.reject(getNewValErr);
                        }
                    );
                },
                function (err) {
                    var operation = ": Setting new value for setting '" + settingKey + "' failed.";
                    var setNewValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

                    pRes.reject(setNewValErr);
                }
            );
        },
        function (err) {
            var operation = ": Getting current value for setting '" + settingKey + "' failed.";
            var getOldValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

            pRes.reject(getOldValErr);
        }
    );

    return pRes;
};

/**
 * Getter for the nativeSettingsHandler.
 *
 * @param {Object} payload The payload.
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.getImpl = function (payload) {
    var pRes = fluid.promise();

    var getFn = windows.nativeSettingsHandler.functions[payload.options.functionName].get;

    var settingsArray = fluid.makeArray(payload.settings);
    var uniqueSetting = settingsArray[0];
    var results = {};

    // Get payload setting and prepare results for returning it
    var settingKey = fluid.keys(uniqueSetting)[0];
    results[settingKey] = {};

    var pGetRes = getFn();

    pGetRes.then(
        function (curVal) {
            results[settingKey].value = curVal;

            pRes.resolve(results);
        },
        function (err) {
            var operation = ": Getting current value for setting '" + settingKey + "' failed.";
            var getOldValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

            pRes.reject(getOldValErr);
        }
    );

    return pRes;
};

/**
 * Invoke the settings handler.
 *
 * @param {Object} payload The payload
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.get = function (payload) {
    return gpii.settingsHandlers.invokeSettingsHandler(windows.nativeSettingsHandler.getImpl, payload);
};

/**
 * Invoke the settings handler.
 *
 * @param {Object} payload The payload
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.set = function (payload) {
    return gpii.settingsHandlers.invokeSettingsHandler(windows.nativeSettingsHandler.setImpl, payload);
};
<commit_msg>GPII-3145: SettingsHandler now checks the presence of the requested functions<commit_after>/*
 * Windows Native Settings Handler
 *
 * Deals with individual settings that are only accessible throught isolated
 * API calls.
 *
 * Copyright 2018 Raising the Floor - International
 *
 * Licensed under the New BSD license. You may not use this file except in
 * compliance with this License.
 *
 * The research leading to these results has received funding from the European Union's
 * Seventh Framework Programme (FP7/2007-2013)
 * under grant agreement no. 289016.
 *
 * You may obtain a copy of the License at
 * https://github.com/GPII/universal/blob/master/LICENSE.txt
 */

"use strict";

var fluid = require("gpii-universal"),
    gpii = fluid.registerNamespace("gpii"),
    windows = fluid.registerNamespace("gpii.windows");

require("../../WindowsUtilities/WindowsUtilities.js");

fluid.registerNamespace("gpii.windows.nativeSettingsHandler");

var hndName = "nativeSettingsHandler";

/**
 * Gets the current double click time for mouse.
 *
 * @return {Number} The current system double click time for mouse.
 */
windows.nativeSettingsHandler.GetDoubleClickTime = function () {
    var result = windows.user32.GetDoubleClickTime();

    return fluid.toPromise(result);
};

/**
 * Sets the current double click time for mouse.
 *
 * @param {Number} num The double click time to set in the system.
 * @return {Object} Object with the error information.
 */
windows.nativeSettingsHandler.SetDoubleClickTime = function (num) {
    var pRes = fluid.promise();

    var retVal = windows.user32.SetDoubleClickTime(num);
    if (retVal !== 0) {
        pRes.resolve();
    } else {
        var lastErr = windows.kernel32.GetLastError();
        var lastErrMsg = windows.translateLastError(lastErr);

        pRes.reject({code: lastErr, msg: lastErrMsg});
    }

    return pRes;
};

windows.nativeSettingsHandler.functions = {
    DoubleClickTime: {
        set: windows.nativeSettingsHandler.SetDoubleClickTime,
        get: windows.nativeSettingsHandler.GetDoubleClickTime
    }
};

/**
 * Helper function that converts a error to string, so the rejection from the
 * settings handler only holds a message.
 *
 * @param {Object} err The error to be stringified.
 * @return {String} The error message.
 */
windows.nativeSettingsHandler.errorInfo = function (err) {
    return "With error - '" + JSON.stringify(err) + "'";
};

/**
 * Setter for the nativeSettingsHandler.
 *
 * The payload should have the following format:
 *
 * {
 *      "functionName": "FunctionName",
 *      "setParam": val
 * }
 *
 * The first two items:
 *   - function: Function name for the function to be used to set/get the value.
 *   - setParam: Parameter to be passed to the 'set' function.
 *
 * @param {Object} payload The payload.
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.setImpl = function (payload) {
    var pRes = fluid.promise();

    var fnName = fluid.get(payload, "options.functionName");
    var setFn = fluid.get(windows.nativeSettingsHandler.functions, fnName + ".set");
    var getFn = fluid.get(windows.nativeSettingsHandler.functions, fnName + ".get");
    var fnNotDef = [": Failed due to '", " "+ fnName + "' function not being defined."];

    if (setFn === undefined) {
        pRes.reject(hndName + fnNotDef[0] + "set" + fnNotDef[1]);
    } else if (getFn === undefined) {
        pRes.reject(hndName + fnNotDef[0] + "get" + fnNotDef[1]);
    } else {
        var results = {};
        var settingsArray = fluid.makeArray(payload.settings);

        var uniqueSetting = settingsArray[0];
        // Get the payload value to set.
        var settingKey = fluid.keys(uniqueSetting)[0];
        var valueToSet = fluid.values(uniqueSetting)[0].value;

        // Create object for storing setting results.
        results[settingKey] = {};
        // Get the current values for the setting.
        var pGetOld = getFn();

        pGetOld.then(
            function (oldVal) {
                // Store the current value in results.
                fluid.set(results[settingKey], "oldValue.value", oldVal);

                var pSet = setFn(valueToSet);

                pSet.then(
                    function () {
                        var pGetNew = getFn();

                        pGetNew.then(
                            function (newVal) {
                                fluid.set(results[settingKey], "newValue.value", newVal);

                                pRes.resolve(results);
                            },
                            function (err) {
                                var operation = ": Getting new value for setting '" + settingKey + "' failed.";
                                var getNewValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

                                pRes.reject(getNewValErr);
                            }
                        );
                    },
                    function (err) {
                        var operation = ": Setting new value for setting '" + settingKey + "' failed.";
                        var setNewValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

                        pRes.reject(setNewValErr);
                    }
                );
            },
            function (err) {
                var operation = ": Getting current value for setting '" + settingKey + "' failed.";
                var getOldValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

                pRes.reject(getOldValErr);
            }
        );
    }

    return pRes;
};

/**
 * Getter for the nativeSettingsHandler.
 *
 * @param {Object} payload The payload.
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.getImpl = function (payload) {
    var pRes = fluid.promise();

    var fnName = fluid.get(payload, "options.functionName");
    var getFn = fluid.get(windows.nativeSettingsHandler.functions, fnName + ".get");
    var fnNotDef = [": Failed due to '", " "+ fnName + "' function not being defined."];

    if (getFn === undefined) {
        pRes.reject(hndName + fnNotDef[0] + "get" + fnNotDef[1]);
    } else {
        var settingsArray = fluid.makeArray(payload.settings);
        var uniqueSetting = settingsArray[0];
        var results = {};

        // Get payload setting and prepare results for returning it
        var settingKey = fluid.keys(uniqueSetting)[0];
        results[settingKey] = {};

        var pGetRes = getFn();

        pGetRes.then(
            function (curVal) {
                results[settingKey].value = curVal;

                pRes.resolve(results);
            },
            function (err) {
                var operation = ": Getting current value for setting '" + settingKey + "' failed.";
                var getOldValErr = hndName + operation + windows.nativeSettingsHandler.errorInfo(err);

                pRes.reject(getOldValErr);
            }
        );
    }

    return pRes;
};

/**
 * Invoke the settings handler.
 *
 * @param {Object} payload The payload
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.get = function (payload) {
    return gpii.settingsHandlers.invokeSettingsHandler(windows.nativeSettingsHandler.getImpl, payload);
};

/**
 * Invoke the settings handler.
 *
 * @param {Object} payload The payload
 * @return {Promise} Resolves with the response.
 */
windows.nativeSettingsHandler.set = function (payload) {
    return gpii.settingsHandlers.invokeSettingsHandler(windows.nativeSettingsHandler.setImpl, payload);
};
<|endoftext|>


<commit_before><commit_msg>Remove debug output (not needed)<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

extensibleController('chartCtrl', ['$scope', '$element', '$filter', '$uibModal', 'Session', 'ProjectService', 'SprintService', 'ReleaseService', 'BacklogService', function($scope, $element, $filter, $uibModal, Session, ProjectService, SprintService, ReleaseService, BacklogService) {
    $scope.defaultOptions = {
        chart: {
            height: 350
        }
    };
    $scope.chartLoaders = {
        project: function(chartName, item) {
            return ProjectService.openChart(item ? item : Session.getProject(), chartName);
        },
        release: function(chartName, item) {
            return ReleaseService.openChart(item, chartName);
        },
        sprint: function(chartName, item) {
            return SprintService.openChart(item, item.parentRelease.parentProject ? item.parentRelease.parentProject : ($scope.project ? $scope.project : Session.getProject()), chartName);
        },
        backlog: function(chartName, item) {
            return BacklogService.openChart(item, item.project, chartName);
        }
    };
    $scope.chartOptions = {
        project: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            },
            flowCumulative: {
                chart: {
                    type: 'stackedAreaChart',
                    margin: {right: 45}
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            burnup: {
                chart: {
                    margin: {right: 45}
                }
            },
            velocity: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    },
                    margin: {
                        left: 100
                    }
                }
            }
        },
        release: {
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    },
                    margin: {
                        left: 100
                    }
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    stacked: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            }
        },
        sprint: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    xScale: d3.time.scale.utc(),
                    xAxis: {
                        tickFormat: $filter('dayShorter'),
                        showMaxMin: false
                    }
                }
            }
        },
        backlog: {
            default: {
                chart: {
                    type: 'pieChart',
                    donut: true,
                    height: 200,
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showLabels: true,
                    duration: 500,
                    showLegend: false,
                    margin: {
                        top: 0,
                        right: 0,
                        bottom: 0,
                        left: 0
                    }
                },
                title: {
                    enable: false
                },
                caption: {
                    enable: true
                }
            }
        }
    };
    $scope.openChart = function(itemType, chartName, item, options) {
        $scope.cleanData();
        $scope.chartParams = {
            item: item,
            itemType: itemType,
            chartName: chartName
        };
        $scope.options = _.merge({}, $scope.defaultOptions);
        $scope.options = _.merge($scope.options, $scope.chartOptions[itemType]['default']);
        $scope.options = _.merge($scope.options, $scope.chartOptions[itemType][chartName] ? $scope.chartOptions[itemType][chartName] : {});
        $scope.options = _.merge($scope.options, options ? options : {});
        return $scope.chartLoaders[itemType](chartName, item).then(function(chart) {
            $scope.data = chart.data;
            $scope.options = _.merge($scope.options, chart.options);
            $scope.options = _.merge($scope.options, options);
            $scope.options.title.enable = !_.isEmpty($scope.options.title) && $scope.options.title.enable !== false;
            if (chart.labelsX) {
                $scope.labelsX = chart.labelsX;
            }
            if (chart.labelsY) {
                $scope.labelsY = chart.labelsY;
            }
            if (angular.isFunction($scope.options.chart.height)) {
                $scope.options.chart.height = $scope.options.chart.height($element);
            }
            return chart;
        });
    };
    $scope.processSaveChart = function() {
        var title = $element.find('.title.h4');
        saveChartAsPng($element.find('svg')[0], {}, title[0], function(imageBase64) {
            // Server side "attachment" content type is needed because the a.download HTML5 feature is not supported in crappy browsers (safari & co).
            jQuery.download($scope.serverUrl + '/saveImage', {'image': imageBase64, 'title': title.text()});
        });
    };

    $scope.openChartInModal = function(chartParams) {
        $uibModal.open({
            templateUrl: 'chart.modal.html',
            size: 'wide',
            controller: ["$scope", "$controller", "hotkeys", "$window", function($scope, $controller, hotkeys, $window) {
                $element = angular.element('.modal-wide');
                $controller('chartCtrl', {$scope: $scope, $element: $element});
                $scope.defaultOptions.chart.height = ($window.innerHeight * 75 / 100);
                $scope.openChart(chartParams.itemType, chartParams.chartName, chartParams.item);
                $scope.submit = function() {
                    $scope.$close(true);
                };
                // Required because there is not input so the form cannot be submitted by "return"
                hotkeys.bindTo($scope).add({
                    combo: 'return',
                    callback: function(event) {
                        event.preventDefault(); // Prevents propagation of click to unwanted places
                        $scope.submit();
                    }
                });
            }]
        });
    };
    $scope.saveChart = function(chartParams) {
        $uibModal.open({
            templateUrl: 'chart.modal.html',
            size: 'chart invisible',
            controller: ["$scope", "$controller", "$window", "$timeout", function($scope, $controller, $window, $timeout) {
                $timeout(function() {
                    angular.element('body').addClass('process-chart');
                    $element = angular.element('.modal-chart');
                    $controller('chartCtrl', {$scope: $scope, $element: $element});
                    $scope.defaultOptions.chart.width = 1600;
                    $scope.defaultOptions.chart.height = 800;
                    $scope.openChart(chartParams.itemType, chartParams.chartName, chartParams.item);
                    $timeout(function() {
                        $scope.processSaveChart();
                        $scope.$close(true);
                    }, 500);
                }, 500);
            }]
        });
    };
    $scope.cleanData = function() {
        $scope.data = [];
        $scope.labelsX = [];
        $scope.labelsY = [];
        $scope.options = {};
    };
    // Init
    $scope.cleanData();
}]);

controllers.controller('chartWidgetCtrl', ['$scope', 'WidgetService', 'FormService', 'ProjectService', '$controller', '$element', function($scope, WidgetService, FormService, ProjectService, $controller, $element) {
    $controller('widgetCtrl', {$scope: $scope});
    $controller('chartCtrl', {$scope: $scope, $element: $element});
    $scope.getChartWidgetOptions = function(widget) {
        var chartWidgetOptions = {
            chart: {
                height: function($element) {
                    return $element ? $element.parents('.panel-body')[0].getBoundingClientRect().height : 0;
                }
            },
            title: {
                enable: false
            }
        };
        if (widget.width === 1 || widget.height === 1) {
            chartWidgetOptions = _.merge(chartWidgetOptions, {
                chart: {
                    showXAxis: false,
                    showYAxis: false,
                    showLegend: false,
                    margin: {top: 30, right: 0, bottom: 15, left: 0}
                },
                title: {
                    enable: false
                }
            });
        }
        return chartWidgetOptions;
    }
}]);<commit_msg>Improve parking lot<commit_after>/*
 * Copyright (c) 2016 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

extensibleController('chartCtrl', ['$scope', '$element', '$filter', '$uibModal', 'Session', 'ProjectService', 'SprintService', 'ReleaseService', 'BacklogService', function($scope, $element, $filter, $uibModal, Session, ProjectService, SprintService, ReleaseService, BacklogService) {
    $scope.defaultOptions = {
        chart: {
            height: 350
        }
    };
    $scope.chartLoaders = {
        project: function(chartName, item) {
            return ProjectService.openChart(item ? item : Session.getProject(), chartName);
        },
        release: function(chartName, item) {
            return ReleaseService.openChart(item, chartName);
        },
        sprint: function(chartName, item) {
            return SprintService.openChart(item, item.parentRelease.parentProject ? item.parentRelease.parentProject : ($scope.project ? $scope.project : Session.getProject()), chartName);
        },
        backlog: function(chartName, item) {
            return BacklogService.openChart(item, item.project, chartName);
        }
    };
    $scope.chartOptions = {
        project: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            },
            flowCumulative: {
                chart: {
                    type: 'stackedAreaChart',
                    margin: {right: 45}
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            burnup: {
                chart: {
                    margin: {right: 45}
                }
            },
            velocity: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    },
                    margin: {
                        left: 100
                    },
                    showControls: false
                }
            }
        },
        release: {
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    },
                    margin: {
                        left: 100
                    },
                    showControls: false
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    stacked: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            }
        },
        sprint: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    xScale: d3.time.scale.utc(),
                    xAxis: {
                        tickFormat: $filter('dayShorter'),
                        showMaxMin: false
                    }
                }
            }
        },
        backlog: {
            default: {
                chart: {
                    type: 'pieChart',
                    donut: true,
                    height: 200,
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showLabels: true,
                    duration: 500,
                    showLegend: false,
                    margin: {
                        top: 0,
                        right: 0,
                        bottom: 0,
                        left: 0
                    }
                },
                title: {
                    enable: false
                },
                caption: {
                    enable: true
                }
            }
        }
    };
    $scope.openChart = function(itemType, chartName, item, options) {
        $scope.cleanData();
        $scope.chartParams = {
            item: item,
            itemType: itemType,
            chartName: chartName
        };
        $scope.options = _.merge({}, $scope.defaultOptions);
        $scope.options = _.merge($scope.options, $scope.chartOptions[itemType]['default']);
        $scope.options = _.merge($scope.options, $scope.chartOptions[itemType][chartName] ? $scope.chartOptions[itemType][chartName] : {});
        $scope.options = _.merge($scope.options, options ? options : {});
        return $scope.chartLoaders[itemType](chartName, item).then(function(chart) {
            $scope.data = chart.data;
            $scope.options = _.merge($scope.options, chart.options);
            $scope.options = _.merge($scope.options, options);
            $scope.options.title.enable = !_.isEmpty($scope.options.title) && $scope.options.title.enable !== false;
            if (chart.labelsX) {
                $scope.labelsX = chart.labelsX;
            }
            if (chart.labelsY) {
                $scope.labelsY = chart.labelsY;
            }
            if (angular.isFunction($scope.options.chart.height)) {
                $scope.options.chart.height = $scope.options.chart.height($element);
            }
            return chart;
        });
    };
    $scope.processSaveChart = function() {
        var title = $element.find('.title.h4');
        saveChartAsPng($element.find('svg')[0], {}, title[0], function(imageBase64) {
            // Server side "attachment" content type is needed because the a.download HTML5 feature is not supported in crappy browsers (safari & co).
            jQuery.download($scope.serverUrl + '/saveImage', {'image': imageBase64, 'title': title.text()});
        });
    };

    $scope.openChartInModal = function(chartParams) {
        $uibModal.open({
            templateUrl: 'chart.modal.html',
            size: 'wide',
            controller: ["$scope", "$controller", "hotkeys", "$window", function($scope, $controller, hotkeys, $window) {
                $element = angular.element('.modal-wide');
                $controller('chartCtrl', {$scope: $scope, $element: $element});
                $scope.defaultOptions.chart.height = ($window.innerHeight * 75 / 100);
                $scope.openChart(chartParams.itemType, chartParams.chartName, chartParams.item);
                $scope.submit = function() {
                    $scope.$close(true);
                };
                // Required because there is not input so the form cannot be submitted by "return"
                hotkeys.bindTo($scope).add({
                    combo: 'return',
                    callback: function(event) {
                        event.preventDefault(); // Prevents propagation of click to unwanted places
                        $scope.submit();
                    }
                });
            }]
        });
    };
    $scope.saveChart = function(chartParams) {
        $uibModal.open({
            templateUrl: 'chart.modal.html',
            size: 'chart invisible',
            controller: ["$scope", "$controller", "$window", "$timeout", function($scope, $controller, $window, $timeout) {
                $timeout(function() {
                    angular.element('body').addClass('process-chart');
                    $element = angular.element('.modal-chart');
                    $controller('chartCtrl', {$scope: $scope, $element: $element});
                    $scope.defaultOptions.chart.width = 1600;
                    $scope.defaultOptions.chart.height = 800;
                    $scope.openChart(chartParams.itemType, chartParams.chartName, chartParams.item);
                    $timeout(function() {
                        $scope.processSaveChart();
                        $scope.$close(true);
                    }, 500);
                }, 500);
            }]
        });
    };
    $scope.cleanData = function() {
        $scope.data = [];
        $scope.labelsX = [];
        $scope.labelsY = [];
        $scope.options = {};
    };
    // Init
    $scope.cleanData();
}]);

controllers.controller('chartWidgetCtrl', ['$scope', 'WidgetService', 'FormService', 'ProjectService', '$controller', '$element', function($scope, WidgetService, FormService, ProjectService, $controller, $element) {
    $controller('widgetCtrl', {$scope: $scope});
    $controller('chartCtrl', {$scope: $scope, $element: $element});
    $scope.getChartWidgetOptions = function(widget) {
        var chartWidgetOptions = {
            chart: {
                height: function($element) {
                    return $element ? $element.parents('.panel-body')[0].getBoundingClientRect().height : 0;
                }
            },
            title: {
                enable: false
            }
        };
        if (widget.width === 1 || widget.height === 1) {
            chartWidgetOptions = _.merge(chartWidgetOptions, {
                chart: {
                    showXAxis: false,
                    showYAxis: false,
                    showLegend: false,
                    margin: {top: 30, right: 0, bottom: 15, left: 0}
                },
                title: {
                    enable: false
                }
            });
        }
        return chartWidgetOptions;
    }
}]);<|endoftext|>


<commit_before>'use strict';

var app = require('app');
var BrowserWindow = require('browser-window');
var Menu = require('menu');

var mainWindow = null;

var menu = Menu.buildFromTemplate([
  {
    label: 'er',
    submenu: [
      {
        label: 'About',
        role: 'about'
      },
      {
        type: 'separator'
      },
      {
        label: 'Quit',
        accelerator: 'Command+Q',
        click: function() { app.quit(); }
      }
    ]
  }
]);
Menu.setApplicationMenu(menu);

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    quit();
  }
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({width: 800, height: 600, center: true});
  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});
<commit_msg>Fix menu is not shown.<commit_after>'use strict';

var app = require('app');
var BrowserWindow = require('browser-window');
var Menu = require('menu');

var mainWindow = null;

var menu = Menu.buildFromTemplate([
  {
    label: 'er',
    submenu: [
      {
        label: 'About',
        role: 'about'
      },
      {
        type: 'separator'
      },
      {
        label: 'Quit',
        accelerator: 'Command+Q',
        click: function() { app.quit(); }
      }
    ]
  }
]);

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    quit();
  }
});

app.on('ready', function() {
  Menu.setApplicationMenu(menu);
  mainWindow = new BrowserWindow({width: 800, height: 600, center: true});
  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});
<|endoftext|>