<commit_before>import React from "react";
import kofi from "kofi";
import {If, Renderer} from "neutrine/lib/components";

import {Splash} from "../../components/Splash/index.js";
import {SandboxConfig} from "../../components/SandboxConfig/index.js";
import {SandboxExport} from "../../components/SandboxExport/index.js";
import {SandboxHeader} from "../../components/SandboxHeader/index.js";
import {SandboxEditor} from "../../components/SandboxEditor/index.js";
import {getLocalSandbox, updateLocalSandbox, deleteLocalSandbox} from "../../utils/sandbox.js";
import {getRemoteSandbox} from "../../utils/sandbox.js";
import {createSandbox, parseSandbox} from "../../utils/sandbox.js";
import {redirect, redirectToSandbox} from "../../utils/redirect.js";
import style from "./style.scss";

//Generate a dialog to delete the sandbox
let deleteSandboxDialog = function (cb) {
    //Display a confirmation dialog
    return window.confirm.show({
        "title": "Delete sandbox",
        "content": "This will remove this sandbox from your computer. This action can not be undone. Continue?",
        "onConfirm": cb,
        "confirmText": "Yes, delete",
        "cancelText": "Cancel"
    });
};

//Export sandbox editor component
export class EditorPage extends React.Component {
    constructor(props) {
        super(props);
        //Initial state
        this.state = {
            "loading": true,
            "configVisible": false,
            "exportVisible": false,
            "local": false,
            "sandbox": {}
        };
        //Referenced elements
        this.ref = {
            "editor": React.createRef()
        };
        //Bind sandbox management methods
        this.loadSandbox = this.loadSandbox.bind(this);
        this.saveSandbox = this.saveSandbox.bind(this);
        this.updateSandbox = this.updateSandbox.bind(this);
        this.handleSave = this.handleSave.bind(this);
        this.handleExit = this.handleExit.bind(this);
        this.handleDelete = this.handleDelete.bind(this);
        //this.handleExport = this.handleExport.bind(this);
        this.handleUpdate = this.handleUpdate.bind(this);
        this.handleConfigToggle = this.handleConfigToggle.bind(this);
        this.handleExportOpen = this.handleExportOpen.bind(this);
        this.handleExportClose = this.handleExportClose.bind(this);
    }
    //Component did mount
    componentDidMount() {
        return this.loadSandbox();
    }
    //Save a sandbox
    saveSandbox(sandbox, forceSave) {
        if (this.state.local === false && forceSave !== true) {
            return Promise.resolve(sandbox); //Do not save the sandbox
        }
        //Update the sandbox
        return updateLocalSandbox(sandbox);
    }
    //Update sandbox with new data
    updateSandbox(newData, callback) {
        let self = this;
        //let sandbox = null; //Object.assign(this.ref.editor.current.getSandbox(), newData);
        return this.ref.editor.current.getSandbox().then(function (sandbox) {
            sandbox = Object.assign(sandbox, newData); //Update sandbox data
            //Save new sandbox data
            return self.setState({"sandbox": sandbox}, function () {
                return self.saveSandbox(sandbox, false).then(function () {
                    window.toast.success({"message": "Sandbox saved"}); //Display confirmation
                    if (typeof callback === "function") {
                        return callback();
                    }
                });
            });
        });
    }
    //Load a sandbox
    loadSandbox() {
        let self = this;
        let isLocalSandbox = false; //To save if this sandbox is stored in local
        let params = this.props.request.query;
        //Update the state before start loading the sandbox
        return this.setState({"loading": true}, function () {
            return kofi.delay(1000).then(function () {
                //Check for url sandbox
                if (typeof params.url === "string") {
                    return getRemoteSandbox(decodeURIComponent(params.url));
                }
                //Check for sandbox id
                else if (typeof params.sandbox === "string") {
                    isLocalSandbox = true; //Local sandbox
                    return getLocalSandbox(decodeURIComponent(params.sandbox));
                }
                //Other --> unknown sandbox source
                return Promise.reject(new Error("Unknown sandbox source"));
            }).then(function (newSandbox) {
                console.log(newSandbox); //Only for debugging
                if (newSandbox === null || typeof newSandbox === "undefined") {
                    return Promise.reject(new Error("Sandbox not found"));
                }
                //Save the sandbox
                return self.setState({
                    "loading": false,
                    "local": isLocalSandbox,
                    "sandbox": createSandbox(newSandbox)
                });
            }).catch(function (error) {
                console.error(error);
                //TODO: threat error
                return null;
            });
        });
    }
    //Handle editor exit
    handleExit() {
        let self = this;
        //let sandbox = this.ref.editor.current.getSandbox();
        this.ref.editor.current.getSandbox().then(function (sandbox) {
            return self.saveSandbox(sandbox, false).then(function () {
                return redirect("/");
            });
        });
    }
    //Handle delete sandbox
    handleDelete() {
        let self = this;
        let sandbox = this.state.sandbox; //Get sandbox
        //Check for no local sandbox --> do not remove it
        if (this.state.local === false) {
            return; //You can not delete a non-local sandbox
        }
        //Didsplay the delete dialog
        return deleteSandboxDialog(function () {
            return deleteLocalSandbox(sandbox.id).then(function () {
                window.toast.success({"message": "Sandbox removed"}); //Display confirmation
                return redirect("/"); //Redirect to home
            });
        });
    }
    //Handle save
    handleSave() {
        let self = this;
        //let sandbox = this.ref.editor.current.getSandbox();
        this.ref.editor.current.getSandbox().then(function (sandbox) {
            //Check for local sandbox ---> save it without asking
            if (self.state.local === true) {
                return self.saveSandbox(sandbox, false).then(function (newSandbox) {
                    window.toast.success({"message": "Sandbox saved"});
                    return self.setState({"sandbox": newSandbox});
                });
            }
            //No local sandbox --> ask for saving as a new local sandbox
            return window.confirm.show({
                "title": "Clone and save sandbox",
                "content": "You can not save a remote sandbox. Do you want to create a local clone of this sandbox?",
                "onConfirm": function () {
                    let newSandbox = Object.assign(createSandbox(sandbox), {
                        "readonly": false, //Disable readonly
                        "created_at": Date.now() //Update the sandbox creation date
                    });
                    return self.saveSandbox(sandbox, true).then(function () {
                        window.toast.success({"message": "Sandbox cloned"}); //Show confirmation toast
                        let newState = {
                            "sandbox": newSandbox,
                            "local": true
                        };
                        return self.setState(newState, function () {
                            return redirectToSandbox("sandbox", newSandbox.id);
                        });
                    });
                },
                "confirmText": "Yes, create a clone"
            });
        });
    }
    //Handle export view open
    handleExportOpen() {
        let self = this;
        return this.ref.editor.current.getSandbox().then(function (sandbox) {
            return self.setState({
                "sandbox": sandbox,
                "exportVisible": true
            });
        });
    }
    //Handle export close
    handleExportClose() {
        return this.setState({"exportVisible": false});
    }
    //Handle config modal toggle
    handleConfigToggle() {
        return this.setState({
            "configVisible": !this.state.configVisible
        });
    }
    //Handle sandbox metadata update
    handleUpdate(newData) {
        let self = this;
        if (this.state.local === false) {
            return null; //Not local sandbox --> disable metadata update
        }
        //Update the sandbox and hide config modal
        return this.updateSandbox(newData, function () {
            return self.setState({"configVisible": false});
        });
    }
    //Handle sandbox update
    handleSandboxUpdate(newSandbox, callback) {
        return this.setState({"sandbox": newSandbox}, function () {
            return callback();
        });
    }
    //Render the editor
    render() {
        let self = this;
        //Check for loading --> display the loading animation
        if (this.state.loading === true) {
            return React.createElement(Splash, {});
        }
        console.log("---> update editor");
        //Render the editor panels
        return (

                {/* Sandbox header */}

                    <Renderer render={function () {
                        return React.createElement(SandboxHeader, {
                            "sandbox": self.state.sandbox,
                            //"menuActive": self.state.menuVisible,
                            "onLogoClick": self.handleExit,
                            "onSaveClick": self.handleSave,
                            "onExportClick": self.handleExportOpen,
                            "onConfigClick": self.handleConfigToggle,
                            "onDeleteClick": self.handleDelete
                        });
                    }} />

                {/* Sandbox editor */}

                    <Renderer render={function () {
                        return React.createElement(SandboxEditor, {
                            "ref": self.ref.editor,
                            "sandbox": self.state.sandbox,
                            "onSandboxUpdate": self.handleSandboxUpdate
                        });
                    }} />

                {/* Config sandbox modal */}
                <If condition={this.state.configVisible} render={function () {
                    return React.createElement(SandboxConfig, {
                        "onClose": self.handleConfigToggle,
                        "onSubmit": self.handleUpdate,
                        "sandbox": self.state.sandbox,
                        "localSandbox": self.state.local
                    });
                }} />
                {/* Export sandbox modal */}
                <If condition={this.state.exportVisible} render={function () {
                    return React.createElement(SandboxExport, {
                        "sandbox": self.state.sandbox,
                        "onClose": self.handleExportClose
                    });
                }} />

        );
    }
}

