<commit_before>define([
	'mustache',
	'modules/core/src/SongBarsIterator',
	'utils/UserLog',
	'jquery',
	'pubsub',
], function(Mustache, SongBarsIterator, UserLog, $, pubsub) {
	/**
	 * ChordEditionController manages all chords edition function
	 * @exports ChordEdition/ChordEditionController
	 */
	function ChordEditionController(songModel, cursor, chordSpaceMng) {
		if (!songModel || !cursor || !chordSpaceMng) {
			throw "ChordEditionController params are wrong";
		}
		this.songModel = songModel;
		this.cursor = cursor;
		this.chordSpaceMng = chordSpaceMng;
		this.initSubscribe();
	}

	/**
	 * Subscribe to view events
	 */
	ChordEditionController.prototype.initSubscribe = function() {
		var self = this;

		$.subscribe('ChordEditionView', function(el, fn, param) {
			if (self.chordSpaceMng.isEnabled()) {
				self[fn].call(self, param);
				$.publish('ToViewer-draw', self.songModel);
			}
		});
	};

	ChordEditionController.prototype.deleteChords = function() {

		var beats = this.getSelectedChordsBeats();
		var chordMng = this.songModel.getComponent('chords');
		var self = this;
		var firstChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,beats[0]);
		var lastChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,beats[1] - 1);
		if (lastChordSpace.exceedsSongLength){ //when we are removing last positions, we just set lastChordSpace greater than last position
			var lastChordSpaceView = this.chordSpaceMng.chordSpace[this.chordSpaceMng.chordSpace.length - 1];
			lastChordSpace.barNumber = lastChordSpaceView.barNumber + 1;
			lastChordSpace.beatNumber = lastChordSpaceView.beatNumber + 1;
		}
		chordMng.removeChordsBetweenPositions(firstChordSpace.barNumber, firstChordSpace.beatNumber, lastChordSpace.barNumber, lastChordSpace.beatNumber);

		$.publish('ToHistory-add', 'Remove chord');
	};

	/*ChordEditionController.prototype.addChord = function() {
		console.log('addChord');
		// editor.addChord();
	};*/
	ChordEditionController.prototype.toggleEditChord = function() {
		console.log('toggleEditChord');
	};

	ChordEditionController.prototype.copyChords = function() {
		this.buffer = this.getSelectedChordsBeats();
		//this.buffer now equals to [startBeat, endBeat]
	};

	ChordEditionController.prototype.pasteChords = function() {
		if (!this.buffer || this.buffer.length === 0) {
			return;
		}
		var chordMng = this.songModel.getComponent('chords');
		var arrBeatChords = chordMng.getBeatsBasedChordIndexes(this.songModel);
		var indexesBeats = chordMng.getChordsRelativeToBeat(this.songModel,this.buffer[0], this.buffer[1], arrBeatChords);
		// indexesBeat is an array of objects {index: 1, beat: 2} (with the index of the chord, and the beat differents to start beat of selected sections)

		if (indexesBeats.length === 0){
			//no chords selected
			return;
		}

		var pos1 = indexesBeats[0].index;
		var pos2 = indexesBeats[indexesBeats.length - 1].index;

		var copiedChords = chordMng.cloneElems(pos1, pos2 + 1);
		var startPasteBeat = this.getSelectedChordsBeats()[0];
		var endPasteBeat = startPasteBeat + this.buffer[1] - this.buffer[0] - 1;

		// remove chords in affected chordspaces
		var firstChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,startPasteBeat);
		var lastChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,endPasteBeat);
		if (firstChordSpace.exceedsSongLength || lastChordSpace.exceedsSongLength){
			throw "ChordEdition error exceedsSongLength";
		}
		chordMng.removeChordsBetweenPositions(firstChordSpace.barNumber, firstChordSpace.beatNumber, lastChordSpace.barNumber, lastChordSpace.beatNumber);

		//we copy chords
		var pasteBeat, numBarAndBeat, barNumAndBeat;
		for (var i = 0; i < indexesBeats.length; i++) {
			pasteBeat = indexesBeats[i].beat + startPasteBeat;
			barNumAndBeat = chordMng.getBarNumAndBeatFromBeat(this.songModel,pasteBeat);
			if (!barNumAndBeat.notExactBeat){
				copiedChords[i].setBarNumber(barNumAndBeat.barNumber);
				copiedChords[i].setBeat(barNumAndBeat.beatNumber);
				chordMng.addChord(copiedChords[i]);
			}
		}

		var ch, str;
		for (var i = 0; i < chordMng.getChords().length; i++) {
			ch = chordMng.getChords()[i]
			str=ch.toString()+" "+ch.getBarNumber()+ " ..  " +ch.getBeat() ;
		}

		$.publish('ToHistory-add', 'Paste chord');
	};

	/*ChordEditionController.prototype.chordTabEvent = function(way) {
		console.log('chordTabEvent', way);
	};*/

	/**
	 * returns start and end beats of chords taking into account cursor, depending on chordSpaces selected
	 * @return {Array} [startBeat, endBeat]
	 */
	ChordEditionController.prototype.getSelectedChordsBeats = function() {
		var songIt = new SongBarsIterator(this.songModel);
		var startChordSpace = this.chordSpaceMng.chordSpace[this.cursor.getStart()];
		var startBarNum = startChordSpace.barNumber;

		songIt.setBarIndex(startBarNum);
		var beatInc = 4 / songIt.getBarTimeSignature().getBeatUnit(); //will be 1 for x/4 time signatures, 2 for x/2, and 0.5 for x/8
		var barBeatOffset = (startChordSpace.beatNumber - 1) * beatInc;
		var startBeat = this.songModel.getStartBeatFromBarNumber(startBarNum) + barBeatOffset;
		var iBeat = startBeat;

		for (var i = this.cursor.getStart(); i <= this.cursor.getEnd(); i++) {
			if (barBeatOffset === songIt.getBarTimeSignature().getQuarterBeats() && songIt.hasNext()) {
				songIt.next();
				beatInc = 4 / songIt.getBarTimeSignature().getBeatUnit();
				barBeatOffset = 0;
			} else if (barBeatOffset > songIt.getBarTimeSignature().getQuarterBeats()) {
				console.warn("barBeatOffset > total bar duration"); //should never enter here
			}
			iBeat += beatInc;
			barBeatOffset += beatInc;
		}
		return [startBeat, iBeat];
	};

	ChordEditionController.prototype.getSelectedChordsIndexes = function() {
		var chordManager = this.songModel.getComponent('chords');
		var selectedChords = [];
		for (var cursorIndex = this.cursor.getStart(); cursorIndex <= this.cursor.getEnd(); cursorIndex++) {
			var chordSpace = this.chordSpaceMng.chordSpace[cursorIndex];
			var pos = {
				numBeat: chordSpace.beatNumber,
				numBar: chordSpace.barNumber
			};
			var r = chordManager.getChordIndexByPosition(pos);
			if (r.exact) {
				selectedChords.push(r.index);
			}
		}
		return selectedChords;
	};

	return ChordEditionController;
});<commit_msg>fixed bug renaming chordSpaces variable<commit_after>define([
	'mustache',
	'modules/core/src/SongBarsIterator',
	'utils/UserLog',
	'jquery',
	'pubsub',
], function(Mustache, SongBarsIterator, UserLog, $, pubsub) {
	/**
	 * ChordEditionController manages all chords edition function
	 * @exports ChordEdition/ChordEditionController
	 */
	function ChordEditionController(songModel, cursor, chordSpaceMng) {
		if (!songModel || !cursor || !chordSpaceMng) {
			throw "ChordEditionController params are wrong";
		}
		this.songModel = songModel;
		this.cursor = cursor;
		this.chordSpaceMng = chordSpaceMng;
		this.initSubscribe();
	}

	/**
	 * Subscribe to view events
	 */
	ChordEditionController.prototype.initSubscribe = function() {
		var self = this;

		$.subscribe('ChordEditionView', function(el, fn, param) {
			if (self.chordSpaceMng.isEnabled()) {
				self[fn].call(self, param);
				$.publish('ToViewer-draw', self.songModel);
			}
		});
	};

	ChordEditionController.prototype.deleteChords = function() {

		var beats = this.getSelectedChordsBeats();
		var chordMng = this.songModel.getComponent('chords');
		var self = this;
		var firstChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,beats[0]);
		var lastChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,beats[1] - 1);
		if (lastChordSpace.exceedsSongLength){ //when we are removing last positions, we just set lastChordSpace greater than last position
			var lastChordSpaceView = this.chordSpaceMng.chordSpaces[this.chordSpaceMng.chordSpaces.length - 1];
			lastChordSpace.barNumber = lastChordSpaceView.barNumber + 1;
			lastChordSpace.beatNumber = lastChordSpaceView.beatNumber + 1;
		}
		chordMng.removeChordsBetweenPositions(firstChordSpace.barNumber, firstChordSpace.beatNumber, lastChordSpace.barNumber, lastChordSpace.beatNumber);

		$.publish('ToHistory-add', 'Remove chord');
	};

	/*ChordEditionController.prototype.addChord = function() {
		console.log('addChord');
		// editor.addChord();
	};*/
	ChordEditionController.prototype.toggleEditChord = function() {
		console.log('toggleEditChord');
	};

	ChordEditionController.prototype.copyChords = function() {
		this.buffer = this.getSelectedChordsBeats();
		//this.buffer now equals to [startBeat, endBeat]
	};

	ChordEditionController.prototype.pasteChords = function() {
		if (!this.buffer || this.buffer.length === 0) {
			return;
		}
		var chordMng = this.songModel.getComponent('chords');
		var arrBeatChords = chordMng.getBeatsBasedChordIndexes(this.songModel);
		var indexesBeats = chordMng.getChordsRelativeToBeat(this.songModel,this.buffer[0], this.buffer[1], arrBeatChords);
		// indexesBeat is an array of objects {index: 1, beat: 2} (with the index of the chord, and the beat differents to start beat of selected sections)

		if (indexesBeats.length === 0){
			//no chords selected
			return;
		}

		var pos1 = indexesBeats[0].index;
		var pos2 = indexesBeats[indexesBeats.length - 1].index;

		var copiedChords = chordMng.cloneElems(pos1, pos2 + 1);
		var startPasteBeat = this.getSelectedChordsBeats()[0];
		var endPasteBeat = startPasteBeat + this.buffer[1] - this.buffer[0] - 1;

		// remove chords in affected chordspaces
		var firstChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,startPasteBeat);
		var lastChordSpace = chordMng.getBarNumAndBeatFromBeat(this.songModel,endPasteBeat);
		if (firstChordSpace.exceedsSongLength || lastChordSpace.exceedsSongLength){
			throw "ChordEdition error exceedsSongLength";
		}
		chordMng.removeChordsBetweenPositions(firstChordSpace.barNumber, firstChordSpace.beatNumber, lastChordSpace.barNumber, lastChordSpace.beatNumber);

		//we copy chords
		var pasteBeat, numBarAndBeat, barNumAndBeat;
		for (var i = 0; i < indexesBeats.length; i++) {
			pasteBeat = indexesBeats[i].beat + startPasteBeat;
			barNumAndBeat = chordMng.getBarNumAndBeatFromBeat(this.songModel,pasteBeat);
			if (!barNumAndBeat.notExactBeat){
				copiedChords[i].setBarNumber(barNumAndBeat.barNumber);
				copiedChords[i].setBeat(barNumAndBeat.beatNumber);
				chordMng.addChord(copiedChords[i]);
			}
		}

		var ch, str;
		for (var i = 0; i < chordMng.getChords().length; i++) {
			ch = chordMng.getChords()[i]
			str=ch.toString()+" "+ch.getBarNumber()+ " ..  " +ch.getBeat() ;
		}

		$.publish('ToHistory-add', 'Paste chord');
	};

	/*ChordEditionController.prototype.chordTabEvent = function(way) {
		console.log('chordTabEvent', way);
	};*/

	/**
	 * returns start and end beats of chords taking into account cursor, depending on chordSpaces selected
	 * @return {Array} [startBeat, endBeat]
	 */
	ChordEditionController.prototype.getSelectedChordsBeats = function() {
		var songIt = new SongBarsIterator(this.songModel);
		var startChordSpace = this.chordSpaceMng.chordSpaces[this.cursor.getStart()];
		var startBarNum = startChordSpace.barNumber;

		songIt.setBarIndex(startBarNum);
		var beatInc = 4 / songIt.getBarTimeSignature().getBeatUnit(); //will be 1 for x/4 time signatures, 2 for x/2, and 0.5 for x/8
		var barBeatOffset = (startChordSpace.beatNumber - 1) * beatInc;
		var startBeat = this.songModel.getStartBeatFromBarNumber(startBarNum) + barBeatOffset;
		var iBeat = startBeat;

		for (var i = this.cursor.getStart(); i <= this.cursor.getEnd(); i++) {
			if (barBeatOffset === songIt.getBarTimeSignature().getQuarterBeats() && songIt.hasNext()) {
				songIt.next();
				beatInc = 4 / songIt.getBarTimeSignature().getBeatUnit();
				barBeatOffset = 0;
			} else if (barBeatOffset > songIt.getBarTimeSignature().getQuarterBeats()) {
				console.warn("barBeatOffset > total bar duration"); //should never enter here
			}
			iBeat += beatInc;
			barBeatOffset += beatInc;
		}
		return [startBeat, iBeat];
	};

	ChordEditionController.prototype.getSelectedChordsIndexes = function() {
		var chordManager = this.songModel.getComponent('chords');
		var selectedChords = [];
		for (var cursorIndex = this.cursor.getStart(); cursorIndex <= this.cursor.getEnd(); cursorIndex++) {
			var chordSpace = this.chordSpaceMng.chordSpaces[cursorIndex];
			var pos = {
				numBeat: chordSpace.beatNumber,
				numBar: chordSpace.barNumber
			};
			var r = chordManager.getChordIndexByPosition(pos);
			if (r.exact) {
				selectedChords.push(r.index);
			}
		}
		return selectedChords;
	};

	return ChordEditionController;
});<|endoftext|>


