<commit_before>/**
 * @fileoverview Template generator will create the full HTML template for the reporter based on the results and options passed in.
 * The code in this file is based on the code written by Julian Laval for eslint's default reporter
 * and inspired by Sven Piller's eslint-formatter-markdown
 * @author Marcelo S. Portugal <marceloquarion@gmail.com>
 */
'use strict';

const _ = require('lodash'),
	fs = require('fs'),
	path = require('path');

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const styles = _.template(fs.readFileSync(path.join(__dirname, 'helpers/styles.html'), 'utf-8')),
	scripts = _.template(fs.readFileSync(path.join(__dirname, 'helpers/scripts.html'), 'utf-8')),
	pageTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/main-page.html'), 'utf-8')),
	resultTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/details/result.html'), 'utf-8')),
	resultDetailsTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/details/details.html'), 'utf-8')),
	resultSummaryTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/details/summary.html'), 'utf-8')),
	codeWrapperTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/details/code/code-wrapper.html'), 'utf-8')),
	codeTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/details/code/code.html'), 'utf-8')),
	issueTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/details/code/issue.html'), 'utf-8')),
	summaryDetailsTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/summary/summary-details.html'), 'utf-8')),
	rulesTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/summary/rules.html'), 'utf-8')),
	mostProblemsTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/summary/most-problems.html'), 'utf-8')),
	filesTemplate = _.template(fs.readFileSync(path.join(__dirname, 'templates/summary/files.html'), 'utf-8'));

/**
 * Given a word and a count, append an s if count is not one.
 * @param {string} word A word in its singular form.
 * @param {int} count A number controlling whether word should be pluralized.
 * @returns {string} The original word with an s on the end if count is not one.
 */
function pluralize(word, count) {
	return (count === 1 ? word : `${word}s`);
}

/**
 * Renders text along the template of x problems (x errors, x warnings)
 * @param {int} totalErrors Total errors
 * @param {int} totalWarnings Total warnings
 * @returns {string} The formatted string, pluralized where necessary
 */
function renderSummary(totalErrors, totalWarnings) {
	const totalProblems = totalErrors + totalWarnings;
	let renderedText = `${totalProblems} ${pluralize('problem', totalProblems)}`;

	if (totalProblems !== 0) {
		renderedText += ` (${totalErrors} ${pluralize('error', totalErrors)}, ${totalWarnings} ${pluralize('warning', totalWarnings)})`;
	}
	return renderedText;
}

/**
 * Takes in a rule Id and returns the correct link for the description
 * @param {string} ruleId A eslint rule Id
 * @return {string} The link to the rules description
 */
function getRuleLink(ruleId) {
	let ruleLink = `http://eslint.org/docs/rules/${ruleId}`;

	if (_.startsWith(ruleId, 'angular')) {
		ruleId = ruleId.replace('angular/', '');
		ruleLink = `https://github.com/Gillespie59/eslint-plugin-angular/blob/master/docs/${ruleId}.md`;
	} else if (_.startsWith(ruleId, 'lodash')) {
		ruleId = ruleId.replace('lodash/', '');
		ruleLink = `https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/${ruleId}.md`;
	}
	return ruleLink;
}

/**
 * Generates the summary details section by only including the necessary tables.
 * @param {object} rules An object with all of the rules sorted by type
 * @param {array} [problemFiles] An optional object with the top 5 worst files being linted
 * @param {String} currDir Current working directory
 * @return {string} HTML string of all the summary detail tables that are needed
 */
function renderSummaryDetails(rules, problemFiles, currDir) {
	let summaryDetails = '
';

	// errors exist
	if (rules['2']) {
		summaryDetails += summaryDetailsTemplate({
			ruleType: 'error',
			topRules: renderRules(rules['2'])
		});
	}

	// warnings exist
	if (rules['1']) {
		summaryDetails += summaryDetailsTemplate({
			ruleType: 'warning',
			topRules: renderRules(rules['1'])
		});
	}

	summaryDetails += '
';

	// files with problems exist
	if (!_.isEmpty(problemFiles)) {
		summaryDetails += mostProblemsTemplate({
			files: renderProblemFiles(problemFiles, currDir)
		});
	}

	return summaryDetails;
}

/**
 * Get the color based on whether there are errors/warnings...
 * @param {int} totalErrors Total errors
 * @param {int} totalWarnings Total warnings
 * @returns {string} The color code (success = green, warning = yellow, error = red)
 */
function renderColor(totalErrors, totalWarnings) {
	if (totalErrors !== 0) {
		return severityString(2);
	} else if (totalWarnings !== 0) {
		return severityString(1);
	}
	return severityString(0);
}

/**
 * Converts the severity number to a string
 * @param {int} severity severity number
 * @returns {string} The color string based on severity number (0 = success, 1 = warning, 2 = error)
 */
function severityString(severity) {
	const colors = ['success', 'warning', 'error'];

	return colors[severity];
}

/**
 * Renders an issue
 * @param {object} message a message object with an issue
 * @returns {string} HTML string of an issue
 */
function renderIssue(message) {
	return issueTemplate({
		severity: severityString(message.severity),
		severityName: message.severity === 1 ? 'Warning' : 'Error',
		lineNumber: message.line,
		column: message.column,
		message: message.message,
		ruleId: message.ruleId,
		ruleLink: getRuleLink(message.ruleId)
	});
}

/**
 * Renders the source code for the files that have issues and marks the lines that have problems
 * @param {string} sourceCode source code string
 * @param {array} messages array of messages with the problems in a file
 * @param {int} parentIndex file index
 * @returns {string} HTML string of the code file that is being linted
 */
function renderSourceCode(sourceCode, messages, parentIndex) {
	return codeWrapperTemplate({
		parentIndex,
		sourceCode: _.map(sourceCode.split('\n'), function(code, lineNumber) {
			const lineMessages = _.filter(messages, {line: lineNumber + 1}),
				severity = _.get(lineMessages[0], 'severity') || 0;

			let template = '';

			// checks if there is a problem on the current line and renders it
			if (!_.isEmpty(lineMessages)) {
				template += _.map(lineMessages, renderIssue).join('');
			}

			// adds a line of code to the template (with line number and severity color if appropriate
			template += codeTemplate({
				lineNumber: lineNumber + 1,
				code,
				severity: severityString(severity)
			});

			return template;
		}).join('\n')
	});
}

/**
 * Renders the result details with tabs for source code and a summary
 * @param {string} sourceCode source code string
 * @param {array} messages array of messages with the problems in a file
 * @param {int} parentIndex file index
 * @returns {string} HTML string of result details
 */
function renderResultDetails(sourceCode, messages, parentIndex) {
	const topIssues = messages.length < 10 ? '' : _.groupBy(messages, 'severity');

	return resultDetailsTemplate({
		parentIndex,
		sourceCode: renderSourceCode(sourceCode, messages, parentIndex),
		detailSummary: resultSummaryTemplate({
			topIssues: renderSummaryDetails(topIssues),
			issues: _.map(messages, renderIssue).join('')
		})
	});
}

/**
 * Formats the source code before adding it to the HTML
 * @param {string} sourceCode Source code string
 * @returns {string} Source code string which will not cause issues in the HTML
 */
function formatSourceCode(sourceCode) {
	return sourceCode.replace(/</g, '<').replace(/>/g, '>');
}

/**
 * Creates the test results HTML
 * @param {Array} results Test results.
 * @param {String} currDir Current working directory
 * @returns {string} HTML string describing the results.
 */
function renderResults(results, currDir) {
	return _.map(results, function(result, index) {
		let template = resultTemplate({
			index,
			fileId: _.camelCase(result.filePath),
			filePath: result.filePath.replace(currDir, ''),
			color: renderColor(result.errorCount, result.warningCount),
			summary: renderSummary(result.errorCount, result.warningCount),
			problemCount: result.errorCount + result.warningCount
		});

		// only renders the source code if there are issues present in the file
		if (!_.isEmpty(result.messages)) {
			// reads the file to get the source code if the source is not provided
			const sourceCode = formatSourceCode(result.source || fs.readFileSync(result.filePath, 'utf8'));

			template += renderResultDetails(sourceCode, result.messages, index);
		}

		return template;
	}).join('\n');
}

/**
 * @param {Array} rules Test rules.
 * @returns {string} HTML string describing the rules.
 */
function renderRules(rules) {
	return _(rules).groupBy('ruleId').map(function(ruleMessages, ruleId) {
		return {
			ruleId,
			ruleCount: _.size(ruleMessages),
			ruleLink: getRuleLink(ruleId)
		};
	}).orderBy(['ruleCount'], ['desc']).take(5).map(rulesTemplate).value().join('\n');
}

/**
 * Renders list of problem files
 * @param {array} files
 * @param {String} currDir Current working directory
 * @return {string} HTML string describing the files.
 */
function renderProblemFiles(files, currDir) {
	return _.map(files, function(fileDetails) {
		return filesTemplate({
			fileId: _.camelCase(fileDetails.filePath),
			filePath: fileDetails.filePath.replace(currDir, ''),
			errorCount: fileDetails.errorCount,
			warningCount: fileDetails.warningCount
		});
	}).join('\n');
}

/**
 * Writes a file at the specified location and removes the specified strings
 * @param {string} filePath The path of the new file
 * @param {string} fileContent The contents of the new file
 * @param {RegExp} regex A regex with strings to be removed from the fileContent
 * @return {void} n/a
 */
function writeFile(filePath, fileContent, regex) {
	fs.writeFileSync(filePath, fileContent.replace(regex, ''));
}

/**
 * Returns the output directory for the report
 * @return {String} the output directory for the report
 */
function getOutputDir() {
	const outputOptionIdx = process.argv.indexOf('-o') !== -1 ? process.argv.indexOf('-o') : process.argv.indexOf('--output-file'),
		argsLength = process.argv.length,
		outputDirOption = '--outputDirectory=';

	if (process.argv[1].includes('grunt')) {
		for (var i = 2; i < argsLength; i++) {
			if (process.argv[i].includes(outputDirOption)) {
				return '/' + process.argv[i].replace(outputDirOption, '');
			}
		}
		return '/reports/'; // defaults to a reports folder if nothing else is found
	} else if (outputOptionIdx !== -1) {
		return '/' + process.argv[outputOptionIdx + 1].split('/')[0] + '/';
	}

	return '';
}