//Sandbox editor default props
EditorPage.defaultProps = {};

<commit_msg>lab: minor fixes in Editor page component for working with sandbox files<commit_after>import React from "react";
import kofi from "kofi";
import {If, Renderer} from "neutrine/lib/components";

import {Splash} from "../../components/Splash/index.js";
import {SandboxConfig} from "../../components/SandboxConfig/index.js";
import {SandboxExport} from "../../components/SandboxExport/index.js";
import {SandboxHeader} from "../../components/SandboxHeader/index.js";
import {SandboxEditor} from "../../components/SandboxEditor/index.js";
import {getLocalSandbox, updateLocalSandbox, deleteLocalSandbox} from "../../utils/sandbox.js";
import {getRemoteSandbox} from "../../utils/sandbox.js";
import {createSandbox, parseSandbox} from "../../utils/sandbox.js";
import {redirect, redirectToSandbox} from "../../utils/redirect.js";
import style from "./style.scss";

//Generate a dialog to delete the sandbox
let deleteSandboxDialog = function (cb) {
    //Display a confirmation dialog
    return window.confirm.show({
        "title": "Delete sandbox",
        "content": "This will remove this sandbox from your computer. This action can not be undone. Continue?",
        "onConfirm": cb,
        "confirmText": "Yes, delete",
        "cancelText": "Cancel"
    });
};

//Export sandbox editor component
export class EditorPage extends React.Component {
    constructor(props) {
        super(props);
        //Initial state
        this.state = {
            "loading": true,
            "configVisible": false,
            "exportVisible": false,
            "local": false,
            "sandbox": {}
        };
        //Referenced elements
        this.ref = {
            "editor": React.createRef()
        };
        //Bind sandbox management methods
        this.loadSandbox = this.loadSandbox.bind(this);
        this.saveSandbox = this.saveSandbox.bind(this);
        this.updateSandbox = this.updateSandbox.bind(this);
        this.handleSave = this.handleSave.bind(this);
        this.handleExit = this.handleExit.bind(this);
        this.handleDelete = this.handleDelete.bind(this);
        //this.handleExport = this.handleExport.bind(this);
        this.handleUpdate = this.handleUpdate.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.handleConfigToggle = this.handleConfigToggle.bind(this);
        this.handleExportOpen = this.handleExportOpen.bind(this);
        this.handleExportClose = this.handleExportClose.bind(this);
    }
    //Component did mount
    componentDidMount() {
        return this.loadSandbox();
    }
    //Save a sandbox
    saveSandbox(sandbox, forceSave) {
        if (this.state.local === false && forceSave !== true) {
            return Promise.resolve(sandbox); //Do not save the sandbox
        }
        //Update the sandbox
        return updateLocalSandbox(sandbox);
    }
    //Update sandbox with new data
    updateSandbox(newData, callback) {
        let self = this;
        //let sandbox = null; //Object.assign(this.ref.editor.current.getSandbox(), newData);
        return this.ref.editor.current.getSandbox().then(function (sandbox) {
            sandbox = Object.assign(sandbox, newData); //Update sandbox data
            //Save new sandbox data
            return self.setState({"sandbox": sandbox}, function () {
                return self.saveSandbox(sandbox, false).then(function () {
                    window.toast.success({"message": "Sandbox saved"}); //Display confirmation
                    if (typeof callback === "function") {
                        return callback();
                    }
                });
            });
        });
    }
    //Load a sandbox
    loadSandbox() {
        let self = this;
        let isLocalSandbox = false; //To save if this sandbox is stored in local
        let params = this.props.request.query;
        //Update the state before start loading the sandbox
        return this.setState({"loading": true}, function () {
            return kofi.delay(1000).then(function () {
                //Check for url sandbox
                if (typeof params.url === "string") {
                    return getRemoteSandbox(decodeURIComponent(params.url));
                }
                //Check for sandbox id
                else if (typeof params.sandbox === "string") {
                    isLocalSandbox = true; //Local sandbox
                    return getLocalSandbox(decodeURIComponent(params.sandbox));
                }
                //Other --> unknown sandbox source
                return Promise.reject(new Error("Unknown sandbox source"));
            }).then(function (newSandbox) {
                console.log(newSandbox); //Only for debugging
                if (newSandbox === null || typeof newSandbox === "undefined") {
                    return Promise.reject(new Error("Sandbox not found"));
                }
                //Save the sandbox
                return self.setState({
                    "loading": false,
                    "local": isLocalSandbox,
                    "sandbox": createSandbox(newSandbox)
                });
            }).catch(function (error) {
                console.error(error);
                //TODO: threat error
                return null;
            });
        });
    }
    //Handle editor exit
    handleExit() {
        let self = this;
        //let sandbox = this.ref.editor.current.getSandbox();
        this.ref.editor.current.getSandbox().then(function (sandbox) {
            return self.saveSandbox(sandbox, false).then(function () {
                return redirect("/");
            });
        });
    }
    //Handle delete sandbox
    handleDelete() {
        let self = this;
        let sandbox = this.state.sandbox; //Get sandbox
        //Check for no local sandbox --> do not remove it
        if (this.state.local === false) {
            return; //You can not delete a non-local sandbox
        }
        //Didsplay the delete dialog
        return deleteSandboxDialog(function () {
            return deleteLocalSandbox(sandbox.id).then(function () {
                window.toast.success({"message": "Sandbox removed"}); //Display confirmation
                return redirect("/"); //Redirect to home
            });
        });
    }
    //Handle save
    handleSave() {
        let self = this;
        //let sandbox = this.ref.editor.current.getSandbox();
        this.ref.editor.current.getSandbox().then(function (sandbox) {
            //Check for local sandbox ---> save it without asking
            if (self.state.local === true) {
                return self.saveSandbox(sandbox, false).then(function (newSandbox) {
                    window.toast.success({"message": "Sandbox saved"});
                    return self.setState({"sandbox": newSandbox});
                });
            }
            //No local sandbox --> ask for saving as a new local sandbox
            return window.confirm.show({
                "title": "Clone and save sandbox",
                "content": "You can not save a remote sandbox. Do you want to create a local clone of this sandbox?",
                "onConfirm": function () {
                    let newSandbox = Object.assign(createSandbox(sandbox), {
                        "readonly": false, //Disable readonly
                        "created_at": Date.now() //Update the sandbox creation date
                    });
                    return self.saveSandbox(sandbox, true).then(function () {
                        window.toast.success({"message": "Sandbox cloned"}); //Show confirmation toast
                        let newState = {
                            "sandbox": newSandbox,
                            "local": true
                        };
                        return self.setState(newState, function () {
                            return redirectToSandbox("sandbox", newSandbox.id);
                        });
                    });
                },
                "confirmText": "Yes, create a clone"
            });
        });
    }
    //Handle export view open
    handleExportOpen() {
        let self = this;
        return this.ref.editor.current.getSandbox().then(function (sandbox) {
            return self.setState({
                "sandbox": sandbox,
                "exportVisible": true
            });
        });
    }
    //Handle export close
    handleExportClose() {
        return this.setState({"exportVisible": false});
    }
    //Handle config modal toggle
    handleConfigToggle() {
        return this.setState({
            "configVisible": !this.state.configVisible
        });
    }
    //Handle sandbox metadata update
    handleUpdate(newData) {
        let self = this;
        if (this.state.local === false) {
            return null; //Not local sandbox --> disable metadata update
        }
        //Update the sandbox and hide config modal
        return this.updateSandbox(newData, function () {
            return self.setState({"configVisible": false});
        });
    }
    //Handle sandbox change
    handleChange(newSandbox, callback) {
        let self = this;
        //return this.setState({"sandbox": newSandbox}, function () {
        //    return callback();
        //});
        return this.saveSandbox(newSandbox, false).then(function () {
            return self.setState({"sandbox": newSandbox}, function () {
                return callback();
            });
        });
    }
    //Render the editor
    render() {
        let self = this;
        //Check for loading --> display the loading animation
        if (this.state.loading === true) {
            return React.createElement(Splash, {});
        }
        console.log("---> update editor");
        //Render the editor panels
        return (

                {/* Sandbox header */}

                    <Renderer render={function () {
                        return React.createElement(SandboxHeader, {
                            "sandbox": self.state.sandbox,
                            //"menuActive": self.state.menuVisible,
                            "onLogoClick": self.handleExit,
                            "onSaveClick": self.handleSave,
                            "onExportClick": self.handleExportOpen,
                            "onConfigClick": self.handleConfigToggle,
                            "onDeleteClick": self.handleDelete
                        });
                    }} />

                {/* Sandbox editor */}

                    <Renderer render={function () {
                        return React.createElement(SandboxEditor, {
                            "ref": self.ref.editor,
                            "sandbox": self.state.sandbox,
                            "onChange": self.handleChange
                        });
                    }} />

                {/* Config sandbox modal */}
                <If condition={this.state.configVisible} render={function () {
                    return React.createElement(SandboxConfig, {
                        "onClose": self.handleConfigToggle,
                        "onSubmit": self.handleUpdate,
                        "sandbox": self.state.sandbox,
                        "localSandbox": self.state.local
                    });
                }} />
                {/* Export sandbox modal */}
                <If condition={this.state.exportVisible} render={function () {
                    return React.createElement(SandboxExport, {
                        "sandbox": self.state.sandbox,
                        "onClose": self.handleExportClose
                    });
                }} />

        );
    }
}

