<commit_before>(function() {
    'use strict';

    var DIR         = __dirname + '/../../',
        DIR_HTML    = DIR       + 'html/',
        DIR_LIB     = DIR       + 'lib/',
        DIR_SERVER  = __dirname + '/',
        DIR_FS      = DIR_HTML  + 'fs/',

        fs          = require('fs'),

        mellow      = require(DIR_SERVER + 'mellow'),
        ponse       = require(DIR_SERVER + 'ponse'),
        files       = require(DIR_SERVER + 'files'),
        minify      = require(DIR_SERVER + 'minify'),
        config      = require(DIR_SERVER + 'config'),

        Util        = require(DIR_LIB + 'util'),
        CloudFunc   = require(DIR_LIB + 'cloudfunc'),
        format      = require(DIR_LIB + 'format'),

        PATH_INDEX  = DIR_FS   + 'index.html',

        TMPL_PATH   = [
            'file',
            'panel',
            'path',
            'pathLink',
            'link',
        ],

        Template    = {},

        FS          = CloudFunc.FS;

    module.exports  = function(req, res, next) {
        readFiles(function() {
            route(req, res, next);
        });
    };

    /**
     * additional processing of index file
     */
    function indexProcessing(options) {
        var keysPanel, left, right,
            LEFT    = CloudFunc.PANEL_LEFT,
            RIGHT   = CloudFunc.PANEL_RIGHT,
            data    = options.data,
            panel   = options.panel;

        if (!config('showKeysPanel')) {
            keysPanel  = '<div class="keyspanel';
            data        = data.replace(keysPanel + '"', keysPanel +' hidden"');
        }

        left    = Util.render(Template.panel, {
            id      : LEFT,
            side    : 'left',
            content : panel
        });

        right    = Util.render(Template.panel, {
            id      : RIGHT,
            side    : 'right',
            content : panel
        });

        data = Util.render(data, {
            title   : CloudFunc.getTitle(),
            fm      : left + right
        });

        return data;
    }

    function readFiles(callback) {
        var filesList,
            paths       = {},

            lengthTmpl  = Object.keys(Template).length,
            lenthPath   = TMPL_PATH.length,
            isRead      = lengthTmpl === lenthPath;

        Util.checkArgs(arguments, ['callback']);

        if (isRead) {
            callback();
        } else {
            filesList   = TMPL_PATH.map(function(name) {
                var path = DIR_FS + name + '.html';

                paths[path] = name;

                return path;
            });

            files.read(filesList, 'utf8', function(error, files) {
                if (error)
                    Util.log(error.message);
                else
                    Object.keys(files).forEach(function(path) {
                        var name = paths[path];

                        Template[name] = files[path];
                    });

                callback();
            });
        }
    }

    /**
     * routing of server queries
     */
    function route(request, response, callback) {
        var name, p, isAuth, isFS, path;

        Util.checkArgs(arguments, ['req', 'res', 'callback']);

        name    = ponse.getPathName(request);
        isAuth  = Util.strCmp(name, ['/auth', '/auth/github']);
        isFS    = Util.strCmp(name, '/') || Util.isContainStrAtBegin(name, FS);

        p       = {
            request     : request,
            response    : response,
            gzip        : true,
            name        : name
        };

        if (!isAuth && !isFS)
            callback();
        else if (isAuth) {
            Util.log('* Routing' + '-> ' + name);

            p.name = DIR_HTML + name + '.html';
            ponse.sendFile(p);
        } else if (isFS) {
            name    = Util.rmStrOnce(name, CloudFunc.FS) || '/';
            path    = mellow.convertPath(name);

            mellow.read(path, function(error, dir) {
                if (dir)
                    dir.path = format.addSlashToEnd(name);

                if (error)
                    if (error.code !== 'ENOTDIR')
                        ponse.sendError(error, p);
                    else
                        fs.realpath(path, function(error, pathReal) {
                            if (!error)
                                p.name = pathReal;
                            else
                                p.name = path;

                            p.gzip = false;
                            ponse.sendFile(p);
                        });
                else
                    buildIndex(dir, function(error, data) {
                        var NOT_LOG = true;

                        p.name = PATH_INDEX;

                        if (error)
                            ponse.sendError(error, p);
                        else
                            ponse.send(data, p, NOT_LOG);
                    });
            });
        }
    }

    function buildIndex(json, callback) {
        var isMinify = config('minify');

        Util.exec.if(!isMinify, function(error, name) {
            fs.readFile(name || PATH_INDEX, 'utf8', function(error, template) {
                var panel, data;

                if (!error) {
                    panel   = CloudFunc.buildFromJSON({
                        data        : json,
                        template    : Template
                    }),

                    data    = indexProcessing({
                        panel   : panel,
                        data    : template,
                    });
                }

                Util.exec(callback, error, data);
            });
        },  function(callback) {
                minify(PATH_INDEX, {
                    log         : true,
                    returnName  : true
                }, callback);
        });
    }
})();
<commit_msg>fix(route) showKeysPanel<commit_after>(function() {
    'use strict';

    var DIR         = __dirname + '/../../',
        DIR_HTML    = DIR       + 'html/',
        DIR_LIB     = DIR       + 'lib/',
        DIR_SERVER  = __dirname + '/',
        DIR_FS      = DIR_HTML  + 'fs/',

        fs          = require('fs'),

        mellow      = require(DIR_SERVER + 'mellow'),
        ponse       = require(DIR_SERVER + 'ponse'),
        files       = require(DIR_SERVER + 'files'),
        minify      = require(DIR_SERVER + 'minify'),
        config      = require(DIR_SERVER + 'config'),

        Util        = require(DIR_LIB + 'util'),
        CloudFunc   = require(DIR_LIB + 'cloudfunc'),
        format      = require(DIR_LIB + 'format'),

        PATH_INDEX  = DIR_FS   + 'index.html',

        TMPL_PATH   = [
            'file',
            'panel',
            'path',
            'pathLink',
            'link',
        ],

        Template    = {},

        FS          = CloudFunc.FS;

    module.exports  = function(req, res, next) {
        readFiles(function() {
            route(req, res, next);
        });
    };

    /**
     * additional processing of index file
     */
    function indexProcessing(options) {
        var keysPanel, left, right,
            LEFT    = CloudFunc.PANEL_LEFT,
            RIGHT   = CloudFunc.PANEL_RIGHT,
            data    = options.data,
            panel   = options.panel;

        if (!config('showKeysPanel')) {
            keysPanel  = '<div id="js-keyspanel" class="keyspanel';
            data        = data.replace(keysPanel + '"', keysPanel +' hidden"');
        }

        left    = Util.render(Template.panel, {
            id      : LEFT,
            side    : 'left',
            content : panel
        });

        right    = Util.render(Template.panel, {
            id      : RIGHT,
            side    : 'right',
            content : panel
        });

        data = Util.render(data, {
            title   : CloudFunc.getTitle(),
            fm      : left + right
        });

        return data;
    }

    function readFiles(callback) {
        var filesList,
            paths       = {},

            lengthTmpl  = Object.keys(Template).length,
            lenthPath   = TMPL_PATH.length,
            isRead      = lengthTmpl === lenthPath;

        Util.checkArgs(arguments, ['callback']);

        if (isRead) {
            callback();
        } else {
            filesList   = TMPL_PATH.map(function(name) {
                var path = DIR_FS + name + '.html';

                paths[path] = name;

                return path;
            });

            files.read(filesList, 'utf8', function(error, files) {
                if (error)
                    Util.log(error.message);
                else
                    Object.keys(files).forEach(function(path) {
                        var name = paths[path];

                        Template[name] = files[path];
                    });

                callback();
            });
        }
    }

    /**
     * routing of server queries
     */
    function route(request, response, callback) {
        var name, p, isAuth, isFS, path;

        Util.checkArgs(arguments, ['req', 'res', 'callback']);

        name    = ponse.getPathName(request);
        isAuth  = Util.strCmp(name, ['/auth', '/auth/github']);
        isFS    = Util.strCmp(name, '/') || Util.isContainStrAtBegin(name, FS);

        p       = {
            request     : request,
            response    : response,
            gzip        : true,
            name        : name
        };

        if (!isAuth && !isFS)
            callback();
        else if (isAuth) {
            Util.log('* Routing' + '-> ' + name);

            p.name = DIR_HTML + name + '.html';
            ponse.sendFile(p);
        } else if (isFS) {
            name    = Util.rmStrOnce(name, CloudFunc.FS) || '/';
            path    = mellow.convertPath(name);

            mellow.read(path, function(error, dir) {
                if (dir)
                    dir.path = format.addSlashToEnd(name);

                if (error)
                    if (error.code !== 'ENOTDIR')
                        ponse.sendError(error, p);
                    else
                        fs.realpath(path, function(error, pathReal) {
                            if (!error)
                                p.name = pathReal;
                            else
                                p.name = path;

                            p.gzip = false;
                            ponse.sendFile(p);
                        });
                else
                    buildIndex(dir, function(error, data) {
                        var NOT_LOG = true;

                        p.name = PATH_INDEX;

                        if (error)
                            ponse.sendError(error, p);
                        else
                            ponse.send(data, p, NOT_LOG);
                    });
            });
        }
    }

    function buildIndex(json, callback) {
        var isMinify = config('minify');

        Util.exec.if(!isMinify, function(error, name) {
            fs.readFile(name || PATH_INDEX, 'utf8', function(error, template) {
                var panel, data;

                if (!error) {
                    panel   = CloudFunc.buildFromJSON({
                        data        : json,
                        template    : Template
                    }),

                    data    = indexProcessing({
                        panel   : panel,
                        data    : template,
                    });
                }

                Util.exec(callback, error, data);
            });
        },  function(callback) {
                minify(PATH_INDEX, {
                    log         : true,
                    returnName  : true
                }, callback);
        });
    }
})();
<|endoftext|>


<commit_before>//
// Authentication with MakerPass
//
var passport = require('passport')
var MakerpassStrategy = require('passport-makerpass').Strategy
var Promise    = require('knex/node_modules/bluebird')
var User       = require('./models/user')
var Group      = require('./models/group')
var Membership = require('./models/membership')
var School     = require('./models/school')

exports.mount = function (app, host) {

  if (! process.env.MAKERPASS_CLIENT_ID || ! process.env.MAKERPASS_CLIENT_SECRET) {
    throw new Error("Please set MAKERPASS_CLIENT_ID and MAKERPASS_CLIENT_SECRET")
  }

  passport.use(new MakerpassStrategy({
      clientID: process.env.MAKERPASS_CLIENT_ID,
      clientSecret: process.env.MAKERPASS_CLIENT_SECRET,
      callbackURL: host + '/auth/makerpass/callback'
    },
    function(accessToken, refreshToken, profile, done) {
      importAuthData(profile).then(done.papp(null))
    }
  ))

  app.use(passport.initialize())
  app.use(passport.session())

  passport.serializeUser(function(user, done) {
    done(null, user.uid)
  })

  passport.deserializeUser(function(id, done) {
    User.find(id)
      .then(done.papp(null))
      .catch(function (err) {
        if (err.message === 'not_found') {
          done(null, null)
        }
        else {
          done(err)
        }
      })
  })

  app.get('/auth/makerpass',
    passport.authenticate('makerpass'))

  app.get('/auth/makerpass/callback',
    passport.authenticate('makerpass', { failureRedirect: '/' }),
    function(req, res) {
      // Successful authentication, redirect home.sj
      res.redirect('/me')
    })

  // app.get('/me', function (req, res) {
  //   console.log(req)
  //   res.send({ user: req.user})
  // })

  app.get('/me', function(req, res){
    var users = User.retrieve(function(x){res.send({users: x})
    })
  })

  app.post('/signout', function (req, res) {
    req.session = null
    res.send({})
  })

}

var importAuthData = module.exports.importAuthData = function (mks) {

  // These two can run in parallel
  var userPromise = importUser(mks)
  var schoolPromises = mks.schools.map(School.updateOrCreate)

  return Promise.all(schoolPromises).then(function() {
    return Promise.all( mks.memberships.map( getProp('group') ).map(Group.updateOrCreate) )
  }).then(function() {
    return Membership.sync(mks.uid, mks.memberships)
  })
  .then(function() {
    return userPromise
  })
}

