<commit_before>//
// Set the Privly version number as a header on all requests
//
chrome.webRequest.onBeforeSendHeaders.addListener(
  function(details) {
    details.requestHeaders.push({name:'X-Privly-Version', value:'0.0.7'});
    return {requestHeaders: details.requestHeaders};
  },
  {urls: ["<all_urls>"]},
  ["blocking", "requestHeaders"]);

//
// browserAction Icon Interaction
//
chrome.browserAction.onClicked.addListener(function(tab) {

  // Set the text color to red
  chrome.browserAction.setBadgeBackgroundColor({color: "#FF0000"});

  chrome.browserAction.getBadgeText({},
    function(currentText) {

      //toggle the on/off state of the button
      if (currentText === "off") {
        chrome.browserAction.setBadgeText({text: ""});
        chrome.browserAction.setTitle({title: "Turn Privly Viewing Off"});

        // If the badge text was previously set to off, we probably
        // need to inject the script.
        chrome.tabs.captureVisibleTab(null, null, function(tab){
          if (tab !== undefined) {
            chrome.tabs.executeScript(tab.id, {file: "/javascripts/privly.js", allFrames: true});
          }
        })
      } else {
        chrome.browserAction.setBadgeText({text: "off"});
        chrome.browserAction.setTitle({title: "Turn Privly Viewing On"});
      }
    });
});

//
// Content Script Loading
//
// Loads content script if the badge text is not set to "off"
//
chrome.tabs.onUpdated.addListener(function(tab) {
  chrome.browserAction.getBadgeText({},
    function(currentText) {
      if (currentText !== "off") {
        chrome.tabs.executeScript(tab.id, {file: "/javascripts/privly.js", allFrames: true});
      }
    });
});

//
// Posting Process
//
// 1. The user selects an editable element with a right click
// 2. The user clicks the "Encrypt and Post" option
// 3. The script records the host page the link will be posted to
// 4. The script opens a posting window and records its ID
// 5. The posting application will complete and send this script
//    a message with the Privly URL
// 6. The script sends the host page's content script the URL

// Address to open for the posting process
var postingApplicationUrl = "https://privlyalpha.org/zero_bin/";

// Remembers where the PrivlyUrl will be placed based on the context menu
var postingResultTab = undefined;
var postingApplicationTabId = undefined;

// Handles right click on form event by opening posting window.
var postingHandler = function(info, sourceTab) {

  // only open a new posting window
  if (postingApplicationTabId === undefined) {

    // Open a new window.
    chrome.windows.create({url: postingApplicationUrl, focused: true}, function(newWindow){

      //Get the window's tab
      var tab = newWindow.tabs[0];

      //remember the posting tab id
      postingApplicationTabId = tab.id;

      //remember the tab id where the post will be placed. The content script
      //will remember which form element was clicked
      postingResultTab = sourceTab;

      //tell the host page not to change the posting location on subsequent
      //right click events
      chrome.tabs.sendMessage(postingResultTab.id, {pendingPost: true});

    })
  } else {
    // Notify users of their
    var notification = webkitNotifications.createNotification(
      '../images/logo_48.png',  // icon url - can be relative
      'Privly Warning',  // notification title
      'Close the posting window or finish the post before starting a new post.'  // notification body text
    );
    notification.show();
  }
};

// Creates the context (right click) menu
chrome.contextMenus.create({
    "title": "Encrypt and Post",
    "contexts": ["editable"],
    "onclick" : function(info, tab) {
        postingHandler(info, tab);
    }
  });

// Handles the receipt of Privly URLs for addition to the web page.
// The request object should contain the privlyUrl.
chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.privlyUrl !== undefined) {

      //Switches current tab to the page receiving the URL
      chrome.tabs.update(postingResultTab.id, {selected: true});

      //sends URL to host page
      chrome.tabs.sendMessage(postingResultTab.id, {privlyUrl: request.privlyUrl, pendingPost: false});

      //close the posting application
      chrome.tabs.remove(sender.tab.id);
      postingApplicationTabId = undefined;

      //remove the record of where we are posting to
      postingResultTab = undefined;

    }
  });

// If the posting application or host page closes, the state should reset.
// The posting form will close as well.
chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) {
  if (tabId === postingApplicationTabId) {
    postingApplicationTabId = undefined;
    chrome.tabs.sendMessage(postingResultTab.id, {pendingPost: false});
    postingResultTab = undefined;
  }

  if (tabId === postingResultTab.id) {
    chrome.tabs.remove(postingApplicationTabId);
    postingResultTab = undefined;
    postingApplicationTabId = undefined;
  }
});
<commit_msg>added Privly post endpoint<commit_after>//
// Set the Privly version number as a header on all requests
//
chrome.webRequest.onBeforeSendHeaders.addListener(
  function(details) {
    details.requestHeaders.push({name:'X-Privly-Version', value:'0.0.7'});
    return {requestHeaders: details.requestHeaders};
  },
  {urls: ["<all_urls>"]},
  ["blocking", "requestHeaders"]);

//
// browserAction Icon Interaction
//
chrome.browserAction.onClicked.addListener(function(tab) {

  // Set the text color to red
  chrome.browserAction.setBadgeBackgroundColor({color: "#FF0000"});

  chrome.browserAction.getBadgeText({},
    function(currentText) {

      //toggle the on/off state of the button
      if (currentText === "off") {
        chrome.browserAction.setBadgeText({text: ""});
        chrome.browserAction.setTitle({title: "Turn Privly Viewing Off"});

        // If the badge text was previously set to off, we probably
        // need to inject the script.
        chrome.tabs.captureVisibleTab(null, null, function(tab){
          if (tab !== undefined) {
            chrome.tabs.executeScript(tab.id, {file: "/javascripts/privly.js", allFrames: true});
          }
        })
      } else {
        chrome.browserAction.setBadgeText({text: "off"});
        chrome.browserAction.setTitle({title: "Turn Privly Viewing On"});
      }
    });
});

//
// Content Script Loading
//
// Loads content script if the badge text is not set to "off"
//
chrome.tabs.onUpdated.addListener(function(tab) {
  chrome.browserAction.getBadgeText({},
    function(currentText) {
      if (currentText !== "off") {
        chrome.tabs.executeScript(tab.id, {file: "/javascripts/privly.js", allFrames: true});
      }
    });
});

//
// Posting Process
//
// 1. The user selects an editable element with a right click
// 2. The user clicks the "Encrypt and Post" option
// 3. The script records the host page the link will be posted to
// 4. The script opens a posting window and records its ID
// 5. The posting application will complete and send this script
//    a message with the Privly URL
// 6. The script sends the host page's content script the URL

// Remembers where the PrivlyUrl will be placed based on the context menu
var postingResultTab = undefined;
var postingApplicationTabId = undefined;

// Handles right click on form event by opening posting window.
var postingHandler = function(info, sourceTab, postingApplicationUrl) {

  // only open a new posting window
  if (postingApplicationTabId === undefined) {

    // Open a new window.
    chrome.windows.create({url: postingApplicationUrl, focused: true}, function(newWindow){

      //Get the window's tab
      var tab = newWindow.tabs[0];

      //remember the posting tab id
      postingApplicationTabId = tab.id;

      //remember the tab id where the post will be placed. The content script
      //will remember which form element was clicked
      postingResultTab = sourceTab;

      //tell the host page not to change the posting location on subsequent
      //right click events
      chrome.tabs.sendMessage(postingResultTab.id, {pendingPost: true});

    })
  } else {
    // Notify users of their
    var notification = webkitNotifications.createNotification(
      '../images/logo_48.png',  // icon url - can be relative
      'Privly Warning',  // notification title
      'Close the posting window or finish the post before starting a new post.'  // notification body text
    );
    notification.show();
  }
};

// Creates the context (right click) menu
chrome.contextMenus.create({
    "title": "You Must have a Developer Account",
    "contexts": ["editable"],
    "enabled": false
  });

// Address to open for the ZeroBin posting process
var zeroBinPostingApplicationUrl = "https://privlyalpha.org/zero_bin/";

// Creates the context (right click) menu
chrome.contextMenus.create({
    "title": "Encrypt and Post",
    "contexts": ["editable"],
    "onclick" : function(info, tab) {
        postingHandler(info, tab, zeroBinPostingApplicationUrl);
    }
  });

// Address to open for the ZeroBin posting process
var privlyPostPostingApplicationUrl = "https://privlyalpha.org/posts/new";

// Creates the context (right click) menu
chrome.contextMenus.create({
    "title": "Post Unencrypted Content",
    "contexts": ["editable"],
    "onclick" : function(info, tab) {
        postingHandler(info, tab, privlyPostPostingApplicationUrl);
    }
  });

// Handles the receipt of Privly URLs for addition to the web page.
// The request object should contain the privlyUrl.
chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.privlyUrl !== undefined) {

      //Switches current tab to the page receiving the URL
      chrome.tabs.update(postingResultTab.id, {selected: true});

      //sends URL to host page
      chrome.tabs.sendMessage(postingResultTab.id, {privlyUrl: request.privlyUrl, pendingPost: false});

      //close the posting application
      chrome.tabs.remove(sender.tab.id);
      postingApplicationTabId = undefined;

      //remove the record of where we are posting to
      postingResultTab = undefined;

    }
  });

// If the posting application or host page closes, the state should reset.
// The posting form will close as well.
chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) {
  if (tabId === postingApplicationTabId) {
    postingApplicationTabId = undefined;
    chrome.tabs.sendMessage(postingResultTab.id, {pendingPost: false});
    postingResultTab = undefined;
  }

  if (tabId === postingResultTab.id) {
    chrome.tabs.remove(postingApplicationTabId);
    postingResultTab = undefined;
    postingApplicationTabId = undefined;
  }
});
<|endoftext|>