//Sandbox editor default props
EditorPage.defaultProps = {};

<|endoftext|>


<commit_before>var app;
var express;

function implementStructurePath(structure) {
  app.get(structure.url_prefix, function(req, res) {
    res.json(structure);
  });
}

function customRouter(path, router_module, application) {
  var router = express.Router();
  router_module(router);
  app.use(prefix, router);
}

module.exports = function(a, e) {
  app = a;
  express = e;

  var module = {};

  module.path = implementStructurePath;
  module.customRouter = customRouter;

  return module;
}
<commit_msg>Changes prefix to path<commit_after>var app;
var express;

function implementStructurePath(structure) {
  app.get(structure.url_prefix, function(req, res) {
    res.json(structure);
  });
}

function customRouter(path, router_module, application) {
  var router = express.Router();
  router_module(router);
  app.use(path, router);
}

module.exports = function(a, e) {
  app = a;
  express = e;

  var module = {};

  module.path = implementStructurePath;
  module.customRouter = customRouter;

  return module;
}
<|endoftext|>


<commit_before>/*
 * routes.js - module to provide routing
*/

/*jslint         node    : true, continue : true,
  devel  : true, indent  : 2,    maxerr   : 50,
  newcap : true, nomen   : true, plusplus : true,
  regexp : true, sloppy  : true, vars     : false,
  white  : true
*/
/*global */

// ------------ BEGIN MODULE SCOPE VARIABLES --------------
'use strict';
var
  configRoutes,
  mongodb     = require( 'mongodb' ),

  mongoServer = new mongodb.Server(
    'localhost',
    mongodb.Connection.DEFAULT_PORT
  ),
  dbHandle    = new mongodb.Db(
    'cemcollection', mongoServer, { safe : true }
  ),

  makeMongoId = mongodb.ObjectID;
// ------------- END MODULE SCOPE VARIABLES ---------------

// ---------------- BEGIN PUBLIC METHODS ------------------

// This probably doesn't belong here, but for now . . .
var booleans = { "cemetery": { "hasReading": false, "hasRegistry": false, "isActive": false },  "geolocation": { "isBox": false } },
key_name,
check_map,
id;

configRoutes = function ( app, server ) {
  app.all( '/:obj_type/*?', function ( request, response, next ) {
    response.contentType( 'json' );
    next();
  });

  app.post( '/:obj_type/create', function ( request, response ) {
    // Do you smell a kludge here?
    // Get next ID for appropriate collection
    var dbName = request.params.obj_type;
    dbHandle.collection(
        'counters',
        function ( outer_error, collection ) {
        var
          sort_order = [],
          options_map = {
            'new' : true, safe: true, fsync: true
          };
        collection.findAndModify(
            { _id: dbName },
            [[ '_id',1]],
            { $inc: { seq: 1 } },
            {new: true, fsync: true},
        function(err, doc){
          console.log('Retval #1: ' + doc.seq);
	  id = doc.seq;
          }
          ); // findAndModify
        } // outer function
    ); // collection operation
    // Now make this one wait. . . dammit
    setTimeout(function() {dbHandle.collection(
      request.params.obj_type,
      function ( outer_error, collection ) {
        var
          options_map = { safe: true },
          obj_map     = request.body;
	  // Insert false values for unsent booleans
	  // Is there a better way of doing this??  Tell me please!!
	  console.log(request.params.obj_type);
	  var inputMap = JSON.parse(obj_map.json);
	  console.log('Input map: ' + inputMap);
	  check_map = booleans[request.params.obj_type];
	  for ( key_name in check_map ) {
		if ( !(inputMap.hasOwnProperty( key_name )) ) {
		  inputMap[key_name] = check_map[key_name];
		  }
	  	};
	  // Flush contents of check_map for next run
	  for (var member in check_map) delete check_map[member];
	  // Add call to set primary key (depending on object type)
          console.log('Going to use: ' + id);
	  // You can only do this once
	  inputMap['_id'] = id;
	  console.log(inputMap);
          collection.insert(
            inputMap,
            options_map,
            function ( inner_error, result_map ) {
	      // I think we should return the _id here, if possible
	      // But ATM I don't know how. . .
              response.send( inputMap );
              }
          ); // end insert
        } // end outer func
    ); // end handler
   },100);
  });

  app.post( '/:obj_type/update/:id', function ( request, response ) {
    var
      find_map = { _id: makeMongoId( request.params.id ) },
      obj_map  = request.body;

    dbHandle.collection(
      request.params.obj_type,
      function ( outer_error, collection ) {
        var
          sort_order = [],
          options_map = {
            'new' : true, upsert: false, safe: true
          };

        collection.findAndModify(
          find_map,
          sort_order,
          obj_map,
          options_map,
          function ( inner_error, updated_map ) {
            response.send( updated_map );
          }
        );
      }
    );
  });

  app.get( '/:obj_type/delete/:id', function ( request, response ) {
    var find_map = { _id: makeMongoId( request.params.id ) };

    dbHandle.collection(
      request.params.obj_type,
      function ( outer_error, collection ) {
        var options_map = { safe: true, single: true };

        collection.remove(
          find_map,
          options_map,
          function ( inner_error, delete_count ) {
            response.send({ delete_count: delete_count });
          }
        );
      }
    );
  });
};

module.exports = { configRoutes : configRoutes };
// ----------------- END PUBLIC METHODS -------------------

// ------------- BEGIN MODULE INITIALIZATION --------------
dbHandle.open( function () {
  console.log( '** Connected to MongoDB **' );
});
// -------------- END MODULE INITIALIZATION ---------------
<commit_msg>Clean up and comment recent changes<commit_after>/*
 * routes.js - module to provide routing
*/

/*jslint         node    : true, continue : true,
  devel  : true, indent  : 2,    maxerr   : 50,
  newcap : true, nomen   : true, plusplus : true,
  regexp : true, sloppy  : true, vars     : false,
  white  : true
*/
/*global */

// ------------ BEGIN MODULE SCOPE VARIABLES --------------
'use strict';
var
  configRoutes,
  mongodb     = require( 'mongodb' ),

  mongoServer = new mongodb.Server(
    'localhost',
    mongodb.Connection.DEFAULT_PORT
  ),
  dbHandle    = new mongodb.Db(
    'cemcollection', mongoServer, { safe : true }
  ),

  makeMongoId = mongodb.ObjectID;
// ------------- END MODULE SCOPE VARIABLES ---------------

// ---------------- BEGIN PUBLIC METHODS ------------------

// This probably doesn't belong here, but for now . . .
var booleans = { "cemetery": { "hasReading": false, "hasRegistry": false, "isActive": false },  "geolocation": { "isBox": false } },
key_name,
check_map,
id;

configRoutes = function ( app, server ) {
  app.all( '/:obj_type/*?', function ( request, response, next ) {
    response.contentType( 'json' );
    next();
  });

  app.post( '/:obj_type/create', function ( request, response ) {

    // Do you smell a kludge here?
    // Get next ID for appropriate collection
    var dbName = request.params.obj_type;
    dbHandle.collection(
        'counters',
        function ( outer_error, collection ) {
        var
          sort_order = [],
          options_map = {
            'new' : true, safe: true, fsync: true
          };
        collection.findAndModify(
            { _id: dbName },
            [[ '_id',1]],
            { $inc: { seq: 1 } },
            {new: true, fsync: true},
        function(err, doc){
          console.log('Retval #1: ' + doc.seq);
	  id = doc.seq;
          }
          ); // findAndModify
        } // outer function
    ); // collection operation

    // Now make the create operation wait . . . dammit
    // Timeout seems needed by wait for sequence fetch
    setTimeout(function() {dbHandle.collection(
      request.params.obj_type,
      function ( outer_error, collection ) {
        var
          options_map = { safe: true },
          obj_map     = request.body;

	  // Insert false values for unsent booleans
	  // Is there a better way of doing this??  Tell me please!!
	  console.log(request.params.obj_type);
	  var inputMap = JSON.parse(obj_map.json);
	  console.log('Input map: ' + inputMap);
	  check_map = booleans[request.params.obj_type];
	  for ( key_name in check_map ) {
		if ( !(inputMap.hasOwnProperty( key_name )) ) {
		  inputMap[key_name] = check_map[key_name];
		  }
	  	};
	  // Flush contents of check_map for next run
	  for (var member in check_map) delete check_map[member];

	  // Set primary key (depending on object type)
	  inputMap['_id'] = id;
	  console.log(inputMap);

	  // Write full record to database, including generated key
          collection.insert(
            inputMap,
            options_map,
            function ( inner_error, result_map ) {
	      // I think we should return the _id here, if possible
	      // But ATM I don't know how. . .
              response.send( inputMap );
              }
          ); // end insert
        } // end outer func
    ); // end handler
   },100);
  });

  app.post( '/:obj_type/update/:id', function ( request, response ) {
    var
      find_map = { _id: makeMongoId( request.params.id ) },
      obj_map  = request.body;

    dbHandle.collection(
      request.params.obj_type,
      function ( outer_error, collection ) {
        var
          sort_order = [],
          options_map = {
            'new' : true, upsert: false, safe: true
          };

        collection.findAndModify(
          find_map,
          sort_order,
          obj_map,
          options_map,
          function ( inner_error, updated_map ) {
            response.send( updated_map );
          }
        );
      }
    );
  });

  app.get( '/:obj_type/delete/:id', function ( request, response ) {
    var find_map = { _id: makeMongoId( request.params.id ) };

    dbHandle.collection(
      request.params.obj_type,
      function ( outer_error, collection ) {
        var options_map = { safe: true, single: true };

        collection.remove(
          find_map,
          options_map,
          function ( inner_error, delete_count ) {
            response.send({ delete_count: delete_count });
          }
        );
      }
    );
  });
};