function importUser (mks) {
  return User.updateOrCreate({
    uid: mks.id,
    name: mks.name,
    email: mks.email,
    avatar_url: mks.avatar_url
  })
}
<commit_msg>feat/added query for current user<commit_after>//
// Authentication with MakerPass
//
var passport = require('passport')
var MakerpassStrategy = require('passport-makerpass').Strategy
var Promise    = require('knex/node_modules/bluebird')
var User       = require('./models/user')
var Group      = require('./models/group')
var Membership = require('./models/membership')
var School     = require('./models/school')

exports.mount = function (app, host) {

  if (! process.env.MAKERPASS_CLIENT_ID || ! process.env.MAKERPASS_CLIENT_SECRET) {
    throw new Error("Please set MAKERPASS_CLIENT_ID and MAKERPASS_CLIENT_SECRET")
  }

  passport.use(new MakerpassStrategy({
      clientID: process.env.MAKERPASS_CLIENT_ID,
      clientSecret: process.env.MAKERPASS_CLIENT_SECRET,
      callbackURL: host + '/auth/makerpass/callback'
    },
    function(accessToken, refreshToken, profile, done) {
      importAuthData(profile).then(done.papp(null))
    }
  ))

  app.use(passport.initialize())
  app.use(passport.session())

  passport.serializeUser(function(user, done) {
    done(null, user.uid)
  })

  passport.deserializeUser(function(id, done) {
    User.find(id)
      .then(done.papp(null))
      .catch(function (err) {
        if (err.message === 'not_found') {
          done(null, null)
        }
        else {
          done(err)
        }
      })
  })

  app.get('/auth/makerpass',
    passport.authenticate('makerpass'))

  app.get('/auth/makerpass/callback',
    passport.authenticate('makerpass', { failureRedirect: '/' }),
    function(req, res) {
      // Successful authentication, redirect home.sj
      res.redirect('/me')
    })

  app.get('/me', function (req, res) {
    res.send({ user: req.user})
  })

  app.get('/users', function(req, res){
    var users = User.retrieve(function(x){res.send({users: x})
    })
  })

  app.post('/signout', function (req, res) {
    req.session = null
    res.send({})
  })

}

var importAuthData = module.exports.importAuthData = function (mks) {

  // These two can run in parallel
  var userPromise = importUser(mks)
  var schoolPromises = mks.schools.map(School.updateOrCreate)

  return Promise.all(schoolPromises).then(function() {
    return Promise.all( mks.memberships.map( getProp('group') ).map(Group.updateOrCreate) )
  }).then(function() {
    return Membership.sync(mks.uid, mks.memberships)
  })
  .then(function() {
    return userPromise
  })
}

function importUser (mks) {
  return User.updateOrCreate({
    uid: mks.id,
    name: mks.name,
    email: mks.email,
    avatar_url: mks.avatar_url
  })
}
<|endoftext|>


<commit_before>var ip = require('ip')
var path = require('path')
var util = require('util')
var Asset = require('../web/asset')
var debug = require('debug')('micromono:service:pipe')
var Router = require('../web/router')

exports.getEnvVariables = function() {
  var argv = require('../argv').parse(process.argv)
  return {
    port: argv.port || process.env.PORT || 0,
    host: argv.host || process.env.HOST || ip.address() || '0.0.0.0',
    rpcPort: argv.rpcPort || 0
  }
}

exports.prepareService = function(hasAsset, service) {
  var hasWebFeature = !!(hasAsset || service.route || service.middleware)
  return {
    api: service.api,
    use: service.use,
    init: service.init,
    page: service.page || {},
    route: service.route,
    framework: hasWebFeature && (service.framework || 'express'),
    middleware: service.middleware,
    pageApiBaseUrl: service.pageApiBaseUrl || '/_api',
    middlewareBaseUrl: service.middlewareBaseUrl || '/_middleware'
  }
}

exports.prepareFramework = function(framework, setDep) {
  if ('string' === typeof framework) {
    var FrameworkAdapter = require('../web/framework/' + framework)
    framework = new FrameworkAdapter()
  }

  debug('set framework type "%s"', framework.type)

  // App might be a function, set it directly to avoid autoBind.
  setDep('app', framework.app)
  setDep(framework, ['attachRoutes', 'attachLocalMiddlewares', 'startHttpServer', 'serveLocalAsset'])
}

exports.getPackageJSON = function(packagePath) {
  var packageJSONPath = path.join(packagePath, 'package.json')
  var packageJSON = require(packageJSONPath)

  return {
    packageJSON: packageJSON
  }
}

exports.getServiceInfo = function(packageJSON, service) {
  var serviceName = packageJSON.name
  if (packageJSON.micromono && packageJSON.micromono.name) {
    serviceName = packageJSON.micromono.name
  }

  service.name = serviceName

  return {
    hasAsset: packageJSON.jspm,
    serviceName: serviceName,
    serviceInfo: packageJSON.micromono,
    serviceVersion: packageJSON.version
  }
}

exports.setupAsset = function(hasAsset, packageJSON) {
  return {
    asset: new Asset(packageJSON)
  }
}

exports.setupRoute = function(route, page, pageApiBaseUrl) {
  return {
    routes: Router.normalizeRoutes(route, page, pageApiBaseUrl)
  }
}

exports.setupUse = function(use) {
  return {
    uses: Router.normalizeUses(use)
  }
}

exports.setupMiddleware = function(middleware, middlewareBaseUrl) {
  return {
    middlewares: Router.normalizeMiddlewares(middleware, middlewareBaseUrl)
  }
}

exports.startWebServer = function(port, host, serviceName, startHttpServer, setDep) {
  debug('[%s] startWebServer()', serviceName)

  if (!startHttpServer) {
    // no need to start http server if we don't have asset or route to serve.
    debug('[%s] no need to start web server', serviceName)
    return true
  }

  port = port || 0
  host = host || '0.0.0.0'

  debug('[%s] start web server at %s:%s', serviceName, host, port)

  startHttpServer(port, host).then(function(server) {
    if (server) {
      var address = server.address()

      setDep('httpServer', server)
      setDep('httpPort', address.port)
      setDep('httpHost', address.address)

      debug('[%s] web server started at %s:%s', serviceName, address.address, address.port)
    } else {
      var error = util.format('[%s] Can not start web server', serviceName)
      throw new Error(error)
    }
  })
}
<commit_msg>Add RPC and generate announcement.<commit_after>var ip = require('ip')
var RPC = require('../rpc')
var path = require('path')
var util = require('util')
var Asset = require('../web/asset')
var debug = require('debug')('micromono:service:pipe')
var Router = require('../web/router')
var Announcement = require('../announcement')

exports.getEnvVariables = function() {
  var argv = require('../argv').parse(process.argv)
  return {
    port: argv.port || process.env.PORT || 0,
    host: argv.host || process.env.HOST || ip.address() || '0.0.0.0',
    rpcPort: argv.rpcPort || 0
  }
}

exports.prepareService = function(hasAsset, service) {
  var hasWebFeature = !!(hasAsset || service.route || service.middleware)
  return {
    api: service.api,
    rpcType: service.rpcType || 'axon',
    use: service.use,
    init: service.init,
    page: service.page || {},
    route: service.route,
    framework: hasWebFeature && (service.framework || 'express'),
    middleware: service.middleware,
    upgradeUrl: service.upgradeUrl,
    pageApiBaseUrl: service.pageApiBaseUrl || '/_api',
    middlewareBaseUrl: service.middlewareBaseUrl || '/_middleware'
  }
}

exports.prepareFramework = function(framework, setDep) {
  if ('string' === typeof framework) {
    var FrameworkAdapter = require('../web/framework/' + framework)
    framework = new FrameworkAdapter()
  }

  debug('set framework type "%s"', framework.type)

  // App might be a function, set it directly to avoid autoBind.
  setDep('app', framework.app)
  setDep(framework, ['attachRoutes', 'attachLocalMiddlewares', 'startHttpServer', 'serveLocalAsset'])
}

exports.getPackageJSON = function(packagePath) {
  var packageJSONPath = path.join(packagePath, 'package.json')
  var packageJSON = require(packageJSONPath)

  return {
    packageJSON: packageJSON
  }
}

exports.getServiceInfo = function(packageJSON, service) {
  var serviceName = packageJSON.name
  if (packageJSON.micromono && packageJSON.micromono.name) {
    serviceName = packageJSON.micromono.name
  }

  service.name = serviceName
  service.version = packageJSON.version

  return {
    hasAsset: packageJSON.jspm,
    serviceName: serviceName,
    serviceInfo: packageJSON.micromono,
    serviceVersion: packageJSON.version
  }
}

exports.setupAsset = function(hasAsset, packageJSON) {
  var asset = new Asset(packageJSON)
  var assetInfo = asset.parseJSPM()
  return {
    asset: asset,
    assetInfo: assetInfo
  }
}

exports.setupRoute = function(route, page, pageApiBaseUrl) {
  return {
    routes: Router.normalizeRoutes(route, page, pageApiBaseUrl)
  }
}

exports.setupUse = function(use) {
  return {
    uses: Router.normalizeUses(use)
  }
}

exports.setupMiddleware = function(middleware, middlewareBaseUrl) {
  return {
    middlewares: Router.normalizeMiddlewares(middleware, middlewareBaseUrl)
  }
}

exports.startWebServer = function(port, host, serviceName, startHttpServer, setDep) {
  debug('[%s] startWebServer()', serviceName)

  if (!startHttpServer) {
    // no need to start http server if we don't have asset or route to serve.
    debug('[%s] no need to start web server', serviceName)
    return true
  }

  port = port || 0
  host = host || '0.0.0.0'

  debug('[%s] start web server at %s:%s', serviceName, host, port)

  startHttpServer(port, host).then(function(server) {
    if (server) {
      var address = server.address()

      setDep('httpServer', server)
      setDep('httpPort', address.port)
      setDep('httpHost', address.address)

      debug('[%s] web server started at %s:%s', serviceName, address.address, address.port)
    } else {
      var error = util.format('[%s] Can not start web server', serviceName)
      throw new Error(error)
    }
  })
}

exports.setupRPC = function(api, rpcType) {
  var rpcOptions = {
    api: api,
    type: rpcType,
    isRemote: false
  }
  var rpc = new RPC(rpcOptions)

  return {
    rpc: rpc,
    rpcApi: rpc.getAPIs()
  }
}

exports.startRPCServer = function(rpc, rpcPort, rpcHost, service, setDep, next) {
  debug('[%s] start "%s" rpc server at %s:%s', service.name, rpc.type, rpcHost, rpcPort)
  return rpc.startServer(rpcPort, rpcHost).then(function(server) {
    if (server) {
      var address = server.address()
      setDep('rpcPort', address.port)
      debug('[%s] "%s" rpc server started at %s:%s',
        service.name,
        rpc.type,
        address.address,
        address.port
      )
    }
    next()
  })
}

exports.generateAnnouncement = function(assetInfo, routes, uses, middlewares, service, httpPort, framework, rpcApi, rpcPort, rpcType, host) {
  var ann = new Announcement(service)

  ann.asset = assetInfo
  ann.web = {
    use: uses,
    route: routes,
    middleware: middlewares,
    framework: framework
  }
  ann.httpPort = httpPort
  ann.host = host

  ann.rpc = {
    api: rpcApi,
    port: rpcPort,
    type: rpcType
  }

  var annStr = util.inspect(ann, {
    colors: true,
    depth: 4
  })
  debug('[%s] service started with announcement: \n%s\n', service.name, annStr)
}
<|endoftext|>


<commit_before>var Buffer = require('safe-buffer').Buffer;
var zlib = require('../util/zlib');

var STATUS_CODES = require('http').STATUS_CODES || {};
var wsParser = require('ws-parser');

var CRLF = Buffer.from('\r\n');
var TYPE_RE = /(request|response)-length:/i;
var noop = function() {};
var frameIndex = 100000;
var TYPES = ['whistle', 'Fiddler'];