/**
 * Returns the full path to the report
 * @param currWorkingDir
 * @return {string} the full path to the report
 */
function getOutputPath(currWorkingDir) {
	return currWorkingDir + getOutputDir();
}

/**
 * Creates a styles.css and a main.js file for the report
 * @param {string} currWorkingDir The current working directory
 */
function buildScriptsAndStyleFiles(currWorkingDir) {
	const outputPath = getOutputPath(currWorkingDir),
		stylesRegex = /


<commit_before>/**
 * Nextcloud - passman
 *
 * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

(function () {
	'use strict';

	/**
	 * @ngdoc directive
	 * @name passmanApp.directive:passwordGen
	 * @description
	 * # passwordGen
	 */
	angular.module('passmanApp')
		.directive('otpGenerator', ['$compile', '$timeout',
			function ($compile, $timeout) {
				function dec2hex (s) {
					return (s < 15.5 ? '0' : '') + Math.round(s).toString(16);
				}

				function hex2dec (s) {
					return parseInt(s, 16);
				}

				function base32tohex (base32) {
					if (!base32) {
						return;
					}
					var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
					var bits = "";
					var hex = "";
					var i;
					for (i = 0; i < base32.length; i++) {
						var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
						bits += leftpad(val.toString(2), 5, '0');
					}

					for (i = i % 8; i > 0; i--) {
						bits += leftpad('0', 5, '0');
					}

					for (i = 0; i + 4 <= bits.length; i += 4) {
						var chunk = bits.substr(i, 4);
						hex = hex + parseInt(chunk, 2).toString(16);
					}
					return hex;

				}

				function leftpad (str, len, pad) {
					if (len + 1 >= str.length) {
						str = Array(len + 1 - str.length).join(pad) + str;
					}
					return str;
				}

				return {
					restrict: 'A',
					template: ' ',
					transclude: false,
					scope: {
						secret: '='
					},
					replace: true,
					link: function (scope) {
						scope.otp = null;
						scope.timeleft = null;
						scope.timer = null;
						var updateOtp = function () {
							if (!scope.secret) {
								return;
							}
							var key = base32tohex(scope.secret);
							var epoch = Math.round(new Date().getTime() / 1000.0);
							var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0');
							/** global: jsSHA */
							var hmacObj = new jsSHA(time, 'HEX');
							var hmac = hmacObj.getHMAC(key, 'HEX', 'SHA-1', "HEX");
							var offset = hex2dec(hmac.substring(hmac.length - 1));
							var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) + '';
							otp = (otp).substr(otp.length - 6, 6);
							scope.otp = otp;

						};

						var timer = function () {
							var epoch = Math.round(new Date().getTime() / 1000.0);
							var countDown = 30 - (epoch % 30);
							if (epoch % 30 === 0) updateOtp();
							scope.timeleft = countDown;
							scope.timer = $timeout(timer, 1000);

						};
						scope.$watch("secret", function (n) {
							if (n) {
								$timeout.cancel(scope.timer);
								updateOtp();
								timer();
							} else {
								$timeout.cancel(scope.timer);
							}
						}, true);
						scope.$on(
							"$destroy",
							function () {
								$timeout.cancel(scope.timer);
							}
						);
					}
				};
			}
		]);
}());<commit_msg>Fix 16 Bits Codes<commit_after>/**
 * Nextcloud - passman
 *
 * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

(function () {
	'use strict';

	/**
	 * @ngdoc directive
	 * @name passmanApp.directive:passwordGen
	 * @description
	 * # passwordGen
	 */
	angular.module('passmanApp')
		.directive('otpGenerator', ['$compile', '$timeout',
			function ($compile, $timeout) {
				function dec2hex (s) {
					return (s < 15.5 ? '0' : '') + Math.round(s).toString(16);
				}

				function hex2dec (s) {
					return parseInt(s, 16);
				}

				function base32tohex (base32) {
					if (!base32) {
						return;
					}
					var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
					var bits = "";
					var hex = "";
					var i;
					for (i = 0; i < base32.length; i++) {
						var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
						bits += leftpad(val.toString(2), 5, '0');
					}

					for (i = 0; i + 4 <= bits.length; i += 4) {
						var chunk = bits.substr(i, 4);
						hex = hex + parseInt(chunk, 2).toString(16);
					}
					return hex.length % 2 ? hex + "0" : hex;

				}

				function leftpad (str, len, pad) {
					if (len + 1 >= str.length) {
						str = Array(len + 1 - str.length).join(pad) + str;
					}
					return str;
				}

				return {
					restrict: 'A',
					template: ' ',
					transclude: false,
					scope: {
						secret: '='
					},
					replace: true,
					link: function (scope) {
						scope.otp = null;
						scope.timeleft = null;
						scope.timer = null;
						var updateOtp = function () {
							if (!scope.secret) {
								return;
							}
							var key = base32tohex(scope.secret);
							var epoch = Math.round(new Date().getTime() / 1000.0);
							var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0');
							/** global: jsSHA */
							var hmacObj = new jsSHA(time, 'HEX');
							var hmac = hmacObj.getHMAC(key, 'HEX', 'SHA-1', "HEX");
							var offset = hex2dec(hmac.substring(hmac.length - 1));
							var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) + '';
							otp = (otp).substr(otp.length - 6, 6);
							scope.otp = otp;

						};

						var timer = function () {
							var epoch = Math.round(new Date().getTime() / 1000.0);
							var countDown = 30 - (epoch % 30);
							if (epoch % 30 === 0) updateOtp();
							scope.timeleft = countDown;
							scope.timer = $timeout(timer, 1000);

						};
						scope.$watch("secret", function (n) {
							if (n) {
								$timeout.cancel(scope.timer);
								updateOtp();
								timer();
							} else {
								$timeout.cancel(scope.timer);
							}
						}, true);
						scope.$on(
							"$destroy",
							function () {
								$timeout.cancel(scope.timer);
							}
						);
					}
				};
			}
		]);
}());
<|endoftext|>


<commit_before>const { Observable } = require("rxjs");

const POSITION_UPDATES_INTERVAL = 100;

/**
 * Add event listeners to the RxPlayer to update the module's state at the right
 * time.
 * Unsubscribe when $destroy emit.
 * @param {RxPlayer} player
 * @param {Subject} state
 * @param {Subject} $destroy
 */
const linkPlayerEventsToState = (player, state, $destroy) => {
  const fromPlayerEvent = (event) =>
    Observable.create(obs => {
      const func = (payload) => obs.next(payload);
      player.addEventListener(event, func);

      return () => {
        player.removeEventListener(event, func);
      };
    });

  const linkPlayerEventToState = (event, stateItem) =>
    fromPlayerEvent(event)
      .takeUntil($destroy)
      .subscribe(arg => state.set({ [stateItem]: arg }));

  linkPlayerEventToState("subtitleChange", "subtitle");
  linkPlayerEventToState("languageChange", "language");
  linkPlayerEventToState("videoBitrateChange", "videoBitrate");
  linkPlayerEventToState("audioBitrateChange", "audioBitrate");
  linkPlayerEventToState("error", "error");
  linkPlayerEventToState("fullscreenChange", "isFullscreen");
  linkPlayerEventToState("volumeChange", "volume");

  player.getImageTrack()
    .takeUntil($destroy)
    .subscribe(images => state.set({ images }));

  // use an interval for current position
  // TODO Only active for content playback
  Observable
    .interval(POSITION_UPDATES_INTERVAL)
    .map(() => ({
      currentTime: player.getWallClockTime() / 1000,
      bufferGap: player.getVideoLoadedTime() - player.getVideoPlayedTime(),
      duration: player.getVideoDuration(),
    }))
    .takeUntil($destroy)
    .subscribe(arg => {
      state.set(arg);
    });

  fromPlayerEvent("playerStateChange")
    .distinctUntilChanged()
    .takeUntil($destroy)
    .subscribe((arg) => {
      const stateUpdates = {
        hasEnded: arg === "ENDED",
        hasLoadedContent: !["STOPPED", "LOADING"].includes(arg),
        isBuffering: arg === "BUFFERING",
        isLoading: arg === "LOADING",
        isSeeking: arg === "SEEKING",
        isStopped: arg === "STOPPED",
        speed: arg === "PLAYING" ? player.getPlaybackRate() : 0,
      };

      if (arg === "PAUSED") {
        stateUpdates.isPaused = true;
      } else if (arg === "PLAYING") {
        stateUpdates.isPaused = false;
      } else if (arg === "LOADED") {
        stateUpdates.availableAudioBitrates =
          player.getAvailableAudioBitrates();
        stateUpdates.availableVideoBitrates =
          player.getAvailableVideoBitrates();
        stateUpdates.availableLanguages =
          player.getAvailableAudioTracks();
        stateUpdates.availableSubtitles =
          player.getAvailableTextTracks();
      } else if (arg === "STOPPED" || arg === "ENDED") {
        stateUpdates.audioBitrate = undefined;
        stateUpdates.videoBitrate = undefined;
        stateUpdates.availableAudioBitrates = [];
        stateUpdates.availableVideoBitrates = [];
        stateUpdates.availableLanguages = [];
        stateUpdates.availableSubtitles = [];
      }

      if (arg !== "STOPPED") {
        // error is never cleaned up
        stateUpdates.error = null;
      }

      state.set(stateUpdates);
    });

  player.getMetrics()
    .takeUntil($destroy)
    // .map((metric) => metric.value.response)
    // .filter((response) => response.size > 2000)
    .subscribe((metric = {}) => {
      const { response } = metric.value;
      if (response && response.size > 10000) {
        state.set({
          bandwidth: (response.size / response.duration) * 0.008, // in mbps
        });
      }
    });

  fromPlayerEvent("manifestChange")
    .map(() => player.isLive())
    .distinctUntilChanged()
    .takeUntil($destroy)
    .subscribe((isLive) => {
      state.set({ isLive });
    });
};

module.exports = {
  linkPlayerEventsToState,
};
<commit_msg>demo: fix time reporting<commit_after>const { Observable } = require("rxjs");

const POSITION_UPDATES_INTERVAL = 100;

/**
 * Add event listeners to the RxPlayer to update the module's state at the right
 * time.
 * Unsubscribe when $destroy emit.
 * @param {RxPlayer} player
 * @param {Subject} state
 * @param {Subject} $destroy
 */