<commit_before>$.fn.ready(function() {

  var $listmode = $('#listmode'),
      $listentries = $("#list-entries");

  /* ==========================================================================
     Menu
     ========================================================================== */

  $("#menu").click(function(){
    $("#links").toggle();
	if ($('#content').hasClass('opacity03')) {
		$('#content').removeClass('opacity03');
	}
  });

  /* ==========================================================================
     List mode or Table Mode
     ========================================================================== */

  $listmode.click(function(){
    if ( $.cookie("listmode") == 1 ) {
      // Cookie
      $.removeCookie("listmode");

      $listentries.removeClass("listmode");
      $listmode.removeClass("tablemode");
      $listmode.addClass("listmode");
    }
    else {
      // Cookie
      $.cookie("listmode", 1, {expires: 365});

      $listentries.addClass("listmode");
      $listmode.removeClass("listmode");
      $listmode.addClass("tablemode");
    }

  });

  /* ==========================================================================
     Cookie listmode
     ========================================================================== */

  if ( $.cookie("listmode") == 1 ) {
    $listentries.addClass("listmode");
    $listmode.removeClass("listmode");
    $listmode.addClass("tablemode");
  }

});
<commit_msg>Changing my tabs to spaces :)<commit_after>$.fn.ready(function() {

  var $listmode = $('#listmode'),
      $listentries = $("#list-entries");

  /* ==========================================================================
     Menu
     ========================================================================== */

  $("#menu").click(function(){
    $("#links").toggle();
    if ($('#content').hasClass('opacity03')) {
        $('#content').removeClass('opacity03');
    }
  });

  /* ==========================================================================
     List mode or Table Mode
     ========================================================================== */

  $listmode.click(function(){
    if ( $.cookie("listmode") == 1 ) {
      // Cookie
      $.removeCookie("listmode");

      $listentries.removeClass("listmode");
      $listmode.removeClass("tablemode");
      $listmode.addClass("listmode");
    }
    else {
      // Cookie
      $.cookie("listmode", 1, {expires: 365});

      $listentries.addClass("listmode");
      $listmode.removeClass("listmode");
      $listmode.addClass("tablemode");
    }

  });

  /* ==========================================================================
     Cookie listmode
     ========================================================================== */

  if ( $.cookie("listmode") == 1 ) {
    $listentries.addClass("listmode");
    $listmode.removeClass("listmode");
    $listmode.addClass("tablemode");
  }

});
<|endoftext|>


<commit_before>// Template.listLimma

AutoForm.addHooks("createLimma", {
  onSuccess(formType, job_id) {
    FlowRouter.go("limmaJob", { job_id });
  },
});

Template.listLimma.onCreated(function () {
  let instance = this;

  // subscribe to the sample group data when the user selects a value type
  instance.autorun(() => {
    let valueType = AutoForm.getFieldValue("value_type", "createLimma");

    if (valueType) {
      instance.subscribe("limmaFormData", valueType);
    }
  });
});

Template.listLimma.helpers({
  createLimmaSchema() {
    // inherit allowed values from sample group allowed values
    let { allowedValues } = SampleGroups.simpleSchema().schema().value_type;

    return new SimpleSchema({
      value_type: {
        type: String,
        allowedValues,
        autoform: {
          options: _.map(allowedValues, (value) => {
            return {
              value,
              label: MedBook.utility.slugToString(value),
            };
          }),
        },
      },

      // name and version set server-side
      experimental_sample_group_id: {
        type: String,
        label: "Experimental group",
      },
      reference_sample_group_id: {
        type: String,
        label: "Reference group",
      },

      top_genes_count: { type: Number, min: 1 },
    });
  },
  loadingIfFalse(boolean) {
    if (!boolean) {
      return "loading";
    }

    // in order to show error messages
    return "warning";
  },
  sampleGroupOptions() {
    let value_type = AutoForm.getFieldValue("value_type", "createLimma");

    if (!value_type) {
      return false;
    }

    let cursor = SampleGroups.find({ value_type }, {
      sort: {
        name: 1,
        version: 1,
      }
    });

    return cursor.map((sampleGroup) => {
      return {
        value: sampleGroup._id,
        label: `${sampleGroup.name} (v${sampleGroup.version})`,
      };
    });
  },
  duplicateSamples() {
    // this should return true when a sample is selected both as a primary
    // and a progression tumor
    let primarySamples = AutoForm.getFieldValue("primary_sample_labels",
        "createLimma");
    let progressionSamples = AutoForm.getFieldValue("progression_sample_labels",
        "createLimma");

    if (primarySamples && progressionSamples) {
      let uniqueSamples = _.uniq(primarySamples.concat(progressionSamples));
      let selectedSampleCount = primarySamples.length + progressionSamples.length;

      return uniqueSamples.length !== selectedSampleCount;
    }
  },
  previousJobsCols() {
    return [
      {
        title: "Experimental group",
        func: function (job) {
          return job.args.experimental_sample_group_name +
              ` (v${job.args.experimental_sample_group_version})`;
        },
        fields: [
          "args.experimental_sample_group_name",
          "args.experimental_sample_group_version",
        ],
      },
      {
        title: "Reference group",
        func: function (job) {
          return job.args.reference_sample_group_name +
              ` (v${job.args.reference_sample_group_version})`;
        },
        fields: [
          "args.reference_sample_group_name",
          "args.reference_sample_group_version",
        ],
      },
      { title: "Top genes count", field: "args.top_genes_count" },
    ];
  },
});

// Template.limmaJob

Template.limmaJob.onCreated(function () {
  let instance = this;

  // subscribe and keep up to date
  instance.autorun(function () {
    instance.subscribe("specificJob", FlowRouter.getParam("job_id"));
  });
});

Template.limmaJob.helpers({
  getJobResultUrl: function(fileName) {
    let userId = Meteor.userId();
    let loginToken = Accounts._storedLoginToken();
    let jobId = FlowRouter.getParam("job_id");

    return `/download/${userId}/${loginToken}/job-blob/${jobId}/${fileName}`;
  },
  jobOptions() {
    return {
      job_id: FlowRouter.getParam("job_id"),
      title: "Limma Result",
      listRoute: "listLimma",
      argsTemplate: "limmaJobArgs",
    };
  },
});

Template.limmaJob.events({
  "click .run-gsea"(event, instance) {
    // pass the gene set to the modal via a query
    FlowRouter.setQueryParams({
      "geneSetIdForGsea": GeneSets.findOne()._id
    });
  },
  "click .voom-iframe-new-tab"(event, instance) {
    // open the current iFrame URL in a new tab: magic!
    window.open($("#voom-plot").contents().get(0).location.href, '_blank');
  },
  "click .mds-iframe-new-tab"(event, instance) {
    // open the current iFrame URL in a new tab: magic!
    window.open($("#mds-plot").contents().get(0).location.href, '_blank');
  },
});

// Template.limmaJobArgs

Template.limmaJobArgs.helpers({
  slugToString: MedBook.utility.slugToString,
});

// Template.showLimmaResult

Template.showLimmaResult.onCreated(function () {
  let instance = this;

  instance.subscribe("associatedObjectGeneSet", {
    collection_name: "Jobs",
    mongo_id: instance.data._id,
  });
});

Template.showLimmaResult.helpers({
  getGeneSet() {
    // it should be the only one loaded...
    return GeneSets.findOne();
  },
});
<commit_msg>Add default value type to standalone limma<commit_after>// Template.listLimma

AutoForm.addHooks("createLimma", {
  onSuccess(formType, job_id) {
    FlowRouter.go("limmaJob", { job_id });
  },
});

Template.listLimma.onCreated(function () {
  let instance = this;

  // subscribe to the sample group data when the user selects a value type
  instance.autorun(() => {
    let valueType = AutoForm.getFieldValue("value_type", "createLimma");

    if (valueType) {
      instance.subscribe("limmaFormData", valueType);
    }
  });
});

Template.listLimma.helpers({
  createLimmaSchema() {
    // inherit allowed values from sample group allowed values
    let { allowedValues } = SampleGroups.simpleSchema().schema().value_type;

    return new SimpleSchema({
      value_type: {
        type: String,
        allowedValues,
        autoform: {
          value: allowedValues[0],
          options: _.map(allowedValues, (value) => {
            return {
              value,
              label: MedBook.utility.slugToString(value),
            };
          }),
        },
      },

      // name and version set server-side
      experimental_sample_group_id: {
        type: String,
        label: "Experimental group",
      },
      reference_sample_group_id: {
        type: String,
        label: "Reference group",
      },

      top_genes_count: { type: Number, min: 1 },
    });
  },
  loadingIfFalse(boolean) {
    if (!boolean) {
      return "loading";
    }

    // in order to show error messages
    return "warning";
  },
  sampleGroupOptions() {
    let value_type = AutoForm.getFieldValue("value_type", "createLimma");

    if (!value_type) {
      return false;
    }

    let cursor = SampleGroups.find({ value_type }, {
      sort: {
        name: 1,
        version: 1,
      }
    });

    return cursor.map((sampleGroup) => {
      return {
        value: sampleGroup._id,
        label: `${sampleGroup.name} (v${sampleGroup.version})`,
      };
    });
  },
  duplicateSamples() {
    // this should return true when a sample is selected both as a primary
    // and a progression tumor
    let primarySamples = AutoForm.getFieldValue("primary_sample_labels",
        "createLimma");
    let progressionSamples = AutoForm.getFieldValue("progression_sample_labels",
        "createLimma");

    if (primarySamples && progressionSamples) {
      let uniqueSamples = _.uniq(primarySamples.concat(progressionSamples));
      let selectedSampleCount = primarySamples.length + progressionSamples.length;

      return uniqueSamples.length !== selectedSampleCount;
    }
  },
  previousJobsCols() {
    return [
      {
        title: "Experimental group",
        func: function (job) {
          return job.args.experimental_sample_group_name +
              ` (v${job.args.experimental_sample_group_version})`;
        },
        fields: [
          "args.experimental_sample_group_name",
          "args.experimental_sample_group_version",
        ],
      },
      {
        title: "Reference group",
        func: function (job) {
          return job.args.reference_sample_group_name +
              ` (v${job.args.reference_sample_group_version})`;
        },
        fields: [
          "args.reference_sample_group_name",
          "args.reference_sample_group_version",
        ],
      },
      { title: "Top genes count", field: "args.top_genes_count" },
    ];
  },
});

