<commit_before>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var passport = require("passport");
var oauth2orize = require("oauth2orize");

var strategies = require("./strategies");
var Tokens = require("./tokens");
var Users = require("./users");
var permissions = require("./permissions");

var theme = require("../theme");

var settings = null;
var log = null

passport.use(strategies.bearerStrategy.BearerStrategy);
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
passport.use(strategies.anonymousStrategy);

var server = oauth2orize.createServer();

server.exchange(oauth2orize.exchange.password(strategies.passwordTokenExchange));

function init(runtime) {
    settings = runtime.settings;
    log = runtime.log;
    if (settings.adminAuth) {
        Users.init(settings.adminAuth);
        Tokens.init(settings.adminAuth,runtime.storage);
        strategies.init(runtime);
    }
}

function needsPermission(permission) {
    return function(req,res,next) {
        if (settings && settings.adminAuth) {
            return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
                if (!req.user) {
                    return next();
                }
                if (permissions.hasPermission(req.authInfo.scope,permission)) {
                    return next();
                }
                log.audit({event: "permission.fail", permissions: permission},req);
                return res.status(401).end();
            });
        } else {
            next();
        }
    }
}

function ensureClientSecret(req,res,next) {
    if (!req.body.client_secret) {
        req.body.client_secret = 'not_available';
    }
    next();
}
function authenticateClient(req,res,next) {
    return passport.authenticate(['oauth2-client-password'], {session: false})(req,res,next);
}
function getToken(req,res,next) {
    return server.token()(req,res,next);
}

function login(req,res) {
    var response = {};
    if (settings.adminAuth) {
        if (settings.adminAuth.type === "credentials") {
            response = {
                "type":"credentials",
                "prompts":[{id:"username",type:"text",label:"user.username"},{id:"password",type:"password",label:"user.password"}]
            }
        } else if (settings.adminAuth.type === "strategy") {
            response = {
                "type":"strategy",
                "prompts":[{type:"button",label:settings.adminAuth.strategy.label, url:"/auth/strategy"}]
            }
            if (settings.adminAuth.strategy.icon) {
                response.prompts[0].icon = settings.adminAuth.strategy.icon;
            }
            if (settings.adminAuth.strategy.image) {
                response.prompts[0].image = theme.serveFile('/login/',settings.adminAuth.strategy.image);
            }
        }
        if (theme.context().login && theme.context().login.image) {
            response.image = theme.context().login.image;
        }
    }
    res.json(response);
}

function revoke(req,res) {
    var token = req.body.token;
    // TODO: audit log
    Tokens.revoke(token).then(function() {
        log.audit({event: "auth.login.revoke"},req);
        if (settings.editorTheme && settings.editorTheme.logout && settings.editorTheme.logout.redirect) {
            res.json({redirect:settings.editorTheme.logout.redirect});
        } else {
            res.status(200).end();
        }
    });
}

function completeVerify(profile,done) {
    Users.authenticate(profile).then(function(user) {
        if (user) {
            Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
                log.audit({event: "auth.login",username:user.username,scope:user.permissions});
                user.tokens = tokens;
                done(null,user);
            });
        } else {
            log.audit({event: "auth.login.fail.oauth",username:typeof profile === "string"?profile:profile.username});
            done(null,false);
        }
    });
}

module.exports = {
    init: init,
    needsPermission: needsPermission,
    ensureClientSecret: ensureClientSecret,
    authenticateClient: authenticateClient,
    getToken: getToken,
    errorHandler: function(err,req,res,next) {
        //TODO: audit log statment
        //console.log(err.stack);
        //log.log({level:"audit",type:"auth",msg:err.toString()});
        return server.errorHandler()(err,req,res,next);
    },
    login: login,
    revoke: revoke,
    genericStrategy: function(adminApp,strategy) {
        var session = require('express-session');
        var crypto = require("crypto");
        adminApp.use(session({
            // As the session is only used across the life-span of an auth
            // hand-shake, we can use a instance specific random string
            secret: crypto.randomBytes(20).toString('hex'),
            resave: false,
            saveUninitialized:false
        }));
        //TODO: all passport references ought to be in ./auth
        adminApp.use(passport.initialize());
        adminApp.use(passport.session());

        var options = strategy.options;

        passport.use(new strategy.strategy(options,
            function() {
                var originalDone = arguments[arguments.length-1];
                if (options.verify) {
                    var args = Array.prototype.slice.call(arguments);
                    args[args.length-1] = function(err,profile) {
                        if (err) {
                            return originalDone(err);
                        } else {
                            return completeVerify(profile,originalDone);
                        }
                    };
                    options.verify.apply(null,args);
                } else {
                    var profile = arguments[arguments.length - 2];
                    return completeVerify(profile,originalDone);
                }

            }
        ));

        adminApp.get('/auth/strategy', passport.authenticate(strategy.name));
        adminApp.get('/auth/strategy/callback',
            passport.authenticate(strategy.name, {session:false, failureRedirect: '/' }),
            function(req, res) {
                var tokens = req.user.tokens;
                delete req.user.tokens;
                // Successful authentication, redirect home.
                res.redirect('/?access_token='+tokens.accessToken);
            }
        );

    }
}
<commit_msg>[fix] github oauth strategy when Root is not / (#1430)<commit_after>/**
 * Copyright JS Foundation and other contributors, http://js.foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var passport = require("passport");
var oauth2orize = require("oauth2orize");

var strategies = require("./strategies");
var Tokens = require("./tokens");
var Users = require("./users");
var permissions = require("./permissions");

var theme = require("../theme");

var settings = null;
var log = null

passport.use(strategies.bearerStrategy.BearerStrategy);
passport.use(strategies.clientPasswordStrategy.ClientPasswordStrategy);
passport.use(strategies.anonymousStrategy);

var server = oauth2orize.createServer();

server.exchange(oauth2orize.exchange.password(strategies.passwordTokenExchange));

function init(runtime) {
    settings = runtime.settings;
    log = runtime.log;
    if (settings.adminAuth) {
        Users.init(settings.adminAuth);
        Tokens.init(settings.adminAuth,runtime.storage);
        strategies.init(runtime);
    }
}

function needsPermission(permission) {
    return function(req,res,next) {
        if (settings && settings.adminAuth) {
            return passport.authenticate(['bearer','anon'],{ session: false })(req,res,function() {
                if (!req.user) {
                    return next();
                }
                if (permissions.hasPermission(req.authInfo.scope,permission)) {
                    return next();
                }
                log.audit({event: "permission.fail", permissions: permission},req);
                return res.status(401).end();
            });
        } else {
            next();
        }
    }
}

function ensureClientSecret(req,res,next) {
    if (!req.body.client_secret) {
        req.body.client_secret = 'not_available';
    }
    next();
}
function authenticateClient(req,res,next) {
    return passport.authenticate(['oauth2-client-password'], {session: false})(req,res,next);
}
function getToken(req,res,next) {
    return server.token()(req,res,next);
}

function login(req,res) {
    var response = {};
    if (settings.adminAuth) {
        if (settings.adminAuth.type === "credentials") {
            response = {
                "type":"credentials",
                "prompts":[{id:"username",type:"text",label:"user.username"},{id:"password",type:"password",label:"user.password"}]
            }
        } else if (settings.adminAuth.type === "strategy") {
            response = {
                "type":"strategy",
                "prompts":[{type:"button",label:settings.adminAuth.strategy.label, url: settings.httpAdminRoot + "auth/strategy"}]
            }
            if (settings.adminAuth.strategy.icon) {
                response.prompts[0].icon = settings.adminAuth.strategy.icon;
            }
            if (settings.adminAuth.strategy.image) {
                response.prompts[0].image = theme.serveFile('/login/',settings.adminAuth.strategy.image);
            }
        }
        if (theme.context().login && theme.context().login.image) {
            response.image = theme.context().login.image;
        }
    }
    res.json(response);
}

function revoke(req,res) {
    var token = req.body.token;
    // TODO: audit log
    Tokens.revoke(token).then(function() {
        log.audit({event: "auth.login.revoke"},req);
        if (settings.editorTheme && settings.editorTheme.logout && settings.editorTheme.logout.redirect) {
            res.json({redirect:settings.editorTheme.logout.redirect});
        } else {
            res.status(200).end();
        }
    });
}

function completeVerify(profile,done) {
    Users.authenticate(profile).then(function(user) {
        if (user) {
            Tokens.create(user.username,"node-red-editor",user.permissions).then(function(tokens) {
                log.audit({event: "auth.login",username:user.username,scope:user.permissions});
                user.tokens = tokens;
                done(null,user);
            });
        } else {
            log.audit({event: "auth.login.fail.oauth",username:typeof profile === "string"?profile:profile.username});
            done(null,false);
        }
    });
}

module.exports = {
    init: init,
    needsPermission: needsPermission,
    ensureClientSecret: ensureClientSecret,
    authenticateClient: authenticateClient,
    getToken: getToken,
    errorHandler: function(err,req,res,next) {
        //TODO: audit log statment
        //console.log(err.stack);
        //log.log({level:"audit",type:"auth",msg:err.toString()});
        return server.errorHandler()(err,req,res,next);
    },
    login: login,
    revoke: revoke,
    genericStrategy: function(adminApp,strategy) {
        var session = require('express-session');
        var crypto = require("crypto");
        adminApp.use(session({
            // As the session is only used across the life-span of an auth
            // hand-shake, we can use a instance specific random string
            secret: crypto.randomBytes(20).toString('hex'),
            resave: false,
            saveUninitialized:false
        }));
        //TODO: all passport references ought to be in ./auth
        adminApp.use(passport.initialize());
        adminApp.use(passport.session());

        var options = strategy.options;

        passport.use(new strategy.strategy(options,
            function() {
                var originalDone = arguments[arguments.length-1];
                if (options.verify) {
                    var args = Array.prototype.slice.call(arguments);
                    args[args.length-1] = function(err,profile) {
                        if (err) {
                            return originalDone(err);
                        } else {
                            return completeVerify(profile,originalDone);
                        }
                    };
                    options.verify.apply(null,args);
                } else {
                    var profile = arguments[arguments.length - 2];
                    return completeVerify(profile,originalDone);
                }

            }
        ));

        adminApp.get('/auth/strategy', passport.authenticate(strategy.name));
        adminApp.get('/auth/strategy/callback',
            passport.authenticate(strategy.name, {session:false, failureRedirect: settings.httpAdminRoot }),
            function(req, res) {
                var tokens = req.user.tokens;
                delete req.user.tokens;
                // Successful authentication, redirect home.
                res.redirect(settings.httpAdminRoot + '?access_token='+tokens.accessToken);
            }
        );

    }
}
<|endoftext|>


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

'use strict';

// set process title
process.title = 'fengine';

var Tilda = require('tilda');
var fengine = require('../');
var colors = require('colors/safe');
var pkg = require('../package.json');

// set commander
new Tilda({
  name: 'fengine',
  version: pkg.version,
  description: colors.cyan.bold(pkg.description),
  documentation: colors.magenta.bold(pkg.homepage),
  examples: ['fengine', 'fengine -p 80']
}).option([
  {
    default: 80,
    name: 'port',
    type: 'number',
    opts: ['p', 'port'],
    desc: 'Set the server port.'
  }
]).main(function (tilda){
  var port = tilda.options.port;

  console.log(port.value < 0 ? port.default : port.value);
});

<commit_msg>add files<commit_after>#!/usr/bin/env node

'use strict';

// set process title
process.title = 'fengine';

var Tilda = require('tilda');
var fengine = require('../');
var colors = require('colors/safe');
var pkg = require('../package.json');

// set commander
new Tilda({
  name: 'fengine',
  version: pkg.version,
  description: colors.cyan.bold(pkg.description),
  documentation: colors.magenta.bold(pkg.homepage),
  examples: ['fengine', 'fengine -p 80', 'fengine --port 80']
}).option([
  {
    default: 80,
    name: 'port',
    type: 'number',
    opts: ['p', 'port'],
    desc: 'Set the server port.'
  }
]).main(function (tilda){
  var port = tilda.options.port;

  console.log(port.value < 0 ? port.default : port.value);
});

<|endoftext|>


<commit_before>var subarg = require('subarg');

function Prorogram(opts) {
    this.opts = opts || {};

    this.options = {};
    this.commands = {};

    this.raw_arguments = {};
    this.parsed = {};

    this.selected = {};
}

// Prototype Setter/Getter Properties

Object.defineProperty(Prorogram.prototype, "action", {
    enumerable: false,
    get: function() {
        return this.opts.action;
    },
    set: function(fn) {
        this.opts.action = fn;
    }
});

Object.defineProperty(Prorogram.prototype, "required", {
    enumerable: false,
    get: function() {
        return this.opts.required;
    },
    set: function(reqd) {
        this.opts.required = reqd;
    }
});

// Main API Methods

Prorogram.prototype.create = function create(opts) {
    return new Prorogram(opts);
};

Prorogram.prototype.option = function(flag_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof flag_name !== 'string') {
        throw new Error("Missing Flag Name");
    }

    opts.flag_name = flag_name = clearLeadingDashes(flag_name);
    opts.shortcut = createShortcut(opts.shortcut, flag_name, this.options);
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.options[flag_name] = opts;

    return this;
};