module.exports = { configRoutes : configRoutes };
// ----------------- END PUBLIC METHODS -------------------

// ------------- BEGIN MODULE INITIALIZATION --------------
dbHandle.open( function () {
  console.log( '** Connected to MongoDB **' );
});
// -------------- END MODULE INITIALIZATION ---------------
<|endoftext|>


<commit_before>const express = require('express')
require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` })

const app = express()
app.set('view engine', 'pug')
const PORT = 3000

// Utils

const toHex = (value) => value.toString(16)

// Conversion logics

const conversionValues = {
  signup: 1,
  'add-to-cart': 2,
  checkout: 3
}

// Reports

let reports = []

// Server

app.use(express.static('static'))

app.get('/', (req, res) => {
  res.render('index')
})

app.get('/ad', (req, res) => {
  const href = `${process.env.ADVERTISER_URL}/shoes07`
  const conversionDestination = process.env.ADVERTISER_URL
  const reportingOrigin = process.env.ADTECH_URL
  res.render('ad', {
    href,
    conversiondestination: conversionDestination,
    reportingorigin: reportingOrigin
  })
})

// TODO rename "script"
app.get('/script', (req, res) => {
  res.set('Content-Type', 'text/javascript')
  const adUrl = `${process.env.ADTECH_URL}/ad`
  res.send(
    `console.log('✔ Loaded adtech script'); document.write("<iframe src='${adUrl}' allow='conversion-measurement' width=200 height=230 scrolling=no frameborder=1 padding=0></iframe>")`
  )
})

app.get('/conversion', (req, res) => {
  const conversionData = conversionValues[req.query.type]
  const encodedConversionData = toHex(conversionData)
  res.redirect(
    302,
    `/.well-known/register-conversion?conversion-data=${encodedConversionData}`
  )
})

app.get('/reports', (req, res) => {
  res.send(JSON.stringify(reports))
})

app.post('/*', (req, res) => {
  const newReport = req.query
  console.log(req.query)
  reports = [...reports, newReport]
  // TODO response OK
})

const listener = app.listen(process.env.PORT || PORT, () => {
  console.log(
    '🚀 Adtech server is listening on port ' + listener.address().port
  )
})
<commit_msg>feat: send OK server response<commit_after>const express = require('express')
require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` })

const app = express()
app.set('view engine', 'pug')
const PORT = 3000

// Utils

const toHex = (value) => value.toString(16)

// Conversion logics

const conversionValues = {
  signup: 1,
  'add-to-cart': 2,
  checkout: 3
}

// Reports

let reports = []

// Server

app.use(express.static('static'))

app.get('/', (req, res) => {
  res.render('index')
})

app.get('/ad', (req, res) => {
  const href = `${process.env.ADVERTISER_URL}/shoes07`
  const conversionDestination = process.env.ADVERTISER_URL
  const reportingOrigin = process.env.ADTECH_URL
  res.render('ad', {
    href,
    conversiondestination: conversionDestination,
    reportingorigin: reportingOrigin
  })
})

// TODO rename "script"
app.get('/script', (req, res) => {
  res.set('Content-Type', 'text/javascript')
  const adUrl = `${process.env.ADTECH_URL}/ad`
  res.send(
    `console.log('✔ Loaded adtech script'); document.write("<iframe src='${adUrl}' allow='conversion-measurement' width=200 height=230 scrolling=no frameborder=1 padding=0></iframe>")`
  )
})

app.get('/conversion', (req, res) => {
  const conversionData = conversionValues[req.query.type]
  const encodedConversionData = toHex(conversionData)
  res.redirect(
    302,
    `/.well-known/register-conversion?conversion-data=${encodedConversionData}`
  )
})

app.get('/reports', (req, res) => {
  res.send(JSON.stringify(reports))
})

app.post('/*', (req, res) => {
  const newReport = req.query
  console.log(req.query)
  reports = [...reports, newReport]
  res.sendStatus(200)
})

const listener = app.listen(process.env.PORT || PORT, () => {
  console.log(
    '🚀 Adtech server is listening on port ' + listener.address().port
  )
})
<|endoftext|>


<commit_before>const DrawCard = require('../../drawcard.js');
const { Players, PlayTypes } = require('../../Constants');

class AkodoToturi2 extends DrawCard {
    setupCardAbilities(ability) {
        this.action({
            title: 'Prevent each player playing cards from hand',
            condition: context => context.source.isParticipating() && context.player.imperialFavor !== '',
            effect: 'prevent each player playing cards from hand',
            gameAction: [
                ability.actions.playerLastingEffect({
                    targetController: Players.Any,
                    effect: ability.effects.playerCannot({
                        cannot: PlayTypes.PlayFromHand
                    })
                })
            ]
        });
    }
}

AkodoToturi2.id = 'akodo-toturi-neutral';

module.exports = AkodoToturi2;
<commit_msg>Update AkodoToturi2.js<commit_after>const DrawCard = require('../../drawcard.js');
const { Players, PlayTypes } = require('../../Constants');

class AkodoToturi2 extends DrawCard {
    setupCardAbilities(ability) {
        this.action({
            title: 'Prevent each player playing cards from hand',
            condition: context => context.source.isParticipating() && context.player.imperialFavor !== '',
            effect: 'prevent each player playing cards from hand',
            gameAction: [
                ability.actions.playerLastingEffect({
                    targetController: Players.Any,
                    effect: ability.effects.playerCannot({
                        cannot: PlayTypes.PlayFromHand
                    })
                })
            ]
        });
    }
}

AkodoToturi2.id = 'akodo-toturi-2';

module.exports = AkodoToturi2;
<|endoftext|>


<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

<commit_msg>implement select ring<commit_after>const _ = require('underscore');
const UiPrompt = require('./uiprompt.js');

/**
 * General purpose prompt that asks the user to select 1 or more cards.
 *
 * The properties option object has the following properties:
 * numCards           - an integer specifying the number of cards the player
 *                      must select. Set to 0 if there is no limit on the num
 *                      of cards that can be selected.
 * multiSelect        - boolean that ensures that the selected cards are sent as
 *                      an array, even if the numCards limit is 1.
 * additionalButtons  - array of additional buttons for the prompt.
 * activePromptTitle  - the title that should be used in the prompt for the
 *                      choosing player.
 * waitingPromptTitle - the title that should be used in the prompt for the
 *                      opponent players.
 * maxStat            - a function that returns the maximum value that cards
 *                      selected by the prompt cannot exceed. If not specified,
 *                      then no stat limiting is done on the prompt.
 * cardStat           - a function that takes a card and returns a stat value.
 *                      Used for prompts that have a maximum stat value.
 * cardCondition      - a function that takes a card and should return a boolean
 *                      on whether that card is elligible to be selected.
 * cardType           - a string or array of strings listing which types of
 *                      cards can be selected. Defaults to the list of draw
 *                      card types.
 * onSelect           - a callback that is called once all cards have been
 *                      selected. On single card prompts this is called as soon
 *                      as an elligible card is clicked. On multi-select prompts
 *                      it is called when the done button is clicked. If the
 *                      callback does not return true, the prompt is not marked
 *                      as complete.
 * onMenuCommand      - a callback that is called when one of the additional
 *                      buttons is clicked.
 * onCancel           - a callback that is called when the player clicks the
 *                      done button without selecting any cards.
 * source             - what is at the origin of the user prompt, usually a card;
 *                      used to provide a default waitingPromptTitle, if missing
 * gameAction         - a string representing the game action to be checked on
 *                      target cards.
 * ordered            - an optional boolean indicating whether or not to display
 *                      the order of the selection during the prompt.
 */
class SelectRingPrompt extends UiPrompt {
    constructor(game, choosingPlayer, properties) {
        super(game);

        this.choosingPlayer = choosingPlayer;
        if(properties.source && !properties.waitingPromptTitle) {
            properties.waitingPromptTitle = 'Waiting for opponent to use ' + properties.source.name;
        }

        this.properties = properties;
        _.defaults(this.properties, this.defaultProperties());
        this.selectedRing = null;
    }

    defaultProperties() {
        return {
            additionalButtons: [],
            ringCondition: () => true,
            onSelect: () => true,
            onMenuCommand: () => true,
            onCancel: () => true
        };
    }

    activeCondition(player) {
        return player === this.choosingPlayer;
    }