const linkPlayerEventsToState = (player, state, $destroy) => {
  const fromPlayerEvent = (event) =>
    Observable.create(obs => {
      const func = (payload) => obs.next(payload);
      player.addEventListener(event, func);

      return () => {
        player.removeEventListener(event, func);
      };
    });

  const linkPlayerEventToState = (event, stateItem) =>
    fromPlayerEvent(event)
      .takeUntil($destroy)
      .subscribe(arg => state.set({ [stateItem]: arg }));

  linkPlayerEventToState("subtitleChange", "subtitle");
  linkPlayerEventToState("languageChange", "language");
  linkPlayerEventToState("videoBitrateChange", "videoBitrate");
  linkPlayerEventToState("audioBitrateChange", "audioBitrate");
  linkPlayerEventToState("error", "error");
  linkPlayerEventToState("fullscreenChange", "isFullscreen");
  linkPlayerEventToState("volumeChange", "volume");

  player.getImageTrack()
    .takeUntil($destroy)
    .subscribe(images => state.set({ images }));

  // use an interval for current position
  // TODO Only active for content playback
  Observable
    .interval(POSITION_UPDATES_INTERVAL)
    .map(() => ({
      currentTime: player.getWallClockTime(),
      bufferGap: player.getVideoLoadedTime() - player.getVideoPlayedTime(),
      duration: player.getVideoDuration(),
    }))
    .takeUntil($destroy)
    .subscribe(arg => {
      state.set(arg);
    });

  fromPlayerEvent("playerStateChange")
    .distinctUntilChanged()
    .takeUntil($destroy)
    .subscribe((arg) => {
      const stateUpdates = {
        hasEnded: arg === "ENDED",
        hasLoadedContent: !["STOPPED", "LOADING"].includes(arg),
        isBuffering: arg === "BUFFERING",
        isLoading: arg === "LOADING",
        isSeeking: arg === "SEEKING",
        isStopped: arg === "STOPPED",
        speed: arg === "PLAYING" ? player.getPlaybackRate() : 0,
      };

      if (arg === "PAUSED") {
        stateUpdates.isPaused = true;
      } else if (arg === "PLAYING") {
        stateUpdates.isPaused = false;
      } else if (arg === "LOADED") {
        stateUpdates.availableAudioBitrates =
          player.getAvailableAudioBitrates();
        stateUpdates.availableVideoBitrates =
          player.getAvailableVideoBitrates();
        stateUpdates.availableLanguages =
          player.getAvailableAudioTracks();
        stateUpdates.availableSubtitles =
          player.getAvailableTextTracks();
      } else if (arg === "STOPPED" || arg === "ENDED") {
        stateUpdates.audioBitrate = undefined;
        stateUpdates.videoBitrate = undefined;
        stateUpdates.availableAudioBitrates = [];
        stateUpdates.availableVideoBitrates = [];
        stateUpdates.availableLanguages = [];
        stateUpdates.availableSubtitles = [];
      }

      if (arg !== "STOPPED") {
        // error is never cleaned up
        stateUpdates.error = null;
      }

      state.set(stateUpdates);
    });

  player.getMetrics()
    .takeUntil($destroy)
    // .map((metric) => metric.value.response)
    // .filter((response) => response.size > 2000)
    .subscribe((metric = {}) => {
      const { response } = metric.value;
      if (response && response.size > 10000) {
        state.set({
          bandwidth: (response.size / response.duration) * 0.008, // in mbps
        });
      }
    });

  fromPlayerEvent("manifestChange")
    .map(() => player.isLive())
    .distinctUntilChanged()
    .takeUntil($destroy)
    .subscribe((isLive) => {
      state.set({ isLive });
    });
};

module.exports = {
  linkPlayerEventsToState,
};
<|endoftext|>


<commit_before>'use strict';

const debug = require('debug')('xsd2jsonschema:JsonSchemaFileDraft04');
const path = require('path');
const URI = require('urijs');
const JsonSchemaFile = require('./JsonSchemaFile');

/**
 * JSON Schema file operations.  This is based on the JSON Schema meta-schema located at http://json-schema.org/draft-04/schema#.
 *
 *
 * Please see http://json-schema.org for more details.
 */

class JsonSchemaFileDraft04 extends JsonSchemaFile {
	constructor(options) {
		if (options != undefined) {
			options.$schema = options.$schema != undefined ? options.$schema : 'http://json-schema.org/draft-04/schema#';
			options.schemaId = options.schemaId != undefined ? options.schemaId : 'id';
		}
		super(options);
	}

	/**
	 * Creates a child JsonSchemaFile using the given options. The parent is set automatically.
	 *
	 * @param {Object} options - And object used to override default options.
	 * @param {string} options.baseFilename - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.id - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.targetNamespace - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.title - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.ref - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.$ref - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {JsonSchemaFile} options.parent - this parameter is set to the current JsonSchemaFile.
	 *
	 * @returns {JsonSchemaFileDraft04} - Returns a new JsonSchemaFileDraft04 that has the current JsonSchemaFile as its parent.
	 */
	newJsonSchemaFile(options) {
		if (options != undefined) {
			if (options.parent == undefined) {
				options.parent = this;
			}
			return new JsonSchemaFileDraft04(options);
		} else {
			return new JsonSchemaFileDraft04({ parent: this });
		}
	}

}

module.exports = JsonSchemaFileDraft04;<commit_msg>Corrected file reference causing codeship error<commit_after>'use strict';

const debug = require('debug')('xsd2jsonschema:JsonSchemaFileDraft04');
const path = require('path');
const URI = require('urijs');
const JsonSchemaFile = require('./jsonSchemaFile');

/**
 * JSON Schema file operations.  This is based on the JSON Schema meta-schema located at http://json-schema.org/draft-04/schema#.
 *
 *
 * Please see http://json-schema.org for more details.
 */

class JsonSchemaFileDraft04 extends JsonSchemaFile {
	constructor(options) {
		if (options != undefined) {
			options.$schema = options.$schema != undefined ? options.$schema : 'http://json-schema.org/draft-04/schema#';
			options.schemaId = options.schemaId != undefined ? options.schemaId : 'id';
		}
		super(options);
	}

	/**
	 * Creates a child JsonSchemaFile using the given options. The parent is set automatically.
	 *
	 * @param {Object} options - And object used to override default options.
	 * @param {string} options.baseFilename - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.id - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.targetNamespace - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.title - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.ref - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {string} options.$ref - The directory from which xml schema's should be loaded.  The default value is the current directory.
	 * @param {JsonSchemaFile} options.parent - this parameter is set to the current JsonSchemaFile.
	 *
	 * @returns {JsonSchemaFileDraft04} - Returns a new JsonSchemaFileDraft04 that has the current JsonSchemaFile as its parent.
	 */
	newJsonSchemaFile(options) {
		if (options != undefined) {
			if (options.parent == undefined) {
				options.parent = this;
			}
			return new JsonSchemaFileDraft04(options);
		} else {
			return new JsonSchemaFileDraft04({ parent: this });
		}
	}

}

module.exports = JsonSchemaFileDraft04;<|endoftext|>


<commit_before>(function(win){
	var Utils = win.Utils;
	var EventDispatcher = win.EventDispatcher;
	var Rect = win.Rect;
	var Polygon = win.Polygon;

	var DisplayObject = win.DisplayObject = function(x, y)
	{
		this.x = x||0;
		this.y = y||0;
		this.originX = 0;
		this.originY = 0;
		this.scaleX = 1;
		this.scaleY = 1;
		this.width = 0;
		this.height = 0;
		this.angle = 0;
		this.alpha = 1;
		this.timeStep = 0;
		this.mouseEnable = false;
		this.rect = new Rect();
		EventDispatcher.call(this);
	};

	Utils.extends(DisplayObject, EventDispatcher);

	DisplayObject.prototype.render = function(ctx)
	{
		this.isInStage = this._inStage();
		if(!ctx || !this.isInStage) return;
		ctx.save();
		ctx.globalAlpha = this.alpha;
		ctx.translate(this.x, this.y);
		ctx.rotate(this.angle);
		ctx.scale(this.scaleX, this.scaleY);
		this._draw(ctx);
		ctx.restore();

		if(FL.debug)
		{
			this._debugDraw(ctx);
		}
	};

	DisplayObject.prototype._debugDraw = function(ctx)
	{
		ctx.save();
		var rect = this.getBounds();
		ctx.strokeStyle = "#f00";
		ctx.lineWidth = .5;
		ctx.beginPath();
		ctx.moveTo(this.points[0].x, this.points[0].y)
		for(var i = 1, l = this.points.length;i < l;i ++)
		{
			ctx.lineTo(this.points[i].x, this.points[i].y);
		}
		ctx.closePath();
		ctx.stroke();

		ctx.strokeStyle = "#00f";
		ctx.beginPath();
		ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
		ctx.stroke();
		ctx.restore();
	}

	DisplayObject.prototype.setCenter = function()
	{
		this.originX = this.width >>1;
		this.originY = this.height >>1;
	}

	DisplayObject.prototype._draw = function(ctx)
	{

	};

	DisplayObject.prototype.initStage = function(stage, timeStep)
	{
		this.stage = stage;
		this.timeStep = timeStep;
	}

	DisplayObject.prototype._inStage =function()
	{
		return this.stage && this.x + this.width*2 > 0 && this.y + this.height*2 > 0 && this.x - 2*this.width< this.stage.width && this.y - 2*this.height< this.stage.height;
	}

	DisplayObject.prototype.getBounds = function()
	{
		var cos = Math.cos(this.angle);
		var sin = Math.sin(this.angle);
		var originX = this.originX;
		var originY = this.originY;
		var minx, miny, maxx, maxy;
		var points = [[0, 0], [0, this.height], [this.width, this.height], [this.width, 0]];
		for(var i = 3;i >= 0;i --)
		{
			var tx = points[i][0] - originX;
			var ty = points[i][1] - originY;
			var ex = tx * cos - ty * sin + this.x;
			var ey = tx * sin + ty * cos + this.y;
			points[i] = new Vector(ex, ey);
			if(i == 3)
			{
				minx = maxx = ex;
				miny = maxy = ey;
			}
			else
			{
				minx > ex && (minx = ex);
				miny > ey && (miny = ey);
				maxx < ex && (maxx = ex);
				maxy < ey && (maxy = ey);
			}
		}
		this.points = points;
		return new Rect(minx, miny, maxx - minx, maxy - miny);
	};

	/**
	 * copy from https://github.com/quark-dev-team/quarkjs/blob/master/src/base/display/DisplayObject.js
	 * 获得一个对象相对于其某个祖先（默认即舞台）的连接矩阵。
	 * @private
	 */
	DisplayObject.prototype.getConcatenatedMatrix = function(ancestor)
	{
		var mtx = new FL.Matrix(1, 0, 0, 1, 0, 0);
		if(ancestor == this) return mtx;
		for(var o = this; o.parent != null && o.parent != ancestor; o = o.parent)
		{
			var cos = 1, sin = 0;
			if(o.rotation%360 != 0)
			{
				var r = o.rotation * DEG_TO_RAD;
				cos = Math.cos(r);
				sin = Math.sin(r);
			}

			if(o.regX != 0) mtx.tx -= o.regX;
			if(o.regY != 0) mtx.ty -= o.regY;

			mtx.concat(new FL.Matrix(cos*o.scaleX, sin*o.scaleX, -sin*o.scaleY, cos*o.scaleY, o.x, o.y));
		}
		return mtx;
	};

	DisplayObject.prototype.hitTestPoint = function(x, y)
	{
		if(this.angle == 0)
		{
			return new Rect(this.x - this.originX, this.y - this.originY, this.width, this.height).hitTestPoint(x, y);
		}

		if(this.getBounds().hitTestPoint(x, y))
		{
			return new Polygon(this.points).hitTestPoint(x, y);
		}
		return false;
	};

	DisplayObject.prototype.hitTestObject = function(obj)
	{
		var bounds = this.bounds || this.getBounds();
		if(bounds.intersects(obj.bounds||obj.getBounds()))
		{
			return true;
			// return new Polygon(this.points).hit(new Polygon(obj.points));
		}
		return false;
	};

})(FL);