<commit_before>( function( mw, $ ) {"use strict";

// Class defined in resources/class/class.js
mw.KBasePlugin = Class.extend({
	asyncInit: false,
	init: function( embedPlayer, callback, pluginName ){

		// Save to local scope
		this.embedPlayer = embedPlayer;
		this.initCompleteCallback = callback;
		this.pluginName = pluginName;

		this.bindPostFix = '.' + pluginName;

		this.setDefaults();

		var safeEnviornment = this.isSafeEnviornment();
		var _this = this;

		// Check if jQuery Deferrer
		if( typeof safeEnviornment == 'object' && safeEnviornment.promise ){
			safeEnviornment.done(function(isSafe){
				if( !isSafe ){
					_this.destroy();
				}
			});
		} else if( typeof safeEnviornment == 'boolean' && ! safeEnviornment ) {
			this.initCompleteCallback();
			return false;
		}

		// Add onConfigChange binding
		this.bindConfigChangeEvent();

		// Call plugin setup method
		this.setup();

		// Run initCompleteCallback
		if( this.asyncInit === false ) {
			this.initCompleteCallback();
		}

		return this;
	},
	setDefaults: function( obj ){
		obj = obj || this.defaultConfig;
		var _this = this;
		// Set default configuration for the plugin
		if( $.isPlainObject(obj) ) {
			$.each( obj, function( key, value ) {
				if( _this.getConfig( key ) === undefined ) {
					_this.setConfig( key, value, true );
				}
			});
		}
	},
	isSafeEnviornment: function(){
		return true;
	},
	setup: function() {},
	getPlayer: function() {
		return this.embedPlayer;
	},
	getConfig: function( attr, raw ) {
		if( raw ){
			return this.embedPlayer.getRawKalturaConfig( this.pluginName, attr );
		}
		return this.embedPlayer.getKalturaConfig( this.pluginName, attr );
	},
	setConfig: function( attr, value, quiet ) {
		this.embedPlayer.setKalturaConfig( this.pluginName, attr, value, quiet );
	},
	getTemplateHTML: function( data ){
		var _this = this;
		// Setup empty object
		data = data || {};
		// Add out plugin instance
		data.self = this;
		data.player = this.embedPlayer;
		data.entry = this.embedPlayer.kalturaPlayerMetaData;
		data.entryMetadata = this.embedPlayer.kalturaEntryMetaData;

		// First get template from 'template' config
		var rawHTML = this.getConfig( 'template', true );
		if( !rawHTML ){
			var templatePath = this.getConfig( 'templatePath' );
			if( !templatePath || !window.kalturaIframePackageData.templates[ templatePath ]) {
				this.log('getTemplateHTML:: Template not found');
				return '';
			}
			rawHTML = window.kalturaIframePackageData.templates[ templatePath ];
		}
		var transformedHTML = mw.util.tmpl( rawHTML, data );
		var evaluatedHTML = $.trim( this.embedPlayer.evaluate( transformedHTML ) );
		var $templateHtml = $( '' + evaluatedHTML + '' );

		$templateHtml
			.find('[data-click],[data-notification]')
			.click(function(e){
				var data = $(this).data();
				return _this.handleClick( e, data );
			});

		// Handle form submission
		$templateHtml.find('[data-submit]').submit(function(e){
			var cb = $(this).data('submit');
			if( $.isFunction( _this[cb] ) ) {
				_this[cb](e);
			}
			return false;
		});

		return $templateHtml;
	},
	handleClick: function( e, data ){

		e.preventDefault();

		// Trigger local callback for data-click property
		if( data.click && $.isFunction(this[data.click]) ){
			this[data.click]( e, data );
		}

		if( data.notification ){
			this.getPlayer().sendNotification( data.notification, data );
		}

		return false;
	},
	bind: function( eventName, callback ){
		var bindEventsString = '',
			events = eventName.split(" "),
			totalEvents = events.length,
			i = 0,
			space = ' ';

		for( i; i<totalEvents; i++ ){
			if( i == (totalEvents-1) ){
				space = '';
			}
			bindEventsString += events[ i ] + this.bindPostFix + space;
		}
		return this.embedPlayer.bindHelper( bindEventsString, callback);
	},
	unbind: function( eventName ){
		eventName += this.bindPostFix;
		return this.embedPlayer.unbindHelper( eventName );
	},
	log: function( msg ){
		mw.log( this.pluginName + '::' + msg );
	},
	bindConfigChangeEvent: function(){
		var _this = this;
		if( typeof this.onConfigChange !== 'function' ){
			return ;
		}
		this.bind('Kaltura_ConfigChanged', function(event, pluginName, property, value){
			if( pluginName === _this.pluginName ){
				_this.onConfigChange( property, value );
			}
		});
	},
	getKalturaClient: function() {
		if( ! this.kClient ) {
			this.kClient = mw.kApiGetPartnerClient( this.embedPlayer.kwidgetid );
		}
		return this.kClient;
	},
	destroy: function(){
		this.unbind();
	}
});

} )( window.mw, window.jQuery );
<commit_msg>Add event name validation before unbinding<commit_after>( function( mw, $ ) {"use strict";

// Class defined in resources/class/class.js
mw.KBasePlugin = Class.extend({
	asyncInit: false,
	init: function( embedPlayer, callback, pluginName ){

		// Save to local scope
		this.embedPlayer = embedPlayer;
		this.initCompleteCallback = callback;
		this.pluginName = pluginName;

		this.bindPostFix = '.' + pluginName;

		this.setDefaults();

		var safeEnviornment = this.isSafeEnviornment();
		var _this = this;

		// Check if jQuery Deferrer
		if( typeof safeEnviornment == 'object' && safeEnviornment.promise ){
			safeEnviornment.done(function(isSafe){
				if( !isSafe ){
					_this.destroy();
				}
			});
		} else if( typeof safeEnviornment == 'boolean' && ! safeEnviornment ) {
			this.initCompleteCallback();
			return false;
		}

		// Add onConfigChange binding
		this.bindConfigChangeEvent();

		// Call plugin setup method
		this.setup();

		// Run initCompleteCallback
		if( this.asyncInit === false ) {
			this.initCompleteCallback();
		}

		return this;
	},
	setDefaults: function( obj ){
		obj = obj || this.defaultConfig;
		var _this = this;
		// Set default configuration for the plugin
		if( $.isPlainObject(obj) ) {
			$.each( obj, function( key, value ) {
				if( _this.getConfig( key ) === undefined ) {
					_this.setConfig( key, value, true );
				}
			});
		}
	},
	isSafeEnviornment: function(){
		return true;
	},
	setup: function() {},
	getPlayer: function() {
		return this.embedPlayer;
	},
	getConfig: function( attr, raw ) {
		if( raw ){
			return this.embedPlayer.getRawKalturaConfig( this.pluginName, attr );
		}
		return this.embedPlayer.getKalturaConfig( this.pluginName, attr );
	},
	setConfig: function( attr, value, quiet ) {
		this.embedPlayer.setKalturaConfig( this.pluginName, attr, value, quiet );
	},
	getTemplateHTML: function( data ){
		var _this = this;
		// Setup empty object
		data = data || {};
		// Add out plugin instance
		data.self = this;
		data.player = this.embedPlayer;
		data.entry = this.embedPlayer.kalturaPlayerMetaData;
		data.entryMetadata = this.embedPlayer.kalturaEntryMetaData;

		// First get template from 'template' config
		var rawHTML = this.getConfig( 'template', true );
		if( !rawHTML ){
			var templatePath = this.getConfig( 'templatePath' );
			if( !templatePath || !window.kalturaIframePackageData.templates[ templatePath ]) {
				this.log('getTemplateHTML:: Template not found');
				return '';
			}
			rawHTML = window.kalturaIframePackageData.templates[ templatePath ];
		}
		var transformedHTML = mw.util.tmpl( rawHTML, data );
		var evaluatedHTML = $.trim( this.embedPlayer.evaluate( transformedHTML ) );
		var $templateHtml = $( '' + evaluatedHTML + '' );

		$templateHtml
			.find('[data-click],[data-notification]')
			.click(function(e){
				var data = $(this).data();
				return _this.handleClick( e, data );
			});

		// Handle form submission
		$templateHtml.find('[data-submit]').submit(function(e){
			var cb = $(this).data('submit');
			if( $.isFunction( _this[cb] ) ) {
				_this[cb](e);
			}
			return false;
		});

		return $templateHtml;
	},
	handleClick: function( e, data ){

		e.preventDefault();

		// Trigger local callback for data-click property
		if( data.click && $.isFunction(this[data.click]) ){
			this[data.click]( e, data );
		}

		if( data.notification ){
			this.getPlayer().sendNotification( data.notification, data );
		}

		return false;
	},
	bind: function( eventName, callback ){
		var bindEventsString = '',
			events = eventName.split(" "),
			totalEvents = events.length,
			i = 0,
			space = ' ';

		for( i; i<totalEvents; i++ ){
			if( i == (totalEvents-1) ){
				space = '';
			}
			bindEventsString += events[ i ] + this.bindPostFix + space;
		}
		return this.embedPlayer.bindHelper( bindEventsString, callback);
	},
	unbind: function( eventName ){
		var fullEventName = eventName + this.bindPostFix;
		if (eventName === null || eventName === undefined){
			fullEventName = this.bindPostFix;
		}
		return this.embedPlayer.unbindHelper( fullEventName );
	},
	log: function( msg ){
		mw.log( this.pluginName + '::' + msg );
	},
	bindConfigChangeEvent: function(){
		var _this = this;
		if( typeof this.onConfigChange !== 'function' ){
			return ;
		}
		this.bind('Kaltura_ConfigChanged', function(event, pluginName, property, value){
			if( pluginName === _this.pluginName ){
				_this.onConfigChange( property, value );
			}
		});
	},
	getKalturaClient: function() {
		if( ! this.kClient ) {
			this.kClient = mw.kApiGetPartnerClient( this.embedPlayer.kwidgetid );
		}
		return this.kClient;
	},
	destroy: function(){
		this.unbind();
	}
});

} )( window.mw, window.jQuery );
<|endoftext|>


