<commit_before>var Lang = A.Lang,
	getClassName = A.ClassNameManager.getClassName,

	IFRAME = 'iframe',

	CSS_IFRAME_NODE = getClassName('dialog', IFRAME, 'node'),

	BUFFER_CSS_CLASS = [CSS_IFRAME_NODE],

	TPL_EMPTY_NODE = '

',
	TPL_IFRAME = '';

var DialogIframePlugin = A.Component.create(
	{
		ATTRS: {
			closeOnEscape: {
				value: true
			},

			iframeCssClass: {
				value: '',
				setter: '_setIframeCssClass'
			},

			iframeId: {
				valueFn: function() {
					return A.guid();
				}
			},

			uri: {
			}
		},

		EXTENDS: A.Plugin.Base,
		NAME: IFRAME,
		NS: IFRAME,
		prototype: {
			initializer: function(config) {
				var instance = this;

				instance._host = instance.get('host');

				instance.publish(
					'load',
					{
						defaultFn: instance._defaultLoadIframeFn
					}
				);

				instance.afterHostMethod('renderUI', instance.renderUI);
				instance.afterHostMethod('bindUI', instance.bindUI);

				instance.afterHostMethod('render', instance._afterRender);
			},

			renderUI: function() {
				var instance = this;

				instance._previousBodyContent = instance._host.get('bodyContent');

				var bodyContent = A.Node.create(TPL_EMPTY_NODE);

				var iframeTpl = Lang.sub(
					TPL_IFRAME,
					{
						cssClass: instance.get('iframeCssClass'),
						id: instance.get('iframeId'),
						uri: instance.get('uri')
					}
				);

				var node = A.Node.create(iframeTpl);

				bodyContent.append(node);

				instance._host.set('bodyContent', bodyContent);

				instance._bodyNode = instance._host.bodyNode;
				instance.node = node;
			},

			bindUI: function() {
				var instance = this;

				instance.afterHostEvent('heightChange', instance._updateIframeSize, instance);
				instance.afterHostEvent('widthChange', instance._updateIframeSize, instance);

				instance.after('uriChange', instance._afterUriChange);

				instance.node.on('load', A.bind(instance.fire, instance, 'load'));
			},

			destructor: function() {
				var instance = this;

				instance._host.set('bodyContent', instance._previousBodyContent);

				instance.node.remove(true);
			},

			_adjustSize: A.cached(
				function(number) {
					return ((parseInt(number, 10) || 0) - 5);
				}
			),

			_afterRender: function() {
				var instance = this;

				instance._bodyNode.plug(A.LoadingMask).loadingmask.show();
			},

			_afterUriChange: function(event) {
				var instance = this;

				instance._uiSetUri(event.newVal);
			},

			_defaultLoadIframeFn: function(event) {
				var instance = this;

				var node = instance.node;

				try {
					var iframeDoc = node.get('contentWindow.document');

					iframeDoc.get('documentElement').setStyle('overflow', 'visible');

					var iframeBody = iframeDoc.get('body');

					node.set('height', iframeBody.get('scrollHeight') + 5);

					if (instance.get('closeOnEscape')) {
						A.on(
							'key',
							function(event) {
								instance._host.close();
							},
							[iframeDoc],
							'down:27'
						);
					}
				}
				catch (e) {
				}

				instance._bodyNode.loadingmask.hide();
			},

			_setIframeCssClass: function(value) {
				BUFFER_CSS_CLASS[1] = value;

				return BUFFER_CSS_CLASS.join(' ');
			},

			_uiSetUri: function(value) {
				var instance = this;

				if (instance._bodyNode.loadingmask) {
					instance._bodyNode.loadingmask.show();
				}

				instance.node.attr('src', value);
			},

			_updateIframeSize: function(event) {
				var instance = this;

				var adjustSize = instance._adjustSize;

				var bodyNode = instance._bodyNode;
				var node = instance.node;

				var updateIframeSizeUI = instance._updateIframeSizeUI;

				if (!updateIframeSizeUI) {
					updateIframeSizeUI = function() {
						var bodyHeight = bodyNode.getStyle('height');

						node.setStyle('height', adjustSize(bodyHeight));

						bodyNode.loadingmask.refreshMask();
					};

					instance._updateIframeSizeUI = updateIframeSizeUI;
				}

				setTimeout(updateIframeSizeUI, 50);
			}
		}
	}
);

A.Plugin.DialogIframe = DialogIframePlugin;<commit_msg>AUI-333 - AUI Dialog iframe needs to update it's URI when user navigates to a different page<commit_after>var Lang = A.Lang,
	getClassName = A.ClassNameManager.getClassName,

	IFRAME = 'iframe',

	CSS_IFRAME_NODE = getClassName('dialog', IFRAME, 'node'),

	BUFFER_CSS_CLASS = [CSS_IFRAME_NODE],

	TPL_EMPTY_NODE = '

',
	TPL_IFRAME = '',

	UI = A.Widget.UI_SRC,
	UI_SRC = {
		src: UI
	};

var DialogIframePlugin = A.Component.create(
	{
		ATTRS: {
			closeOnEscape: {
				value: true
			},

			iframeCssClass: {
				value: '',
				setter: '_setIframeCssClass'
			},

			iframeId: {
				valueFn: function() {
					return A.guid();
				}
			},

			uri: {
			}
		},

		EXTENDS: A.Plugin.Base,
		NAME: IFRAME,
		NS: IFRAME,
		prototype: {
			initializer: function(config) {
				var instance = this;

				instance._host = instance.get('host');

				instance.publish(
					'load',
					{
						defaultFn: instance._defaultLoadIframeFn
					}
				);

				instance.afterHostMethod('renderUI', instance.renderUI);
				instance.afterHostMethod('bindUI', instance.bindUI);

				instance.afterHostMethod('render', instance._afterRender);
			},

			renderUI: function() {
				var instance = this;

				instance._previousBodyContent = instance._host.get('bodyContent');

				var bodyContent = A.Node.create(TPL_EMPTY_NODE);

				var iframeTpl = Lang.sub(
					TPL_IFRAME,
					{
						cssClass: instance.get('iframeCssClass'),
						id: instance.get('iframeId'),
						uri: instance.get('uri')
					}
				);

				var node = A.Node.create(iframeTpl);

				bodyContent.append(node);

				instance._host.set('bodyContent', bodyContent);

				instance._bodyNode = instance._host.bodyNode;
				instance.node = node;
			},

			bindUI: function() {
				var instance = this;

				instance.afterHostEvent('heightChange', instance._updateIframeSize, instance);
				instance.afterHostEvent('widthChange', instance._updateIframeSize, instance);

				instance.after('uriChange', instance._afterUriChange);

				instance.node.on('load', A.bind(instance.fire, instance, 'load'));
			},

			destructor: function() {
				var instance = this;

				instance._host.set('bodyContent', instance._previousBodyContent);

				instance.node.remove(true);
			},

			_adjustSize: A.cached(
				function(number) {
					return ((parseInt(number, 10) || 0) - 5);
				}
			),

			_afterRender: function() {
				var instance = this;

				instance._bodyNode.plug(A.LoadingMask).loadingmask.show();
			},

			_afterUriChange: function(event) {
				var instance = this;

				if (event.src != UI) {
					instance._uiSetUri(event.newVal);
				}
			},

			_defaultLoadIframeFn: function(event) {
				var instance = this;

				var node = instance.node;

				try {
					var iframeDoc = node.get('contentWindow.document');

					iframeDoc.get('documentElement').setStyle('overflow', 'visible');

					var iframeBody = iframeDoc.get('body');

					node.set('height', iframeBody.get('scrollHeight') + 5);

					instance.set('uri', iframeDoc('location.href'), UI_SRC);

					if (instance.get('closeOnEscape')) {
						A.on(
							'key',
							function(event) {
								instance._host.close();
							},
							[iframeDoc],
							'down:27'
						);
					}
				}
				catch (e) {
				}

				instance._bodyNode.loadingmask.hide();
			},

			_setIframeCssClass: function(value) {
				BUFFER_CSS_CLASS[1] = value;

				return BUFFER_CSS_CLASS.join(' ');
			},

			_uiSetUri: function(value) {
				var instance = this;

				if (instance._bodyNode.loadingmask) {
					instance._bodyNode.loadingmask.show();
				}

				instance.node.attr('src', value);
			},

			_updateIframeSize: function(event) {
				var instance = this;

				var adjustSize = instance._adjustSize;

				var bodyNode = instance._bodyNode;
				var node = instance.node;

				var updateIframeSizeUI = instance._updateIframeSizeUI;

				if (!updateIframeSizeUI) {
					updateIframeSizeUI = function() {
						var bodyHeight = bodyNode.getStyle('height');

						node.setStyle('height', adjustSize(bodyHeight));

						bodyNode.loadingmask.refreshMask();
					};

					instance._updateIframeSizeUI = updateIframeSizeUI;
				}

				setTimeout(updateIframeSizeUI, 50);
			}
		}
	}
);

A.Plugin.DialogIframe = DialogIframePlugin;<|endoftext|>


<commit_before>/**
 * deling.js is a simple share plugin with minimal fuzz.
 */