<commit_msg>add displayobject visible prop<commit_after>(function(win){
	var Utils = win.Utils;
	var EventDispatcher = win.EventDispatcher;
	var Rect = win.Rect;
	var Polygon = win.Polygon;

	var DisplayObject = win.DisplayObject = function(x, y)
	{
		this.x = x||0;
		this.y = y||0;
		this.originX = 0;
		this.originY = 0;
		this.scaleX = 1;
		this.scaleY = 1;
		this.width = 0;
		this.height = 0;
		this.angle = 0;
		this.alpha = 1;
		this.timeStep = 0;
		this.mouseEnable = false;
		this.visible = true;
		this.rect = new Rect();
		EventDispatcher.call(this);
	};

	Utils.extends(DisplayObject, EventDispatcher);

	DisplayObject.prototype.render = function(ctx)
	{
		this.isInStage = this._inStage();
		if(!this.visible||!ctx || !this.isInStage) return;
		ctx.save();
		ctx.globalAlpha = this.alpha;
		ctx.translate(this.x, this.y);
		ctx.rotate(this.angle);
		ctx.scale(this.scaleX, this.scaleY);
		this._draw(ctx);
		ctx.restore();

		if(FL.debug)
		{
			this._debugDraw(ctx);
		}
	};

	DisplayObject.prototype._debugDraw = function(ctx)
	{
		ctx.save();
		var rect = this.getBounds();
		ctx.strokeStyle = "#f00";
		ctx.lineWidth = .5;
		ctx.beginPath();
		ctx.moveTo(this.points[0].x, this.points[0].y)
		for(var i = 1, l = this.points.length;i < l;i ++)
		{
			ctx.lineTo(this.points[i].x, this.points[i].y);
		}
		ctx.closePath();
		ctx.stroke();

		ctx.strokeStyle = "#00f";
		ctx.beginPath();
		ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
		ctx.stroke();
		ctx.restore();
	}

	DisplayObject.prototype.setCenter = function()
	{
		this.originX = this.width >>1;
		this.originY = this.height >>1;
	}

	DisplayObject.prototype._draw = function(ctx)
	{

	};

	DisplayObject.prototype.initStage = function(stage, timeStep)
	{
		this.stage = stage;
		this.timeStep = timeStep;
	}

	DisplayObject.prototype._inStage =function()
	{
		return this.stage && this.x + this.width*2 > 0 && this.y + this.height*2 > 0 && this.x - 2*this.width< this.stage.width && this.y - 2*this.height< this.stage.height;
	}

	DisplayObject.prototype.getBounds = function()
	{
		var cos = Math.cos(this.angle);
		var sin = Math.sin(this.angle);
		var originX = this.originX;
		var originY = this.originY;
		var minx, miny, maxx, maxy;
		var points = [[0, 0], [0, this.height], [this.width, this.height], [this.width, 0]];
		for(var i = 3;i >= 0;i --)
		{
			var tx = points[i][0] - originX;
			var ty = points[i][1] - originY;
			var ex = tx * cos - ty * sin + this.x;
			var ey = tx * sin + ty * cos + this.y;
			points[i] = new Vector(ex, ey);
			if(i == 3)
			{
				minx = maxx = ex;
				miny = maxy = ey;
			}
			else
			{
				minx > ex && (minx = ex);
				miny > ey && (miny = ey);
				maxx < ex && (maxx = ex);
				maxy < ey && (maxy = ey);
			}
		}
		this.points = points;
		return new Rect(minx, miny, maxx - minx, maxy - miny);
	};

	/**
	 * copy from https://github.com/quark-dev-team/quarkjs/blob/master/src/base/display/DisplayObject.js
	 * 获得一个对象相对于其某个祖先（默认即舞台）的连接矩阵。
	 * @private
	 */
	DisplayObject.prototype.getConcatenatedMatrix = function(ancestor)
	{
		var mtx = new FL.Matrix(1, 0, 0, 1, 0, 0);
		if(ancestor == this) return mtx;
		for(var o = this; o.parent != null && o.parent != ancestor; o = o.parent)
		{
			var cos = 1, sin = 0;
			if(o.rotation%360 != 0)
			{
				var r = o.rotation * DEG_TO_RAD;
				cos = Math.cos(r);
				sin = Math.sin(r);
			}

			if(o.regX != 0) mtx.tx -= o.regX;
			if(o.regY != 0) mtx.ty -= o.regY;

			mtx.concat(new FL.Matrix(cos*o.scaleX, sin*o.scaleX, -sin*o.scaleY, cos*o.scaleY, o.x, o.y));
		}
		return mtx;
	};

	DisplayObject.prototype.hitTestPoint = function(x, y)
	{
		if(this.angle == 0)
		{
			return new Rect(this.x - this.originX, this.y - this.originY, this.width, this.height).hitTestPoint(x, y);
		}

		if(this.getBounds().hitTestPoint(x, y))
		{
			return new Polygon(this.points).hitTestPoint(x, y);
		}
		return false;
	};

	DisplayObject.prototype.hitTestObject = function(obj)
	{
		var bounds = this.bounds || this.getBounds();
		if(bounds.intersects(obj.bounds||obj.getBounds()))
		{
			return true;
			// return new Polygon(this.points).hit(new Polygon(obj.points));
		}
		return false;
	};

})(FL);

<|endoftext|>


<commit_before>/* global mocha, jasmine */
'use strict';

/**
 * Function to be used with Jest/Jasmine as a data provider
 *
 * @link https://github.com/jphpsf/jasmine-data-provider
 *
 * Example usage:
 *
 * describes('some method', function() {
 *     using('integers from 5 to 10', [5, 6, 7, 8, 9, 10], function(value) {
 *         it('should return the integer plus 1', function() {
 *             // Use `value` here
 *         });
 *     });
 * });
 *
 * @param  {String}   description Description of the set being used
 * @param  {Array}    values      Array of values to use
 * @param  {Function} func        Function containing calls to `it()`
 */
module.exports = function(description, values, func)
{
    var count = values.length;

    for (var i = 0; i < count; i += 1) {
        if (Object.prototype.toString.call(values[i]) !== '[object Array]') {
            values[i] = [values[i]];
        }
        func.apply(this, values[i]);
        (mocha || jasmine).currentEnv_.currentSpec.description += ' (with "' + description + '" using ' + values[i].join(', ') + ')';
    }
};
<commit_msg>Refs #16 - Use better approach that actually works.<commit_after>'use strict';
/* global describe */

/**
 * Function to be used with Jest/Jasmine as a data provider
 *
 * @link https://github.com/jphpsf/jasmine-data-provider
 *
 * Example usage:
 *
 * describes('some method', function() {
 *     using('integers from 5 to 10', [5, 6, 7, 8, 9, 10], function(value) {
 *         it('should return the integer plus 1', function() {
 *             // Use `value` here
 *         });
 *     });
 * });
 *
 * @param  {String}   description Description of the set being used
 * @param  {Array}    values      Array of values to use
 * @param  {Function} func        Function containing calls to `it()`
 */
module.exports = function(description, values, func)
{
    var count = values.length;

    for (var i = 0; i < count; i += 1) {
        describe('using ' + description + ': ' + values[i], func.bind(null, values[i]));
    }
};
<|endoftext|>


<commit_before>'use strict';

var Q                       = require('q'),
    request                 = require('request'),
    constants               = require('./constants.js'),
    randombase64            = require('randombase64'),
    wifiClient              = require('./wifi-tool'),

    apiEndPoint             = 'http://' + constants.localIPCamera + '/cgi-bin/cgi',

    token                   = null,
    connectedCameraId       = null,
    connectedToCamera       = false,
    streamingActivated      = false,

    mockCameraSettings      = [{'stream_type':'mjpg'},{'std_def_video':'on'},{'stream_while_record':'on'},{'video_resolution':'1920x1080 30P 16:9'},{'el_wdr':'off'},{'el_angle_deg':'170'},{'el_white_balance':'auto'},{'el_warp_correction':'off'},{'el_stabilization':'off'},{'el_ae_exposure_level':'0'},{'el_ae_light_metering':'center'},{'el_image_rotation':'off'},{'el_rec_duration':'30min'},{'el_burst_per_sec':'60'},{'el_speaker_volume':'0'},{'el_self_timer':'off'},{'el_battery':'97'},{'el_capture_mode':'single'},{'el_interval_time':'00:00:30'},{'el_get_version':'01.02.0006'},{'el_wifi_auto_power_off':'disable'},{'el_get_ac_connection':'disconnected'},{'el_rec_audio_level':'5'},{'el_rec_audio_balance':'0'},{'el_auto_power_off':'off'},{'el_ae_control':'manual'},{'el_ae_manual_gain':'10'},{'el_ae_manual_shutter':'16'},{'el_wb_control':'manual'},{'el_wb_manual_temp':'1'},{'el_destination':'eu'},{'app_status':'idle'},{'camera_clock':'2014-12-16 13:44:43'}],

    messageIds = {
        cameraParams: 3,
        setter: 2,
        streamOnPart2: 259,
        heartBeat: 260,
        token: 257
    };