<commit_before>define([], function () {

  'use strict';

  var TR = {
    // config
    configTitle: '환경설정',

    // background
    backgroundTitle: '배경',
    backgroundReset: '초기화',
    backgroundImport: '배경 (jpg, png...)',
    backgroundFill: '체우기',

    // camera
    cameraTitle: '카메라',
    cameraReset: '뷰',
    cameraCenter: '초기화 (bar)',
    cameraFront: '앞쪽 (F)',
    cameraLeft: '왼쪽 (L)',
    cameraTop: '위쪽 (T)',
    cameraMode: '모드',
    cameraOrbit: '궤도 (Turntable)',
    cameraSpherical: '구 (Trackball)',
    cameraPlane: '평면 (Trackball)',
    cameraProjection: '투사',
    cameraPerspective: '원근법',
    cameraOrthographic: '정사영법',
    cameraFov: '화',
    cameraPivot: '피봇 고르기',

    // file
    fileTitle: '파일 (가져오기/내보내기)',
    fileImportTitle: '가져오기',
    fileAdd: '파일 (obj, sgl, ply, stl)',
    fileExportMeshTitle: '메쉬 내보내기',
    fileExportSceneTitle: '장면 내보내기',
    fileExportSGL: 'sgl로 저장하기',
    fileExportOBJ: 'obj로 저장하기',
    fileExportPLY: 'ply로 저장하기',
    fileExportSTL: 'stl로 저장하기',
    fileReplayerTitle: '리플레이어 (BETA)',
    fileReplayerImport: 'rep 로드하기',
    fileReplayerExport: 'rep 저장하기',

    // replayer
    replayTitle: '리플레이 환경설정',
    replayPaused: '정지',
    replaySpeed: '리플레이 속',
    replayOverride: '덮기',

    // scene
    sceneTitle: '장면',
    sceneReset: '장면 초기화',
    sceneAddSphere: '구 추가하기 ',

    // mesh
    meshTitle: '메쉬',
    meshNbVertices: '점들 : ',
    meshNbFaces: '면들 : ',

    // topology
    topologyTitle: '토폴로',

    //multires
    multiresTitle: '다중 해상도',
    multiresSubdivide: '세분화',
    multiresReverse: '리버스',
    multiresResolution: '해상도',
    multiresNoLower: '더 낮은 해상도가 존재하지 않습니다.',
    multiresNoHigher: '더 높은 해상도가 존재하지 않습니다.',
    multiresDelHigher: '더 높은 것을 삭제',
    multiresDelLower: '더 낮은 것을 삭제',
    multiresSelectLowest: '리버싱 하기 전에 더 낮은 해상도를 고르시오.',
    multiresSelectHighest: '세분화 하기 전에 더 높은 해상도를 고르시오',
    multiresWarnBigMesh: function (nbFacesNext) {
      return '다음 세분화 레벨은 ' + nbFacesNext + ' 면만큼 도달할 것이다.\n' +
          '만약 당신이 무엇을 하는지 안다면 "세분화"를 다시 클릭하세요.';
    },
    multiresNotReversible: '이 메쉬는 리버싱할 수 없습니다.\n' +
    '이 메쉬는 여러가지 메쉬의 표면의 세분화를 product한 것이 아닙니다.(loop-catmull)',

    // remesh
    remeshTitle: 'Voxel Remeshing',
    remeshRemesh: 'Remesh',
    remeshResolution: 'Resolution',
    remeshBlock: 'Block',

    // dynamic
    dynamicTitle: 'Dynamic Topology',
    dynamicActivated: 'Activated (no quads)',
    dynamicSubdivision: 'Subdivision',
    dynamicDecimation: 'Decimation',
    dynamicLinear: 'Linear subdivision',

    // sculpt
    sculptTitle: 'Sculpting & Painting',
    sculptBrush: '브러쉬 (1)',
    sculptInflate: 'Inflate (2)',
    sculptTwist: 'Twist (3)',
    sculptSmooth: 'Smooth (4 or -Shift)',
    sculptFlatten: 'Flatten (5)',
    sculptPinch: 'Pinch (6)',
    sculptCrease: 'Crease (7)',
    sculptDrag: 'Drag (8)',
    sculptPaint: 'Paint (9)',
    sculptMasking: 'Masking (-Ctrl)',
    sculptMove: 'Move (0)',
    sculptScale: 'Scale',
    sculptTranslate: 'Translate (E)',
    sculptRotate: 'Rotate (R)',
    sculptTool: 'Tool',
    sculptSymmetry: 'Symmetry',
    sculptContinuous: 'Continuous',
    sculptRadius: 'Radius (-X)',
    sculptIntensity: 'Intensity (-C)',
    sculptHardness: 'Hardness',
    sculptCulling: 'Thin surface (front vertex only)',
    sculptAlphaTitle: 'Alpha',
    sculptAlphaTex: 'Texture',
    sculptImportAlpha: 'Import alpha tex (jpg, png...)',
    sculptNegative: 'Negative (N or -Alt)',
    sculptColor: 'Albedo',
    sculptRoughness: 'Roughness',
    sculptMetallic: 'Metallic',
    sculptClay: 'Clay',
    sculptAccumulate: 'Accumulate (no limit per stroke)',
    sculptColorGlobal: 'Global',
    sculptPickColor: 'Picking Material',
    sculptTangentialSmoothing: 'Relax only',
    sculptTopologicalCheck: 'Topological check',
    sculptMoveAlongNormal: 'Move along normal (N or -Alt)',
    sculptMaskingClear: 'Clear (-Ctrl + Drag)',
    sculptMaskingInvert: 'Invert (-Ctrl + Click)',
    sculptMaskingBlur: 'Blur',
    sculptMaskingSharpen: 'Sharpen',
    sculptDeleteMesh: 'Delete the mesh ?',
    sculptPBRTitle: 'PBR materials',
    sculptPaintAll: 'Paint all',

    // states
    stateTitle: '역사',
    stateUndo: '되돌리기',
    stateRedo: '다시하기',
    stateMaxStack: '최대 스택',

    // wacom
    wacomTitle: '와콤 테블릿',
    wacomRadius: '압력 반지름',
    wacomIntensity: '압력 강도',

    // rendering
    renderingTitle: '렌더링',
    renderingGrid: '그리드 보이기',
    renderingSymmetryLine: '대칭선 보이기',
    renderingMatcap: 'Matcap',
    renderingPBR: 'PBR',
    renderingTransparency: '투명도',
    renderingNormal: '노말 쉐이더',
    renderingUV: 'UV 쉐이더',
    renderingShader: '쉐이더',
    renderingMaterial: '질',
    renderingImportUV: '가져오기 (jpg, png...)',
    renderingExtra: '추가',
    renderingFlat: '편평한 (느리게)',
    renderingWireframe: '와이어프레임 (느리게)',

    // matcaps
    matcapPearl: 'Pearl',
    matcapClay: 'Clay',
    matcapSkin: 'Skin',
    matcapGreen: 'Green',
    matcapWhite: 'White',
    matcapBronze: 'Bronze',
    matcapChavant: 'Chavant',
    matcapDrink: 'Drink',
    matcapRedVelvet: 'Red Velvet',
    matcapOrange: 'Orange',

    // sketchfab
    sketchfabTitle: 'Sketchfab으로 가기 !',
    sketchfabUpload: '올리기',
    sketchfabUploadMessage: 'Please enter your sketchfab API Key.\n' +
    'You can also leave "guest" to upload anonymously.\n' +
    '(a new window will pop up when the uploading and processing is finished)',
    sketchfabUploadError: function (error) {
      return 'Sketchfab upload error :\n' + error;
    },
    sketchfabUploadSuccess: 'Upload success !\nHere is your link :',
    sketchfabAbort: 'Abort the last upload ?',

    donate: 'Donate !'
  };

  return TR;
});<commit_msg>fix 체우기 -> 채우기<commit_after>define([], function () {

  'use strict';

  var TR = {
    // config
    configTitle: '환경설정',

    // background
    backgroundTitle: '배경',
    backgroundReset: '초기화',
    backgroundImport: '배경 (jpg, png...)',
    backgroundFill: '채우기',

    // camera
    cameraTitle: '카메라',
    cameraReset: '뷰',
    cameraCenter: '초기화 (bar)',
    cameraFront: '앞쪽 (F)',
    cameraLeft: '왼쪽 (L)',
    cameraTop: '위쪽 (T)',
    cameraMode: '모드',
    cameraOrbit: '궤도 (Turntable)',
    cameraSpherical: '구 (Trackball)',
    cameraPlane: '평면 (Trackball)',
    cameraProjection: '투사',
    cameraPerspective: '원근법',
    cameraOrthographic: '정사영법',
    cameraFov: '화',
    cameraPivot: '피봇 고르기',

    // file
    fileTitle: '파일 (가져오기/내보내기)',
    fileImportTitle: '가져오기',
    fileAdd: '파일 (obj, sgl, ply, stl)',
    fileExportMeshTitle: '메쉬 내보내기',
    fileExportSceneTitle: '장면 내보내기',
    fileExportSGL: 'sgl로 저장하기',
    fileExportOBJ: 'obj로 저장하기',
    fileExportPLY: 'ply로 저장하기',
    fileExportSTL: 'stl로 저장하기',
    fileReplayerTitle: '리플레이어 (BETA)',
    fileReplayerImport: 'rep 로드하기',
    fileReplayerExport: 'rep 저장하기',

    // replayer
    replayTitle: '리플레이 환경설정',
    replayPaused: '정지',
    replaySpeed: '리플레이 속',
    replayOverride: '덮기',

    // scene
    sceneTitle: '장면',
    sceneReset: '장면 초기화',
    sceneAddSphere: '구 추가하기 ',

    // mesh
    meshTitle: '메쉬',
    meshNbVertices: '점들 : ',
    meshNbFaces: '면들 : ',

    // topology
    topologyTitle: '토폴로',

    //multires
    multiresTitle: '다중 해상도',
    multiresSubdivide: '세분화',
    multiresReverse: '리버스',
    multiresResolution: '해상도',
    multiresNoLower: '더 낮은 해상도가 존재하지 않습니다.',
    multiresNoHigher: '더 높은 해상도가 존재하지 않습니다.',
    multiresDelHigher: '더 높은 것을 삭제',
    multiresDelLower: '더 낮은 것을 삭제',
    multiresSelectLowest: '리버싱 하기 전에 더 낮은 해상도를 고르시오.',
    multiresSelectHighest: '세분화 하기 전에 더 높은 해상도를 고르시오',
    multiresWarnBigMesh: function (nbFacesNext) {
      return '다음 세분화 레벨은 ' + nbFacesNext + ' 면만큼 도달할 것이다.\n' +
          '만약 당신이 무엇을 하는지 안다면 "세분화"를 다시 클릭하세요.';
    },
    multiresNotReversible: '이 메쉬는 리버싱할 수 없습니다.\n' +
    '이 메쉬는 여러가지 메쉬의 표면의 세분화를 product한 것이 아닙니다.(loop-catmull)',

    // remesh
    remeshTitle: 'Voxel Remeshing',
    remeshRemesh: 'Remesh',
    remeshResolution: 'Resolution',
    remeshBlock: 'Block',

    // dynamic
    dynamicTitle: 'Dynamic Topology',
    dynamicActivated: 'Activated (no quads)',
    dynamicSubdivision: 'Subdivision',
    dynamicDecimation: 'Decimation',
    dynamicLinear: 'Linear subdivision',

    // sculpt
    sculptTitle: 'Sculpting & Painting',
    sculptBrush: '브러쉬 (1)',
    sculptInflate: 'Inflate (2)',
    sculptTwist: 'Twist (3)',
    sculptSmooth: 'Smooth (4 or -Shift)',
    sculptFlatten: 'Flatten (5)',
    sculptPinch: 'Pinch (6)',
    sculptCrease: 'Crease (7)',
    sculptDrag: 'Drag (8)',
    sculptPaint: 'Paint (9)',
    sculptMasking: 'Masking (-Ctrl)',
    sculptMove: 'Move (0)',
    sculptScale: 'Scale',
    sculptTranslate: 'Translate (E)',
    sculptRotate: 'Rotate (R)',
    sculptTool: 'Tool',
    sculptSymmetry: 'Symmetry',
    sculptContinuous: 'Continuous',
    sculptRadius: 'Radius (-X)',
    sculptIntensity: 'Intensity (-C)',
    sculptHardness: 'Hardness',
    sculptCulling: 'Thin surface (front vertex only)',
    sculptAlphaTitle: 'Alpha',
    sculptAlphaTex: 'Texture',
    sculptImportAlpha: 'Import alpha tex (jpg, png...)',
    sculptNegative: 'Negative (N or -Alt)',
    sculptColor: 'Albedo',
    sculptRoughness: 'Roughness',
    sculptMetallic: 'Metallic',
    sculptClay: 'Clay',
    sculptAccumulate: 'Accumulate (no limit per stroke)',
    sculptColorGlobal: 'Global',
    sculptPickColor: 'Picking Material',
    sculptTangentialSmoothing: 'Relax only',
    sculptTopologicalCheck: 'Topological check',
    sculptMoveAlongNormal: 'Move along normal (N or -Alt)',
    sculptMaskingClear: 'Clear (-Ctrl + Drag)',
    sculptMaskingInvert: 'Invert (-Ctrl + Click)',
    sculptMaskingBlur: 'Blur',
    sculptMaskingSharpen: 'Sharpen',
    sculptDeleteMesh: 'Delete the mesh ?',
    sculptPBRTitle: 'PBR materials',
    sculptPaintAll: 'Paint all',

    // states
    stateTitle: '역사',
    stateUndo: '되돌리기',
    stateRedo: '다시하기',
    stateMaxStack: '최대 스택',

    // wacom
    wacomTitle: '와콤 테블릿',
    wacomRadius: '압력 반지름',
    wacomIntensity: '압력 강도',

    // rendering
    renderingTitle: '렌더링',
    renderingGrid: '그리드 보이기',
    renderingSymmetryLine: '대칭선 보이기',
    renderingMatcap: 'Matcap',
    renderingPBR: 'PBR',
    renderingTransparency: '투명도',
    renderingNormal: '노말 쉐이더',
    renderingUV: 'UV 쉐이더',
    renderingShader: '쉐이더',
    renderingMaterial: '질',
    renderingImportUV: '가져오기 (jpg, png...)',
    renderingExtra: '추가',
    renderingFlat: '편평한 (느리게)',
    renderingWireframe: '와이어프레임 (느리게)',

    // matcaps
    matcapPearl: 'Pearl',
    matcapClay: 'Clay',
    matcapSkin: 'Skin',
    matcapGreen: 'Green',
    matcapWhite: 'White',
    matcapBronze: 'Bronze',
    matcapChavant: 'Chavant',
    matcapDrink: 'Drink',
    matcapRedVelvet: 'Red Velvet',
    matcapOrange: 'Orange',

    // sketchfab
    sketchfabTitle: 'Sketchfab으로 가기 !',
    sketchfabUpload: '올리기',
    sketchfabUploadMessage: 'Please enter your sketchfab API Key.\n' +
    'You can also leave "guest" to upload anonymously.\n' +
    '(a new window will pop up when the uploading and processing is finished)',
    sketchfabUploadError: function (error) {
      return 'Sketchfab upload error :\n' + error;
    },
    sketchfabUploadSuccess: 'Upload success !\nHere is your link :',
    sketchfabAbort: 'Abort the last upload ?',

    donate: 'Donate !'
  };

  return TR;
});<|endoftext|>