// Template.limmaJob

Template.limmaJob.onCreated(function () {
  let instance = this;

  // subscribe and keep up to date
  instance.autorun(function () {
    instance.subscribe("specificJob", FlowRouter.getParam("job_id"));
  });
});

Template.limmaJob.helpers({
  getJobResultUrl: function(fileName) {
    let userId = Meteor.userId();
    let loginToken = Accounts._storedLoginToken();
    let jobId = FlowRouter.getParam("job_id");

    return `/download/${userId}/${loginToken}/job-blob/${jobId}/${fileName}`;
  },
  jobOptions() {
    return {
      job_id: FlowRouter.getParam("job_id"),
      title: "Limma Result",
      listRoute: "listLimma",
      argsTemplate: "limmaJobArgs",
    };
  },
});

Template.limmaJob.events({
  "click .run-gsea"(event, instance) {
    // pass the gene set to the modal via a query
    FlowRouter.setQueryParams({
      "geneSetIdForGsea": GeneSets.findOne()._id
    });
  },
  "click .voom-iframe-new-tab"(event, instance) {
    // open the current iFrame URL in a new tab: magic!
    window.open($("#voom-plot").contents().get(0).location.href, '_blank');
  },
  "click .mds-iframe-new-tab"(event, instance) {
    // open the current iFrame URL in a new tab: magic!
    window.open($("#mds-plot").contents().get(0).location.href, '_blank');
  },
});

// Template.limmaJobArgs

Template.limmaJobArgs.helpers({
  slugToString: MedBook.utility.slugToString,
});

// Template.showLimmaResult

Template.showLimmaResult.onCreated(function () {
  let instance = this;

  instance.subscribe("associatedObjectGeneSet", {
    collection_name: "Jobs",
    mongo_id: instance.data._id,
  });
});

Template.showLimmaResult.helpers({
  getGeneSet() {
    // it should be the only one loaded...
    return GeneSets.findOne();
  },
});
<|endoftext|>