function dechunkify(body) {
  var result = [];
  var index;
  while((index = indexOfBuffer(body, CRLF)) > 0) {
    var size = parseInt(body.slice(0, index).toString(), 16) || 0;
    if (!size) {
      break;
    }
    index += 2;
    result.push(body.slice(index, index += size));
    body = body.slice(index + 2);
  }
  return result.length ? Buffer.concat(result) : body;
}

function getMethod(method) {
  if (typeof method !== 'string') {
    return 'GET';
  }
  return method.trim().toUpperCase() || 'GET';
}

function getHeadersRaw(headers, rawHeaderNames) {
  var result = [];
  if (headers) {
    rawHeaderNames = rawHeaderNames || {};
    Object.keys(headers).forEach(function(name) {
      var value = headers[name];
      var key = rawHeaderNames[name] || name;
      if (!Array.isArray(value)) {
        result.push(key + ': ' + value);
        return;
      }
      value.forEach(function(val) {
        result.push(key + ': ' + val);
      });
    });
  }
  return result;
}

function decodeRaw(headers, data) {
  var body = getBodyBuffer(data);
  var raw = Buffer.from(headers.join('\r\n') + '\r\n\r\n');
  return body ? Buffer.concat([raw, body]) : raw;
}

function removeEncodingFields(headers) {
  if (headers) {
    delete headers['content-encoding'];
    delete headers['transfer-encoding'];
  }
}

function getBodyBuffer(data) {
  if (data.base64) {
    try {
      return Buffer.from(data.base64 + '', 'base64');
    } catch(e) {}
    return Buffer.from(data.base64 + '');
  }
  if (data.body) {
    return Buffer.from(data.body + '');
  }
}

function getReqRaw(req) {
  removeEncodingFields(req.headers);
  var headers = getHeadersRaw(req.headers, req.rawHeaderNames);
  var url = String(req.url || '').replace(/^ws/, 'http');
  headers.unshift([getMethod(req.method), url, 'HTTP/1.1'].join(' '));
  return decodeRaw(headers, req);
}

exports.getReqRaw = getReqRaw;

function getResRaw(res) {
  removeEncodingFields(res.headers);
  var headers = getHeadersRaw(res.headers, res.rawHeaderNames);
  var statusCode = res.statusCode === 'aborted' ? 502 : res.statusCode;
  var statusMessage = !statusCode ? '' : res.statusMessage || STATUS_CODES[statusCode] || 'unknown';
  headers.unshift(['HTTP/1.1', statusCode, statusMessage].join(' '));
  return decodeRaw(headers, res);
}

exports.getResRaw = getResRaw;

var BODY_SEP = Buffer.from('\r\n\r\n');

function getBodyOffset(raw) {
  var index = indexOfBuffer(raw, BODY_SEP);
  if (index !== -1) {
    return [index, index + 4];
  }
}
function indexOfBuffer(buf, subBuf, start) {
  start = start || 0;
  if (buf.indexOf) {
    return buf.indexOf(subBuf, start);
  }

  var subLen = subBuf.length;
  if (subLen) {
    for (var i = start, len = buf.length - subLen; i <= len; i++) {
      var j = 0;
      for (; j < subLen; j++) {
        if (subBuf[j] !== buf[i + j]) {
          break;
        }
      }
      if (j == subLen) {
        return i;
      }
    }
  }

  return -1;
}

function getBody(body, headers, callback) {
  if (body) {
    var chunked = headers['transfer-encoding'];
    if (typeof chunked === 'string') {
      chunked = chunked.trim().toLowerCase();
    }
    if (chunked === 'chunked') {
      body = dechunkify(body);
    }
  }

  zlib.unzip(headers['content-encoding'], body, function(err, result) {
    if (!err && result) {
      body = result;
    }
    return callback(body && body.toString('base64'));
  });
}

function parseRawData(raw, callback, isRes) {
  var offset = getBodyOffset(raw);
  var body = '';
  if (offset) {
    body = raw.slice(offset[1]);
    raw = raw.slice(0, offset[0]);
  }
  raw = raw.toString();
  raw = raw.trim().split(/\r\n?|\n/g);
  var firstLine = raw.shift().split(/\s+/g);
  var headers = {};
  var rawHeaderNames = {};
  raw.forEach(function(line) {
    var index = line.indexOf(':');
    if (index === -1) {
      return;
    }
    var name = line.substring(0, index).trim();
    if (!name) {
      return;
    }
    var key = name.toLowerCase();
    var value = headers[key];
    var val = line.substring(index + 1).trim();
    if (value != null) {
      if (Array.isArray(value)) {
        value.push(val);
      } else {
        value = [value, val];
      }
    } else {
      value = val;
    }
    rawHeaderNames[key] = name;
    headers[key] = value;
  });

  var type = 'TEXT';
  if (isRes) {
    type = getType(headers['content-type']);
  }
  getBody(type ? body : '', headers, function(base64) {
    callback({
      firstLine: firstLine,
      headers: headers,
      size: base64 ? base64.length : 0,
      rawHeaderNames: rawHeaderNames,
      base64: base64
    });
  }, type);
}

function getReq(raw, callback) {
  raw = parseRawData(raw, function(raw) {
    var method = raw.firstLine[0] || 'GET';
    callback(raw ? {
      method: method,
      httpVersion: '1.1',
      rawHeaderNames: raw.rawHeaderNames,
      url: raw.firstLine[1],
      headers: raw.headers,
      size: /^get$/i.test(method) ? 0 : raw.size,
      base64: raw.base64
    } : null);
  });
}

exports.getReq = getReq;

function getType(type) {
  if (typeof type == 'string') {
    type = type.toLowerCase();
    if (type.indexOf('javascript') != -1) {
      return 'JS';
    }

    if (type.indexOf('css') != -1) {
      return 'CSS';
    }

    if (type.indexOf('html') != -1) {
      return 'HTML';
    }

    if (type.indexOf('json') != -1) {
      return 'JSON';
    }

    if (type.indexOf('xml') != -1) {
      return 'XML';
    }

    if (type.indexOf('text/') != -1) {
      return 'TEXT';
    }

    if (type.indexOf('image/') != -1) {
      return 'IMG';
    }
  } else if (!type) {
    return 'TEXT';
  }

  return null;
}

function getRes(raw, callback) {
  parseRawData(raw, function(raw) {
    callback(raw ? {
      statusCode: raw.firstLine[1],
      httpVersion: '1.1',
      rawHeaderNames: raw.rawHeaderNames,
      statusMessage: raw.firstLine[2],
      headers: raw.headers,
      size: raw.size,
      base64: raw.base64
    } : {});
  }, true);
}

exports.getRes = getRes;

function parseJSON(str) {
  try {
    return JSON.parse(str);
  } catch(e) {}
}

exports.parseJSON = parseJSON;

function padding(num) {
  return num < 10 ? '0' + num : num;
}

function paddingMS(ms) {
  if (ms > 99) {
    return ms;
  }
  if (ms > 9) {
    return '0' + ms;
  }
  return '00' + ms;
}

function formatDate() {
  var date = new Date();
  var result = [];
  result.push(date.getFullYear());
  result.push(padding(date.getMonth() + 1));
  result.push(padding(date.getDate()));
  result.push(padding(date.getHours()));
  result.push(padding(date.getMinutes()));
  result.push(padding(date.getSeconds()));
  result.push(paddingMS(date.getMilliseconds()));
  return result.join('');
}

function getFilename(type, filename) {
  if (!~TYPES.indexOf(type)) {
    type = 'whistle';
  }
  if (typeof filename !== 'string') {
    filename = '';
  }
  if (type === 'whistle') {
    if (filename) {
      if (!/\.(json|txt)$/i.test(filename)) {
        filename += '.txt';
      }
    } else {
      filename = 'whistle_' + formatDate() + '.txt';
    }
  } else {
    if (filename) {
      if (!/\.saz$/i.test(filename)) {
        filename += '.saz';
      }
    } else {
      filename = 'fiddler_' + formatDate() + '.saz';
    }
  }
  return filename;
}

exports.getFilename = getFilename;

var ONE_MINUTE = 60 * 1000;
function toISOString(time) {
  var date = new Date();
  var offet = -date.getTimezoneOffset();
  time += offet * ONE_MINUTE;
  offet /= 60;
  time = time >= 0 ? new Date(time) : new Date();
  return time.toISOString().slice(0, -1) + '0000'
    + (offet >= 0 ? '+' : '-') + padding(Math.abs(offet)) + ':00';
}

exports.toISOString = toISOString;

function removeIPV6Prefix(ip) {
  if (typeof ip != 'string') {
    return '';
  }

  return ip.indexOf('::ffff:') === 0 ? ip.substring(7) : ip;
}

exports.removeIPV6Prefix = removeIPV6Prefix;

function getIndex() {
  if (frameIndex > 10000000) {
    frameIndex = 100000;
  }
  return ++frameIndex;
}

function resolveFrames(res, frames, callback) {
  var len = frames.length;
  var result = [];
  if (len) {
    res.headers = res.headers || {};
    var receiver = wsParser.getReceiver(res);
    var execCallback = function() {
      receiver.onData = noop;
      callback(result);
    };
    var index = 0;
    receiver.onData = function(chunk, opts) {
      var frame = frames[index];
      ++index;
      if (frame) {
        result.push({
          frameId: frame.frameId,
          isClient: frame.type === 'request',
          mask: opts.mask,
          base64: chunk.toString('base64'),
          compressed: opts.compressed,
          length: opts.length,
          opcode: opts.opcode
        });
      }
      if (!frame || len === index) {
        setImmediate(execCallback);
      }
    };
    setTimeout(execCallback, 1600);
    frames.forEach((frame) => {
      receiver.add(frame.bin);
    });
  }
  callback(result);
}

function parseFrames(res, content, callback) {
  var end = content.indexOf(CRLF, 0);
  var start = 2;
  var frames = [];

  while(end !== -1) {
    var line = content.slice(start, end).toString();
    if (TYPE_RE.test(line)) {
      var frame = { type: RegExp.$1.toLowerCase() };
      frame.length = line.substring(line.indexOf(':') + 1).trim();
      start = content.indexOf(CRLF, start + 90);
      if (start === -1) {
        break;
      }
      start += 2;
      end = content.indexOf(CRLF, start);
      if (end === -1) {
        break;
      }
      line = content.slice(start, end).toString();
      var time = new Date(line.substring(line.indexOf(':') + 1).trim() || 0).getTime();
      frame.frameId = time + '-' + getIndex();
      start = end + 4;
      end = content.indexOf(CRLF, start);
      if (end === -1) {
        break;
      }
      frame.bin = content.slice(start, end);
      frames.push(frame);
    }
    start = end + 2;
    end = content.indexOf(CRLF, start);
  }
  resolveFrames(res, frames, callback);
}

exports.parseFrames = parseFrames;
<commit_msg>feat: extract websocket frames from saz file<commit_after>var Buffer = require('safe-buffer').Buffer;
var zlib = require('../util/zlib');

var STATUS_CODES = require('http').STATUS_CODES || {};
var wsParser = require('ws-parser');

var CRLF = Buffer.from('\r\n');
var TYPE_RE = /(request|response)-length:/i;
var frameIndex = 100000;
var TYPES = ['whistle', 'Fiddler'];

function dechunkify(body) {
  var result = [];
  var index;
  while((index = indexOfBuffer(body, CRLF)) > 0) {
    var size = parseInt(body.slice(0, index).toString(), 16) || 0;
    if (!size) {
      break;
    }
    index += 2;
    result.push(body.slice(index, index += size));
    body = body.slice(index + 2);
  }
  return result.length ? Buffer.concat(result) : body;
}

function getMethod(method) {
  if (typeof method !== 'string') {
    return 'GET';
  }
  return method.trim().toUpperCase() || 'GET';
}

function getHeadersRaw(headers, rawHeaderNames) {
  var result = [];
  if (headers) {
    rawHeaderNames = rawHeaderNames || {};
    Object.keys(headers).forEach(function(name) {
      var value = headers[name];
      var key = rawHeaderNames[name] || name;
      if (!Array.isArray(value)) {
        result.push(key + ': ' + value);
        return;
      }
      value.forEach(function(val) {
        result.push(key + ': ' + val);
      });
    });
  }
  return result;
}