    activePrompt() {
        return {
            selectCard: true,
            selectOrder: this.properties.ordered,
            menuTitle: this.properties.activePromptTitle || this.defaultActivePromptTitle(),
            buttons: this.properties.additionalButtons.concat([
                { text: 'Done', arg: 'done' }
            ]),
            promptTitle: this.properties.source ? this.properties.source.name : undefined
        };
    }

    defaultActivePromptTitle() {
        return 'Choose a card';
    }

    waitingPrompt() {
        return { menuTitle: this.properties.waitingPromptTitle || 'Waiting for opponent' };
    }

    onRingClicked(player, ring) {
        if(player !== this.choosingPlayer) {
            return false;
        }

        if(!this.ringCondition(ring)) {
            return false;
        }

        if(this.properties.onSelect(player, ring)) {
            this.complete();
        }
    }

    onMenuCommand(player, arg) {
        if(player !== this.choosingPlayer) {
            return false;
        }

        if(arg !== 'done') {
            if(this.properties.onMenuCommand(player, arg)) {
                this.complete();
            }
            return;
        }

        this.properties.onCancel(player);
        this.complete();
    }
}

module.exports = SelectRingPrompt;

<|endoftext|>


<commit_before>/**
 * rowcol - a library for row-column data manipulation
 * @module rowcol
 * @author Samuel Rouse <samuel.rouse@gmail.com>
 * @license MIT http://opensource.org/licenses/MIT
 */

(function() {
    "use strict";

    /*--------------------------------------------------------------------------*/
    /*
     * Constants and basic settings
     * Structure and code from Lo-Dash 2.4.1 <http://lodash.com/>
     */

    var version = "2.0.0";

    /** Used to determine if values are of the language type Object */
    var objectTypes = {
        'function': true,
        'object': true
    };

    /* istanbul ignore next UMD code */
    /** Used as a reference to the global object */
    var root = (objectTypes[typeof window] && window) || this;

    /** Detect free variable `exports` */
    var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;

    /** Detect free variable `module` */
    var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;

    /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
    var freeGlobal = freeExports && freeModule && typeof global === 'object' && global;
    /* istanbul ignore next UMD code */
    if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
        root = freeGlobal;
    }

    /** Detect the popular CommonJS extension `module.exports` */
    var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;

    /*--------------------------------------------------------------------------*/

    /* Functions */

    /**
     * Indicates if the passed object is an array
     * @param {*} obj
     * @returns {boolean}
     */
    function isArray(obj){
        return Object.prototype.toString.call(obj) === '[object Array]';
    }

    /**
     * Returns an array of indexes that match a filter string or function.
     * @param {Array} array Array of values to match
     * @param {Function|String} filter Function or String to match array values.
     * @returns {Array} Array of indexes that match the filter.
     */
    function getIndexes (array, filter) {
        var indexes = [],
            len = array.length,
            i;

        if (typeof filter === 'function') {
            for (i = 0; i < len; i++) {
                if ( filter(array[i], i) ) {
                    indexes.push(i);
                }
            }
        } else {
            for (i = 0; i < len; i++) {
                if ( array[i] === filter ) {
                    indexes.push(i);
                }
            }
        }
        return indexes;
    }

    /**
     * Returns the elements of an array using a list of selected indexes.
     * @param {Array} array
     * @param {Array} indexes
     * @returns {Array}
     */
    function getByIndexes (array, indexes) {
        var i,
            len = indexes.length,
            data = [];

        for (i = 0; i < len; i++) {
            data.push(array[indexes[i]]);
        }
        return data;
    }

    /**
     * Performs the rotation for an unlimited (regular) rotation
     * @param {Array} arr
     * @param {Object} result
     * @returns {Object}
     */
    function arrayRotateUnlimited (arr, result) {
        var obj, att, i = arr.length;

        for (;i;) {
            obj = arr[--i];

            // All variables submit to for-in loops
            for (att in obj) {
                if ( obj.hasOwnProperty(att) ) {
                    if ( result[att] === undefined ) {
                        result[att] = [];
                    }
                    result[att][i] = obj[att];
                }
            }
        }

        return result;
    }

    /**
     * Performs the rotation for a limited (partial) rotation
     * @param {Array} arr
     * @param {Object} result
     * @param {Array|boolean} limited
     * @returns {Object}
     */
    function arrayRotateLimited (arr, result, limited) {
        var objKeys, keyLen, obj, att, i, j;

        // Is limited the list of keys?
        if (isArray(limited)) {
            objKeys = limited;
        } else {
            // Get the keys for limited rotate
            objKeys = Object.keys(result);
        }

        // One pass to eliminate any unusable keys and create missing arrays
        objKeys = objKeys.filter(function(key){
            // Create arrays for missing keys
            if (undefined === result[key]) {
                result[key] = [];
                return true;
            }

            // Check if existing keys are arrays
            return isArray(result[key]);
        });

        keyLen = objKeys.length;

        i = arr.length;

        for (;i;) {
            obj = arr[--i];

            // All variables submit to for-in loops
            // JSHint hates it, but Object.keys
            for (j = 0; j < keyLen; j++) {

                att = objKeys[j];
                result[att][i] = obj[att];
            }
        }

        return result;
    }

    /**
     * Rotate an array of row-data into a column-data object
     * @param {Array} arr
     * @param {Object} [result] Result object to use
     * @param {boolean} [limited] Only update keys passed on the result object, allowing a limited rotation
     * @returns {Object}
     */
    function arrayRotate (arr, result, limited) {

        // Not an array? Send it back.
        if ( !isArray(arr) ) {
            throw new TypeError("RC: Argument is not an array");
        }

        if ( !result || typeof result !== 'object' ) {
            if ( limited ) {
                throw new TypeError("RC: Must pass a result object when 'limited' is true");
            } else {
                result = {};
            }
        }

        // Explicit check: you could pass [0], limited could be falsy.
        if (limited !== undefined && limited !== false) {
            return arrayRotateLimited(arr, result, limited);
        }

        return arrayRotateUnlimited(arr, result);
    }

    /**
     * Filter a column-data object for a particular field.
     * @param {Object} obj
     * @param {String} field
     * @param {Function|String} filter
     * @returns {*}
     */
    function objectFilter (obj, field, filter) {
        return filterMerge(obj, filterIndexes(obj, field, filter));
    }

    /**
     *
     * @param obj
     * @param field
     * @param filter
     * @returns {Array}
     */
    function filterIndexes (obj, field, filter) {
        var indexes = [];

        if ( obj.hasOwnProperty(field) ) {
            indexes = getIndexes(obj[field], filter);
        }
        return indexes;
    }

    /**
     * Filters all properties in a column-data object using an array of indexes.
     * @param {Object} obj
     * @param {Array} indexes
     * @returns {Object}
     */
    function filterMerge(obj, indexes) {
        var result = {},
            att;

        // Don't waste time if tehre are no indexes to merge.
        if (indexes === undefined || !indexes.length) {
            return result;
        }

        for (att in obj) {
            if ( obj.hasOwnProperty(att) ) {
                result[att] = getByIndexes(obj[att], indexes);
            }
        }
        return result;
    }

    /**
     * Finds the longest length of any property in a column-data object.
     * @param {Object} obj
     * @returns {number}
     */
    function objectLength (obj) {
        var att, len = 0;

        // Get the longest length of all properties
        for (att in obj) {
            if ( obj.hasOwnProperty(att) ) {
                len = Math.max(len, obj[att].length);
            }
        }

        return len;
    }

    /**
     * Rotates column-data to row-data and optionally adds it to an existing array.
     * @param {Object} obj
     * @param {Array} [result] Optional array init which we should place rotated data.
     * @param {Boolean} [clearUndef]
     * @returns {Array}
     */
    function objectRotate (obj, result, clearUndef) {
        var att, i, resultIndex, len, resultOffset, output;

        // Not an array? Send it back.
        if ( typeof obj !== 'object' ) {
            throw new TypeError("RC: Argument is not an object");
        }

        // Don't replace parameters to avoid optimization issues.
        output = result || [];

        if ( !isArray(output) ) {
            throw new TypeError("RC: Result argument is not an array");
        }

        // Get the existing result array length
        resultOffset = output.length;

        len = objectLength(obj);

        for (i = 0; i < len; i++) {
            resultIndex = i + resultOffset;
            output[resultIndex] = {};

            /** Because of resultOffset, there is no way for the error condition to execute
            if ( result[resultIndex] === undefined ) {
                result[resultIndex] = {};
            } else if ( typeof result[resultIndex] !== 'object' ) {
                throw new TypeError("RC: Result contains incorrect type at index " + i);
            }
             **/

            for (att in obj) {
                if ( obj.hasOwnProperty(att) && ( !clearUndef || obj[att][i] !== undefined ) ) {
                    output[resultIndex][att] = obj[att][i];
                }
            }
        }

        return output;
    }

    /**
     * Create a
     * @param {Object} obj
     * @param {number} index
     * @param {Boolean} [clearUndef]
     * @param {Object} [result]
     * @returns {*}
     */
    function objFromIndex (obj, index, clearUndef, result) {
        var att;

        // Check for a passed result object, used by Proxy/objFromIndex
        if ( result === undefined ) {
            result = {};
        }

        for ( att in obj ) {
            if ( obj.hasOwnProperty(att) && ( !clearUndef || obj[att][index] !== undefined ) ) {
                result[att] = obj[att][index];
            }
        }

        return result;
    }

    /**
     * Create a proxy
     * @param obj
     * @param index
     * @param clearUndef
     */
    function proxyFromIndex (obj, index, clearUndef) {
        return new RCProxy(obj, index, clearUndef);
    }

    /**
     * A generic rotate function that accepts row or column data to rotate.
     * @param {Object|Array} obj
     * @returns {Array|Object}
     */
    function rotate(obj) {
        // Generic, which directs to the appropriate array/object rotate
        if (typeof obj !== 'object') throw new TypeError("RC: rotate requires an object or an array");

        if ( isArray(obj) ) {
            return arrayRotate.apply(null, arguments);
        } else {
            return objectRotate.apply(null, arguments);
        }
    }

    /**
     * Increment over column-data like it was array data, making a "read-only" object for each index.
     * Does not prevent modification of values with complex data types (objects, arrays).
     * @param {Object} obj
     * @param {Function} fn
     */
    function readEach(obj, fn) {
        var len = objectLength(obj),
            i = 0;

        for (;i<len;i++) {
            fn(objFromIndex(obj, i));
        }
    }

    /**
     * Increment over column-data like it was array data, making a proxy object for each index.
     * @param {Object} obj
     * @param {Function} fn
     */
    function objEach(obj, fn) {
        var len = objectLength(obj),
            i = 0,
            prox;

        for (;i<len;i++) {
            prox = new RCProxy(obj, i);

            fn(prox, i);

            prox.finalize();
        }
    }

    /**
     * Create an object and add a .commit() prototype to place the values back into the original.
     * Useful for moving simple data types around. Objects and arrays will be automatically referenced.
     * @constructor
     * @param {Object} obj - A columnar object
     * @param {number} index - The index to convert into a row-based object
     * @param {Boolean} [clearUndef] - Clear undefined attributes when copying the object.
     * @example
     * var proxyRow = new RCProxy(colData, index);
     */
    var RCProxy = (function() {
        var __obj = [],
            __idx = [],
            __clr = [],
            __this = [],
            guid = 0;

        /**
         * Uses a private array to locate the same object, so the proxy doesn't expose itself to modification.
         * We compare the passed object against an array of existing RCProxy objects; basically pointer comparison.
         * @param {RCProxy} proxy
         * @returns {number} The proxy ID to allow commit and destroy to locate the correct element
         * @private
         */
        function __getId(proxy) {
            var i = __this.length, pid;

            // Most likely to be at the end, so start there
            for (;i;) {
                i--;
                if (__this[i] === proxy) {
                    pid = i;
                    break;
                }
            }

            if (pid === undefined) {
                throw new ReferenceError("Proxy is finalized and cannot be used again.");
            }
            return pid;
        }

        /**
         * The actual RCProxy constructor.
         * @param {Object} obj
         * @param {number} index
         * @param {Boolean} [clearUndef]
         * @constructor
         */
        function RCProxy (obj, index, clearUndef) {

            // Increment the guid
            ++guid;

            // Set the private data.
            __obj[guid] = obj;
            __idx[guid] = index;
            __clr[guid] = clearUndef;
            __this[guid] = this;

            // Call reusable code for objFromIndex
            objFromIndex(obj, index, clearUndef, this);
        }

        // Defined inside the constructor to give it access to the originating object and parameters

        /**
         * Commits the changes from the proxy to the original.
         */
        RCProxy.prototype.commit = function(){
            var pid = __getId(this),
                obj = __obj[pid],
                index = __idx[pid],
                clearUndef = __clr[pid],
                att;

            for ( att in this ) {
                if ( att !== '__rcProxyId' && this.hasOwnProperty(att) && ( !clearUndef || this[att] !== undefined ) ) {
                    obj[att][index] = this[att];
                }
            }
        };

        /**
         * Removes the proxy to prevent memory leaks
         */
        RCProxy.prototype.destroy = function() {
            var pid = __getId(this);
            delete __this[pid];
            delete __obj[pid];
            delete __idx[pid];
            delete __clr[pid];
        };

        /**
         * Commit and destroy the proxy, as a single step
         */
        RCProxy.prototype.finalize = function() {
            this.commit();
            this.destroy();
        };

        return RCProxy;
    }());

    /*--------------------------------------------------------------------------*/

    var rowcol = {
        rotate: rotate,
        proxy: proxyFromIndex,
        array: {
            getIndexes: getIndexes,
            getByIndexes: getByIndexes,
            rotate: arrayRotate
        },
        object: {
            filter: objectFilter,
            filterIndexes: filterIndexes,
            filterMerge: filterMerge,
            rotate: objectRotate,
            objFromIndex: objFromIndex,
            proxy: proxyFromIndex,
            readEach: readEach,
            each: objEach,
            objLength: objectLength
        },
        VERSION: version,
        test: {
            isArray: isArray
        }
    };

    /*--------------------------------------------------------------------------*/

    /* istanbul ignore next UMD */
    // some AMD build optimizers like r.js check for condition patterns like the following:
    if (typeof define === 'function' && define.amd && typeof define.amd === 'object') {
        // Expose to the global object even when an AMD loader is present in
        // case RowCol is loaded with a RequireJS shim config.
            // See http://requirejs.org/docs/api.html#config-shim
        root.rowcol = rowcol;

        // define as an anonymous module so, through path mapping, it can be
                // referenced as the "underscore" module
        define(function() {
            return rowcol;
        });
    }
    // check for `exports` after `define` in case a build optimizer adds an `exports` object
    else if (freeExports && freeModule) {
        // in Node.js or RingoJS
        if (moduleExports) {
            (freeModule.exports = rowcol).rowcol = rowcol;
        }
        // in Narwhal or Rhino -require
        else {
            freeExports.rowcol = rowcol;
        }
    }
    else {
        // in a browser or Rhino
        root.rowcol = rowcol;
    }
}());
<commit_msg>Restructure for complexity rules<commit_after>/**
 * rowcol - a library for row-column data manipulation
 * @module rowcol
 * @author Samuel Rouse <samuel.rouse@gmail.com>
 * @license MIT http://opensource.org/licenses/MIT
 */