(function (window, document) {
  'use strict';

  var supportedNetworks = {
    'facebook': {
      url: 'https://www.facebook.com/share.php?u={{url}}',
      title: 'Facebook',
    },
    'twitter': {
      url: 'https://twitter.com/intent/tweet?url={{url}}&text={{title}}',
      title: 'Twitter',
    },
    'pinterest': {
      url: 'https://pinterest.com/pin/create/button/?url={{url}}&media={{media}}&title={{title}}',
      title: 'Pinterest',
      icon: 'pinterest-p',
    },
    'linkedin': {
      url: 'https://www.linkedin.com/shareArticle?mini=true&url={{url}}&title={{title}}&summary={{summary}}',
      title: 'LinkedIn',
    },
    'google-plus': {
      url: 'https://plus.google.com/share?url={{url}}',
      title: 'Google Plus',
    },
    'reddit': {
      url: 'https://www.reddit.com/submit?url={{url}}',
      title: 'reddit',
    },
    'tumblr':   {
      url: 'https://www.tumblr.com/share?v=3&u={{url}}&t={{title}}&content={{summary}}',
      title: 'tumblr',
    },
    'mail': {
      url: 'mailto:?subject=&body={{url}}',
      title: 'Mail',
      icon: 'envelope',
    },
  };

  function replacer (str, pairs) {
    str = str.toString();

    if (!pairs) {
      return str;
    }

    Object.keys(pairs).forEach(function (key) {
      var value = pairs[key];

      str = str.replace(new RegExp(key, 'g'), value);
    });

    return encodeURI(str);
  }

  function trim (str) {
    return str.trim();
  }

  function lowerCase (str) {
    return str.toLowerCase();
  }

  function getSettingsForElement (element) {
    // Defaults.
    var settings = {
      url: window.location.href,
      title: '',
      image: '',
      summary: '',
      networks: [],
      icons: true,
      names: false,
      popup: true,
      iconClass: 'deling-icon-',
    };

    for (var i = 0, j = element.attributes.length; i < j; i++) {
      var name = element.attributes[i].name;

      switch (name) {
        case 'data-networks':
          var attributeNetworks = element.attributes[i].value.split(',').map(trim).map(lowerCase);

          // Add only supported networks.
          for (var k = 0, l = attributeNetworks.length; k < l; k++) {
            if (supportedNetworks[attributeNetworks[k]]) {
              settings.networks.push(attributeNetworks[k]);
            }
          }

          break;
        case 'data-url':
          settings.url = element.attributes[i].value;
          break;

        case 'data-icons':
          settings.icons = element.attributes[i].value === 'true';
          break;

        case 'data-names':
          settings.names = element.attributes[i].value === 'true';
          break;

        case 'data-popup':
          settings.popup = element.attributes[i].value === 'true';
          break;

        case 'data-icon-class':
          settings.iconClass = element.attributes[i].value;
          break;

        case 'data-title':
          settings.title = element.attributes[i].value;
          break;

        case 'data-media':
          settings.media = element.attributes[i].value;
          break;

        case 'data-summary':
          settings.summary = element.attributes[i].value;
          break;
      }
    }

    if (!settings.networks.length) {
      Object.keys(supportedNetworks).forEach(function (n) {
        settings.networks.push(n);
      });
    }

    return settings;
  }

  function insertShareInElement (element, settings) {
    settings.networks.forEach(function (n) {
      var anchor = document.createElement('a'),
          network = supportedNetworks[n];

      anchor.setAttribute('class', 'deling-button network-' + n);
      anchor.setAttribute('href', replacer(network.url, {
        '{{url}}': settings.url,
        '{{title}}': settings.title,
        '{{media}}': settings.media,
        '{{summary}}': settings.summary,
      }));
      anchor.setAttribute('title', network.title);

      if (settings.popup) {
        anchor.setAttribute('target', '_blank');
      }

      if (settings.icons) {
        var icon = document.createElement('i');

        icon.setAttribute('class', 'deling-icon ' + settings.iconClass + (network.icon || n));

        anchor.appendChild(icon);
      }

      if (settings.names) {
        var name = document.createTextNode(network.title);

        anchor.appendChild(name);
      }

      element.appendChild(anchor);
    });
  }

  function addShareToElement (element) {
    insertShareInElement(element, getSettingsForElement(element));
  }

  function findAndPrepareElements (element, className) {
    var elements = element.getElementsByClassName(className);

    for (var i = 0, j = elements.length; i < j; i++) {
      addShareToElement(elements[i]);
    }
  }

  function deling (element, className) {
    className = className || 'deling';

    if (!element) {
      throw new Error('simpleShare requires an element.');
    }

    findAndPrepareElements(element, className);
  }

  if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', function () {
      deling(document);
    });
  } else {
    throw new Error('deling.js requires a newish browser.');
  }

  // Assign a global for updates.
  window.deling = deling;

})(window, document);
<commit_msg>Use decription param for pinterest.<commit_after>/**
 * deling.js is a simple share plugin with minimal fuzz.
 */

(function (window, document) {
  'use strict';

  var supportedNetworks = {
    'facebook': {
      url: 'https://www.facebook.com/share.php?u={{url}}',
      title: 'Facebook',
    },
    'twitter': {
      url: 'https://twitter.com/intent/tweet?url={{url}}&text={{title}}',
      title: 'Twitter',
    },
    'pinterest': {
      url: 'https://pinterest.com/pin/create/button/?url={{url}}&media={{media}}&description={{title}}',
      title: 'Pinterest',
      icon: 'pinterest-p',
    },
    'linkedin': {
      url: 'https://www.linkedin.com/shareArticle?mini=true&url={{url}}&title={{title}}&summary={{summary}}',
      title: 'LinkedIn',
    },
    'google-plus': {
      url: 'https://plus.google.com/share?url={{url}}',
      title: 'Google Plus',
    },
    'reddit': {
      url: 'https://www.reddit.com/submit?url={{url}}',
      title: 'reddit',
    },
    'tumblr':   {
      url: 'https://www.tumblr.com/share?v=3&u={{url}}&t={{title}}&content={{summary}}',
      title: 'tumblr',
    },
    'mail': {
      url: 'mailto:?subject=&body={{url}}',
      title: 'Mail',
      icon: 'envelope',
    },
  };

  function replacer (str, pairs) {
    str = str.toString();

    if (!pairs) {
      return str;
    }

    Object.keys(pairs).forEach(function (key) {
      var value = pairs[key];

      str = str.replace(new RegExp(key, 'g'), value);
    });

    return encodeURI(str);
  }

  function trim (str) {
    return str.trim();
  }

  function lowerCase (str) {
    return str.toLowerCase();
  }

  function getSettingsForElement (element) {
    // Defaults.
    var settings = {
      url: window.location.href,
      title: '',
      image: '',
      summary: '',
      networks: [],
      icons: true,
      names: false,
      popup: true,
      iconClass: 'deling-icon-',
    };

    for (var i = 0, j = element.attributes.length; i < j; i++) {
      var name = element.attributes[i].name;

      switch (name) {
        case 'data-networks':
          var attributeNetworks = element.attributes[i].value.split(',').map(trim).map(lowerCase);

          // Add only supported networks.
          for (var k = 0, l = attributeNetworks.length; k < l; k++) {
            if (supportedNetworks[attributeNetworks[k]]) {
              settings.networks.push(attributeNetworks[k]);
            }
          }

          break;
        case 'data-url':
          settings.url = element.attributes[i].value;
          break;

        case 'data-icons':
          settings.icons = element.attributes[i].value === 'true';
          break;

        case 'data-names':
          settings.names = element.attributes[i].value === 'true';
          break;

        case 'data-popup':
          settings.popup = element.attributes[i].value === 'true';
          break;

        case 'data-icon-class':
          settings.iconClass = element.attributes[i].value;
          break;

        case 'data-title':
          settings.title = element.attributes[i].value;
          break;

        case 'data-media':
          settings.media = element.attributes[i].value;
          break;

        case 'data-summary':
          settings.summary = element.attributes[i].value;
          break;
      }
    }

    if (!settings.networks.length) {
      Object.keys(supportedNetworks).forEach(function (n) {
        settings.networks.push(n);
      });
    }

    return settings;
  }

  function insertShareInElement (element, settings) {
    settings.networks.forEach(function (n) {
      var anchor = document.createElement('a'),
          network = supportedNetworks[n];

      anchor.setAttribute('class', 'deling-button network-' + n);
      anchor.setAttribute('href', replacer(network.url, {
        '{{url}}': settings.url,
        '{{title}}': settings.title,
        '{{media}}': settings.media,
        '{{summary}}': settings.summary,
      }));
      anchor.setAttribute('title', network.title);

      if (settings.popup) {
        anchor.setAttribute('target', '_blank');
      }

      if (settings.icons) {
        var icon = document.createElement('i');

        icon.setAttribute('class', 'deling-icon ' + settings.iconClass + (network.icon || n));

        anchor.appendChild(icon);
      }

      if (settings.names) {
        var name = document.createTextNode(network.title);

        anchor.appendChild(name);
      }

      element.appendChild(anchor);
    });
  }

  function addShareToElement (element) {
    insertShareInElement(element, getSettingsForElement(element));
  }

  function findAndPrepareElements (element, className) {
    var elements = element.getElementsByClassName(className);

    for (var i = 0, j = elements.length; i < j; i++) {
      addShareToElement(elements[i]);
    }
  }

  function deling (element, className) {
    className = className || 'deling';

    if (!element) {
      throw new Error('simpleShare requires an element.');
    }

    findAndPrepareElements(element, className);
  }

  if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', function () {
      deling(document);
    });
  } else {
    throw new Error('deling.js requires a newish browser.');
  }

  // Assign a global for updates.
  window.deling = deling;

})(window, document);
<|endoftext|>


<commit_before>// September 2012, Franziska Hinkelmann, Mike Stillman, and Lars Kastner
//
// This is server-side JavaScript, intended to be run with Node.js.
// This file defines a Node.js server for serving 'tryM2'.
//   run
//      node m2server.js
// in a terminal in this directory.
// Then in a browser, use:
//      http://localhost:8000/
// Required Node.js libraries: cookies.  Install via:
//   npm install cookies, or sudo npm install -g cookies
// Required on path: M2
// We are using our own open script to make Graphs.m2 work (generate jpegs for users), please include the current directory in your path:
// export PATH=.:$PATH

// intended to run on (s)chrooted environment, where every user starts M2 in a separate schroot.
//
// A message on / : possibly creates a cookie, and serves back index.html
//   and related js/css/png files
// A POST message on /chat: input should be Macaulay2 commands to perform.
// A message on /chat: start an event emitter, which will return the output of
// the M2 process.

var port = 8002;
var sandboxDir = "/";

var http = require('http')
    , connect = require('connect')
    , Cookies = require('cookies');

var SCHROOT = false; // start with --schroot on server

// The HTML file for the chat client. Used below.
//var clientui = require('fs').readFileSync("index.html");
var totalUsers = 0;

// An array of Client objects.  Each has an M2 process, and a response object
// It is possible that this.m2 is not defined, and/or that this.eventStream is not
// defined.
var clients = {};

function Client(m2process, resp) {
    this.m2 = m2process;
    this.eventStream = resp;
    this.clientID = null;
}

startUser = function(cookies) {
    totalUsers = totalUsers + 1;
    var clientID = Math.random()*1000000;
    clientID = Math.floor(clientID);
    clientID = "user" + clientID.toString(10);
    cookies.set( "tryM2", clientID, { httpOnly: false } );
    clients[clientID] = new Client();
    clients[clientID].clientID = clientID;
    return clientID;
}

initializeRunningM2 = function(m2, clientID) {
    m2.stdout.setEncoding("utf8");
    m2.stderr.setEncoding("utf8");
    //console.log('Spawned m2 pid: ' + m2.pid);
    //    m2.on('exit', function(code, signal) {
    //	m2.running = false;
    //	console.log("M2 exited");
    //      });
    clients[clientID].m2 = m2;
};

m2Start = function(clientID, callbackFcn) {
    var spawn = require('child_process').spawn;
    if (SCHROOT) {
        console.log("Spawning new schroot process named " + clientID + ".");
        var e = require('child_process').exec('schroot -c clone -n '+ clientID + ' -b', function() {
            console.log("PID of exec that begins a schroot: " + e.pid);
            var filename = "/var/lib/schroot/mount/" + clientID + "/home/franzi/sName.txt";
             // TODO copy some files
            // create a file inside schroot directory to allow schroot know its own name
            require('fs').writeFile(filename, clientID, function(err) {
                if(err) {
                    console.log("failing to write the file " + filename);
                    console.log(err);
                } else {
                    console.log("wrote schroot's name into " + filename);
                }
            });

            var m2 = spawn('schroot', ['-c', clientID, '-u', 'franzi', '-d', '/home/franzi/', '-r', '/M2/bin/M2']);
            console.log("PID of spawn: " + m2.pid);
	        callbackFcn(m2, clientID);
        });
    } else {
        console.log("Spawning new M2 process...");
        m2 = spawn('M2');
	    callbackFcn(m2, clientID);
    }
}