<commit_before>import React from 'react';
import { StatusBar, StyleSheet, Text, View } from 'react-native';
import isEmpty from 'lodash.isempty';
import Icon from '../icons/Icon';

const DummyNavButton = () => (
  <View style={styles.dummyNavBtn} />
);

const Title = (props) => {
  const {
    text,
  ...attributes,
  } = props;

  return (
    <Text
      numberOfLines={1}
      {...attributes}
    >
      {text}
    </Text>
  );
};

const NavButton = (props) => {
  const {
    icon,
  ...attributes,
  } = props;

  return (
    <Icon
      name={icon}
      {...attributes}
    />
  );
};

function generateChild(value, type) {
  if (React.isValidElement(value)) {
    return (
      <View key={type}>
        {value}
      </View>
    );
  } else if (typeof value === 'object' && !isEmpty(value)) {
    return type === 'center' ?
      <Title {...value} key={type} /> :
      <NavButton {...value} key={type} />;
  }
  return type === 'center' ? null : <DummyNavButton key={type} />;
}

function populateChildren(propChildren) {
  const childrenArray = [];

  const leftComponent = generateChild(propChildren.leftComponent, 'left');
  const centerComponent = generateChild(propChildren.centerComponent, 'center');
  const rightComponent = generateChild(propChildren.rightComponent, 'right');

  childrenArray.push(
    leftComponent,
    centerComponent,
    rightComponent,
  );

  return childrenArray;
}

const Header = (props) => {
  const {
    children,
    statusBarProps,
    leftComponent,
    centerComponent,
    rightComponent,
    outerContainerStyles,
    innerContainerStyles,
    ...attributes,
  } = props;

  let propChildren = [];

  if (leftComponent || centerComponent || rightComponent) {
    propChildren = populateChildren({
      leftComponent,
      centerComponent,
      rightComponent,
    });
  }

  return (
    <View style={[styles.outerContainer, outerContainerStyles]} {...attributes}>
      <StatusBar {...statusBarProps} />
      <View style={[styles.innerContainer, innerContainerStyles]}>
        {propChildren.length > 0 ? propChildren : children}
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  dummyNavBtn: {
    height: 24,
    width: 24,
  },
  innerContainer: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'flex-end',
  },
  outerContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: '#fff',
    borderBottomColor: '#f2f2f2',
    borderBottomWidth: 1,
    padding: 15,
    height: 70,
  },
});

export default Header;
<commit_msg>Add backgroundColor prop<commit_after>import React from 'react';
import { StatusBar, StyleSheet, Text, View } from 'react-native';
import isEmpty from 'lodash.isempty';
import Icon from '../icons/Icon';

const DummyNavButton = () => (
  <View style={styles.dummyNavBtn} />
);

const Title = (props) => {
  const {
    text,
  ...attributes,
  } = props;

  return (
    <Text
      numberOfLines={1}
      {...attributes}
    >
      {text}
    </Text>
  );
};

const NavButton = (props) => {
  const {
    icon,
  ...attributes,
  } = props;

  return (
    <Icon
      name={icon}
      {...attributes}
    />
  );
};

function generateChild(value, type) {
  if (React.isValidElement(value)) {
    return (
      <View key={type}>
        {value}
      </View>
    );
  } else if (typeof value === 'object' && !isEmpty(value)) {
    return type === 'center' ?
      <Title {...value} key={type} /> :
      <NavButton {...value} key={type} />;
  }
  return type === 'center' ? null : <DummyNavButton key={type} />;
}

function populateChildren(propChildren) {
  const childrenArray = [];

  const leftComponent = generateChild(propChildren.leftComponent, 'left');
  const centerComponent = generateChild(propChildren.centerComponent, 'center');
  const rightComponent = generateChild(propChildren.rightComponent, 'right');

  childrenArray.push(
    leftComponent,
    centerComponent,
    rightComponent,
  );

  return childrenArray;
}

const Header = (props) => {
  const {
    children,
    statusBarProps,
    leftComponent,
    centerComponent,
    rightComponent,
    backgroundColor,
    outerContainerStyles,
    innerContainerStyles,
    ...attributes,
  } = props;

  let propChildren = [];

  if (leftComponent || centerComponent || rightComponent) {
    propChildren = populateChildren({
      leftComponent,
      centerComponent,
      rightComponent,
    });
  }

  return (
    <View style={[styles.outerContainer, { backgroundColor }, outerContainerStyles]} {...attributes}>
      <StatusBar {...statusBarProps} />
      <View style={[styles.innerContainer, innerContainerStyles]}>
        {propChildren.length > 0 ? propChildren : children}
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  dummyNavBtn: {
    height: 24,
    width: 24,
  },
  innerContainer: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'flex-end',
  },
  outerContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: '#fff',
    borderBottomColor: '#f2f2f2',
    borderBottomWidth: 1,
    padding: 15,
    height: 70,
  },
});

export default Header;
<|endoftext|>


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

  angular
    .module('polls')
    .run(menuConfig);

  menuConfig.$inject = ['Menus'];

  function menuConfig(Menus) {
    // Set top bar menu items
    Menus.addMenuItem('topbar', {
      title: 'Polls',
      state: 'polls.list',
      position: 0
    });
    // Menus.addMenuItem('topbar', {
    //   title: 'Polls',
    //   state: 'polls',
    //   type: 'dropdown',
    //   roles: ['*']
    // });

    // // Add the dropdown list item
    // Menus.addSubMenuItem('topbar', 'polls', {
    //   title: 'List Polls',
    //   state: 'polls.list'
    // });

    // // Add the dropdown create item
    // Menus.addSubMenuItem('topbar', 'polls', {
    //   title: 'Create Poll',
    //   state: 'polls.create',
    //   roles: ['user']
    // });
  }
}());
<commit_msg>Commited from lenh at Mon, Aug 14, 2017 12:07:06 PM<commit_after>(function () {
  'use strict';

  angular
    .module('polls')
    .run(menuConfig);

  menuConfig.$inject = ['Menus'];

  function menuConfig(Menus) {
    // Set top bar menu items
    Menus.addMenuItem('topbar', {
      title: 'Polls',
      state: 'polls.list',
      roles: ['*'],
      position: 0
    });
    // Menus.addMenuItem('topbar', {
    //   title: 'Polls',
    //   state: 'polls',
    //   type: 'dropdown',
    //   roles: ['*']
    // });

    // // Add the dropdown list item
    // Menus.addSubMenuItem('topbar', 'polls', {
    //   title: 'List Polls',
    //   state: 'polls.list'
    // });

    // // Add the dropdown create item
    // Menus.addSubMenuItem('topbar', 'polls', {
    //   title: 'Create Poll',
    //   state: 'polls.create',
    //   roles: ['user']
    // });
  }
}());
<|endoftext|>