(function() {
    "use strict";

    /*--------------------------------------------------------------------------*/
    /*
     * Constants and basic settings
     * Structure and code from Lo-Dash 2.4.1 <http://lodash.com/>
     */

    var version = "2.0.1";

    /*--------------------------------------------------------------------------*/

    /* Functions */

    /**
     * Indicates if the passed object is an array
     * @param {*} obj
     * @returns {boolean}
     */
    function isArray(obj){
        return Object.prototype.toString.call(obj) === '[object Array]';
    }

    /**
     * Returns an array of indexes that match a filter string or function.
     * @param {Array} array Array of values to match
     * @param {Function|String} filter Function or String to match array values.
     * @returns {Array} Array of indexes that match the filter.
     */
    function getIndexes (array, filter) {
        var indexes = [],
            len = array.length,
            i;

        if (typeof filter === 'function') {
            for (i = 0; i < len; i++) {
                if ( filter(array[i], i) ) {
                    indexes.push(i);
                }
            }
        } else {
            for (i = 0; i < len; i++) {
                if ( array[i] === filter ) {
                    indexes.push(i);
                }
            }
        }
        return indexes;
    }

    /**
     * Returns the elements of an array using a list of selected indexes.
     * @param {Array} array
     * @param {Array} indexes
     * @returns {Array}
     */
    function getByIndexes (array, indexes) {
        var i,
            len = indexes.length,
            data = [];

        for (i = 0; i < len; i++) {
            data.push(array[indexes[i]]);
        }
        return data;
    }

    /**
     * Performs the rotation for an unlimited (regular) rotation
     * @param {Array} arr
     * @param {Object} result
     * @returns {Object}
     */
    function arrayRotateUnlimited (arr, result) {
        var obj, att, i = arr.length;

        for (;i;) {
            obj = arr[--i];

            // All variables submit to for-in loops
            for (att in obj) {
                if ( obj.hasOwnProperty(att) ) {
                    if ( result[att] === undefined ) {
                        result[att] = [];
                    }
                    result[att][i] = obj[att];
                }
            }
        }

        return result;
    }

    /**
     * Performs the rotation for a limited (partial) rotation
     * @param {Array} arr
     * @param {Object} result
     * @param {Array|boolean} limited
     * @returns {Object}
     */
    function arrayRotateLimited (arr, result, limited) {
        var objKeys, keyLen, obj, att, i, j;

        // Is limited the list of keys?
        if (isArray(limited)) {
            objKeys = limited;
        } else {
            // Get the keys for limited rotate
            objKeys = Object.keys(result);
        }

        // One pass to eliminate any unusable keys and create missing arrays
        objKeys = objKeys.filter(function(key){
            // Create arrays for missing keys
            if (undefined === result[key]) {
                result[key] = [];
                return true;
            }

            // Check if existing keys are arrays
            return isArray(result[key]);
        });

        keyLen = objKeys.length;

        i = arr.length;

        for (;i;) {
            obj = arr[--i];

            // All variables submit to for-in loops
            // JSHint hates it, but Object.keys
            for (j = 0; j < keyLen; j++) {

                att = objKeys[j];
                result[att][i] = obj[att];
            }
        }

        return result;
    }

    /**
     * Rotate an array of row-data into a column-data object
     * @param {Array} arr
     * @param {Object} [result] Result object to use
     * @param {boolean} [limited] Only update keys passed on the result object, allowing a limited rotation
     * @returns {Object}
     */
    function arrayRotate (arr, result, limited) {

        // Not an array? Send it back.
        if ( !isArray(arr) ) {
            throw new TypeError("RC: Argument is not an array");
        }

        if ( !result || typeof result !== 'object' ) {
            if ( limited ) {
                throw new TypeError("RC: Must pass a result object when 'limited' is true");
            } else {
                result = {};
            }
        }

        // Explicit check: you could pass [0], limited could be falsy.
        if (limited !== undefined && limited !== false) {
            return arrayRotateLimited(arr, result, limited);
        }

        return arrayRotateUnlimited(arr, result);
    }

    /**
     * Filter a column-data object for a particular field.
     * @param {Object} obj
     * @param {String} field
     * @param {Function|String} filter
     * @returns {*}
     */
    function objectFilter (obj, field, filter) {
        return filterMerge(obj, filterIndexes(obj, field, filter));
    }

    /**
     *
     * @param obj
     * @param field
     * @param filter
     * @returns {Array}
     */
    function filterIndexes (obj, field, filter) {
        var indexes = [];

        if ( obj.hasOwnProperty(field) ) {
            indexes = getIndexes(obj[field], filter);
        }

        return indexes;
    }

    /**
     * Filters all properties in a column-data object using an array of indexes.
     * @param {Object} obj
     * @param {Array} indexes
     * @returns {Object}
     */
    function filterMerge(obj, indexes) {
        var result = {},
            att;

        // Don't waste time if tehre are no indexes to merge.
        if (indexes === undefined || !indexes.length) {
            return result;
        }

        for (att in obj) {
            if ( obj.hasOwnProperty(att) ) {
                result[att] = getByIndexes(obj[att], indexes);
            }
        }

        return result;
    }

    /**
     * Finds the longest length of any property in a column-data object.
     * @param {Object} obj
     * @returns {number}
     */
    function objectLength (obj) {
        var att, len = 0;

        // Get the longest length of all properties
        for (att in obj) {
            if ( obj.hasOwnProperty(att) ) {
                len = Math.max(len, obj[att].length);
            }
        }

        return len;
    }

    /**
     * Error throwing for object rotate
     * @param {Object} obj
     * @param result
     */
    function objectRotateErrors(obj, result) {

        // Not an array? Send it back.
        if ( typeof obj !== 'object' ) {
            throw new TypeError("RC: Argument is not an object");
        }

        // If a result is passed and isn't an array, send it back.
        if ( undefined !== result && !isArray(result) ) {
            throw new TypeError("RC: Result argument is not an array");
        }
    }

    /**
     * Rotates column-data to row-data and optionally adds it to an existing array.
     * @param {Object} obj
     * @param {Array} [result] Optional array init which we should place rotated data.
     * @param {Boolean} [clearUndef]
     * @returns {Array}
     */
    function objectRotate (obj, result, clearUndef) {
        var att, i, resultIndex, len, resultOffset, output;

        // Call out for errors
        objectRotateErrors(obj, result);

        // Don't replace parameters to avoid optimization issues.
        output = result || [];

        // Get the existing result array length
        resultOffset = output.length;

        len = objectLength(obj);

        for (i = 0; i < len; i++) {
            resultIndex = i + resultOffset;
            output[resultIndex] = {};

            for (att in obj) {
                if ( obj.hasOwnProperty(att) && ( !clearUndef || obj[att][i] !== undefined ) ) {
                    output[resultIndex][att] = obj[att][i];
                }
            }
        }

        return output;
    }

    /**
     * Create a
     * @param {Object} obj
     * @param {number} index
     * @param {Boolean} [clearUndef]
     * @param {Object} [result]
     * @returns {*}
     */
    function objFromIndex (obj, index, clearUndef, result) {
        var att;

        // Check for a passed result object, used by Proxy/objFromIndex
        if ( result === undefined ) {
            result = {};
        }

        for ( att in obj ) {
            if ( obj.hasOwnProperty(att) && ( !clearUndef || obj[att][index] !== undefined ) ) {
                result[att] = obj[att][index];
            }
        }

        return result;
    }

    /**
     * Create a proxy
     * @param obj
     * @param index
     * @param clearUndef
     */
    function proxyFromIndex (obj, index, clearUndef) {
        return new RCProxy(obj, index, clearUndef);
    }

    /**
     * A generic rotate function that accepts row or column data to rotate.
     * @param {Object|Array} obj
     * @returns {Array|Object}
     */
    function rotate(obj) {
        // Generic, which directs to the appropriate array/object rotate
        if (typeof obj !== 'object') throw new TypeError("RC: rotate requires an object or an array");

        if ( isArray(obj) ) {
            return arrayRotate.apply(null, arguments);
        } else {
            return objectRotate.apply(null, arguments);
        }
    }

    /**
     * Increment over column-data like it was array data, making a "read-only" object for each index.
     * Does not prevent modification of values with complex data types (objects, arrays).
     * @param {Object} obj
     * @param {Function} fn
     */
    function readEach(obj, fn) {
        var len = objectLength(obj),
            i = 0;

        for (;i<len;i++) {
            fn(objFromIndex(obj, i));
        }
    }

    /**
     * Increment over column-data like it was array data, making a proxy object for each index.
     * @param {Object} obj
     * @param {Function} fn
     */
    function objEach(obj, fn) {
        var len = objectLength(obj),
            i = 0,
            prox;

        for (;i<len;i++) {
            prox = new RCProxy(obj, i);

            fn(prox, i);

            prox.finalize();
        }
    }

    /**
     * Create an object and add a .commit() prototype to place the values back into the original.
     * Useful for moving simple data types around. Objects and arrays will be automatically referenced.
     * @constructor
     * @param {Object} obj - A columnar object
     * @param {number} index - The index to convert into a row-based object
     * @param {Boolean} [clearUndef] - Clear undefined attributes when copying the object.
     * @example
     * var proxyRow = new RCProxy(colData, index);
     */
    var RCProxy = (function() {
        var __obj = [],
            __idx = [],
            __clr = [],
            __this = [],
            guid = 0;

        /**
         * Uses a private array to locate the same object, so the proxy doesn't expose itself to modification.
         * We compare the passed object against an array of existing RCProxy objects; basically pointer comparison.
         * @param {RCProxy} proxy
         * @returns {number} The proxy ID to allow commit and destroy to locate the correct element
         * @private
         */
        function __getId(proxy) {
            var i = __this.length, pid;

            // Most likely to be at the end, so start there
            for (;i;) {
                i--;
                if (__this[i] === proxy) {
                    pid = i;
                    break;
                }
            }

            if (pid === undefined) {
                throw new ReferenceError("Proxy is finalized and cannot be used again.");
            }
            return pid;
        }

        /**
         * The actual RCProxy constructor.
         * @param {Object} obj
         * @param {number} index
         * @param {Boolean} [clearUndef]
         * @constructor
         */
        function RCProxy (obj, index, clearUndef) {

            // Increment the guid
            ++guid;

            // Set the private data.
            __obj[guid] = obj;
            __idx[guid] = index;
            __clr[guid] = clearUndef;
            __this[guid] = this;

            // Call reusable code for objFromIndex
            objFromIndex(obj, index, clearUndef, this);
        }

        // Defined inside the constructor to give it access to the originating object and parameters

        /**
         * Commits the changes from the proxy to the original.
         */
        RCProxy.prototype.commit = function(){
            var pid = __getId(this),
                obj = __obj[pid],
                index = __idx[pid],
                clearUndef = __clr[pid],
                att;

            for ( att in this ) {
                if ( att !== '__rcProxyId' && this.hasOwnProperty(att) && ( !clearUndef || this[att] !== undefined ) ) {
                    obj[att][index] = this[att];
                }
            }
        };

        /**
         * Removes the proxy to prevent memory leaks
         */
        RCProxy.prototype.destroy = function() {
            var pid = __getId(this);
            delete __this[pid];
            delete __obj[pid];
            delete __idx[pid];
            delete __clr[pid];
        };

        /**
         * Commit and destroy the proxy, as a single step
         */
        RCProxy.prototype.finalize = function() {
            this.commit();
            this.destroy();
        };

        return RCProxy;
    }());

    /*--------------------------------------------------------------------------*/

    var rowcol = {
        rotate: rotate,
        proxy: proxyFromIndex,
        array: {
            getIndexes: getIndexes,
            getByIndexes: getByIndexes,
            rotate: arrayRotate
        },
        object: {
            filter: objectFilter,
            filterIndexes: filterIndexes,
            filterMerge: filterMerge,
            rotate: objectRotate,
            objFromIndex: objFromIndex,
            proxy: proxyFromIndex,
            readEach: readEach,
            each: objEach,
            objLength: objectLength
        },
        VERSION: version,
        test: {
            isArray: isArray
        }
    };

    /*--------------------------------------------------------------------------*/

    // Export mechanisms
    (function(){

        /** Used to determine if values are of the language type Object */
        var objectTypes = {
            'function': true,
            'object': true
        },

            /** Used as a reference to the global object */
            /* istanbul ignore next UMD code */
            root = (objectTypes[typeof window] && window) || this,

            /** Detect free variable `exports` */
            freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports,

            /** Detect free variable `module` */
            freeModule = objectTypes[typeof module] && module && !module.nodeType && module,

            /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
            freeGlobal = freeExports && freeModule && typeof global === 'object' && global;

        /* istanbul ignore next UMD code */
        if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
            root = freeGlobal;
        }

        /** Detect the popular CommonJS extension `module.exports` */
        var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;

        /* istanbul ignore next UMD */
        // some AMD build optimizers like r.js check for condition patterns like the following:
        if (typeof define === 'function' && define.amd && typeof define.amd === 'object') {
            // Expose to the global object even when an AMD loader is present in
            // case RowCol is loaded with a RequireJS shim config.
            // See http://requirejs.org/docs/api.html#config-shim
            root.rowcol = rowcol;

            // define as an anonymous module so, through path mapping, it can be
            // referenced as the "underscore" module
            define(function() {
                return rowcol;
            });
        }
        // check for `exports` after `define` in case a build optimizer adds an `exports` object
        else if (freeExports && freeModule) {
            // in Node.js or RingoJS
            if (moduleExports) {
                (freeModule.exports = rowcol).rowcol = rowcol;
            }
            // in Narwhal or Rhino -require
            else {
                freeExports.rowcol = rowcol;
            }
        }
        else {
            // in a browser or Rhino
            root.rowcol = rowcol;
        }
    }());
}());
<|endoftext|>


