<commit_before>/*
* IX Server code
*
* Copyright (C) Province of British Columbia, 2013
*/

var express = require('express')
  , url = require('url')
  , util = require('util')
  , vault = require('./vault')
  , config = require('../config')
  , request = require('../lib/request')
  , token = require('../lib/token')
  , db = require('../lib/db')
  , api = require('../lib/api')
  , jwt = require('../lib/jwt')
  , mw = require('../lib/middleware')

function diCreate ( req, res, next ) {
    var AS = req.request['request.a2p3.org'].AS
    var rsHosts = req.request['request.a2p3.org'].RS
    var redirects = req.request['request.a2p3.org'].redirects
    db.newUser( AS, rsHosts, redirects, function ( e, dis ) {
      if (e) { e.code = "INTERNAL_ERROR"; return next(e) }
      res.send( {'result': {'dis': dis}} )
    })
}

// parses out hosts from passed in scopes
function getHosts ( scopes ) {
  var results = {}
  scopes.forEach( function ( scope ) {
    var o = url.parse( scope )
    results[o.hostname] = results[o.hostname] || []
    results[o.hostname].push( scope )
  })
  return results
}

// exchange IX Token for RS Tokens if all is good
function exchange ( req, res, next ) {

  var jwe, jws, ixToken, e

  try {
    jwe = new jwt.Parse( req.request['request.a2p3.org'].token )
    if ( !jwe.header.kid || !vault.keys.as[jwe.header.kid] ) {
      e = new Error( "No AS key for 'kid' "+jwe.header.kid)
      e.code = "INVALID_TOKEN"
      return next( e )
    }
    ixToken = jwe.decrypt( vault.keys.as[jwe.header.kid] ) // list of keys for AS
  }
  catch (e) {
    e.code = 'INVALID_TOKEN'
    return next( e )
  }
  try {
    jws = new jwt.Parse( req.request['request.a2p3.org'].request )  // agent Request
    if ( !jwt ) {
      e = new Error( "Invalid Agent Request")
      e.code = "INVALID_REQUEST"
      return next( e )
    }
  }
  catch (e) {
    e.code = 'INVALID_REQUEST'
    return next( e )
  }

  // make sure IX Token 'iss' matches associated 'kid'
  if (!vault.keys[ixToken.iss][jwe.header.kid]) {
      e = new Error("'iss' does not have supplied 'kid'")
      e.code = 'INVALID_TOKEN'
      return next( e )
  }
  // check agent request signature matches 'sar' that AS got
  if (ixToken['token.a2p3.org'].sar != jws.signature) {
      e = new Error("IX Token 'sar' does not match request signature")
      e.code = 'INVALID_IXREQUEST'
      return next( e )
  }
  // check ix request and agent request are from same app
  if (req.request.iss != jws.payload.iss) {
      e = new Error("Agent Request 'iss' does not match IX Request 'iss'")
      e.code = 'INVALID_REQUEST'
      return next( e )
  }
  // check IX & Agent Requests and IX Token have not expired
  if ( jwt.expired( req.request.iat ) ) {
      e = new Error("IX Request has expired")
      e.code = 'EXPIRED_IXREQUEST'
      return next( e )
  }
  if ( jwt.expired( jws.payload.iat ) ) {
      e = new Error("Agent Request has expired")
      e.code = 'EXPIRED_REQUEST'
      return next( e )
  }
  if ( jwt.expired( jwe.payload.iat ) ) {
      e = new Error("IX Token has expired")
      e.code = 'EXPIRED_TOKEN'
      return next( e )
  }

// console.log('\njwe\n', util.inspect( jwe, null, null ) )
// console.log('\njws\n', util.inspect( jws, null, null ) )

  var rsScopes = getHosts( jws.payload['request.a2p3.org'].resources )
  db.getStandardResourceHosts( ixToken.sub, ixToken.iss, Object.keys( rsScopes ), function ( e, redirects ) {
    var hostList = {}
    hostList[jws.payload.iss] = true
    Object.keys(rsScopes).forEach( function (rs) {
      if (redirects && redirects[rs]) {
        redirects[rs].forEach( function (host) {
          hostList[host] = true
          rsScopes[host] = rsScopes[rs] // redirected host has scope of standardized resource
        })
      } else {
        hostList[rs] = true
      }
    })

// console.log('\nhostList\n',hostList)

    // app keys for IX are stored with registrar
    db.getAppKeys( 'registrar', Object.keys(hostList), vault.keys, function ( e, keys ) {
      if (e) return next( e )
        var err
      if ( !keys[jws.payload.iss] || !keys[jws.payload.iss][jws.header.kid] ) {
        err = new Error( "Invalid Agent Request key or kid")
        err.code = "INVALID_REQUEST"
        return next( err )
      }
      if ( !jws.verify( keys[jws.payload.iss][jws.header.kid] ) ) {
        err = new Error( "Invalid Agent Request")
        err.code = "INVALID_REQUEST"
        return next( err )
      }
      db.getRsDIfromAsDI( ixToken.sub, ixToken.iss, Object.keys(hostList), function ( e, dis ) {
        if (e) return next( e )
        // make tokens for all resources, delete caller from list
        var tokens = {}
        delete hostList[jws.payload.iss]
        Object.keys( hostList ).forEach( function (rs) {
          var payload =
            { 'iss': config.host.ix
            , 'aud': rs
            , 'sub': dis[rs]
            , 'token.a2p3.org':
              { 'auth': jwe.payload['token.a2p3.org'].auth
              , 'app': jws.payload.iss
              , 'scopes': rsScopes[rs]
              }
            }
          tokens[rs] = token.create( payload, keys[rs].latest )
        })
        return res.send( { result: {'sub': dis[jws.payload.iss], 'tokens': tokens, 'redirects': redirects} } )
      })
    })
  })
}

// APIs called from AS agent registration web app
function agentList ( req, res, next ) {
    db.listAgents(  req.request['request.a2p3.org'].di
                  , req.request.iss
                  , function( e, handles ) {
                      if (e) return next (e)
                      return res.send({ result: { 'handles': handles } } )
                    } )
}

function agentAdd ( req, res, next ) {
    db.addAgent( req.request['request.a2p3.org'].di
                  , req.request.iss
                  , req.request['request.a2p3.org'].name
                  , function( e, token, handle ) {
                      if (e) return next (e)
                      return res.send({ result: { token: token, handle: handle } } )
                    } )
}

function agentDelete ( req, res, next ) {
  var di = req.request['request.a2p3.org'].di
    , as = req.request.iss
    , handle = req.request['request.a2p3.org'].handle
    db.deleteAgent( di, as, handle, function( e, AS ) {
      var details =
        { host: config.reverseHost[AS]  // hack because of how api.call works currently TBD :(
        , api: '/agent/delete'
        , credentials: vault.keys[AS].latest
        , payload:
          { iss: config.host.ix
          , aud: AS
          , 'request.a2p3.org': { 'handle': handle }
          }
        }
      api.call( details, function ( e ) {
        if (e) return next (e)
        return res.send( { result: { success: true } } )
    })
  })
}

exports.app = function() {
	var app = express()
  app.use(express.limit('10kb'))  // protect against large POST attack
  app.use(express.bodyParser())

  app.post('/di/create'
          , request.check( vault.keys, config.roles.enroll )
          , mw.a2p3Params( ['AS', 'RS', 'redirects'] )
          , diCreate
          )
  app.post('/exchange'
          , request.check( vault.keys, null, 'registrar' )  // registrar holds all IX App keys
          , mw.a2p3Params( ['token', 'request'] )
          , exchange
          )
  app.post('/agent/list'
          , request.check( vault.keys, config.roles.as )
          , agentList
          )
  app.post('/agent/add'
          , request.check( vault.keys, config.roles.as )
          , agentAdd
          )
  app.post('/agent/delete'
          , request.check( vault.keys, config.roles.as )
          , agentDelete
          )

  // show README.md as documentation
  app.get('/documentation', mw.md( __dirname+'/README.md' ) )

  // key integrity checking API
  app.post( '/key/check', mw.keyCheck( vault, config.host.ix ) )

  app.use( mw.errorHandler )

	return app
}
<commit_msg>added improved error messaging<commit_after>/*
* IX Server code
*
* Copyright (C) Province of British Columbia, 2013
*/

var express = require('express')
  , url = require('url')
  , util = require('util')
  , vault = require('./vault')
  , config = require('../config')
  , request = require('../lib/request')
  , token = require('../lib/token')
  , db = require('../lib/db')
  , api = require('../lib/api')
  , jwt = require('../lib/jwt')
  , mw = require('../lib/middleware')

function diCreate ( req, res, next ) {
    var AS = req.request['request.a2p3.org'].AS
    var rsHosts = req.request['request.a2p3.org'].RS
    var redirects = req.request['request.a2p3.org'].redirects
    db.newUser( AS, rsHosts, redirects, function ( e, dis ) {
      if (e) { e.code = "INTERNAL_ERROR"; return next(e) }
      res.send( {'result': {'dis': dis}} )
    })
}

// parses out hosts from passed in scopes
function getHosts ( scopes ) {
  var results = {}
  scopes.forEach( function ( scope ) {
    var o = url.parse( scope )
    results[o.hostname] = results[o.hostname] || []
    results[o.hostname].push( scope )
  })
  return results
}