Prorogram.prototype.command = function(command_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof command_name !== 'string') {
        throw new Error("Missing Command Name");
    }

    opts.command_name = command_name;
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.commands[command_name] = this.create(opts);

    return this.commands[command_name];
};

Prorogram.prototype.parse = function(argv) {

    if (!Array.isArray(argv) && typeof argv === 'object') {
        argv = this.rebuildArgArray(argv);
    }

    this.parsed = subarg(argv);
    this.raw_arguments = {
        _: argv
    };

    if (!evalCmd(this, this.parsed, argv, this.commands)) {
        evalFlags(this, this.parsed, this.options);
    }
};

// Core Functional Evaluation Methods

function evalFlags(program, args, options) {

    var value = null,
        err = null,
        flag = null;

    for (var flag_name in options) {

        flag = options[flag_name];
        value = args[flag_name] || args[flag.shortcut];

        if (value) {
            if (flag.required && value === true) {
                err = new Error('Required argument <' + flag.required + '> missing for flag: \'--' + flag_name  + '\'');
            } else {
                err = null;
            }

            program.selected[flag_name] = value;

            if (typeof flag.action === 'function') {
                flag.action(err, value, program);
            }
        }
    }
}

function evalCmd(program, parse_args, argv, commands) {

    var possible_commands = parse_args._,
        command,
        possible,
        remaining_args,
        err;

    for (var i = 0; i < possible_commands.length; i++) {

        possible = possible_commands[i];

        for (var command_name in commands) {

            if (possible === command_name || possible === commands[command_name].alias) {

                command = commands[command_name];

                if (command.opts.required && possible_commands[i+1] === undefined) {
                    err = new Error('Required argument <' + command.opts.required + '> missing for command: \'' + command_name + '\'');
                } else {
                    err = null;
                }

                remaining_args = argv.slice(i);
                command.parse(remaining_args);

                if (typeof command.action === 'function') {
                    command.action(err, remaining_args, program);
                }
                return true;
            }
        }
    }
    return false;
}

// Extra Sauce API Methods

Prorogram.prototype.rebuildArgString = function(parsed_args) {
    return unparse(parsed_args).command_string;
};

Prorogram.prototype.rebuildArgArray = function(parsed_args) {
    return unparse(parsed_args);
};

function createShortcut(shortcut, flag_name, options) {

    var exists;

    if (!shortcut) {
        for (var i = 0; i < flag_name.length; i++) {
            exists = false;
            shortcut = flag_name[i];
            for (var flag in options) {
                if (options[flag].shortcut === shortcut) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                break;
            }
        }
    } else {
        shortcut = clearLeadingDashes(shortcut);
    }
    return shortcut;
}

function clearLeadingDashes(str) {
    for (var i = 0; i < str.length; i++) {
        if (str[i] !== '-')
            break;
    }
    return str.slice(i);
}

function mergeOpts(opts, fn) {
    opts = opts || {};

    if (typeof opts === 'function' && fn === undefined) {
        fn = opts;
        opts = {};
    }
    if (typeof fn === 'function' && typeof opts.action !== 'function') {
        opts.action = fn;
    }

    return opts;
}

module.exports = exports = new Prorogram();
<commit_msg>adding enumerable pseudo properties<commit_after>var subarg = require('subarg');

function Prorogram(opts) {

    Object.defineProperty(this, opts, {
        enumerable: false,
        value: opts || {}
    });

    this.options = {};
    this.commands = {};

    this.raw_arguments = {};
    this.parsed = {};

    this.selected = {};
}

// Prototype Setter/Getter Properties

Object.defineProperty(Prorogram.prototype, "action", {
    enumerable: true,
    get: function() {
        return this.opts.action;
    },
    set: function(fn) {
        this.opts.action = fn;
    }
});

Object.defineProperty(Prorogram.prototype, "required", {
    enumerable: true,
    get: function() {
        return this.opts.required;
    },
    set: function(reqd) {
        this.opts.required = reqd;
    }
});

Object.defineProperty(Prorogram.prototype, "description", {
    enumerable: true,
    get: function() {
        return this.opts.description;
    },
    set: function(desc) {
        this.opts.description = desc;
    }
});

// Main API Methods

Prorogram.prototype.create = function create(opts) {
    return new Prorogram(opts);
};

Prorogram.prototype.option = function(flag_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof flag_name !== 'string') {
        throw new Error("Missing Flag Name");
    }

    opts.flag_name = flag_name = clearLeadingDashes(flag_name);
    opts.shortcut = createShortcut(opts.shortcut, flag_name, this.options);
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.options[flag_name] = opts;

    return this;
};

Prorogram.prototype.command = function(command_name, opts, fn) {

    opts = mergeOpts(opts, fn);

    if (typeof command_name !== 'string') {
        throw new Error("Missing Command Name");
    }

    opts.command_name = command_name;
    opts.description = opts.description || '';
    opts.prorogram = this;

    this.commands[command_name] = this.create(opts);

    return this.commands[command_name];
};

Prorogram.prototype.parse = function(argv) {

    if (!Array.isArray(argv) && typeof argv === 'object') {
        argv = this.rebuildArgArray(argv);
    }

    this.parsed = subarg(argv);
    this.raw_arguments = {
        _: argv
    };

    if (!evalCmd(this, this.parsed, argv, this.commands)) {
        evalFlags(this, this.parsed, this.options);
    }
};

// Core Functional Evaluation Methods

function evalFlags(program, args, options) {

    var value = null,
        err = null,
        flag = null;

    for (var flag_name in options) {

        flag = options[flag_name];
        value = args[flag_name] || args[flag.shortcut];

        if (value) {
            if (flag.required && value === true) {
                err = new Error('Required argument <' + flag.required + '> missing for flag: \'--' + flag_name + '\'');
            } else {
                err = null;
            }

            program.selected[flag_name] = value;

            if (typeof flag.action === 'function') {
                flag.action(err, value, program);
            }
        }
    }
}

function evalCmd(program, parse_args, argv, commands) {

    var possible_commands = parse_args._,
        command,
        possible,
        remaining_args,
        err;

    for (var i = 0; i < possible_commands.length; i++) {

        possible = possible_commands[i];

        for (var command_name in commands) {

            if (possible === command_name || possible === commands[command_name].alias) {

                command = commands[command_name];

                if (command.required && possible_commands[i + 1] === undefined) {
                    err = new Error('Required argument <' + command.required + '> missing for command: \'' + command_name + '\'');
                } else {
                    err = null;
                }

                remaining_args = argv.slice(i);
                command.parse(remaining_args);

                if (typeof command.action === 'function') {
                    command.action(err, remaining_args, program);
                }
                return true;
            }
        }
    }
    return false;
}

// Extra Sauce API Methods

Prorogram.prototype.rebuildArgString = function(parsed_args) {
    return unparse(parsed_args).command_string;
};

Prorogram.prototype.rebuildArgArray = function(parsed_args) {
    return unparse(parsed_args);
};

function createShortcut(shortcut, flag_name, options) {

    var exists;

    if (!shortcut) {
        for (var i = 0; i < flag_name.length; i++) {
            exists = false;
            shortcut = flag_name[i];
            for (var flag in options) {
                if (options[flag].shortcut === shortcut) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                break;
            }
        }
    } else {
        shortcut = clearLeadingDashes(shortcut);
    }
    return shortcut;
}