<commit_before>import { app, BrowserWindow, Menu, crashReporter, shell } from 'electron';

let menu;
let template;
let mainWindow = null;

crashReporter.start();

if (process.env.NODE_ENV === 'development') {
  require('electron-debug')();
}

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

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    show: false,
    width: 1500,
    height: 900,
    minWidth: 1150,
    minHeight: 700
  });

  mainWindow.loadURL(`file://${__dirname}/app/app.html`);

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show();
    mainWindow.focus();
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools();
  }

  if (process.platform === 'darwin') {
    template = [{
      label: 'Electron',
      submenu: [{
        label: 'About ElectronReact',
        selector: 'orderFrontStandardAboutPanel:'
      }, {
        type: 'separator'
      }, {
        label: 'Services',
        submenu: []
      }, {
        type: 'separator'
      }, {
        label: 'Hide ElectronReact',
        accelerator: 'Command+H',
        selector: 'hide:'
      }, {
        label: 'Hide Others',
        accelerator: 'Command+Shift+H',
        selector: 'hideOtherApplications:'
      }, {
        label: 'Show All',
        selector: 'unhideAllApplications:'
      }, {
        type: 'separator'
      }, {
        label: 'Quit',
        accelerator: 'Command+Q',
        click() {
          app.quit();
        }
      }]
    }, {
      label: 'Edit',
      submenu: [{
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      }, {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      }, {
        type: 'separator'
      }, {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      }, {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      }, {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      }, {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      }]
    }, {
      label: 'View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: 'Reload',
        accelerator: 'Command+R',
        click() {
          mainWindow.restart();
        }
      }, {
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }, {
        label: 'Toggle Developer Tools',
        accelerator: 'Alt+Command+I',
        click() {
          mainWindow.toggleDevTools();
        }
      }] : [{
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }]
    }, {
      label: 'Window',
      submenu: [{
        label: 'Minimize',
        accelerator: 'Command+M',
        selector: 'performMiniaturize:'
      }, {
        label: 'Close',
        accelerator: 'Command+W',
        selector: 'performClose:'
      }, {
        type: 'separator'
      }, {
        label: 'Bring All to Front',
        selector: 'arrangeInFront:'
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io');
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme');
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron');
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues');
        }
      }]
    }];

    menu = Menu.buildFromTemplate(template);
    Menu.setApplicationMenu(menu);
  } else {
    template = [{
      label: '&File',
      submenu: [{
        label: '&Open',
        accelerator: 'Ctrl+O'
      }, {
        label: '&Close',
        accelerator: 'Ctrl+W',
        click() {
          mainWindow.close();
        }
      }]
    }, {
      label: '&View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: '&Reload',
        accelerator: 'Ctrl+R',
        click() {
          mainWindow.restart();
        }
      }, {
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }, {
        label: 'Toggle &Developer Tools',
        accelerator: 'Alt+Ctrl+I',
        click() {
          mainWindow.toggleDevTools();
        }
      }] : [{
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen());
        }
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io');
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme');
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron');
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues');
        }
      }]
    }];
    menu = Menu.buildFromTemplate(template);
    mainWindow.setMenu(menu);
  }
});
<commit_msg>Make sure the app closes when all windows are closed<commit_after>import { app, BrowserWindow, Menu, crashReporter, shell } from 'electron'