// exchange IX Token for RS Tokens if all is good
function exchange ( req, res, next ) {
  var jwe, jws, ixToken, e
  try {
    jwe = new jwt.Parse( req.request['request.a2p3.org'].token )
    if (jwe.header.typ === 'JWS') {
      e = new Error( 'Received a JWS when expecting a JWE')
      e.code = "INVALID_TOKEN"
      return next( e )
    }
    if (jwe.header.typ !== 'JWE') {
      e = new Error( 'Uknown token type.')
      e.code = "INVALID_TOKEN"
      return next( e )
    }
    if ( !jwe.header.kid || !vault.keys.as[jwe.header.kid] ) {
      e = new Error( "No AS key for 'kid' "+jwe.header.kid)
      e.code = "INVALID_TOKEN"
      return next( e )
    }
    ixToken = jwe.decrypt( vault.keys.as[jwe.header.kid] ) // list of keys for AS
  }
  catch (e) {
    e.code = 'INVALID_TOKEN'
    return next( e )
  }
  try {
    jws = new jwt.Parse( req.request['request.a2p3.org'].request )  // agent Request
    if ( !jwt ) {
      e = new Error( "Invalid Agent Request")
      e.code = "INVALID_REQUEST"
      return next( e )
    }
  }
  catch (e) {
    e.code = 'INVALID_REQUEST'
    return next( e )
  }

  // make sure IX Token 'iss' matches associated 'kid'
  if (!vault.keys[ixToken.iss][jwe.header.kid]) {
      e = new Error("'iss' does not have supplied 'kid'")
      e.code = 'INVALID_TOKEN'
      return next( e )
  }
  // check agent request signature matches 'sar' that AS got
  if (ixToken['token.a2p3.org'].sar != jws.signature) {
      e = new Error("IX Token 'sar' does not match request signature")
      e.code = 'INVALID_IXREQUEST'
      return next( e )
  }
  // check ix request and agent request are from same app
  if (req.request.iss != jws.payload.iss) {
      e = new Error("Agent Request 'iss' does not match IX Request 'iss'")
      e.code = 'INVALID_REQUEST'
      return next( e )
  }
  // check IX & Agent Requests and IX Token have not expired
  if ( jwt.expired( req.request.iat ) ) {
      e = new Error("IX Request has expired")
      e.code = 'EXPIRED_IXREQUEST'
      return next( e )
  }
  if ( jwt.expired( jws.payload.iat ) ) {
      e = new Error("Agent Request has expired")
      e.code = 'EXPIRED_REQUEST'
      return next( e )
  }
  if ( jwt.expired( jwe.payload.iat ) ) {
      e = new Error("IX Token has expired")
      e.code = 'EXPIRED_TOKEN'
      return next( e )
  }

// console.log('\njwe\n', util.inspect( jwe, null, null ) )
// console.log('\njws\n', util.inspect( jws, null, null ) )

  var rsScopes = getHosts( jws.payload['request.a2p3.org'].resources )
  db.getStandardResourceHosts( ixToken.sub, ixToken.iss, Object.keys( rsScopes ), function ( e, redirects ) {
    var hostList = {}
    hostList[jws.payload.iss] = true
    Object.keys(rsScopes).forEach( function (rs) {
      if (redirects && redirects[rs]) {
        redirects[rs].forEach( function (host) {
          hostList[host] = true
          rsScopes[host] = rsScopes[rs] // redirected host has scope of standardized resource
        })
      } else {
        hostList[rs] = true
      }
    })

// console.log('\nhostList\n',hostList)

    // app keys for IX are stored with registrar
    db.getAppKeys( 'registrar', Object.keys(hostList), vault.keys, function ( e, keys ) {
      if (e) return next( e )
        var err
      if ( !keys[jws.payload.iss] || !keys[jws.payload.iss][jws.header.kid] ) {
        err = new Error( "Invalid Agent Request key or kid")
        err.code = "INVALID_REQUEST"
        return next( err )
      }
      if ( !jws.verify( keys[jws.payload.iss][jws.header.kid] ) ) {
        err = new Error( "Invalid Agent Request")
        err.code = "INVALID_REQUEST"
        return next( err )
      }
      db.getRsDIfromAsDI( ixToken.sub, ixToken.iss, Object.keys(hostList), function ( e, dis ) {
        if (e) return next( e )
        // make tokens for all resources, delete caller from list
        var tokens = {}
        delete hostList[jws.payload.iss]
        Object.keys( hostList ).forEach( function (rs) {
          var payload =
            { 'iss': config.host.ix
            , 'aud': rs
            , 'sub': dis[rs]
            , 'token.a2p3.org':
              { 'auth': jwe.payload['token.a2p3.org'].auth
              , 'app': jws.payload.iss
              , 'scopes': rsScopes[rs]
              }
            }
          tokens[rs] = token.create( payload, keys[rs].latest )
        })
        return res.send( { result: {'sub': dis[jws.payload.iss], 'tokens': tokens, 'redirects': redirects} } )
      })
    })
  })
}

// APIs called from AS agent registration web app
function agentList ( req, res, next ) {
    db.listAgents(  req.request['request.a2p3.org'].di
                  , req.request.iss
                  , function( e, handles ) {
                      if (e) return next (e)
                      return res.send({ result: { 'handles': handles } } )
                    } )
}

function agentAdd ( req, res, next ) {
    db.addAgent( req.request['request.a2p3.org'].di
                  , req.request.iss
                  , req.request['request.a2p3.org'].name
                  , function( e, token, handle ) {
                      if (e) return next (e)
                      return res.send({ result: { token: token, handle: handle } } )
                    } )
}

function agentDelete ( req, res, next ) {
  var di = req.request['request.a2p3.org'].di
    , as = req.request.iss
    , handle = req.request['request.a2p3.org'].handle
    db.deleteAgent( di, as, handle, function( e, AS ) {
      var details =
        { host: config.reverseHost[AS]  // hack because of how api.call works currently TBD :(
        , api: '/agent/delete'
        , credentials: vault.keys[AS].latest
        , payload:
          { iss: config.host.ix
          , aud: AS
          , 'request.a2p3.org': { 'handle': handle }
          }
        }
      api.call( details, function ( e ) {
        if (e) return next (e)
        return res.send( { result: { success: true } } )
    })
  })
}

exports.app = function() {
	var app = express()
  app.use(express.limit('10kb'))  // protect against large POST attack
  app.use(express.bodyParser())

  app.post('/di/create'
          , request.check( vault.keys, config.roles.enroll )
          , mw.a2p3Params( ['AS', 'RS', 'redirects'] )
          , diCreate
          )
  app.post('/exchange'
          , request.check( vault.keys, null, 'registrar' )  // registrar holds all IX App keys
          , mw.a2p3Params( ['token', 'request'] )
          , exchange
          )
  app.post('/agent/list'
          , request.check( vault.keys, config.roles.as )
          , agentList
          )
  app.post('/agent/add'
          , request.check( vault.keys, config.roles.as )
          , agentAdd
          )
  app.post('/agent/delete'
          , request.check( vault.keys, config.roles.as )
          , agentDelete
          )

  // show README.md as documentation
  app.get('/documentation', mw.md( __dirname+'/README.md' ) )

  // key integrity checking API
  app.post( '/key/check', mw.keyCheck( vault, config.host.ix ) )

  app.use( mw.errorHandler )

	return app
}
<|endoftext|>


<commit_before>var UI = {
	Menu: function Menu (type, options) {
		var aside = document.createElement("aside"),
			menuItems = [],
			menuItem = null,
			menu = this,
			m = 0;
		aside.setAttribute("class", "UI-Menu");
		this.element = aside;
		this.applet = null;
		type = (!!type ? type : "standard");
		switch (type) {
			case "standard":
				menuItems = UI.defaults.menu.options;
			break;
			case "custom":
				menuItems = options.menuItems;
			break;
		}
		while (m < menuItems.length) {
			// create menu for app
			menuItem = menuItems[m];
			var button = document.createElement("a");
			button.setAttribute("class", "UI-Menu-Button");
			button.setAttribute("href", "javascript:void(0);");
			button.setAttribute("title", menuItem.name);
			button.setAttribute("style", "background-image:url("+menuItem.icon+")");
			button.addEventListener("click", function (evt) {
				menuItem.click(evt, menu);
			});
			aside.appendChild(button);
			m += 1;
		}
	},
	Sidebar: function Sidebar (type, options) {
		var aside = document.createElement("aside"),
			icon = document.createElement("img"),
			h2 = document.createElement("h2"),
			h3 = document.createElement("h3");
		aside.setAttribute("class", "UI-Sidebar");
		this.element = aside;
        this.options = options;
		switch (type) {
			case "standard":
				icon.src = options.icon;
                icon.setAttribute("class", "icon");
				h2.innerHTML = options.title;
				h3.innerHTML = options.subtitle;
				aside.appendChild(icon);
				aside.appendChild(h2);
				aside.appendChild(h3);
				aside.appendChild(document.createElement("br"));
			break;
			case "custom":

			break;
		}
	},
	Toolbar: function Toolbar (type, options) {
		var aside = document.createElement("aside");
		aside.setAttribute("class", "UI-Toolbar");
		this.element = aside;
		switch (type) {
			case "standard":

			break;
			case "custom":

			break;
		}
	},
	Frame: function Frame (type, options) {
		var main = document.createElement("main"),
			view = null;
		main.setAttribute("class", "UI-Frame");
		this.element = main;
		switch (type) {
			case "text":
				view = document.createElement("textarea");
			break;
			case "codemirror":
				view = document.createElement("textarea");
			break;
			case "canvas":
				view = document.createElement("canvas");
			break;
			case "webgl":
				view  = document.createElement("canvas");
			break;

		}
		this.animate = function () {

		};
		this.resize = function () {

		};
	},
	ModalWindow: function ModalWindow (type, options) {
		var section = document.createElement("section");
		section.setAttribute("class", "UI-ModalWindow");
		this.element = section;
		switch (type) {
			case "standard":

			break;
			case "custom":

			break;
		}
	},
	ContextMenu: function ContextMenu (options) {
		var div = document.createElement("div"),
			list = document.createElement("ul"),
			item = document.createElement("li");
		this.element = div;
		div.setAttribute("class", "UI-Context-Menu");
		item.innerHTML="Download";
		div.appendChild(list);
		list.appendChild(item);
		if (options.menuItems.length == 0) {
			options.menuItems = UI.defaults.contextMenu.options.menuItems;
		}
		options.menuItems.forEach(function (menuItem) {
			item = document.createElement("li");
			item.innerHTML = menuItem.name;
			item.setAttribute("data-resource", options.resource);
            item.setAttribute("data-name", options.name);
			item.setAttribute("class", "icon");
			item.setAttribute("style", "background-image:url("+menuItem.icon+")");
			item.addEventListener("click", function (evt) {
				menuItem.click(evt);
			}, true);
			list.appendChild(item);
		});
	},
	VectorEditor: function VectorEditor (options) {
		var div = document.createElement("div"),
			list = document.createElement("ul"),
			item = document.createElement("li");
		this.element = div;
		div.setAttribute("class", "UI-Vector-Editor");
		item.innerHTML="
"+options.name+"
";
		div.appendChild(list);
		list.appendChild(item);
		if (options.menuItems.length == 0) {
			options.menuItems = UI.defaults.contextMenu.options.menuItems;
		}
		options.menuItems.forEach(function (menuItem) {
			item = document.createElement("li");
			item.innerHTML = menuItem.name;
			item.addEventListener("click", function (evt) {
				menuItem.click(evt);
			}, false);
			list.appendChild(item);
		});
	},
	defaults: {
		menu: {
			options:[
				{"name": "Close", "icon":"/app/data/192/x.png", "click": function (event, menu) {
					menu.applet.dataPane.close();
				}},
				{"name": "New", "icon":"/app/data/plus.png", "click": function (event, applet) {

				}},
				{"name": "Options", "icon":"/app/data/192/circle.png", "click": function (event, applet) {

				}}
			]
		},
		sidebar: {
			loadFiles: function () {

			}
		},
		contextMenu: {
			options: {
				menuItems: [
//					{"name": "Open", "icon":"/app/data/hidpi-box.png", "click": function (e) { }},
					{"name": "Edit", "icon":"/app/data/192/dark/edit.png", "click": function (e) {
						var element = e.target,
							resource = element.getAttribute("data-resource"),
                            name = element.getAttribute("data-name");
						e.preventDefault();
						app.request("GET", resource+"?cache="+Date.now(), "", function (response) {
							app.openPane('edit', name, {"resource":app.cwd+"/"+name, "text": response});
						});
						return false;
					}},
					{"name": "Delete", "icon":"/app/data/192/dark/x.png", "click": function (e) {
						var element = e.target,
							resource = element.getAttribute("data-resource");
						deletePath(resource);
						// implement...

					}}
				]
			}
		}
	}

}