function decodeRaw(headers, data) {
  var body = getBodyBuffer(data);
  var raw = Buffer.from(headers.join('\r\n') + '\r\n\r\n');
  return body ? Buffer.concat([raw, body]) : raw;
}

function removeEncodingFields(headers) {
  if (headers) {
    delete headers['content-encoding'];
    delete headers['transfer-encoding'];
  }
}

function getBodyBuffer(data) {
  if (data.base64) {
    try {
      return Buffer.from(data.base64 + '', 'base64');
    } catch(e) {}
    return Buffer.from(data.base64 + '');
  }
  if (data.body) {
    return Buffer.from(data.body + '');
  }
}

function getReqRaw(req) {
  removeEncodingFields(req.headers);
  var headers = getHeadersRaw(req.headers, req.rawHeaderNames);
  var url = String(req.url || '').replace(/^ws/, 'http');
  headers.unshift([getMethod(req.method), url, 'HTTP/1.1'].join(' '));
  return decodeRaw(headers, req);
}

exports.getReqRaw = getReqRaw;

function getResRaw(res) {
  removeEncodingFields(res.headers);
  var headers = getHeadersRaw(res.headers, res.rawHeaderNames);
  var statusCode = res.statusCode === 'aborted' ? 502 : res.statusCode;
  var statusMessage = !statusCode ? '' : res.statusMessage || STATUS_CODES[statusCode] || 'unknown';
  headers.unshift(['HTTP/1.1', statusCode, statusMessage].join(' '));
  return decodeRaw(headers, res);
}

exports.getResRaw = getResRaw;

var BODY_SEP = Buffer.from('\r\n\r\n');

function getBodyOffset(raw) {
  var index = indexOfBuffer(raw, BODY_SEP);
  if (index !== -1) {
    return [index, index + 4];
  }
}
function indexOfBuffer(buf, subBuf, start) {
  start = start || 0;
  if (buf.indexOf) {
    return buf.indexOf(subBuf, start);
  }

  var subLen = subBuf.length;
  if (subLen) {
    for (var i = start, len = buf.length - subLen; i <= len; i++) {
      var j = 0;
      for (; j < subLen; j++) {
        if (subBuf[j] !== buf[i + j]) {
          break;
        }
      }
      if (j == subLen) {
        return i;
      }
    }
  }

  return -1;
}

function getBody(body, headers, callback) {
  if (body) {
    var chunked = headers['transfer-encoding'];
    if (typeof chunked === 'string') {
      chunked = chunked.trim().toLowerCase();
    }
    if (chunked === 'chunked') {
      body = dechunkify(body);
    }
  }

  zlib.unzip(headers['content-encoding'], body, function(err, result) {
    if (!err && result) {
      body = result;
    }
    return callback(body && body.toString('base64'));
  });
}

function parseRawData(raw, callback, isRes) {
  var offset = getBodyOffset(raw);
  var body = '';
  if (offset) {
    body = raw.slice(offset[1]);
    raw = raw.slice(0, offset[0]);
  }
  raw = raw.toString();
  raw = raw.trim().split(/\r\n?|\n/g);
  var firstLine = raw.shift().split(/\s+/g);
  var headers = {};
  var rawHeaderNames = {};
  raw.forEach(function(line) {
    var index = line.indexOf(':');
    if (index === -1) {
      return;
    }
    var name = line.substring(0, index).trim();
    if (!name) {
      return;
    }
    var key = name.toLowerCase();
    var value = headers[key];
    var val = line.substring(index + 1).trim();
    if (value != null) {
      if (Array.isArray(value)) {
        value.push(val);
      } else {
        value = [value, val];
      }
    } else {
      value = val;
    }
    rawHeaderNames[key] = name;
    headers[key] = value;
  });

  var type = 'TEXT';
  if (isRes) {
    type = getType(headers['content-type']);
  }
  getBody(type ? body : '', headers, function(base64) {
    callback({
      firstLine: firstLine,
      headers: headers,
      size: base64 ? base64.length : 0,
      rawHeaderNames: rawHeaderNames,
      base64: base64
    });
  }, type);
}

function getReq(raw, callback) {
  raw = parseRawData(raw, function(raw) {
    var method = raw.firstLine[0] || 'GET';
    callback(raw ? {
      method: method,
      httpVersion: '1.1',
      rawHeaderNames: raw.rawHeaderNames,
      url: raw.firstLine[1],
      headers: raw.headers,
      size: /^get$/i.test(method) ? 0 : raw.size,
      base64: raw.base64
    } : null);
  });
}

exports.getReq = getReq;

function getType(type) {
  if (typeof type == 'string') {
    type = type.toLowerCase();
    if (type.indexOf('javascript') != -1) {
      return 'JS';
    }

    if (type.indexOf('css') != -1) {
      return 'CSS';
    }

    if (type.indexOf('html') != -1) {
      return 'HTML';
    }

    if (type.indexOf('json') != -1) {
      return 'JSON';
    }

    if (type.indexOf('xml') != -1) {
      return 'XML';
    }

    if (type.indexOf('text/') != -1) {
      return 'TEXT';
    }

    if (type.indexOf('image/') != -1) {
      return 'IMG';
    }
  } else if (!type) {
    return 'TEXT';
  }

  return null;
}

function getRes(raw, callback) {
  parseRawData(raw, function(raw) {
    callback(raw ? {
      statusCode: raw.firstLine[1],
      httpVersion: '1.1',
      rawHeaderNames: raw.rawHeaderNames,
      statusMessage: raw.firstLine[2],
      headers: raw.headers,
      size: raw.size,
      base64: raw.base64
    } : {});
  }, true);
}

exports.getRes = getRes;

function parseJSON(str) {
  try {
    return JSON.parse(str);
  } catch(e) {}
}

exports.parseJSON = parseJSON;

function padding(num) {
  return num < 10 ? '0' + num : num;
}

function paddingMS(ms) {
  if (ms > 99) {
    return ms;
  }
  if (ms > 9) {
    return '0' + ms;
  }
  return '00' + ms;
}

function formatDate() {
  var date = new Date();
  var result = [];
  result.push(date.getFullYear());
  result.push(padding(date.getMonth() + 1));
  result.push(padding(date.getDate()));
  result.push(padding(date.getHours()));
  result.push(padding(date.getMinutes()));
  result.push(padding(date.getSeconds()));
  result.push(paddingMS(date.getMilliseconds()));
  return result.join('');
}

function getFilename(type, filename) {
  if (!~TYPES.indexOf(type)) {
    type = 'whistle';
  }
  if (typeof filename !== 'string') {
    filename = '';
  }
  if (type === 'whistle') {
    if (filename) {
      if (!/\.(json|txt)$/i.test(filename)) {
        filename += '.txt';
      }
    } else {
      filename = 'whistle_' + formatDate() + '.txt';
    }
  } else {
    if (filename) {
      if (!/\.saz$/i.test(filename)) {
        filename += '.saz';
      }
    } else {
      filename = 'fiddler_' + formatDate() + '.saz';
    }
  }
  return filename;
}

exports.getFilename = getFilename;

var ONE_MINUTE = 60 * 1000;
function toISOString(time) {
  var date = new Date();
  var offet = -date.getTimezoneOffset();
  time += offet * ONE_MINUTE;
  offet /= 60;
  time = time >= 0 ? new Date(time) : new Date();
  return time.toISOString().slice(0, -1) + '0000'
    + (offet >= 0 ? '+' : '-') + padding(Math.abs(offet)) + ':00';
}

exports.toISOString = toISOString;

function removeIPV6Prefix(ip) {
  if (typeof ip != 'string') {
    return '';
  }

  return ip.indexOf('::ffff:') === 0 ? ip.substring(7) : ip;
}

exports.removeIPV6Prefix = removeIPV6Prefix;

function getIndex() {
  if (frameIndex > 10000000) {
    frameIndex = 100000;
  }
  return ++frameIndex;
}

function resolveFrames(res, frames, callback) {
  var len = frames.length;
  var result = [];
  if (len) {
    res.headers = res.headers || {};
    var receiver = wsParser.getReceiver(res);
    var execCallback = function() {
      if (receiver) {
        receiver = null;
        callback(result);
      }
    };
    var index = 0;
    receiver.onerror = execCallback;
    receiver.onData = execCallback;
    receiver.onclose = execCallback;
    receiver.onData = function(chunk, opts) {
      var frame = frames[index];
      ++index;
      if (frame) {
        result.push({
          frameId: frame.frameId,
          isClient: frame.type === 'request',
          mask: opts.mask,
          base64: chunk.toString('base64'),
          compressed: opts.compressed,
          length: opts.length,
          opcode: opts.opcode
        });
      }
      if (!frame || len === index) {
        setImmediate(execCallback);
      }
    };
    setTimeout(execCallback, 2000);
    frames.forEach((frame) => {
      receiver.add(frame.bin);
    });
  }
  callback(result);
}

function parseFrames(res, content, callback) {
  var end = content.indexOf(CRLF, 0);
  var start = 2;
  var frames = [];

  while(end !== -1) {
    var line = content.slice(start, end).toString();
    if (TYPE_RE.test(line)) {
      var frame = { type: RegExp.$1.toLowerCase() };
      frame.length = line.substring(line.indexOf(':') + 1).trim();
      start = content.indexOf(CRLF, start + 90);
      if (start === -1) {
        break;
      }
      start += 2;
      end = content.indexOf(CRLF, start);
      if (end === -1) {
        break;
      }
      line = content.slice(start, end).toString();
      var time = new Date(line.substring(line.indexOf(':') + 1).trim() || 0).getTime();
      frame.frameId = time + '-' + getIndex();
      start = end + 4;
      end = content.indexOf(CRLF, start);
      if (end === -1) {
        break;
      }
      frame.bin = content.slice(start, end);
      frames.push(frame);
    }
    start = end + 2;
    end = content.indexOf(CRLF, start);
  }
  resolveFrames(res, frames, callback);
}

exports.parseFrames = parseFrames;
<|endoftext|>


<commit_before>const app = require('./app')

app()

<commit_msg>seperate messenger<commit_after>const {app} = require('./app')

app()

<|endoftext|>


<commit_before>/**
 * @license
 * Code City: serialization and deserialization for JavaScript Intepreter.
 *
 * Copyright 2017 Google Inc.
 *
 * 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.
 */