m2ConnectStream = function(clientID) {
     var client = clients[clientID];
     var ondata = function(data) {
         console.log('ondata: ' + data);
         message = 'data: ' + data.replace(/\n/g, '\ndata: ') + "\r\n\r\n";
         if (!client.eventStream) { // fatal error, should not happen
             console.log("Error: No event stream in Start M2");
             throw "Error: No client.eventStream in Start M2";
         }
         client.eventStream.write(message);
     };
     console.log("Bind stdout to client's m2");
     client.m2.stdout.removeAllListeners('data');
     client.m2.stderr.removeAllListeners('data');
     client.m2.stdout.on('data', ondata);
     client.m2.stderr.on('data', ondata);
};

m2AssureRunning = function(clientID, callbackFcn) {
    // clientID: name of the desired client
    // callbackFcn: function(clientID) {} which is to be called once
    //   we are assured that M2 is running.
    // Caveat: It is possible to kill m2 after being being assured that it is
    //   there, so there is a possibility for a problem here.  We need to consider that? TODO

    var client = clients[clientID];
    if (!client.m2) {
        m2Start(clientID, function(m2) {
	        initializeRunningM2(m2, clientID);
	        m2ConnectStream(clientID);
	        callbackFcn(clientID);
	    });
    } else {
        callbackFcn(clientID);
    }
};

getCurrentClientID = function(request, response) {
    var cookies = new Cookies(request, response);
    var clientID = cookies.get("tryM2");
    //console.log("Client has cookie value: " + clientID);

    // Start new user for users coming with invalid, i.e., old, cookie
    if (!clients[clientID]) {
        console.log("startUser");
        clientID = startUser(cookies);
    }
    return clientID;
};