function AppIcon (name, index) {
	var element = document.createElement("div"),
		applet = app.applets[name],
		directionClass = "";
	if (!! index) {
		if (index == 1) {
			directionClass = " up";
		} else if (index == 4) {
			directionClass = " down";
		}
	}
    console.log("name", name);
	element.setAttribute("class", "UI-App-Icon" + directionClass);
	element.setAttribute("style", "background-image: url(" + applet.icon + ");");
	element.innerHTML = ""+applet.name+"";
	this.element = element;
	element.addEventListener("click", function () {
		app.openPane("app", applet.name, { applet: {name: name} });
	}, true);
}

function DataPane (type, name, data) {
	console.log(data);
    var container = document.createElement("div"),
        titleString = "",
        title = document.createElement("h2"),
		titleEntry = document.createElement("input"),
        done = document.createElement("input"),
		entry = document.createElement("textarea"),
		showTitle = false,
        showEntry = false,
        showTitleEntry = false,
		close = document.createElement("input"),
        upload = null,
        editWidget = null,
		applet = null;
    container.setAttribute("class", "DataPane");
	titleEntry.setAttribute("type", "text");
	titleEntry.setAttribute("class", "titleEntry");
	done.setAttribute("type", "button");
	done.setAttribute("class", "done");
	done.setAttribute("value", "Done");
	done.addEventListener("click", this.getCloseMethod(true), true);
	close.setAttribute("type", "button");
	close.setAttribute("class", "close");
	close.setAttribute("value", "X");
	close.addEventListener("click", this.getCloseMethod(), true);
    if (!!data.applet) {
        // load applet form data.applet
        applet = new Applet(data.applet.name);
		applet.dataPane = this; // won't be needed once DataPane is deprecated
		this.applet = applet;
		container = applet.div;
    } else {
		switch (type) {
            case "touch":
                showEntry = true;
                showTitleEntry = true;
				titleEntry.setAttribute("style", "background-image: url(/app/data/touch.png)");
				titleEntry.setAttribute("class", "titleEntry icon");
            break;
			case "mkdir":
                showTitleEntry = true;
				titleEntry.setAttribute("style", "background-image: url(/app/data/mkdir.png);");
				titleEntry.setAttribute("class", "titleEntry icon");
            break;
            case "upload":
                upload = document.createElement("input");
                upload.setAttribute("type", "file");
                upload.setAttribute("multiple", "multiple");
				titleString = 'Upload Files';
				showTitle = true;
            break;
            case "view":
                titleString = "View File";
                showEntry = true;
            break;
            case "edit":
                titleString = '';
                showEntry = true;
                showTitleEntry = true;
				if (!! data.icon) {
					titleEntry.setAttribute("style", "background-image: url("+data.icon+");");
				} else {
					titleEntry.setAttribute("style", "background-image: url(/app/data/text2.png);");
				}
				titleEntry.setAttribute("class", "titleEntry icon");

            break;
        }
        title.innerHTML = titleString;
		if (showTitle) {
			container.appendChild(title);
		}
		if (typeof(data)=='undefined' || typeof(data.controls) == 'undefined' || data.controls == true) {
        	container.appendChild(done);
        	container.appendChild(close);
		}
		if (!!data && !! data.class) {
			container.setAttribute("class", "DataPane "+data.class);
		}
        if (!! upload) {
            container.appendChild(upload);
        }
        if (showTitleEntry) {
            container.appendChild(titleEntry);
            titleEntry.value = name;
        }
        if (showEntry) {
            container.appendChild(entry);
            if (!! data.text) {
                entry.value = data.text;
            }
        }
        // used to add "done" button here
    }
    this.type = type;
    this.name = name;
    this.data = data;
	this.done = done;
	this.entry = entry;
	this.paneTitle = title;
	this.titleEntry = titleEntry;
    this.uploadInput = upload;
    this.container = container;
}

DataPane.prototype.snap = function (direction) {
	this.container.setAttribute("class", "DataPane "+direction);
};

DataPane.prototype.close = function () {
    var panes = app.panes,
        pane = this;
    pane.container.parentNode.removeChild(pane.container);
    panes.splice(panes.indexOf(pane));
};

DataPane.prototype.getCloseMethod = function (save) {
    var panes = app.panes,
        pane = this;
    return function (evt) {
		var leaveOpen = false;
		if (save) {
			switch (pane.type) {
                case "touch":
                    saveText(pane);
                break;
                case "mkdir":
                    makeDirectory(pane);
                break;
                case "upload":
                    uploadFiles(pane);
					leaveOpen = true;
                break;
                case "edit":
        			saveText(pane);
                break;
            }
		}
		if (!leaveOpen) {
			pane.container.parentNode.removeChild(pane.container);
			panes.splice(panes.indexOf(pane));
		}
    };
};

function Card (name, resource, options) {
    var e = document.createElement("div"),
        i = null,
		up = false,
		isImage = false,
		contextMenu = true,
		link = document.createElement("span"),
		close = document.createElement("input"),
		edit = document.createElement("input");
	e.setAttribute("class", "Card");
	e.setAttribute("data-resource", resource);
	e.setAttribute("data-name", name);
	link.setAttribute("target", "_blank");
	link.innerHTML = name;
	link.setAttribute("href", resource);
	close.setAttribute("class", "close");
	close.setAttribute("type", "button");
	close.setAttribute("value", "X");
	close.addEventListener("click", function (event) {
		event.preventDefault();
		deletePath(app.cwd+"/"+name);
		return false;
	}, true);
	isImage = /(\.jpg|\.png|\.gif|\.jpeg|\.webp)/i.test(resource);
    if (isImage) {
		var thumb = resource.replace(/\s/g, "%20");
		if (!/(\.webp|\.gif)/i.test(resource)) { // don't thumbnail webp or gif
			var rPath = thumb.split("/");
			var thumb = rPath[rPath.length-1];
			rPath.splice(rPath.length-1, 1);
			rPath.push("DHThumbs");
			if (window.innerWidth < 641) { // temporary hack to use high-dpi on mobile
				rPath.push("1024");
			}
			rPath.push(thumb+".jpg");
			thumb = rPath.join("/");
		} else {
			thumb = resource;
		}
		e.setAttribute("style", "background-image: url('"+thumb+"');"); //resource+"');");
		e.setAttribute("class", "Card Image");
    } else {
		e.appendChild(link);
		if (/^(.*\/){0,1}[^\.]*.{1}$/.test(resource)) { // detect folders
			contextMenu = false; // disable context menu for now...
            link.setAttribute("href", "#");
			link.addEventListener("click", function (event) {
				event.preventDefault();
				openFolder(resource);
				return false;
			}, true);
			e.setAttribute("class", "Card Folder");
		} else {
			if (!contextMenu) {
				edit.setAttribute("class", "close edit");
				edit.setAttribute("type", "button");
				edit.setAttribute("value", "Edit");
				edit.addEventListener("click", function (event) {
					event.preventDefault();
					app.request("GET", resource+"?cache="+Date.now(), "", function (response) {
						app.openPane('edit', name, {"resource":app.cwd+"/"+name, "text": response});
					});
					return false;
				}, true);
				e.appendChild(edit);
			}
		}
    }
	//	Experimental..
	if (contextMenu) {
		var menu = new UI.ContextMenu({
			name: name,
			resource: resource,
			menuItems: [] // dummy menu items
		});
		if (isImage) {
			e.appendChild(menu.element);
		} else {
			link.appendChild(menu.element);
		}
	} else {
		e.appendChild(close);
	}

    for (i in options) {
        e.setAttribute(i, options[i]);
    }
    return e;
}