<commit_before>define([
	"dojo/_base/kernel",
	"dojo/_base/declare",
	"dojo/_base/array",
	"dojo/_base/lang",
	"dojo/dom",
	"dojo/on",
	"dojo/touch",
	"dojo/has",
	"../main"
], function(kernel, declare, array, lang, dom, on, touch, has, dojox){
	// module:
	//		dojox/gesture/Base
	// summary:
	//		This module provides an abstract parental class for various gesture implementations.

	kernel.experimental("dojox.gesture.Base");

	lang.getObject("gesture", true, dojox);

	// Declare an internal anonymous class which will only be exported by module return value
	// should be changed to "declare(null, {...});" once http://bugs.dojotoolkit.org/ticket/13890 is fixed
	return declare(" ", null, {
		// summary:
		//		An abstract parental class for various gesture implementations.
		//
		//		It's mainly responsible for:
		//
		//		1. Binding on() listening handlers for supported gesture events.
		//
		//		2. Monitoring underneath events and process different phases - 'press'|'move'|'release'|'cancel'.
		//
		//		3. Normalizing, dispatching and bubbling gesture events with on() API.
		//
		//		A gesture implementation only needs to extend this class and overwrite appropriate phase handlers
		//		- press()|move()|release()|cancel for recognizing and firing gestures
		//
		// example:
		//		1. A typical gesture implementation:
		//
		//		- Define dojox/gesture/a module which provides 3 gesture events:"a", "a.x", "a.y" to be used as:
		//
		//		|	dojo.connect(node, dojox.gesture.a, function(e){});
		//		|	dojo.connect(node, dojox.gesture.a.x, function(e){});
		//		|	dojo.connect(node, dojox.gesture.a.y, function(e){});
		//
		//		|	define([..., "./Base"], function(..., Base){
		//		|		var clz = declare(Base, {
		//		|			defaultEvent: "a",
		//		|
		//		|			subEvents: ["x", "y"],
		//		|
		//		|			press: function(data, e){
		//		|				this.fire(node, {type: "a.x", ...});
		//		|			},
		//		|			move: function(data, e){
		//		|				this.fire(node, {type: "a.y", ...});
		//		|			},
		//		|			release: function(data, e){
		//		|				this.fire(node, {type: "a", ...});
		//		|			},
		//		|			cancel: function(data, e){
		//		|				// clean up
		//		|			}
		//		|		});
		//		|
		//		|		// in order to have a default instance for handy use
		//		|		dojox.gesture.a = new clz();
		//		|
		//		|		// so that we can create new instances like
		//		|		// var mine = new dojox.gesture.a.A({/*parameters*/})
		//		|		dojox.gesture.a.A = clz;
		//		|
		//		|		return dojox.gesture.a;
		//		|	});
		//		|
		//		2. A gesture can be used in the following ways(taking dojox.gestre.tap for example):
		//		A. Used with dojo.connect()
		//		|	dojo.connect(node, dojox.gesture.tap, function(e){});
		//		|	dojo.connect(node, dojox.gesture.tap.hold, function(e){});
		//		|	dojo.connect(node, dojox.gesture.tap.doubletap, function(e){});
		//
		//		B. Used with dojo.on
		//		|	define(["dojo/on", "dojox/gesture/tap"], function(on, tap){
		//		|		on(node, tap, function(e){});
		//		|		on(node, tap.hold, function(e){});
		//		|		on(node, tap.doubletap, function(e){});
		//
		//		C. Used with dojox.gesture.tap.* directly
		//		|	dojox.gesture.tap(node, function(e){});
		//		|	dojox.gesture.tap.hold(node, function(e){});
		//		|	dojox.gesture.tap.doubletap(node, function(e){});
		//
		//		Though there is always a default gesture instance after being required, e.g
		//		|	require(["dojox/gesture/tap"], function(){...});
		//
		//		It's possible to create a new one with different parameter setting:
		//		|	var myTap = new dojox.gesture.tap.Tap({holdThreshold: 300});
		//		|	dojo.connect(node, myTap, function(e){});
		//		|	dojo.connect(node, myTap.hold, function(e){});
		//		|	dojo.connect(node, myTap.doubletap, function(e){});
		//
		//		Please refer to dojox/gesture/* for more gesture usages

		// defaultEvent: [readonly] String
		//		Default event e.g. 'tap' is a default event of dojox.gesture.tap
		defaultEvent: " ",

		// subEvents: [readonly] Array
		//		A list of sub events e.g ['hold', 'doubletap'],
		//		used by being combined with defaultEvent like 'tap.hold', 'tap.doubletap' etc.
		subEvents: [],

		// touchOnly: boolean
		//		Whether the gesture is touch-device only
		touchOnly : false,

		//	_elements: Array
		//		List of elements that wraps target node and gesture data
		_elements: null,

		/*=====
		// _lock: Dom
		//		The dom target(including all its descendant) that's being locked for processing
		_lock: null,

		// _events: [readonly] Array
		//		The complete list of supported gesture events with full name space
		//		e.g ['tap', 'tap.hold', 'tap.doubletap']
		_events: null,
		=====*/

		constructor: function(args){
			lang.mixin(this, args);
			this.init();
		},
		init: function(){
			// summary:
			//		Initialization works
			this._elements = [];

			if(!has("touch") && this.touchOnly){
				console.warn("Gestures:[", this.defaultEvent, "] is only supported on touch devices!");
				return;
			}

			// bind on() handlers for various events
			var evt = this.defaultEvent;
			this.call = this._handle(evt);

			this._events = [evt];
			array.forEach(this.subEvents, function(subEvt){
				this[subEvt] = this._handle(evt + '.' + subEvt);
				this._events.push(evt + '.' + subEvt);
			}, this);
		},
		_handle: function(/*String*/eventType){
			// summary:
			//		Bind listen handler for the given gesture event(e.g. 'tap', 'tap.hold' etc.)
			//		the returned handle will be used internally by dojo/on
			var self = this;
			//called by dojo/on
			return function(node, listener){
				// normalize, arguments might be (null, node, listener)
				var a = arguments;
				if(a.length > 2){
					node = a[1];
					listener = a[2];
				}
				var isNode = node && (node.nodeType || node.attachEvent || node.addEventListener);
				if(!isNode){
					return on(node, eventType, listener);
				}else{
					var onHandle = self._add(node, eventType, listener);
					// FIXME - users are supposed to explicitly call either
					// disconnect(signal) or signal.remove() to release resources
					var signal = {
						remove: function(){
							onHandle.remove();
							self._remove(node, eventType);
						}
					};
					return signal;
				}
			}; // dojo/on handle
		},
		_add: function(/*Dom*/node, /*String*/type, /*function*/listener){
			// summary:
			//		Bind dojo/on handlers for both gesture event(e.g 'tab.hold')
			//		and underneath 'press'|'move'|'release' events
			var element = this._getGestureElement(node);
			if(!element){
				// the first time listening to the node
				element = {
					target: node,
					data: {},
					handles: {}
				};

				var _press = lang.hitch(this, "_process", element, "press");
				var _move = lang.hitch(this, "_process", element, "move");
				var _release = lang.hitch(this, "_process", element, "release");
				var _cancel = lang.hitch(this, "_process", element, "cancel");

				var handles = element.handles;
				if(this.touchOnly){
					handles.press = on(node, 'touchstart', _press);
					handles.move = on(node, 'touchmove', _move);
					handles.release = on(node, 'touchend', _release);
					handles.cancel = on(node, 'touchcancel', _cancel);
				}else{
					handles.press = touch.press(node, _press);
					handles.move = touch.move(node, _move);
					handles.release = touch.release(node, _release);
					handles.cancel = touch.cancel(node, _cancel);
				}
				this._elements.push(element);
			}
			// track num of listeners for the gesture event - type
			// so that we can release element if no more gestures being monitored
			element.handles[type] = !element.handles[type] ? 1 : ++element.handles[type];

			return on(node, type, listener); //handle
		},
		_getGestureElement: function(/*Dom*/node){
			// summary:
			//		Obtain a gesture element for the give node
			var i = 0, element;
			for(; i < this._elements.length; i++){
				element = this._elements[i];
				if(element.target === node){
					return element;
				}
			}
		},
		_process: function(element, phase, e){
			// summary:
			//		Process and dispatch to appropriate phase handlers.
			//		Also provides the machinery for managing gesture bubbling.
			// description:
			//		1. e._locking is used to make sure only the most inner node
			//		will be processed for the same gesture, suppose we have:
			//	|	on(inner, dojox.gesture.tap, func1);
			//	|	on(outer, dojox.gesture.tap, func2);
			//		only the inner node will be processed by tap gesture, once matched,
			//		the 'tap' event will be bubbled up from inner to outer, dojo.StopEvent(e)
			//		can be used at any level to stop the 'tap' event.
			//
			//		2. Once a node starts being processed, all it's descendant nodes will be locked.
			//		The same gesture won't be processed on its descendant nodes until the lock is released.
			// element: Object
			//		Gesture element
			// phase: String
			//		Phase of a gesture to be processed, might be 'press'|'move'|'release'|'cancel'
			// e: Event
			//		Native event
			e._locking = e._locking || {};
			if(e._locking[this.defaultEvent] || this.isLocked(e.currentTarget)){
				return;
			}
			// invoking gesture.press()|move()|release()|cancel()
			e.preventDefault();
			e._locking[this.defaultEvent] = true;
			this[phase](element.data, e);
		},
		press: function(data, e){
			// summary:
			//		Process the 'press' phase of a gesture
		},
		move: function(data, e){
			// summary:
			//		Process the 'move' phase of a gesture
		},
		release: function(data, e){
			// summary:
			//		Process the 'release' phase of a gesture
		},
		cancel: function(data, e){
			// summary:
			//		Process the 'cancel' phase of a gesture
		},
		fire: function(node, event){
			// summary:
			//		Fire a gesture event and invoke registered listeners
			//		a simulated GestureEvent will also be sent along
			// node: DomNode
			//		Target node to fire the gesture
			// event: Object
			//		An object containing specific gesture info e.g {type: 'tap.hold'|'swipe.left'), ...}
			//		all these properties will be put into a simulated GestureEvent when fired.
			//		Note - Default properties in a native Event won't be overwritten, see on.emit() for more details.
			if(!node || !event){
				return;
			}
			event.bubbles = true;
			event.cancelable = true;
			on.emit(node, event.type, event);
		},
		_remove: function(/*Dom*/node, /*String*/type){
			// summary:
			//		Check and remove underneath handlers if node
			//		is not being listened for 'this' gesture anymore,
			//		this happens when user removed all previous on() handlers.
			var element = this._getGestureElement(node);
			if(!element || !element.handles){ return; }

			element.handles[type]--;

			var handles = element.handles;
			if(!array.some(this._events, function(evt){
				return handles[evt] > 0;
			})){
				// clean up if node is not being listened anymore
				this._cleanHandles(handles);
				var i = array.indexOf(this._elements, element);
				if(i >= 0){
					this._elements.splice(i, 1);
				}
			}
		},
		_cleanHandles: function(/*Object*/handles){
			// summary:
			//		Clean up on handles
			for(var x in handles){
				//remove handles for "press"|"move"|"release"|"cancel"
				if(handles[x].remove){
					handles[x].remove();
				}
				delete handles[x];
			}
		},
		lock: function(/*Dom*/node){
			// summary:
			//		Lock the node including all its descendant for processing.
			// tags:
			//		protected
			this._lock = node;
		},
		unLock: function(){
			// summary:
			//		Release the lock
			// tags:
			//		protected
			this._lock = null;
		},
		isLocked: function(node){
			// summary:
			//		Check if the node is locked, isLocked(node) means
			//		whether it's a descendant of the currently locked node.
			// tags:
			//		protected
			if(!this._lock || !node){
				return false;
			}
			return this._lock !== node && dom.isDescendant(node, this._lock);
		},
		destroy: function(){
			// summary:
			//		Release all handlers and resources
			array.forEach(this._elements, function(element){
				this._cleanHandles(element.handles);
			}, this);
			this._elements = null;
		}
	});
});<commit_msg>Refs #13828 !strict, 1 trivial comment wording for dojox/gesture/Base<commit_after>define([
	"dojo/_base/kernel",
	"dojo/_base/declare",
	"dojo/_base/array",
	"dojo/_base/lang",
	"dojo/dom",
	"dojo/on",
	"dojo/touch",
	"dojo/has",
	"../main"
], function(kernel, declare, array, lang, dom, on, touch, has, dojox){
	// module:
	//		dojox/gesture/Base
	// summary:
	//		This module provides an abstract parental class for various gesture implementations.

	kernel.experimental("dojox.gesture.Base");

	lang.getObject("gesture", true, dojox);

	// Declare an internal anonymous class which will only be exported by module return value
	// should be changed to "declare(null, {...});" once http://bugs.dojotoolkit.org/ticket/13890 is fixed
	return declare(" ", null, {
		// summary:
		//		An abstract parental class for various gesture implementations.
		//
		//		It's mainly responsible for:
		//
		//		1. Binding on() listening handlers for supported gesture events.
		//
		//		2. Monitoring underneath events and process different phases - 'press'|'move'|'release'|'cancel'.
		//
		//		3. Firing and bubbling gesture events with on() API.
		//
		//		A gesture implementation only needs to extend this class and overwrite appropriate phase handlers
		//		- press()|move()|release()|cancel for recognizing and firing gestures
		//
		// example:
		//		1. A typical gesture implementation:
		//
		//		- Define dojox/gesture/a module which provides 3 gesture events:"a", "a.x", "a.y" to be used as:
		//
		//		|	dojo.connect(node, dojox.gesture.a, function(e){});
		//		|	dojo.connect(node, dojox.gesture.a.x, function(e){});
		//		|	dojo.connect(node, dojox.gesture.a.y, function(e){});
		//
		//		|	define([..., "./Base"], function(..., Base){
		//		|		var clz = declare(Base, {
		//		|			defaultEvent: "a",
		//		|
		//		|			subEvents: ["x", "y"],
		//		|
		//		|			press: function(data, e){
		//		|				this.fire(node, {type: "a.x", ...});
		//		|			},
		//		|			move: function(data, e){
		//		|				this.fire(node, {type: "a.y", ...});
		//		|			},
		//		|			release: function(data, e){
		//		|				this.fire(node, {type: "a", ...});
		//		|			},
		//		|			cancel: function(data, e){
		//		|				// clean up
		//		|			}
		//		|		});
		//		|
		//		|		// in order to have a default instance for handy use
		//		|		dojox.gesture.a = new clz();
		//		|
		//		|		// so that we can create new instances like
		//		|		// var mine = new dojox.gesture.a.A({/*parameters*/})
		//		|		dojox.gesture.a.A = clz;
		//		|
		//		|		return dojox.gesture.a;
		//		|	});
		//		|
		//		2. A gesture can be used in the following ways(taking dojox.gestre.tap for example):
		//		A. Used with dojo.connect()
		//		|	dojo.connect(node, dojox.gesture.tap, function(e){});
		//		|	dojo.connect(node, dojox.gesture.tap.hold, function(e){});
		//		|	dojo.connect(node, dojox.gesture.tap.doubletap, function(e){});
		//
		//		B. Used with dojo.on
		//		|	define(["dojo/on", "dojox/gesture/tap"], function(on, tap){
		//		|		on(node, tap, function(e){});
		//		|		on(node, tap.hold, function(e){});
		//		|		on(node, tap.doubletap, function(e){});
		//
		//		C. Used with dojox.gesture.tap.* directly
		//		|	dojox.gesture.tap(node, function(e){});
		//		|	dojox.gesture.tap.hold(node, function(e){});
		//		|	dojox.gesture.tap.doubletap(node, function(e){});
		//
		//		Though there is always a default gesture instance after being required, e.g
		//		|	require(["dojox/gesture/tap"], function(){...});
		//
		//		It's possible to create a new one with different parameter setting:
		//		|	var myTap = new dojox.gesture.tap.Tap({holdThreshold: 300});
		//		|	dojo.connect(node, myTap, function(e){});
		//		|	dojo.connect(node, myTap.hold, function(e){});
		//		|	dojo.connect(node, myTap.doubletap, function(e){});
		//
		//		Please refer to dojox/gesture/* for more gesture usages

		// defaultEvent: [readonly] String
		//		Default event e.g. 'tap' is a default event of dojox.gesture.tap
		defaultEvent: " ",

		// subEvents: [readonly] Array
		//		A list of sub events e.g ['hold', 'doubletap'],
		//		used by being combined with defaultEvent like 'tap.hold', 'tap.doubletap' etc.
		subEvents: [],

		// touchOnly: boolean
		//		Whether the gesture is touch-device only
		touchOnly : false,

		//	_elements: Array
		//		List of elements that wraps target node and gesture data
		_elements: null,

		/*=====
		// _lock: Dom
		//		The dom target(including all its descendant) that's being locked for processing
		_lock: null,

		// _events: [readonly] Array
		//		The complete list of supported gesture events with full name space
		//		e.g ['tap', 'tap.hold', 'tap.doubletap']
		_events: null,
		=====*/

		constructor: function(args){
			lang.mixin(this, args);
			this.init();
		},
		init: function(){
			// summary:
			//		Initialization works
			this._elements = [];

			if(!has("touch") && this.touchOnly){
				console.warn("Gestures:[", this.defaultEvent, "] is only supported on touch devices!");
				return;
			}

			// bind on() handlers for various events
			var evt = this.defaultEvent;
			this.call = this._handle(evt);

			this._events = [evt];
			array.forEach(this.subEvents, function(subEvt){
				this[subEvt] = this._handle(evt + '.' + subEvt);
				this._events.push(evt + '.' + subEvt);
			}, this);
		},
		_handle: function(/*String*/eventType){
			// summary:
			//		Bind listen handler for the given gesture event(e.g. 'tap', 'tap.hold' etc.)
			//		the returned handle will be used internally by dojo/on
			var self = this;
			//called by dojo/on
			return function(node, listener){
				// normalize, arguments might be (null, node, listener)
				var a = arguments;
				if(a.length > 2){
					node = a[1];
					listener = a[2];
				}
				var isNode = node && (node.nodeType || node.attachEvent || node.addEventListener);
				if(!isNode){
					return on(node, eventType, listener);
				}else{
					var onHandle = self._add(node, eventType, listener);
					// FIXME - users are supposed to explicitly call either
					// disconnect(signal) or signal.remove() to release resources
					var signal = {
						remove: function(){
							onHandle.remove();
							self._remove(node, eventType);
						}
					};
					return signal;
				}
			}; // dojo/on handle
		},
		_add: function(/*Dom*/node, /*String*/type, /*function*/listener){
			// summary:
			//		Bind dojo/on handlers for both gesture event(e.g 'tab.hold')
			//		and underneath 'press'|'move'|'release' events
			var element = this._getGestureElement(node);
			if(!element){
				// the first time listening to the node
				element = {
					target: node,
					data: {},
					handles: {}
				};

				var _press = lang.hitch(this, "_process", element, "press");
				var _move = lang.hitch(this, "_process", element, "move");
				var _release = lang.hitch(this, "_process", element, "release");
				var _cancel = lang.hitch(this, "_process", element, "cancel");

				var handles = element.handles;
				if(this.touchOnly){
					handles.press = on(node, 'touchstart', _press);
					handles.move = on(node, 'touchmove', _move);
					handles.release = on(node, 'touchend', _release);
					handles.cancel = on(node, 'touchcancel', _cancel);
				}else{
					handles.press = touch.press(node, _press);
					handles.move = touch.move(node, _move);
					handles.release = touch.release(node, _release);
					handles.cancel = touch.cancel(node, _cancel);
				}
				this._elements.push(element);
			}
			// track num of listeners for the gesture event - type
			// so that we can release element if no more gestures being monitored
			element.handles[type] = !element.handles[type] ? 1 : ++element.handles[type];

			return on(node, type, listener); //handle
		},
		_getGestureElement: function(/*Dom*/node){
			// summary:
			//		Obtain a gesture element for the give node
			var i = 0, element;
			for(; i < this._elements.length; i++){
				element = this._elements[i];
				if(element.target === node){
					return element;
				}
			}
		},
		_process: function(element, phase, e){
			// summary:
			//		Process and dispatch to appropriate phase handlers.
			//		Also provides the machinery for managing gesture bubbling.
			// description:
			//		1. e._locking is used to make sure only the most inner node
			//		will be processed for the same gesture, suppose we have:
			//	|	on(inner, dojox.gesture.tap, func1);
			//	|	on(outer, dojox.gesture.tap, func2);
			//		only the inner node will be processed by tap gesture, once matched,
			//		the 'tap' event will be bubbled up from inner to outer, dojo.StopEvent(e)
			//		can be used at any level to stop the 'tap' event.
			//
			//		2. Once a node starts being processed, all it's descendant nodes will be locked.
			//		The same gesture won't be processed on its descendant nodes until the lock is released.
			// element: Object
			//		Gesture element
			// phase: String
			//		Phase of a gesture to be processed, might be 'press'|'move'|'release'|'cancel'
			// e: Event
			//		Native event
			e._locking = e._locking || {};
			if(e._locking[this.defaultEvent] || this.isLocked(e.currentTarget)){
				return;
			}
			// invoking gesture.press()|move()|release()|cancel()
			e.preventDefault();
			e._locking[this.defaultEvent] = true;
			this[phase](element.data, e);
		},
		press: function(data, e){
			// summary:
			//		Process the 'press' phase of a gesture
		},
		move: function(data, e){
			// summary:
			//		Process the 'move' phase of a gesture
		},
		release: function(data, e){
			// summary:
			//		Process the 'release' phase of a gesture
		},
		cancel: function(data, e){
			// summary:
			//		Process the 'cancel' phase of a gesture
		},
		fire: function(node, event){
			// summary:
			//		Fire a gesture event and invoke registered listeners
			//		a simulated GestureEvent will also be sent along
			// node: DomNode
			//		Target node to fire the gesture
			// event: Object
			//		An object containing specific gesture info e.g {type: 'tap.hold'|'swipe.left'), ...}
			//		all these properties will be put into a simulated GestureEvent when fired.
			//		Note - Default properties in a native Event won't be overwritten, see on.emit() for more details.
			if(!node || !event){
				return;
			}
			event.bubbles = true;
			event.cancelable = true;
			on.emit(node, event.type, event);
		},
		_remove: function(/*Dom*/node, /*String*/type){
			// summary:
			//		Check and remove underneath handlers if node
			//		is not being listened for 'this' gesture anymore,
			//		this happens when user removed all previous on() handlers.
			var element = this._getGestureElement(node);
			if(!element || !element.handles){ return; }

			element.handles[type]--;

			var handles = element.handles;
			if(!array.some(this._events, function(evt){
				return handles[evt] > 0;
			})){
				// clean up if node is not being listened anymore
				this._cleanHandles(handles);
				var i = array.indexOf(this._elements, element);
				if(i >= 0){
					this._elements.splice(i, 1);
				}
			}
		},
		_cleanHandles: function(/*Object*/handles){
			// summary:
			//		Clean up on handles
			for(var x in handles){
				//remove handles for "press"|"move"|"release"|"cancel"
				if(handles[x].remove){
					handles[x].remove();
				}
				delete handles[x];
			}
		},
		lock: function(/*Dom*/node){
			// summary:
			//		Lock the node including all its descendant for processing.
			// tags:
			//		protected
			this._lock = node;
		},
		unLock: function(){
			// summary:
			//		Release the lock
			// tags:
			//		protected
			this._lock = null;
		},
		isLocked: function(node){
			// summary:
			//		Check if the node is locked, isLocked(node) means
			//		whether it's a descendant of the currently locked node.
			// tags:
			//		protected
			if(!this._lock || !node){
				return false;
			}
			return this._lock !== node && dom.isDescendant(node, this._lock);
		},
		destroy: function(){
			// summary:
			//		Release all handlers and resources
			array.forEach(this._elements, function(element){
				this._cleanHandles(element.handles);
			}, this);
			this._elements = null;
		}
	});
});<|endoftext|>