/**
 * @fileoverview Saving and restoring the state of the interpreter.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

var Interpreter;

var Serializer = {};

Serializer.deserialize = function(json, intrp) {
  function decodeValue(value) {
    if (value && typeof value === 'object') {
      var data;
      if ((data = value['#'])) {
       // Object reference: {'#': 42}
       value = objectList[data];
        if (!value) {
          throw ReferenceError('Object reference not found: ' + data);
        }
        return value;
      }
      if ((data = value['Number'])) {
        // Special number: {'Number': 'Infinity'}
        return Number(data);
      }
      if ((data = value['Value'])) {
        // Special value: {'Value': 'undefined'}
        if (value['Value'] === 'undefined') {
          return undefined;
        }
      }
    }
    return value;
  }

  if (!Array.isArray(json)) {
    throw TypeError('Top-level JSON is not a list.');
  }

  // Require native functions to be present.  Can't just create fresh
  // new interpreter instance because client code may want to add
  // custom builtins.
  if (!intrp.global) {
    throw Error('Interpreter must be initialized prior to deserialization.');
  }
  // Find all native functions in existing interpreter.
  // Find all native functions to get id => func mappings.
  var objectList = [];
  Serializer.objectHunt_(intrp, objectList);
  var functionHash = Object.create(null);
  for (var i = 0; i < objectList.length; i++) {
    if (typeof objectList[i] === 'function') {
      functionHash[objectList[i].id] = objectList[i];
    }
  }
  // Get types.
  var types = this.getTypesDeserialize_(intrp);

  // First pass: Create object stubs for every object.  We don't need
  // to (re)create object #0, because that's the interpreter proper.
  objectList = [intrp];
  for (var i = 1; i < json.length; i++) {
    var jsonObj = json[i];
    var obj;
    var type = jsonObj['type'];
    switch (type) {
      case 'Map':
        obj = Object.create(null);
        break;
      case 'Object':
        obj = {};
        break;
      case 'ScopeReference':
        obj = Interpreter.SCOPE_REFERENCE;
        break;
      case 'Function':
        obj = functionHash[jsonObj['id']];
        if (!obj) {
          throw RangeError('Function ID not found: ' + jsonObj['id']);
        }
        break;
      case 'Array':
        // Currently we assume that Arrays are not sparse.
        obj = [];
        break;
      case 'Set':
        obj = new Set();
        break;
      case 'Date':
        obj = new Date(jsonObj['data']);
        if (isNaN(obj)) {
          throw TypeError('Invalid date: ' + jsonObj['data']);
        }
        break;
      case 'RegExp':
        obj = RegExp(jsonObj['source'], jsonObj['flags']);
        break;
      default:
        var constructor = types[type];
        if (!constructor) {
          throw TypeError('Unknown type: ' + jsonObj['type']);
        }
        obj = new constructor;
    }
    objectList[i] = obj;
  }
  // Second pass: Populate properties for every object.
  for (var i = 0; i < json.length; i++) {
    var jsonObj = json[i];
    var obj = objectList[i];
    // Repopulate objects.
    var props = jsonObj['props'];
    if (props) {
      var names = Object.getOwnPropertyNames(props);
      for (var j = 0; j < names.length; j++) {
        var name = names[j];
        obj[name] = decodeValue(props[name]);
      }
    }
    // Repopulate arrays.
    if (Array.isArray(obj)) {
      var data = jsonObj['data'];
      if (data) {
        for (var j = 0; j < data.length; j++) {
          obj.push(decodeValue(data[j]));
        }
      }
    }
    // Repopulate sets.
    if (obj instanceof Set) {
      var data = jsonObj['data'];
      if (data) {
        for (var j = 0; j < data.length; j++) {
          obj.add(decodeValue(data[j]));
        }
      }
    }
  }
};

Serializer.serialize = function(intrp) {
  function encodeValue(value) {
    if (value && (typeof value === 'object' || typeof value === 'function')) {
      var ref = objectList.indexOf(value);
      if (ref === -1) {
        throw RangeError('Object not found in table.');
      }
      return {'#': ref};
    }
    if (value === undefined) {
      return {'Value': 'undefined'};
    }
    if (typeof value === 'number') {
      if (value === Infinity) {
        return {'Number': 'Infinity'};
      } else if (value === -Infinity) {
        return {'Number': '-Infinity'};
      } else if (isNaN(value)) {
        return {'Number': 'NaN'};
      } else if (1 / value === -Infinity) {
        return {'Number': '-0'};
      }
    }
    return value;
  }

  // Properties on Interpreter instances to ignore.
  var skipList = ['Object', 'Function', 'Array', 'Date', 'RegExp', 'Error',
                  'functionMap_', 'functionCounter_'];
  // Find all objects.
  var objectList = [];
  Serializer.objectHunt_(intrp, objectList, skipList);
  // Get types.
  var types = this.getTypesSerialize_(intrp);
  // Serialize every object.
  var json = [];
  for (var i = 0; i < objectList.length; i++) {
    var jsonObj = Object.create(null);
    json.push(jsonObj);
    var obj = objectList[i];
    // TODO: Add a flag on the '#' prop.  On for debugging, off for production.
    if (true) {
      jsonObj['#'] = i;
    }
    var proto = Object.getPrototypeOf(obj);
    switch (proto) {
      case null:
        jsonObj['type'] = 'Map';
        break;
      case Object.prototype:
        if (obj === Interpreter.SCOPE_REFERENCE) {
          jsonObj['type'] = 'ScopeReference';
        } else {
          jsonObj['type'] = 'Object';
        }
        break;
      case Function.prototype:
        jsonObj['type'] = 'Function';
        jsonObj['id'] = obj.id;
        if (obj.id === undefined) {
          throw Error('Native function has no ID: ' + obj);
        }
        continue;  // No need to index properties.
      case Array.prototype:
        // Currently we assume that Arrays are not sparse.
        jsonObj['type'] = 'Array';
        if (obj.length) {
          jsonObj['data'] = obj.map(encodeValue);
        }
        continue;  // No need to index properties.
      case Set.prototype:
        jsonObj['type'] = 'Set';
        if (obj.size) {
          jsonObj['data'] = Array.from(obj.values()).map(encodeValue);
        }
        continue;  // No need to index properties.
      case Date.prototype:
        jsonObj['type'] = 'Date';
        jsonObj['data'] = obj.toJSON();
        continue;  // No need to index properties.
      case RegExp.prototype:
        jsonObj['type'] = 'RegExp';
        jsonObj['source'] = obj.source;
        jsonObj['flags'] = obj.flags;
        continue;  // No need to index properties.
      default:
        var type = types.get(proto);
        if (!type) {
          throw TypeError('Unknown type: ' + obj);
        }
        jsonObj['type'] = type;
    }
    var props = Object.create(null);
    var names = Object.getOwnPropertyNames(obj);
    for (var j = 0; j < names.length; j++) {
      var name = names[j];
      if (obj !== intrp || skipList.indexOf(name) === -1) {
        props[name] = encodeValue(obj[name]);
      }
    }
    if (names.length) {
      jsonObj['props'] = props;
    }
  }
  return json;
};

// Recursively search the stack to find all non-primitives.
Serializer.objectHunt_ = function(node, objectList, skipList) {
  if (node && (typeof node === 'object' || typeof node === 'function')) {
    if (objectList.indexOf(node) !== -1) {
      return;
    }
    objectList.push(node);
    if (typeof node === 'object') {  // Recurse.
      var names = Object.getOwnPropertyNames(node);
      for (var i = 0; i < names.length; i++) {
        var name = names[i];
        if (!skipList || skipList.indexOf(name) === -1) {
          // Don't pass skiplist; it's only for top-level property keys.
          Serializer.objectHunt_(node[names[i]], objectList);
        }
      }
    }
  }
};

/**
 * Make a map of typename to contructor for each type that might be
 * found while serializing an Interpreter instance.
 * @param {!Interpreter} intrp The interpreter instance being serialized
 *     (needed for inner classes).
 * @return {!Object} A key/value map of typesnames to constructors.
 */
Serializer.getTypesDeserialize_ = function (intrp) {
  var types = {
    Interpreter: Interpreter,
    Scope: Interpreter.Scope,
    PseudoObject: intrp.Object,
    PseudoFunction: intrp.Function,
    PseudoArray: intrp.Array,
    PseudoDate: intrp.Date,
    PseudoRegExp: intrp.RegExp,
    PseudoError: intrp.Error,
  };
  // Fake up a constructor for Acorn AST nodes:
  types.Node = function Node() {};
  types.Node.prototype = intrp.stateStack[0].node.constructor.prototype;
  return types;
};

/**
 * Make a map of prototype to typename for each of the types that
 * might be found while deserializing an Interpreter instance.
 * @param {!Interpreter} intrp An interpreter instance being
 *     deserialized into (needed for inner classes).
 * @return {!Map} A key/value map of protoytype objects to typesnames.
 */
Serializer.getTypesSerialize_ = function (intrp) {
  var types = this.getTypesDeserialize_(intrp);
  var map = new Map;
  for (var t in types) {
    if (types.hasOwnProperty(t)) {
      map.set(types[t].prototype, t);
    }
  }
  return map;
};

if (typeof module !== 'undefined') {  // Node.js
  Interpreter = require('./interpreter');
  module.exports = Serializer;
}
<commit_msg>Fix performance degradation in post-roundtrip interpreter<commit_after>/**
 * @license
 * Code City: serialization and deserialization for JavaScript Intepreter.
 *
 * Copyright 2017 Google Inc.
 *
 * 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.
 */

/**
 * @fileoverview Saving and restoring the state of the interpreter.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

var Interpreter;

var Serializer = {};

Serializer.deserialize = function(json, intrp) {
  function decodeValue(value) {
    if (value && typeof value === 'object') {
      var data;
      if ((data = value['#'])) {
       // Object reference: {'#': 42}
       value = objectList[data];
        if (!value) {
          throw ReferenceError('Object reference not found: ' + data);
        }
        return value;
      }
      if ((data = value['Number'])) {
        // Special number: {'Number': 'Infinity'}
        return Number(data);
      }
      if ((data = value['Value'])) {
        // Special value: {'Value': 'undefined'}
        if (value['Value'] === 'undefined') {
          return undefined;
        }
      }
    }
    return value;
  }

  if (!Array.isArray(json)) {
    throw TypeError('Top-level JSON is not a list.');
  }

  // Require native functions to be present.  Can't just create fresh
  // new interpreter instance because client code may want to add
  // custom builtins.
  if (!intrp.global) {
    throw Error('Interpreter must be initialized prior to deserialization.');
  }
  // Find all native functions in existing interpreter.
  // Find all native functions to get id => func mappings.
  var objectList = [];
  Serializer.objectHunt_(intrp, objectList);
  var functionHash = Object.create(null);
  for (var i = 0; i < objectList.length; i++) {
    if (typeof objectList[i] === 'function') {
      functionHash[objectList[i].id] = objectList[i];
    }
  }
  // Get types.
  var types = this.getTypesDeserialize_(intrp);

  // First pass: Create object stubs for every object.  We don't need
  // to (re)create object #0, because that's the interpreter proper.
  objectList = [intrp];
  for (var i = 1; i < json.length; i++) {
    var jsonObj = json[i];
    var obj;
    var type = jsonObj['type'];
    switch (type) {
      case 'Map':
        obj = Object.create(null);
        break;
      case 'Object':
        obj = {};
        break;
      case 'ScopeReference':
        obj = Interpreter.SCOPE_REFERENCE;
        break;
      case 'Function':
        obj = functionHash[jsonObj['id']];
        if (!obj) {
          throw RangeError('Function ID not found: ' + jsonObj['id']);
        }
        break;
      case 'Array':
        // Currently we assume that Arrays are not sparse.
        obj = [];
        break;
      case 'Set':
        obj = new Set();
        break;
      case 'Date':
        obj = new Date(jsonObj['data']);
        if (isNaN(obj)) {
          throw TypeError('Invalid date: ' + jsonObj['data']);
        }
        break;
      case 'RegExp':
        obj = RegExp(jsonObj['source'], jsonObj['flags']);
        break;
      default:
        var constructor = types[type];
        if (!constructor) {
          throw TypeError('Unknown type: ' + jsonObj['type']);
        }
        obj = new constructor;
    }
    objectList[i] = obj;
  }
  // Second pass: Populate properties for every object.
  for (var i = 0; i < json.length; i++) {
    var jsonObj = json[i];
    var obj = objectList[i];
    // Repopulate objects.
    var props = jsonObj['props'];
    if (props) {
      var names = Object.getOwnPropertyNames(props);
      for (var j = 0; j < names.length; j++) {
        var name = names[j];
        obj[name] = decodeValue(props[name]);
      }
    }
    // Repopulate arrays.
    if (Array.isArray(obj)) {
      var data = jsonObj['data'];
      if (data) {
        for (var j = 0; j < data.length; j++) {
          obj.push(decodeValue(data[j]));
        }
      }
    }
    // Repopulate sets.
    if (obj instanceof Set) {
      var data = jsonObj['data'];
      if (data) {
        for (var j = 0; j < data.length; j++) {
          obj.add(decodeValue(data[j]));
        }
      }
    }
  }
};

Serializer.serialize = function(intrp) {
  function encodeValue(value) {
    if (value && (typeof value === 'object' || typeof value === 'function')) {
      var ref = objectList.indexOf(value);
      if (ref === -1) {
        throw RangeError('Object not found in table.');
      }
      return {'#': ref};
    }
    if (value === undefined) {
      return {'Value': 'undefined'};
    }
    if (typeof value === 'number') {
      if (value === Infinity) {
        return {'Number': 'Infinity'};
      } else if (value === -Infinity) {
        return {'Number': '-Infinity'};
      } else if (isNaN(value)) {
        return {'Number': 'NaN'};
      } else if (1 / value === -Infinity) {
        return {'Number': '-0'};
      }
    }
    return value;
  }

  // Properties on Interpreter instances to ignore.
  var skipList = ['Object', 'Function', 'Array', 'Date', 'RegExp', 'Error',
                  'functionMap_', 'functionCounter_'];
  // Find all objects.
  var objectList = [];
  Serializer.objectHunt_(intrp, objectList, skipList);
  // Get types.
  var types = this.getTypesSerialize_(intrp);
  // Serialize every object.
  var json = [];
  for (var i = 0; i < objectList.length; i++) {
    var jsonObj = Object.create(null);
    json.push(jsonObj);
    var obj = objectList[i];
    // TODO: Add a flag on the '#' prop.  On for debugging, off for production.
    if (true) {
      jsonObj['#'] = i;
    }
    var proto = Object.getPrototypeOf(obj);
    switch (proto) {
      case null:
        jsonObj['type'] = 'Map';
        break;
      case Object.prototype:
        if (obj === Interpreter.SCOPE_REFERENCE) {
          jsonObj['type'] = 'ScopeReference';
        } else {
          jsonObj['type'] = 'Object';
        }
        break;
      case Function.prototype:
        jsonObj['type'] = 'Function';
        jsonObj['id'] = obj.id;
        if (obj.id === undefined) {
          throw Error('Native function has no ID: ' + obj);
        }
        continue;  // No need to index properties.
      case Array.prototype:
        // Currently we assume that Arrays are not sparse.
        jsonObj['type'] = 'Array';
        if (obj.length) {
          jsonObj['data'] = obj.map(encodeValue);
        }
        continue;  // No need to index properties.
      case Set.prototype:
        jsonObj['type'] = 'Set';
        if (obj.size) {
          jsonObj['data'] = Array.from(obj.values()).map(encodeValue);
        }
        continue;  // No need to index properties.
      case Date.prototype:
        jsonObj['type'] = 'Date';
        jsonObj['data'] = obj.toJSON();
        continue;  // No need to index properties.
      case RegExp.prototype:
        jsonObj['type'] = 'RegExp';
        jsonObj['source'] = obj.source;
        jsonObj['flags'] = obj.flags;
        continue;  // No need to index properties.
      default:
        var type = types.get(proto);
        if (!type) {
          throw TypeError('Unknown type: ' + obj);
        }
        jsonObj['type'] = type;
    }
    var props = Object.create(null);
    var names = Object.getOwnPropertyNames(obj);
    for (var j = 0; j < names.length; j++) {
      var name = names[j];
      if (obj !== intrp || skipList.indexOf(name) === -1) {
        props[name] = encodeValue(obj[name]);
      }
    }
    if (names.length) {
      jsonObj['props'] = props;
    }
  }
  return json;
};

// Recursively search the stack to find all non-primitives.
Serializer.objectHunt_ = function(node, objectList, skipList) {
  if (node && (typeof node === 'object' || typeof node === 'function')) {
    if (objectList.indexOf(node) !== -1) {
      return;
    }
    objectList.push(node);
    if (typeof node === 'object') {  // Recurse.
      var names = Object.getOwnPropertyNames(node);
      for (var i = 0; i < names.length; i++) {
        var name = names[i];
        if (!skipList || skipList.indexOf(name) === -1) {
          // Don't pass skiplist; it's only for top-level property keys.
          Serializer.objectHunt_(node[names[i]], objectList);
        }
      }
    }
  }
};

/**
 * Make a map of typename to contructor for each type that might be
 * found while serializing an Interpreter instance.
 * @param {!Interpreter} intrp The interpreter instance being serialized
 *     (needed for inner classes).
 * @return {!Object} A key/value map of typesnames to constructors.
 */