var getToken = function() {
    console.log('getToken');
    var deferred = Q.defer();

    request.post({
        url: apiEndPoint,
        form: '{"msg_id":' + messageIds.token + ', "token": 0}'
    }, function(err, httpResponse, body) {
        token = JSON.parse(body).param;
        console.log('token: ', token);
        deferred.resolve(token);
    });

    return deferred.promise;
};

var setSetting = function(type, value) {
    var deferred = Q.defer();

    var _call = function() {
        request.post({
            url: apiEndPoint,
            form: '{"msg_id":' + messageIds.setter + ', "param": "' + value + '", "type": "' + type + '", "token": ' + token + '}'
        }, function(err, httpResponse, body) {
            console.log(body);
            var modifiedParam = JSON.parse(body);
            console.log('modifiedParam: ', modifiedParam);
            deferred.resolve(modifiedParam);
        });
    }

    if (connectedToCamera && token !== null) {
        getHeartBeat().then(_call);
    } else if (connectedToCamera && token === null) {
        getToken().then(getHeartBeat).then(_call);
    } else {
        deferred.reject();
    }

    return deferred.promise;
};

var getHeartBeat = function() {
    console.log('getHeartBeat');
    var deferred = Q.defer();

    request.post({
        url: apiEndPoint,
        form: '{"msg_id":' + messageIds.heartBeat + ', "token": ' + token + '}'
    }, function(err, httpResponse, body) {
        var result = JSON.parse(body);
        if (result.rval === 0 && result.msg_id === messageIds.heartBeat) {
            deferred.resolve();
        } else {
            deferred.reject();
        }
    });

    return deferred.promise;
};

var reformatArrayFromCamera = function(data) {
    var _result = {},
        len = 0,
        i = 0;

    len = (typeof data !== 'undefined') ? data.length : 0;

    for (i; i < len; i++) {
        for (var k in data[i]) {
            //Parse numbers too
            if (isNaN(data[i][k])) {
                _result[k] = data[i][k];
            } else {
                _result[k] = parseInt(data[i][k]);
            }
        }
    }

    return _result;
};

var getCameraSettings = function(req, res, next) {

    var _call = function() {
        request.post({
            url: apiEndPoint,
            form: '{"msg_id":' + messageIds.cameraParams + ', "token": ' + token + '}'
        }, function(err, httpResponse, body) {
            var params = JSON.parse(body).param;
            res.json(reformatArrayFromCamera(params));
        });
    };

    if (connectedToCamera && token !== null) {
        _call();
    } else if (connectedToCamera && token === null) {
        getToken().then(_call);
    } else {
        res.json(reformatArrayFromCamera(mockCameraSettings));
    }
};

var activateStreaming = function() {
    var deferred = Q.defer();

    request.post({
        url: apiEndPoint,
        form: '{"msg_id":' + messageIds.setter + ', "param": "on", "type": "stream_while_record", "token": ' + token + '}'
    }, function(err, httpResponse, body) {
        var resultPart1 = JSON.parse(body);

        console.log('resultPart1: ', resultPart1);

        if (resultPart1.msg_id === messageIds.setter && resultPart1.type === 'stream_while_record') {
            request.post({
                url: apiEndPoint,
                form: '{"msg_id":' + messageIds.streamOnPart2 + ', "param": "none_force", "token": ' + token + '}'
            }, function(err, httpResponse, body) {
                var resultPart2 = JSON.parse(body);

                console.log('resultPart2: ', resultPart2);

                if (resultPart2.msg_id === messageIds.streamOnPart2) {
                    streamingActivated = true;
                    deferred.resolve(token);
                }
            });
        }
    });

    return deferred.promise;
};

var getCameraThumb = function(req, res, next) {

    var _cameraId = req.params.id,
        _contentType = null,
        _finalURI = null;

    var _callThumb = function() {
        request('http://' + constants.localIPCamera + '/mjpeg/amba.jpg', function(error, response, body) {
            //console.log(response);
            //_finalURI = 'data:image/jpeg;base64,' + new Buffer(body).toString('base64');
            res.send('ok');
        });
    };

    if (connectedToCamera && token !== null && streamingActivated) {
        _callThumb();
    } else if (connectedToCamera && token === null && !streamingActivated) {
        getToken().then(getHeartBeat).then(activateStreaming).then(_callThumb);
    } else {
        // Send random noise image
        randombase64.generate({
            height: 240,
            width: 424,
            withPrefix: true
        }, function(err, str) {
            res.send(str);
        });
    }
};

var connectToCamera = function(req, res, next) {
    var cameraId = req.params.id,
        token = null,
        timeoutConnect = 5000,

        _connect = function() {
            wifiClient.connectToNetwork(constants.namespaceCameraName + cameraId, constants.defaultCameraPassword).then(function() {
                setTimeout(function() {
                    //Test correct connection after 5s
                    wifiClient.getCurrentWifiNetwork().then(function(name) {
                        connectedCameraId = name;
                    });
                    connectedToCamera = true;
                    console.log('connectedCameraId 2: ', connectedCameraId);
                    res.sendStatus(200);
                }, timeoutConnect);
            });
        };

    //First test is not already connected to desired camera
    wifiClient.getCurrentWifiNetwork().then(function(name) {
        if (constants.namespaceCameraName + cameraId === name) {
            connectedToCamera = true;
            connectedCameraId = name;
            console.log('connectedCameraId 1: ', connectedCameraId);
            res.sendStatus(200);
        } else {
            connectedToCamera = false;
            _connect();
        }
    });
};

var setCameraSetting = function(req, res, next) {
    var settingType = req.query.type,
        settingValue = req.query.value;

    console.log('setCameraSetting: ', settingType, settingValue);

    setSetting(settingType, settingValue).then(function(result) {
        res.sendStatus(200);
    }, function() {
        res.sendStatus(404);
    })
};

var qbicProxy = {
    getCameraSettings: getCameraSettings,
    getCameraThumb: getCameraThumb,
    connectToCamera: connectToCamera,
    setCameraSetting: setCameraSetting
};

module.exports = qbicProxy;
<commit_msg>Server : setting call<commit_after>'use strict';

var Q                       = require('q'),
    request                 = require('request'),
    constants               = require('./constants.js'),
    randombase64            = require('randombase64'),
    wifiClient              = require('./wifi-tool'),

    apiEndPoint             = 'http://' + constants.localIPCamera + '/cgi-bin/cgi',

    token                   = null,
    connectedCameraId       = null,
    connectedToCamera       = false,
    streamingActivated      = false,

    mockCameraSettings      = [{'stream_type':'mjpg'},{'std_def_video':'on'},{'stream_while_record':'on'},{'video_resolution':'1920x1080 30P 16:9'},{'el_wdr':'off'},{'el_angle_deg':'170'},{'el_white_balance':'auto'},{'el_warp_correction':'off'},{'el_stabilization':'off'},{'el_ae_exposure_level':'0'},{'el_ae_light_metering':'center'},{'el_image_rotation':'off'},{'el_rec_duration':'30min'},{'el_burst_per_sec':'60'},{'el_speaker_volume':'0'},{'el_self_timer':'off'},{'el_battery':'97'},{'el_capture_mode':'single'},{'el_interval_time':'00:00:30'},{'el_get_version':'01.02.0006'},{'el_wifi_auto_power_off':'disable'},{'el_get_ac_connection':'disconnected'},{'el_rec_audio_level':'5'},{'el_rec_audio_balance':'0'},{'el_auto_power_off':'off'},{'el_ae_control':'manual'},{'el_ae_manual_gain':'10'},{'el_ae_manual_shutter':'16'},{'el_wb_control':'manual'},{'el_wb_manual_temp':'1'},{'el_destination':'eu'},{'app_status':'idle'},{'camera_clock':'2014-12-16 13:44:43'}],

    messageIds = {
        cameraParams: 3,
        setter: 2,
        streamOnPart2: 259,
        heartBeat: 260,
        token: 257
    };

var getToken = function() {
    console.log('getToken');
    var deferred = Q.defer();

    request.post({
        url: apiEndPoint,
        form: '{"msg_id":' + messageIds.token + ', "token": 0}'
    }, function(err, httpResponse, body) {
        token = JSON.parse(body).param;
        console.log('token: ', token);
        deferred.resolve(token);
    });

    return deferred.promise;
};

var setSetting = function(type, value) {
    var deferred = Q.defer();

    var _call = function() {
        var deferred = Q.defer();
        request.post({
            url: apiEndPoint,
            form: '{"msg_id":' + messageIds.setter + ', "param": "' + value + '", "type": "' + type + '", "token": ' + token + '}'
        }, function(err, httpResponse, body) {
            console.log(body);
            var modifiedParam = JSON.parse(body);
            console.log('modifiedParam: ', modifiedParam);
            deferred.resolve(modifiedParam);
        });
        return deferred.promise;
    }

    if (connectedToCamera && token !== null) {
        getHeartBeat().then(_call).then(getHeartBeat).then(activateStreaming);
    } else if (connectedToCamera && token === null) {
        getToken().then(getHeartBeat).then(_call).then(getHeartBeat).then(activateStreaming);
    } else {
        deferred.reject();
    }

    return deferred.promise;
};

var getHeartBeat = function() {
    console.log('getHeartBeat');
    var deferred = Q.defer();

    request.post({
        url: apiEndPoint,
        form: '{"msg_id":' + messageIds.heartBeat + ', "token": ' + token + '}'
    }, function(err, httpResponse, body) {
        var result = JSON.parse(body);
        if (result.rval === 0 && result.msg_id === messageIds.heartBeat) {
            deferred.resolve();
        } else {
            deferred.reject();
        }
    });

    return deferred.promise;
};