function clearLeadingDashes(str) {
    for (var i = 0; i < str.length; i++) {
        if (str[i] !== '-')
            break;
    }
    return str.slice(i);
}

function mergeOpts(opts, fn) {
    opts = opts || {};

    if (typeof opts === 'function' && fn === undefined) {
        fn = opts;
        opts = {};
    }
    if (typeof fn === 'function' && typeof opts.action !== 'function') {
        opts.action = fn;
    }

    return opts;
}

module.exports = exports = new Prorogram();
<|endoftext|>


<commit_before>/**
 * Bind
 * ====
 *
 * Bind content and events to the DOM and create DOM Elements.
 *
 * */
var Bind = module.exports = function (bind, dataContext) {

    var self = this
      , context = $(this.dom)
      ;

    if (bind.context) {
        context = $(bind.context, context);
    }

    var target = context;
    if (bind.target) {
        target = $(bind.target, context);
    }

    dataContext = dataContext || {};

    function computeStringOrSourceDataValue (dataType, dataContext) {

        var value = "";
        if (typeof dataType === "string") {
            value = dataType;
        } else {
            value = computeDataValue(dataType, dataContext);
        }

        return value;
    }

    function computeDataValue (dataType, dataContext) {

        var dataSource = undefined;

        // if the source is $ the value the data context will be considered the value
        if (dataType.source === "$") {
            dataSource = dataContext.toString();
        } else {
            dataSource = Utils.findValue (dataContext, dataType.source);
        }

        if (dataSource === undefined || dataSource === null) {
            if (typeof dataType["default"] === "string") {
                value = dataType["default"];
            } else {
                value = "?" + dataType.source + "?";
            }
        } else if (dataSource.constructor.name === "Object") {
            var locale = M.getLocale();
            value = dataSource[locale] || "Missing value for '" + locale + "' language";
        } else {
            value = dataSource;
        }

        var filterFunction = Utils.findFunction (self, dataType.filter) || Utils.findFunction (window, dataType.filter);
        if (typeof filterFunction === "function") {
            value = filterFunction (self, dataContext, dataType.source, value);
        }

        return value;
    };

    var domManipulators = {

        /**
         *  Add/modify attribute
         *
         *  Examples:
         *  "binds": [
         *      {
         *          "attr": [
         *              {
         *                  "name": "the_attribute name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "the_attribute name",
         *                  "value": {
         *                      "source": "the_field_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        attr: function (target, context, attrTypes, dataContext) {
            if (!attrTypes || !attrTypes.length) {
                return;
            }
            for (var i = 0; i < attrTypes.length; ++i) {
                var value = computeStringOrSourceDataValue (attrTypes[i].value, dataContext);
                target.attr(attrTypes[i].name, value);
            }
        },

        /**
         *  Add/modify properties
         *
         *  Examples:
         *  "binds": [
         *      {
         *          "prop": [
         *              {
         *                  "name": "prop name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "prop name",
         *                  "value": {
         *                      "source": "the_prop_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        prop: function (target, context, propTypes, dataContext) {

            if (!propTypes || !propTypes.length) {
                return;
            }

            for (var i = 0; i < propTypes.length; ++i) {
                var value = computeStringOrSourceDataValue (propTypes[i].value, dataContext);
                target.prop(propTypes[i].name, value);
            }
        },

        /**
         *  Add class
         *  Examples:
         *  "binds": [
         *      {
         *          "addClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        addClass: function(target, context, classes, dataContext) {
            if (!classes || !classes.length) {
                return;
            }
            for (var i = 0; i < classes.length; ++i) {
                target.addClass(classes[i]);
            }
        },

        /**
         *  Remove class
         *  Examples:
         *  "binds": [
         *      {
         *          "removeClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        removeClass: function(target, context, classes, dataContext) {

            if (!classes || !classes.length) {
                return;
            }

            for (var i = 0; i < classes.length; ++i) {
                target.removeClass(classes[i]);
            }
        },

        /**
         *  Modify HTML
         *
         *  Examples:
         *  "binds": [
         *      {
         *          "html": "a_string_value"
         *      },
         *
         *      {
         *          "html": {
         *              "source": "the_field_name_from_a_source"
         *          }
         *      }
         *  ]
         */
        html: function(target, context, dataType, dataContext) {

            var value = computeStringOrSourceDataValue (dataType, dataContext);

            if (value === undefined || value === null) {
                value = '';
            } else {
                value = value.toString();
            }

            target.html(value);
        },

        /*
         *  Repeat the target for each item in array source
         *
         *   "binds": [
         *       {
         *           "repeat": {
         *               "source": "the_array_name_from_a_source",
         *               "preFilter": "handler_name",
         *               "postFilter": "handler_name",
         *               "binds": [
         *                   ...
         *               ]
         *           }
         *       }
         *   ]
         */
        repeat: function(target, context, bindTemplate, dataContext) {

            if (!target.length) {
                console.warn("Empty bind 'repeat' target");
                return;
            }

            if (typeof dataContext !== "object" || !dataContext) {
                console.warn("A bind 'repeat' can only be used with an object data context");
                return;
            }

            var sourceArray = dataContext[bindTemplate.source] || [];

            if (!sourceArray || sourceArray.constructor.name !== "Array" ) {
                console.warn("A bind 'repeat' did not find an array in the source field of the data context");
                return;
            }

            var template = target.clone()
              , container = target.parent()
              ;

            // run the pre-filtering handler
            var filterFunction = Utils.findFunction (self, bindTemplate.preFilter) || Utils.findFunction (window, bindTemplate.prefilter);
            if (filterFunction) {
                sourceArray = filterFunction (self, dataContext, bindTemplate.source, sourceArray, container);
            }

            // run the binds for each item
            for (var i = 0; i < sourceArray.length; ++i) {

                var newDom = template.clone();

                if (!bindTemplate.binds || !bindTemplate.binds.length) {
                    continue;
                }

                for (var j = 0; j < bindTemplate.binds.length; ++j) {
                    var bind = bindTemplate.binds[j];
                    bind.context = newDom;
                    Bind.call (self, bind, sourceArray[i]);
                }

                container.append(newDom);
            }

            // run the post-filtering handler
            filterFunction = Utils.findFunction (self, bindTemplate.postFilter) || Utils.findFunction (window, bindTemplate.postFilter);
            if (filterFunction) {
                sourceArray = filterFunction (self, dataContext, bindTemplate.source, sourceArray, container);
            }

            target.remove();
        }
    }

    for (var key in bind) {
        if (!bind.hasOwnProperty(key)) continue;

        if (domManipulators[key]) {
            domManipulators[key](target, context, bind[key], dataContext);
        }
    }

    if (bind.on) {
        for (var i = 0; i < bind.on.length; ++i) {
            var curOn = bind.on[i];
            if (curOn.handler || curOn.emit) {
                (function (curOn) {
                    var t = target;
                    var s = null;

                    // of the delegated option is set, this bind will work for future DOM insertions
                    if (curOn.delegated) {
                        t = context;
                        s = target.selector;
                    }

                    t.on(curOn.name, s,function(event) {
                        event.stopPropagation();

                        var name = curOn.handler;
                        var args = [];

                        if (typeof name === "object") {
                            args = name.args || [];
                            name = name.name;
                        }

                        // if the noEvent option is set, the DOM event will not be passed to the called handler or emitted event
                        if (!curOn.noEvent) {
                            args.push(event);
                        }

                        args.push(dataContext);

                        if (typeof name === "function") {
                            name.apply(self, args);
                            return false;
                        }

                        var handler = Utils.findFunction (self, name) || Utils.findFunction (window, name);

                        if (typeof handler === "function") {
                            handler.apply(self, args);
                        }

                        if (curOn.emit) {
                            self.emit (curOn.emit, dataContext);
                        }

                        return false;
                    });
                })(curOn);
            }
        }
    }

    for (var key in bind.listen) {
        if (!bind.listen.hasOwnProperty(key)) continue;

        var curListen = bind.listen[key];
        self.on (curListen.name, curListen.miid, self[curListen.handler]);
    }
};
<commit_msg>Require utils<commit_after>// dependencies
var Utils = require ("github/jillix/utils");

/**
 * Bind
 * ====
 *
 * Bind content and events to the DOM and create DOM Elements.
 *
 * */