Serializer.getTypesDeserialize_ = function (intrp) {
  return {
    'Interpreter': Interpreter,
    'Scope': Interpreter.Scope,
    'PseudoObject': intrp.Object,
    'PseudoFunction': intrp.Function,
    'PseudoArray': intrp.Array,
    'PseudoDate': intrp.Date,
    'PseudoRegExp': intrp.RegExp,
    'PseudoError': intrp.Error,
    'Node': intrp.stateStack[0].node.constructor,
  };
};

/**
 * Make a map of prototype to typename for each of the types that
 * might be found while deserializing an Interpreter instance.
 * @param {!Interpreter} intrp An interpreter instance being
 *     deserialized into (needed for inner classes).
 * @return {!Map} A key/value map of protoytype objects to typesnames.
 */
Serializer.getTypesSerialize_ = function (intrp) {
  var types = this.getTypesDeserialize_(intrp);
  var map = new Map;
  for (var t in types) {
    if (types.hasOwnProperty(t)) {
      map.set(types[t].prototype, t);
    }
  }
  return map;
};

if (typeof module !== 'undefined') {  // Node.js
  Interpreter = require('./interpreter');
  module.exports = Serializer;
}
<|endoftext|>


<commit_before>import express from 'express';
import Dropbox from 'dropbox';

const port = process.env.PORT || 8000;
const slideshowFolder = process.env.SLIDESHOW_FOLDER || '/slideshow/current';
const imageTimeout = process.env.SLIDESHOW_TIMEOUT || 60;

const dbx = new Dropbox({ accessToken: process.env.DROPBOX_API_KEY });

let imageList = [];
let currentImageName;
let currentExpires = Date.now();

async function awaitChanges(cursor) {
  console.log('Waiting for changes', cursor);
  const response = await dbx.filesListFolderLongpoll({ cursor });
  if (response.changes) {
    console.log('change detected', response);
    imageList = [];
  } else {
    awaitChanges(cursor);
  }
}

async function loadImages() {
  console.log('Loading images');
  const response = await dbx.filesListFolder({ path: slideshowFolder });
  awaitChanges(response.cursor);
  const list = [];
  response.entries.forEach((entry) => {
    list.push({ name: entry.name, path: entry.path_lower });
  });
  list.sort((a, b) => {
    const nameA = a.name.toLowerCase();
    const nameB = b.name.toLowerCase();
    if (nameA < nameB) {
      return -1;
    } else if (nameA > nameB) {
      return 1;
    }
    return 0;
  });
  imageList = list;
}

async function getImageList() {
  if (imageList.length === 0) {
    await loadImages();
  }
  return imageList;
}

async function getImage() {
  const images = await getImageList();

  // Try to find the current image in the list
  let imageIx = 0;
  if (currentImageName) {
    imageIx = images.findIndex(el => el.name === currentImageName);
  }

  // Fetch the image - should we have a fallback?
  let image = images[imageIx];

  // Check if image has expired
  console.log(`Refreshing ${image.name} with index ${imageIx} in ${currentExpires - Date.now()}ms`);
  if (currentExpires && currentExpires <= Date.now()) {
    currentExpires = Date.now() + (imageTimeout * 1000);
    imageIx = images.indexOf(image) + 1;
    if (imageIx >= images.length) {
      imageIx = 0;
    }
    image = images[imageIx];
  }

  // Set expiry on new images
  if (!currentExpires) {
    currentExpires = Date.now() + (imageTimeout * 1000);
  }

  //
  if (!image.url) {
    const response = await dbx.filesGetTemporaryLink({ path: image.path });
    image.url = response.link;
  }

  console.log(`Image index is now ${imageIx} and the current image is ${image.name}`);
  currentImageName = image.name;
  return image;
}

const app = express();

function nocache(req, res, next) {
  res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
  res.header('Expires', '-1');
  res.header('Pragma', 'no-cache');
  next();
}

app.use(nocache, express.static('public'));

app.get('/api/image', nocache, async (req, res) => {
  try {
    const image = await getImage();
    res.send({ name: image.name, expires: currentExpires, url: image.url });
  } catch (err) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
});

app.get('/api/images', nocache, async (req, res) => {
  try {
    await getImageList();
    res.send(imageList);
  } catch (err) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
});

app.get('/api/refresh', nocache, async (req, res) => {
  try {
    imageList = [];
    await getImageList();
    res.send(imageList);
  } catch (err) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
});

app.listen(port, () => {
  console.log(`Slideshow server listening on port ${port}!`);
});

<commit_msg>Fix issue where deletion can lead to a null slide<commit_after>import express from 'express';
import Dropbox from 'dropbox';

const port = process.env.PORT || 8000;
const slideshowFolder = process.env.SLIDESHOW_FOLDER || '/slideshow/current';
const imageTimeout = process.env.SLIDESHOW_TIMEOUT || 60;

const dbx = new Dropbox({ accessToken: process.env.DROPBOX_API_KEY });

let imageList = [];
let currentImageName;
let currentExpires = Date.now();

async function awaitChanges(cursor) {
  console.log('Waiting for changes', cursor);
  const response = await dbx.filesListFolderLongpoll({ cursor });
  if (response.changes) {
    console.log('change detected', response);
    imageList = [];
  } else {
    awaitChanges(cursor);
  }
}

async function loadImages() {
  console.log('Loading images');
  const response = await dbx.filesListFolder({ path: slideshowFolder });
  awaitChanges(response.cursor);
  const list = [];
  response.entries.forEach((entry) => {
    list.push({ name: entry.name, path: entry.path_lower });
  });
  list.sort((a, b) => {
    const nameA = a.name.toLowerCase();
    const nameB = b.name.toLowerCase();
    if (nameA < nameB) {
      return -1;
    } else if (nameA > nameB) {
      return 1;
    }
    return 0;
  });
  imageList = list;
}

async function getImageList() {
  if (imageList.length === 0) {
    await loadImages();
  }
  return imageList;
}

async function getImage() {
  const images = await getImageList();

  // Try to find the current image in the list
  let imageIx = 0;
  if (currentImageName) {
    imageIx = images.findIndex(el => el.name === currentImageName);
  }
  if (imageIx < 0) {
    imageIx = 0;
  }

  // Fetch the image - should we have a fallback?
  let image = images[imageIx];

  // Check if image has expired
  console.log(`Refreshing ${image.name} with index ${imageIx} in ${currentExpires - Date.now()}ms`);
  if (currentExpires && currentExpires <= Date.now()) {
    currentExpires = Date.now() + (imageTimeout * 1000);
    imageIx = images.indexOf(image) + 1;
    if (imageIx >= images.length) {
      imageIx = 0;
    }
    image = images[imageIx];
  }

  // Set expiry on new images
  if (!currentExpires) {
    currentExpires = Date.now() + (imageTimeout * 1000);
  }

  //
  if (!image.url) {
    const response = await dbx.filesGetTemporaryLink({ path: image.path });
    image.url = response.link;
  }

  console.log(`Image index is now ${imageIx} and the current image is ${image.name}`);
  currentImageName = image.name;
  return image;
}

const app = express();

function nocache(req, res, next) {
  res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
  res.header('Expires', '-1');
  res.header('Pragma', 'no-cache');
  next();
}

app.use(nocache, express.static('public'));

app.get('/api/image', nocache, async (req, res) => {
  try {
    const image = await getImage();
    res.send({ name: image.name, expires: currentExpires, url: image.url });
  } catch (err) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
});

app.get('/api/images', nocache, async (req, res) => {
  try {
    await getImageList();
    res.send(imageList);
  } catch (err) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
});

app.get('/api/refresh', nocache, async (req, res) => {
  try {
    imageList = [];
    await getImageList();
    res.send(imageList);
  } catch (err) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
});

app.listen(port, () => {
  console.log(`Slideshow server listening on port ${port}!`);
});

<|endoftext|>