var stats = function(request, response, next) {
    // to do: authorization
     response.writeHead(200, {"Content-Type": "text/html"});
     var currentUsers = 0;
     for( var c in clients) {
         if(clients.hasOwnProperty(c))
            currentUsers = currentUsers + 1;
     }
     response.write('<link rel="stylesheet" href="m2.css" type="text/css" media="screen">' );
     response.write('
Macaulay2 User Statistics
');
     response.write("There are currently " + currentUsers + " users using M2.
" );
     response.write("In total, there were " + totalUsers + " users since the server started.
");
     response.write("Enjoy M2!");
     response.end();
}

// Send a comment to the clients every 20 seconds so they don't
// close the connection and then reconnect
setInterval(function() {
    for (var prop in clients) {
        if (clients.hasOwnProperty(prop)
            && clients[prop]
            && clients[prop].eventStream) {
            clients[prop].eventStream.write(":ping\n");
        }
    }
}, 20000);

// Client starts eventStream to obtain M2 output and start M2
startSource = function( request, response) {
    var clientID = getCurrentClientID(request, response);
    response.writeHead(200, {'Content-Type': "text/event-stream" });
    if (!clients[clientID].eventStream) {
        clients[clientID].eventStream = response;
	m2AssureRunning(clientID, m2ConnectStream);
    }

    // If the client closes the connection, remove client from the list of active clients
    request.connection.on("end", function() {
        console.log("close connection: clients[" + clientID + "]");
        clients[clientID].eventStream = null;
        response.end();
    });
};

chatAction = function( request, response) {
    var clientID = getCurrentClientID(request, response);
    if (!checkForEventStream(clientID, response)) {return false};
    request.setEncoding("utf8");
    var body = "";
    // When we get a chunk of data, add it to the body
    request.on("data", function(chunk) { body += chunk; });

    // Send input to M2 when we have received the complete body
    request.on("end", function() {
	m2ProcessInput(clientID, body, response);
      });
};

m2ProcessInput = function( clientID, body, response ) {
    // this starts m2 if needed, and when it is done, calls callback
    console.log("entered m2ProcessInput");
    m2AssureRunning(clientID, function() {
	try {
	  console.log("M2 input: " + body);
	  clients[clientID].m2.stdin.write(body);
	}
	catch (err) {
	    console.log(err);
	    console.log("Internal error: nothing to write to?!");
	    throw ("Internal error: nothing to write to?!");
	    return;
	}
	response.writeHead(200);
	response.end();
    });
};

restartAction = function(request, response) {
    var clientID = getCurrentClientID(request, response);
    if (!checkForEventStream(clientID, response)) {return false};
    var client = clients[clientID];
    console.log("received: /restart from " + clientID);
    if (client.m2) {
        client.m2.kill();
        console.log("In restartAction, killed child process with PID " + client.m2.pid);
        if (SCHROOT) {
            require('child_process').spawn('schroot', ['-c', clientID, '-e']); // this unmounts the schroot
        }
        client.m2 = null;
    }
    m2Start(clientID, function(m2, clientID) {
	initializeRunningM2(m2, clientID);
	m2ConnectStream(clientID);
      });
    response.writeHead(200);
    response.end();
};

interruptAction = function(request, response)  {
    var clientID = getCurrentClientID(request, response);
    if (!checkForEventStream(clientID, response)) {return false};
    console.log("received: /interrupt from " + clientID);
    if (clients[clientID] && clients[clientID].m2) {
        clients[clientID].m2.kill('SIGINT');
    }
    response.writeHead(200);
    response.end();
};

// returning clientID for a given M2 pid
// This currently does not work when working inside a schroot, because pid is not the schroot's pid
findClientID = function(pid){
    //var pid1 = parseInt(pid,10);
    console.log("Searching for clientID whose M2 has PID " + pid);
    for (var prop in clients) {
        if (clients.hasOwnProperty(prop) && clients[prop] && clients[prop].m2) {
            if (pid == clients[prop].m2.pid) {
                console.log("We found the client! It is " + prop);
                if (clients[prop].eventStream) {
                    console.log("findClientID picked user with clientID " + prop);
                    return prop;
                } else {
                    throw ("Client " + clientID + " does not have an eventstream.");
                }
            }
        }
    }
    throw ("Did not find a client for PID " + pid);
}

// return PID extracted from pathname for image displaying
parseUrlForPid = function(url) {
    console.log(url);
    if (SCHROOT) {
        var pid = url.match(/^\/(user\d+)\//);
    } else {
        pid = url.match(/\/M2-(\d+)-/);
    }
    //console.log( pid );
    if (!pid) {
        console.log("error, didn't get PID in image url");
        throw ("Did not get PID in image url");
    }
    console.log("PID = " + pid[1]);
    return pid[1];
    //return parseInt(pid[1],10);
}

// return path to image
parseUrlForPath = function(url) {
    var imagePath = url.match(/^\/(user)?\d+\/(.*)/);
    console.log(imagePath);

    if (!imagePath) {
        throw("Did not get imagePath in image url");
    }
    console.log("imagePath = " + imagePath[2]);
    return imagePath[2];
}

// we get a /image from our open script
// imageAction finds the matching client by parsing the url, then sends the address of the image to the client's eventStream
imageAction = function(request, response, next) {
    var url = require('url').parse(request.url).pathname;
    response.writeHead(200);
    response.end();

    try {
        var pid = parseUrlForPid(url);
        var path = parseUrlForPath(url); // a string
        if (SCHROOT) {
            var clientID = pid;
        } else {
            clientID = findClientID(pid);
        }

        console.log("ClientID = " + clientID);

        client = clients[clientID];
          if (!client) {
              console.log("oops, no client");
              return;
          }

          if (SCHROOT) {
              path = "/var/lib/schroot/mount/" + clientID + path
          }
          console.log('we got a request for an image: ' + path + ", for clientID " + clientID);
          // parse request for PID and path to image

          message = 'event: image\r\ndata: ' + path + "\r\n\r\n";
          if (!client.eventStream) { // fatal error, should not happen
              console.log("Error: No event stream in Start M2");
          }
          else {
              console.log("Sent image message: " + message);
              client.eventStream.write(message);
          }
    }
    catch (err) {
        console.log("Received invalid /image request: " + err);
    }

};

function checkForEventStream(clientID, response) {
    if (!clients[clientID].eventStream ) {
      console.log("Send notEventSourceError back to user.");
      response.writeHead(200, {'notEventSourceError': 'No socket for client...' });
      response.end();
      return false;
   }
   return true;
}

function unhandled(request, response, next) {
    var url = require('url').parse(request.url).pathname;
    if (url == '/chat' || url == 'interrupt' || url == '/restart') {
        next();
        return;
    }
    console.log("User requested something we don't serve");
    console.log(request.url);
}

// when run in production, work with schroots, see startM2Process()
if( process.argv[2] && process.argv[2]=='--schroot') {
    console.log('Running with schroots.');
    SCHROOT=true;
}

var app = connect()
    .use(connect.logger('dev'))
    .use(connect.favicon())
    .use(connect.static('public'))
    .use('/var', connect.static('/var')) // M2 creates temporary files (like created by Graphs.m2) here on MacOS
    .use('/tmp', connect.static('/tmp')) // and here on Ubuntu
    .use('/admin', stats)
    .use('/image', imageAction)
    .use('/startSourceEvent', startSource)
    .use('/chat', chatAction)
    .use('/interrupt', interruptAction)
    .use('/restart', restartAction)
    .use(unhandled)
    ;
    //.use(connect.errorHandler());
console.log("Listening on port " + port + "...");
http.createServer(app).listen(port);

<commit_msg>make parseURL for image work in schroot<commit_after>// September 2012, Franziska Hinkelmann, Mike Stillman, and Lars Kastner
//
// This is server-side JavaScript, intended to be run with Node.js.
// This file defines a Node.js server for serving 'tryM2'.
//   run
//      node m2server.js
// in a terminal in this directory.
// Then in a browser, use:
//      http://localhost:8000/
// Required Node.js libraries: cookies.  Install via:
//   npm install cookies, or sudo npm install -g cookies
// Required on path: M2
// We are using our own open script to make Graphs.m2 work (generate jpegs for users), please include the current directory in your path:
// export PATH=.:$PATH

// intended to run on (s)chrooted environment, where every user starts M2 in a separate schroot.
//
// A message on / : possibly creates a cookie, and serves back index.html
//   and related js/css/png files
// A POST message on /chat: input should be Macaulay2 commands to perform.
// A message on /chat: start an event emitter, which will return the output of
// the M2 process.

var port = 8002;
var sandboxDir = "/";

var http = require('http')
    , connect = require('connect')
    , Cookies = require('cookies');

var SCHROOT = false; // start with --schroot on server

// The HTML file for the chat client. Used below.
//var clientui = require('fs').readFileSync("index.html");
var totalUsers = 0;

// An array of Client objects.  Each has an M2 process, and a response object
// It is possible that this.m2 is not defined, and/or that this.eventStream is not
// defined.
var clients = {};

function Client(m2process, resp) {
    this.m2 = m2process;
    this.eventStream = resp;
    this.clientID = null;
}

startUser = function(cookies) {
    totalUsers = totalUsers + 1;
    var clientID = Math.random()*1000000;
    clientID = Math.floor(clientID);
    clientID = "user" + clientID.toString(10);
    cookies.set( "tryM2", clientID, { httpOnly: false } );
    clients[clientID] = new Client();
    clients[clientID].clientID = clientID;
    return clientID;
}

initializeRunningM2 = function(m2, clientID) {
    m2.stdout.setEncoding("utf8");
    m2.stderr.setEncoding("utf8");
    //console.log('Spawned m2 pid: ' + m2.pid);
    //    m2.on('exit', function(code, signal) {
    //	m2.running = false;
    //	console.log("M2 exited");
    //      });
    clients[clientID].m2 = m2;
};

m2Start = function(clientID, callbackFcn) {
    var spawn = require('child_process').spawn;
    if (SCHROOT) {
        console.log("Spawning new schroot process named " + clientID + ".");
        var e = require('child_process').exec('schroot -c clone -n '+ clientID + ' -b', function() {
            console.log("PID of exec that begins a schroot: " + e.pid);
            var filename = "/var/lib/schroot/mount/" + clientID + "/home/franzi/sName.txt";
             // TODO copy some files
            // create a file inside schroot directory to allow schroot know its own name
            require('fs').writeFile(filename, clientID, function(err) {
                if(err) {
                    console.log("failing to write the file " + filename);
                    console.log(err);
                } else {
                    console.log("wrote schroot's name into " + filename);
                }
            });

            var m2 = spawn('schroot', ['-c', clientID, '-u', 'franzi', '-d', '/home/franzi/', '-r', '/M2/bin/M2']);
            console.log("PID of schroot: " + m2.pid);
            var ps = spawn('ps', ['--ppid', m2.pid, '-o', 'pid=']);
            ps.stdout.on('data', function (data) {
              console.log('M2 pid should be: ' + data);
              var m2Pid = data;
            });
	        callbackFcn(m2, clientID);
        });
    } else {
        console.log("Spawning new M2 process...");
        m2 = spawn('M2');
	    callbackFcn(m2, clientID);
    }
}

m2ConnectStream = function(clientID) {
     var client = clients[clientID];
     var ondata = function(data) {
         console.log('ondata: ' + data);
         message = 'data: ' + data.replace(/\n/g, '\ndata: ') + "\r\n\r\n";
         if (!client.eventStream) { // fatal error, should not happen
             console.log("Error: No event stream in Start M2");
             throw "Error: No client.eventStream in Start M2";
         }
         client.eventStream.write(message);
     };
     console.log("Bind stdout to client's m2");
     client.m2.stdout.removeAllListeners('data');
     client.m2.stderr.removeAllListeners('data');
     client.m2.stdout.on('data', ondata);
     client.m2.stderr.on('data', ondata);
};

m2AssureRunning = function(clientID, callbackFcn) {
    // clientID: name of the desired client
    // callbackFcn: function(clientID) {} which is to be called once
    //   we are assured that M2 is running.
    // Caveat: It is possible to kill m2 after being being assured that it is
    //   there, so there is a possibility for a problem here.  We need to consider that? TODO

    var client = clients[clientID];
    if (!client.m2) {
        m2Start(clientID, function(m2) {
	        initializeRunningM2(m2, clientID);
	        m2ConnectStream(clientID);
	        callbackFcn(clientID);
	    });
    } else {
        callbackFcn(clientID);
    }
};

getCurrentClientID = function(request, response) {
    var cookies = new Cookies(request, response);
    var clientID = cookies.get("tryM2");
    //console.log("Client has cookie value: " + clientID);

    // Start new user for users coming with invalid, i.e., old, cookie
    if (!clients[clientID]) {
        console.log("startUser");
        clientID = startUser(cookies);
    }
    return clientID;
};

var stats = function(request, response, next) {
    // to do: authorization
     response.writeHead(200, {"Content-Type": "text/html"});
     var currentUsers = 0;
     for( var c in clients) {
         if(clients.hasOwnProperty(c))
            currentUsers = currentUsers + 1;
     }
     response.write('<link rel="stylesheet" href="m2.css" type="text/css" media="screen">' );
     response.write('
Macaulay2 User Statistics
');
     response.write("There are currently " + currentUsers + " users using M2.
" );
     response.write("In total, there were " + totalUsers + " users since the server started.
");
     response.write("Enjoy M2!");
     response.end();
}

// Send a comment to the clients every 20 seconds so they don't
// close the connection and then reconnect
setInterval(function() {
    for (var prop in clients) {
        if (clients.hasOwnProperty(prop)
            && clients[prop]
            && clients[prop].eventStream) {
            clients[prop].eventStream.write(":ping\n");
        }
    }
}, 20000);

// Client starts eventStream to obtain M2 output and start M2
startSource = function( request, response) {
    var clientID = getCurrentClientID(request, response);
    response.writeHead(200, {'Content-Type': "text/event-stream" });
    if (!clients[clientID].eventStream) {
        clients[clientID].eventStream = response;
	m2AssureRunning(clientID, m2ConnectStream);
    }

    // If the client closes the connection, remove client from the list of active clients
    request.connection.on("end", function() {
        console.log("close connection: clients[" + clientID + "]");
        clients[clientID].eventStream = null;
        response.end();
    });
};

chatAction = function( request, response) {
    var clientID = getCurrentClientID(request, response);
    if (!checkForEventStream(clientID, response)) {return false};
    request.setEncoding("utf8");
    var body = "";
    // When we get a chunk of data, add it to the body
    request.on("data", function(chunk) { body += chunk; });

    // Send input to M2 when we have received the complete body
    request.on("end", function() {
	m2ProcessInput(clientID, body, response);
      });
};

m2ProcessInput = function( clientID, body, response ) {
    // this starts m2 if needed, and when it is done, calls callback
    console.log("entered m2ProcessInput");
    m2AssureRunning(clientID, function() {
	try {
	  console.log("M2 input: " + body);
	  clients[clientID].m2.stdin.write(body);
	}
	catch (err) {
	    console.log(err);
	    console.log("Internal error: nothing to write to?!");
	    throw ("Internal error: nothing to write to?!");
	    return;
	}
	response.writeHead(200);
	response.end();
    });
};

restartAction = function(request, response) {
    var clientID = getCurrentClientID(request, response);
    if (!checkForEventStream(clientID, response)) {return false};
    var client = clients[clientID];
    console.log("received: /restart from " + clientID);
    if (client.m2) {
        client.m2.kill();
        console.log("In restartAction, killed child process with PID " + client.m2.pid);
        if (SCHROOT) {
            require('child_process').spawn('schroot', ['-c', clientID, '-e']); // this unmounts the schroot
        }
        client.m2 = null;
    }
    m2Start(clientID, function(m2, clientID) {
	initializeRunningM2(m2, clientID);
	m2ConnectStream(clientID);
      });
    response.writeHead(200);
    response.end();
};

interruptAction = function(request, response)  {
    var clientID = getCurrentClientID(request, response);
    if (!checkForEventStream(clientID, response)) {return false};
    console.log("received: /interrupt from " + clientID);
    if (clients[clientID] && clients[clientID].m2) {
        clients[clientID].m2.kill('SIGINT');
    }
    response.writeHead(200);
    response.end();
};

// returning clientID for a given M2 pid
// This currently does not work when working inside a schroot, because pid is not the schroot's pid
findClientID = function(pid){
    //var pid1 = parseInt(pid,10);
    console.log("Searching for clientID whose M2 has PID " + pid);
    for (var prop in clients) {
        if (clients.hasOwnProperty(prop) && clients[prop] && clients[prop].m2) {
            if (pid == clients[prop].m2.pid) {
                console.log("We found the client! It is " + prop);
                if (clients[prop].eventStream) {
                    console.log("findClientID picked user with clientID " + prop);
                    return prop;
                } else {
                    throw ("Client " + clientID + " does not have an eventstream.");
                }
            }
        }
    }
    throw ("Did not find a client for PID " + pid);
}

// return PID extracted from pathname for image displaying
parseUrlForPid = function(url) {
    console.log(url);
    if (SCHROOT) {
        var pid = url.match(/^\/(user\d+)\//);
    } else {
        pid = url.match(/\/M2-(\d+)-/);
    }
    //console.log( pid );
    if (!pid) {
        console.log("error, didn't get PID in image url");
        throw ("Did not get PID in image url");
    }
    console.log("PID = " + pid[1]);
    return pid[1];
    //return parseInt(pid[1],10);
}

// return path to image
parseUrlForPath = function(url) {
    var imagePath = url.match(/^\/(user)?\d+\/(.*)/);
    console.log(imagePath);

    if (!imagePath) {
        throw("Did not get imagePath in image url");
    }
    console.log("imagePath = " + imagePath[2]);
    return imagePath[2];
}

// we get a /image from our open script
// imageAction finds the matching client by parsing the url, then sends the address of the image to the client's eventStream
imageAction = function(request, response, next) {
    var url = require('url').parse(request.url).pathname;
    response.writeHead(200);
    response.end();

    try {
        var pid = parseUrlForPid(url);
        var path = parseUrlForPath(url); // a string
        if (SCHROOT) {
            var clientID = pid;
        } else {
            clientID = findClientID(pid);
        }

        console.log("ClientID = " + clientID);

        client = clients[clientID];
          if (!client) {
              console.log("oops, no client");
              return;
          }

          if (SCHROOT) {
              path = "/var/lib/schroot/mount/" + clientID + path
          }
          console.log('we got a request for an image: ' + path + ", for clientID " + clientID);
          // parse request for PID and path to image

          message = 'event: image\r\ndata: ' + path + "\r\n\r\n";
          if (!client.eventStream) { // fatal error, should not happen
              console.log("Error: No event stream in Start M2");
          }
          else {
              console.log("Sent image message: " + message);
              client.eventStream.write(message);
          }
    }
    catch (err) {
        console.log("Received invalid /image request: " + err);
    }

};

function checkForEventStream(clientID, response) {
    if (!clients[clientID].eventStream ) {
      console.log("Send notEventSourceError back to user.");
      response.writeHead(200, {'notEventSourceError': 'No socket for client...' });
      response.end();
      return false;
   }
   return true;
}

function unhandled(request, response, next) {
    var url = require('url').parse(request.url).pathname;
    if (url == '/chat' || url == 'interrupt' || url == '/restart') {
        next();
        return;
    }
    console.log("User requested something we don't serve");
    console.log(request.url);
}

// when run in production, work with schroots, see startM2Process()
if( process.argv[2] && process.argv[2]=='--schroot') {
    console.log('Running with schroots.');
    SCHROOT=true;
}

var app = connect()
    .use(connect.logger('dev'))
    .use(connect.favicon())
    .use(connect.static('public'))
    .use('/var', connect.static('/var')) // M2 creates temporary files (like created by Graphs.m2) here on MacOS
    .use('/tmp', connect.static('/tmp')) // and here on Ubuntu
    .use('/admin', stats)
    .use('/image', imageAction)
    .use('/startSourceEvent', startSource)
    .use('/chat', chatAction)
    .use('/interrupt', interruptAction)
    .use('/restart', restartAction)
    .use(unhandled)
    ;
    //.use(connect.errorHandler());
console.log("Listening on port " + port + "...");
http.createServer(app).listen(port);

<|endoftext|>


<commit_before>// ==UserScript==
// @name        Tiny-Customize
// @description 为常用网站添加功能定制。例如：3DMGame、贴吧、淘宝、京东、GitHub...
// @homepageURL https://github.com/nonoroazoro/firefox/tree/master/greasemonkey/tiny-customize
// @namespace   https://greasyfork.org/zh-CN/scripts/19823-tiny-customize
// @author      nonoroazoro
// @include     /^https?:\/\/(.+\.)?github\./
// @include     http://bbs.3dmgame.com/*
// @include     http://bbs.kafan.cn/*
// @include     http://forum.gamer.com.tw/*
// @include     http://poedb.tw/dps*
// @include     http://tieba.baidu.com/*
// @include     https://forum.gamer.com.tw/*
// @include     https://login.taobao.com/*
// @include     https://passport.jd.com/*
// @include     https://www.chiphell.com/*
// @version     1.2.7
// @grant       none
// ==/UserScript==

const host = window.location.host;
const href = window.location.href;

/**
 * 获取立即执行的操作。
 */
const getInstantActions = () =>
{
    const actions = [];

    if (host === "forum.gamer.com.tw")
    {
        // 巴哈姆特。

        // 反反广告检测。
        actions.push(() =>
        {
            if (window.AntiAd)
            {
                window.AntiAd.check = _noop;
                window.AntiAd.block = _noop;
                window.AntiAd.verifyLink = () => false;
            }
        });
    }
    else if (
        host === "bbs.kafan.cn" ||
        host === "bbs.3dmgame.com" ||
        host === "www.chiphell.com"
    )
    {
        // 卡饭、3DMGame、Chiphell 论坛（Discuz 驱动的论坛）。

        // 屏蔽方向键翻页。
        actions.push(() =>
        {
            if (window.keyPageScroll)
            {
                window.keyPageScroll = _noop;
            }
        });
    }
    else if (/^https?:\/\/poedb\.tw(\/?.*)\/dps/.test(href))
    {
        // 流亡编年史。

        // 屏蔽默认自动全选物品信息、自动查询物品信息。
        actions.push(() =>
        {
            const elem = document.querySelector(`#iteminfo`);
            const form = document.querySelector(`form[action^="dps"]`);
            elem.addEventListener("click", e => e.stopPropagation(), true);
            elem.addEventListener("keydown", (e) =>
            {
                if (e.key === "Enter")
                {
                    form.submit();
                    e.preventDefault();
                }
            });

            elem.addEventListener("paste", (e) =>
            {
                setTimeout(() => form.submit(), 0);
            });
        });
    }
    else if (host === "login.taobao.com")
    {
        // 淘宝。

        // 默认显示密码登录（而非 QR 码登录）界面。
        actions.push(() =>
        {
            // 始终显示密码登录。
            let elems = document.querySelectorAll(`.static-form, .iconfont.static`);
            elems.forEach(e => e.setAttribute("style", "display: block !important"));

            // 删除扫码登录。
            elems = document.querySelectorAll(`.login-switch, .login-tip, .iconfont.quick, .quick-form`);
            elems.forEach(e => e.remove());
        });
    }
    else if (host === "passport.jd.com")
    {
        // 京东。

        // 默认显示密码登录（而非 QR 码登录）界面。
        actions.push(() =>
        {
            // 删除扫码登录。
            let elems = document.querySelectorAll(`.login-tab, .login-box > .mt.tab-h, .qrcode-login, #qrCoagent`);
            elems.forEach(e => e.remove());

            // 始终显示密码登录。
            elems = document.querySelectorAll(`.login-box, #entry`);
            elems.forEach(e => e.setAttribute("style", "display: block !important; visibility: visible !important;"));
        });
    }
    else if (/^(.+\.)?github\./.test(host))
    {
        // GitHub。

        // 禁用快捷键: "s"，"w"。
        _disableKeydown("s w");
    }

    return actions;
};

/**
 * 获取延迟执行的操作。
 */
const getLazyActions = () =>
{
    const actions = [];

    if (host === "forum.gamer.com.tw")
    {
        // 巴哈姆特。

        // 自动开启图片。
        actions.push(() =>
        {
            if (window.forumShowAllMedia)
            {
                window.forumShowAllMedia();
            }
        });
    }
    else if (host === "tieba.baidu.com")
    {
        // 贴吧。

        // 删除广告贴。
        actions.push(() =>
        {
            let spans;
            const elems = document.querySelectorAll(`#j_p_postlist > div`);
            elems.forEach((e) =>
            {
                spans = e.querySelectorAll(`.core_reply_tail span`);
                for (const s of spans)
                {
                    if (s.innerText.trim() === "商业推广")
                    {
                        e.remove();
                        break;
                    }
                }
            });
        });
    }

    return actions;
};

/**
 * 立即执行指定的操作。
 */
const exec = (p_actions) =>
{
    p_actions.forEach(p_action => p_action());
};

// 1. 立即执行。
exec(getInstantActions());

// 2. 延迟执行。
window.addEventListener("load", () => exec(getLazyActions()), true);

function _noop() { }

/**
 * 禁止键盘快捷键（单键）。
 */
function _disableKeydown(p_keys)
{
    if (typeof p_keys === "string")
    {
        const keys = p_keys.split(/\W+/);
        document.addEventListener("keydown", (e) =>
        {
            if (keys.indexOf(e.key.toLowerCase()) !== -1)
            {
                e.stopPropagation();
            }
        }, true);
    }
}
<commit_msg>disable xiami QR login<commit_after>// ==UserScript==
// @name        Tiny-Customize
// @description 为常用网站添加功能定制。例如：3DMGame、贴吧、淘宝、京东、GitHub...
// @homepageURL https://github.com/nonoroazoro/firefox/tree/master/greasemonkey/tiny-customize
// @namespace   https://greasyfork.org/zh-CN/scripts/19823-tiny-customize
// @author      nonoroazoro
// @include     /^https?:\/\/(.+\.)?github\./
// @include     http://bbs.3dmgame.com/*
// @include     http://bbs.kafan.cn/*
// @include     http://forum.gamer.com.tw/*
// @include     http://poedb.tw/dps*
// @include     http://tieba.baidu.com/*
// @include     https://forum.gamer.com.tw/*
// @include     https://login.taobao.com/*
// @include     https://login.xiami.com/*
// @include     https://passport.jd.com/*
// @include     https://www.chiphell.com/*
// @version     1.2.8
// @grant       none
// ==/UserScript==

const host = window.location.host;
const href = window.location.href;

/**
 * 获取立即执行的操作。
 */
const getInstantActions = () =>
{
    const actions = [];

    if (host === "forum.gamer.com.tw")
    {
        // 巴哈姆特。

        // 反反广告检测。
        actions.push(() =>
        {
            if (window.AntiAd)
            {
                window.AntiAd.check = _noop;
                window.AntiAd.block = _noop;
                window.AntiAd.verifyLink = () => false;
            }
        });
    }
    else if (
        host === "bbs.kafan.cn" ||
        host === "bbs.3dmgame.com" ||
        host === "www.chiphell.com"
    )
    {
        // 卡饭、3DMGame、Chiphell 论坛（Discuz 驱动的论坛）。

        // 屏蔽方向键翻页。
        actions.push(() =>
        {
            if (window.keyPageScroll)
            {
                window.keyPageScroll = _noop;
            }
        });
    }
    else if (/^https?:\/\/poedb\.tw(\/?.*)\/dps/.test(href))
    {
        // 流亡编年史。

        // 屏蔽默认自动全选物品信息、自动查询物品信息。
        actions.push(() =>
        {
            const elem = document.querySelector(`#iteminfo`);
            const form = document.querySelector(`form[action^="dps"]`);
            elem.addEventListener("click", e => e.stopPropagation(), true);
            elem.addEventListener("keydown", (e) =>
            {
                if (e.key === "Enter")
                {
                    form.submit();
                    e.preventDefault();
                }
            });

            elem.addEventListener("paste", (e) =>
            {
                setTimeout(() => form.submit(), 0);
            });
        });
    }
    else if (host === "login.taobao.com")
    {
        // 淘宝。

        // 默认显示密码登录（而非 QR 码登录）界面。
        actions.push(() =>
        {
            _disableQRLogin(
                ".login-switch, .login-tip, .iconfont.quick, .quick-form",
                ".static-form, .iconfont.static",
                `input[name="TPL_username"]`
            );
        });
    }
    else if (host === "passport.jd.com")
    {
        // 京东。

        // 默认显示密码登录（而非 QR 码登录）界面。
        actions.push(() =>
        {
            _disableQRLogin(
                ".login-tab, .login-box > .mt.tab-h, .qrcode-login, #qrCoagent",
                ".login-box, #entry",
                `input[name="loginname"]`
            );
        });
    }
    else if (host === "login.xiami.com")
    {
        // 虾米。

        // 默认显示密码登录（而非 QR 码登录）界面。
        actions.push(() =>
        {
            _disableQRLogin(
                ".login-switch, .login-qrcode, .qrcode-tips",
                ".login-xm",
                `input[name="account"]`
            );
        });
    }
    else if (/^(.+\.)?github\./.test(host))
    {
        // GitHub。

        // 禁用快捷键: "s"，"w"。
        _disableKeydown("s w");
    }

    return actions;
};

/**
 * 获取延迟执行的操作。
 */
const getLazyActions = () =>
{
    const actions = [];

    if (host === "forum.gamer.com.tw")
    {
        // 巴哈姆特。

        // 自动开启图片。
        actions.push(() =>
        {
            if (window.forumShowAllMedia)
            {
                window.forumShowAllMedia();
            }
        });
    }
    else if (host === "tieba.baidu.com")
    {
        // 贴吧。

        // 删除广告贴。
        actions.push(() =>
        {
            let spans;
            const elems = document.querySelectorAll(`#j_p_postlist > div`);
            elems.forEach((e) =>
            {
                spans = e.querySelectorAll(`.core_reply_tail span`);
                for (const s of spans)
                {
                    if (s.innerText.trim() === "商业推广")
                    {
                        e.remove();
                        break;
                    }
                }
            });
        });
    }

    return actions;
};

/**
 * 立即执行指定的操作。
 */
const exec = (p_actions) =>
{
    p_actions.forEach(p_action => p_action());
};

// 1. 立即执行。
exec(getInstantActions());

// 2. 延迟执行。
window.addEventListener("load", () => exec(getLazyActions()), true);

function _noop() { }

/**
 * 禁止键盘快捷键（单键）。
 */
function _disableKeydown(p_keys)
{
    if (typeof p_keys === "string")
    {
        const keys = p_keys.split(/\W+/);
        document.addEventListener("keydown", (e) =>
        {
            if (keys.indexOf(e.key.toLowerCase()) !== -1)
            {
                e.stopPropagation();
            }
        }, true);
    }
}

/**
 * 默认显示密码登录（而非 QR 码登录）界面
 */
function _disableQRLogin(p_hide, p_show, p_focus)
{
    // 删除扫码登录。
    let elems = document.querySelectorAll(p_hide);
    elems.forEach(e => e.remove());

    // 始终显示密码登录。
    elems = document.querySelectorAll(p_show);
    elems.forEach(e => e.setAttribute("style", "display: block !important; visibility: visible !important;"));

    // 自动聚焦用户名输入框。
    if (p_focus)
    {
        const elem = document.querySelector(p_focus);
        if (elem)
        {
            setTimeout(() => elem.select(), 300);
        }
    }
}
<|endoftext|>


<commit_before>module.exports = GSet

var EventEmitter = require('events').EventEmitter
var Obj = require('./obj')
var clone = require('./utils').clone

/*
  GSet -- grow only set.

  base class for other collection types.
*/

/*
  since I want the user to inject the factory function,
  this is too complicated.

  my brain is doing a strang thing.
  it's thinking it would be a good idea to implement a
  little peer to peer relational db.

IDEAS -- use events instead.

If a relational database was peer to peer, what would that mean?

1. no incremental primary keys.
2. updates only. to delete, set a delete column to true.

one most important thing to achive, after actually having being p2p, is a easy way to attach to UI stuff.

on the one hand, the relational store seems like a natural fit. it just feels insane.

it's resql -- replicated sql.

there arn't any templating languages that support arbitary json,
so maybe there should be a fairly structured data model.

new Set(id).init({
  users: crdt.Obj().on('change', function (key, value) {
    //register a event listeners for update here...
    //throw if the it does not update.
    //no, because might throw by accident.
    //veto callback? that allows async validation.

    //update the model...

    veto(false) //allow this change
    veto(true, reason)  //this was invalid
    // ... veto basicially means to change back to an old value.
    // also, to remove the change from histroy?
    // this is really a security feature...
    // will have to experiment .

    this example could be currently logged in users.
    if value, add new user.
    var userel = $(userList).find('.'+key)
    if !value, remove user from list...

  }).on('validate', function (change, obj) {
    // throw if not valid. -- this is better.
    say, allow username : boolean

  }),
  //async validation is possible too. it would just be handled like a message that arrived late.
  messages: new Set().on('new', function (obj, veto) {
     //object has id. so don't need to pass key.
     obj
  }).on('validate', function (change, obj, usr_ctx) {
    merge change and obj.get()
    MUST have user: name, (which must be a valid user)
    and text: message.
    MAY NOT update a user context that does not own this username.
  })
  .set('0', {text: 'hello'})
})

*/

function defFactory (id) {

  var set = (Array.isArray(id) && id.length > 1)

  var obj = set ? new GSet(id = id[0]) : new Obj(id)
  this[id] = obj.get()

  return obj
}

function GSet(id, state, factory) {
  this.id = id
  this.state = state || {}
  this.objects = {}
  this.queue = []
  this._factory = factory || defFactory
}

GSet.prototype = new EventEmitter()

function getMember (self, key) {
  var f = self._factory
  var obj
  var path = key

  if(Array.isArray(path)) {
    key = path[0]
  }

  if(!self.objects[key]) {

    function enqueue () {
      if(~self.queue.indexOf(obj)) return
      self.queue.push(obj)
      self.emit('queue')
    }

    function create () {
      return f.call(self.state, path)
    }

    obj = create()

    try {
      self.emit('new', obj, self)
    } catch (e) {
      //someone will have to throw away all the changes for this...
      return
    }

    obj = self.objects[key] = obj
    obj.on('queue', enqueue)
  }

  return self.objects[key]
}

GSet.prototype.set =
GSet.prototype.add = function (key, changes, val) {

  if('string' == typeof changes) {
    var _key = changes
    changes = {}
    changes[_key] = val
  }

  if(Array.isArray(key) && key.length == 1)
    key = key[0]

  //error if cannot apply this set.

  if ('object' != typeof changes ) {
    throw new Error('cannot do that' +  JSON.stringify(changes))
  }

 //THIS is ugly. maybe just remove the abitily to call set(key, value)
  if(Array.isArray(key)) {
    var set = getMember(this, key)
    key.shift()
    set.set.call(set, key, changes)
  } else {
    var obj = getMember(this, key)
    obj.set.call(obj, changes)
  }
  return this
}

GSet.prototype.update = function (update) {
  update = clone(update)
  var key = update[0].shift()
  var obj = getMember(this, key)

  if(obj) { // if was not valid, this is null.
    obj.update(update)
    //update events behave different on Set to on Obj.
    //it updates when any member updates.
    this.emit('update', key, obj.get())
  }
}

/*
  this can probably be used as the flush implementation for any
  collection Obj
*/

GSet.prototype.flush = function (obj) {
  var id = this.id
  var updates = []
  var queue = this.queue
  if(!queue.length)
    return
  while(queue.length) {
    //note: an object MAY NOT be a member of more than one set.
    var obj = queue.shift()
    var update = obj.flush()

    this.emit('update', obj.id, obj.get())

    if(!update) return
    update = clone(update)
    update[0].unshift(id)
    updates.push(update)

  }

  this.emit('flush', updates)
  return updates
}

GSet.prototype.history = function () {
  var hist = []
  var objects = this.objects
  var id = this.id
  for(var k in objects)
    objects[k].history().forEach(function (e) {
      e = clone(e)
      e[0].unshift(id)

      hist.push(e)
    })
  return hist
}

GSet.prototype.toArray =
GSet.prototype.get = function (path) {
  if(!arguments.length)
    return this.state
  //if path is defined, pass to members...
}

GSet.prototype.init = function (schema) {
  for (var id in schema) {
    (this.objects[id] = schema[id]).id = id
  }
  return this
}
<commit_msg>handle sub sets correctly<commit_after>module.exports = GSet

var EventEmitter = require('events').EventEmitter
var Obj = require('./obj')
var clone = require('./utils').clone

/*
  GSet -- grow only set.

  base class for other collection types.
*/

/*
  since I want the user to inject the factory function,
  this is too complicated.

  my brain is doing a strang thing.
  it's thinking it would be a good idea to implement a
  little peer to peer relational db.

IDEAS -- use events instead.

If a relational database was peer to peer, what would that mean?

1. no incremental primary keys.
2. updates only. to delete, set a delete column to true.

one most important thing to achive, after actually having being p2p, is a easy way to attach to UI stuff.

on the one hand, the relational store seems like a natural fit. it just feels insane.

it's resql -- replicated sql.

there arn't any templating languages that support arbitary json,
so maybe there should be a fairly structured data model.

new Set(id).init({
  users: crdt.Obj().on('change', function (key, value) {
    //register a event listeners for update here...
    //throw if the it does not update.
    //no, because might throw by accident.
    //veto callback? that allows async validation.

    //update the model...

    veto(false) //allow this change
    veto(true, reason)  //this was invalid
    // ... veto basicially means to change back to an old value.
    // also, to remove the change from histroy?
    // this is really a security feature...
    // will have to experiment .

    this example could be currently logged in users.
    if value, add new user.
    var userel = $(userList).find('.'+key)
    if !value, remove user from list...

  }).on('validate', function (change, obj) {
    // throw if not valid. -- this is better.
    say, allow username : boolean

  }),
  //async validation is possible too. it would just be handled like a message that arrived late.
  messages: new Set().on('new', function (obj, veto) {
     //object has id. so don't need to pass key.
     obj
  }).on('validate', function (change, obj, usr_ctx) {
    merge change and obj.get()
    MUST have user: name, (which must be a valid user)
    and text: message.
    MAY NOT update a user context that does not own this username.
  })
  .set('0', {text: 'hello'})
})

*/

function defFactory (id) {

  var set = (Array.isArray(id) && id.length > 1)

  var obj = set ? new GSet(id = id[0]) : new Obj('' + id)
  this[id] = obj.get()

  return obj
}

function GSet(id, state, factory) {
  this.id = id
  this.state = state || {}
  this.objects = {}
  this.queue = []
  this._factory = factory || defFactory
}

GSet.prototype = new EventEmitter()

function getMember (self, key) {
  var f = self._factory
  var obj
  var path = key

  if(Array.isArray(path)) {
    key = path[0]
    if(!path.length)
      throw new Error('path erros')
  }

  if(!self.objects[key]) {

    function enqueue () {
      if(~self.queue.indexOf(obj)) return
      self.queue.push(obj)
      self.emit('queue')
    }

    obj = f.call(self.state, path)

    try {
      self.emit('new', obj, self)
    } catch (e) {
      console.error('validation:', e.message)
      //someone will have to throw away all the changes for this...
      return
    }

    obj = self.objects[key] = obj
    obj.on('queue', enqueue)
  }

  return self.objects[key]
}

GSet.prototype.set =
GSet.prototype.add = function (key, changes, val) {

  if('string' == typeof changes) {
    var _key = changes
    changes = {}
    changes[_key] = val
  }

  if(Array.isArray(key) && key.length == 1)
    key = key[0]

  //error if cannot apply this set.

  if ('object' != typeof changes ) {
    throw new Error('cannot do that' +  JSON.stringify(changes))
  }

 //THIS is ugly. maybe just remove the abitily to call set(key, value)
  if(Array.isArray(key)) {
    var set = getMember(this, key)
    key.shift()
    set.set.call(set, key, changes)
  } else {
    var obj = getMember(this, key)
    obj && obj.set.call(obj, changes)
  }
  return this
}

GSet.prototype.update = function (update) {
  update = clone(update)
  var path = update[0]
  var obj = getMember(this, path)
  var key = path.shift()
  if(obj) { // if was not valid, this is null.
    obj.update(update)
    //update events behave different on Set to on Obj.
    //it updates when any member updates.
    this.emit('update', key, obj.get())
  }
}

/*
  this can probably be used as the flush implementation for any
  collection Obj
*/

GSet.prototype.flush = function (obj) {
  var id = this.id
  var updates = []
  var queue = this.queue
  if(!queue.length)
    return
  while(queue.length) {
    //note: an object MAY NOT be a member of more than one set.
    var obj = queue.shift()
    //if obj is a set, it will return an array of updates.
    //
    var flushed = obj instanceof GSet ? obj.flush() : [obj.flush()]

    this.emit('update', obj.id, obj.get())

    while(flushed.length) {
      var update = flushed.shift()
      update = clone(update)
      update[0].unshift(id)
      updates.push(update)
    }

  }

  this.emit('flush', updates)
  return updates
}

GSet.prototype.history = function () {
  var hist = []
  var objects = this.objects
  var id = this.id
  for(var k in objects)
    objects[k].history().forEach(function (e) {
      e = clone(e)
      e[0].unshift(id)

      hist.push(e)
    })
  return hist
}

GSet.prototype.toArray =
GSet.prototype.get = function (path) {
  if(!arguments.length)
    return this.state
  //if path is defined, pass to members...
}

GSet.prototype.init = function (schema) {
  var self = this
  for (var id in schema) {
    (function () {
      var obj = self.objects[id] = schema[id]
      self.state[id] = obj.get()
      obj.id = id
      obj.on('queue',
        function () {
        if(~self.queue.indexOf(obj)) return
        self.queue.push(obj)
        self.emit('queue')
      })
    })()
  }
  return this
}
<|endoftext|>


<commit_before>
const Path = require('./Path')
const { digg } = require('./util')

/**
 *
 */
class Query {
  static get DEFAULT_LIMIT () {
    return 10000
  }

  /**
   *
   */
  constructor (connection, pathOrEntity, conditions, opts) {
    conditions = conditions || []
    opts = opts || {}

    this.connection = connection
    this.pathOrEntity = pathOrEntity
    this.conditions = conditions
    this.opts = opts
  }

  /**
   *
   */
  count () {
    return this.fetch([], 'count').then(digg('count'))
  }

  /**
   *
   */
  get (fields) {
    return this.fetch(fields, 'search').then(digg('data'))
  }

  /**
   *
   */
  getInBatches (fields, iteratee) {
    const limit = this.opts.limit || Query.DEFAULT_LIMIT
    const offset = this.opts.offset || 0

    return this.limit(limit).offset(offset).fetch(fields, 'search')
      .then(partial => {
        if (partial.length > 0) {
          return iteratee(partial)
            .then(() => this.offset(offset).getInBatches(fields, iteratee))
        }
      })
  }

  /**
   *
   */
  limit (limit) {
    const opts = Object.assign({}, this.opts, { limit: limit })
    return new Query(this.connection, this.pathOrEntity, this.conditions, opts)
  }

  /**
   *
   */
  offset (offset) {
    const opts = Object.assign({}, this.opts, { offset: offset })
    return new Query(this.connection, this.pathOrEntity, this.conditions, opts)
  }

  /**
   *
   */
  where (field, operator, value) {
    const condition = [field, operator, value]
    const conditions = this.conditions.concat([condition])
    return new Query(this.connection, this.pathOrEntity, conditions, this.opts)
  }

  /**
   *
   */
  fetch (fields, suffix) {
    const where = this.toParameter(this.conditions)
    const params = Object.assign(where, { fields })

    return this.request(params, suffix)
  }

  /**
   *
   */
  request (params, suffix) {
    const path = Path.resolve(this.pathOrEntity, suffix)

    return this.connection.request('POST', path, params)
  }

  toOperator (operator) {
    switch (operator.toLowerCase()) {
      case '=':
        return 'eq'
      case '!=':
      case '<>':
        return 'neq'
      case '>':
        return 'gt'
      case '>=':
        return 'gte'
      case '<':
        return 'lt'
      case '<=':
        return 'lte'
      case 'in':
        return 'in'
      case 'not in':
        return 'nin'
      case 'like':
        return 'like'
      case 'not like':
        return 'nlike'
      case 'is null':
        return 'null'
      case 'is not null':
        return 'nnull'
      case 'is blank':
        return 'blank'
      case 'is not blank':
        return 'nblank'
      default:
        throw new Error('Unknown operator: ' + operator)
    }
  }

  toParameter () {
    const where = this.conditions.reduce((acc, condition) => {
      const [field, operator, value] = condition
      acc[`${field}-${this.toOperator(operator)}`] = value
      return acc
    }, {})

    return Object.assign(where, this.opts)
  }
}

module.exports = Query
<commit_msg>docs: Add DocComment to Query.js<commit_after>
const Path = require('./Path')
const { digg } = require('./util')

/**
 * Search query builder
 */
class Query {
  static get DEFAULT_LIMIT () {
    return 10000
  }

  /**
   * @param Connection    connection      Instance of Connection
   * @param string|Entity pathOrEntity    Search path or Entity
   * @param object[]      [conditions=[]] List of query condition
   * @param object        [opts={}]       Limit, offset, ...
   */
  constructor (connection, pathOrEntity, conditions, opts) {
    conditions = conditions || []
    opts = opts || {}

    this.connection = connection
    this.pathOrEntity = pathOrEntity
    this.conditions = conditions
    this.opts = opts
  }

  /**
   * Return number of result data
   *
   * @return Promise
   */
  count () {
    return this.fetch([], 'count').then(digg('count'))
  }

  /**
   * Fetch query result
   *
   * @param string[] List of field
   * @return Promise
   */
  get (fields) {
    return this.fetch(fields, 'search').then(digg('data'))
  }

  /**
   * Fetch query result in batch
   *
   * @see get
   * @param function iteratee Callback function
   * @return Promise resolve when all callbacks are finished
   */
  getInBatches (fields, iteratee) {
    const limit = this.opts.limit || Query.DEFAULT_LIMIT
    const offset = this.opts.offset || 0

    return this.limit(limit).offset(offset).fetch(fields, 'search')
      .then(partial => {
        if (partial.length > 0) {
          return iteratee(partial)
            .then(() => this.offset(offset).getInBatches(fields, iteratee))
        }
      })
  }

  /**
   * Set limit to query condition
   *
   * @param int limit
   * @return Query New instance of Query
   */
  limit (limit) {
    const opts = Object.assign({}, this.opts, { limit: limit })
    return new Query(this.connection, this.pathOrEntity, this.conditions, opts)
  }

  /**
   * Set offset to query condition
   *
   * @param int offset
   * @return Query New instance of Query
   */
  offset (offset) {
    const opts = Object.assign({}, this.opts, { offset: offset })
    return new Query(this.connection, this.pathOrEntity, this.conditions, opts)
  }

  /**
   * Set where to query condition
   *
   * @see toOperator
   * @param string field    One of field
   * @param string operator One of operator
   * @param string value
   * @return Query New instance of Query
   */
  where (field, operator, value) {
    const condition = [field, operator, value]
    const conditions = this.conditions.concat([condition])
    return new Query(this.connection, this.pathOrEntity, conditions, this.opts)
  }

  /**
   * Prepare for API request
   *
   * @param string[] fields List of field
   * @param string   suffix /api_v1_xxx/{XXX} <-
   * @return Promise
   */
  fetch (fields, suffix) {
    const where = this.toParameter(this.conditions)
    const params = Object.assign(where, { fields })

    return this.request(params, suffix)
  }

  /**
   * Execute API request
   *
   * @param object params Request parameters
   * @param string suffix /api_v1_xxx/{XXX} <-
   * @return Promise
   */
  request (params, suffix) {
    const path = Path.resolve(this.pathOrEntity, suffix)

    return this.connection.request('POST', path, params)
  }

  toOperator (operator) {
    switch (operator.toLowerCase()) {
      case '=':
        return 'eq'
      case '!=':
      case '<>':
        return 'neq'
      case '>':
        return 'gt'
      case '>=':
        return 'gte'
      case '<':
        return 'lt'
      case '<=':
        return 'lte'
      case 'in':
        return 'in'
      case 'not in':
        return 'nin'
      case 'like':
        return 'like'
      case 'not like':
        return 'nlike'
      case 'is null':
        return 'null'
      case 'is not null':
        return 'nnull'
      case 'is blank':
        return 'blank'
      case 'is not blank':
        return 'nblank'
      default:
        throw new Error('Unknown operator: ' + operator)
    }
  }

  toParameter () {
    const where = this.conditions.reduce((acc, condition) => {
      const [field, operator, value] = condition
      acc[`${field}-${this.toOperator(operator)}`] = value
      return acc
    }, {})

    return Object.assign(where, this.opts)
  }
}

module.exports = Query
<|endoftext|>


<commit_before>Application.Provenance.Controllers.controller('provenanceIOStepsIOStep',
    ["$scope", "ProvDrafts", "$stateParams", "mcapi",
        function ($scope, ProvDrafts, $stateParams, mcapi) {
            $scope.model = {
                additionalProperty: {},
                pick_sample: {}
            };

            $scope.pick_sample = function () {
                var i = _.indexOf($scope.samples_list, function (item) {
                    return (item.id === $scope.doc.sample.id);
                });

                if (i !== -1) {
                    $scope.doc.sample = $scope.samples_list[i];
                    $scope.doc.model = $scope.doc.sample.model;
                    $scope.doc.owner = $scope.doc.sample.owner;
                    $scope.doc.sample_id = $scope.doc.sample.id;
                }
            };

            $scope.addAdditionalProperty = function () {
                $scope.doc.model.added_properties.push($scope.model.additionalProperty);
            };

            $scope.addCustomProperty = function () {
                $scope.doc.model.added_properties.push({'name': $scope.customPropertyName, 'value': $scope.customPropertyValue, 'unit': '', 'value_choice': [], 'unit_choice': []});
            };

//            $scope.loadMaterials = function () {
//                mcapi('/materials')
//                    .success(function (data) {
//                        $scope.materials = data;
//
//                        if ($scope.doc.material) {
//                            var i = _.indexOf($scope.materials, function (item) {
//                                return (item.name === $scope.doc.material.name);
//                            });
//
//                            if (i !== -1) {
//                                $scope.doc.material = $scope.materials[i];
//                                if ($scope.doc.sample) {
//                                    var j = _.indexOf($scope.samples_list, function (item) {
//                                        return (item.id === $scope.doc.sample.id);
//                                    });
//                                    if (j !== -1) {
//                                        $scope.doc.sample = $scope.samples_list[j];
//                                        $scope.doc.model = $scope.doc.sample.model;
//                                        $scope.doc.owner = $scope.doc.sample.owner;
//                                        $scope.doc.sample_id = $scope.doc.sample.id;
//                                    }
//                                }
//                            }
//                        }
//                    }).jsonp();
//            };

            $scope.load_all_samples = function () {
                mcapi('/samples')
                    .success(function (data) {
                        $scope.samples_list = data;
                    }).jsonp();
            };

            $scope.init = function () {
                $scope.stepName = $stateParams.iostep;
                if ($stateParams.iosteps === 'inputs') {
                    $scope.doc = ProvDrafts.current.attributes.input_conditions[$scope.stepName];
                } else {
                    $scope.doc = ProvDrafts.current.attributes.output_conditions[$scope.stepName];
                }
                $scope.load_all_samples();
                //$scope.loadMaterials();
            };

            $scope.init();
        }
    ])
;<commit_msg>updated the sample dropdown<commit_after>Application.Provenance.Controllers.controller('provenanceIOStepsIOStep',
    ["$scope", "ProvDrafts", "$stateParams", "mcapi",
        function ($scope, ProvDrafts, $stateParams, mcapi) {
            $scope.model = {
                additionalProperty: {},
                pick_sample: {}
            };

            $scope.pick_sample = function () {
                var i = _.indexOf($scope.samples_list, function (item) {
                    return (item.id === $scope.doc.sample.id);
                });

                if (i !== -1) {
                    $scope.doc.sample = $scope.samples_list[i];
                    $scope.doc.model = $scope.doc.sample.model;
                    $scope.doc.owner = $scope.doc.sample.owner;
                    $scope.doc.sample_id = $scope.doc.sample.id;
                }
            };

            $scope.addAdditionalProperty = function () {
                $scope.doc.model.added_properties.push($scope.model.additionalProperty);
            };

            $scope.addCustomProperty = function () {
                $scope.doc.model.added_properties.push({'name': $scope.customPropertyName, 'value': $scope.customPropertyValue, 'unit': '', 'value_choice': [], 'unit_choice': []});
            };

//            $scope.loadMaterials = function () {
//                mcapi('/materials')
//                    .success(function (data) {
//                        $scope.materials = data;
//
//                        if ($scope.doc.material) {
//                            var i = _.indexOf($scope.materials, function (item) {
//                                return (item.name === $scope.doc.material.name);
//                            });
//
//                            if (i !== -1) {
//                                $scope.doc.material = $scope.materials[i];
//                                if ($scope.doc.sample) {
//                                    var j = _.indexOf($scope.samples_list, function (item) {
//                                        return (item.id === $scope.doc.sample.id);
//                                    });
//                                    if (j !== -1) {
//                                        $scope.doc.sample = $scope.samples_list[j];
//                                        $scope.doc.model = $scope.doc.sample.model;
//                                        $scope.doc.owner = $scope.doc.sample.owner;
//                                        $scope.doc.sample_id = $scope.doc.sample.id;
//                                    }
//                                }
//                            }
//                        }
//                    }).jsonp();
//            };

            $scope.load_all_samples = function () {
                mcapi('/samples')
                    .success(function (data) {
                        $scope.samples_list = data;
                        if ($scope.doc.sample) {
                            var i = _.indexOf($scope.samples_list, function (item) {
                                return (item.id === $scope.doc.sample.id);
                            });

                            if (i !== -1) {
                                $scope.doc.sample = $scope.samples_list[i];
                            }
                        }
                    }).jsonp();

            };

            $scope.init = function () {
                $scope.stepName = $stateParams.iostep;
                if ($stateParams.iosteps === 'inputs') {
                    $scope.doc = ProvDrafts.current.attributes.input_conditions[$scope.stepName];
                } else {
                    $scope.doc = ProvDrafts.current.attributes.output_conditions[$scope.stepName];
                }
                if ($scope.doc.template_pick === 'sample') {
                    $scope.load_all_samples();

                }
            };

            $scope.init();
        }
    ])
;<|endoftext|>


<commit_before>/** @jsx m */
import utils from '../../../utils';
import helper from '../../helper';
import widgets from '../../widget/common';
import layout from '../../layout';
import gameApi from '../../../lichess/game';
import i18n from '../../../i18n';
import gameStatus from '../../../lichess/status';
const moment = window.moment;

export default function view(ctrl) {
  const header = utils.partialf(widgets.header, null,
    widgets.backButton(m.route.param('id') + ' games')
  );

  function renderBody() {
    return (

          <select id="filterGames" onchange={ctrl.onFilterChange}>
            {ctrl.availableFilters().map(f => {
              return (
                <option value={f.key} selected={ctrl.currentFilter() === f.key}>
                  {utils.capitalize(i18n(f.label).replace('%s ', ''))} ({f.count})
                </option>
              );
            })}
          </select>

        {renderAllGames(ctrl)}

    );
  }

  return layout.free(header, renderBody, widgets.empty, widgets.empty);
}

function renderAllGames(ctrl) {
  return (

        { ctrl.games().map((g, i) => renderGame(g, i, ctrl.userId)) }
        {helper.cond(ctrl.isLoadingNextPage(),

loading...

        )}

  );
}

function renderGame(g, index, userId) {
  const wideScreen = helper.isWideScreen();
  const time = gameApi.time(g);
  const mode = g.rated ? i18n('rated') : i18n('casual');
  const title = time + ' • ' + g.variant.name + ' • ' + mode;
  const date = moment(g.timestamp).calendar();
  const status = gameStatus.toLabel(g.status.name, g.winner, g.variant.key) +
    (g.winner ? '. ' + i18n(g.winner === 'white' ? 'whiteIsVictorious' : 'blackIsVictorious') + '.' : '');
  const icon = utils.gameIcon(g.perf) || '';
  const userColor = g.players.white.userId === userId ? 'white' : 'black';
  const evenOrOdd = index % 2 === 0 ? 'even' : 'odd';

  return (
    <li className={`list_item userGame ${evenOrOdd} nav`}
      config={helper.ontouchY(() => m.route('/game/' + g.id))}>
      {helper.cond(wideScreen, helper.viewOnlyBoard(g.fen, g.lastMove, userColor))}

{title}

        {date}

          {renderPlayer(g.players, 'white')}

          {renderPlayer(g.players, 'black')}

{status}

        {g.opening ?

{g.opening.name}
 : null
        }

  );
}

function renderPlayer(players, color) {
  let player = players[color];
  let playerName;
  if (player.userId) playerName = player.userId;
  else if (player.aiLevel) playerName = utils.aiName(player.aiLevel);

  return (

      {playerName}

      {helper.cond(player.rating,
      {player.rating}
      )}

  );
}

<commit_msg>Display anonymous players in games list<commit_after>/** @jsx m */
import utils from '../../../utils';
import helper from '../../helper';
import widgets from '../../widget/common';
import layout from '../../layout';
import gameApi from '../../../lichess/game';
import i18n from '../../../i18n';
import gameStatus from '../../../lichess/status';
const moment = window.moment;

export default function view(ctrl) {
  const header = utils.partialf(widgets.header, null,
    widgets.backButton(m.route.param('id') + ' games')
  );

  function renderBody() {
    return (

          <select id="filterGames" onchange={ctrl.onFilterChange}>
            {ctrl.availableFilters().map(f => {
              return (
                <option value={f.key} selected={ctrl.currentFilter() === f.key}>
                  {utils.capitalize(i18n(f.label).replace('%s ', ''))} ({f.count})
                </option>
              );
            })}
          </select>

        {renderAllGames(ctrl)}

    );
  }

  return layout.free(header, renderBody, widgets.empty, widgets.empty);
}

function renderAllGames(ctrl) {
  return (

        { ctrl.games().map((g, i) => renderGame(g, i, ctrl.userId)) }
        {helper.cond(ctrl.isLoadingNextPage(),

loading...

        )}

  );
}

function renderGame(g, index, userId) {
  const wideScreen = helper.isWideScreen();
  const time = gameApi.time(g);
  const mode = g.rated ? i18n('rated') : i18n('casual');
  const title = time + ' • ' + g.variant.name + ' • ' + mode;
  const date = moment(g.timestamp).calendar();
  const status = gameStatus.toLabel(g.status.name, g.winner, g.variant.key) +
    (g.winner ? '. ' + i18n(g.winner === 'white' ? 'whiteIsVictorious' : 'blackIsVictorious') + '.' : '');
  const icon = utils.gameIcon(g.perf) || '';
  const userColor = g.players.white.userId === userId ? 'white' : 'black';
  const evenOrOdd = index % 2 === 0 ? 'even' : 'odd';

  return (
    <li className={`list_item userGame ${evenOrOdd} nav`}
      config={helper.ontouchY(() => m.route('/game/' + g.id))}>
      {helper.cond(wideScreen, helper.viewOnlyBoard(g.fen, g.lastMove, userColor))}

{title}

        {date}

          {renderPlayer(g.players, 'white')}

          {renderPlayer(g.players, 'black')}

{status}

        {g.opening ?

{g.opening.name}
 : null
        }

  );
}

function renderPlayer(players, color) {
  let player = players[color];
  let playerName;
  if (player.userId) playerName = player.userId;
  else if (player.aiLevel) playerName = utils.aiName(player.aiLevel);
  else playerName = 'Anonymous';

  return (

      {playerName}

      {helper.cond(player.rating,
      {player.rating}
      )}

  );
}

<|endoftext|>


<commit_before>/**
 * db
 * Module which exposes mongo database access
 */

var db = {

  host: '127.0.0.1',

  port: 27017,

  db_name: 'queixinhas',

  load: function (collection_name, id, callback){
    var mongodb = require('mongodb');
    var ObjectId = require('mongodb').ObjectID;

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);

        collection.find({_id: ObjectId(id)}).toArray(function (error, docs) {
          callback(error, docs);
        });
      }
    });
  },

  save: function (collection_name, doc, callback){
    var mongodb = require('mongodb');

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);

        collection.insert(doc, {safe: true}, function(error, doc){
          callback(error, doc &&  doc[0] && doc[0]._id.toString());
        });
      }
    });
  },

  remove: function (collection_name, id, callback){
    var mongodb = require('mongodb');
    var ObjectId = require('mongodb').ObjectID;

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);

        collection.remove({_id: ObjectId(id)}, function(error, docs){
          callback(error, docs);
        });
      }
    });
  }
};