<commit_before>/**
 * This function toggles the play/pause state of the jukebox.
 */
function playPause() {
    sendMsg({'cmd': 'playpause'}, function () {
        // success
    }, function () {
        // failure
        alert("Failed to play/pause");
    });
}

/**
 * This function toggles the play pause button. It is called by the websocket's onmessage function.
 */
function guiTogglePlayPause() {
    if ($("#playpause").html() == "Play") {
        $("#playpause").html("Pause");
    } else {
        $("#playpause").html("Play");
    }
}

/**
 * This function plays a specified video.
 * @param id The video
 */
function play(id) {
    $("#" + id).text("loading");
    $("#" + id).prop("disabled", true);
    sendMsg({'cmd': 'play', 'id': id}, function () {
    }, function (e) {
        alert("Failed to play video");
        $("#" + id).prop("disabled", false);
        $("#" + id).text("play");
    });
}

/**
 * This function adds a video to the playlist.
 * @param youtubeURL The video to add
 */
function addVideo(youtubeURL) {
    $("#videoUrl").prop("disabled", true);
    sendMsg({'cmd': 'add', 'uri': youtubeURL}, function (e) {
        $("#videoUrl").prop("disabled", false);
        $("#videoUrl").val("");
    }, function (e) {
        alert("Failed to add video");
        $("#videoUrl").prop("disabled", false);
        $("#videoUrl").val("");
    });
}

/**
 * This function increases the volume.
 */
function volUp() {
    sendMsg({'cmd': 'volup'}, function (e) {
        // success
    }, function (e) {
        // failure
        alert("Failed to increase volume");
    });
}

/**
 * This function decreases the volume.
 */
function volDown() {
    sendMsg({'cmd': 'voldn'}, function (e) {
        // success
    }, function (e) {
        // failure
        alert("Failed to decrease volume");
    });
}