var Bind = module.exports = function (bind, dataContext) {

    var self = this
      , context = $(this.dom)
      ;

    if (bind.context) {
        context = $(bind.context, context);
    }

    var target = context;
    if (bind.target) {
        target = $(bind.target, context);
    }

    dataContext = dataContext || {};

    function computeStringOrSourceDataValue (dataType, dataContext) {

        var value = "";
        if (typeof dataType === "string") {
            value = dataType;
        } else {
            value = computeDataValue(dataType, dataContext);
        }

        return value;
    }

    function computeDataValue (dataType, dataContext) {

        var dataSource = undefined;

        // if the source is $ the value the data context will be considered the value
        if (dataType.source === "$") {
            dataSource = dataContext.toString();
        } else {
            dataSource = Utils.findValue (dataContext, dataType.source);
        }

        if (dataSource === undefined || dataSource === null) {
            if (typeof dataType["default"] === "string") {
                value = dataType["default"];
            } else {
                value = "?" + dataType.source + "?";
            }
        } else if (dataSource.constructor.name === "Object") {
            var locale = M.getLocale();
            value = dataSource[locale] || "Missing value for '" + locale + "' language";
        } else {
            value = dataSource;
        }

        var filterFunction = Utils.findFunction (self, dataType.filter) || Utils.findFunction (window, dataType.filter);
        if (typeof filterFunction === "function") {
            value = filterFunction (self, dataContext, dataType.source, value);
        }

        return value;
    };

    var domManipulators = {

        /**
         *  Add/modify attribute
         *
         *  Examples:
         *  "binds": [
         *      {
         *          "attr": [
         *              {
         *                  "name": "the_attribute name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "the_attribute name",
         *                  "value": {
         *                      "source": "the_field_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        attr: function (target, context, attrTypes, dataContext) {
            if (!attrTypes || !attrTypes.length) {
                return;
            }
            for (var i = 0; i < attrTypes.length; ++i) {
                var value = computeStringOrSourceDataValue (attrTypes[i].value, dataContext);
                target.attr(attrTypes[i].name, value);
            }
        },

        /**
         *  Add/modify properties
         *
         *  Examples:
         *  "binds": [
         *      {
         *          "prop": [
         *              {
         *                  "name": "prop name",
         *                  "value": "a_string_value"
         *              },
         *              {
         *                  "name": "prop name",
         *                  "value": {
         *                      "source": "the_prop_value_from_a_source"
         *                  }
         *              },
         *              ...
         *          ]
         *      }
         *  ]
         */
        prop: function (target, context, propTypes, dataContext) {

            if (!propTypes || !propTypes.length) {
                return;
            }

            for (var i = 0; i < propTypes.length; ++i) {
                var value = computeStringOrSourceDataValue (propTypes[i].value, dataContext);
                target.prop(propTypes[i].name, value);
            }
        },

        /**
         *  Add class
         *  Examples:
         *  "binds": [
         *      {
         *          "addClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        addClass: function(target, context, classes, dataContext) {
            if (!classes || !classes.length) {
                return;
            }
            for (var i = 0; i < classes.length; ++i) {
                target.addClass(classes[i]);
            }
        },

        /**
         *  Remove class
         *  Examples:
         *  "binds": [
         *      {
         *          "removeClass": [
         *              "class_1",
         *              "class_2",
         *              ...
         *          ]
         *      }
         *  ]
         */
        removeClass: function(target, context, classes, dataContext) {

            if (!classes || !classes.length) {
                return;
            }

            for (var i = 0; i < classes.length; ++i) {
                target.removeClass(classes[i]);
            }
        },

        /**
         *  Modify HTML
         *
         *  Examples:
         *  "binds": [
         *      {
         *          "html": "a_string_value"
         *      },
         *
         *      {
         *          "html": {
         *              "source": "the_field_name_from_a_source"
         *          }
         *      }
         *  ]
         */
        html: function(target, context, dataType, dataContext) {

            var value = computeStringOrSourceDataValue (dataType, dataContext);

            if (value === undefined || value === null) {
                value = '';
            } else {
                value = value.toString();
            }

            target.html(value);
        },

        /*
         *  Repeat the target for each item in array source
         *
         *   "binds": [
         *       {
         *           "repeat": {
         *               "source": "the_array_name_from_a_source",
         *               "preFilter": "handler_name",
         *               "postFilter": "handler_name",
         *               "binds": [
         *                   ...
         *               ]
         *           }
         *       }
         *   ]
         */
        repeat: function(target, context, bindTemplate, dataContext) {

            if (!target.length) {
                console.warn("Empty bind 'repeat' target");
                return;
            }

            if (typeof dataContext !== "object" || !dataContext) {
                console.warn("A bind 'repeat' can only be used with an object data context");
                return;
            }

            var sourceArray = dataContext[bindTemplate.source] || [];

            if (!sourceArray || sourceArray.constructor.name !== "Array" ) {
                console.warn("A bind 'repeat' did not find an array in the source field of the data context");
                return;
            }

            var template = target.clone()
              , container = target.parent()
              ;

            // run the pre-filtering handler
            var filterFunction = Utils.findFunction (self, bindTemplate.preFilter) || Utils.findFunction (window, bindTemplate.prefilter);
            if (filterFunction) {
                sourceArray = filterFunction (self, dataContext, bindTemplate.source, sourceArray, container);
            }

            // run the binds for each item
            for (var i = 0; i < sourceArray.length; ++i) {

                var newDom = template.clone();

                if (!bindTemplate.binds || !bindTemplate.binds.length) {
                    continue;
                }

                for (var j = 0; j < bindTemplate.binds.length; ++j) {
                    var bind = bindTemplate.binds[j];
                    bind.context = newDom;
                    Bind.call (self, bind, sourceArray[i]);
                }

                container.append(newDom);
            }

            // run the post-filtering handler
            filterFunction = Utils.findFunction (self, bindTemplate.postFilter) || Utils.findFunction (window, bindTemplate.postFilter);
            if (filterFunction) {
                sourceArray = filterFunction (self, dataContext, bindTemplate.source, sourceArray, container);
            }

            target.remove();
        }
    }

    for (var key in bind) {
        if (!bind.hasOwnProperty(key)) continue;

        if (domManipulators[key]) {
            domManipulators[key](target, context, bind[key], dataContext);
        }
    }

    if (bind.on) {
        for (var i = 0; i < bind.on.length; ++i) {
            var curOn = bind.on[i];
            if (curOn.handler || curOn.emit) {
                (function (curOn) {
                    var t = target;
                    var s = null;

                    // of the delegated option is set, this bind will work for future DOM insertions
                    if (curOn.delegated) {
                        t = context;
                        s = target.selector;
                    }

                    t.on(curOn.name, s,function(event) {
                        event.stopPropagation();

                        var name = curOn.handler;
                        var args = [];

                        if (typeof name === "object") {
                            args = name.args || [];
                            name = name.name;
                        }

                        // if the noEvent option is set, the DOM event will not be passed to the called handler or emitted event
                        if (!curOn.noEvent) {
                            args.push(event);
                        }

                        args.push(dataContext);

                        if (typeof name === "function") {
                            name.apply(self, args);
                            return false;
                        }

                        var handler = Utils.findFunction (self, name) || Utils.findFunction (window, name);

                        if (typeof handler === "function") {
                            handler.apply(self, args);
                        }

                        if (curOn.emit) {
                            self.emit (curOn.emit, dataContext);
                        }

                        return false;
                    });
                })(curOn);
            }
        }
    }

    for (var key in bind.listen) {
        if (!bind.listen.hasOwnProperty(key)) continue;

        var curListen = bind.listen[key];
        self.on (curListen.name, curListen.miid, self[curListen.handler]);
    }
};
<|endoftext|>


<commit_before>//Importing modules to print and manage the app
const {ipcMain, Menu, shell, app, BrowserWindow} = require('electron');
var os = require("os");
var fs = require("fs");
var path = require("path");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let workerWindow;

function createWindow() {
    /*MAIN WINDOWS*/
    mainWindow = new BrowserWindow({
        transparent: false,
        frame: false,
        fullscreen: false,
        width: 780,
        height: 350,
        resizable: false,
        movable: false,
        icon: __dirname + '/styles/images/app.png'
    });
    //mainWindow.setIcon( __dirname + '/styles/images/appIcon.png');

    mainWindow.loadURL(`file://${__dirname}/index.html`);
    mainWindow.on('closed', function () {
        mainWindow = null;
        workerWindow.close();
        workerWindow = null;
    });
    /*WORKER WINDOW*/
    workerWindow = new BrowserWindow({ show: false });
    workerWindow.loadURL(`file://${__dirname}/worker.html`);
    workerWindow.hide();
}
app.on('ready', createWindow);
app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.on('activate', function () {
    if (mainWindow === null) {
        createWindow();
    }
});

ipcMain.on("printPDF", function (event, content) {
    workerWindow.webContents.send("printPDF", content);
});

app.on("open-url", function (event, content) {
    event.preventDefault();
});

/*TRIGGER PRINT FUNCTION, NEED CALIBRATE*/
ipcMain.on("printer", function (event) {
    workerWindow.webContents.print();
//    mainWindow.webContents.print();
});

ipcMain.on("readyToPrintPDF", function (event) {
    const pdfPath = path.join(os.tmpdir(), 'print.pdf');
    //    workerWindow.webContents.print({silent: true});
    workerWindow.webContents.printToPDF({}, function (error, data) {
        if (error) {
            throw error;
        }
        fs.writeFile(pdfPath, data, function (error) {
            if (error) {
                throw error;
            }
            shell.openItem(pdfPath);
            event.sender.send('wrote-pdf', pdfPath);
        })
    })
});<commit_msg>metodos para manejar windows squirrel para la instalacion<commit_after>const {ipcMain, Menu, shell, app, BrowserWindow} = require('electron');
// this should be placed at top of main.js to handle setup events quickly
if (handleSquirrelEvent()) {
  // squirrel event handled and app will exit in 1000ms, so don't do anything else
  return;
}

function handleSquirrelEvent() {
  if (process.argv.length === 1) {
    return false;
  }

  const ChildProcess = require('child_process');
  const path = require('path');

  const appFolder = path.resolve(process.execPath, '..');
  const rootAtomFolder = path.resolve(appFolder, '..');
  const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
  const exeName = path.basename(process.execPath);

  const spawn = function(command, args) {
    let spawnedProcess, error;

    try {
      spawnedProcess = ChildProcess.spawn(command, args, {detached: true});
    } catch (error) {}

    return spawnedProcess;
  };

  const spawnUpdate = function(args) {
    return spawn(updateDotExe, args);
  };

  const squirrelEvent = process.argv[1];
  switch (squirrelEvent) {
    case '--squirrel-install':
    case '--squirrel-updated':
      // Optionally do things such as:
      // - Add your .exe to the PATH
      // - Write to the registry for things like file associations and
      //   explorer context menus

      // Install desktop and start menu shortcuts
      spawnUpdate(['--createShortcut', exeName]);

      setTimeout(app.quit, 1000);
      return true;

    case '--squirrel-uninstall':
      // Undo anything you did in the --squirrel-install and
      // --squirrel-updated handlers

      // Remove desktop and start menu shortcuts
      spawnUpdate(['--removeShortcut', exeName]);

      setTimeout(app.quit, 1000);
      return true;

    case '--squirrel-obsolete':
      // This is called on the outgoing version of your app before
      // we update to the new version - it's the opposite of
      // --squirrel-updated

      app.quit();
      return true;
  }
};

//Importing modules to print and manage the app

var os = require("os");
var fs = require("fs");
var path = require("path");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let workerWindow;