<commit_before>/*
 * Copyright 2009 Kantega AS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function aksessFormValidate() {
    var formOk = true;
    $(".formElement").each(function() {
        $(this).removeClass("error");
        var formFieldOk = true;
        // Check mandatory fields
        if ($(this).hasClass("mandatory")) {
            if ($("input[type=text]", this).val() == "") {
                formFieldOk = false;
            }
            if ($("input[type=textarea]", this).val() == "") {
                formFieldOk = false;
            }
            if ($("input:checkbox", this).length > 0) {
                if ($("input:checkbox:checked", this).length == 0) {
                    formFieldOk = false;
                }
            }
            if ($("input:radio", this).length > 0) {
                if ($("input:radio:checked", this).length == 0) {
                    formFieldOk = false;
                }
            }
        }
        // Check email fields
        var email = $("input.email", this).val();
        if (email && email != "") {
            if (email.indexOf("@") == -1) {
                formFieldOk = false;
            }
        }
        // Check number fields
        var number = $("input.number", this).val();
        if (number && number != "") {
            var n = parseInt(number, 10);
            if (isNaN(n)) {
                formFieldOk = false;
            }
        }

        if (!formFieldOk) {
            formOk = false;
            $(this).addClass("error");
        }
    }
    );

    if (formOk) {
        $("#form_Error").hide();
    } else {
        $("#form_Error").show();
        var form_Error = document.getElementById("form_Error");
        if (form_Error && form_Error.scrollIntoView) {
            form_Error.scrollIntoView();
        }
    }

    return formOk;
}<commit_msg>Forms module: Validate textareas<commit_after>/*
 * Copyright 2009 Kantega AS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function aksessFormValidate() {
    var formOk = true;
    $(".formElement").each(function() {
        $(this).removeClass("error");
        var formFieldOk = true;
        // Check mandatory fields
        if ($(this).hasClass("mandatory")) {
            if ($("input[type=text]", this).val() == "") {
                formFieldOk = false;
            }
            if ($("textarea", this).val() == "") {
                formFieldOk = false;
            }
            if ($("input:checkbox", this).length > 0) {
                if ($("input:checkbox:checked", this).length == 0) {
                    formFieldOk = false;
                }
            }
            if ($("input:radio", this).length > 0) {
                if ($("input:radio:checked", this).length == 0) {
                    formFieldOk = false;
                }
            }
        }
        // Check email fields
        var email = $("input.email", this).val();
        if (email && email != "") {
            if (email.indexOf("@") == -1) {
                formFieldOk = false;
            }
        }
        // Check number fields
        var number = $("input.number", this).val();
        if (number && number != "") {
            var n = parseInt(number, 10);
            if (isNaN(n)) {
                formFieldOk = false;
            }
        }

        if (!formFieldOk) {
            formOk = false;
            $(this).addClass("error");
        }
    }
    );

    if (formOk) {
        $("#form_Error").hide();
    } else {
        $("#form_Error").show();
        var form_Error = document.getElementById("form_Error");
        if (form_Error && form_Error.scrollIntoView) {
            form_Error.scrollIntoView();
        }
    }

    return formOk;
}<|endoftext|>


<commit_before>if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports){
  module.exports = 'highcharts-ng';
}
(function () {
  'use strict';
  /*global angular: false, Highcharts: false */

  angular.module('highcharts-ng', [])
    .factory('highchartsNGUtils', highchartsNGUtils)
    .directive('highchart', ['highchartsNGUtils', '$timeout', highchart]);

  function highchartsNGUtils() {

    return {

      //IE8 support
      indexOf: function (arr, find, i /*opt*/) {
        if (i === undefined) i = 0;
        if (i < 0) i += arr.length;
        if (i < 0) i = 0;
        for (var n = arr.length; i < n; i++)
          if (i in arr && arr[i] === find)
            return i;
        return -1;
      },

      prependMethod: function (obj, method, func) {
        var original = obj[method];
        obj[method] = function () {
          var args = Array.prototype.slice.call(arguments);
          func.apply(this, args);
          if (original) {
            return original.apply(this, args);
          } else {
            return;
          }

        };
      },

      deepExtend: function deepExtend(destination, source) {
        //Slightly strange behaviour in edge cases (e.g. passing in non objects)
        //But does the job for current use cases.
        if (angular.isArray(source)) {
          destination = angular.isArray(destination) ? destination : [];
          for (var i = 0; i < source.length; i++) {
            destination[i] = deepExtend(destination[i] || {}, source[i]);
          }
        } else if (angular.isObject(source)) {
          for (var property in source) {
            destination[property] = deepExtend(destination[property] || {}, source[property]);
          }
        } else {
          destination = source;
        }
        return destination;
      }
    };
  }

  function highchart(highchartsNGUtils, $timeout) {

    // acceptable shared state
    var seriesId = 0;
    var ensureIds = function (series) {
      var changed = false;
      angular.forEach(series, function(s) {
        if (!angular.isDefined(s.id)) {
          s.id = 'series-' + seriesId++;
          changed = true;
        }
      });
      return changed;
    };

    // immutable
    var axisNames = [ 'xAxis', 'yAxis' ];

    var getMergedOptions = function (scope, element, config) {
      var mergedOptions = {};

      var defaultOptions = {
        chart: {
          events: {}
        },
        title: {},
        subtitle: {},
        series: [],
        credits: {},
        plotOptions: {},
        navigator: {enabled: false}
      };

      if (config.options) {
        mergedOptions = highchartsNGUtils.deepExtend(defaultOptions, config.options);
      } else {
        mergedOptions = defaultOptions;
      }
      mergedOptions.chart.renderTo = element[0];

      angular.forEach(axisNames, function(axisName) {
        if(angular.isDefined(config[axisName])) {
          mergedOptions[axisName] = angular.copy(config[axisName]);

          if(angular.isDefined(config[axisName].currentMin) ||
              angular.isDefined(config[axisName].currentMax)) {

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'selection', function(e){
              var thisChart = this;
              if (e[axisName]) {
                scope.$apply(function () {
                  scope.config[axisName].currentMin = e[axisName][0].min;
                  scope.config[axisName].currentMax = e[axisName][0].max;
                });
              } else {
                //handle reset button - zoom out to all
                scope.$apply(function () {
                  scope.config[axisName].currentMin = thisChart[axisName][0].dataMin;
                  scope.config[axisName].currentMax = thisChart[axisName][0].dataMax;
                });
              }
            });

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
              scope.config[axisName].currentMin = this[axisName][0].min || scope.config[axisName].currentMin;
              scope.config[axisName].currentMax = this[axisName][0].max || scope.config[axisName].currentMax;
            });
          }
        }
      });

      if(config.title) {
        mergedOptions.title = config.title;
      }
      if (config.subtitle) {
        mergedOptions.subtitle = config.subtitle;
      }
      if (config.credits) {
        mergedOptions.credits = config.credits;
      }
      if(config.size) {
        if (config.size.width) {
          mergedOptions.chart.width = config.size.width;
        }
        if (config.size.height) {
          mergedOptions.chart.height = config.size.height;
        }
      }
      return mergedOptions;
    };

    var updateZoom = function (axis, modelAxis) {
      var extremes = axis.getExtremes();
      if(modelAxis.currentMin !== extremes.dataMin || modelAxis.currentMax !== extremes.dataMax) {
        axis.setExtremes(modelAxis.currentMin, modelAxis.currentMax, false);
      }
    };

    var processExtremes = function(chart, axis, axisName) {
      if(axis.currentMin || axis.currentMax) {
        chart[axisName][0].setExtremes(axis.currentMin, axis.currentMax, true);
      }
    };

    var chartOptionsWithoutEasyOptions = function (options) {
      return angular.extend({}, options, {data: null, visible: null});
    };

    return {
      restrict: 'EAC',
      replace: true,
      template: '

',
      scope: {
        config: '=',
        disableDataWatch: '='
      },
      link: function (scope, element, attrs) {
        // We keep some chart-specific variables here as a closure
        // instead of storing them on 'scope'.

        // prevSeriesOptions is maintained by processSeries
        var prevSeriesOptions = {};

        var processSeries = function(series) {
          var i;
          var ids = [];

          if(series) {
            var setIds = ensureIds(series);
            if(setIds) {
              //If we have set some ids this will trigger another digest cycle.
              //In this scenario just return early and let the next cycle take care of changes
              return false;
            }

            //Find series to add or update
            angular.forEach(series, function(s) {
              ids.push(s.id);
              var chartSeries = chart.get(s.id);
              if (chartSeries) {
                if (!angular.equals(prevSeriesOptions[s.id], chartOptionsWithoutEasyOptions(s))) {
                  chartSeries.update(angular.copy(s), false);
                } else {
                  if (s.visible !== undefined && chartSeries.visible !== s.visible) {
                    chartSeries.setVisible(s.visible, false);
                  }
                  chartSeries.setData(angular.copy(s.data), false);
                }
              } else {
                chart.addSeries(angular.copy(s), false);
              }
              prevSeriesOptions[s.id] = chartOptionsWithoutEasyOptions(s);
            });

            //  Shows no data text if all series are empty
            if(scope.config.noData) {
              var chartContainsData = false;

              for(i = 0; i < series.length; i++) {
                if (series[i].data && series[i].data.length > 0) {
                  chartContainsData = true;

                  break;
                }
              }

              if (!chartContainsData) {
                chart.showLoading(scope.config.noData);
              } else {
                chart.hideLoading();
              }
            }
          }

          //Now remove any missing series
          for(i = chart.series.length - 1; i >= 0; i--) {
            var s = chart.series[i];
            if (s.options.id !== 'highcharts-navigator-series' && highchartsNGUtils.indexOf(ids, s.options.id) < 0) {
              s.remove(false);
            }
          }

          return true;
        };

        // chart is maintained by initChart
        var chart = false;
        var initChart = function() {
          if (chart) chart.destroy();
          prevSeriesOptions = {};
          var config = scope.config || {};
          var mergedOptions = getMergedOptions(scope, element, config);
          var func = config.func || undefined;
          chart = config.useHighStocks ?
            new Highcharts.StockChart(mergedOptions, func) :
            new Highcharts.Chart(mergedOptions, func);
          for (var i = 0; i < axisNames.length; i++) {
            if (config[axisNames[i]]) {
              processExtremes(chart, config[axisNames[i]], axisNames[i]);
            }
          }
          if(config.loading) {
            chart.showLoading();
          }

        };
        initChart();

        if(scope.disableDataWatch){
          scope.$watchCollection('config.series', function (newSeries, oldSeries) {
            processSeries(newSeries);
            chart.redraw();
          });
        } else {
          scope.$watch('config.series', function (newSeries, oldSeries) {
            var needsRedraw = processSeries(newSeries);
            if(needsRedraw) {
              chart.redraw();
            }
          }, true);
        }

        scope.$watch('config.title', function (newTitle) {
          chart.setTitle(newTitle, true);
        }, true);

        scope.$watch('config.subtitle', function (newSubtitle) {
          chart.setTitle(true, newSubtitle);
        }, true);

        scope.$watch('config.loading', function (loading) {
          if(loading) {
            chart.showLoading();
          } else {
            chart.hideLoading();
          }
        });

        scope.$watch('config.credits.enabled', function (enabled) {
          if (enabled) {
            chart.credits.show();
          } else if (chart.credits) {
            chart.credits.hide();
          }
        });

        scope.$watch('config.useHighStocks', function (useHighStocks, oldUseHighStocks) {
          if(useHighStocks === oldUseHighStocks) return;
          initChart();
        });

        angular.forEach(axisNames, function(axisName) {
          scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
            if (newAxes === oldAxes) return;
            if(newAxes) {
              chart[axisName][0].update(newAxes, false);
              updateZoom(chart[axisName][0], angular.copy(newAxes));
              chart.redraw();
            }
          }, true);
        });
        scope.$watch('config.options', function (newOptions, oldOptions, scope) {
          //do nothing when called on registration
          if (newOptions === oldOptions) return;
          initChart();
          processSeries(scope.config.series);
          chart.redraw();
        }, true);

        scope.$watch('config.size', function (newSize, oldSize) {
          if(newSize === oldSize) return;
          if(newSize) {
            chart.setSize(newSize.width || undefined, newSize.height || undefined);
          }
        }, true);

        scope.$on('highchartsng.reflow', function () {
          chart.reflow();
        });

        scope.$on('$destroy', function() {
          if (chart) {
            chart.destroy();
            $timeout(function(){
              element.remove();
            }, 0);
          }
        });

      }
    };
  }

}());
<commit_msg>Add a getter on the Highcharts chart object<commit_after>if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports){
  module.exports = 'highcharts-ng';
}
(function () {
  'use strict';
  /*global angular: false, Highcharts: false */

  angular.module('highcharts-ng', [])
    .factory('highchartsNGUtils', highchartsNGUtils)
    .directive('highchart', ['highchartsNGUtils', '$timeout', highchart]);

  function highchartsNGUtils() {

    return {

      //IE8 support
      indexOf: function (arr, find, i /*opt*/) {
        if (i === undefined) i = 0;
        if (i < 0) i += arr.length;
        if (i < 0) i = 0;
        for (var n = arr.length; i < n; i++)
          if (i in arr && arr[i] === find)
            return i;
        return -1;
      },

      prependMethod: function (obj, method, func) {
        var original = obj[method];
        obj[method] = function () {
          var args = Array.prototype.slice.call(arguments);
          func.apply(this, args);
          if (original) {
            return original.apply(this, args);
          } else {
            return;
          }

        };
      },

      deepExtend: function deepExtend(destination, source) {
        //Slightly strange behaviour in edge cases (e.g. passing in non objects)
        //But does the job for current use cases.
        if (angular.isArray(source)) {
          destination = angular.isArray(destination) ? destination : [];
          for (var i = 0; i < source.length; i++) {
            destination[i] = deepExtend(destination[i] || {}, source[i]);
          }
        } else if (angular.isObject(source)) {
          for (var property in source) {
            destination[property] = deepExtend(destination[property] || {}, source[property]);
          }
        } else {
          destination = source;
        }
        return destination;
      }
    };
  }

  function highchart(highchartsNGUtils, $timeout) {

    // acceptable shared state
    var seriesId = 0;
    var ensureIds = function (series) {
      var changed = false;
      angular.forEach(series, function(s) {
        if (!angular.isDefined(s.id)) {
          s.id = 'series-' + seriesId++;
          changed = true;
        }
      });
      return changed;
    };

    // immutable
    var axisNames = [ 'xAxis', 'yAxis' ];

    var getMergedOptions = function (scope, element, config) {
      var mergedOptions = {};

      var defaultOptions = {
        chart: {
          events: {}
        },
        title: {},
        subtitle: {},
        series: [],
        credits: {},
        plotOptions: {},
        navigator: {enabled: false}
      };

      if (config.options) {
        mergedOptions = highchartsNGUtils.deepExtend(defaultOptions, config.options);
      } else {
        mergedOptions = defaultOptions;
      }
      mergedOptions.chart.renderTo = element[0];

      angular.forEach(axisNames, function(axisName) {
        if(angular.isDefined(config[axisName])) {
          mergedOptions[axisName] = angular.copy(config[axisName]);

          if(angular.isDefined(config[axisName].currentMin) ||
              angular.isDefined(config[axisName].currentMax)) {

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'selection', function(e){
              var thisChart = this;
              if (e[axisName]) {
                scope.$apply(function () {
                  scope.config[axisName].currentMin = e[axisName][0].min;
                  scope.config[axisName].currentMax = e[axisName][0].max;
                });
              } else {
                //handle reset button - zoom out to all
                scope.$apply(function () {
                  scope.config[axisName].currentMin = thisChart[axisName][0].dataMin;
                  scope.config[axisName].currentMax = thisChart[axisName][0].dataMax;
                });
              }
            });

            highchartsNGUtils.prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
              scope.config[axisName].currentMin = this[axisName][0].min || scope.config[axisName].currentMin;
              scope.config[axisName].currentMax = this[axisName][0].max || scope.config[axisName].currentMax;
            });
          }
        }
      });

      if(config.title) {
        mergedOptions.title = config.title;
      }
      if (config.subtitle) {
        mergedOptions.subtitle = config.subtitle;
      }
      if (config.credits) {
        mergedOptions.credits = config.credits;
      }
      if(config.size) {
        if (config.size.width) {
          mergedOptions.chart.width = config.size.width;
        }
        if (config.size.height) {
          mergedOptions.chart.height = config.size.height;
        }
      }
      return mergedOptions;
    };

    var updateZoom = function (axis, modelAxis) {
      var extremes = axis.getExtremes();
      if(modelAxis.currentMin !== extremes.dataMin || modelAxis.currentMax !== extremes.dataMax) {
        axis.setExtremes(modelAxis.currentMin, modelAxis.currentMax, false);
      }
    };

    var processExtremes = function(chart, axis, axisName) {
      if(axis.currentMin || axis.currentMax) {
        chart[axisName][0].setExtremes(axis.currentMin, axis.currentMax, true);
      }
    };

    var chartOptionsWithoutEasyOptions = function (options) {
      return angular.extend({}, options, {data: null, visible: null});
    };

    return {
      restrict: 'EAC',
      replace: true,
      template: '

',
      scope: {
        config: '=',
        disableDataWatch: '='
      },
      link: function (scope, element, attrs) {
        // We keep some chart-specific variables here as a closure
        // instead of storing them on 'scope'.

        // prevSeriesOptions is maintained by processSeries
        var prevSeriesOptions = {};

        var processSeries = function(series) {
          var i;
          var ids = [];

          if(series) {
            var setIds = ensureIds(series);
            if(setIds) {
              //If we have set some ids this will trigger another digest cycle.
              //In this scenario just return early and let the next cycle take care of changes
              return false;
            }

            //Find series to add or update
            angular.forEach(series, function(s) {
              ids.push(s.id);
              var chartSeries = chart.get(s.id);
              if (chartSeries) {
                if (!angular.equals(prevSeriesOptions[s.id], chartOptionsWithoutEasyOptions(s))) {
                  chartSeries.update(angular.copy(s), false);
                } else {
                  if (s.visible !== undefined && chartSeries.visible !== s.visible) {
                    chartSeries.setVisible(s.visible, false);
                  }
                  chartSeries.setData(angular.copy(s.data), false);
                }
              } else {
                chart.addSeries(angular.copy(s), false);
              }
              prevSeriesOptions[s.id] = chartOptionsWithoutEasyOptions(s);
            });

            //  Shows no data text if all series are empty
            if(scope.config.noData) {
              var chartContainsData = false;

              for(i = 0; i < series.length; i++) {
                if (series[i].data && series[i].data.length > 0) {
                  chartContainsData = true;

                  break;
                }
              }

              if (!chartContainsData) {
                chart.showLoading(scope.config.noData);
              } else {
                chart.hideLoading();
              }
            }
          }

          //Now remove any missing series
          for(i = chart.series.length - 1; i >= 0; i--) {
            var s = chart.series[i];
            if (s.options.id !== 'highcharts-navigator-series' && highchartsNGUtils.indexOf(ids, s.options.id) < 0) {
              s.remove(false);
            }
          }

          return true;
        };

        // chart is maintained by initChart
        var chart = false;
        var initChart = function() {
          if (chart) chart.destroy();
          prevSeriesOptions = {};
          var config = scope.config || {};
          var mergedOptions = getMergedOptions(scope, element, config);
          var func = config.func || undefined;
          chart = config.useHighStocks ?
            new Highcharts.StockChart(mergedOptions, func) :
            new Highcharts.Chart(mergedOptions, func);
          for (var i = 0; i < axisNames.length; i++) {
            if (config[axisNames[i]]) {
              processExtremes(chart, config[axisNames[i]], axisNames[i]);
            }
          }
          if(config.loading) {
            chart.showLoading();
          }
          config.getHighcharts = function() {
            return chart;
          };

        };
        initChart();

        if(scope.disableDataWatch){
          scope.$watchCollection('config.series', function (newSeries, oldSeries) {
            processSeries(newSeries);
            chart.redraw();
          });
        } else {
          scope.$watch('config.series', function (newSeries, oldSeries) {
            var needsRedraw = processSeries(newSeries);
            if(needsRedraw) {
              chart.redraw();
            }
          }, true);
        }

        scope.$watch('config.title', function (newTitle) {
          chart.setTitle(newTitle, true);
        }, true);

        scope.$watch('config.subtitle', function (newSubtitle) {
          chart.setTitle(true, newSubtitle);
        }, true);

        scope.$watch('config.loading', function (loading) {
          if(loading) {
            chart.showLoading();
          } else {
            chart.hideLoading();
          }
        });

        scope.$watch('config.credits.enabled', function (enabled) {
          if (enabled) {
            chart.credits.show();
          } else if (chart.credits) {
            chart.credits.hide();
          }
        });

        scope.$watch('config.useHighStocks', function (useHighStocks, oldUseHighStocks) {
          if(useHighStocks === oldUseHighStocks) return;
          initChart();
        });

        angular.forEach(axisNames, function(axisName) {
          scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
            if (newAxes === oldAxes) return;
            if(newAxes) {
              chart[axisName][0].update(newAxes, false);
              updateZoom(chart[axisName][0], angular.copy(newAxes));
              chart.redraw();
            }
          }, true);
        });
        scope.$watch('config.options', function (newOptions, oldOptions, scope) {
          //do nothing when called on registration
          if (newOptions === oldOptions) return;
          initChart();
          processSeries(scope.config.series);
          chart.redraw();
        }, true);

        scope.$watch('config.size', function (newSize, oldSize) {
          if(newSize === oldSize) return;
          if(newSize) {
            chart.setSize(newSize.width || undefined, newSize.height || undefined);
          }
        }, true);

        scope.$on('highchartsng.reflow', function () {
          chart.reflow();
        });

        scope.$on('$destroy', function() {
          if (chart) {
            chart.destroy();
            $timeout(function(){
              element.remove();
            }, 0);
          }
        });

      }
    };
  }

}());
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { connect } from 'react-redux';
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'
import { fetchInterfaceColList, fetchCaseList, setColData } from '../../../../reducer/modules/interfaceCol'