var reformatArrayFromCamera = function(data) {
    var _result = {},
        len = 0,
        i = 0;

    len = (typeof data !== 'undefined') ? data.length : 0;

    for (i; i < len; i++) {
        for (var k in data[i]) {
            //Parse numbers too
            if (isNaN(data[i][k])) {
                _result[k] = data[i][k];
            } else {
                _result[k] = parseInt(data[i][k]);
            }
        }
    }

    return _result;
};

var getCameraSettings = function(req, res, next) {

    var _call = function() {
        request.post({
            url: apiEndPoint,
            form: '{"msg_id":' + messageIds.cameraParams + ', "token": ' + token + '}'
        }, function(err, httpResponse, body) {
            var params = JSON.parse(body).param;
            res.json(reformatArrayFromCamera(params));
        });
    };

    if (connectedToCamera && token !== null) {
        _call();
    } else if (connectedToCamera && token === null) {
        getToken().then(_call);
    } else {
        res.json(reformatArrayFromCamera(mockCameraSettings));
    }
};

var activateStreaming = function() {
    var deferred = Q.defer();

    request.post({
        url: apiEndPoint,
        form: '{"msg_id":' + messageIds.setter + ', "param": "on", "type": "stream_while_record", "token": ' + token + '}'
    }, function(err, httpResponse, body) {
        var resultPart1 = JSON.parse(body);

        console.log('resultPart1: ', resultPart1);

        if (resultPart1.msg_id === messageIds.setter && resultPart1.type === 'stream_while_record') {
            request.post({
                url: apiEndPoint,
                form: '{"msg_id":' + messageIds.streamOnPart2 + ', "param": "none_force", "token": ' + token + '}'
            }, function(err, httpResponse, body) {
                var resultPart2 = JSON.parse(body);

                console.log('resultPart2: ', resultPart2);

                if (resultPart2.msg_id === messageIds.streamOnPart2) {
                    streamingActivated = true;
                    deferred.resolve(token);
                }
            });
        }
    });

    return deferred.promise;
};

var getCameraThumb = function(req, res, next) {

    var _cameraId = req.params.id,
        _contentType = null,
        _finalURI = null;

    var _callThumb = function() {
        request('http://' + constants.localIPCamera + '/mjpeg/amba.jpg', function(error, response, body) {
            //console.log(response);
            //_finalURI = 'data:image/jpeg;base64,' + new Buffer(body).toString('base64');
            res.send('ok');
        });
    };

    if (connectedToCamera && token !== null && streamingActivated) {
        _callThumb();
    } else if (connectedToCamera && token === null && !streamingActivated) {
        getToken().then(getHeartBeat).then(activateStreaming).then(_callThumb);
    } else {
        // Send random noise image
        randombase64.generate({
            height: 240,
            width: 424,
            withPrefix: true
        }, function(err, str) {
            res.send(str);
        });
    }
};

var connectToCamera = function(req, res, next) {
    var cameraId = req.params.id,
        token = null,
        timeoutConnect = 5000,

        _connect = function() {
            wifiClient.connectToNetwork(constants.namespaceCameraName + cameraId, constants.defaultCameraPassword).then(function() {
                setTimeout(function() {
                    //Test correct connection after 5s
                    wifiClient.getCurrentWifiNetwork().then(function(name) {
                        connectedCameraId = name;
                    });
                    connectedToCamera = true;
                    console.log('connectedCameraId 2: ', connectedCameraId);
                    res.sendStatus(200);
                }, timeoutConnect);
            });
        };

    //First test is not already connected to desired camera
    wifiClient.getCurrentWifiNetwork().then(function(name) {
        if (constants.namespaceCameraName + cameraId === name) {
            connectedToCamera = true;
            token = null;
            connectedCameraId = name;
            console.log('connectedCameraId 1: ', connectedCameraId);
            res.sendStatus(200);
        } else {
            connectedToCamera = false;
            _connect();
        }
    });
};

var setCameraSetting = function(req, res, next) {
    var settingType = req.query.type,
        settingValue = req.query.value;

    console.log('setCameraSetting: ', settingType, settingValue);

    setSetting(settingType, settingValue).then(function(result) {
        res.sendStatus(200);
    }, function() {
        res.sendStatus(404);
    })
};

var qbicProxy = {
    getCameraSettings: getCameraSettings,
    getCameraThumb: getCameraThumb,
    connectToCamera: connectToCamera,
    setCameraSetting: setCameraSetting
};

module.exports = qbicProxy;
<|endoftext|>


<commit_before>/*
 * @file HTML Buttons plugin for CKEditor
 * Copyright (C) 2012 Alfonso Martnez de Lizarrondo
 * A simple plugin to help create custom buttons to insert HTML blocks
 */

CKEDITOR.plugins.add( 'htmlbuttons',
{
	init : function( editor )
	{
		var buttonsConfig = editor.config.htmlbuttons;
		if (!buttonsConfig)
			return;

		function createCommand( definition )
		{
			return {
				exec: function( editor ) {
					editor.insertHtml( definition.html );
				}
			};
		}

		// Create the command for each button
		for(var i=0; i<buttonsConfig.length; i++)
		{
			var button = buttonsConfig[ i ];
			var commandName = button.name;
			editor.addCommand( commandName, createCommand(button, editor) );

			editor.ui.addButton( commandName,
			{
				label : button.title,
				command : commandName,
				icon : this.path + button.icon
			});
		}
	} //Init

} );

/**
 * An array of buttons to add to the toolbar.
 * Each button is an object with these properties:
 *	name: The name of the command and the button (the one to use in the toolbar configuration)
 *	icon: The icon to use. Place them in the plugin folder
 *	html: The HTML to insert when the user clicks the button
 *	title: Title that appears while hovering the button
 *
 * Default configuration with some sample buttons:
 */
CKEDITOR.config.htmlbuttons =  [
	{
		name:'button1',
		icon:'icon1.png',
		html:'Search something',
		title:'A link to Google'
	},
	{
		name:'button2',
		icon:'icon2.png',
		html:'

',
		title:'A simple table'
	},
	{
		name:'button3',
		icon:'icon3.png',
		html:'

Item 1

Sub item 1

Sub item 2

',
		title:'A nested list'
	}
];<commit_msg>Fix compilation<commit_after>/*
 * @file HTML Buttons plugin for CKEditor
 * Copyright (C) 2012 Alfonso Martнnez de Lizarrondo
 * A simple plugin to help create custom buttons to insert HTML blocks
 */

CKEDITOR.plugins.add( 'htmlbuttons',
{
	init : function( editor )
	{
		var buttonsConfig = editor.config.htmlbuttons;
		if (!buttonsConfig)
			return;

		function createCommand( definition )
		{
			return {
				exec: function( editor ) {
					editor.insertHtml( definition.html );
				}
			};
		}

		// Create the command for each button
		for(var i=0; i<buttonsConfig.length; i++)
		{
			var button = buttonsConfig[ i ];
			var commandName = button.name;
			editor.addCommand( commandName, createCommand(button, editor) );

			editor.ui.addButton( commandName,
			{
				label : button.title,
				command : commandName,
				icon : this.path + button.icon
			});
		}
	} //Init

} );

/**
 * An array of buttons to add to the toolbar.
 * Each button is an object with these properties:
 *	name: The name of the command and the button (the one to use in the toolbar configuration)
 *	icon: The icon to use. Place them in the plugin folder
 *	html: The HTML to insert when the user clicks the button
 *	title: Title that appears while hovering the button
 *
 * Default configuration with some sample buttons:
 */
CKEDITOR.config.htmlbuttons =  [
	{
		name:'button1',
		icon:'icon1.png',
		html:'Search something',
		title:'A link to Google'
	},
	{
		name:'button2',
		icon:'icon2.png',
		html:'

',
		title:'A simple table'
	},
	{
		name:'button3',
		icon:'icon3.png',
		html:'

Item 1

Sub item 1

Sub item 2

',
		title:'A nested list'
	}
];<|endoftext|>


<commit_before>/**********************************************************************************

  Copyright (C) 2012 by Mozilla Foundation

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.

 **********************************************************************************/