<commit_msg>got default vertical App-UI menu button events working<commit_after>var UI = {
	Menu: function Menu (type, options) {
		var aside = document.createElement("aside"),
			menuItems = [],
			menuItem = null,
			menu = this,
			m = 0;
		aside.setAttribute("class", "UI-Menu");
		this.element = aside;
		this.applet = null;
		type = (!!type ? type : "standard");
		switch (type) {
			case "standard":
				menuItems = UI.defaults.menu.options;
			break;
			case "custom":
				menuItems = options.menuItems;
			break;
		}
		while (m < menuItems.length) {
			// create menu for app
			menuItem = menuItems[m];
			var button = document.createElement("a");
			button.setAttribute("class", "UI-Menu-Button");
			button.setAttribute("href", "javascript:void(0);");
			button.setAttribute("title", menuItem.name);
			button.setAttribute("style", "background-image:url("+menuItem.icon+")");
			(function (buttonMenu, buttonMenuItem){
				button.addEventListener("click", function (evt) {
					buttonMenuItem.click(buttonMenu);
				}, true);
			})(menu, menuItem);
			aside.appendChild(button);
			m += 1;
		}
	},
	Sidebar: function Sidebar (type, options) {
		var aside = document.createElement("aside"),
			icon = document.createElement("img"),
			h2 = document.createElement("h2"),
			h3 = document.createElement("h3");
		aside.setAttribute("class", "UI-Sidebar");
		this.element = aside;
        this.options = options;
		switch (type) {
			case "standard":
				icon.src = options.icon;
                icon.setAttribute("class", "icon");
				h2.innerHTML = options.title;
				h3.innerHTML = options.subtitle;
				aside.appendChild(icon);
				aside.appendChild(h2);
				aside.appendChild(h3);
				aside.appendChild(document.createElement("br"));
			break;
			case "custom":

			break;
		}
	},
	Toolbar: function Toolbar (type, options) {
		var aside = document.createElement("aside");
		aside.setAttribute("class", "UI-Toolbar");
		this.element = aside;
		switch (type) {
			case "standard":

			break;
			case "custom":

			break;
		}
	},
	Frame: function Frame (type, options) {
		var main = document.createElement("main"),
			view = null;
		main.setAttribute("class", "UI-Frame");
		this.element = main;
		switch (type) {
			case "text":
				view = document.createElement("textarea");
			break;
			case "codemirror":
				view = document.createElement("textarea");
			break;
			case "canvas":
				view = document.createElement("canvas");
			break;
			case "webgl":
				view  = document.createElement("canvas");
			break;

		}
		this.animate = function () {

		};
		this.resize = function () {

		};
	},
	ModalWindow: function ModalWindow (type, options) {
		var section = document.createElement("section");
		section.setAttribute("class", "UI-ModalWindow");
		this.element = section;
		switch (type) {
			case "standard":

			break;
			case "custom":

			break;
		}
	},
	ContextMenu: function ContextMenu (options) {
		var div = document.createElement("div"),
			list = document.createElement("ul"),
			item = document.createElement("li");
		this.element = div;
		div.setAttribute("class", "UI-Context-Menu");
		item.innerHTML="Download";
		div.appendChild(list);
		list.appendChild(item);
		if (options.menuItems.length == 0) {
			options.menuItems = UI.defaults.contextMenu.options.menuItems;
		}
		options.menuItems.forEach(function (menuItem) {
			item = document.createElement("li");
			item.innerHTML = menuItem.name;
			item.setAttribute("data-resource", options.resource);
            item.setAttribute("data-name", options.name);
			item.setAttribute("class", "icon");
			item.setAttribute("style", "background-image:url("+menuItem.icon+")");
			item.addEventListener("click", function (evt) {
				menuItem.click(evt);
			}, true);
			list.appendChild(item);
		});
	},
	VectorEditor: function VectorEditor (options) {
		var div = document.createElement("div"),
			list = document.createElement("ul"),
			item = document.createElement("li");
		this.element = div;
		div.setAttribute("class", "UI-Vector-Editor");
		item.innerHTML="
"+options.name+"
";
		div.appendChild(list);
		list.appendChild(item);
		if (options.menuItems.length == 0) {
			options.menuItems = UI.defaults.contextMenu.options.menuItems;
		}
		options.menuItems.forEach(function (menuItem) {
			item = document.createElement("li");
			item.innerHTML = menuItem.name;
			item.addEventListener("click", function (evt) {
				menuItem.click(evt);
			}, false);
			list.appendChild(item);
		});
	},
	defaults: {
		menu: {
			options:[
				{"name": "Close", "icon":"/app/data/192/x.png", "click": function close (menu) {
					console.log("Close event handler is happening now");
					menu.applet.dataPane.close();
				}},
				{"name": "New", "icon":"/app/data/plus.png", "click": function create (event, menu) {

				}},
				{"name": "Options", "icon":"/app/data/192/circle.png", "click": function options (event, menu) {

				}}
			]
		},
		sidebar: {
			loadFiles: function () {

			}
		},
		contextMenu: {
			options: {
				menuItems: [
//					{"name": "Open", "icon":"/app/data/hidpi-box.png", "click": function (e) { }},
					{"name": "Edit", "icon":"/app/data/192/dark/edit.png", "click": function (e) {
						var element = e.target,
							resource = element.getAttribute("data-resource"),
                            name = element.getAttribute("data-name");
						e.preventDefault();
						app.request("GET", resource+"?cache="+Date.now(), "", function (response) {
							app.openPane('edit', name, {"resource":app.cwd+"/"+name, "text": response});
						});
						return false;
					}},
					{"name": "Delete", "icon":"/app/data/192/dark/x.png", "click": function (e) {
						var element = e.target,
							resource = element.getAttribute("data-resource");
						deletePath(resource);
						// implement...

					}}
				]
			}
		}
	}

}

function AppIcon (name, index) {
	var element = document.createElement("div"),
		applet = app.applets[name],
		directionClass = "";
	if (!! index) {
		if (index == 1) {
			directionClass = " up";
		} else if (index == 4) {
			directionClass = " down";
		}
	}
    console.log("name", name);
	element.setAttribute("class", "UI-App-Icon" + directionClass);
	element.setAttribute("style", "background-image: url(" + applet.icon + ");");
	element.innerHTML = ""+applet.name+"";
	this.element = element;
	element.addEventListener("click", function () {
		app.openPane("app", applet.name, { applet: {name: name} });
	}, true);
}

function DataPane (type, name, data) {
	console.log(data);
    var container = document.createElement("div"),
        titleString = "",
        title = document.createElement("h2"),
		titleEntry = document.createElement("input"),
        done = document.createElement("input"),
		entry = document.createElement("textarea"),
		showTitle = false,
        showEntry = false,
        showTitleEntry = false,
		close = document.createElement("input"),
        upload = null,
        editWidget = null,
		applet = null;
    container.setAttribute("class", "DataPane");
	titleEntry.setAttribute("type", "text");
	titleEntry.setAttribute("class", "titleEntry");
	done.setAttribute("type", "button");
	done.setAttribute("class", "done");
	done.setAttribute("value", "Done");
	done.addEventListener("click", this.getCloseMethod(true), true);
	close.setAttribute("type", "button");
	close.setAttribute("class", "close");
	close.setAttribute("value", "X");
	close.addEventListener("click", this.getCloseMethod(), true);
    if (!!data.applet) {
        // load applet form data.applet
        applet = new Applet(data.applet.name);
		applet.dataPane = this; // won't be needed once DataPane is deprecated
		this.applet = applet;
		container = applet.div;
    } else {
		switch (type) {
            case "touch":
                showEntry = true;
                showTitleEntry = true;
				titleEntry.setAttribute("style", "background-image: url(/app/data/touch.png)");
				titleEntry.setAttribute("class", "titleEntry icon");
            break;
			case "mkdir":
                showTitleEntry = true;
				titleEntry.setAttribute("style", "background-image: url(/app/data/mkdir.png);");
				titleEntry.setAttribute("class", "titleEntry icon");
            break;
            case "upload":
                upload = document.createElement("input");
                upload.setAttribute("type", "file");
                upload.setAttribute("multiple", "multiple");
				titleString = 'Upload Files';
				showTitle = true;
            break;
            case "view":
                titleString = "View File";
                showEntry = true;
            break;
            case "edit":
                titleString = '';
                showEntry = true;
                showTitleEntry = true;
				if (!! data.icon) {
					titleEntry.setAttribute("style", "background-image: url("+data.icon+");");
				} else {
					titleEntry.setAttribute("style", "background-image: url(/app/data/text2.png);");
				}
				titleEntry.setAttribute("class", "titleEntry icon");

            break;
        }
        title.innerHTML = titleString;
		if (showTitle) {
			container.appendChild(title);
		}
		if (typeof(data)=='undefined' || typeof(data.controls) == 'undefined' || data.controls == true) {
        	container.appendChild(done);
        	container.appendChild(close);
		}
		if (!!data && !! data.class) {
			container.setAttribute("class", "DataPane "+data.class);
		}
        if (!! upload) {
            container.appendChild(upload);
        }
        if (showTitleEntry) {
            container.appendChild(titleEntry);
            titleEntry.value = name;
        }
        if (showEntry) {
            container.appendChild(entry);
            if (!! data.text) {
                entry.value = data.text;
            }
        }
        // used to add "done" button here
    }
    this.type = type;
    this.name = name;
    this.data = data;
	this.done = done;
	this.entry = entry;
	this.paneTitle = title;
	this.titleEntry = titleEntry;
    this.uploadInput = upload;
    this.container = container;
}

DataPane.prototype.snap = function (direction) {
	this.container.setAttribute("class", "DataPane "+direction);
};

DataPane.prototype.close = function () {
    var panes = app.panes,
        pane = this;
    pane.container.parentNode.removeChild(pane.container);
    panes.splice(panes.indexOf(pane));
};

DataPane.prototype.getCloseMethod = function (save) {
    var panes = app.panes,
        pane = this;
    return function (evt) {
		var leaveOpen = false;
		if (save) {
			switch (pane.type) {
                case "touch":
                    saveText(pane);
                break;
                case "mkdir":
                    makeDirectory(pane);
                break;
                case "upload":
                    uploadFiles(pane);
					leaveOpen = true;
                break;
                case "edit":
        			saveText(pane);
                break;
            }
		}
		if (!leaveOpen) {
			pane.container.parentNode.removeChild(pane.container);
			panes.splice(panes.indexOf(pane));
		}
    };
};

function Card (name, resource, options) {
    var e = document.createElement("div"),
        i = null,
		up = false,
		isImage = false,
		contextMenu = true,
		link = document.createElement("span"),
		close = document.createElement("input"),
		edit = document.createElement("input");
	e.setAttribute("class", "Card");
	e.setAttribute("data-resource", resource);
	e.setAttribute("data-name", name);
	link.setAttribute("target", "_blank");
	link.innerHTML = name;
	link.setAttribute("href", resource);
	close.setAttribute("class", "close");
	close.setAttribute("type", "button");
	close.setAttribute("value", "X");
	close.addEventListener("click", function (event) {
		event.preventDefault();
		deletePath(app.cwd+"/"+name);
		return false;
	}, true);
	isImage = /(\.jpg|\.png|\.gif|\.jpeg|\.webp)/i.test(resource);
    if (isImage) {
		var thumb = resource.replace(/\s/g, "%20");
		if (!/(\.webp|\.gif)/i.test(resource)) { // don't thumbnail webp or gif
			var rPath = thumb.split("/");
			var thumb = rPath[rPath.length-1];
			rPath.splice(rPath.length-1, 1);
			rPath.push("DHThumbs");
			if (window.innerWidth < 641) { // temporary hack to use high-dpi on mobile
				rPath.push("1024");
			}
			rPath.push(thumb+".jpg");
			thumb = rPath.join("/");
		} else {
			thumb = resource;
		}
		e.setAttribute("style", "background-image: url('"+thumb+"');"); //resource+"');");
		e.setAttribute("class", "Card Image");
    } else {
		e.appendChild(link);
		if (/^(.*\/){0,1}[^\.]*.{1}$/.test(resource)) { // detect folders
			contextMenu = false; // disable context menu for now...
            link.setAttribute("href", "#");
			link.addEventListener("click", function (event) {
				event.preventDefault();
				openFolder(resource);
				return false;
			}, true);
			e.setAttribute("class", "Card Folder");
		} else {
			if (!contextMenu) {
				edit.setAttribute("class", "close edit");
				edit.setAttribute("type", "button");
				edit.setAttribute("value", "Edit");
				edit.addEventListener("click", function (event) {
					event.preventDefault();
					app.request("GET", resource+"?cache="+Date.now(), "", function (response) {
						app.openPane('edit', name, {"resource":app.cwd+"/"+name, "text": response});
					});
					return false;
				}, true);
				e.appendChild(edit);
			}
		}
    }
	//	Experimental..
	if (contextMenu) {
		var menu = new UI.ContextMenu({
			name: name,
			resource: resource,
			menuItems: [] // dummy menu items
		});
		if (isImage) {
			e.appendChild(menu.element);
		} else {
			link.appendChild(menu.element);
		}
	} else {
		e.appendChild(close);
	}

    for (i in options) {
        e.setAttribute(i, options[i]);
    }
    return e;
}