@connect(
  state => {
    return {
      interfaceColList: state.interfaceCol.interfaceColList,
      currColId: state.interfaceCol.currColId,
      currCaseId: state.interfaceCol.currCaseId,
      isShowCol: state.interfaceCol.isShowCol
    }
  },
  {
    fetchInterfaceColList,
    fetchCaseList,
    setColData
  }
)
@withRouter
export default class InterfaceColContent extends Component {

  static propTypes = {
    match: PropTypes.object,
    interfaceColList: PropTypes.array,
    fetchInterfaceColList: PropTypes.func,
    fetchCaseList: PropTypes.func,
    setColData: PropTypes.func,
    history: PropTypes.object,
    currColId: PropTypes.number,
    currCaseId: PropTypes.number,
    isShowCol: PropTypes.bool
  }

  constructor(props) {
    super(props)
  }

  async componentWillMount() {
    const result = await this.props.fetchInterfaceColList(this.props.match.params.id)
    let { currColId } = this.props;
    const params = this.props.match.params;
    const { actionId } = params;
    currColId = +actionId || +currColId || result.payload.data.data[0].caseList[0]._id;
    this.props.history.push('/project/' + params.id + '/interface/col/' + currColId)
    this.props.fetchCaseList(currColId)
    this.props.setColData({currColId: +currColId, isShowCol: true})
  }

  componentWillReceiveProps(nextProps) {
    const oldCaseId = this.props.match.params.actionId
    const newCaseId = nextProps.match.params.actionId
    if (oldCaseId !== newCaseId) {
      this.props.fetchCaseList(newCaseId);
      this.props.setColData({currColId: +newCaseId, isShowCol: true})
    }
  }

  render() {
    return
hello colContent

  }
}
<commit_msg>feat: col menu<commit_after>import React, { Component } from 'react'
import { connect } from 'react-redux';
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'
import { fetchInterfaceColList, fetchCaseList, setColData } from '../../../../reducer/modules/interfaceCol'

@connect(
  state => {
    return {
      interfaceColList: state.interfaceCol.interfaceColList,
      currColId: state.interfaceCol.currColId,
      currCaseId: state.interfaceCol.currCaseId,
      isShowCol: state.interfaceCol.isShowCol,
      currCaseList: state.interfaceCol.currCaseList
    }
  },
  {
    fetchInterfaceColList,
    fetchCaseList,
    setColData
  }
)
@withRouter
export default class InterfaceColContent extends Component {