<commit_before>enyo.kind({
	name: "Serializer",
	kind: "Component",
	//* public
	serialize: function(inContainer, inOwner) {
		var s = this._serialize(inContainer, inOwner);
		return enyo.json.codify.to(s, null, 4);
	},
	//* public
	getComponents: function(inContainer, inOwner) {
		return this._serialize(inContainer, inOwner);
	},
	//* protected
	_serialize: function(inContainer, inOwner) {
		var s = [];
		var c$ = inContainer.getClientControls();
		for (var i=0, c; c=c$[i]; i++) {
			if (c.owner == inOwner) {
				s.push(this._serializeComponent(c, inOwner));
			}
		}
		return s;
	},
	//* public
	serializeComponent: function(inComponent, inOwner) {
		var s = this._serializeComponent(inComponent, inOwner);
		return enyo.json.codify.to(s, null, 4);
	},
	//* protected
	_serializeComponent: function(inComponent, inOwner) {
		var p = this.serializeProps(inComponent);
		if (inComponent instanceof enyo.Control) {
			var cs = this._serialize(inComponent, inOwner);
			if (cs && cs.length) {
				p.components = cs;
			}
		}
		this.serializeEvents(p, inComponent);
		return p;
	},
	noserialize: {owner: 1, container: 1, parent: 1, id: 1, attributes: 1, selected: 1, active: 1},
	serializeProps: function(inComponent) {
		var o = {
			kind: this.getComponentKindName(inComponent)
		};
		var ps = this.buildPropList(inComponent, "published");
		var proto = inComponent.ctor.prototype;
		for (var j=0, p; p=ps[j]; j++) {
			if (!this.noserialize[p] && proto[p] != inComponent[p]) {
				o[p] = inComponent[p];
			}
		}
		return o;
	},
	getComponentKindName: function(inComponent) {
		var k = inComponent.kindName.split(".");
		if (k[0] == "enyo") {
			k.shift();
		}
		return k.join(".");
	},
	serializeEvents: function(inProps, inComponent) {
		var ps = this.buildPropList(inComponent, "events");
		var proto = inComponent.ctor.prototype;
		for (var j=0, p; p=ps[j]; j++) {
			if (!this.noserialize[p] && proto[p] != inComponent[p]) {
				inProps[p] = inComponent[p];
			}
		}
		// this catches any event handlers added that aren't in the "events" list (e.g. DOM events)
		for (p in inComponent) {
			if (inComponent.hasOwnProperty(p) && p.substring(0,2) == "on") {
				inProps[p] = inComponent[p];
			}
		}
		return inProps;
	},
	buildPropList: function(inControl, inSource) {
		var map = {};
		var context = inControl;
		while (context) {
			for (var i in context[inSource]) {
				map[i] = true;
			}
			context = context.base && context.base.prototype;
		}
		var props = [];
		for (var n in map) {
			props.push(n);
		}
		return props;
	}
});
<commit_msg>ENYO-1480: Ares designer no longer generates the 'isContainer" attribute<commit_after>enyo.kind({
	name: "Serializer",
	kind: "Component",
	//* public
	serialize: function(inContainer, inOwner) {
		var s = this._serialize(inContainer, inOwner);
		return enyo.json.codify.to(s, null, 4);
	},
	//* public
	getComponents: function(inContainer, inOwner) {
		return this._serialize(inContainer, inOwner);
	},
	//* protected
	_serialize: function(inContainer, inOwner) {
		var s = [];
		var c$ = inContainer.getClientControls();
		for (var i=0, c; (c=c$[i]); i++) {
			if (c.owner == inOwner) {
				s.push(this._serializeComponent(c, inOwner));
			}
		}
		return s;
	},
	//* public
	serializeComponent: function(inComponent, inOwner) {
		var s = this._serializeComponent(inComponent, inOwner);
		return enyo.json.codify.to(s, null, 4);
	},
	//* protected
	_serializeComponent: function(inComponent, inOwner) {
		var p = this.serializeProps(inComponent);
		if (inComponent instanceof enyo.Control) {
			var cs = this._serialize(inComponent, inOwner);
			if (cs && cs.length) {
				p.components = cs;
			}
		}
		this.serializeEvents(p, inComponent);
		return p;
	},
	noserialize: {owner: 1, container: 1, parent: 1, id: 1, attributes: 1, selected: 1, active: 1, isContainer: 1},
	serializeProps: function(inComponent) {
		var o = {
			kind: this.getComponentKindName(inComponent)
		};
		var ps = this.buildPropList(inComponent, "published");
		var proto = inComponent.ctor.prototype;
		for (var j=0, p; (p=ps[j]); j++) {
			if (!this.noserialize[p] && proto[p] != inComponent[p]) {
				o[p] = inComponent[p];
			}
		}
		return o;
	},
	getComponentKindName: function(inComponent) {
		var k = inComponent.kindName.split(".");
		if (k[0] == "enyo") {
			k.shift();
		}
		return k.join(".");
	},
	serializeEvents: function(inProps, inComponent) {
		var ps = this.buildPropList(inComponent, "events");
		var proto = inComponent.ctor.prototype;
		for (var j=0, p; (p=ps[j]); j++) {
			if (!this.noserialize[p] && proto[p] != inComponent[p]) {
				inProps[p] = inComponent[p];
			}
		}
		// this catches any event handlers added that aren't in the "events" list (e.g. DOM events)
		for (p in inComponent) {
			if (inComponent.hasOwnProperty(p) && p.substring(0,2) == "on") {
				inProps[p] = inComponent[p];
			}
		}
		return inProps;
	},
	buildPropList: function(inControl, inSource) {
		var map = {};
		var context = inControl;
		while (context) {
			for (var i in context[inSource]) {
				map[i] = true;
			}
			context = context.base && context.base.prototype;
		}
		var props = [];
		for (var n in map) {
			props.push(n);
		}
		return props;
	}
});
<|endoftext|>


<commit_before>/** A spectrograph of Analyst results */

import React, { Component } from 'react'
import chroma from 'chroma-js'

const CANVAS_HEIGHT = 500
const MINUTES = 120

export default class Spectrograph extends Component {
  constructor (props) {
    super(props)
    this.state = { count: 1 }
  }

  render () {
    return

      {/* random key so it is replaced on re render */}
      <canvas ref={this.drawCanvas} width={MINUTES} height={CANVAS_HEIGHT} key={Math.random()} style={{ transformOrigin: 'left', transform: `scaleX(${1200 / MINUTES})` }} />

      <input type='range' min={1} max={this.props.data.length} step={1} value={this.state.count} onChange={(e) => this.setState({ count: parseInt(e.target.value) })} />
      {this.state.count} iterations

  }

  drawCanvas = (canvas) => {
    // canvas is null when unmounting
    if (canvas == null) return

    // munge the data
    // first create a big grid of ints
    let data = this.props.data.slice(0, this.state.count)

    let iterations = data.length

    // make data cumulative
    let cumulative = []

    let maxAccessibility = 0

    for (let i = 0; i < iterations; i++) cumulative.push([data[i][0]])

    // make all values cumulative first
    for (let minute = 1; minute < MINUTES; minute++) {
      for (let iteration = 0; iteration < iterations; iteration++) {
        let val = cumulative[iteration][minute - 1] + data[iteration][minute]
        cumulative[iteration].push(val)
        maxAccessibility = Math.max(maxAccessibility, val)
      }
    }

    // grid is row-major order, with columns indicating a particular minute of the cumulative accessibiltiy graph
    // and rows indicating the number of iterations having the given accessibility value. So row 0 has the highest recorded accessibility of any iteration
    // at 120 minutes, and so on
    let grid = new Uint16Array(MINUTES * CANVAS_HEIGHT)

    let maxPixelValue = 0

    for (let iteration = 0; iteration < iterations; iteration++) {
      for (let minute = 0; minute < MINUTES; minute++) {
        let yPixel = CANVAS_HEIGHT - 1 - Math.floor(cumulative[iteration][minute] / maxAccessibility * (CANVAS_HEIGHT - 1))
        grid[yPixel * MINUTES + minute] += 1

        if (grid[yPixel * MINUTES + minute] === undefined) {
          console.log('undefined!!')
        }

        maxPixelValue = Math.max(maxPixelValue, grid[yPixel * MINUTES + minute])
      }
    }

    const colorScale = chroma
      .scale(['black', 'blue', 'orange', 'white'])
      .mode('lab')
      .domain([0, 0.01, 0.1, 1].map(i => i * maxPixelValue))

    // draw the canvas
    let ctx = canvas.getContext('2d')
    let id = ctx.createImageData(MINUTES, CANVAS_HEIGHT)

    for (let pixel = 0; pixel < grid.length; pixel++) {
      id.data.set(colorScale(grid[pixel]).rgb(), pixel * 4)
      id.data[pixel * 4 + 3] = 255 // opaque
    }

    ctx.putImageData(id, 0, 0)
  }

  log (x, base) {
    return Math.log(x) / Math.log(base)
  }
}
<commit_msg>multiple y-axis scales, don't recreate canvas on every draw.<commit_after>/** A spectrograph of Analyst results */

import React, { Component } from 'react'
import chroma from 'chroma-js'

const STEPS = 200
const MINUTES = 120
const SCALE_X = 13
const SCALE_Y = 4

export default class Spectrograph extends Component {
  constructor (props) {
    super(props)
    this.state = {
      count: 1,
      scale: 'linear'
    }
  }

  assignState = (state) => {
    this.setState(Object.assign({}, this.state, state))
  }

  render () {
    return

      {/* random key so it is replaced on re render */}
      <canvas ref={(canvas) => { this.canvas = canvas }} width={MINUTES * SCALE_X} height={STEPS * SCALE_Y} />

        <input type='range' min={1} max={this.props.data.length} step={1} value={this.state.count} onChange={(e) => this.assignState({ count: parseInt(e.target.value) })} />
        {this.state.count} iterations

      Y scale:

        <input type='radio' name='scale' checked={this.state.scale === 'linear'} value='linear' onChange={(e) => { if (e.target.checked) this.assignState({ scale: e.target.value }) }} />
        Linear

        <input type='radio' name='scale' checked={this.state.scale === 'log'} value='log' onChange={(e) => { if (e.target.checked) this.assignState({ scale: e.target.value }) }} />
        Logarithmic

        <input type='radio' name='scale' checked={this.state.scale === 'sqrt'} value='sqrt' onChange={(e) => { if (e.target.checked) this.assignState({ scale: e.target.value }) }} />
        Square root

  }

  componentDidMount () {
    this.drawCanvas()
  }

  componentDidUpdate () {
    this.drawCanvas()
  }

  drawCanvas = () => {
    let { data } = this.props

    let iterations = data.length

    // make data cumulative
    let cumulative = []

    for (let i = 0; i < iterations; i++) cumulative.push([data[i][0]])

    // make all values cumulative first
    for (let minute = 1; minute < MINUTES; minute++) {
      for (let iteration = 0; iteration < iterations; iteration++) {
        let val = cumulative[iteration][minute - 1] + data[iteration][minute]
        cumulative[iteration].push(val)
      }
    }

    // take logs
    if (this.state.scale === 'log') cumulative = cumulative.map((arr) => arr.map((i) => Math.log(i + 1)))
    else if (this.state.scale === 'sqrt') cumulative = cumulative.map((arr) => arr.map((i) => Math.sqrt(i)))

    // find max accessibility. NB do this before slicing so horiz. axis does not change
    let maxAccessibility = Math.max(...cumulative.map((arr) => Math.max(...arr)))

    cumulative = cumulative.slice(0, this.state.count)
    iterations = cumulative.length

    // grid is row-major order, with columns indicating a particular minute of the cumulative accessibiltiy graph
    // and rows indicating the number of iterations having the given accessibility value. So row 0 has the highest recorded accessibility of any iteration
    // at 120 minutes, and so on
    let grid = new Uint16Array(MINUTES * STEPS)

    let maxPixelValue = 0

    for (let iteration = 0; iteration < iterations; iteration++) {
      for (let minute = 0; minute < MINUTES; minute++) {
        let yPixel = STEPS - 1 - Math.floor(cumulative[iteration][minute] / maxAccessibility * (STEPS - 1))
        grid[yPixel * MINUTES + minute] += 1

        if (grid[yPixel * MINUTES + minute] === undefined) {
          console.log('undefined!!')
        }

        maxPixelValue = Math.max(maxPixelValue, grid[yPixel * MINUTES + minute])
      }
    }

    const colorScale = chroma
      .scale(['black', 'blue', 'orange', 'white'])
      .mode('lab')
      .domain([0, 0.01, 0.1, 1].map((i) => i * maxPixelValue))
      .out('rgb')

    // draw the canvas
    let ctx = this.canvas.getContext('2d')
    let id = ctx.createImageData(MINUTES * SCALE_X, STEPS * SCALE_Y)

    for (let gridx = 0; gridx < MINUTES; gridx++) {
      for (let gridy = 0; gridy < STEPS; gridy++) {
        let cell = gridy * MINUTES + gridx
        let col = colorScale(grid[cell])

        for (let xoff = 0; xoff < SCALE_X; xoff++) {
          for (let yoff = 0; yoff < SCALE_Y; yoff++) {
            let pixel = (gridy * SCALE_Y + yoff) * MINUTES * SCALE_X + gridx * SCALE_X + xoff
            id.data.set(col, pixel * 4)
            id.data[pixel * 4 + 3] = 255 // opaque
          }
        }
      }
    }

    ctx.putImageData(id, 0, 0)
  }