function createWindow() {
    /*MAIN WINDOWS*/
    mainWindow = new BrowserWindow({
        transparent: false,
        frame: false,
        fullscreen: false,
        width: 780,
        height: 350,
        resizable: false,
        movable: false,
        icon: __dirname + '/styles/images/app.png'
    });
    //mainWindow.setIcon( __dirname + '/styles/images/appIcon.png');

    mainWindow.loadURL(`file://${__dirname}/index.html`);
    mainWindow.on('closed', function () {
        mainWindow = null;
        workerWindow.close();
        workerWindow = null;
    });
    /*WORKER WINDOW*/
    workerWindow = new BrowserWindow({ show: false });
    workerWindow.loadURL(`file://${__dirname}/worker.html`);
    workerWindow.hide();
}
app.on('ready', createWindow);
app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.on('activate', function () {
    if (mainWindow === null) {
        createWindow();
    }
});

ipcMain.on("printPDF", function (event, content) {
    workerWindow.webContents.send("printPDF", content);
});

app.on("open-url", function (event, content) {
    event.preventDefault();
});

/*TRIGGER PRINT FUNCTION, NEED CALIBRATE*/
ipcMain.on("printer", function (event) {
    workerWindow.webContents.print();
//    mainWindow.webContents.print();
});

ipcMain.on("readyToPrintPDF", function (event) {
    const pdfPath = path.join(os.tmpdir(), 'print.pdf');
    //    workerWindow.webContents.print({silent: true});
    workerWindow.webContents.printToPDF({}, function (error, data) {
        if (error) {
            throw error;
        }
        fs.writeFile(pdfPath, data, function (error) {
            if (error) {
                throw error;
            }
            shell.openItem(pdfPath);
            event.sender.send('wrote-pdf', pdfPath);
        })
    })
});<|endoftext|>


<commit_before>"use strict";

// modified BufferBuilder

function BufferBuilder(initialCapacity) {
  var buffer = Buffer.isBuffer(initialCapacity) ? initialCapacity : new Buffer(initialCapacity || 512);
  this.buffers = [buffer];

  this.writeIndex = 0;
  this.length = 0;
}

/* Append a Buffer */
BufferBuilder.prototype.appendBuffer = function(source) {
  if (source.length === 0) return this;

  /* slice the tail buffer */
  var tail = this.buffers[this.buffers.length-1];
  this.buffers[this.buffers.length-1] = tail.slice(0, this.writeIndex);

  /* add the new buffer */
  this.buffers.push(source);
  this.writeIndex = source.length;
  this.length += source.length;

  return this;
};

/* Prepend a Buffer */
BufferBuilder.prototype.prependBuffer = function(source) {
  if (source.length === 0) return this;
  this.buffers.unshift(source);
  this.length += source.length;
  return this;
}

BufferBuilder.prototype.getBufferWithSpace = function(size) {
  var buf = this.buffers[this.buffers.length-1];
  if (this.writeIndex + size > buf.length) {
    /* slice the current buffer */
    this.buffers[this.buffers.length-1] = buf.slice(0, this.writeIndex);
    /* add a new buffer */
    var newbuf = new Buffer(Math.max(buf.length*2, size));
    this.buffers.push(newbuf);
    this.writeIndex = 0;
    buf = newbuf
  }
  return buf;
}

function makeAppender(encoder, size) {
  return function(x) {
    var buf = this.getBufferWithSpace(size);
    encoder.call(buf, x, this.writeIndex, true);
    this.writeIndex += size;
    this.length += size;

    return this;
  };
}

BufferBuilder.prototype.appendUInt8 = makeAppender(Buffer.prototype.writeUInt8, 1);
BufferBuilder.prototype.appendUInt16LE = makeAppender(Buffer.prototype.writeUInt16LE, 2);
BufferBuilder.prototype.appendUInt16BE = makeAppender(Buffer.prototype.writeUInt16BE, 2);
BufferBuilder.prototype.appendUInt32LE = makeAppender(Buffer.prototype.writeUInt32LE, 4);
BufferBuilder.prototype.appendUInt32BE = makeAppender(Buffer.prototype.writeUInt32BE, 4);
BufferBuilder.prototype.appendInt8 = makeAppender(Buffer.prototype.writeInt8, 1);
BufferBuilder.prototype.appendInt16LE = makeAppender(Buffer.prototype.writeInt16LE, 2);
BufferBuilder.prototype.appendInt16BE = makeAppender(Buffer.prototype.writeInt16BE, 2);
BufferBuilder.prototype.appendInt32LE = makeAppender(Buffer.prototype.writeInt32LE, 4);
BufferBuilder.prototype.appendInt32BE = makeAppender(Buffer.prototype.writeInt32BE, 4);
BufferBuilder.prototype.appendFloatLE = makeAppender(Buffer.prototype.writeFloatLE, 4);
BufferBuilder.prototype.appendFloatBE = makeAppender(Buffer.prototype.writeFloatBE, 4);
BufferBuilder.prototype.appendDoubleLE = makeAppender(Buffer.prototype.writeDoubleLE, 8);
BufferBuilder.prototype.appendDoubleBE = makeAppender(Buffer.prototype.writeDoubleBE, 8);

BufferBuilder.prototype.appendStringEx = function(str, size, encoding) {
  if (!size) return;
  var buf = this.getBufferWithSpace(size);
  buf.write(str, this.writeIndex, size, encoding);
  this.writeIndex += size;
  this.length += size;

  return this;
};

BufferBuilder.prototype.appendString = function(str, encoding) {
  return this.appendStringEx(str, Buffer.byteLength(str, encoding), encoding);
}

BufferBuilder.prototype.appendStringZero = function(str, encoding) {
  return this.appendString(str + '\0', encoding);
}

BufferBuilder.prototype.appendFill = function(value, count) {
  if (!count) return;
  var buf = this.getBufferWithSpace(count);
  buf.fill(value, this.writeIndex, this.writeIndex + count);
  this.writeIndex += count;
  this.length += count;

  return this;
};

/* Convert to a plain Buffer */
BufferBuilder.prototype.get = function() {
  /* slice the tail buffer */
  var tail = this.buffers[this.buffers.length-1];
  this.buffers[this.buffers.length-1] = tail.slice(0, this.writeIndex);
  /* concatenate them */
  return Buffer.concat(this.buffers);
};

// Binn

exports.encode = encode;
exports.decode = decode;

function Decoder(buffer, offset) {
  this.offset = offset || 0;
  this.buffer = buffer;
}
Decoder.prototype.list = function (length) {
  var value = new Array(length);
  for (var i = 0; i < length; i++) {
    value[i] = this.parse();
  }
  return value;
};
Decoder.prototype.map = function (length) {
  var value = {};
  for (var i = 0; i < length; i++) {
    var key = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    value[key] = this.parse();
  }
  return value;
};
Decoder.prototype.obj = function (count) {
  var value = {};
  for (var i = 0; i < count; i++) {
    var keylen = this.buffer[this.offset];
    this.offset++;
    var key = this.buffer.toString('utf8', this.offset, this.offset + keylen);
    this.offset += keylen;
    value[key] = this.parse();
  }
  return value;
};
Decoder.prototype.blob = function (length) {
  var value = this.buffer.slice(this.offset, this.offset + length);
  this.offset += length;
  return value;
};
Decoder.prototype.string = function (length) {
  var value = this.buffer.toString('utf8', this.offset, this.offset + length);
  this.offset += length + 1;  // null terminator
  return value;
};
Decoder.prototype.getVarint = function () {
  var value = this.buffer[this.offset];
  if (value & 0x80) {
    value = this.buffer.readInt32BE(this.offset);
    value &= 0x7FFFFFFF;
    this.offset += 4;
  } else {
    this.offset++;
  }
  return value;
};
Decoder.prototype.parse = function () {
  var type, size, count, value;  //, extType

  type = this.buffer[this.offset];
  this.offset++;

  switch (type) {
  // List
  case 0xE0:
    size = this.getVarint();
    count = this.getVarint();
    return this.list(count);
  // Map
  case 0xE1:
    size = this.getVarint();
    count = this.getVarint();
    return this.map(count);
  // Object
  case 0xE2:
    size = this.getVarint();
    count = this.getVarint();
    return this.obj(count);

  // nil
  case 0x00:
    this.offset++;
    return null;
  // true
  case 0x01:
    this.offset++;
    return true;
  // false
  case 0x02:
    this.offset++;
    return false;
  // undefined
  case 0x03:
    this.offset++;
    return undefined;

  // uint8
  case 0x20:
    value = this.buffer[this.offset];
    this.offset++;
    return value;
  // uint 16
  case 0x40:
    value = this.buffer.readUInt16BE(this.offset);
    this.offset += 2;
    return value;
  // uint 32
  case 0x60:
    value = this.buffer.readUInt32BE(this.offset);
    this.offset += 4;
    return value;
  // uint64
  case 0x80:
    value = this.buffer.readUInt64BE(this.offset);
    this.offset += 8;
    return value;

  // int 8
  case 0x21:
    value = this.buffer.readInt8(this.offset);
    this.offset++;
    return value;
  // int 16
  case 0x41:
    value = this.buffer.readInt16BE(this.offset);
    this.offset += 2;
    return value;
  // int 32
  case 0x61:
    value = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    return value;
  // int 64
  case 0x81:
    value = this.buffer.readInt64BE(this.offset);
    this.offset += 8;
    return value;

  // float 32
  case 0x62:
    value = this.buffer.readFloatBE(this.offset);
    this.offset += 4;
    return value;
  // float 64 / double
  case 0x82:
    value = this.buffer.readDoubleBE(this.offset);
    this.offset += 8;
    return value;

  // string
  case 0xA0:
    size = this.getVarint();
    return this.string(size);

  // datetime, date, time, decimalstr
  // TODO

  // blob
  case 0xC0:
    size = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    return this.blob(size);

  }

  throw new Error("Unknown type 0x" + type.toString(16));
};
function decode(buffer) {
  var decoder = new Decoder(buffer);
  var value = decoder.parse();
  if (decoder.offset !== buffer.length) throw new Error((buffer.length - decoder.offset) + " trailing bytes");
  return value;
}