  static propTypes = {
    match: PropTypes.object,
    interfaceColList: PropTypes.array,
    fetchInterfaceColList: PropTypes.func,
    fetchCaseList: PropTypes.func,
    setColData: PropTypes.func,
    history: PropTypes.object,
    currCaseList: PropTypes.array,
    currColId: PropTypes.number,
    currCaseId: PropTypes.number,
    isShowCol: PropTypes.bool
  }

  constructor(props) {
    super(props)
  }

  async componentWillMount() {
    const result = await this.props.fetchInterfaceColList(this.props.match.params.id)
    let { currColId } = this.props;
    const params = this.props.match.params;
    const { actionId } = params;
    currColId = +actionId || +currColId || result.payload.data.data[0].caseList[0]._id;
    this.props.history.push('/project/' + params.id + '/interface/col/' + currColId)
    this.props.fetchCaseList(currColId)
    this.props.setColData({currColId: +currColId, isShowCol: true})
  }

  componentWillReceiveProps(nextProps) {
    const oldCaseId = this.props.match.params.actionId
    const newCaseId = nextProps.match.params.actionId
    if (oldCaseId !== newCaseId) {
      this.props.fetchCaseList(newCaseId);
      this.props.setColData({currColId: +newCaseId, isShowCol: true})
    }
  }

  render() {
    return (

hello colContent

        {JSON.stringify(this.props.currCaseList, null, 2)}

    )
  }
}
<|endoftext|>


<commit_before>const fs = require('fs');
const rx = require('rx');
const lwip = require('lwip');
const imgur = require('imgur');
const promisify = require('promisify-node');

const openImage = promisify(lwip.open);
const createImage = promisify(lwip.create);

class ImageHelpers {

  // Public: Creates an image of the board from the given cards using the
  // light-weight image processing library (`lwip`), then writes the result to
  // a file and uploads it to `imgur`.
  //
  // imageFiles - An array of three image files
  // outputFile - The file where the result will be saved
  // upload - (Optional) Defaults to `imgur`, but can be overridden for testing
  //
  // Returns an {Observable} that will `onNext` with the URL of the combined
  // image, or `onError` if anything goes wrong
  static createBoardImage(cards, upload=imgur.uploadFile) {
    let subj = new rx.AsyncSubject();
    let imageFiles = cards.map((c) => `resources/${c.toAsciiString()}.png`);

    if (!fs.existsSync('./output')) {
      fs.mkdirSync('./output');
    }

    let makeImage = null;
    switch (cards.length) {
    case 3:
      makeImage = ImageHelpers.combineThree(imageFiles, './output/flop.png');
      break;
    case 4:
      makeImage = ImageHelpers.combineThree(imageFiles, './output/flop.png')
        .then((outputFile) => ImageHelpers.combineTwo([outputFile, imageFiles[3]], './output/turn.png'));
      break;
    case 5:
      makeImage = ImageHelpers.combineThree(imageFiles, './output/flop.png')
        .then((outputFile) => ImageHelpers.combineThree([outputFile, imageFiles[3], imageFiles[4]], './output/river.png'));
      break;
    default:
      throw new Error(`Attempted to make board image for ${cards.length} cards.`);
    }

    makeImage
      .then((outputFile) => upload(outputFile))
      .then((result) => {
        subj.onNext(result.data.link);
        subj.onCompleted();
      })
      .catch((err) => subj.onError(err));

    return subj;
  }

  // Private: Combines two image files into a single row
  //
  // imageFiles - An array of two image files
  // outputFile - The file where the result will be saved
  //
  // Returns a {Promise} of the resulting file
  static combineTwo(imageFiles, outputFile) {
    let images = [];

    return openImage(imageFiles[0])
      .then((firstImage) => {
        images.push(firstImage);
        return openImage(imageFiles[1]);
      })
      .then((secondImage) => {
        images.push(secondImage);
        return createImage(images[0].width() + images[1].width(), images[0].height(), 'white');
      })
      .then((destImage) => ImageHelpers.paste(images[0], destImage, 0, 0))
      .then((destImage) => ImageHelpers.paste(images[1], destImage, images[0].width(), 0))
      .then((destImage) => ImageHelpers.writeFile(destImage, outputFile));
  }

  // Private: Combines three images files into a single row, using the
  // `combineTwo` sequentially
  //
  // imageFiles - An array of three image files
  // outputFile - The file where the result will be saved
  //
  // Returns a {Promise} of the resulting file
  static combineThree(imageFiles, outputFile) {
    return ImageHelpers.combineTwo(imageFiles.slice(0, 2), outputFile)
      .then(() => ImageHelpers.combineTwo([outputFile, imageFiles[2]], outputFile));
  }

  // Private: Returns a Promisified version of the `paste` method
  //
  // src - The image to paste
  // dest - The target image for the paste operation
  // x - The x-coordinate of the paste
  // y - The y-coordinate of the paste
  //
  // Returns a {Promise} of the resulting image
  static paste(src, dest, x, y) {
    return new Promise((resolve, reject) => {
      dest.paste(x, y, src, (err, img) => {
        if (!err) {
          resolve(img);
        } else {
          reject(err);
        }
      });
    });
  }

  // Private: Returns a Promisified version of the `writeFile` method
  //
  // img - The image to write
  // outputFile - The output file path
  //
  // Returns a {Promise} indicating completion
  static writeFile(img, outputFile) {
    return new Promise((resolve, reject) => {
      img.writeFile(outputFile, 'png', {compression: 'fast'}, (err) => {
        if (!err) {
          resolve(outputFile);
        } else {
          reject(err);
        }
      });
    });
  }

  // Private: Returns a Promisified version of the `toBuffer` method
  //
  // img - The image to convert
  //
  // Returns a {Promise} of the {Buffer}, encoded as a jpeg
  static toBuffer(img) {
    return new Promise((resolve, reject) => {
      img.toBuffer('jpg', {quality: 100}, (err, buffer) => {
        if (!err) {
          resolve(buffer);
        } else {
          reject(err);
        }
      });
    });
  }
}

module.exports = ImageHelpers;
<commit_msg>Update image-helpers.js<commit_after>
<|endoftext|>


<commit_before>Template.singleHomeActivityStatus.onCreated(function () {
    var instance = this;

    // Get ID of current home
    instance.homeId = instance.data.home._id;

    // Add variable to hold activity counts
    instance.activityLevelCounts = new ReactiveVar();

    instance.autorun(function () {
      // Get count of home current residents
      instance.homeCurrentResidentsCount = ReactiveMethod.call("getHomeCurrentResidentCount", instance.homeId);

      // Retrieve home resident activity level counts from server
      const activityLevelCounts = ReactiveMethod.call("getHomeActivityLevelCounts", instance.homeId);

      // Make sure activity level counts exist
      if (activityLevelCounts && instance.homeCurrentResidentsCount) {
        /*
        Re-structure activity level counts data to an object containing:
        type: the type of activity level (inactive, semiActive, active)
        count: the number of residents with a given activity level
        homePercentage: percengage of home residents with the activity level
        */
        const activityLevelTypes = _.keys(activityLevelCounts);

        const activityLevelData = _.map(activityLevelTypes, function (type) {
          // Calculate the percentage of home residents in activity level class
          const homePercentage = activityLevelCounts[type] / instance.homeCurrentResidentsCount;

          // Construct an object with the type and count keys
          const activityLevelCountObject = {
            // Activity level class (inactive, semi-active, active)
            type: type,
            // Number of residents in activity class
            count: activityLevelCounts[type],
            // Percentage of home residents fallint into activity level class
            homePercentage: homePercentage
          };

          return activityLevelCountObject;
        });

        // Update the reactive variable, to trigger the graph to render
        instance.activityLevelCounts.set(activityLevelData);
      }
    });
  });

Template.singleHomeActivityStatus.onRendered(function () {
  // Get reference to template instance
  const instance = this;

  // Get home ID
  const homeId = instance.homeId;

  /*
  Set up chart
  */

  // Set up ID string for chart element
  const svgId = `#activityLevelCountsChart-${homeId}`;

  // Get reference to chart element
  const svg = dimple.newSvg(svgId, "100%", 50);

  // Initialize chart with empty data array
  const activityLevelsChart = new dimple.chart(svg, []);

  // Set chart boundaries
  activityLevelsChart.setBounds(10, 0, "90%", "65%");

  // Add home resident percentage to x axis
  const xAxis = activityLevelsChart.addMeasureAxis("x", "homePercentage");

  // Format x axis as percentage
  // Note: both chart.addPctAxis and axis.showPercentage caused d3 NaN errors
  xAxis.tickFormat = "%";

  // Set x axis max to 100% for easy cross-comparison
  xAxis.overrideMax = 1;

  // Remove x axis grid lines
  xAxis.showGridlines = false;

  // Add activity level type to y axis
  const yAxis = activityLevelsChart.addCategoryAxis("y", "type");

  // Hide the y axis labels
  yAxis.hidden = true;

  // Sort the y axis activity levels
  yAxis.addOrderRule(["active", "semiActive", "inactive"]);

  // Define bar chart series
  activityLevelsChart.addSeries(null, dimple.plot.bar);

  instance.autorun(function () {
    // Get activity level counts
    const activityLevelCounts = instance.activityLevelCounts.get();

    if (activityLevelCounts) {
      // Add activity level data to chart
      activityLevelsChart.data = activityLevelCounts;

      // Draw the chart
      activityLevelsChart.draw(1000);

      // Remove x axis title
      xAxis.titleShape.remove();
    }
  });
});
<commit_msg>Cal getHomeCurrentAndActiveResidentsCount<commit_after>Template.singleHomeActivityStatus.onCreated(function () {
    var instance = this;

    // Get ID of current home
    instance.homeId = instance.data.home._id;

    // Add variable to hold activity counts
    instance.activityLevelCounts = new ReactiveVar();

    instance.autorun(function () {
      // Get count of home current residents (not departed or on hiatus)
      instance.homeCurrentResidentsCount = ReactiveMethod.call("getHomeCurrentAndActiveResidentCount", instance.homeId);

      // Retrieve home resident activity level counts from server
      const activityLevelCounts = ReactiveMethod.call("getHomeActivityLevelCounts", instance.homeId);

      // Make sure activity level counts exist
      if (activityLevelCounts && instance.homeCurrentResidentsCount) {
        /*
        Re-structure activity level counts data to an object containing:
        type: the type of activity level (inactive, semiActive, active)
        count: the number of residents with a given activity level
        homePercentage: percengage of home residents with the activity level
        */
        const activityLevelTypes = _.keys(activityLevelCounts);

        const activityLevelData = _.map(activityLevelTypes, function (type) {
          // Calculate the percentage of home residents in activity level class
          const homePercentage = activityLevelCounts[type] / instance.homeCurrentResidentsCount;

          // Construct an object with the type and count keys
          const activityLevelCountObject = {
            // Activity level class (inactive, semi-active, active)
            type: type,
            // Number of residents in activity class
            count: activityLevelCounts[type],
            // Percentage of home residents fallint into activity level class
            homePercentage: homePercentage
          };

          return activityLevelCountObject;
        });

        // Update the reactive variable, to trigger the graph to render
        instance.activityLevelCounts.set(activityLevelData);
      }
    });
  });