<|endoftext|>


<commit_before>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

/**
 * @deprecated
 * Use `echarts/data/helper/createDimensions` instead.
 */

import {createHashMap, each, isString, defaults, extend, isObject, clone} from 'zrender/src/core/util';
import {normalizeToArray} from '../../util/model';
import {guessOrdinal} from './sourceHelper';
import Source from '../Source';
import {OTHER_DIMENSIONS} from './dimensionHelper';

/**
 * @see {module:echarts/test/ut/spec/data/completeDimensions}
 *
 * Complete the dimensions array, by user defined `dimension` and `encode`,
 * and guessing from the data structure.
 * If no 'value' dimension specified, the first no-named dimension will be
 * named as 'value'.
 *
 * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which
 *      provides not only dim template, but also default order.
 *      properties: 'name', 'type', 'displayName'.
 *      `name` of each item provides default coord name.
 *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and
 *                                    provide dims count that the sysDim required.
 *      [{ordinalMeta}] can be specified.
 * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)
 * @param {Object} [opt]
 * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
 *      For example: ['asdf', {name, type}, ...].
 * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}
 * @param {string} [opt.generateCoord] Generate coord dim with the given name.
 *                 If not specified, extra dim names will be:
 *                 'value', 'value0', 'value1', ...
 * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.
 *                 If `generateCoordCount` specified, the generated dim names will be:
 *                 `generateCoord` + 0, `generateCoord` + 1, ...
 *                 can be Infinity, indicate that use all of the remain columns.
 * @param {number} [opt.dimCount] If not specified, guess by the first data item.
 * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.
 * @return {Array.<Object>} [{
 *      name: string mandatory,
 *      displayName: string, the origin name in dimsDef, see source helper.
 *                 If displayName given, the tooltip will displayed vertically.
 *      coordDim: string mandatory,
 *      coordDimIndex: number mandatory,
 *      type: string optional,
 *      otherDims: { never null/undefined
 *          tooltip: number optional,
 *          label: number optional,
 *          itemName: number optional,
 *          seriesName: number optional,
 *      },
 *      isExtraCoord: boolean true if coord is generated
 *          (not specified in encode and not series specified)
 *      other props ...
 * }]
 */
function completeDimensions(sysDims, source, opt) {
    if (!Source.isInstance(source)) {
        source = Source.seriesDataToSource(source);
    }

    opt = opt || {};
    sysDims = (sysDims || []).slice();
    var dimsDef = (opt.dimsDef || []).slice();
    var encodeDef = createHashMap(opt.encodeDef);
    var dataDimNameMap = createHashMap();
    var coordDimNameMap = createHashMap();
    // var valueCandidate;
    var result = [];

    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);

    // Apply user defined dims (`name` and `type`) and init result.
    for (var i = 0; i < dimCount; i++) {
        var dimDefItem = dimsDef[i] = extend(
            {}, isObject(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}
        );
        var userDimName = dimDefItem.name;
        var resultItem = result[i] = {otherDims: {}};
        // Name will be applied later for avoiding duplication.
        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
            // Only if `series.dimensions` is defined in option
            // displayName, will be set, and dimension will be diplayed vertically in
            // tooltip by default.
            resultItem.name = resultItem.displayName = userDimName;
            dataDimNameMap.set(userDimName, i);
        }
        dimDefItem.type != null && (resultItem.type = dimDefItem.type);
        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
    }

    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
    encodeDef.each(function (dataDims, coordDim) {
        dataDims = normalizeToArray(dataDims).slice();

        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
        // `{encode: {x: -1, y: 1}}`. Should not filter anything in
        // this case.
        if (dataDims.length === 1 && typeof dataDims[0] === 'number' && dataDims[0] < 0) {
            encodeDef.set(coordDim, false);
            return;
        }

        var validDataDims = encodeDef.set(coordDim, []);
        each(dataDims, function (resultDimIdx, idx) {
            // The input resultDimIdx can be dim name or index.
            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));
            if (resultDimIdx != null && resultDimIdx < dimCount) {
                validDataDims[idx] = resultDimIdx;
                applyDim(result[resultDimIdx], coordDim, idx);
            }
        });
    });

    // Apply templetes and default order from `sysDims`.
    var availDimIdx = 0;
    each(sysDims, function (sysDimItem, sysDimIndex) {
        var coordDim;
        var sysDimItem;
        var sysDimItemDimsDef;
        var sysDimItemOtherDims;
        if (isString(sysDimItem)) {
            coordDim = sysDimItem;
            sysDimItem = {};
        }
        else {
            coordDim = sysDimItem.name;
            var ordinalMeta = sysDimItem.ordinalMeta;
            sysDimItem.ordinalMeta = null;
            sysDimItem = clone(sysDimItem);
            sysDimItem.ordinalMeta = ordinalMeta;
            // `coordDimIndex` should not be set directly.
            sysDimItemDimsDef = sysDimItem.dimsDef;
            sysDimItemOtherDims = sysDimItem.otherDims;
            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex
                = sysDimItem.dimsDef = sysDimItem.otherDims = null;
        }

        var dataDims = encodeDef.get(coordDim);

        // negative resultDimIdx means no need to mapping.
        if (dataDims === false) {
            return;
        }

        var dataDims = normalizeToArray(dataDims);

        // dimensions provides default dim sequences.
        if (!dataDims.length) {
            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {
                    availDimIdx++;
                }
                availDimIdx < result.length && dataDims.push(availDimIdx++);
            }
        }

        // Apply templates.
        each(dataDims, function (resultDimIdx, coordDimIndex) {
            var resultItem = result[resultDimIdx];
            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
            if (resultItem.name == null && sysDimItemDimsDef) {
                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
                !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});
                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
            }
            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
        });
    });

    function applyDim(resultItem, coordDim, coordDimIndex) {
        if (OTHER_DIMENSIONS.get(coordDim) != null) {
            resultItem.otherDims[coordDim] = coordDimIndex;
        }
        else {
            resultItem.coordDim = coordDim;
            resultItem.coordDimIndex = coordDimIndex;
            coordDimNameMap.set(coordDim, true);
        }
    }

    // Make sure the first extra dim is 'value'.
    var generateCoord = opt.generateCoord;
    var generateCoordCount = opt.generateCoordCount;
    var fromZero = generateCoordCount != null;
    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;
    var extra = generateCoord || 'value';

    // Set dim `name` and other `coordDim` and other props.
    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};
        var coordDim = resultItem.coordDim;

        if (coordDim == null) {
            resultItem.coordDim = genName(
                extra, coordDimNameMap, fromZero
            );
            resultItem.coordDimIndex = 0;
            if (!generateCoord || generateCoordCount <= 0) {
                resultItem.isExtraCoord = true;
            }
            generateCoordCount--;
        }

        resultItem.name == null && (resultItem.name = genName(
            resultItem.coordDim,
            dataDimNameMap
        ));

        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {
            resultItem.type = 'ordinal';
        }
    }

    return result;
}

// ??? TODO
// Originally detect dimCount by data[0]. Should we
// optimize it to only by sysDims and dimensions and encode.
// So only necessary dims will be initialized.
// But
// (1) custom series should be considered. where other dims
// may be visited.
// (2) sometimes user need to calcualte bubble size or use visualMap
// on other dimensions besides coordSys needed.
// So, dims that is not used by system, should be shared in storage?
function getDimCount(source, sysDims, dimsDef, optDimCount) {
    // Note that the result dimCount should not small than columns count
    // of data, otherwise `dataDimNameMap` checking will be incorrect.
    var dimCount = Math.max(
        source.dimensionsDetectCount || 1,
        sysDims.length,
        dimsDef.length,
        optDimCount || 0
    );
    each(sysDims, function (sysDimItem) {
        var sysDimItemDimsDef = sysDimItem.dimsDef;
        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));
    });
    return dimCount;
}

function genName(name, map, fromZero) {
    if (fromZero || map.get(name) != null) {
        var i = 0;
        while (map.get(name + i) != null) {
            i++;
        }
        name += i;
    }
    map.set(name, true);
    return name;
}

export default completeDimensions;
<commit_msg>Tweak the "is string" check.<commit_after>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

/**
 * @deprecated
 * Use `echarts/data/helper/createDimensions` instead.
 */

import {createHashMap, each, isString, defaults, extend, isObject, clone} from 'zrender/src/core/util';
import {normalizeToArray} from '../../util/model';
import {guessOrdinal} from './sourceHelper';
import Source from '../Source';
import {OTHER_DIMENSIONS} from './dimensionHelper';

/**
 * @see {module:echarts/test/ut/spec/data/completeDimensions}
 *
 * Complete the dimensions array, by user defined `dimension` and `encode`,
 * and guessing from the data structure.
 * If no 'value' dimension specified, the first no-named dimension will be
 * named as 'value'.
 *
 * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which
 *      provides not only dim template, but also default order.
 *      properties: 'name', 'type', 'displayName'.
 *      `name` of each item provides default coord name.
 *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and
 *                                    provide dims count that the sysDim required.
 *      [{ordinalMeta}] can be specified.
 * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)
 * @param {Object} [opt]
 * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
 *      For example: ['asdf', {name, type}, ...].
 * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}
 * @param {string} [opt.generateCoord] Generate coord dim with the given name.
 *                 If not specified, extra dim names will be:
 *                 'value', 'value0', 'value1', ...
 * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.
 *                 If `generateCoordCount` specified, the generated dim names will be:
 *                 `generateCoord` + 0, `generateCoord` + 1, ...
 *                 can be Infinity, indicate that use all of the remain columns.
 * @param {number} [opt.dimCount] If not specified, guess by the first data item.
 * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.
 * @return {Array.<Object>} [{
 *      name: string mandatory,
 *      displayName: string, the origin name in dimsDef, see source helper.
 *                 If displayName given, the tooltip will displayed vertically.
 *      coordDim: string mandatory,
 *      coordDimIndex: number mandatory,
 *      type: string optional,
 *      otherDims: { never null/undefined
 *          tooltip: number optional,
 *          label: number optional,
 *          itemName: number optional,
 *          seriesName: number optional,
 *      },
 *      isExtraCoord: boolean true if coord is generated
 *          (not specified in encode and not series specified)
 *      other props ...
 * }]
 */