function encodeableKeys (value) {
  return Object.keys(value).filter(function (e) {
    return typeof value[e] !== 'function' || value[e].toJSON;
  });
}
function encode(value, builder) {
  var type = typeof value;
  var count, size;

  // String
  if (type === "string") {
    size = Buffer.byteLength(value);
    // store the type
    builder.appendUInt8(0xA0);
    // store the size
    if (size > 127) {
      builder.appendInt32BE(size | 0x80000000);
    } else {
      builder.appendUInt8(size);
    }
    // store the string
    builder.appendStringEx(value + '\0', size + 1);
    return;
  }

  // Blob
  if (Buffer.isBuffer(value)) {
    size = value.length;
    // store the type
    builder.appendUInt8(0xC0);
    // store the size
    if (size > 127) {
      builder.appendInt32BE(size | 0x80000000);
    } else {
      builder.appendUInt8(size);
    }
    // store the string
    builder.appendBuffer(value);
    return;
  }

  if (type === "number") {
    // Floating Point
    if ((value << 0) !== value) {
      // store the type
      builder.appendUInt8(0x82);
      // store the value
      builder.appendDoubleBE(value);
      return;
    }

    // Integers
    if (value >=0) {
      // uint 8
      if (value < 0x100) {
        // store the type
        builder.appendUInt8(0x20);
        // store the value
        builder.appendUInt8(value);
        return;
      }
      // uint 16
      if (value < 0x10000) {
        // store the type
        builder.appendUInt8(0x40);
        // store the value
        builder.appendUInt16BE(value);
        return;
      }
      // uint 32
      if (value < 0x100000000) {
        // store the type
        builder.appendUInt8(0x60);
        // store the value
        builder.appendUInt32BE(value);
        return 5;
      }
      // uint 64
      if (value < 0x10000000000000000) {
        // store the type
        builder.appendUInt8(0x80);
        // store the value
        builder.appendUInt64BE(value);
        return;
      }
      throw new Error("Number too big 0x" + value.toString(16));
    }
    // int 8
    if (value >= -0x80) {
      // store the type
      builder.appendUInt8(0x21);
      // store the value
      builder.appendInt8(value);
      return;
    }
    // int 16
    if (value >= -0x8000) {
      // store the type
      builder.appendUInt8(0x41);
      // store the value
      builder.appendInt16BE(value);
      return;
    }
    // int 32
    if (value >= -0x80000000) {
      // store the type
      builder.appendUInt8(0x61);
      // store the value
      builder.appendInt32BE(value);
      return;
    }
    // int 64
    if (value >= -0x8000000000000000) {
      // store the type
      builder.appendUInt8(0x81);
      // store the value
      builder.appendInt64BE(value);
      return;
    }
    throw new Error("Number too small -0x" + value.toString(16).substr(1));
  }

  if (type === "undefined") {
    // store the type
    builder.appendUInt8(0x03); // special type
    return;
  }

  // null
  if (value === null) {
    // store the type
    builder.appendUInt8(0x00);
    return;
  }

  // Boolean
  if (type === "boolean") {
    // store the type
    builder.appendUInt8(value ? 0x01 : 0x02);
    return;
  }

  // Custom toJSON function.
  if (typeof value.toJSON === 'function') {
    return encode(value.toJSON(), builder);
  }

  // Container Types
  if (type === "object") {

    var isArray = Array.isArray(value);

    if (isArray) {
      count = value.length;
    }
    else {
      var keys = encodeableKeys(value);
      count = keys.length;
    }

    // create a new buffer builder
    builder = new BufferBuilder();

    if (isArray) {
      type = 0xE0;
      // add the values to it
      for (var i = 0; i < count; i++) {
        encode(value[i], builder);
      }
    }
    else {
      type = 0xE2;
      // add the key value pairs to it
      for (var i = 0; i < count; i++) {
        var key = keys[i];
        // store the key
        size = Buffer.byteLength(key);
        if (size > 255) {
          throw new Error("Key is longer than 255: " + key);
        }
        builder.appendUInt8(size);
        builder.appendStringEx(key, size);
        // store the value
        encode(value[key], builder);
      }
    }

    // save the header
    var header = Buffer.allocUnsafe(9);
    header.writeUInt8(type, 0);
    // calculate the total size including the header
    size = builder.length + 3;
    if (count > 127) size += 3;
    if (size  > 127) size += 3;
    var offset;
    // write the size
    if (size > 127) {
      header.writeInt32BE(size | 0x80000000, 1);
      offset = 5;
    } else {
      header.writeUInt8(size, 1);
      offset = 2;
    }
    // write the count
    if (count > 127) {
      header.writeInt32BE(count | 0x80000000, offset);
      offset += 4;
    } else {
      header.writeUInt8(count, offset);
      offset += 1;
    }
    // if the header is smaller than the max, resize it
    if (offset < 9) {
      header = header.slice(0, offset);
    }
    // prepend the header in the builder and return the resulting buffer
    builder.prependBuffer(header);
    return builder.get();
  }

  if (type === "function") return undefined;
  throw new Error("Unknown type " + type);
}
<commit_msg>corrections on code<commit_after>"use strict";

// modified BufferBuilder

function BufferBuilder(initialCapacity) {
  var buffer = Buffer.isBuffer(initialCapacity) ? initialCapacity : new Buffer(initialCapacity || 512);
  this.buffers = [buffer];

  this.writeIndex = 0;
  this.length = 0;
}

/* Append a Buffer */
BufferBuilder.prototype.appendBuffer = function(source) {
  if (source.length === 0) return this;

  /* slice the tail buffer */
  var tail = this.buffers[this.buffers.length-1];
  this.buffers[this.buffers.length-1] = tail.slice(0, this.writeIndex);

  /* add the new buffer */
  this.buffers.push(source);
  this.writeIndex = source.length;
  this.length += source.length;

  return this;
};

/* Prepend a Buffer */
BufferBuilder.prototype.prependBuffer = function(source) {
  if (source.length === 0) return this;
  this.buffers.unshift(source);
  this.length += source.length;
  return this;
}

BufferBuilder.prototype.getBufferWithSpace = function(size) {
  var buf = this.buffers[this.buffers.length-1];
  if (this.writeIndex + size > buf.length) {
    /* slice the current buffer */
    this.buffers[this.buffers.length-1] = buf.slice(0, this.writeIndex);
    /* add a new buffer */
    var newbuf = new Buffer(Math.max(buf.length*2, size));
    this.buffers.push(newbuf);
    this.writeIndex = 0;
    buf = newbuf
  }
  return buf;
}

function makeAppender(encoder, size) {
  return function(x) {
    var buf = this.getBufferWithSpace(size);
    encoder.call(buf, x, this.writeIndex, true);
    this.writeIndex += size;
    this.length += size;

    return this;
  };
}

BufferBuilder.prototype.appendUInt8 = makeAppender(Buffer.prototype.writeUInt8, 1);
BufferBuilder.prototype.appendUInt16LE = makeAppender(Buffer.prototype.writeUInt16LE, 2);
BufferBuilder.prototype.appendUInt16BE = makeAppender(Buffer.prototype.writeUInt16BE, 2);
BufferBuilder.prototype.appendUInt32LE = makeAppender(Buffer.prototype.writeUInt32LE, 4);
BufferBuilder.prototype.appendUInt32BE = makeAppender(Buffer.prototype.writeUInt32BE, 4);
BufferBuilder.prototype.appendInt8 = makeAppender(Buffer.prototype.writeInt8, 1);
BufferBuilder.prototype.appendInt16LE = makeAppender(Buffer.prototype.writeInt16LE, 2);
BufferBuilder.prototype.appendInt16BE = makeAppender(Buffer.prototype.writeInt16BE, 2);
BufferBuilder.prototype.appendInt32LE = makeAppender(Buffer.prototype.writeInt32LE, 4);
BufferBuilder.prototype.appendInt32BE = makeAppender(Buffer.prototype.writeInt32BE, 4);
BufferBuilder.prototype.appendFloatLE = makeAppender(Buffer.prototype.writeFloatLE, 4);
BufferBuilder.prototype.appendFloatBE = makeAppender(Buffer.prototype.writeFloatBE, 4);
BufferBuilder.prototype.appendDoubleLE = makeAppender(Buffer.prototype.writeDoubleLE, 8);
BufferBuilder.prototype.appendDoubleBE = makeAppender(Buffer.prototype.writeDoubleBE, 8);

BufferBuilder.prototype.appendStringEx = function(str, size, encoding) {
  if (!size) return;
  var buf = this.getBufferWithSpace(size);
  buf.write(str, this.writeIndex, size, encoding);
  this.writeIndex += size;
  this.length += size;

  return this;
};

BufferBuilder.prototype.appendString = function(str, encoding) {
  return this.appendStringEx(str, Buffer.byteLength(str, encoding), encoding);
}

BufferBuilder.prototype.appendStringZero = function(str, encoding) {
  return this.appendString(str + '\0', encoding);
}

BufferBuilder.prototype.appendFill = function(value, count) {
  if (!count) return;
  var buf = this.getBufferWithSpace(count);
  buf.fill(value, this.writeIndex, this.writeIndex + count);
  this.writeIndex += count;
  this.length += count;

  return this;
};

/* Convert to a plain Buffer */
BufferBuilder.prototype.get = function() {
  /* slice the tail buffer */
  var tail = this.buffers[this.buffers.length-1];
  this.buffers[this.buffers.length-1] = tail.slice(0, this.writeIndex);
  /* concatenate them */
  return Buffer.concat(this.buffers);
};

// Binn

exports.encode = encode;
exports.decode = decode;