Template.singleHomeActivityStatus.onRendered(function () {
  // Get reference to template instance
  const instance = this;

  // Get home ID
  const homeId = instance.homeId;

  /*
  Set up chart
  */

  // Set up ID string for chart element
  const svgId = `#activityLevelCountsChart-${homeId}`;

  // Get reference to chart element
  const svg = dimple.newSvg(svgId, "100%", 50);

  // Initialize chart with empty data array
  const activityLevelsChart = new dimple.chart(svg, []);

  // Set chart boundaries
  activityLevelsChart.setBounds(10, 0, "90%", "65%");

  // Add home resident percentage to x axis
  const xAxis = activityLevelsChart.addMeasureAxis("x", "homePercentage");

  // Format x axis as percentage
  // Note: both chart.addPctAxis and axis.showPercentage caused d3 NaN errors
  xAxis.tickFormat = "%";

  // Set x axis max to 100% for easy cross-comparison
  xAxis.overrideMax = 1;

  // Remove x axis grid lines
  xAxis.showGridlines = false;

  // Add activity level type to y axis
  const yAxis = activityLevelsChart.addCategoryAxis("y", "type");

  // Hide the y axis labels
  yAxis.hidden = true;

  // Sort the y axis activity levels
  yAxis.addOrderRule(["active", "semiActive", "inactive"]);

  // Define bar chart series
  activityLevelsChart.addSeries(null, dimple.plot.bar);

  instance.autorun(function () {
    // Get activity level counts
    const activityLevelCounts = instance.activityLevelCounts.get();

    if (activityLevelCounts) {
      // Add activity level data to chart
      activityLevelsChart.data = activityLevelCounts;

      // Draw the chart
      activityLevelsChart.draw(1000);

      // Remove x axis title
      xAxis.titleShape.remove();
    }
  });
});
<|endoftext|>


<commit_before>var KNETMAPS = KNETMAPS || {};

KNETMAPS.KnetMaps = function() {

	var maskloader = KNETMAPS.MaskLoader();
	var generator = KNETMAPS.Generator();

	var drawDiv = function(target, networkId) {
		$(target).html("
"
				+ "<input type='submit' id='maximizeOverlay' class='max unhover' value='' title='Toggle full screen' onclick='KNETMAPS.Menu().OnMaximizeClick();' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='showAll' value='' class='unhover' onclick='KNETMAPS.Menu().showAll();' title='Show all the concept & relations in the Network' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='openItemInfoBtn' value='' class='unhover' onclick='KNETMAPS.Menu().popupItemInfo();' title='Show Info box' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='relayoutNetwork' value='' class='unhover' onclick='KNETMAPS.Menu().rerunLayout();' title='Re-run the Layout' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ ""
				+ "<select id='layouts_dropdown' class='knet-dropdowns' onChange='KNETMAPS.Menu().rerunLayout();' title='Select network layout'>"
				+ "<option value='cose_layout' selected='selected' title='using CoSE layout algorithm (useful for larger networks with clustering)'>CoSE layout</option>"
				+ "<option value='ngraph_force_layout' title='using ngraph_force layout (works well on planar graphs)'>Force layout</option>"
				+ "<option value='circle_layout'>Circular layout</option>"
				+ "<option value='concentric_layout'>Concentric layout</option>"
				+ "<option value='coseBilkent_layout' title='using CoSE-Bilkent layout (with node clustering, but performance-intensive for larger networks)'>CoSE-Bilkent layout</option>"
				+
				/*
				 * "<option value='euler_layout'>Euler layout</option>"+ "<option
				 * value='random_layout'>Random layout</option>"+
				 */
				"</select>"
				+ "<select id='changeLabelVisibility' class='knet-dropdowns' onChange='KNETMAPS.Menu().showHideLabels(this.value);' title='Select label visibility'>"
				+ "<option value='None' selected='selected'>Labels: None</option>"
				+ "<option value='Concepts'>Labels: Concepts</option>"
				+ "<option value='Relations'>Labels: Relations</option>"
				+ "<option value='Both'>Labels: Both</option>"
				+ "</select>"
				+ "<select id='changeLabelFont' class='knet-dropdowns' onChange='KNETMAPS.Menu().changeLabelFontSize(this.value);' title='Select label font size'>"
				+ "<option value='8'>Label size: 8px</option>"
				+ "<option value='12'>Label size: 12px</option>"
				+ "<option value='16' selected='selected'>Label size: 16px</option>"
				+ "<option value='20'>Label size: 20px</option>"
				+ "<option value='24'>Label size: 24px</option>"
				+ "<option value='28'>Label size: 28px</option>"
				+ "<option value='32'>Label size: 32px</option>"
				+ "<option value='36'>Label size: 36px</option>"
				+ "<option value='40'>Label size: 40px</option>"
				+ "</select>"
				+ ""
				+ "<input type='submit' id='resetNetwork' value='' class='unhover' onclick='KNETMAPS.Menu().resetGraph();' title='Reposition (reset and re-fit) the graph' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='saveJSON' value='' class='unhover' onclick='KNETMAPS.Menu()exportAsJson(\""+networkId+"\");' title='Save the knetwork to knetspace' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
			/*	+ "<input type='submit' id='openJSON' value='' class='unhover' onclick='KNETMAPS.Menu().importJson();' title='Import a kNetwork json' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>" */
				+ "<input type='submit' id='savePNG' value='' class='unhover' onclick='KNETMAPS.Menu().exportAsImage();' title='Export the network as a .png image' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='helpURL' value='' class='unhover' onclick='KNETMAPS.Menu().openKnetHelpPage();' title='Go to help documentation' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='file' accept='.json,.cyjs.json,.cyjs,.cx' id='openNetworkFile' style='display:none' onchange='KNETMAPS.Menu().OpenKnetFile(event);' >"
				+ "
 "
				+ "
 "
				+ "
"
				+ "
Info box:	"
				+ "<input type='submit' id='btnCloseItemInfoPane' value='' onclick='KNETMAPS.ItemInfo().closeItemInfoPane();'>	"
				+ "

"
				+ "
"
				+ ""
				+ "

"
				+ ""
				+ "
Concepts:
"
				+ ""
				+ "
KnetMaps
"
				+ "

 "
				);
	};

	var showDiv = function(target) {
		$(target).css("display", "block"); // show the KnetMaps block
	};

	var my = function() {};

	// Exposed API

	my.drawRaw = function(target, graph, networkId) {
		drawDiv(target, networkId);
		showDiv(target);
		maskloader.showNetworkLoader(target);
		generator.generateNetworkGraphRaw(graph);
		maskloader.removeNetworkLoader(target);
	};

	my.draw = function(target, eles_jsons, metadata_json, eles_styles, networkId) {
		drawDiv(target, networkId);
		showDiv(target);
		maskloader.showNetworkLoader(target);
		generator.generateNetworkGraph(eles_jsons, metadata_json, eles_styles);
		maskloader.removeNetworkLoader(target);
	};

	return my;
};
<commit_msg>new saveKnet knetmaps btn<commit_after>var KNETMAPS = KNETMAPS || {};

KNETMAPS.KnetMaps = function() {

	var maskloader = KNETMAPS.MaskLoader();
	var generator = KNETMAPS.Generator();

	var drawDiv = function(target, networkId) {
		$(target).html("
"
				+ "<input type='submit' id='maximizeOverlay' class='max unhover' value='' title='Toggle full screen' onclick='KNETMAPS.Menu().OnMaximizeClick();' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='showAll' value='' class='unhover' onclick='KNETMAPS.Menu().showAll();' title='Show all the concept & relations in the Network' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='openItemInfoBtn' value='' class='unhover' onclick='KNETMAPS.Menu().popupItemInfo();' title='Show Info box' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='relayoutNetwork' value='' class='unhover' onclick='KNETMAPS.Menu().rerunLayout();' title='Re-run the Layout' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ ""
				+ "<select id='layouts_dropdown' class='knet-dropdowns' onChange='KNETMAPS.Menu().rerunLayout();' title='Select network layout'>"
				+ "<option value='cose_layout' selected='selected' title='using CoSE layout algorithm (useful for larger networks with clustering)'>CoSE layout</option>"
				+ "<option value='ngraph_force_layout' title='using ngraph_force layout (works well on planar graphs)'>Force layout</option>"
				+ "<option value='circle_layout'>Circular layout</option>"
				+ "<option value='concentric_layout'>Concentric layout</option>"
				+ "<option value='coseBilkent_layout' title='using CoSE-Bilkent layout (with node clustering, but performance-intensive for larger networks)'>CoSE-Bilkent layout</option>"
				+
				/*
				 * "<option value='euler_layout'>Euler layout</option>"+ "<option
				 * value='random_layout'>Random layout</option>"+
				 */
				"</select>"
				+ "<select id='changeLabelVisibility' class='knet-dropdowns' onChange='KNETMAPS.Menu().showHideLabels(this.value);' title='Select label visibility'>"
				+ "<option value='None' selected='selected'>Labels: None</option>"
				+ "<option value='Concepts'>Labels: Concepts</option>"
				+ "<option value='Relations'>Labels: Relations</option>"
				+ "<option value='Both'>Labels: Both</option>"
				+ "</select>"
				+ "<select id='changeLabelFont' class='knet-dropdowns' onChange='KNETMAPS.Menu().changeLabelFontSize(this.value);' title='Select label font size'>"
				+ "<option value='8'>Label size: 8px</option>"
				+ "<option value='12'>Label size: 12px</option>"
				+ "<option value='16' selected='selected'>Label size: 16px</option>"
				+ "<option value='20'>Label size: 20px</option>"
				+ "<option value='24'>Label size: 24px</option>"
				+ "<option value='28'>Label size: 28px</option>"
				+ "<option value='32'>Label size: 32px</option>"
				+ "<option value='36'>Label size: 36px</option>"
				+ "<option value='40'>Label size: 40px</option>"
				+ "</select>"
				+ ""
				+ "<input type='submit' id='resetNetwork' value='' class='unhover' onclick='KNETMAPS.Menu().resetGraph();' title='Reposition (reset and re-fit) the graph' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
			/*	+ "<input type='submit' id='saveJSON' value='' class='unhover' onclick='KNETMAPS.Menu()exportAsJson(\""+networkId+"\");' title='Save the knetwork to knetspace' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='openJSON' value='' class='unhover' onclick='KNETMAPS.Menu().importJson();' title='Import a kNetwork json' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='submit' id='savePNG' value='' class='unhover' onclick='KNETMAPS.Menu().exportAsImage();' title='Export the network as a .png image' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>" */
				+ "<input type='submit' id='helpURL' value='' class='unhover' onclick='KNETMAPS.Menu().openKnetHelpPage();' title='Go to help documentation' onmouseover='KNETMAPS.Menu().onHover($(this));' onmouseout='KNETMAPS.Menu().offHover($(this));'>"
				+ "<input type='file' accept='.json,.cyjs.json,.cyjs,.cx' id='openNetworkFile' style='display:none' onchange='KNETMAPS.Menu().OpenKnetFile(event);' >"
                                + "<button id='saveJSON' style='float:right;' class='btn knet_button' onclick='KNETMAPS.Menu()exportAsJson(\""+networkId+"\");' title='Save the knetwork to knetspace'>Save</button>"
				+ "
 "
				+ "
 "
				+ "
"
				+ "
Info box:	"
				+ "<input type='submit' id='btnCloseItemInfoPane' value='' onclick='KNETMAPS.ItemInfo().closeItemInfoPane();'>	"
				+ "

"
				+ "
"
				+ ""
				+ "

"
				+ ""
				+ "
Concepts:
"
				+ ""
				+ "
KnetMaps
"
				+ "

 "
				);
	};

	var showDiv = function(target) {
		$(target).css("display", "block"); // show the KnetMaps block
	};

	var my = function() {};

	// Exposed API

	my.drawRaw = function(target, graph, networkId) {
		drawDiv(target, networkId);
		showDiv(target);
		maskloader.showNetworkLoader(target);
		generator.generateNetworkGraphRaw(graph);
		maskloader.removeNetworkLoader(target);
	};

	my.draw = function(target, eles_jsons, metadata_json, eles_styles, networkId) {
		drawDiv(target, networkId);
		showDiv(target);
		maskloader.showNetworkLoader(target);
		generator.generateNetworkGraph(eles_jsons, metadata_json, eles_styles);
		maskloader.removeNetworkLoader(target);
	};

	return my;
};
<|endoftext|>