function completeDimensions(sysDims, source, opt) {
    if (!Source.isInstance(source)) {
        source = Source.seriesDataToSource(source);
    }

    opt = opt || {};
    sysDims = (sysDims || []).slice();
    var dimsDef = (opt.dimsDef || []).slice();
    var encodeDef = createHashMap(opt.encodeDef);
    var dataDimNameMap = createHashMap();
    var coordDimNameMap = createHashMap();
    // var valueCandidate;
    var result = [];

    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);

    // Apply user defined dims (`name` and `type`) and init result.
    for (var i = 0; i < dimCount; i++) {
        var dimDefItem = dimsDef[i] = extend(
            {}, isObject(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}
        );
        var userDimName = dimDefItem.name;
        var resultItem = result[i] = {otherDims: {}};
        // Name will be applied later for avoiding duplication.
        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
            // Only if `series.dimensions` is defined in option
            // displayName, will be set, and dimension will be diplayed vertically in
            // tooltip by default.
            resultItem.name = resultItem.displayName = userDimName;
            dataDimNameMap.set(userDimName, i);
        }
        dimDefItem.type != null && (resultItem.type = dimDefItem.type);
        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
    }

    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
    encodeDef.each(function (dataDims, coordDim) {
        dataDims = normalizeToArray(dataDims).slice();

        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
        // `{encode: {x: -1, y: 1}}`. Should not filter anything in
        // this case.
        if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
            encodeDef.set(coordDim, false);
            return;
        }

        var validDataDims = encodeDef.set(coordDim, []);
        each(dataDims, function (resultDimIdx, idx) {
            // The input resultDimIdx can be dim name or index.
            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));
            if (resultDimIdx != null && resultDimIdx < dimCount) {
                validDataDims[idx] = resultDimIdx;
                applyDim(result[resultDimIdx], coordDim, idx);
            }
        });
    });

    // Apply templetes and default order from `sysDims`.
    var availDimIdx = 0;
    each(sysDims, function (sysDimItem, sysDimIndex) {
        var coordDim;
        var sysDimItem;
        var sysDimItemDimsDef;
        var sysDimItemOtherDims;
        if (isString(sysDimItem)) {
            coordDim = sysDimItem;
            sysDimItem = {};
        }
        else {
            coordDim = sysDimItem.name;
            var ordinalMeta = sysDimItem.ordinalMeta;
            sysDimItem.ordinalMeta = null;
            sysDimItem = clone(sysDimItem);
            sysDimItem.ordinalMeta = ordinalMeta;
            // `coordDimIndex` should not be set directly.
            sysDimItemDimsDef = sysDimItem.dimsDef;
            sysDimItemOtherDims = sysDimItem.otherDims;
            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex
                = sysDimItem.dimsDef = sysDimItem.otherDims = null;
        }

        var dataDims = encodeDef.get(coordDim);

        // negative resultDimIdx means no need to mapping.
        if (dataDims === false) {
            return;
        }

        var dataDims = normalizeToArray(dataDims);

        // dimensions provides default dim sequences.
        if (!dataDims.length) {
            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {
                    availDimIdx++;
                }
                availDimIdx < result.length && dataDims.push(availDimIdx++);
            }
        }

        // Apply templates.
        each(dataDims, function (resultDimIdx, coordDimIndex) {
            var resultItem = result[resultDimIdx];
            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
            if (resultItem.name == null && sysDimItemDimsDef) {
                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
                !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});
                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
            }
            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
        });
    });

    function applyDim(resultItem, coordDim, coordDimIndex) {
        if (OTHER_DIMENSIONS.get(coordDim) != null) {
            resultItem.otherDims[coordDim] = coordDimIndex;
        }
        else {
            resultItem.coordDim = coordDim;
            resultItem.coordDimIndex = coordDimIndex;
            coordDimNameMap.set(coordDim, true);
        }
    }

    // Make sure the first extra dim is 'value'.
    var generateCoord = opt.generateCoord;
    var generateCoordCount = opt.generateCoordCount;
    var fromZero = generateCoordCount != null;
    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;
    var extra = generateCoord || 'value';

    // Set dim `name` and other `coordDim` and other props.
    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};
        var coordDim = resultItem.coordDim;

        if (coordDim == null) {
            resultItem.coordDim = genName(
                extra, coordDimNameMap, fromZero
            );
            resultItem.coordDimIndex = 0;
            if (!generateCoord || generateCoordCount <= 0) {
                resultItem.isExtraCoord = true;
            }
            generateCoordCount--;
        }

        resultItem.name == null && (resultItem.name = genName(
            resultItem.coordDim,
            dataDimNameMap
        ));

        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {
            resultItem.type = 'ordinal';
        }
    }

    return result;
}

// ??? TODO
// Originally detect dimCount by data[0]. Should we
// optimize it to only by sysDims and dimensions and encode.
// So only necessary dims will be initialized.
// But
// (1) custom series should be considered. where other dims
// may be visited.
// (2) sometimes user need to calcualte bubble size or use visualMap
// on other dimensions besides coordSys needed.
// So, dims that is not used by system, should be shared in storage?
function getDimCount(source, sysDims, dimsDef, optDimCount) {
    // Note that the result dimCount should not small than columns count
    // of data, otherwise `dataDimNameMap` checking will be incorrect.
    var dimCount = Math.max(
        source.dimensionsDetectCount || 1,
        sysDims.length,
        dimsDef.length,
        optDimCount || 0
    );
    each(sysDims, function (sysDimItem) {
        var sysDimItemDimsDef = sysDimItem.dimsDef;
        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));
    });
    return dimCount;
}

function genName(name, map, fromZero) {
    if (fromZero || map.get(name) != null) {
        var i = 0;
        while (map.get(name + i) != null) {
            i++;
        }
        name += i;
    }
    map.set(name, true);
    return name;
}

export default completeDimensions;
<|endoftext|>


<commit_before>function Sprite(options) {
  this.canvas = options.canvas;
  this.context = this.canvas.getContext('2d');
  this.image = options.image;

  this.rows = options.rows;
  this.columns = options.columns;

  this.rowIndex = options.rowIndex || 0;
  this.columnIndex = options.columnIndex || 0;

  this.rowFrequency = options.rowFrequency || 0;
  this.columnFrequency = options.columnFrequency || 0;

  this.rowCycle = options.rowCycle || false;
  this.columnCycle = options.columnCycle || false;

  this.rowDirection = options.rowDirection || 1;
  this.columnDirection = options.rowDirection || 1;

  var blockWidth = this.image.width / this.columns;
  var blockHeight = this.image.height / this.rows;

  this.width = options.width || blockWidth;
  this.height = options.height || blockHeight;

  this._count = 1;
}

/*
 *  Private API
 */

Sprite.prototype._updateSprite = function(dimension) {
  if (this._count % this[dimension + 'Frequency'] === 0) {
    this[dimension + 'Index'] += this[dimension + 'Direction'];

    // Revert the direction when the dimension index is at the dimension limits
    // (zero or length - 1)
    if ((!this[dimension + 'Cycle']) &&
        ((this[dimension + 'Index'] === (this[dimension + 's'] - 1)) ||
         (this[dimension + 'Index'] === 0))) {
      this[dimension + 'Direction'] *= -1;
      return;
    }
    this[dimension + 'Index'] = this[dimension + 'Index'] % this[dimension + 's'];
  }
}

Sprite.prototype._getClipRectangle = function() {
  var blockWidth = this.image.width / this.columns;
  var blockHeight = this.image.height / this.rows;
  return {
    x: this.columnIndex * blockWidth,
    y: this.rowIndex * blockHeight,
    width: blockWidth,
    height: blockHeight,
  };
}

/*
 *  Public API
 */

Sprite.prototype.draw = function(x, y) {
  this._updateSprite('row');
  this._updateSprite('column');

  var clip = this._getClipRectangle();
  this.context.drawImage(this.image, clip.x, clip.y, clip.width, clip.height,
                         x, y, this.width, this.height);

  this._count += 1;
}
<commit_msg>Encapsulate whole library in a function<commit_after>(function(global) {
  window.Sprite = function(options) {
    this.canvas = options.canvas;
    this.context = this.canvas.getContext('2d');
    this.image = options.image;

    this.rows = options.rows;
    this.columns = options.columns;

    this.rowIndex = options.rowIndex || 0;
    this.columnIndex = options.columnIndex || 0;

    this.rowFrequency = options.rowFrequency || 0;
    this.columnFrequency = options.columnFrequency || 0;

    this.rowCycle = options.rowCycle || false;
    this.columnCycle = options.columnCycle || false;

    this.rowDirection = options.rowDirection || 1;
    this.columnDirection = options.rowDirection || 1;

    var blockWidth = this.image.width / this.columns;
    var blockHeight = this.image.height / this.rows;

    this.width = options.width || blockWidth;
    this.height = options.height || blockHeight;

    this._count = 1;
  }

  /*
   *  Private API
   */

  Sprite.prototype._updateSprite = function(dimension) {
    if (this._count % this[dimension + 'Frequency'] === 0) {
      this[dimension + 'Index'] += this[dimension + 'Direction'];

      // Revert the direction when the dimension index is at the dimension limits
      // (zero or length - 1)
      if ((!this[dimension + 'Cycle']) &&
          ((this[dimension + 'Index'] === (this[dimension + 's'] - 1)) ||
           (this[dimension + 'Index'] === 0))) {
        this[dimension + 'Direction'] *= -1;
        return;
      }
      this[dimension + 'Index'] = this[dimension + 'Index'] % this[dimension + 's'];
    }
  }

  Sprite.prototype._getClipRectangle = function() {
    var blockWidth = this.image.width / this.columns;
    var blockHeight = this.image.height / this.rows;
    return {
      x: this.columnIndex * blockWidth,
      y: this.rowIndex * blockHeight,
      width: blockWidth,
      height: blockHeight,
    };
  }

  /*
   *  Public API
   */

  Sprite.prototype.draw = function(x, y) {
    this._updateSprite('row');
    this._updateSprite('column');

    var clip = this._getClipRectangle();
    this.context.drawImage(this.image, clip.x, clip.y, clip.width, clip.height,
                           x, y, this.width, this.height);

    this._count += 1;
  }
})(window);
<|endoftext|>