function Decoder(buffer, offset) {
  this.offset = offset || 0;
  this.buffer = buffer;
}
Decoder.prototype.list = function (length) {
  var value = new Array(length);
  for (var i = 0; i < length; i++) {
    value[i] = this.parse();
  }
  return value;
};
Decoder.prototype.map = function (length) {
  var value = {};
  for (var i = 0; i < length; i++) {
    var key = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    value[key] = this.parse();
  }
  return value;
};
Decoder.prototype.obj = function (count) {
  var value = {};
  for (var i = 0; i < count; i++) {
    var keylen = this.buffer[this.offset];
    this.offset++;
    var key = this.buffer.toString('utf8', this.offset, this.offset + keylen);
    this.offset += keylen;
    value[key] = this.parse();
  }
  return value;
};
Decoder.prototype.blob = function (length) {
  var value = this.buffer.slice(this.offset, this.offset + length);
  this.offset += length;
  return value;
};
Decoder.prototype.string = function (length) {
  var value = this.buffer.toString('utf8', this.offset, this.offset + length);
  this.offset += length + 1;  // null terminator
  return value;
};
Decoder.prototype.getVarint = function () {
  var value = this.buffer[this.offset];
  if (value & 0x80) {
    value = this.buffer.readInt32BE(this.offset);
    value &= 0x7FFFFFFF;
    this.offset += 4;
  } else {
    this.offset++;
  }
  return value;
};
Decoder.prototype.parse = function () {
  var type, size, count, value;

  type = this.buffer[this.offset];
  this.offset++;

  switch (type) {
  // List
  case 0xE0:
    size = this.getVarint();
    count = this.getVarint();
    return this.list(count);
  // Map
  case 0xE1:
    size = this.getVarint();
    count = this.getVarint();
    return this.map(count);
  // Object
  case 0xE2:
    size = this.getVarint();
    count = this.getVarint();
    return this.obj(count);

  // nil
  case 0x00:
    return null;
  // true
  case 0x01:
    return true;
  // false
  case 0x02:
    return false;
  // undefined
  case 0x03:
    return undefined;

  // uint8
  case 0x20:
    value = this.buffer[this.offset];
    this.offset++;
    return value;
  // uint 16
  case 0x40:
    value = this.buffer.readUInt16BE(this.offset);
    this.offset += 2;
    return value;
  // uint 32
  case 0x60:
    value = this.buffer.readUInt32BE(this.offset);
    this.offset += 4;
    return value;
  // uint64
  case 0x80:
    value = this.buffer.readUInt64BE(this.offset);
    this.offset += 8;
    return value;

  // int 8
  case 0x21:
    value = this.buffer.readInt8(this.offset);
    this.offset++;
    return value;
  // int 16
  case 0x41:
    value = this.buffer.readInt16BE(this.offset);
    this.offset += 2;
    return value;
  // int 32
  case 0x61:
    value = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    return value;
  // int 64
  case 0x81:
    value = this.buffer.readInt64BE(this.offset);
    this.offset += 8;
    return value;

  // float 32
  case 0x62:
    value = this.buffer.readFloatBE(this.offset);
    this.offset += 4;
    return value;
  // float 64 / double
  case 0x82:
    value = this.buffer.readDoubleBE(this.offset);
    this.offset += 8;
    return value;

  // string
  case 0xA0:
    size = this.getVarint();
    return this.string(size);

  // datetime, date, time, decimalstr
  // TODO

  // blob
  case 0xC0:
    size = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    return this.blob(size);

  }

  throw new Error("Unknown type 0x" + type.toString(16));
};
function decode(buffer) {
  var decoder = new Decoder(buffer);
  var value = decoder.parse();
  if (decoder.offset !== buffer.length) throw new Error((buffer.length - decoder.offset) + " trailing bytes");
  return value;
}

function encodeableKeys (value) {
  return Object.keys(value).filter(function (e) {
    return typeof value[e] !== 'function' || value[e].toJSON;
  });
}
function encode(value, builder) {
  var type = typeof value;
  var count, size;

  // String
  if (type === "string") {
    size = Buffer.byteLength(value);
    // store the type
    builder.appendUInt8(0xA0);
    // store the size
    if (size > 127) {
      builder.appendInt32BE(size | 0x80000000);
    } else {
      builder.appendUInt8(size);
    }
    // store the string
    builder.appendStringEx(value + '\0', size + 1);
    return;
  }

  // Blob
  if (Buffer.isBuffer(value)) {
    size = value.length;
    // store the type
    builder.appendUInt8(0xC0);
    // store the size
    builder.appendInt32BE(size);
    // store the string
    builder.appendBuffer(value);
    return;
  }

  if (type === "number") {
    // Floating Point
    if ((value << 0) !== value) {
      // store the type
      builder.appendUInt8(0x82);
      // store the value
      builder.appendDoubleBE(value);
      return;
    }

    // Integers
    if (value >=0) {
      // uint 8
      if (value < 0x100) {
        // store the type
        builder.appendUInt8(0x20);
        // store the value
        builder.appendUInt8(value);
        return;
      }
      // uint 16
      if (value < 0x10000) {
        // store the type
        builder.appendUInt8(0x40);
        // store the value
        builder.appendUInt16BE(value);
        return;
      }
      // uint 32
      if (value < 0x100000000) {
        // store the type
        builder.appendUInt8(0x60);
        // store the value
        builder.appendUInt32BE(value);
        return 5;
      }
      // uint 64
      if (value < 0x10000000000000000) {
        // store the type
        builder.appendUInt8(0x80);
        // store the value
        builder.appendUInt64BE(value);
        return;
      }
      throw new Error("Number too big 0x" + value.toString(16));
    }
    // int 8
    if (value >= -0x80) {
      // store the type
      builder.appendUInt8(0x21);
      // store the value
      builder.appendInt8(value);
      return;
    }
    // int 16
    if (value >= -0x8000) {
      // store the type
      builder.appendUInt8(0x41);
      // store the value
      builder.appendInt16BE(value);
      return;
    }
    // int 32
    if (value >= -0x80000000) {
      // store the type
      builder.appendUInt8(0x61);
      // store the value
      builder.appendInt32BE(value);
      return;
    }
    // int 64
    if (value >= -0x8000000000000000) {
      // store the type
      builder.appendUInt8(0x81);
      // store the value
      builder.appendInt64BE(value);
      return;
    }
    throw new Error("Number too small -0x" + value.toString(16).substr(1));
  }

  if (type === "undefined") {
    // store the type
    builder.appendUInt8(0x03); // special type
    return;
  }

  // null
  if (value === null) {
    // store the type
    builder.appendUInt8(0x00);
    return;
  }

  // Boolean
  if (type === "boolean") {
    // store the type
    builder.appendUInt8(value ? 0x01 : 0x02);
    return;
  }

  // Custom toJSON function.
  if (typeof value.toJSON === 'function') {
    return encode(value.toJSON(), builder);
  }

  // Container Types
  if (type === "object") {

    // create a new buffer builder
    var builder2 = new BufferBuilder();
    var isArray = Array.isArray(value);

    if (isArray) {
      count = value.length;
    }
    else {
      var keys = encodeableKeys(value);
      count = keys.length;
    }

    if (isArray) {
      type = 0xE0;
      // add the values to it
      for (var i = 0; i < count; i++) {
        encode(value[i], builder2);
      }
    }
    else {
      type = 0xE2;
      // add the key value pairs to it
      for (var i = 0; i < count; i++) {
        var key = keys[i];
        // store the key
        size = Buffer.byteLength(key);
        if (size > 255) {
          throw new Error("Key is longer than 255: " + key);
        }
        builder2.appendUInt8(size);
        builder2.appendStringEx(key, size);
        // store the value
        encode(value[key], builder2);
      }
    }

    // save the header
    var header = Buffer.allocUnsafe(9);
    header.writeUInt8(type, 0);
    // calculate the total size including the header
    size = builder2.length + 3;
    if (count > 127) size += 3;
    if (size  > 127) size += 3;
    var offset;
    // write the size
    if (size > 127) {
      header.writeInt32BE(size | 0x80000000, 1);
      offset = 5;
    } else {
      header.writeUInt8(size, 1);
      offset = 2;
    }
    // write the count
    if (count > 127) {
      header.writeInt32BE(count | 0x80000000, offset);
      offset += 4;
    } else {
      header.writeUInt8(count, offset);
      offset += 1;
    }
    // if the header is smaller than the max, resize it
    if (offset < 9) {
      header = header.slice(0, offset);
    }
    // prepend the header in the builder and return the resulting buffer
    builder2.prependBuffer(header);
    if (builder) {
      builder.appendBuffer(builder2.get());
      return;
    } else {
      return builder2.get();
    }
  }

  if (type === "function") return undefined;
  throw new Error("Unknown type: " + type);
}
<|endoftext|>


<commit_before>

// This is filled with functions where the parameters are the complete nodes and complete edges, for any modifications.
// { func(), storedVariables[] }
var queuedActions = [];

function CompileNode(_scriptStr, _scriptStrPos, result)
{
    // this function compiles script lines until it reaches an IF statement or a checkpoint
    // returns the new script str pos
}

function ToggleButtons(onOrOff)
{
	document.getElementById("fileItem").disabled = !onOrOff;
	document.getElementById("fileItemSave").disabled = !onOrOff;
	document.getElementById("compileButton").disabled = !onOrOff;
	for (var index = 0; index < gl.nodeInfoBoxes.length; index++) {
		var element = gl.nodeInfoBoxes[index];
		if(element)
			element.disabled = !onOrOff;
	}
}

function HideFunctionNodes()
{
	var hideNodes = document.getElementById("settHideFunctions").checked;

	if(hideNodes)
	{
		ToggleButtons(false);
		// iterate through ALL nodes, stash the function nodes and edges, remove them and re-draw
		gl._STASHED_DATA = JSON.stringify(SaveNodesAndEdges())

		for (var key in gl.nodesDataset._data) {
			if (gl.nodesDataset._data.hasOwnProperty(key)) {
				var node = gl.nodesDataset._data[key];
				if(node.nodeType !== Node.NodeTypes.narrative)
				{
					var edgesToNode = [];
					var edgesFromNode = [];
					for (var eKey in gl.edgesDataset._data) {
						if (gl.edgesDataset._data.hasOwnProperty(eKey)) {
							var edge = gl.edgesDataset._data[eKey];
							if(edge.from === node.id)
							{
								edgesFromNode.push(edge);
							}
							else if( edge.to === node.id)
							{
								edgesToNode.push(edge);
							}
							else continue;
						}
					}

					if(edgesFromNode.length != 1)
					{
						// We exclude these nodes because they are important :)
						continue;
					}

					for (var i = 0; i < edgesToNode.length; i++) {
						var edge = edgesToNode[i];
						gl.edgesDataset._data[edge.id].to = edgesFromNode[0].to;
					}

					delete gl.nodesDataset._data[key];
				} else continue;
				delete gl.edgesDataset._data[edgesFromNode[0].id];
			}
		}

		draw();
	}
	else
	{
		ToggleButtons(true);
		// restore stashed nodes
		if(!gl._STASHED_DATA)
		{
			// this should never happen
			return;
		}
		LoadProject(gl._STASHED_DATA);

		gl._STASHED_DATA = null;
	}
}