let menu
let template
let mainWindow = null

crashReporter.start()

if (process.env.NODE_ENV === 'development') {
  require('electron-debug')()
}

app.on('window-all-closed', () => app.quit() )

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 1500,
    height: 900,
    minWidth: 1150,
    minHeight: 700
  })

  mainWindow.loadURL(`file://${__dirname}/app/app.html`)

  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.show()
    mainWindow.focus()
  })

  mainWindow.on('closed', () => {
    mainWindow = null
  })

  if (process.env.NODE_ENV === 'development') {
    mainWindow.openDevTools()
  }

  if (process.platform === 'darwin') {
    template = [{
      label: 'Electron',
      submenu: [{
        label: 'About ElectronReact',
        selector: 'orderFrontStandardAboutPanel:'
      }, {
        type: 'separator'
      }, {
        label: 'Services',
        submenu: []
      }, {
        type: 'separator'
      }, {
        label: 'Hide ElectronReact',
        accelerator: 'Command+H',
        selector: 'hide:'
      }, {
        label: 'Hide Others',
        accelerator: 'Command+Shift+H',
        selector: 'hideOtherApplications:'
      }, {
        label: 'Show All',
        selector: 'unhideAllApplications:'
      }, {
        type: 'separator'
      }, {
        label: 'Quit',
        accelerator: 'Command+Q',
        click() {
          app.quit()
        }
      }]
    }, {
      label: 'Edit',
      submenu: [{
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      }, {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      }, {
        type: 'separator'
      }, {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      }, {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      }, {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      }, {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      }]
    }, {
      label: 'View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: 'Reload',
        accelerator: 'Command+R',
        click() {
          mainWindow.restart()
        }
      }, {
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }, {
        label: 'Toggle Developer Tools',
        accelerator: 'Alt+Command+I',
        click() {
          mainWindow.toggleDevTools()
        }
      }] : [{
        label: 'Toggle Full Screen',
        accelerator: 'Ctrl+Command+F',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }]
    }, {
      label: 'Window',
      submenu: [{
        label: 'Minimize',
        accelerator: 'Command+M',
        selector: 'performMiniaturize:'
      }, {
        label: 'Close',
        accelerator: 'Command+W',
        selector: 'performClose:'
      }, {
        type: 'separator'
      }, {
        label: 'Bring All to Front',
        selector: 'arrangeInFront:'
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io')
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme')
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron')
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues')
        }
      }]
    }]

    menu = Menu.buildFromTemplate(template)
    Menu.setApplicationMenu(menu)
  } else {
    template = [{
      label: '&File',
      submenu: [{
        label: '&Open',
        accelerator: 'Ctrl+O'
      }, {
        label: '&Close',
        accelerator: 'Ctrl+W',
        click() {
          mainWindow.close()
        }
      }]
    }, {
      label: '&View',
      submenu: (process.env.NODE_ENV === 'development') ? [{
        label: '&Reload',
        accelerator: 'Ctrl+R',
        click() {
          mainWindow.restart()
        }
      }, {
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }, {
        label: 'Toggle &Developer Tools',
        accelerator: 'Alt+Ctrl+I',
        click() {
          mainWindow.toggleDevTools()
        }
      }] : [{
        label: 'Toggle &Full Screen',
        accelerator: 'F11',
        click() {
          mainWindow.setFullScreen(!mainWindow.isFullScreen())
        }
      }]
    }, {
      label: 'Help',
      submenu: [{
        label: 'Learn More',
        click() {
          shell.openExternal('http://electron.atom.io')
        }
      }, {
        label: 'Documentation',
        click() {
          shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme')
        }
      }, {
        label: 'Community Discussions',
        click() {
          shell.openExternal('https://discuss.atom.io/c/electron')
        }
      }, {
        label: 'Search Issues',
        click() {
          shell.openExternal('https://github.com/atom/electron/issues')
        }
      }]
    }]
    menu = Menu.buildFromTemplate(template)
    mainWindow.setMenu(menu)
  }
})
<|endoftext|>