module.exports = db;<commit_msg>Add the update method to the DAL<commit_after>/**
 * db
 * Module which exposes mongo database access
 */

var db = {

  host: '127.0.0.1',

  port: 27017,

  db_name: 'queixinhas',

  load: function (collection_name, id, callback){
    var mongodb = require('mongodb');
    var ObjectId = require('mongodb').ObjectID;

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);

        collection.find({_id: ObjectId(id)}).toArray(function (error, docs) {
          callback(error, docs);
        });
      }
    });
  },

  save: function (collection_name, doc, callback){
    var mongodb = require('mongodb');

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);

        collection.insert(doc, {safe: true}, function(error, doc){
          callback(error, doc &&  doc[0] && doc[0]._id.toString());
        });
      }
    });
  },

  update: function (collection_name, id, doc, callback){
    var mongodb = require('mongodb');
    var ObjectId = require('mongodb').ObjectID;

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);
        collection.findAndModify({_id: ObjectId(id)}, [['_id', 'ascending']], {$set: doc}, {new: true}, function(error, new_doc){
          callback(error, new_doc);
        });
      }
    });
  },

  remove: function (collection_name, id, callback){
    var mongodb = require('mongodb');
    var ObjectId = require('mongodb').ObjectID;

    var server = new mongodb.Server(this.host, this.port, {});
    new mongodb.Db(this.db_name, server, {}).open(function (error, client) {
      if (error) {
        callback(error, null);
      }
      else{
        var collection = new mongodb.Collection(client, collection_name);

        collection.remove({_id: ObjectId(id)}, function(error, docs){
          callback(error, docs);
        });
      }
    });
  }
};

module.exports = db;<|endoftext|>