/**
 * This function removes a video from the playlist.
 * @param id The video to remove
 */
function remove(id) {
    sendMsg({'cmd': 'remove', 'id': id}, function (e) {
        // success
    }, function (e) {
        // failure
        alert("Failed to remove video");
    });
}

//////

var sendMsg;

/**
 * Play a video in the playlist
 * @param ev The video to play
 */
function playlistPlay(ev) {
    play(ev.toElement.id);
}

/**
 * Update the HTML backing the playlist. Called by the websocket's onmessage function.
 * @param playlist the playlist.
 */
function guiUpdatePlaylist(playlist) {
    var $playlist = $("#playlist");
    $playlist.empty();
    var lis = [];
    playlist.forEach(function (elm, idx, arr) {
        var li = document.createElement("li");
        li.className = "playlist_elm";

        var button = document.createElement("button");
        button.id = elm.id;
        button.textContent = "play";
        button.onclick = playlistPlay;
        li.appendChild(button);

        var link = document.createElement("a");
        link.href = elm.uri;
        // wheeee no sanitization here
        link.textContent = elm.title;
        link.target = "_blank";
        li.appendChild(link);

        var close = document.createElement("button");
        button.textContent = "⛝";
        button.onClick = remove(elm.id);
        li.appendChild(close);
        lis.push(li);
    });
    $playlist.append(lis);
}

function guiUpdateVolume(vol) {
    $("#volume").text(vol + " %");
}

function guiUpdateCurrentlyPlaying(current) {
    if (current["current"] == null) return;
    $(".playlist_elm > button").prop('disabled', false).text("play");
    var id = "#" + current["current"];
    $(id).text("playing");
    $(id).prop("disabled", true);
}

function generalFail(req) {
    console.log("GENERAL FAIL ON REQUEST:", req);
}

$(document).ready(function () {
    if (!window.WebSocket) {
        alert("Do not have websockets! Boo you >:-(");
        return;
    }

    var ws = new WebSocket("ws://localhost:9000/rq");

    sendMsg = (function (ws) {
        var ws = ws;
        var rqid = 0;
        var wait = {};

        ws.onmessage = function (ev) {
            resp = JSON.parse(ev.data);
            if (resp["broadcast"] === true) {
                switch (resp["type"]) {
                    case "playlist":
                        guiUpdatePlaylist(resp["playlist"]);
                        break;
                    case "volume":
                        guiUpdateVolume(resp["value"]);
                        break;
                    case "playpause":
                        guiTogglePlayPause();
                        break;
                    case "current":
                        guiUpdateCurrentlyPlaying(resp);
                        break;
                    default:
                        console.log("BAD BROADCAST: ", resp);
                }
                return;
            }

            if (wait[resp["rqid"]] === undefined) {
                console.log("BAD MESSAGE:", resp);
                console.log(resp);
            }
            else {
                if (resp["status"] == false) {
                    wait[resp["rqid"]]["failure"](wait[resp["rqid"]]["request"]);
                }
                else {
                    wait[resp["rqid"]]["success"](resp);
                }
            }
        };

        return function (jsonMsg, success_call, fail_call) {
            jsonMsg["rqid"] = rqid;
            wait[rqid] = {
                "request": jsonMsg,
                "success": success_call,
                "failure": fail_call
            };
            rqid++;
            ws.send(JSON.stringify(jsonMsg));
        };
    })(ws);

    ws.onopen = function (ev) {
        console.log("WS Ready");
        sendMsg({"cmd": "playlist"}, function (e) {
            guiUpdatePlaylist(e["playlist"]);
        }, function (e) {
        });
        sendMsg({"cmd": "volume"}, function (e) {
            guiUpdateVolume(e["volume"]);
        }, function (e) {
        });
        sendMsg({"cmd": "current"}, function (e) {
            guiUpdateCurrentlyPlaying(e);
        }, function (e) {
        });
        sendMsg({"cmd": "ispaused"}, function (e) {
            $("#playpause").html(e.ispaused ? "Play" : "Pause");
        }, function (e) {
        });
    };

    $("#addVideo").on("click", function () {
        addVideo($("#videoUrl").val());
    });
});
<commit_msg>comments<commit_after>/**
 * This function toggles the play/pause state of the jukebox.
 */
function playPause() {
    sendMsg({'cmd': 'playpause'}, function () {
        // success
    }, function () {
        // failure
        alert("Failed to play/pause");
    });
}

/**
 * This function plays a specified video.
 * @param id The video
 */
function play(id) {
    $("#" + id).text("loading");
    $("#" + id).prop("disabled", true);
    sendMsg({'cmd': 'play', 'id': id}, function () {
    }, function (e) {
        alert("Failed to play video");
        $("#" + id).prop("disabled", false);
        $("#" + id).text("play");
    });
}

/**
 * This function adds a video to the playlist.
 * @param youtubeURL The video to add
 */
function addVideo(youtubeURL) {
    $("#videoUrl").prop("disabled", true);
    sendMsg({'cmd': 'add', 'uri': youtubeURL}, function (e) {
        $("#videoUrl").prop("disabled", false);
        $("#videoUrl").val("");
    }, function (e) {
        alert("Failed to add video");
        $("#videoUrl").prop("disabled", false);
        $("#videoUrl").val("");
    });
}

/**
 * This function increases the volume.
 */
function volUp() {
    sendMsg({'cmd': 'volup'}, function (e) {
        // success
    }, function (e) {
        // failure
        alert("Failed to increase volume");
    });
}

/**
 * This function decreases the volume.
 */
function volDown() {
    sendMsg({'cmd': 'voldn'}, function (e) {
        // success
    }, function (e) {
        // failure
        alert("Failed to decrease volume");
    });
}

/**
 * This function removes a video from the playlist.
 * @param id The video to remove
 */
function remove(id) {
    sendMsg({'cmd': 'remove', 'id': id}, function (e) {
        // success
    }, function (e) {
        // failure
        alert("Failed to remove video");
    });
}

//////

var sendMsg;

/**
 * Play a video in the playlist
 * @param ev The video to play
 */
function playlistPlay(ev) {
    play(ev.toElement.id);
}

/**
 * This function toggles the play pause button. It is called by the websocket's onmessage function.
 */
function guiTogglePlayPause() {
    if ($("#playpause").html() == "Play") {
        $("#playpause").html("Pause");
    } else {
        $("#playpause").html("Play");
    }
}

/**
 * Update the HTML backing the playlist. Called by the websocket's onmessage function.
 * @param playlist the playlist.
 */
function guiUpdatePlaylist(playlist) {
    var $playlist = $("#playlist");
    $playlist.empty();
    var list = [];
    playlist.forEach(function (elm, idx, arr) {
        var li = document.createElement("li");
        li.className = "playlist_elm";

        var button = document.createElement("button");
        button.id = elm.id;
        button.textContent = "play";
        button.onclick = playlistPlay;
        li.appendChild(button);

        var link = document.createElement("a");
        link.href = elm.uri;
        // wheeee no sanitization here
        link.textContent = elm.title;
        link.target = "_blank";
        li.appendChild(link);

        var close = document.createElement("button");
        button.textContent = "⛝";
        button.onClick = remove(elm.id);
        li.appendChild(close);

        list.push(li);
    });
    $playlist.append(list);
}

/**
 * Update the volume GUI. Called by the websocket's onmessage function.
 * @param vol The new volume
 */
function guiUpdateVolume(vol) {
    $("#volume").text(vol + " %");
}

/**
 * Update the currently playing GUI. Called by the websocket's onmessage function.
 * @param current The currently playing song.
 */
function guiUpdateCurrentlyPlaying(current) {
    if (current["current"] == null) return;
    $(".playlist_elm > button").prop('disabled', false).text("play");
    var id = "#" + current["current"];
    $(id).text("playing");
    $(id).prop("disabled", true);
}

$(document).ready(function () {
    if (!window.WebSocket) {
        alert("Do not have websockets! Boo you >:-(");
        return;
    }

    var ws = new WebSocket("ws://localhost:9000/rq");

    sendMsg = (function (ws) {
        var ws = ws;
        var rqid = 0;
        var wait = {};

        ws.onmessage = function (ev) {
            resp = JSON.parse(ev.data);
            if (resp["broadcast"] === true) {
                switch (resp["type"]) {
                    case "playlist":
                        guiUpdatePlaylist(resp["playlist"]);
                        break;
                    case "volume":
                        guiUpdateVolume(resp["value"]);
                        break;
                    case "playpause":
                        guiTogglePlayPause();
                        break;
                    case "current":
                        guiUpdateCurrentlyPlaying(resp);
                        break;
                    default:
                        console.log("BAD BROADCAST: ", resp);
                }
                return;
            }

            if (wait[resp["rqid"]] === undefined) {
                console.log("BAD MESSAGE:", resp);
                console.log(resp);
            }
            else {
                if (resp["status"] == false) {
                    wait[resp["rqid"]]["failure"](wait[resp["rqid"]]["request"]);
                }
                else {
                    wait[resp["rqid"]]["success"](resp);
                }
            }
        };

        return function (jsonMsg, success_call, fail_call) {
            jsonMsg["rqid"] = rqid;
            wait[rqid] = {
                "request": jsonMsg,
                "success": success_call,
                "failure": fail_call
            };
            rqid++;
            ws.send(JSON.stringify(jsonMsg));
        };
    })(ws);

    ws.onopen = function (ev) {
        console.log("WS Ready");
        sendMsg({"cmd": "playlist"}, function (e) {
            guiUpdatePlaylist(e["playlist"]);
        }, function (e) {
        });
        sendMsg({"cmd": "volume"}, function (e) {
            guiUpdateVolume(e["volume"]);
        }, function (e) {
        });
        sendMsg({"cmd": "current"}, function (e) {
            guiUpdateCurrentlyPlaying(e);
        }, function (e) {
        });
        sendMsg({"cmd": "ispaused"}, function (e) {
            $("#playpause").html(e.ispaused ? "Play" : "Pause");
        }, function (e) {
        });
    };

    $("#addVideo").on("click", function () {
        addVideo($("#videoUrl").val());
    });
});
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var pkg = require(path.resolve(process.cwd(), 'package.json'))