define( [], function(){

  const CHECK_MEDIA_INTERVAL = 50;

  return function( parentElement, media, tracksContainer ){
    var _container = document.createElement( "div" ),
        _node = document.createElement( "div" ),
        _line = document.createElement( "div" ),
        _tracksContainer = tracksContainer,
        _parent = parentElement,
        _media = media,
        _mousePos,
        _zoom = 1,
        _mediaCheckInterval,
        _width,
        _this = this,
        _isPlaying = false,
        _isScrubbing = false;

    _container.className = "butter-timebar-scrubber-container";
    _node.className = "butter-timebar-scrubber-node";
    _line.className = "butter-timebar-scrubber-line";

    _node.appendChild( _line );
    _container.appendChild( _node );
    _parent.appendChild( _container );

    function setNodePosition(){
      var duration = _media.duration,
          currentTime = _media.currentTime,
          pos = currentTime / duration * _tracksContainer.scrollWidth;

      if( pos < _tracksContainer.scrollLeft || pos > _tracksContainer.offsetWidth + _tracksContainer.scrollLeft ){
        _node.style.display = "none";
      }
      else {
        _node.style.left = pos - _tracksContainer.scrollLeft + "px";
        _node.style.display = "block";
      } //if
    } //setNodePosition

    _tracksContainer.addEventListener( "scroll", function( e ){
      setNodePosition();
    }, false );

    function onMouseUp( e ){
      if( _isPlaying ){
        _media.play();
        _isScrubbing =  false;
      }

      window.removeEventListener( "mouseup", onMouseUp, false );
      window.removeEventListener( "mousemove", onMouseMove, false );
    } //onMouseUp

    function onMouseMove( e ){
      var diff = e.pageX - _mousePos;
      diff = Math.max( 0, Math.min( diff, _width ) );
      _node.style.left = diff + "px";
      _media.currentTime = ( diff + _tracksContainer.scrollLeft ) / _tracksContainer.scrollWidth * _media.duration;
    } //onMouseMove

    function onMouseDown( e ){
      _mousePos = e.pageX - _node.offsetLeft;

      if( _isPlaying ){
        _media.pause();
        _isScrubbing = true;
      }

      _node.removeEventListener( "mousedown", onMouseDown, false );
      window.addEventListener( "mousemove", onMouseMove, false );
      window.addEventListener( "mouseup", onMouseUp, false );
    } //onMouesDown

    _node.addEventListener( "mousedown", onMouseDown, false );
    _container.addEventListener( "mousedown", function( e ){
      var pos = e.pageX - _container.getBoundingClientRect().left;
      _media.currentTime = ( pos + _tracksContainer.scrollLeft ) / _tracksContainer.scrollWidth * _media.duration;
      setNodePosition();
      onMouseDown( e );
    }, false );

    this.update = function( zoom ){
      _zoom = zoom;

      var tracklinerContainer = _tracksContainer.firstChild,
          tracklinerWidth = tracklinerContainer.getBoundingClientRect().width;

      _width = _parent.getBoundingClientRect().width;
      _width = Math.min( _width, tracklinerWidth );
      _container.style.width = _width + "px";
      setNodePosition();
    }; //update

    function checkMedia(){
      setNodePosition();
    } //checkMedia

    _media.listen( "mediaplaying", function( e ){
      _isPlaying = true;
      _checkMediaInterval = setInterval( checkMedia, CHECK_MEDIA_INTERVAL );
    });

    _media.listen( "mediapause", function( e ){
      if( !_isScrubbing )
        _isPlaying = false;

      clearInterval( _checkMediaInterval );
    });
  };
});
<commit_msg>[#400]Missed some brackets<commit_after>/**********************************************************************************

  Copyright (C) 2012 by Mozilla Foundation

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.

 **********************************************************************************/

define( [], function(){

  const CHECK_MEDIA_INTERVAL = 50;

  return function( parentElement, media, tracksContainer ){
    var _container = document.createElement( "div" ),
        _node = document.createElement( "div" ),
        _line = document.createElement( "div" ),
        _tracksContainer = tracksContainer,
        _parent = parentElement,
        _media = media,
        _mousePos,
        _zoom = 1,
        _mediaCheckInterval,
        _width,
        _this = this,
        _isPlaying = false,
        _isScrubbing = false;

    _container.className = "butter-timebar-scrubber-container";
    _node.className = "butter-timebar-scrubber-node";
    _line.className = "butter-timebar-scrubber-line";

    _node.appendChild( _line );
    _container.appendChild( _node );
    _parent.appendChild( _container );

    function setNodePosition(){
      var duration = _media.duration,
          currentTime = _media.currentTime,
          pos = currentTime / duration * _tracksContainer.scrollWidth;

      if( pos < _tracksContainer.scrollLeft || pos > _tracksContainer.offsetWidth + _tracksContainer.scrollLeft ){
        _node.style.display = "none";
      }
      else {
        _node.style.left = pos - _tracksContainer.scrollLeft + "px";
        _node.style.display = "block";
      } //if
    } //setNodePosition

    _tracksContainer.addEventListener( "scroll", function( e ){
      setNodePosition();
    }, false );

    function onMouseUp( e ){
      if( _isPlaying ){
        _media.play();
        _isScrubbing =  false;
      }

      window.removeEventListener( "mouseup", onMouseUp, false );
      window.removeEventListener( "mousemove", onMouseMove, false );
    } //onMouseUp

    function onMouseMove( e ){
      var diff = e.pageX - _mousePos;
      diff = Math.max( 0, Math.min( diff, _width ) );
      _node.style.left = diff + "px";
      _media.currentTime = ( diff + _tracksContainer.scrollLeft ) / _tracksContainer.scrollWidth * _media.duration;
    } //onMouseMove

    function onMouseDown( e ){
      _mousePos = e.pageX - _node.offsetLeft;

      if( _isPlaying ){
        _media.pause();
        _isScrubbing = true;
      }

      _node.removeEventListener( "mousedown", onMouseDown, false );
      window.addEventListener( "mousemove", onMouseMove, false );
      window.addEventListener( "mouseup", onMouseUp, false );
    } //onMouesDown

    _node.addEventListener( "mousedown", onMouseDown, false );
    _container.addEventListener( "mousedown", function( e ){
      var pos = e.pageX - _container.getBoundingClientRect().left;
      _media.currentTime = ( pos + _tracksContainer.scrollLeft ) / _tracksContainer.scrollWidth * _media.duration;
      setNodePosition();
      onMouseDown( e );
    }, false );

    this.update = function( zoom ){
      _zoom = zoom;

      var tracklinerContainer = _tracksContainer.firstChild,
          tracklinerWidth = tracklinerContainer.getBoundingClientRect().width;

      _width = _parent.getBoundingClientRect().width;
      _width = Math.min( _width, tracklinerWidth );
      _container.style.width = _width + "px";
      setNodePosition();
    }; //update

    function checkMedia(){
      setNodePosition();
    } //checkMedia

    _media.listen( "mediaplaying", function( e ){
      _isPlaying = true;
      _checkMediaInterval = setInterval( checkMedia, CHECK_MEDIA_INTERVAL );
    });

    _media.listen( "mediapause", function( e ){
      if( !_isScrubbing ){
        _isPlaying = false;
      }

      clearInterval( _checkMediaInterval );
    });
  };
});
<|endoftext|>


<commit_before>'use strict';

// Helper methods needed by multiple controllers.

var Rx = require('../rx');
var xenaQuery = require('../xenaQuery');
var _ = require('../underscore_ext');
var {reifyErrors, collectResults} = require('./errors');
var fetch = require('../fieldFetch');
var {getColSpec} = require('../models/datasetJoins');
var {signatureField} = require('../models/fieldSpec');
var {publicServers} = require('../defaultServers');
// pick up signature fetch
require('../models/signatures');

var datasetResults = resps => collectResults(resps, servers =>
		_.object(_.flatmap(servers, s => _.map(s.datasets, d => [d.dsID, d]))));

function datasetQuery(servers, cohort) {
	return Rx.Observable.zipArray(
		_.map(servers, server => reifyErrors(
				xenaQuery.datasetList(server, [cohort.name]).map(datasets => ({server, datasets})),
				{host: server}))
	).flatMap(datasetResults);
}

function fetchDatasets(serverBus, servers, cohort) {
	serverBus.next(['datasets', datasetQuery(servers, cohort)]);
}

const MAX_SAMPLES = 50 * 1000;

var allSamples = _.curry((cohort, max, server) => xenaQuery.cohortSamples(server, cohort, max === Infinity ? null : max));

function unionOfGroup(gb) {
	return _.union(..._.map(gb, ([v]) => v));
}

// Performance of this is probably poor, esp. due to underscore's horrible
// n^2 set operations.
function cohortHasPrivateSamples(cohortResps) {
	var {'true': pub, 'false': priv} = _.groupBy(cohortResps, ([,, server]) => _.contains(publicServers, server)),
		pubSamps = unionOfGroup(pub),
		privSamps = unionOfGroup(priv);
	return _.difference(privSamps, pubSamps).length > 0;
}

function filterSamples(sampleFilter, samples) {
	return sampleFilter ? _.intersection(sampleFilter, samples) : samples;
}

// For the cohort, query all servers,
// return a stream per-cohort, each of which returns an event
// [cohort, [sample, ...]].
// By not combining them here, we can uniformly handle errors, below.
var cohortSamplesQuery =
	(servers, max, {name, sampleFilter}) =>
		_.map(servers, allSamples(name, max))
			.map((resp, j) => resp.map(samples => [filterSamples(sampleFilter, samples), samples.length >= max, servers[j]]));

var collateSamples = _.curry((cohorts, max, resps) => {
	var serverOver = _.any(resps, ([, over]) => over),
		cohortSamples = unionOfGroup(resps || []).slice(0, max),
		cohortOver = cohortSamples.length >= max,
		hasPrivateSamples = cohortHasPrivateSamples(resps);
	return {samples: cohortSamples, over: serverOver || cohortOver, hasPrivateSamples};
});

// reifyErrors should be pass the server name, but in this expression we don't have it.
function samplesQuery(servers, cohort, max) {
	return Rx.Observable.zipArray(cohortSamplesQuery(servers, max, cohort).map(reifyErrors))
		.flatMap(resps => collectResults(resps, collateSamples(cohort, max)));
}

function fetchSamples(serverBus, servers, cohort, allowOverSamples) {
	serverBus.next(['samples', samplesQuery(servers, cohort, allowOverSamples ? Infinity : MAX_SAMPLES)]);
}

function fetchColumnData(serverBus, samples, id, settings) {

	// XXX  Note that the widget-data-xxx slots are leaked in the groupBy
	// in main.js. We need a better mechanism.
//	if (Math.random() > 0.5) { // testing error handling
		serverBus.next([['widget-data', id], fetch(settings, samples)]);
//	} else {
//		serverBus.onNext([['widget-data', id], Rx.Observable.throw(new Error('Injected error'))]);
//	}
}

function resetZoom(state) {
	let count = _.getIn(state, ['cohortSamples', 'length'], 0);
	return _.updateIn(state, ["zoom"],
					 z => _.merge(z, {count: count, index: 0}));
}

var setCohortRelatedFields = (state, cohort) =>
	_.assoc(state,
		'cohort', cohort,
		'hasPrivateSamples', false,
		'cohortSamples', [],
		'columns', {},
		'columnOrder', [],
		'data', {},
		'survival', null,
		'km', _.assoc(state.km, ['id'], null));

// This adds or overwrites a 'sample' column in the state.
// Called from setCohort, the column data will be fetched after
// the sample list returns from the server.
function addSampleColumn(state, width) {
	if (!_.get(state.cohort, ['name'])) {
		return state;
	}
	var field = signatureField('samples', {
			columnLabel: 'Sample ID',
			valueType: 'coded',
			signature: ['samples']
		}),
		newOrder = _.has(state.columns, 'samples') ? state.columnOrder : [...state.columnOrder, 'samples'],
		colSpec = getColSpec([field], {}),
		settings = _.assoc(colSpec,
				'width', Math.round(width == null ? 136 : width),
				'user', _.pick(colSpec, ['columnLabel', 'fieldLabel'])),
		newState = _.assocIn(state,
			['columns', 'samples'], settings,
			['columnOrder'], newOrder);
	return _.assocIn(newState, ['data', 'samples', 'status'], 'loading');
}

var setWizardAndMode = state =>
	_.assocIn(state,
			['wizardMode'], true,
			['mode'], 'heatmap');

var setCohort = _.curry((cohort, width, state) =>
		addSampleColumn(
			setWizardAndMode(
				resetZoom(
					setCohortRelatedFields(state, cohort))),
			width));

var userServers = state => _.keys(state.servers).filter(h => state.servers[h].user);

var fetchCohortData = (serverBus, state) => {
	let user = userServers(state);
	if (state.cohort) {
		fetchDatasets(serverBus, user, state.cohort);
		fetchSamples(serverBus, user, state.cohort, state.allowOverSamples);
	}
};

var unionOfResults = resps => collectResults(resps, results => _.union(...results));

function cohortQuery(servers) {
	return Rx.Observable.zipArray(_.map(servers, s => reifyErrors(xenaQuery.allCohorts(s), {host: s})))
			.flatMap(unionOfResults);
}

function fetchCohorts(serverBus, state, newState, {force} = {}) {
	var user = userServers(state),
		newUser = userServers(newState);
	if (force || !_.listSetsEqual(user, newUser)) {
		serverBus.next(['cohorts', cohortQuery(newUser)]);
	}
}

function updateWizard(serverBus, state, newState, opts = {}) {
	fetchCohorts(serverBus, state, newState, opts);
	let user = userServers(state);
	// If there's a bookmark on wizard mode step 2, will we fail
	// to load the dataset?
	if (newState.cohort && (opts.force || (newState.cohort.name !== _.get(state.cohort, 'name')))) {
		fetchDatasets(serverBus, user, newState.cohort);
	}
}

var clearWizardCohort = state =>
	_.assocIn(state, ['wizard', 'datasets'], undefined,
					 ['wizard', 'features'], undefined);

module.exports = {
	fetchCohortData,
	fetchCohorts,
	fetchColumnData,
	fetchDatasets,
	fetchSamples,
	resetZoom,
	setCohort,
	userServers,
	updateWizard,
	clearWizardCohort,
	datasetQuery
};
<commit_msg>When updating wizard, use latest hub setting.<commit_after>'use strict';

// Helper methods needed by multiple controllers.

var Rx = require('../rx');
var xenaQuery = require('../xenaQuery');
var _ = require('../underscore_ext');
var {reifyErrors, collectResults} = require('./errors');
var fetch = require('../fieldFetch');
var {getColSpec} = require('../models/datasetJoins');
var {signatureField} = require('../models/fieldSpec');
var {publicServers} = require('../defaultServers');
// pick up signature fetch
require('../models/signatures');

var datasetResults = resps => collectResults(resps, servers =>
		_.object(_.flatmap(servers, s => _.map(s.datasets, d => [d.dsID, d]))));

function datasetQuery(servers, cohort) {
	return Rx.Observable.zipArray(
		_.map(servers, server => reifyErrors(
				xenaQuery.datasetList(server, [cohort.name]).map(datasets => ({server, datasets})),
				{host: server}))
	).flatMap(datasetResults);
}

function fetchDatasets(serverBus, servers, cohort) {
	serverBus.next(['datasets', datasetQuery(servers, cohort)]);
}

const MAX_SAMPLES = 50 * 1000;

var allSamples = _.curry((cohort, max, server) => xenaQuery.cohortSamples(server, cohort, max === Infinity ? null : max));

function unionOfGroup(gb) {
	return _.union(..._.map(gb, ([v]) => v));
}

// Performance of this is probably poor, esp. due to underscore's horrible
// n^2 set operations.
function cohortHasPrivateSamples(cohortResps) {
	var {'true': pub, 'false': priv} = _.groupBy(cohortResps, ([,, server]) => _.contains(publicServers, server)),
		pubSamps = unionOfGroup(pub),
		privSamps = unionOfGroup(priv);
	return _.difference(privSamps, pubSamps).length > 0;
}

function filterSamples(sampleFilter, samples) {
	return sampleFilter ? _.intersection(sampleFilter, samples) : samples;
}

// For the cohort, query all servers,
// return a stream per-cohort, each of which returns an event
// [cohort, [sample, ...]].
// By not combining them here, we can uniformly handle errors, below.
var cohortSamplesQuery =
	(servers, max, {name, sampleFilter}) =>
		_.map(servers, allSamples(name, max))
			.map((resp, j) => resp.map(samples => [filterSamples(sampleFilter, samples), samples.length >= max, servers[j]]));

var collateSamples = _.curry((cohorts, max, resps) => {
	var serverOver = _.any(resps, ([, over]) => over),
		cohortSamples = unionOfGroup(resps || []).slice(0, max),
		cohortOver = cohortSamples.length >= max,
		hasPrivateSamples = cohortHasPrivateSamples(resps);
	return {samples: cohortSamples, over: serverOver || cohortOver, hasPrivateSamples};
});

// reifyErrors should be pass the server name, but in this expression we don't have it.
function samplesQuery(servers, cohort, max) {
	return Rx.Observable.zipArray(cohortSamplesQuery(servers, max, cohort).map(reifyErrors))
		.flatMap(resps => collectResults(resps, collateSamples(cohort, max)));
}

function fetchSamples(serverBus, servers, cohort, allowOverSamples) {
	serverBus.next(['samples', samplesQuery(servers, cohort, allowOverSamples ? Infinity : MAX_SAMPLES)]);
}

function fetchColumnData(serverBus, samples, id, settings) {

	// XXX  Note that the widget-data-xxx slots are leaked in the groupBy
	// in main.js. We need a better mechanism.
//	if (Math.random() > 0.5) { // testing error handling
		serverBus.next([['widget-data', id], fetch(settings, samples)]);
//	} else {
//		serverBus.onNext([['widget-data', id], Rx.Observable.throw(new Error('Injected error'))]);
//	}
}

function resetZoom(state) {
	let count = _.getIn(state, ['cohortSamples', 'length'], 0);
	return _.updateIn(state, ["zoom"],
					 z => _.merge(z, {count: count, index: 0}));
}

var setCohortRelatedFields = (state, cohort) =>
	_.assoc(state,
		'cohort', cohort,
		'hasPrivateSamples', false,
		'cohortSamples', [],
		'columns', {},
		'columnOrder', [],
		'data', {},
		'survival', null,
		'km', _.assoc(state.km, ['id'], null));

// This adds or overwrites a 'sample' column in the state.
// Called from setCohort, the column data will be fetched after
// the sample list returns from the server.
function addSampleColumn(state, width) {
	if (!_.get(state.cohort, ['name'])) {
		return state;
	}
	var field = signatureField('samples', {
			columnLabel: 'Sample ID',
			valueType: 'coded',
			signature: ['samples']
		}),
		newOrder = _.has(state.columns, 'samples') ? state.columnOrder : [...state.columnOrder, 'samples'],
		colSpec = getColSpec([field], {}),
		settings = _.assoc(colSpec,
				'width', Math.round(width == null ? 136 : width),
				'user', _.pick(colSpec, ['columnLabel', 'fieldLabel'])),
		newState = _.assocIn(state,
			['columns', 'samples'], settings,
			['columnOrder'], newOrder);
	return _.assocIn(newState, ['data', 'samples', 'status'], 'loading');
}

var setWizardAndMode = state =>
	_.assocIn(state,
			['wizardMode'], true,
			['mode'], 'heatmap');

var setCohort = _.curry((cohort, width, state) =>
		addSampleColumn(
			setWizardAndMode(
				resetZoom(
					setCohortRelatedFields(state, cohort))),
			width));

var userServers = state => _.keys(state.servers).filter(h => state.servers[h].user);

var fetchCohortData = (serverBus, state) => {
	let user = userServers(state);
	if (state.cohort) {
		fetchDatasets(serverBus, user, state.cohort);
		fetchSamples(serverBus, user, state.cohort, state.allowOverSamples);
	}
};

var unionOfResults = resps => collectResults(resps, results => _.union(...results));

function cohortQuery(servers) {
	return Rx.Observable.zipArray(_.map(servers, s => reifyErrors(xenaQuery.allCohorts(s), {host: s})))
			.flatMap(unionOfResults);
}

function fetchCohorts(serverBus, state, newState, {force} = {}) {
	var user = userServers(state),
		newUser = userServers(newState);
	if (force || !_.listSetsEqual(user, newUser)) {
		serverBus.next(['cohorts', cohortQuery(newUser)]);
	}
}

function updateWizard(serverBus, state, newState, opts = {}) {
	fetchCohorts(serverBus, state, newState, opts);
	let user = userServers(newState);
	// If there's a bookmark on wizard mode step 2, will we fail
	// to load the dataset?
	if (newState.cohort && (opts.force || (newState.cohort.name !== _.get(state.cohort, 'name')))) {
		fetchDatasets(serverBus, user, newState.cohort);
	}
}

var clearWizardCohort = state =>
	_.assocIn(state, ['wizard', 'datasets'], undefined,
					 ['wizard', 'features'], undefined);

module.exports = {
	fetchCohortData,
	fetchCohorts,
	fetchColumnData,
	fetchDatasets,
	fetchSamples,
	resetZoom,
	setCohort,
	userServers,
	updateWizard,
	clearWizardCohort,
	datasetQuery
};
<|endoftext|>


<commit_before>import Nuclear from "../../lib/nuclear.js"

var ES6TodoApp = Nuclear.create({
    add: function (evt) {
        evt.preventDefault();
        this.option.items.push(this.textBox.value);
    },
    render: function () {
        return `

ES6 Todo

 {{#items}}
{{.}}
 {{/items}}

        <form onsubmit="add(event)" >
            <input nc-id="textBox" type="text"  />
            <button>Add #{{items.length}}</button>
        </form>

`;
    },
    style: function () {
        return `h3 { color:red; }
    button{ color:green;}`;
    }
});

export default  ES6TodoApp;<commit_msg>format<commit_after>import Nuclear from "../../lib/nuclear.js"

var ES6TodoApp = Nuclear.create({
    add: function (evt) {
        evt.preventDefault();
        this.option.items.push(this.textBox.value);
    },
    render: function () {
        return `

ES6 Todo

 {{#items}}
{{.}}
 {{/items}}

                    <form onsubmit="add(event)" >
                        <input nc-id="textBox" type="text"  />
                        <button>Add #{{items.length}}</button>
                    </form>

`;
    },
    style: function () {
        return `h3 { color:red; }
               button{ color:green;}`;
    }
});

export default  ES6TodoApp;<|endoftext|>