function CreateLoadMenu()
{
	ModalManager.createModal('<input id="projectLoadButton" type="file" onchange="HandleFiles();" title="Select Script Files">');
}

function HandleFiles()
{
	var file = "";
	gl.scriptFileInput = document.getElementById("projectLoadButton");
	for(i = 0; i < gl.scriptFileInput.files.length; i++)
	{
		file = (gl.scriptFileInput.files[i]);
	}
	var reader = new FileReader();
	reader.onload = function(e) {
		var hashedName = file.name.hashCode();
		LoadProject(e.target.result);
	};
	reader.readAsText(file, "UTF-8");
}

function LoadProject(jsonStr)
{
	var temp = JSON.parse(jsonStr);
	gl.nodesDataset = new vis.DataSet(temp.nodes);
	gl.edgesDataset = new vis.DataSet(temp.edges);
	draw();
}

function SaveNodesAndEdges()
{
	var output =
	{
		"nodes": [],
		"edges": []
	};

	var nodeIds = gl.nodesDataset.getIds();
	for(i = 0; i < nodeIds.length; i++)
	{
		output["nodes"].push(gl.nodesDataset._data[nodeIds[i]]);
	}

	var edgeIds = gl.edgesDataset.getIds();
	for(i = 0; i < edgeIds.length; i++)
	{
		output["edges"].push(gl.edgesDataset._data[edgeIds[i]]);
	}
	return output;
}

function SaveProject()
{
	var output = SaveNodesAndEdges();
	var blob = new Blob([JSON.stringify(output)], {type: "text/plain;charset=utf-8"});
	saveAs(blob, "test.m22proj");
}

async function SaveScripts_Async()
{
	var resultFiles = [];
	var numOfFiles = 0;
	var files = [];
	var nodeIds = gl.nodesDataset.getIds();
	for(i = 0; i < nodeIds.length; i++)
	{
		var fnameFound = -1;
		for(f = 0; f < files.length; f++)
		{
			if(files[f].name === gl.nodesDataset._data[nodeIds[i]].title)
			{
				fnameFound = f;
				break;
			}
		}
		if(fnameFound === -1)
		{
			numOfFiles++;

			var tempFile = {
				name: gl.nodesDataset._data[nodeIds[i]].title,
				nodes: []
			};
			tempFile.nodes.push(gl.nodesDataset._data[nodeIds[i]]);
			files.push(tempFile);
		}
		else
		{
			files[fnameFound].nodes.push(gl.nodesDataset._data[nodeIds[i]]);
		}
	}

	for(i = 0; i < files.length; i++)
	{
		files[i].nodes.sort(
			function(a,b)
			{
				return parseInt(a.level) - parseInt(a.level);
			}
		);
	}

	for(i = 0; i < files.length; i++)
	{
		var result = "";
		for(n = 0; n < files[i].nodes.length; n++)
		{
			result += files[i].nodes[n].startOfNode + "\n\n";
			result += files[i].nodes[n].SCRIPT_TXT + "\n\n";
			result += "\n\n" + files[i].nodes[n].endOfNode + "\n\n";
		}
		//resultFiles[files[i].name] = result;
		var blob = new Blob([result], {type: "text/plain;charset=utf-8"});
		saveAs(blob, files[i].name);
	}

}

function SaveScripts()
{
	SaveScripts_Async();
	alert("Saving scripts, please be patient!");
}

<commit_msg>Complete function node hide functionality<commit_after>

// This is filled with functions where the parameters are the complete nodes and complete edges, for any modifications.
// { func(), storedVariables[] }
var queuedActions = [];

function CompileNode(_scriptStr, _scriptStrPos, result)
{
    // this function compiles script lines until it reaches an IF statement or a checkpoint
    // returns the new script str pos
}

function ToggleButtons(onOrOff)
{
	document.getElementById("fileItem").disabled = !onOrOff;
	document.getElementById("fileItemSave").disabled = !onOrOff;
	document.getElementById("compileButton").disabled = !onOrOff;
	for (var index = 0; index < gl.nodeInfoBoxes.length; index++) {
		var element = gl.nodeInfoBoxes[index];
		if(element)
			element.disabled = !onOrOff;
	}
}

function HideFunctionNodes()
{
	var hideNodes = document.getElementById("settHideFunctions").checked;

	if(hideNodes)
	{
		ToggleButtons(false);
		// iterate through ALL nodes, stash the function nodes and edges, remove them and re-draw
		gl._STASHED_DATA = JSON.stringify(SaveNodesAndEdges())

		for (var key in gl.nodesDataset._data) {
			if (gl.nodesDataset._data.hasOwnProperty(key)) {
				var node = gl.nodesDataset._data[key];
				if(node.nodeType !== Node.NodeTypes.narrative)
				{
					var edgesToNode = [];
					var edgesFromNode = [];
					for (var eKey in gl.edgesDataset._data) {
						if (gl.edgesDataset._data.hasOwnProperty(eKey)) {
							var edge = gl.edgesDataset._data[eKey];
							if(edge.from === node.id)
							{
								edgesFromNode.push(edge);
							}
							else if( edge.to === node.id)
							{
								edgesToNode.push(edge);
							}
							else continue;
						}
					}

					// We exclude these nodes because they are important :)
					if(edgesFromNode.length != 1 || edgesToNode.length <= 0)
					{
						continue;
					}

					for (var i = 0; i < edgesToNode.length; i++) {
						var edge = edgesToNode[i];
						gl.edgesDataset._data[edge.id].to = edgesFromNode[0].to;
					}

					delete gl.nodesDataset._data[key];
				} else continue;
				delete gl.edgesDataset._data[edgesFromNode[0].id];
			}
		}

		draw();
	}
	else
	{
		ToggleButtons(true);
		// restore stashed nodes
		if(!gl._STASHED_DATA)
		{
			// this should never happen
			return;
		}

		gl._STASHED_DATA = JSON.parse(gl._STASHED_DATA);
		// edit stashed data with edited nodes
		for (var i = 0; i < gl._STASHED_DATA["nodes"].length; i++) {
			var stashedNode = gl._STASHED_DATA["nodes"][i];

			for (var nKey in gl.nodesDataset._data) {
				if (gl.nodesDataset._data.hasOwnProperty(nKey)) {
					var realNode = gl.nodesDataset._data[nKey];
					if(nKey === stashedNode.id)
					{
						SetNode(stashedNode,realNode);
						//stashedNode.SCRIPT_TXT = realNode.SCRIPT_TXT;
						break;
					}
				}
			}
		}
		gl._STASHED_DATA = JSON.stringify(gl._STASHED_DATA);

		LoadProject(gl._STASHED_DATA);

		gl._STASHED_DATA = null;
	}
}

function SetNode(node,props)
{
	for (var key in props) {
		if (props.hasOwnProperty(key)) {
			node[key] = props[key];
		}
	}
}

function CreateLoadMenu()
{
	ModalManager.createModal('<input id="projectLoadButton" type="file" onchange="HandleFiles();" title="Select Script Files">');
}

function HandleFiles()
{
	var file = "";
	gl.scriptFileInput = document.getElementById("projectLoadButton");
	for(i = 0; i < gl.scriptFileInput.files.length; i++)
	{
		file = (gl.scriptFileInput.files[i]);
	}
	var reader = new FileReader();
	reader.onload = function(e) {
		var hashedName = file.name.hashCode();
		LoadProject(e.target.result);
	};
	reader.readAsText(file, "UTF-8");
}

function LoadProject(jsonStr)
{
	var temp = JSON.parse(jsonStr);
	gl.nodesDataset = new vis.DataSet(temp.nodes);
	gl.edgesDataset = new vis.DataSet(temp.edges);
	draw();
}

function SaveNodesAndEdges()
{
	var output =
	{
		"nodes": [],
		"edges": []
	};

	var nodeIds = gl.nodesDataset.getIds();
	for(i = 0; i < nodeIds.length; i++)
	{
		output["nodes"].push(gl.nodesDataset._data[nodeIds[i]]);
	}

	var edgeIds = gl.edgesDataset.getIds();
	for(i = 0; i < edgeIds.length; i++)
	{
		output["edges"].push(gl.edgesDataset._data[edgeIds[i]]);
	}
	return output;
}

function SaveProject()
{
	var output = SaveNodesAndEdges();
	var blob = new Blob([JSON.stringify(output)], {type: "text/plain;charset=utf-8"});
	saveAs(blob, "test.m22proj");
}

async function SaveScripts_Async()
{
	var resultFiles = [];
	var numOfFiles = 0;
	var files = [];
	var nodeIds = gl.nodesDataset.getIds();
	for(i = 0; i < nodeIds.length; i++)
	{
		var fnameFound = -1;
		for(f = 0; f < files.length; f++)
		{
			if(files[f].name === gl.nodesDataset._data[nodeIds[i]].title)
			{
				fnameFound = f;
				break;
			}
		}
		if(fnameFound === -1)
		{
			numOfFiles++;

			var tempFile = {
				name: gl.nodesDataset._data[nodeIds[i]].title,
				nodes: []
			};
			tempFile.nodes.push(gl.nodesDataset._data[nodeIds[i]]);
			files.push(tempFile);
		}
		else
		{
			files[fnameFound].nodes.push(gl.nodesDataset._data[nodeIds[i]]);
		}
	}

	for(i = 0; i < files.length; i++)
	{
		files[i].nodes.sort(
			function(a,b)
			{
				return parseInt(a.level) - parseInt(a.level);
			}
		);
	}

	for(i = 0; i < files.length; i++)
	{
		var result = "";
		for(n = 0; n < files[i].nodes.length; n++)
		{
			result += files[i].nodes[n].startOfNode + "\n\n";
			result += files[i].nodes[n].SCRIPT_TXT + "\n\n";
			result += "\n\n" + files[i].nodes[n].endOfNode + "\n\n";
		}
		//resultFiles[files[i].name] = result;
		var blob = new Blob([result], {type: "text/plain;charset=utf-8"});
		saveAs(blob, files[i].name);
	}

}

function SaveScripts()
{
	SaveScripts_Async();
	alert("Saving scripts, please be patient!");
}

<|endoftext|>