  log (x, base) {
    return Math.log(x) / Math.log(base)
  }
}
<|endoftext|>


<commit_before>var queries = require('./queries.js');

module.exports.evalAlg = function(userInput, dataType) {
	/**
	powX represents tests for data size Math.pow(10, X)
	skip pow1 because results not accurate for input size < 100
	*/

	var data = queries.getSets(dataType);
	// TODO: add queries file, get data inputs from database, save in respective variables

	var pow2 = runTimeAverage(userInput, data[0], 8);
	var pow3 = runTimeAverage(userInput, data[1], 6);
	var pow4 = runTimeAverage(userInput, data[2], 3);
	var pow5 = getRunTime(userInput, data[3]);
	var pow6 = getRunTime(userInput, data[4]);
	// var pow7 = getRunTime(userInput, data[5]);

	return [pow2, pow3, pow4, pow5, pow6];
}

module.exports.getCoords = function(data) {
	var coords = [];
	for (var i = 0; i < data.length; i++) {
		coords.push([data[i][1], data[i][0]]);
	}

	// returns array of [runTime, N] for each input size
	return coords;
}

// ~~~~ not exported ~~~~

function runTimeAverage(userInput, dbInput, iterations) {
	var total = 0;
	var i = 0;
	var averageRun;
	var result;
	while (i < iterations) {
		var stats = getRunTime(userInput, dbInput);
		total += stats[0];
		i++;
	}
	averageRun = total / iterations;

	// return [avgRunTime, N, result, iterations] for N <= 10,000
	return [Number(averageRun.toFixed(3)), stats[1], stats[2], iterations];
}

function getRunTime(userInput, dbInput) {
	var userAlg = buildFunc(userInput);
	var time = process.hrtime();
	var result = userAlg(dbInput);
	var diff = process.hrtime(time);
	var runTime = (diff[0] * 1e9 + diff[1]) / 1e6;

	// returns [runtime in milliseconds, input size N, result]
	if (dbInput.length <= 100) {
		return [Number(runTime.toFixed(3)), dbInput.length, result];
	} else {
		return [Number(runTime.toFixed(3)), dbInput.length];
}

function buildFunc(userInput) {
	var param = userInput.slice(userInput.indexOf('(') + 1, userInput.indexOf(')'));
	var algString = userInput.slice(userInput.indexOf('{') + 1, userInput.lastIndexOf('}'));
	var userAlg = new Function(param, algString);

	return userAlg;
}

function getFuncName(string) {
	var dStop = string.indexOf('=');
	var eStop = string.indexOf('(');
	var funcName;
	if (string.substr(0,3) === 'var') {
	  if (string[--dStop] === ' ') {
      funcName = string.slice(4, dStop);
    } else {
      funcName = string.slice(4, ++dStop);
    }
	} else if (string.substr(0, 8) === 'function') {
  	if (string[--eStop] === ' ') {
      funcName = string.slice(9, eStop);
    } else {
      funcName = string.slice(9, ++eStop);
    }
  } else {
      alert ('Please use a function expression or declaration\ne.g. `var myFunc = ...` or `function myFunc()...`');
    }
	return funcName;
}

<commit_msg>[style] improve comments and formatting<commit_after>var queries = require('./queries.js');

module.exports.evalAlg = function(userInput, dataType) {
	// TODO: add queries file, get data inputs from database, save in respective variables
	var data = queries.getSets(dataType);

	/**
	powX represents tests for data size Math.pow(10, X) e.g. 10^3 for 1,000
	skip pow1 because results not accurate for input size < 100
	*/
	var pow2 = runTimeAverage(userInput, data[0], 8);
	var pow3 = runTimeAverage(userInput, data[1], 6);
	var pow4 = runTimeAverage(userInput, data[2], 3);
	var pow5 = getRunTime(userInput, data[3]);
	var pow6 = getRunTime(userInput, data[4]);
	// var pow7 = getRunTime(userInput, data[5]);

	return [pow2, pow3, pow4, pow5, pow6];
}

module.exports.getCoords = function(data) {
	var coords = [];
	for (var i = 0; i < data.length; i++) {
		coords.push([data[i][1], data[i][0]]);
	}

	// returns array of [runTime, N] for each input size
	return coords;
}

function runTimeAverage(userInput, dbInput, iterations) {
	var total = 0;
	var i = 0;
	var averageRun;
	var result;
	while (i < iterations) {
		var stats = getRunTime(userInput, dbInput);
		total += stats[0];
		i++;
	}
	averageRun = total / iterations;

	// returns [avgRunTime, N, result, iterations]
	return [Number(averageRun.toFixed(3)), stats[1], stats[2], iterations];
}

function getRunTime(userInput, dbInput) {
	var userAlg = buildFunc(userInput);
	var time = process.hrtime();
	var result = userAlg(dbInput);
	var diff = process.hrtime(time);
	var runTime = (diff[0] * 1e9 + diff[1]) / 1e6;

	// returns [runtime in milliseconds, input size N, result]
	if (dbInput.length <= 100) {
		return [Number(runTime.toFixed(3)), dbInput.length, result];
	} else {
		return [Number(runTime.toFixed(3)), dbInput.length];
	}
}

function buildFunc(userInput) {
	var param = userInput.slice(userInput.indexOf('(') + 1, userInput.indexOf(')'));
	var algString = userInput.slice(userInput.indexOf('{') + 1, userInput.lastIndexOf('}'));
	var userAlg = new Function(param, algString);

	return userAlg;
}

// TODO: transfer this to be method on codemirror class
function getFuncName(string) {
	var dStop = string.indexOf('=');
	var eStop = string.indexOf('(');
	var funcName;
	if (string.substr(0,3) === 'var') {
	  if (string[--dStop] === ' ') {
      funcName = string.slice(4, dStop);
    } else {
      funcName = string.slice(4, ++dStop);
    }
	} else if (string.substr(0, 8) === 'function') {
  	if (string[--eStop] === ' ') {
      funcName = string.slice(9, eStop);
    } else {
      funcName = string.slice(9, ++eStop);
    }
  } else {
      alert ('Please use a function expression or declaration\ne.g. `var myFunc = ...` or `function myFunc()...`');
  }

	return funcName;
}

<|endoftext|>


<commit_before>'use strict'

// Where applicable, HTTP status codes are reused. Custom RTSP status codes
// have been marked as such below
//
// Check RFC 2326 section 11 for details:
// https://tools.ietf.org/html/rfc2326#page-41

module.exports = { // TODO: Are the full list of HTTP status codes valid for RTSP?
  '100': 'Continue',
  '101': 'Switching Protocols',
  '102': 'Processing',
  '200': 'OK',
  '201': 'Created',
  '202': 'Accepted',
  '203': 'Non-Authoritative Information',
  '204': 'No Content',
  '205': 'Reset Content',
  '206': 'Partial Content',
  '207': 'Multi-Status',
  '250': 'Low on Storage Space', // RTSP
  '300': 'Multiple Choices',
  '301': 'Moved Permanently',
  '302': 'Moved Temporarily',
  '303': 'See Other',
  '304': 'Not Modified',
  '305': 'Use Proxy',
  '307': 'Temporary Redirect',
  '308': 'Permanent Redirect',
  '400': 'Bad Request',
  '401': 'Unauthorized',
  '402': 'Payment Required',
  '403': 'Forbidden',
  '404': 'Not Found',
  '405': 'Method Not Allowed',
  '406': 'Not Acceptable',
  '407': 'Proxy Authentication Required',
  '408': 'Request Time-out',
  '409': 'Conflict',
  '410': 'Gone',
  '411': 'Length Required',
  '412': 'Precondition Failed',
  '413': 'Request Entity Too Large',
  '414': 'Request-URI Too Large',
  '415': 'Unsupported Media Type',
  '416': 'Requested Range Not Satisfiable',
  '417': 'Expectation Failed',
  '418': 'I\'m a teapot',
  '422': 'Unprocessable Entity',
  '423': 'Locked',
  '424': 'Failed Dependency',
  '425': 'Unordered Collection',
  '426': 'Upgrade Required',
  '428': 'Precondition Required',
  '429': 'Too Many Requests',
  '431': 'Request Header Fields Too Large',
  '451': 'Parameter Not Understood', // RTSP
  '452': 'Conference Not Found', // RTSP
  '453': 'Not Enough Bandwidth', // RTSP
  '454': 'Session Not Found', // RTSP
  '455': 'Method Not Valid in This State', // RTSP
  '456': 'Header Field Not Valid for Resource', // RTSP
  '457': 'Invalid Range', // RTSP
  '458': 'Parameter Is Read-Only', // RTSP
  '459': 'Aggregate Operation Not Allowed', // RTSP
  '460': 'Only Aggregate Operation Allowed', // RTSP
  '461': 'Unsupported Transport', // RTSP
  '462': 'Destination Unreachable', // RTSP
  '500': 'Internal Server Error',
  '501': 'Not Implemented',
  '502': 'Bad Gateway',
  '503': 'Service Unavailable',
  '504': 'Gateway Time-out',
  '505': 'HTTP Version Not Supported',
  '506': 'Variant Also Negotiates',
  '507': 'Insufficient Storage',
  '509': 'Bandwidth Limit Exceeded',
  '510': 'Not Extended',
  '511': 'Network Authentication Required',
  '551': 'Option not supported' // RTSP
}
<commit_msg>Update list of status codes to only contain valid RTSP codes<commit_after>'use strict'

// Where applicable, HTTP status codes are reused. Custom RTSP status codes
// have been marked as such below
//
// Check RFC 2326 section 11 for details:
// https://tools.ietf.org/html/rfc2326#page-41

module.exports = {
  '100': 'Continue',

  '200': 'OK',
  '201': 'Created',
  '250': 'Low on Storage Space', // RTSP

  '300': 'Multiple Choices',
  '301': 'Moved Permanently',
  '302': 'Moved Temporarily',
  '303': 'See Other',
  '304': 'Not Modified',
  '305': 'Use Proxy',

  '400': 'Bad Request',
  '401': 'Unauthorized',
  '402': 'Payment Required',
  '403': 'Forbidden',
  '404': 'Not Found',
  '405': 'Method Not Allowed',
  '406': 'Not Acceptable',
  '407': 'Proxy Authentication Required',
  '408': 'Request Time-out',
  '410': 'Gone',
  '411': 'Length Required',
  '412': 'Precondition Failed',
  '413': 'Request Entity Too Large',
  '414': 'Request-URI Too Large',
  '415': 'Unsupported Media Type',
  '451': 'Parameter Not Understood', // RTSP
  '452': 'Conference Not Found', // RTSP
  '453': 'Not Enough Bandwidth', // RTSP
  '454': 'Session Not Found', // RTSP
  '455': 'Method Not Valid in This State', // RTSP
  '456': 'Header Field Not Valid for Resource', // RTSP
  '457': 'Invalid Range', // RTSP
  '458': 'Parameter Is Read-Only', // RTSP
  '459': 'Aggregate Operation Not Allowed', // RTSP
  '460': 'Only Aggregate Operation Allowed', // RTSP
  '461': 'Unsupported Transport', // RTSP
  '462': 'Destination Unreachable', // RTSP

  '500': 'Internal Server Error',
  '501': 'Not Implemented',
  '502': 'Bad Gateway',
  '503': 'Service Unavailable',
  '504': 'Gateway Time-out',
  '505': 'HTTP Version Not Supported',
  '551': 'Option not supported' // RTSP
}
<|endoftext|>