module.exports = function getDefaults () {
  var repoPath = pkg.repository.url.split('github.com/')[1].split('/')
  var owner = repoPath[0]
  var repo = repoPath[1].split('.git')[0]
  var logPath = path.resolve(process.cwd(), 'CHANGELOG.md')
  var log = fs.readFileSync(logPath, { encoding: 'utf-8' })
  var logVersion = log.split('## ')[1].split('\n')[0].split(' ')[0]

  if (logVersion !== pkg.version) {
    var err = 'CHANGELOG.md out of sync with package.json'
    err += '(' + logVersion + ' !== ' + pkg.version + ')'
    throw new Error(err)
  }

  return {
    tag_name: 'v' + pkg.version,
    target_commitish: 'master',
    name: 'v' + pkg.version,
    body: log.split('## ')[1].split('\n').slice(1).join('\n'),
    owner: owner,
    repo: repo,
    draft: false,
    prerelease: false
  }
}
<commit_msg>allow `v` prefix in changelog version names<commit_after>var fs = require('fs')
var path = require('path')
var pkg = require(path.resolve(process.cwd(), 'package.json'))

module.exports = function getDefaults () {
  var repoPath = pkg.repository.url.split('github.com/')[1].split('/')
  var owner = repoPath[0]
  var repo = repoPath[1].split('.git')[0]
  var logPath = path.resolve(process.cwd(), 'CHANGELOG.md')
  var log = fs.readFileSync(logPath, { encoding: 'utf-8' })
  var logVersion = log.split('## ')[1].split('\n')[0].split(' ')[0]

  if (logVersion.indexOf('v') === 0) logVersion = logVersion.slice(1)

  if (logVersion !== pkg.version) {
    var err = 'CHANGELOG.md out of sync with package.json'
    err += '(' + logVersion + ' !== ' + pkg.version + ')'
    throw new Error(err)
  }

  return {
    tag_name: 'v' + pkg.version,
    target_commitish: 'master',
    name: 'v' + pkg.version,
    body: log.split('## ')[1].split('\n').slice(1).join('\n'),
    owner: owner,
    repo: repo,
    draft: false,
    prerelease: false
  }
}
<|endoftext|>


<commit_before>define(['Ti/_', 'Ti/_/browser', 'Ti/_/Evented', 'Ti/_/lang', 'Ti/Locale', 'Ti/_/dom', 'Ti/UI'],
	function(_, browser, Evented, lang, Locale, dom, UI) {

	var doc = document,
		midName = 'ti:mid',
		matches = doc.cookie.match(new RegExp('(?:^|; )' + midName + '=([^;]*)')),
		mid = matches ? decodeURIComponent(matches[1]) : void 0,
		unloaded,
		on = require.on,
		hiddenIFrame = dom.create('iframe', { id: 'urlOpener', style: { display: 'none' } }, doc.body);
		//wifiNetworkPropertyValueChangeListenerId;

	mid || (mid = localStorage.getItem(midName));
	mid || localStorage.setItem(midName, mid = _.uuid());

	function saveMid() {
		if (!unloaded) {
			unloaded = 1;
			// expire cookie in 20 years... forever in mobile terms
			doc.cookie = midName + '=' + encodeURIComponent(mid) + '; expires=' + (new Date(Date.now() + 63072e7)).toUTCString();
			localStorage.setItem(midName, mid);
		}
	};

	// Do we need to unsubsctibe? Do we need ot call it anywhere?
	function deInitPlatformData(){
		if (wifiNetworkPropertyValueChangeListenerId != null)
			tizen.systeminfo.removePropertyValueChangeListener(wifiNetworkPropertyValueChangeListenerId);
	};

	// initialize values that should be initialized via fucntions with callbacks
	function initPlatformData() {
		var deviceCapabilities;

		//Default values for Device and Model
		Platform.constants.__values__.version = '2.0';
		Platform.constants.__values__.model = 'Tizen Device';

		//Get our application info.
		//Workaround for simulator. It throws exception because id is undefined. On Emulator works fine.
		try {
			Platform.constants.__values__.id = tizen.application.getAppInfo().id; //The unique ID for an installed application.
		} catch (e) {
			Platform.constants.__values__.id = 'ID001'; //The unique ID for an installed application.
		}

		//detect is WIFI exist, if yes we can find ip address
		deviceCapabilities = tizen.systeminfo.getCapabilities();
		if(deviceCapabilities.wifi) {
			tizen.systeminfo.getPropertyValue('WIFI_NETWORK', onSuccessWifiNetworkCallback, onErrorCallback);
			// subscribing to WiFi property changes
			 wifiNetworkPropertyValueChangeListenerId = tizen.systeminfo.addPropertyValueChangeListener('WIFI_NETWORK', onSuccessWifiNetworkCallback);
		}
	};

	function onErrorCallback(error) {
		Ti.API.error('An error occurred ' + error.message);
	};

	// Callback to update WiFi's IP address
	function onSuccessWifiNetworkCallback(wifiNetwork) {
		//receive SystemInfoWifiNetwork
		try{
			//console.log("wifiNetwork = "+JSON.stringify(wifiNetwork));
			if (wifiNetwork.status === 'ON') {
				Platform.constants.__values__.address = wifiNetwork.ipAddress;
			} else {
				Platform.constants.__values__.address = void 0;
			}
			Ti.API.info('Platform.address is set to ' + Platform.address);
		}
		catch (e) {
			Ti.API.error('Error on getting WifiNetwork info. Error: ' + e.message);
			Platform.constants.__values__.address = void 0;
		}
	}

	on(window, 'beforeunload', saveMid);
	on(window, 'unload', saveMid);

	var nav = navigator,
		battery = nav.battery || nav.webkitBattery || nav.mozBattery,
		deviceCapabilities = tizen.systeminfo.getCapabilities(),
		Platform = lang.setObject('Ti.Platform', Evented, {

			canOpenURL: function(url) {
				return !!url;
			},

			createUUID: _.uuid,

			is24HourTimeFormat: function() {
				return false;
			},

			openURL: function(url){
				if (/^([tel|sms|mailto])/.test(url)) {
					hiddenIFrame.contentWindow.location.href = url;
				} else {
					var win = UI.createWindow({
							layout: UI._LAYOUT_CONSTRAINING_VERTICAL,
							backgroundColor: '#888'
						}),
						backButton = UI.createButton({
							top: 2,
							bottom: 2,
							title: 'Close'
						}),
						webview = UI.createWebView({
							width: UI.FILL,
							height: UI.FILL
						});
					backButton.addEventListener('singletap', function(){
						win.close();
					});
					win.add(backButton);
					win.add(webview);
					win.open();
					setTimeout(function(){
						webview.url = url;
					}, 1);
				}
			},

			properties: {
				batteryMonitoring: false
			},

			constants: {
				BATTERY_STATE_CHARGING: 1,
				BATTERY_STATE_FULL: 2,
				BATTERY_STATE_UNKNOWN: -1,
				BATTERY_STATE_UNPLUGGED: 0,
				address: void 0,
				architecture: deviceCapabilities.platformCoreCpuArch,
				availableMemory: void 0,
				batteryLevel: function() {
					return this.batteryMonitoring && battery ? battery.level * 100 : -1;
				},
				batteryState: function() {
					return this.batteryMonitoring && battery && battery.charging ? this.BATTERY_STATE_CHARGING : this.BATTERY_STATE_UNKNOWN;
				},
				isBrowser: true,
				id: mid,
				locale: Locale,
				macaddress: void 0,
				model: nav.userAgent,
				name: deviceCapabilities.platformName,
				netmask: void 0,
				osname: 'tizen',
				ostype: nav.platform,
				runtime: browser.runtime,
				processorCount: void 0,
				username: void 0,
				version: deviceCapabilities.platformVersion
			}

		});

	battery && require.on(battery, 'chargingchange', function() {
		Platform.batteryMonitoring && Platform.fireEvent('battery', {
			level: Platform.batteryLevel,
			state: Platform.batteryState
		});
	});

	initPlatformData();
	return Platform;

});
<commit_msg>Added new properties to Ti.Platform from Tizen Sysinfo<commit_after>define(['Ti/_', 'Ti/_/browser', 'Ti/_/Evented', 'Ti/_/lang', 'Ti/Locale', 'Ti/_/dom', 'Ti/UI'],
	function(_, browser, Evented, lang, Locale, dom, UI) {

	var doc = document,
		midName = 'ti:mid',
		matches = doc.cookie.match(new RegExp('(?:^|; )' + midName + '=([^;]*)')),
		mid = matches ? decodeURIComponent(matches[1]) : void 0,
		unloaded,
		on = require.on,
		deviceCapabilities = tizen.systeminfo.getCapabilities(),
		hiddenIFrame = dom.create('iframe', { id: 'urlOpener', style: { display: 'none' } }, doc.body),
		wifiNetworkPropertyValueChangeListenerId, batteryValueChangeListenerId;

	mid || (mid = localStorage.getItem(midName));
	mid || localStorage.setItem(midName, mid = _.uuid());

	function saveMid() {
		if (!unloaded) {
			unloaded = 1;
			// expire cookie in 20 years... forever in mobile terms
			doc.cookie = midName + '=' + encodeURIComponent(mid) + '; expires=' + (new Date(Date.now() + 63072e7)).toUTCString();
			localStorage.setItem(midName, mid);
		}
	};

	// initialize values that should be initialized via fucntions with callbacks
	function initPlatformData() {
		//Get our application info.
		//Workaround for simulator. It throws exception because id is undefined. On Emulator works fine.
		try {
			Platform.constants.__values__.id = tizen.application.getAppInfo().id; //The unique ID for an installed application.
		} catch (e) {
			Platform.constants.__values__.id = 'ID001'; //The unique ID for an installed application.
		}

		if(deviceCapabilities.wifi) {
			tizen.systeminfo.getPropertyValue('WIFI_NETWORK', onSuccessWifiNetworkCallback, onErrorCallback);
			// subscribing to WiFi property changes
			wifiNetworkPropertyValueChangeListenerId = tizen.systeminfo.addPropertyValueChangeListener('WIFI_NETWORK', onSuccessWifiNetworkCallback);
		}

		// Get model property
		tizen.systeminfo.getPropertyValue('BUILD', onSuccessModelCallback, onErrorCallback);

		// Get battery info
		tizen.systeminfo.getPropertyValue('BATTERY', onSuccessBatteryCallback, onErrorCallback);
		batteryValueChangeListenerId = tizen.systeminfo.addPropertyValueChangeListener('BATTERY', onSuccessBatteryCallback);
	};

	function onErrorCallback(error) {
		Ti.API.error('An error occurred ' + error.message);
	};

	// Callback to update WiFi's IP address
	function onSuccessWifiNetworkCallback(wifiNetwork) {
		//receive SystemInfoWifiNetwork
		try {
			if (wifiNetwork.status === 'ON') {
				Platform.constants.__values__.address = wifiNetwork.ipAddress;
			} else {
				Platform.constants.__values__.address = void 0;
			}
			Ti.API.info('Platform.address is set to ' + Platform.address);
		} catch (e) {
			Ti.API.error('Error on getting WifiNetwork info. Error: ' + e.message);
			Platform.constants.__values__.address = void 0;
		}
	}

	// Callback to set Model
	function onSuccessModelCallback(build) {
		try {
			Platform.constants.__values__.model = build.model;
		} catch (e) {
			Ti.API.info('Error on getting model info. Error: ' + e.message);
			Platform.constants.__values__.model = void 0;
		}
	}

	function onSuccessBatteryCallback(battery) {
		try {
			Platform.constants.__values__.batteryMonitoring = true;
			Platform.constants.__values__.batteryLevel = battery.level * 100;
			Platform.constants.__values__.batteryState = battery.isCharging
				? Platform.BATTERY_STATE_CHARGING
				: (battery.level === 1 ? Platform.BATTERY_STATE_FULL : Platform.BATTERY_STATE_UNPLUGGED);
		} catch (e) {
			Ti.API.error('Error on getting battery info. Error: ' + e.message);
			Platform.constants.__values__.batteryMonitoring = false;
			Platform.constants.__values__.batteryLevel = void 0;
			Platform.constants.__values__.batteryState = Platform.BATTERY_STATE_UNKNOWN;
		}
	}

	on(window, 'beforeunload', saveMid);
	on(window, 'unload', saveMid);

	var nav = navigator,
		battery = nav.battery || nav.webkitBattery || nav.mozBattery,
		Platform = lang.setObject('Ti.Platform', Evented, {

			canOpenURL: function(url) {
				return !!url;
			},

			createUUID: _.uuid,

			is24HourTimeFormat: function() {
				return false;
			},

			openURL: function(url){
				if (/^([tel|sms|mailto])/.test(url)) {
					hiddenIFrame.contentWindow.location.href = url;
				} else {
					var win = UI.createWindow({
							layout: UI._LAYOUT_CONSTRAINING_VERTICAL,
							backgroundColor: '#888'
						}),
						backButton = UI.createButton({
							top: 2,
							bottom: 2,
							title: 'Close'
						}),
						webview = UI.createWebView({
							width: UI.FILL,
							height: UI.FILL
						});
					backButton.addEventListener('singletap', function(){
						win.close();
					});
					win.add(backButton);
					win.add(webview);
					win.open();
					setTimeout(function(){
						webview.url = url;
					}, 1);
				}
			},

			properties: {
				batteryMonitoring: false
			},

			constants: {
				BATTERY_STATE_CHARGING: 1,
				BATTERY_STATE_FULL: 2,
				BATTERY_STATE_UNKNOWN: -1,
				BATTERY_STATE_UNPLUGGED: 0,
				address: void 0,
				architecture: deviceCapabilities.platformCoreCpuArch,
				availableMemory: void 0,
				batteryLevel: void 0,
				batteryMonitoring: false,
				batteryState: void 0,
				isBrowser: true,
				id: mid,
				locale: Locale,
				macaddress: void 0,
				model: nav.userAgent,
				name: deviceCapabilities.platformName,
				netmask: void 0,
				osname: 'tizen',
				ostype: nav.platform,
				runtime: browser.runtime,
				processorCount: void 0,
				username: void 0,
				version: deviceCapabilities.platformVersion
			}

		});

	battery && require.on(battery, 'chargingchange', function() {
		Platform.batteryMonitoring && Platform.fireEvent('battery', {
			level: Platform.batteryLevel,
			state: Platform.batteryState
		});
	});

	initPlatformData();
	return Platform;

});
<|endoftext|>