<commit_before>// Copyright (C) 2016 Goom Inc. All rights reserved.

import _ from 'lodash';

import i18n from 'commons/utils/i18n';

const brandName = (brand) => {
  const name = brand && brand.name;
  if (!name) {
    return '';
  }

  return name && i18n.get(name);
};

exports.getName = (brand) => {
  // format: '[Building] Name'
  const name = brandName(brand);
  if (!name) {
    return '';
  }

  const data = brand && brand.data;

  const buildingName = data.building && data.building.name;
  if (buildingName) {
    return `[${buildingName}] ${name}`;
  }
  return name;
};

exports.getNameWithAllBuildingInfo = (brand) => {
  // format: 'Name (Building Floor FlatNumber)'
  const name = brandName(brand);
  if (!name) {
    return '';
  }
  return `${name} (${_.get(brand, 'data.building.name')} ${_.get(brand, 'data.building.floor')} ${_.get(brand, 'data.building.flatNumber')}호)`; // eslint-disable-line
};
<commit_msg>building.name -> location.building.name.ko<commit_after>// Copyright (C) 2016 Goom Inc. All rights reserved.

import _ from 'lodash';

import i18n from 'commons/utils/i18n';

const brandName = (brand) => {
  const name = brand && brand.name;
  if (!name) {
    return '';
  }

  return name && i18n.get(name);
};

exports.getName = (brand) => {
  // format: '[Building] Name'
  const name = brandName(brand);
  if (!name) {
    return '';
  }

  const data = brand && brand.data;

  const buildingName = _.get(data, 'location.building.name.ko');
  if (buildingName) {
    return `[${buildingName}] ${name}`;
  }
  return name;
};

exports.getNameWithAllBuildingInfo = (brand) => {
  // format: 'Name (Building Floor FlatNumber)'
  const name = brandName(brand);
  if (!name) {
    return '';
  }
  return `${name} (${_.get(brand, 'data.location.building.name.ko')} ${_.get(brand, 'data.location.floor')} ${_.get(brand, 'data.location.flatNumber')}호)`; // eslint-disable-line
};
<|endoftext|>


<commit_before>/**
 * @typedef {object} Phaser.Types.Renderer.WebGL.WebGLPipelineConfig
 * @since 3.50.0
 *
 * @property {Phaser.Game} game - The Phaser.Game instance that owns this pipeline.
 * @property {string} [name] - The name of the pipeline.
 * @property {GLenum} [topology=gl.TRIANGLES] - How the primitives are rendered. The default value is GL_TRIANGLES. Here is the full list of rendering primitives: (https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants).
 * @property {string} [vertShader] - The source code, as a string, for the vertex shader. If you need to assign multiple shaders, see the `shaders` property.
 * @property {string} [fragShader] - The source code, as a string, for the fragment shader. Can include `%count%` and `%forloop%` declarations for multi-texture support. If you need to assign multiple shaders, see the `shaders` property.
 * @property {number} [vertexCapacity] - The number of vertices to hold in the batch. Defaults to `RenderConfig.batchSize` * 6.
 * @property {number} [vertexSize] - The size, in bytes, of a single entry in the vertex buffer. Defaults to Float32Array.BYTES_PER_ELEMENT * 6 + Uint8Array.BYTES_PER_ELEMENT * 4.
 * @property {ArrayBuffer} [vertices] - An optional Array Buffer full of pre-calculated vertices data.
 * @property {Phaser.Types.Renderer.WebGL.WebGLPipelineAttributesConfig} [attributes] - An array of shader attribute data. All shaders bound to this pipeline must use the same attributes.
 * @property {string[]} [uniforms] - An array of shader uniform names that will be looked-up to get the locations for. If you need to assign multiple shaders, see the `shaders` property.
 * @property {Phaser.Types.Renderer.WebGL.WebGLPipelineShaderConfig[]} [shaders] - An array of shaders, all of which are created for this one pipeline. Uses the `vertShader`, `fragShader`, `attributes` and `uniforms` properties of this object as defaults.
 */
<commit_msg>You can forceZero via the config now<commit_after>/**
 * @typedef {object} Phaser.Types.Renderer.WebGL.WebGLPipelineConfig
 * @since 3.50.0
 *
 * @property {Phaser.Game} game - The Phaser.Game instance that owns this pipeline.
 * @property {string} [name] - The name of the pipeline.
 * @property {GLenum} [topology=gl.TRIANGLES] - How the primitives are rendered. The default value is GL_TRIANGLES. Here is the full list of rendering primitives: (https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants).
 * @property {string} [vertShader] - The source code, as a string, for the vertex shader. If you need to assign multiple shaders, see the `shaders` property.
 * @property {string} [fragShader] - The source code, as a string, for the fragment shader. Can include `%count%` and `%forloop%` declarations for multi-texture support. If you need to assign multiple shaders, see the `shaders` property.
 * @property {number} [vertexCapacity] - The number of vertices to hold in the batch. Defaults to `RenderConfig.batchSize` * 6.
 * @property {number} [vertexSize] - The size, in bytes, of a single entry in the vertex buffer. Defaults to Float32Array.BYTES_PER_ELEMENT * 6 + Uint8Array.BYTES_PER_ELEMENT * 4.
 * @property {ArrayBuffer} [vertices] - An optional Array Buffer full of pre-calculated vertices data.
 * @property {Phaser.Types.Renderer.WebGL.WebGLPipelineAttributesConfig} [attributes] - An array of shader attribute data. All shaders bound to this pipeline must use the same attributes.
 * @property {string[]} [uniforms] - An array of shader uniform names that will be looked-up to get the locations for. If you need to assign multiple shaders, see the `shaders` property.
 * @property {Phaser.Types.Renderer.WebGL.WebGLPipelineShaderConfig[]} [shaders] - An array of shaders, all of which are created for this one pipeline. Uses the `vertShader`, `fragShader`, `attributes` and `uniforms` properties of this object as defaults.
 * @property {boolean} [forceZero=false] - Force the shader to use just a single sampler2d? Set for anything that extends the Single Pipeline.
 */
<|endoftext|>


<commit_before>const express = require('express');
const fs = require('fs');
const https = require('https');
const http = require('http');

// Constants;
const instanceNumber = Number(process.env.INSTANCE_NUMBER);
const clusterName = process.env.CLUSTER_NAME;
const matchingPaths = process.env.APP_PATHS;
const responseCode = Number(process.env.RESPONSE_CODE);
const responseHeaders = process.env.RESPONSE_HEADERS;
const runHTTPS = (process.env.USE_HTTPS === 'https');

const getResponseHeaders = () => {
    if(responseHeaders) {
        return JSON.parse(JSON.parse(responseHeaders));
    }
    return null;
};

const respond = (responseCode, req, response) => {
    const headers = getResponseHeaders();
    if(headers) {
       Object.keys(headers).map(function(key) {response.set(key, headers[key])});
    }
    response.status(responseCode).json({
        cluster: clusterName,
        instance: instanceNumber,
        request: {
            baseUrl:  req.baseUrl,
            body: req.body,
            cookies: req.cookies,
            headers: req.headers,
            hostname: req.hostname,
            urlToRp: req.get("host"),
            urlToApplication: req.protocol + '://' + req.get('host') + req.originalUrl,
            params: req.params,
            path: req.path,
            protocol: req.protocol,
            query: req.query,
            secure: req.secure,
            signedCookies: req.signedCookies,
            xhr: req.xhr
        }
    });
};

const privateKey = fs.readFileSync('/app/internal.key');
const certificate = fs.readFileSync('/app/internal.cert');

const credentials = {key: privateKey, cert: certificate};
// App
const app = express();

// Map all paths that should have "found" responses.
if(matchingPaths) {
    const paths = matchingPaths.split("|");
    paths.forEach((path) => {
      app.all(path, function (req, res) { respond(responseCode, req, res); });
    });
}

app.get("/INTERNALHEALTHCHECKFORSTARTUP", function(req, res) {
   res.status(200).end();
});

// Handle all other requests as a 404 with the same information.
app.use(function (req, res) {
    respond(404, req, res);
});

let server;
if(runHTTPS) {
    server = https.createServer(credentials, app);
} else {
    server = http.createServer(app);
}
const runningServer = server.listen(3000, function () {
    const host = runningServer.address().address;
    const port = runningServer.address().port;

    console.log('Fake service app listening at http://%s:%s', host, port);
});<commit_msg>Removing unwanted console logging<commit_after>const express = require('express');
const fs = require('fs');
const https = require('https');
const http = require('http');

// Constants;
const instanceNumber = Number(process.env.INSTANCE_NUMBER);
const clusterName = process.env.CLUSTER_NAME;
const matchingPaths = process.env.APP_PATHS;
const responseCode = Number(process.env.RESPONSE_CODE);
const responseHeaders = process.env.RESPONSE_HEADERS;
const runHTTPS = (process.env.USE_HTTPS === 'https');

const getResponseHeaders = () => {
    if(responseHeaders) {
        return JSON.parse(JSON.parse(responseHeaders));
    }
    return null;
};

const respond = (responseCode, req, response) => {
    const headers = getResponseHeaders();
    if(headers) {
       Object.keys(headers).map(function(key) {response.set(key, headers[key])});
    }
    response.status(responseCode).json({
        cluster: clusterName,
        instance: instanceNumber,
        request: {
            baseUrl:  req.baseUrl,
            body: req.body,
            cookies: req.cookies,
            headers: req.headers,
            hostname: req.hostname,
            urlToRp: req.get("host"),
            urlToApplication: req.protocol + '://' + req.get('host') + req.originalUrl,
            params: req.params,
            path: req.path,
            protocol: req.protocol,
            query: req.query,
            secure: req.secure,
            signedCookies: req.signedCookies,
            xhr: req.xhr
        }
    });
};

const privateKey = fs.readFileSync('/app/internal.key');
const certificate = fs.readFileSync('/app/internal.cert');

const credentials = {key: privateKey, cert: certificate};
// App
const app = express();