<commit_before>// example of a simple object
var myFirstObject = {firstName: "Richard", favoriteAuthor: "Conrad"};

var ageGroup = {30: "Children", 100:"Very Old"};
console.log(ageGroup.30) // This will throw an error
// This is how you will access the value of the property 30, to get value "Children"
console.log(ageGroup["30"]); // Children

//It is best to avoid using numbers as property names.<commit_msg>adding ref and primitive datatypes in js<commit_after>// example of a simple object
var myFirstObject = {firstName: "Richard", favoriteAuthor: "Conrad"};

var ageGroup = {30: "Children", 100:"Very Old"};
console.log(ageGroup.30);
// This will throw an error
// This is how you will access the value of the property 30, to get value "Children"
console.log(ageGroup["30"]); // Children

//It is best to avoid using numbers as property names.

// Reference and Primitive datatypes.
// The primitive data type String is stored as a value
var person = "Kobe";
var anotherPerson = person; // anotherPerson = the value of person
person = "Bryant"; // value of person changed

console.log(anotherPerson); // Kobe
console.log(person); // Bryant<|endoftext|>


<commit_before>// getConfig.js - Create a JSON file with the db2 table name and columns
// to be used with the xlsx2db application
const opts = require('commander')

opts
  .version('1.0.0')
  .description(`Create a JSON file of a DB2 table and column configuration.
     Intended for use with the xls2db project.`)
  .option('--schema <name>', 'DB2 schema')
  .option('--table <name>', 'DB2 table name')
  .parse(process.argv)

var db = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/db2i/lib/db2a')
var cfg = {
  schema : opts.schema,
  table : opts.table
}
var dbconn = new db.dbconn(); // Create a connection object.
dbconn.conn("*LOCAL")
var stmt = new db.dbstmt(dbconn)
var SQLstmt =
  `select ORDINAL_POSITION -1 as col, COLUMN_NAME as name, TYPE_NAME as type,
   COLUMN_SIZE as len, DECIMAL_DIGITS as Decimal, NULLABLE
   from sysibm.sqlcolumns
   where table_schem = '${cfg.schema}' and table_name = '${cfg.table}'`

stmt.exec(SQLstmt, function(cols) {
  cfg.cols = cols
  var fsOut = require('fs').createWriteStream(cfg.table + '.json')
  fsOut.write(JSON.stringify(cfg), function() {
    fsOut.end
    stmt.close()      // Clean up the statement object.
    dbconn.disconn()  // Disconnect from the database.
    dbconn.close()    // Clean up the connection object.
  })
})
<commit_msg>Check for no cols returned and throw error<commit_after>// getConfig.js - Create a JSON file with the db2 table name and columns
// to be used with the xlsx2db application
var opts = require('commander')
opts
  .version('1.0.0')
  .description(`Gets the columns from a DB2 database and writes them to
    a JSON file with the same name as the table`)
  .option('--schema <string>', 'database schema name (library)')
  .option('--table <string>','database table name')
  .parse(process.argv)

cfg = {
  schema: opts.schema,
  table: opts.table
}
var db = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/db2i/lib/db2a')

var dbconn = new db.dbconn(); // Create a connection object.
dbconn.conn("*LOCAL")
var stmt = new db.dbstmt(dbconn)
var SQLstmt =
  `select ORDINAL_POSITION -1 as col, COLUMN_NAME as name, TYPE_NAME as type,
   COLUMN_SIZE as len, DECIMAL_DIGITS as Decimal, NULLABLE
   from sysibm.sqlcolumns
   where table_schem = UPPER('${cfg.schema}') and
   table_name = UPPER('${cfg.table}')`

stmt.execSync(SQLstmt, function(cols) {
  if (cols.length  == 0) {
    throw new Error(`No data returned for ${cfg.schema}, table ${cfg.table}`)
  }
  cfg.cols = cols
  var fsOut = require('fs').createWriteStream(cfg.table + '.json')
  fsOut.write(JSON.stringify(cfg,null,'  '), function() {
    fsOut.end
    stmt.close() // Clean up the statement object.
    dbconn.disconn() // Disconnect from the database.
    dbconn.close() // Clean up the connection object.
  })
})
<|endoftext|>