// Map all paths that should have "found" responses.
if(matchingPaths) {
    const paths = matchingPaths.split("|");
    paths.forEach((path) => {
      app.all(path, function (req, res) { respond(responseCode, req, res); });
    });
}

app.get("/INTERNALHEALTHCHECKFORSTARTUP", function(req, res) {
   res.status(200).end();
});

// Handle all other requests as a 404 with the same information.
app.use(function (req, res) {
    respond(404, req, res);
});

let server;
if(runHTTPS) {
    server = https.createServer(credentials, app);
} else {
    server = http.createServer(app);
}
const runningServer = server.listen(3000);<|endoftext|>


<commit_before>/* classes */
var game = function(id, position) {
    this.id = id;
    this.position = position;
    this.wins = 0;
    this.losses = 0;
    this.locked = false;
    this.ranked = false;

    var differential = function() {
        return wins - losses;
    }
}
game.prototype.toString = function() {
    return this.id;
}

var games = function(list) {
    // private
    /*var*/ matchups = [];

    var isFirstGameBetter = function(game1, game2) {
        // todo: get user input

        console.log('contest: ' + game1 + ' vs ' + game2);

        return game1.id < game2.id;
    }

    var logMatchup = function(winner, loser) {
        var matchup = {};
        matchup.winner = winner;
        matchup.loser = loser;

        matchups.push(matchup);
    }

    var rankGames = function(games, gameIndex1, gameIndex2) {
        var isFirstBetter =
            isFirstGameBetter(games[gameIndex1], games[gameIndex2]);

        if(isFirstBetter)
        {
            games[gameIndex1].wins += 1;
            games[gameIndex2].losses += 1;
            logMatchup(games[gameIndex1].id, games[gameIndex2].id);
            games = reposition(games, gameIndex1, gameIndex2);
        }
        else
        {
            games[gameIndex1].losses += 1;
            games[gameIndex2].wins += 1;
            logMatchup(games[gameIndex2].id, games[gameIndex1].id);
            games = reposition(games, gameIndex2, gameIndex1);
        }

        // check_for_locks

        return games;
    }

    var reposition = function(games, winnerIndex, loserIndex) {
        var winnerPosition = games[winnerIndex].position;
        var loserPosition = games[loserIndex].position;

        if(winnerPosition < loserPosition) {
            if(games[winnerIndex].differential() > 0)
            {
                // winner.position increases by differential, as long as it does not move past any games that have been ranked above
            }

            if(games[loserIndex].differential() < 0)
            {
                // loser.position decreases by differential, as long as it does not move past any games that have been ranked below
            }
        }
        else {
            // Array.prototype.map() only supported in IE9+
            games.map(function(item){
                if(item.position >= loserPosition && item.position < winnerPosition)
                    item.position += 1;
            });

            games[winnerIndex].position = loserPosition;
        }

        return games;
    }

    // public
    this.list = list;

    this.sortList = function() {
        this.list.sort(compareGames);
    }

    this.contestAll = function() {
        if(this.list.length <= 1)
        {
            // todo: lock all
            return;
        }

        for(var i = 0; i < this.list.length; i += 2)
        {
            this.list = rankGames(this.list, i, i + 1);
            //this.sortList();
        }

        console.log(matchups);
    }
}
games.prototype.toString = function() {
    return this.list.toString();
}

/* methods */
var compareGames = function(game1, game2) {
  if (game1.position < game2.position)
    return -1;

  if (game1.position > game2.position)
    return 1;

  return 0;
}

var getGames = function() {
    // todo: get user input

    var games = [];
    var i, j;

    for(i = 1, j = 10; i <= 10; i++, j--) {
        games.push(new game(i, j));
    }

    return games;
}

/* main */
var games_array = getGames();
var games_object = new games(games_array);
games_object.toString();
games_object.sortList();
games_object.toString();
games_object.contestAll();

/*
getAllRankedLower:
    if none ranked lower
        return
    else
        return getAllRankedLower(lowerRanked)
*/

//g_losers = []
var getAllRankedLower = function (matchups, id, includeId) {
    console.log('getAllRankedLower: '+id)
    var losers = matchups.map(function(item){
        if (item.winner == id)
            return item.loser;
    }).filter(function(item){
        return item;
    });

    //g_losers.push(id);

    if (losers.length == 0) {
        // return includeId ? [id] : [];
        if (includeId)
            return [id];
        else
            return [];
    }
    else {
        var children = losers.map(function(item) {
            return getAllRankedLower(matchups, item, true);
        });

        var flatChildren = _.flatten(children);

        losers = losers.concat(flatChildren);

        if(includeId)
            losers.push(id);

        return _.uniq(losers);
    }
}

/*

var matchups = [];
matchups.push({'winner': 1, 'loser': 2});
matchups.push({'winner': 3, 'loser': 4});
matchups.push({'winner': 5, 'loser': 6});
matchups.push({'winner': 7, 'loser': 8});
matchups.push({'winner': 9, 'loser': 10});

matchups.push({'winner': 1, 'loser': 3});
matchups.push({'winner': 5, 'loser': 7});
matchups.push({'winner': 5, 'loser': 9});
matchups.push({'winner': 2, 'loser': 4});
matchups.push({'winner': 6, 'loser': 8});
matchups.push({'winner': 6, 'loser': 10});

var parent = 1;
var losers1 = [];
var losers2 = [];
for(var i = 0; i < matchups.length; i++)
{
    if(matchups[i].winner == parent)
        losers1.push(matchups[i].loser);
}

if(losers1.length > 0)
{
    for(var i = 0; i < losers1.length; i++)
    {
        for(var j = 0; j < matchups.length; j++)
        {
            if(losers1[i] == matchups[j].winner)
                losers2.push(matchups[j].loser);
        }
    }
}

var losers = _.uniq(losers1.concat(losers2));
*/<commit_msg>Implement getAllRankedHigher<commit_after>/* classes */
var game = function(id, position) {
    this.id = id;
    this.position = position;
    this.wins = 0;
    this.losses = 0;
    this.locked = false;
    this.ranked = false;

    var differential = function() {
        return wins - losses;
    }
}
game.prototype.toString = function() {
    return this.id;
}

var games = function(list) {
    // private
    /*var*/ matchups = [];

    var isFirstGameBetter = function(game1, game2) {
        // todo: get user input

        console.log('contest: ' + game1 + ' vs ' + game2);

        return game1.id < game2.id;
    }

    var logMatchup = function(winner, loser) {
        var matchup = {};
        matchup.winner = winner;
        matchup.loser = loser;

        matchups.push(matchup);
    }

    var rankGames = function(games, gameIndex1, gameIndex2) {
        var isFirstBetter =
            isFirstGameBetter(games[gameIndex1], games[gameIndex2]);

        if(isFirstBetter)
        {
            games[gameIndex1].wins += 1;
            games[gameIndex2].losses += 1;
            logMatchup(games[gameIndex1].id, games[gameIndex2].id);
            games = reposition(games, gameIndex1, gameIndex2);
        }
        else
        {
            games[gameIndex1].losses += 1;
            games[gameIndex2].wins += 1;
            logMatchup(games[gameIndex2].id, games[gameIndex1].id);
            games = reposition(games, gameIndex2, gameIndex1);
        }

        // check_for_locks

        return games;
    }

    var reposition = function(games, winnerIndex, loserIndex) {
        var winnerPosition = games[winnerIndex].position;
        var loserPosition = games[loserIndex].position;

        if(winnerPosition < loserPosition) {
            if(games[winnerIndex].differential() > 0)
            {
                // winner.position increases by differential, as long as it does not move past any games that have been ranked above
            }

            if(games[loserIndex].differential() < 0)
            {
                // loser.position decreases by differential, as long as it does not move past any games that have been ranked below
            }
        }
        else {
            // Array.prototype.map() only supported in IE9+
            games.map(function(item){
                if(item.position >= loserPosition && item.position < winnerPosition)
                    item.position += 1;
            });

            games[winnerIndex].position = loserPosition;
        }

        return games;
    }

    // public
    this.list = list;

    this.sortList = function() {
        this.list.sort(compareGames);
    }

    this.contestAll = function() {
        if(this.list.length <= 1)
        {
            // todo: lock all
            return;
        }

        for(var i = 0; i < this.list.length; i += 2)
        {
            this.list = rankGames(this.list, i, i + 1);
            //this.sortList();
        }

        console.log(matchups);
    }
}
games.prototype.toString = function() {
    return this.list.toString();
}

/* methods */
var compareGames = function(game1, game2) {
  if (game1.position < game2.position)
    return -1;

  if (game1.position > game2.position)
    return 1;

  return 0;
}

var getGames = function() {
    // todo: get user input

    var games = [];
    var i, j;

    for(i = 1, j = 10; i <= 10; i++, j--) {
        games.push(new game(i, j));
    }

    return games;
}

/* main */
var games_array = getGames();
var games_object = new games(games_array);
games_object.toString();
games_object.sortList();
games_object.toString();
games_object.contestAll();

var getAllRankedLower = function (matchups, id, includeId) {
    var losers = matchups.map(function(item){
        if (item.winner == id)
            return item.loser;
    }).filter(function(item){
        return item;
    });

    if (losers.length == 0) {
        return includeId ? [id] : [];
    }
    else {
        var children = losers.map(function(item) {
            return getAllRankedLower(matchups, item, true);
        });

        losers = losers.concat(_.flatten(children));

        if(includeId)
            losers.push(id);

        return _.uniq(losers);
    }
}

var getAllRankedHigher = function (matchups, id, includeId) {
    var winners = matchups.map(function(item){
        if (item.loser == id)
            return item.winner;
    }).filter(function(item){
        return item;
    });

    if (winners.length == 0) {
        return includeId ? [id] : [];
    }
    else {
        var parents = winners.map(function(item) {
            return getAllRankedHigher(matchups, item, true);
        });

        winners = winners.concat(_.flatten(parents););

        if(includeId)
            winners.push(id);

        return _.uniq(winners);
    }
}

/*
var matchups = [];
matchups.push({'winner': 1, 'loser': 2});
matchups.push({'winner': 3, 'loser': 4});
matchups.push({'winner': 5, 'loser': 6});
matchups.push({'winner': 7, 'loser': 8});
matchups.push({'winner': 9, 'loser': 10});

matchups.push({'winner': 1, 'loser': 3});
matchups.push({'winner': 5, 'loser': 7});
matchups.push({'winner': 5, 'loser': 9});
matchups.push({'winner': 2, 'loser': 4});
matchups.push({'winner': 6, 'loser': 8});
matchups.push({'winner': 6, 'loser': 10});
*/<|endoftext|>