<commit_before>/**
 * Interface for evaluating revisions
 *
 * @author: Helder (https://github.com/he7d3r)
 * @license: CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0/>
 * Based on mockups by Aaron Halfaker
 * https://meta.wikimedia.org/wiki/Research_talk:Revision_scoring_as_a_service?oldid=10266386#Revision_handcoding_.28mockups.29
 */
( function ( mw, $ ) {
	'use strict';
	var i18n, config, fields, workSet, curIdx;

	function toggleSelection( e ) {
		var $target = $( e.target ),
			wasSelected = $target.hasClass( 'rvc-selected' );
		$target
			.parent()
				.find( '.rvc-selected' )
					.removeClass( 'rvc-selected' )
					.end()
				.end();
		if ( !wasSelected ) {
			$target.addClass( 'rvc-selected' );
		}
		// The user must select one value for each field
		$( '#rvc-submit' ).prop(
			'disabled',
			 $( '.mw-ui-button.rvc-selected' ).length !== fields.length ||
			 curIdx >= workSet.length
		);
	}
/*
	function getRandomSet( size, done ) {
		var i, j, rev,
			apiDeferred = $.Deferred(),
			list = [];
		size = size || 100;
		done = done || 70;
		curIdx = done + 1;
		for ( i = 0; i < size; i++ ) {
			rev = {
				revid: Math.floor( Math.random() * 1000000 ),
				pageid: Math.floor( Math.random() * 1000000 ),
				// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
				fields: {}
			};
			if ( i <= done ) {
				// TODO:
				// * Should an 'undefined' value mean 'unknown'?
				//   In that case, this could be a boolean
				// * Or one should explicitly set a value (e.g. 0) to mean 'unknown'?
				//   In case there are just three possibilities, we could use -1, 0 and 1 instead of 0, 1 and 2?
				// FIXME: these names should not be hardcoded
				// TODO: Should we hardcode common sense such as "not damaging implies good faith"?
				for ( j = 0; j < fields.length; j++ ) {
					// Classes from 0 to (N-1), where N is the number of options for this field
					rev.fields[ fields[j].id ] = Math.floor( Math.random() * fields[j].options.length );
				}
			}
			list.push( rev );
		}
		apiDeferred.resolve( list );
		return apiDeferred.promise();
	}
*/
	function getRecentChanges( options ) {
		var apiDeferred = $.Deferred(),
			defaultOptions = {
				action: 'query',
				list: 'recentchanges',
				rctype: 'edit|new',
				rclimit: 50
			},
			params = $.extend( {}, defaultOptions, options );
		new mw.Api().get( params ).done( function( data ){
			var i,
				list = [],
				changes = data.query.recentchanges;
			for( i = 0; i < changes.length; i++ ){
				list.push( {
					revid: changes[i].revid,
					pageid: changes[i].pageid,
					// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
					fields: {}
				} );
			}
			apiDeferred.resolve( list );
		} )
		.fail( function(){
			// TODO: Reject and pass some error info?
			apiDeferred.resolve( [] );
		} );
		return apiDeferred.promise();
	}

	function showWorkSet( ws ){
		var i, j, field, idx, $icon, className, tooltip, value,
			$bar = $( '.rvc-progress' ).empty();
		workSet = ws || workSet;
		for ( i = 0; i < workSet.length; i++ ) {
			$icon = $( '
' );
			tooltip = mw.msg( 'rvc-revision-title', workSet[i].revid );
			for ( j = 0; j < fields.length; j++ ) {
				field = fields[j].id;
				idx = workSet[i].fields[ field ];
				value = fields[j].options[ idx ] && fields[j].options[ idx ].value;
				tooltip += '\n' + fields[j].label + ' ' + value;
				className = 'rvc-' + field + '-' + value;
				$icon.append( $( '
' ).addClass( className ) );
			}
			$icon.attr(
				'title',
				tooltip
			);
			$bar.append( $icon );
		}
		$( '.rvc-progress > div' ).css( 'width', ( 100 / workSet.length ) + '%' );
		$( '.mw-ui-button.rvc-selected' ).removeClass( 'rvc-selected' );
		$( '#rvc-submit' ).prop( 'disabled', true );
		if( curIdx < workSet.length ){
			$bar.find( '> div' ).eq( curIdx ).addClass( 'rvc-selected' );
			showDiff( workSet[ curIdx ].revid );
		}
	}

	function showDiff( revid ){
		new mw.Api().get( {
			action: 'query',
			prop: 'revisions',
			rvdiffto: 'prev',
			revids: revid,
			indexpageids: true
		} ).done( function( data ){
			var page = data.query.pages[ data.query.pageids[0] ];
			// $( '#firstHeading' ).text( page.title );
			$( '#rvc-diff' ).empty().append(
				page.revisions[0].diff['*']
			);
		} );
	}

	function submit(){
		var revData;
		$( '.mw-ui-button.rvc-selected' ).each( function(){
			var $this = $( this ),
				idxValue = $this.data( 'rvc-value' ),
				field = $this.parent().data( 'rvc-field' );
			if( field !== undefined && idxValue !== undefined ){
				workSet[ curIdx ].fields[ field ] = idxValue;
			}
		} );
		// FIXME: Generalize the API provided by the tool on Labs,
		// to deal with arbitrary number of fields (columns?)
		revData = {
			action: 'save',
			rev: workSet[ curIdx ].revid,
			page: workSet[ curIdx ].pageid,
			// FIXME: This number changes between wikis
			// FIXME: Authenticate using OAuth
			user: mw.config.get( 'wgUserId' ),
			// FIXME: This is just a hack to map our values to
			// the ones currently accepted by the tool
			score: {
					0: 'yes',
					1: 'maybe',
					2: 'no'
				}[ workSet[ curIdx ].fields.damaging ],
			gfaith: {
					0: 'yes',
					1: 'maybe',
					2: 'no'
				}[ workSet[ curIdx ].fields['good-faith'] ],
			wiki: mw.config.get( 'wgDBname' ),
			comment: location.origin +
				mw.util.getUrl( 'User:' + mw.config.get( 'wgUserName' ) )
		};
		$( '#rvc-submit' ).injectSpinner( 'rvc-submit-spinner' );
		$.ajax( {
			// See the saved data on http://ores-test.wmflabs.org/table
			url: '//ores-test.wmflabs.org/save',
			data: revData,
			dataType: 'jsonp'
		} ).always( function(){
			$.removeSpinner( 'rvc-submit-spinner' );
		} ).fail( function(){
			console.log( arguments );
			alert( 'An errror occurred! Check the console...' );
		} );
		curIdx++;
		showWorkSet();
		if( curIdx >= workSet.length ){
			alert( mw.msg( 'rvc-dataset-completed' ) );
			$( '#rvc-submit' ).prop( 'disabled', true );
		}
	}

	function load( data ) {
		var $ui = $( '#rvc-ui' ).empty(),
			$submit = $( '<input id="rvc-submit" class="mw-ui-button mw-ui-constructive" type="submit">' )
				.prop( 'disabled', true )
				.click( submit ),
			field, i, j, id, val, $feature, $group;
		config = $.parseJSON( data.query.pages[data.query.pageids[0]].revisions[0]['*'] )
		fields = config.fields;
		i18n = config.i18n;
		mw.messages.set( i18n[ mw.config.get( 'wgUserLanguage' ) ] || i18n.en );

		$submit.val( mw.msg( 'rvc-submit' ) );
		$ui.append(
			$( '
' )
				.text( mw.msg( 'rvc-work-set' ) ),
			$( '
' )
				.addClass( 'rvc-progress' )
		);
		for ( i = 0; i < fields.length; i++ ) {
			field = fields[i];
			id = field.id;
			$group = $( '
' )
				.data( 'rvc-field', id )
				// .addClass( 'mw-ui-radio');
				.addClass( 'mw-ui-button-group');
			for ( j = 0; j < field.options.length; j++ ) {
				val = field.options[j].value;
				$group.append(
					$( '
' )
						.addClass( 'mw-ui-button')
						.attr( 'id', 'rvc-' + field.id + '-' + val )
						.attr( 'title', mw.msg( field.options[j].tooltip ) )
						.text( mw.msg( field.options[j].label ) )
						.data( 'rvc-value', j )
						.click( toggleSelection )
// 					$( '<input type="radio">' )
// 						.attr( 'name', 'rvc-' + field.id )
// 						.attr( 'id', 'rvc-' + field.id + '-' + val )
// 						.attr( 'title', mw.msg( field.options[j].tooltip ) ),
// 					$( '' )
// 						.text( mw.msg( field.options[j].label ) )
// 						.attr( 'for', 'rvc-' + field.id + '-' + val )
// 						.data( 'rvc-value', j )
// 						.click( toggleSelection )
				);
			}
			$feature = $( '
' )
				.attr( 'title', mw.msg( field.help ) )
				.append(
					$( '
' )
						.text( mw.msg( field.label ) ),
					$group
				);
			$ui.append( $feature, '

' );
		}
		$ui.append( $submit )
			.append(
				'
' +
				'<colgroup><col class="diff-marker">' +
				'<col class="diff-content">' +
				'<col class="diff-marker">' +
				'<col class="diff-content">' +
				'</colgroup>

'
			);
		curIdx = 0;
		// getRandomSet()
		getRecentChanges()
			.done( showWorkSet );
	}

	if ( $.inArray( mw.config.get( 'wgAction' ), [ 'view', 'purge' ] ) !== -1 ) {
		$( function () {
			if ( $( '#rvc-ui' ).length !== 0 ) {
				mw.loader.using( [
					'mediawiki.api',
					'jquery.spinner',
					// TODO: Load this only when necessary
					// (e.g. if the user will be required to click on some button before the first diff appears)
					'mediawiki.action.history.diff'
				] ).done( function () {
					$.ajax(
					{
						// TODO: Move this to Labs (and use CORS if needed)
						'url': 'https://meta.wikimedia.org/w/api.php',
						'data': {
							action: 'query',
							format: 'json',
							prop: 'revisions',
							rvprop: 'content',
							titles: 'User:He7d3r/Tools/RevisionCodingConfig.js',
							indexpageids: ''
						},
						'dataType': 'jsonp'
					} )
					.done( load );
				} );
			}
		} );
	}

}( mediaWiki, jQuery ) );
<commit_msg>Update mapping of values<commit_after>/**
 * Interface for evaluating revisions
 *
 * @author: Helder (https://github.com/he7d3r)
 * @license: CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0/>
 * Based on mockups by Aaron Halfaker
 * https://meta.wikimedia.org/wiki/Research_talk:Revision_scoring_as_a_service?oldid=10266386#Revision_handcoding_.28mockups.29
 */
( function ( mw, $ ) {
	'use strict';
	var i18n, config, fields, workSet, curIdx;

	function toggleSelection( e ) {
		var $target = $( e.target ),
			wasSelected = $target.hasClass( 'rvc-selected' );
		$target
			.parent()
				.find( '.rvc-selected' )
					.removeClass( 'rvc-selected' )
					.end()
				.end();
		if ( !wasSelected ) {
			$target.addClass( 'rvc-selected' );
		}
		// The user must select one value for each field
		$( '#rvc-submit' ).prop(
			'disabled',
			 $( '.mw-ui-button.rvc-selected' ).length !== fields.length ||
			 curIdx >= workSet.length
		);
	}
/*
	function getRandomSet( size, done ) {
		var i, j, rev,
			apiDeferred = $.Deferred(),
			list = [];
		size = size || 100;
		done = done || 70;
		curIdx = done + 1;
		for ( i = 0; i < size; i++ ) {
			rev = {
				revid: Math.floor( Math.random() * 1000000 ),
				pageid: Math.floor( Math.random() * 1000000 ),
				// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
				fields: {}
			};
			if ( i <= done ) {
				// TODO:
				// * Should an 'undefined' value mean 'unknown'?
				//   In that case, this could be a boolean
				// * Or one should explicitly set a value (e.g. 0) to mean 'unknown'?
				//   In case there are just three possibilities, we could use -1, 0 and 1 instead of 0, 1 and 2?
				// FIXME: these names should not be hardcoded
				// TODO: Should we hardcode common sense such as "not damaging implies good faith"?
				for ( j = 0; j < fields.length; j++ ) {
					// Classes from 0 to (N-1), where N is the number of options for this field
					rev.fields[ fields[j].id ] = Math.floor( Math.random() * fields[j].options.length );
				}
			}
			list.push( rev );
		}
		apiDeferred.resolve( list );
		return apiDeferred.promise();
	}
*/
	function getRecentChanges( options ) {
		var apiDeferred = $.Deferred(),
			defaultOptions = {
				action: 'query',
				list: 'recentchanges',
				rctype: 'edit|new',
				rclimit: 50
			},
			params = $.extend( {}, defaultOptions, options );
		new mw.Api().get( params ).done( function( data ){
			var i,
				list = [],
				changes = data.query.recentchanges;
			for( i = 0; i < changes.length; i++ ){
				list.push( {
					revid: changes[i].revid,
					pageid: changes[i].pageid,
					// One key for each of the things we want to predict (vandalism, good-faith, quality, etc)
					fields: {}
				} );
			}
			apiDeferred.resolve( list );
		} )
		.fail( function(){
			// TODO: Reject and pass some error info?
			apiDeferred.resolve( [] );
		} );
		return apiDeferred.promise();
	}

	function showWorkSet( ws ){
		var i, j, field, idx, $icon, className, tooltip, value,
			$bar = $( '.rvc-progress' ).empty();
		workSet = ws || workSet;
		for ( i = 0; i < workSet.length; i++ ) {
			$icon = $( '
' );
			tooltip = mw.msg( 'rvc-revision-title', workSet[i].revid );
			for ( j = 0; j < fields.length; j++ ) {
				field = fields[j].id;
				idx = workSet[i].fields[ field ];
				value = fields[j].options[ idx ] && fields[j].options[ idx ].value;
				tooltip += '\n' + fields[j].label + ' ' + value;
				className = 'rvc-' + field + '-' + value;
				$icon.append( $( '
' ).addClass( className ) );
			}
			$icon.attr(
				'title',
				tooltip
			);
			$bar.append( $icon );
		}
		$( '.rvc-progress > div' ).css( 'width', ( 100 / workSet.length ) + '%' );
		$( '.mw-ui-button.rvc-selected' ).removeClass( 'rvc-selected' );
		$( '#rvc-submit' ).prop( 'disabled', true );
		if( curIdx < workSet.length ){
			$bar.find( '> div' ).eq( curIdx ).addClass( 'rvc-selected' );
			showDiff( workSet[ curIdx ].revid );
		}
	}

	function showDiff( revid ){
		new mw.Api().get( {
			action: 'query',
			prop: 'revisions',
			rvdiffto: 'prev',
			revids: revid,
			indexpageids: true
		} ).done( function( data ){
			var page = data.query.pages[ data.query.pageids[0] ];
			// $( '#firstHeading' ).text( page.title );
			$( '#rvc-diff' ).empty().append(
				page.revisions[0].diff['*']
			);
		} );
	}

	function submit(){
		var revData;
		$( '.mw-ui-button.rvc-selected' ).each( function(){
			var $this = $( this ),
				idxValue = $this.data( 'rvc-value' ),
				field = $this.parent().data( 'rvc-field' );
			if( field !== undefined && idxValue !== undefined ){
				workSet[ curIdx ].fields[ field ] = idxValue;
			}
		} );
		// FIXME: Generalize the API provided by the tool on Labs,
		// to deal with arbitrary number of fields (columns?)
		revData = {
			action: 'save',
			rev: workSet[ curIdx ].revid,
			page: workSet[ curIdx ].pageid,
			// FIXME: This number changes between wikis
			// FIXME: Authenticate using OAuth
			user: mw.config.get( 'wgUserId' ),
			// FIXME: This is just a hack to map our values to
			// the ones currently accepted by the tool
			score: {
					0: 'no',
					1: 'yes'
				}[ workSet[ curIdx ].fields.damaging ],
			gfaith: {
					0: 'no',
					1: 'yes'
				}[ workSet[ curIdx ].fields['good-faith'] ],
			wiki: mw.config.get( 'wgDBname' ),
			comment: location.origin +
				mw.util.getUrl( 'User:' + mw.config.get( 'wgUserName' ) )
		};
		$( '#rvc-submit' ).injectSpinner( 'rvc-submit-spinner' );
		$.ajax( {
			// See the saved data on http://ores-test.wmflabs.org/table
			url: '//ores-test.wmflabs.org/save',
			data: revData,
			dataType: 'jsonp'
		} ).always( function(){
			$.removeSpinner( 'rvc-submit-spinner' );
		} ).fail( function(){
			console.log( arguments );
			alert( 'An errror occurred! Check the console...' );
		} );
		curIdx++;
		showWorkSet();
		if( curIdx >= workSet.length ){
			alert( mw.msg( 'rvc-dataset-completed' ) );
			$( '#rvc-submit' ).prop( 'disabled', true );
		}
	}

	function load( data ) {
		var $ui = $( '#rvc-ui' ).empty(),
			$submit = $( '<input id="rvc-submit" class="mw-ui-button mw-ui-constructive" type="submit">' )
				.prop( 'disabled', true )
				.click( submit ),
			field, i, j, id, val, $feature, $group;
		config = $.parseJSON( data.query.pages[data.query.pageids[0]].revisions[0]['*'] )
		fields = config.fields;
		i18n = config.i18n;
		mw.messages.set( i18n[ mw.config.get( 'wgUserLanguage' ) ] || i18n.en );

		$submit.val( mw.msg( 'rvc-submit' ) );
		$ui.append(
			$( '
' )
				.text( mw.msg( 'rvc-work-set' ) ),
			$( '
' )
				.addClass( 'rvc-progress' )
		);
		for ( i = 0; i < fields.length; i++ ) {
			field = fields[i];
			id = field.id;
			$group = $( '
' )
				.data( 'rvc-field', id )
				// .addClass( 'mw-ui-radio');
				.addClass( 'mw-ui-button-group');
			for ( j = 0; j < field.options.length; j++ ) {
				val = field.options[j].value;
				$group.append(
					$( '
' )
						.addClass( 'mw-ui-button')
						.attr( 'id', 'rvc-' + field.id + '-' + val )
						.attr( 'title', mw.msg( field.options[j].tooltip ) )
						.text( mw.msg( field.options[j].label ) )
						.data( 'rvc-value', j )
						.click( toggleSelection )
// 					$( '<input type="radio">' )
// 						.attr( 'name', 'rvc-' + field.id )
// 						.attr( 'id', 'rvc-' + field.id + '-' + val )
// 						.attr( 'title', mw.msg( field.options[j].tooltip ) ),
// 					$( '' )
// 						.text( mw.msg( field.options[j].label ) )
// 						.attr( 'for', 'rvc-' + field.id + '-' + val )
// 						.data( 'rvc-value', j )
// 						.click( toggleSelection )
				);
			}
			$feature = $( '
' )
				.attr( 'title', mw.msg( field.help ) )
				.append(
					$( '
' )
						.text( mw.msg( field.label ) ),
					$group
				);
			$ui.append( $feature, '

' );
		}
		$ui.append( $submit )
			.append(
				'
' +
				'<colgroup><col class="diff-marker">' +
				'<col class="diff-content">' +
				'<col class="diff-marker">' +
				'<col class="diff-content">' +
				'</colgroup>

'
			);
		curIdx = 0;
		// getRandomSet()
		getRecentChanges()
			.done( showWorkSet );
	}

	if ( $.inArray( mw.config.get( 'wgAction' ), [ 'view', 'purge' ] ) !== -1 ) {
		$( function () {
			if ( $( '#rvc-ui' ).length !== 0 ) {
				mw.loader.using( [
					'mediawiki.api',
					'jquery.spinner',
					// TODO: Load this only when necessary
					// (e.g. if the user will be required to click on some button before the first diff appears)
					'mediawiki.action.history.diff'
				] ).done( function () {
					$.ajax(
					{
						// TODO: Move this to Labs (and use CORS if needed)
						'url': 'https://meta.wikimedia.org/w/api.php',
						'data': {
							action: 'query',
							format: 'json',
							prop: 'revisions',
							rvprop: 'content',
							titles: 'User:He7d3r/Tools/RevisionCodingConfig.js',
							indexpageids: ''
						},
						'dataType': 'jsonp'
					} )
					.done( load );
				} );
			}
		} );
	}

}( mediaWiki, jQuery ) );
<|endoftext|>


<commit_before>'use strict'

const ApiClient = require('./ApiClient')

const assertOption = (options, name) => {
  if (!options[name]) {
    throw new Error(`Missing required option '${name}'`)
  }
}

module.exports = function (options) {
  assertOption(options, 'applicationId')
  assertOption(options, 'clientSecretKey')

  const client = new ApiClient(options)

  return {
    /*
    *  List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' }
    */
    list: (query, callback) => {
      return client.get('/vouchers/', query, callback)
    },

    get: (code, callback) => {
      return client.get(`/vouchers/${encodeURIComponent(code)}`, null, callback)
    },

    create: (voucher, callback) => {
      const code = voucher.code || ''
      return client.post(`/vouchers/${encodeURIComponent(code)}`, voucher, callback)
    },

    delete: (voucherCode, params, callback) => {
      if (typeof (params) === 'undefined') {
        params = {}
      }

      if (typeof (params) === 'function') {
        callback = params
        params = {}
      }

      const code = voucherCode || ''
      let path = `/vouchers/${encodeURIComponent(code)}`
      if (params.force) {
        path += '?force=true'
      }

      return client.delete(path, callback)
    },

    update: (voucher, callback) => {
      const code = voucher.code || ''
      return client.put(`/vouchers/${encodeURIComponent(code)}`, voucher, callback)
    },

    enable: (code, callback) => {
      return client.post(`/vouchers/${encodeURIComponent(code)}/enable`, null, callback)
    },

    disable: (code, callback) => {
      return client.post(`/vouchers/${encodeURIComponent(code)}/disable`, null, callback)
    },

    validate: (code, context, callback) => {
      if (typeof (context) === 'undefined') {
        context = {}
      }

      if (typeof (context) === 'function') {
        callback = context
        context = {}
      }

      return client.post(`/vouchers/${encodeURIComponent(code)}/validate`, context, callback)
    },

    redemption: (code, callback) => {
      return client.get(`/vouchers/${encodeURIComponent(code)}/redemption`, null, callback)
    },

    /*
    *  List redemptions. Sample query (1000 successful redemptions from April 2016):
    *  {
    *      limit: 1000,
    *      page: 0,
    *      start_date: '2016-04-01T00:00:00',
    *      end_date: '2016-04-30T23:59:59',
    *      result: 'Success'
    *  }
    */
    redemptions: (query, callback) => {
      return client.get('/redemptions/', query, callback)
    },

    redeem: (code, trackingId, callback) => {
      let context = {}
      if (typeof (code) === 'object') {
        context = code
        code = context.voucher
        delete context.voucher
      }
      // No `tracking_id` passed here,
      // use callback from 2n argument.
      if (typeof (trackingId) === 'function') {
        callback = trackingId
        trackingId = undefined
      }

      let url = `/vouchers/${encodeURIComponent(code)}/redemption`
      // If `tracking_id` passed, use it in query string.
      if (typeof (trackingId) === 'string' && trackingId) {
        url += `?tracking_id=${encodeURIComponent(trackingId)}`
      }

      return client.post(url, context, callback)
    },

    rollback: (redemptionId, data, callback) => {
      if (typeof (data) === 'function') {
        callback = data
        data = undefined
      }

      const qs = {}
      const payload = {}

      // If `reason` passed, use it in query string.
      if (typeof (data) === 'string') {
        qs['reason'] = encodeURIComponent(data)
      }

      if (typeof (data) === 'object') {
        qs['reason'] = data['reason'] || undefined
        qs['tracking_id'] = data['tracking_id'] || undefined
        payload['customer'] = data['customer'] || undefined
      }

      return client.post(
        `/redemptions/${encodeURIComponent(redemptionId)}/rollback`,
        payload, callback, {qs}
      )
    },

    publish: function (campaignName, callback) {
      let path = '/vouchers/publish'
      let payload = {}
      if (typeof (campaignName) === 'string') {
        path += '?campaign=' + encodeURIComponent(campaignName)
      }
      if (typeof (campaignName) === 'object') {
        payload = campaignName
      }

      return client.post(path, payload, callback)
    },

    campaign: {
      voucher: {
        create: (campaignName, voucher, callback) => {
          return client.post(
            `/campaigns/${encodeURIComponent(campaignName || '')}/vouchers`,
            // TODO if voucher is optional, secure against callback version
            voucher || {},
            callback
          )
        }
      }
    },

    customer: {
      create: (customer, callback) => {
        return client.post('/customers', customer, callback)
      },

      get: (customerId, callback) => {
        // TODO why fallback to empty string ?! shall we rather throw an error? print warning?
        return client.get(`/customers/${encodeURIComponent(customerId || '')}`, null, callback)
      },

      update: function (customer, callback) {
        return client.put(`/customers/${encodeURIComponent(customer.id || '')}`, customer, callback)
      },

      delete: function (customerId, callback) {
        return client.delete(`/customers/${encodeURIComponent(customerId || '')}`, callback)
      }
    },

    product: {
      create: function (product, callback) {
        return client.post('/products', product, callback)
      },

      get: function (productId, callback) {
        return client.get(`/products/${encodeURIComponent(productId || '')}`, null, callback)
      },

      update: function (product, callback) {
        return client.put(`/products/${encodeURIComponent(product.id || '')}`, product, callback)
      },

      delete: function (productId, callback) {
        return client.delete(`/products/${encodeURIComponent(productId || '')}`, callback)
      },

      sku: {
        create: function (productId, sku, callback) {
          return client.post(`/products/${encodeURIComponent(productId || '')}/skus`, sku, callback)
        },

        get: function (productId, skuId, callback) {
          return client.get(
            `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(skuId || '')}`,
            null, callback
          )
        },

        update: function (productId, sku, callback) {
          return client.put(
            `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(sku.id || '')}`,
            sku, callback
          )
        },

        delete: function (productId, skuId, callback) {
          return client.delete(
            `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(skuId || '')}`,
            callback
          )
        }
      }
    }
  }
}
<commit_msg>put encode shortcut<commit_after>'use strict'

const ApiClient = require('./ApiClient')

const assertOption = (options, name) => {
  if (!options[name]) {
    throw new Error(`Missing required option '${name}'`)
  }
}

const encode = (value = '') => {
  return encodeURIComponent(value)
}

module.exports = function (options) {
  assertOption(options, 'applicationId')
  assertOption(options, 'clientSecretKey')

  const client = new ApiClient(options)

  return {
    /*
    *  List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' }
    */
    list: (query, callback) => {
      return client.get('/vouchers/', query, callback)
    },

    get: (code, callback) => {
      return client.get(`/vouchers/${encode(code)}`, null, callback)
    },

    create: (voucher, callback) => {
      return client.post(`/vouchers/${encode(voucher.code)}`, voucher, callback)
    },

    delete: (voucherCode, params, callback) => {
      if (typeof (params) === 'undefined') {
        params = {}
      }

      if (typeof (params) === 'function') {
        callback = params
        params = {}
      }

      let path = `/vouchers/${encode(voucherCode)}`
      if (params.force) {
        path += '?force=true'
      }

      return client.delete(path, callback)
    },

    update: (voucher, callback) => {
      return client.put(`/vouchers/${encode(voucher.code)}`, voucher, callback)
    },

    enable: (code, callback) => {
      return client.post(`/vouchers/${encode(code)}/enable`, null, callback)
    },

    disable: (code, callback) => {
      return client.post(`/vouchers/${encode(code)}/disable`, null, callback)
    },

    validate: (code, context, callback) => {
      if (typeof (context) === 'undefined') {
        context = {}
      }

      if (typeof (context) === 'function') {
        callback = context
        context = {}
      }

      return client.post(`/vouchers/${encode(code)}/validate`, context, callback)
    },

    redemption: (code, callback) => {
      return client.get(`/vouchers/${encode(code)}/redemption`, null, callback)
    },

    /*
    *  List redemptions. Sample query (1000 successful redemptions from April 2016):
    *  {
    *      limit: 1000,
    *      page: 0,
    *      start_date: '2016-04-01T00:00:00',
    *      end_date: '2016-04-30T23:59:59',
    *      result: 'Success'
    *  }
    */
    redemptions: (query, callback) => {
      return client.get('/redemptions/', query, callback)
    },

    redeem: (code, trackingId, callback) => {
      let context = {}
      if (typeof (code) === 'object') {
        context = code
        code = context.voucher
        delete context.voucher
      }
      // No `tracking_id` passed here,
      // use callback from 2n argument.
      if (typeof (trackingId) === 'function') {
        callback = trackingId
        trackingId = undefined
      }

      let url = `/vouchers/${encode(code)}/redemption`
      // If `tracking_id` passed, use it in query string.
      if (typeof (trackingId) === 'string' && trackingId) {
        url += `?tracking_id=${encode(trackingId)}`
      }

      return client.post(url, context, callback)
    },

    rollback: (redemptionId, data, callback) => {
      if (typeof (data) === 'function') {
        callback = data
        data = undefined
      }

      const qs = {}
      const payload = {}

      // If `reason` passed, use it in query string.
      if (typeof (data) === 'string') {
        qs['reason'] = encode(data)
      }

      if (typeof (data) === 'object') {
        qs['reason'] = data['reason'] || undefined
        qs['tracking_id'] = data['tracking_id'] || undefined
        payload['customer'] = data['customer'] || undefined
      }

      return client.post(
        `/redemptions/${encode(redemptionId)}/rollback`,
        payload, callback, {qs}
      )
    },

    publish: function (campaignName, callback) {
      let path = '/vouchers/publish'
      let payload = {}
      if (typeof (campaignName) === 'string') {
        path += '?campaign=' + encode(campaignName)
      }
      if (typeof (campaignName) === 'object') {
        payload = campaignName
      }

      return client.post(path, payload, callback)
    },

    campaign: {
      voucher: {
        create: (campaignName, voucher, callback) => {
          return client.post(
            `/campaigns/${encode(campaignName)}/vouchers`,
            // TODO if voucher is optional, secure against callback version
            voucher || {},
            callback
          )
        }
      }
    },

    customer: {
      create: (customer, callback) => {
        return client.post('/customers', customer, callback)
      },

      get: (customerId, callback) => {
        // TODO why fallback to empty string ?! shall we rather throw an error? print warning?
        return client.get(`/customers/${encode(customerId)}`, null, callback)
      },

      update: function (customer, callback) {
        return client.put(`/customers/${encode(customer.id)}`, customer, callback)
      },

      delete: function (customerId, callback) {
        return client.delete(`/customers/${encode(customerId)}`, callback)
      }
    },

    product: {
      create: function (product, callback) {
        return client.post('/products', product, callback)
      },

      get: function (productId, callback) {
        return client.get(`/products/${encode(productId)}`, null, callback)
      },

      update: function (product, callback) {
        return client.put(`/products/${encode(product.id)}`, product, callback)
      },

      delete: function (productId, callback) {
        return client.delete(`/products/${encode(productId)}`, callback)
      },

      sku: {
        create: function (productId, sku, callback) {
          return client.post(`/products/${encode(productId)}/skus`, sku, callback)
        },

        get: function (productId, skuId, callback) {
          return client.get(
            `/products/${encode(productId)}/skus/${encode(skuId)}`,
            null, callback
          )
        },

        update: function (productId, sku, callback) {
          return client.put(
            `/products/${encode(productId)}/skus/${encode(sku.id)}`,
            sku, callback
          )
        },

        delete: function (productId, skuId, callback) {
          return client.delete(
            `/products/${encode(productId)}/skus/${encode(skuId)}`,
            callback
          )
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>var __ = require('underscore');
var util = require('util');
var utils = require('../../../util/utils');
var $ = utils.getLocaleString;

function Publicip(cli, networkResourceProviderClient) {
  this.cli = cli;
  this.networkResourceProviderClient = networkResourceProviderClient;
}

__.extend(Publicip.prototype, {
  create: function (resourceGroupName, name, params, _) {
    var publicipProfile = this._parseAndValidatePublicIP(name, params);
    var publicip = this.get(resourceGroupName, name, _);
    if (publicip) {
      throw new Error(util.format($('A public ip address with name "%s" already exists in the resource group "%s"'), name, resourceGroupName));
    }

    var progress = this.cli.interaction.progress(util.format($('Creating public ip address "%s"'), name));
    try {
      this.networkResourceProviderClient.publicIpAddresses.createOrUpdate(resourceGroupName, name, publicipProfile, _);
    } finally {
      progress.end();
    }
  },

  set: function (resourceGroupName, name, params, _) {
    var publicipProfile = this._parseAndValidatePublicIP(name, params);
    var publicip = this.get(resourceGroupName, name, _);
    if (!publicip) {
      throw new Error(util.format($('A public ip address with name "%s" not found in the resource group "%s"'), name, resourceGroupName));
    }

    if (params.idletimeout) publicip.publicIpAddress.idleTimeoutInMinutes = publicipProfile.idleTimeoutInMinutes;
    if (params.allocationMethod) publicip.publicIpAddress.publicIpAllocationMethod = publicipProfile.publicIpAllocationMethod;
    if (params.domainNameLabel) publicip.publicIpAddress.dnsSettings.domainNameLabel = publicipProfile.dnsSettings.domainNameLabel;
    if (params.fqdn) publicip.publicIpAddress.dnsSettings.fqdn = publicipProfile.dnsSettings.fqdn;
    if (params.reverseFqdn) publicip.publicIpAddress.dnsSettings.reverseFqdn = publicipProfile.dnsSettings.reverseFqdn;

    this.update(resourceGroupName, name, publicip.publicIpAddress, _);
  },

  show: function (resourceGroupName, publicIpName, params, _) {
    var publicIP = this.get(resourceGroupName, publicIpName, _);
    var output = this.cli.output;
    var interaction = this.cli.interaction;

    if (publicIP) {
      interaction.formatOutput(publicIP.publicIpAddress, function () {
        utils.logLineFormat(publicIP.publicIpAddress, output.data);
      });
    } else {
      if (output.format().json) {
        output.json({});
      } else {
        output.warn(util.format($('A public ip address with name "%s" not found in the resource group "%s"'), publicIpName, resourceGroupName));
      }
    }
  },

  delete: function (resourceGroupName, publicIpName, params, _) {
    var publicIP = this.get(resourceGroupName, publicIpName, _);
    if (!publicIP) {
      throw new Error(util.format($('A public ip address with name "%s" not found in the resource group "%s"'), publicIpName, resourceGroupName));
    }

    if (!params.quiet && !this.cli.interaction.confirm(util.format($('Delete public ip address "%s"? [y/n] '), publicIpName), _)) {
      return;
    }

    var progress = this.cli.interaction.progress(util.format($('Deleting public ip address "%s"'), publicIpName));
    try {
      this.networkResourceProviderClient.publicIpAddresses.deleteMethod(resourceGroupName, publicIpName, _);
    } finally {
      progress.end();
    }
  },

  list: function (resourceGroupName, params, _) {
    var progress = this.cli.interaction.progress($('Getting the public ip addresses'));
    var publicIPs = null;
    try {
      publicIPs = this.networkResourceProviderClient.publicIpAddresses.list(resourceGroupName, _);
    } finally {
      progress.end();
    }

    var output = this.cli.output;
    this.cli.interaction.formatOutput(publicIPs.publicIpAddresses, function (outputData) {
      if (outputData.length === 0) {
        output.warn($('No public ip address found'));
      } else {
        output.table(outputData, function (row, item) {
          row.cell($('Name'), item.name);
          row.cell($('Location'), item.location);
          row.cell($('Allocation'), item.publicIpAllocationMethod);
          row.cell($('IP Address'), item.ipAddress || '');
          row.cell($('Idle timeout'), item.idleTimeoutInMinutes || '');
          var dnsName = '';
          if (item.dnsSettings) {
            dnsName = item.dnsSettings.fqdn;
          }
          row.cell($('DNS Name'), dnsName);
        });
      }
    });
  },

  get: function (resourceGroupName, publicIpName, _) {
    var progress = this.cli.interaction.progress(util.format($('Looking up the public ip "%s"'), publicIpName));
    try {
      var publicIP = this.networkResourceProviderClient.publicIpAddresses.get(resourceGroupName, publicIpName, _);
      return publicIP;
    } catch (e) {
      if (e.code === 'ResourceNotFound') {
        return null;
      }
      throw e;
    } finally {
      progress.end();
    }
  },

  update: function (resourceGroupName, publicIpName, publicIpProfile, _) {
    var progress = this.cli.interaction.progress(util.format($('Updating public ip address "%s"'), publicIpName));
    try {
      this.networkResourceProviderClient.publicIpAddresses.createOrUpdate(resourceGroupName, publicIpName, publicIpProfile, _);
    } catch (e) {
      throw e;
    } finally {
      progress.end();
    }
  },

  _parseAndValidatePublicIP: function (name, params) {
    var supportedAllocationTypes = ['Dynamic', 'Static'];
    var self = this;

    var publicipProfile = {
      name: name,
      publicIpAllocationMethod: supportedAllocationTypes[0]
    };

    if (params.idletimeout) {
      var timeoutAsInt = utils.parseInt(params.idletimeout);
      if (isNaN(timeoutAsInt) || timeoutAsInt === 0) {
        throw new Error($('idletimeout parameter must be an integer'));
      }
      publicipProfile.idleTimeoutInMinutes = timeoutAsInt;
    }

    if (params.allocationMethod) {
      if (utils.stringIsNullOrEmpty(params.allocationMethod)) {
        throw new Error($('allocation method parameter must not be null or empty string'));
      }
      publicipProfile.publicIpAllocationMethod = utils.verifyParamExistsInCollection(supportedAllocationTypes,
        params.allocationMethod, 'allocationMethod');
    }

    if (params.domainNameLabel) {
      if (utils.stringIsNullOrEmpty(params.domainNameLabel)) {
        throw new Error($('domain name label parameter must not be null or empty string'));
      }
      self._createDnsSettingsIfNotExist(publicipProfile);
      publicipProfile.dnsSettings.domainNameLabel = params.domainNameLabel;
    }

    if (params.fqdn) {
      if (utils.stringIsNullOrEmpty(params.fqdn)) {
        throw new Error($('fqdn parameter must not be null or empty string'));
      }
      self._createDnsSettingsIfNotExist(publicipProfile);
      publicipProfile.dnsSettings.fqdn = params.fqdn;
    }

    if (params.reverseFqdn) {
      if (utils.stringIsNullOrEmpty(params.reverseFqdn)) {
        throw new Error($('reverse fqdn parameter must not be null or empty string'));
      }
      self._createDnsSettingsIfNotExist(publicipProfile);
      publicipProfile.dnsSettings.fqdn = params.fqdn;
    }

    if (params.tags) {
      publicipProfile.tags = params.tags;
    }

    if (params.location) {
      publicipProfile.location = params.location;
    }

    return publicipProfile;
  },

  _createDnsSettingsIfNotExist: function (publicip) {
    if (!publicip.dnsSettings) publicip.dnsSettings = {};
  }
});

module.exports = Publicip;<commit_msg>'public-ip create' --tags handled<commit_after>var __ = require('underscore');
var util = require('util');
var utils = require('../../../util/utils');
var TagUtils = require('../tag/tagUtils');
var $ = utils.getLocaleString;

function Publicip(cli, networkResourceProviderClient) {
  this.cli = cli;
  this.networkResourceProviderClient = networkResourceProviderClient;
}

__.extend(Publicip.prototype, {
  create: function (resourceGroupName, name, params, _) {
    var publicipProfile = this._parseAndValidatePublicIP(name, params);
    var publicip = this.get(resourceGroupName, name, _);
    if (publicip) {
      throw new Error(util.format($('A public ip address with name "%s" already exists in the resource group "%s"'), name, resourceGroupName));
    }

    var progress = this.cli.interaction.progress(util.format($('Creating public ip address "%s"'), name));
    try {
      this.networkResourceProviderClient.publicIpAddresses.createOrUpdate(resourceGroupName, name, publicipProfile, _);
    } finally {
      progress.end();
    }
  },

  set: function (resourceGroupName, name, params, _) {
    var publicipProfile = this._parseAndValidatePublicIP(name, params);
    var publicip = this.get(resourceGroupName, name, _);
    if (!publicip) {
      throw new Error(util.format($('A public ip address with name "%s" not found in the resource group "%s"'), name, resourceGroupName));
    }

    if (params.idletimeout) publicip.publicIpAddress.idleTimeoutInMinutes = publicipProfile.idleTimeoutInMinutes;
    if (params.allocationMethod) publicip.publicIpAddress.publicIpAllocationMethod = publicipProfile.publicIpAllocationMethod;
    if (params.domainNameLabel) publicip.publicIpAddress.dnsSettings.domainNameLabel = publicipProfile.dnsSettings.domainNameLabel;
    if (params.fqdn) publicip.publicIpAddress.dnsSettings.fqdn = publicipProfile.dnsSettings.fqdn;
    if (params.reverseFqdn) publicip.publicIpAddress.dnsSettings.reverseFqdn = publicipProfile.dnsSettings.reverseFqdn;

    this.update(resourceGroupName, name, publicip.publicIpAddress, _);
  },

  show: function (resourceGroupName, publicIpName, params, _) {
    var publicIP = this.get(resourceGroupName, publicIpName, _);
    var output = this.cli.output;
    var interaction = this.cli.interaction;

    if (publicIP) {
      interaction.formatOutput(publicIP.publicIpAddress, function () {
        utils.logLineFormat(publicIP.publicIpAddress, output.data);
      });
    } else {
      if (output.format().json) {
        output.json({});
      } else {
        output.warn(util.format($('A public ip address with name "%s" not found in the resource group "%s"'), publicIpName, resourceGroupName));
      }
    }
  },

  delete: function (resourceGroupName, publicIpName, params, _) {
    var publicIP = this.get(resourceGroupName, publicIpName, _);
    if (!publicIP) {
      throw new Error(util.format($('A public ip address with name "%s" not found in the resource group "%s"'), publicIpName, resourceGroupName));
    }

    if (!params.quiet && !this.cli.interaction.confirm(util.format($('Delete public ip address "%s"? [y/n] '), publicIpName), _)) {
      return;
    }

    var progress = this.cli.interaction.progress(util.format($('Deleting public ip address "%s"'), publicIpName));
    try {
      this.networkResourceProviderClient.publicIpAddresses.deleteMethod(resourceGroupName, publicIpName, _);
    } finally {
      progress.end();
    }
  },

  list: function (resourceGroupName, params, _) {
    var progress = this.cli.interaction.progress($('Getting the public ip addresses'));
    var publicIPs = null;
    try {
      publicIPs = this.networkResourceProviderClient.publicIpAddresses.list(resourceGroupName, _);
    } finally {
      progress.end();
    }

    var output = this.cli.output;
    this.cli.interaction.formatOutput(publicIPs.publicIpAddresses, function (outputData) {
      if (outputData.length === 0) {
        output.warn($('No public ip address found'));
      } else {
        output.table(outputData, function (row, item) {
          row.cell($('Name'), item.name);
          row.cell($('Location'), item.location);
          row.cell($('Allocation'), item.publicIpAllocationMethod);
          row.cell($('IP Address'), item.ipAddress || '');
          row.cell($('Idle timeout'), item.idleTimeoutInMinutes || '');
          var dnsName = '';
          if (item.dnsSettings) {
            dnsName = item.dnsSettings.fqdn;
          }
          row.cell($('DNS Name'), dnsName);
        });
      }
    });
  },

  get: function (resourceGroupName, publicIpName, _) {
    var progress = this.cli.interaction.progress(util.format($('Looking up the public ip "%s"'), publicIpName));
    try {
      var publicIP = this.networkResourceProviderClient.publicIpAddresses.get(resourceGroupName, publicIpName, _);
      return publicIP;
    } catch (e) {
      if (e.code === 'ResourceNotFound') {
        return null;
      }
      throw e;
    } finally {
      progress.end();
    }
  },

  update: function (resourceGroupName, publicIpName, publicIpProfile, _) {
    var progress = this.cli.interaction.progress(util.format($('Updating public ip address "%s"'), publicIpName));
    try {
      this.networkResourceProviderClient.publicIpAddresses.createOrUpdate(resourceGroupName, publicIpName, publicIpProfile, _);
    } catch (e) {
      throw e;
    } finally {
      progress.end();
    }
  },

  _parseAndValidatePublicIP: function (name, params) {
    var supportedAllocationTypes = ['Dynamic', 'Static'];
    var self = this;

    var publicipProfile = {
      name: name,
      publicIpAllocationMethod: supportedAllocationTypes[0]
    };

    if (params.idletimeout) {
      var timeoutAsInt = utils.parseInt(params.idletimeout);
      if (isNaN(timeoutAsInt) || timeoutAsInt === 0) {
        throw new Error($('idletimeout parameter must be an integer'));
      }
      publicipProfile.idleTimeoutInMinutes = timeoutAsInt;
    }

    if (params.allocationMethod) {
      if (utils.stringIsNullOrEmpty(params.allocationMethod)) {
        throw new Error($('allocation method parameter must not be null or empty string'));
      }
      publicipProfile.publicIpAllocationMethod = utils.verifyParamExistsInCollection(supportedAllocationTypes,
        params.allocationMethod, 'allocationMethod');
    }

    if (params.domainNameLabel) {
      if (utils.stringIsNullOrEmpty(params.domainNameLabel)) {
        throw new Error($('domain name label parameter must not be null or empty string'));
      }
      self._createDnsSettingsIfNotExist(publicipProfile);
      publicipProfile.dnsSettings.domainNameLabel = params.domainNameLabel;
    }

    if (params.fqdn) {
      if (utils.stringIsNullOrEmpty(params.fqdn)) {
        throw new Error($('fqdn parameter must not be null or empty string'));
      }
      self._createDnsSettingsIfNotExist(publicipProfile);
      publicipProfile.dnsSettings.fqdn = params.fqdn;
    }

    if (params.reverseFqdn) {
      if (utils.stringIsNullOrEmpty(params.reverseFqdn)) {
        throw new Error($('reverse fqdn parameter must not be null or empty string'));
      }
      self._createDnsSettingsIfNotExist(publicipProfile);
      publicipProfile.dnsSettings.fqdn = params.fqdn;
    }

    if (params.tags) {
      publicipProfile.tags = TagUtils.buildTagsParameter(null, params);
    }

    if (params.location) {
      publicipProfile.location = params.location;
    }

    return publicipProfile;
  },

  _createDnsSettingsIfNotExist: function (publicip) {
    if (!publicip.dnsSettings) publicip.dnsSettings = {};
  }
});

module.exports = Publicip;<|endoftext|>


<commit_before>/* @flow */
import React, {Component} from 'react';
import {CompositeDecorator, Editor, EditorState, Modifier, RichUtils} from 'draft-js';
import getDefaultKeyBinding from 'draft-js/lib/getDefaultKeyBinding';
import changeBlockDepth from './lib/changeBlockDepth';
import changeBlockType from './lib/changeBlockType';
import insertBlockAfter from './lib/insertBlockAfter';
import isListItem from './lib/isListItem';
import isSoftNewlineEvent from 'draft-js/lib/isSoftNewlineEvent';
import EditorToolbar from './lib/EditorToolbar';
import EditorValue from './lib/EditorValue';
import LinkDecorator from './lib/LinkDecorator';
import cx from 'classnames';
import autobind from 'class-autobind';
import {EventEmitter} from 'events';
import {BLOCK_TYPE} from 'draft-js-utils';

// $FlowIssue - Flow doesn't understand CSS Modules
import './Draft.global.css';
// $FlowIssue - Flow doesn't understand CSS Modules
import styles from './RichTextEditor.css';

import type {ContentBlock} from 'draft-js';

const MAX_LIST_DEPTH = 2;

// Custom overrides for "code" style.
const styleMap = {
  CODE: {
    backgroundColor: '#f3f3f3',
    fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
    fontSize: 16,
    padding: 2,
  },
};

type ChangeHandler = (value: EditorValue) => any;

type Props = {
  className?: string;
  value: EditorValue;
  onChange?: ChangeHandler;
  placeholder?: string;
};

export default class RichTextEditor extends Component {
  props: Props;
  _keyEmitter: EventEmitter;

  constructor() {
    super(...arguments);
    this._keyEmitter = new EventEmitter();
    autobind(this);
  }

  render(): React.Element {
    let {props} = this;
    let editorState = props.value.getEditorState();
    let className = cx(props.className, styles.root);
    let placeholder = props.placeholder ? props.placeholder : '';
    // If the user changes block type before entering any text, we can either
    // style the placeholder or hide it. Let's just hide it for now.
    let editorClassName = cx({
      [styles.editor]: true,
      [styles.hidePlaceholder]: this._shouldHidePlaceholder(),
    });
    return (

        <EditorToolbar
          keyEmitter={this._keyEmitter}
          editorState={editorState}
          onChange={this._onChange}
          focusEditor={this._focus}
        />

          <Editor
            blockStyleFn={getBlockStyle}
            customStyleMap={styleMap}
            editorState={editorState}
            handleReturn={this._handleReturn}
            keyBindingFn={this._customKeyHandler}
            handleKeyCommand={this._handleKeyCommand}
            onTab={this._onTab}
            onChange={this._onChange}
            placeholder={placeholder}
            ref="editor"
            spellCheck={true}
          />

    );
  }

  _shouldHidePlaceholder(): boolean {
    let editorState = this.props.value.getEditorState();
    let contentState = editorState.getCurrentContent();
    if (!contentState.hasText()) {
      if (contentState.getBlockMap().first().getType() !== 'unstyled') {
        return true;
      }
    }
    return false;
  }

  _handleReturn(event: Object): boolean {
    if (this._handleReturnSoftNewline(event)) {
      return true;
    }
    if (this._handleReturnEmptyListItem()) {
      return true;
    }
    if (this._handleReturnSpecialBlock()) {
      return true;
    }
    return false;
  }

  // `shift + return` should insert a soft newline.
  _handleReturnSoftNewline(event: Object): boolean {
    let editorState = this.props.value.getEditorState();
    if (isSoftNewlineEvent(event)) {
      let selection = editorState.getSelection();
      if (selection.isCollapsed()) {
        this._onChange(RichUtils.insertSoftNewline(editorState));
      } else {
        let content = editorState.getCurrentContent();
        let newContent = Modifier.removeRange(content, selection, 'forward');
        let newSelection = newContent.getSelectionAfter();
        let block = newContent.getBlockForKey(newSelection.getStartKey());
        newContent = Modifier.insertText(
          newContent,
          newSelection,
          '\n',
          block.getInlineStyleAt(newSelection.getStartOffset()),
          null,
        );
        this._onChange(
          EditorState.push(editorState, newContent, 'insert-fragment')
        );
      }
      return true;
    }
    return false;
  }

  // If the cursor is in an empty list item when return is pressed, then the
  // block type should change to normal (end the list).
  _handleReturnEmptyListItem(): boolean {
    let editorState = this.props.value.getEditorState();
    let selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      let contentState = editorState.getCurrentContent();
      let blockKey = selection.getStartKey();
      let block = contentState.getBlockForKey(blockKey);
      if (isListItem(block) && block.getLength() === 0) {
        let depth = block.getDepth();
        let newState = (depth === 0) ?
          changeBlockType(editorState, blockKey, BLOCK_TYPE.UNSTYLED) :
          changeBlockDepth(editorState, blockKey, depth - 1);
        this._onChange(newState);
        return true;
      }
    }
    return false;
  }

  // If the cursor is at the end of a special block (any block type other than
  // normal or list item) when return is pressed, new block should be normal.
  _handleReturnSpecialBlock(): boolean {
    let editorState = this.props.value.getEditorState();
    let selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      let contentState = editorState.getCurrentContent();
      let blockKey = selection.getStartKey();
      let block = contentState.getBlockForKey(blockKey);
      if (!isListItem(block) && block.getType() !== BLOCK_TYPE.UNSTYLED) {
        // If cursor is at end.
        if (block.getLength() === selection.getStartOffset()) {
          let newEditorState = insertBlockAfter(
            editorState,
            blockKey,
            BLOCK_TYPE.UNSTYLED
          );
          this._onChange(newEditorState);
          return true;
        }
      }
    }
    return false;
  }

  _onTab(event: Object): ?string {
    let editorState = this.props.value.getEditorState();
    let newEditorState = RichUtils.onTab(event, editorState, MAX_LIST_DEPTH);
    if (newEditorState !== editorState) {
      this._onChange(newEditorState);
    }
  }

  _customKeyHandler(event: Object): ?string {
    // Allow toolbar to catch key combinations.
    let eventFlags = {};
    this._keyEmitter.emit('keypress', event, eventFlags);
    if (eventFlags.wasHandled) {
      return null;
    } else {
      return getDefaultKeyBinding(event);
    }
  }

  _handleKeyCommand(command: string): boolean {
    let editorState = this.props.value.getEditorState();
    let newEditorState = RichUtils.handleKeyCommand(editorState, command);
    if (newEditorState) {
      this._onChange(newEditorState);
      return true;
    } else {
      return false;
    }
  }

  _onChange(editorState: EditorState) {
    let {onChange, value} = this.props;
    if (onChange != null) {
      let newValue = value.setEditorState(editorState);
      onChange(newValue);
    }
  }

  _focus() {
    this.refs.editor.focus();
  }
}

function getBlockStyle(block: ContentBlock): string {
  let result = styles.block;
  switch (block.getType()) {
    case 'unstyled':
      return cx(result, styles.paragraph);
    case 'blockquote':
      return cx(result, styles.blockquote);
    case 'code-block':
      return cx(result, styles.codeBlock);
    default:
      return result;
  }
}

const decorator = new CompositeDecorator([LinkDecorator]);

function createEmptyValue(): EditorValue {
  return EditorValue.createEmpty(decorator);
}

function createValueFromString(markup: string, format: string): EditorValue {
  return EditorValue.createFromString(markup, format, decorator);
}

// $FlowIssue - This should probably not be done this way.
Object.assign(RichTextEditor, {
  EditorValue,
  decorator,
  createEmptyValue,
  createValueFromString,
});

export {EditorValue, decorator, createEmptyValue, createValueFromString};
<commit_msg>Pass extra props to <Editor><commit_after>/* @flow */
import React, {Component} from 'react';
import {CompositeDecorator, Editor, EditorState, Modifier, RichUtils} from 'draft-js';
import getDefaultKeyBinding from 'draft-js/lib/getDefaultKeyBinding';
import changeBlockDepth from './lib/changeBlockDepth';
import changeBlockType from './lib/changeBlockType';
import insertBlockAfter from './lib/insertBlockAfter';
import isListItem from './lib/isListItem';
import isSoftNewlineEvent from 'draft-js/lib/isSoftNewlineEvent';
import EditorToolbar from './lib/EditorToolbar';
import EditorValue from './lib/EditorValue';
import LinkDecorator from './lib/LinkDecorator';
import cx from 'classnames';
import autobind from 'class-autobind';
import {EventEmitter} from 'events';
import {BLOCK_TYPE} from 'draft-js-utils';

// $FlowIssue - Flow doesn't understand CSS Modules
import './Draft.global.css';
// $FlowIssue - Flow doesn't understand CSS Modules
import styles from './RichTextEditor.css';

import type {ContentBlock} from 'draft-js';

const MAX_LIST_DEPTH = 2;

// Custom overrides for "code" style.
const styleMap = {
  CODE: {
    backgroundColor: '#f3f3f3',
    fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
    fontSize: 16,
    padding: 2,
  },
};

type ChangeHandler = (value: EditorValue) => any;

type Props = {
  className?: string;
  value: EditorValue;
  onChange?: ChangeHandler;
  placeholder?: string;
};

export default class RichTextEditor extends Component {
  props: Props;
  _keyEmitter: EventEmitter;

  constructor() {
    super(...arguments);
    this._keyEmitter = new EventEmitter();
    autobind(this);
  }

  render(): React.Element {
    let {value, className, placeholder, ...otherProps} = this.props;
    let editorState = value.getEditorState();
    // If the user changes block type before entering any text, we can either
    // style the placeholder or hide it. Let's just hide it for now.
    let editorClassName = cx({
      [styles.editor]: true,
      [styles.hidePlaceholder]: this._shouldHidePlaceholder(),
    });
    return (

        <EditorToolbar
          keyEmitter={this._keyEmitter}
          editorState={editorState}
          onChange={this._onChange}
          focusEditor={this._focus}
        />

          <Editor
            {...otherProps}
            blockStyleFn={getBlockStyle}
            customStyleMap={styleMap}
            editorState={editorState}
            handleReturn={this._handleReturn}
            keyBindingFn={this._customKeyHandler}
            handleKeyCommand={this._handleKeyCommand}
            onTab={this._onTab}
            onChange={this._onChange}
            placeholder={placeholder}
            ref="editor"
            spellCheck={true}
          />

    );
  }

  _shouldHidePlaceholder(): boolean {
    let editorState = this.props.value.getEditorState();
    let contentState = editorState.getCurrentContent();
    if (!contentState.hasText()) {
      if (contentState.getBlockMap().first().getType() !== 'unstyled') {
        return true;
      }
    }
    return false;
  }

  _handleReturn(event: Object): boolean {
    if (this._handleReturnSoftNewline(event)) {
      return true;
    }
    if (this._handleReturnEmptyListItem()) {
      return true;
    }
    if (this._handleReturnSpecialBlock()) {
      return true;
    }
    return false;
  }

  // `shift + return` should insert a soft newline.
  _handleReturnSoftNewline(event: Object): boolean {
    let editorState = this.props.value.getEditorState();
    if (isSoftNewlineEvent(event)) {
      let selection = editorState.getSelection();
      if (selection.isCollapsed()) {
        this._onChange(RichUtils.insertSoftNewline(editorState));
      } else {
        let content = editorState.getCurrentContent();
        let newContent = Modifier.removeRange(content, selection, 'forward');
        let newSelection = newContent.getSelectionAfter();
        let block = newContent.getBlockForKey(newSelection.getStartKey());
        newContent = Modifier.insertText(
          newContent,
          newSelection,
          '\n',
          block.getInlineStyleAt(newSelection.getStartOffset()),
          null,
        );
        this._onChange(
          EditorState.push(editorState, newContent, 'insert-fragment')
        );
      }
      return true;
    }
    return false;
  }

  // If the cursor is in an empty list item when return is pressed, then the
  // block type should change to normal (end the list).
  _handleReturnEmptyListItem(): boolean {
    let editorState = this.props.value.getEditorState();
    let selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      let contentState = editorState.getCurrentContent();
      let blockKey = selection.getStartKey();
      let block = contentState.getBlockForKey(blockKey);
      if (isListItem(block) && block.getLength() === 0) {
        let depth = block.getDepth();
        let newState = (depth === 0) ?
          changeBlockType(editorState, blockKey, BLOCK_TYPE.UNSTYLED) :
          changeBlockDepth(editorState, blockKey, depth - 1);
        this._onChange(newState);
        return true;
      }
    }
    return false;
  }

  // If the cursor is at the end of a special block (any block type other than
  // normal or list item) when return is pressed, new block should be normal.
  _handleReturnSpecialBlock(): boolean {
    let editorState = this.props.value.getEditorState();
    let selection = editorState.getSelection();
    if (selection.isCollapsed()) {
      let contentState = editorState.getCurrentContent();
      let blockKey = selection.getStartKey();
      let block = contentState.getBlockForKey(blockKey);
      if (!isListItem(block) && block.getType() !== BLOCK_TYPE.UNSTYLED) {
        // If cursor is at end.
        if (block.getLength() === selection.getStartOffset()) {
          let newEditorState = insertBlockAfter(
            editorState,
            blockKey,
            BLOCK_TYPE.UNSTYLED
          );
          this._onChange(newEditorState);
          return true;
        }
      }
    }
    return false;
  }

  _onTab(event: Object): ?string {
    let editorState = this.props.value.getEditorState();
    let newEditorState = RichUtils.onTab(event, editorState, MAX_LIST_DEPTH);
    if (newEditorState !== editorState) {
      this._onChange(newEditorState);
    }
  }

  _customKeyHandler(event: Object): ?string {
    // Allow toolbar to catch key combinations.
    let eventFlags = {};
    this._keyEmitter.emit('keypress', event, eventFlags);
    if (eventFlags.wasHandled) {
      return null;
    } else {
      return getDefaultKeyBinding(event);
    }
  }

  _handleKeyCommand(command: string): boolean {
    let editorState = this.props.value.getEditorState();
    let newEditorState = RichUtils.handleKeyCommand(editorState, command);
    if (newEditorState) {
      this._onChange(newEditorState);
      return true;
    } else {
      return false;
    }
  }

  _onChange(editorState: EditorState) {
    let {onChange, value} = this.props;
    if (onChange != null) {
      let newValue = value.setEditorState(editorState);
      onChange(newValue);
    }
  }

  _focus() {
    this.refs.editor.focus();
  }
}

function getBlockStyle(block: ContentBlock): string {
  let result = styles.block;
  switch (block.getType()) {
    case 'unstyled':
      return cx(result, styles.paragraph);
    case 'blockquote':
      return cx(result, styles.blockquote);
    case 'code-block':
      return cx(result, styles.codeBlock);
    default:
      return result;
  }
}

const decorator = new CompositeDecorator([LinkDecorator]);

function createEmptyValue(): EditorValue {
  return EditorValue.createEmpty(decorator);
}

function createValueFromString(markup: string, format: string): EditorValue {
  return EditorValue.createFromString(markup, format, decorator);
}

// $FlowIssue - This should probably not be done this way.
Object.assign(RichTextEditor, {
  EditorValue,
  decorator,
  createEmptyValue,
  createValueFromString,
});

export {EditorValue, decorator, createEmptyValue, createValueFromString};
<|endoftext|>


<commit_before>import { merge } from './updates.js';

//
// Global state shared by all elements using this mixin.
//

// We assume that the keyboard changed the focus unless we have proof otherwise.
let focusedWithKeyboard = true;

// Flag used to track keyboard focus state across window blur/focus events.
let previousFocusedWithKeyboard;

// Shared event listener for all components using this mixin.
let windowFocusListener;

/**
 * Mixin which tracks a component's focus state so that it can render a focus
 * indication (e.g., a glowing outline) if and only if the user has used the
 * keyboard to interact with the component.
 *
 * This is modeled after the proposed
 * [focus-visible](https://github.com/WICG/focus-visible) feature for CSS.
 *
 * @module FocusVisibleMixin
 */
export default function FocusVisibleMixin(Base) {

  // The class prototype added by the mixin.
  return class FocusVisible extends Base {

    constructor() {
      // @ts-ignore
      super();
      this.addEventListener('blur', () => {
        this.setState({
          focusVisible: false
        });
      });
      this.addEventListener('focus', () => {
        this.setState({
          focusVisible: focusedWithKeyboard
        });

        // Remember how focus changed in case window loses focus.
        previousFocusedWithKeyboard = focusedWithKeyboard;

        // Go back to assuming use of the keyboard.
        focusedWithKeyboard = true;
      });
      this.addEventListener('mousedown', () => {
        // If an element receives focus, it won't be because of the keyboard.
        focusedWithKeyboard = false;
      });

      // We only want to start listening to window focus events if an element
      // using this mixin is actually instantiated, and we only do that for the
      // first such element. All elements can share that window focus listeners.
      if (windowFocusListener == null) {
        windowFocusListener = window.addEventListener('focus', windowFocused);

        // Firefox does not appear to listen to focus events on the window.
        // We listen to focus events on the document instead. There does not
        // appear to be a browser that listens to focus on both window and
        // document, so wiring up focus listeners to both seems to be safe.
        document.addEventListener('focus', windowFocused);
      }
    }

    get defaultState() {
      return Object.assign({}, super.defaultState, {
        focusVisible: false
      });
    }

    // For use with KeyboardMixin
    keydown(event) {
      const result = super.keydown && super.keydown(event);
      if (!this.state.focusVisible) {
        // User set focus on component with mouse, but is now using keyboard.
        this.setState({
          focusVisible: true
        });
      }
      return result;
    }

    get updates() {
      const base = super.updates || {};
      const outline = base.style && base.style.outline ||
        !this.state.focusVisible && 'none' ||
        undefined;
      return merge(base, {
        style: {
          outline
        }
      });
    }
  }
}

// The window has regained focus after having lost it. If the last element that
// had the focus obtained the focus via the keyboard, set our keyboard input
// flag. That previously-focused element is about to receive a focus event, and
// the handler for that can then treat the situation as if the focus was
// obtained via the keyboard. That helps a keyboard user reacquire the focused
// element when returning to the window.
function windowFocused() {
  focusedWithKeyboard = previousFocusedWithKeyboard;
}
<commit_msg>Fix reference to symbols.keydown.<commit_after>import { merge } from './updates.js';
import symbols from './symbols.js';

//
// Global state shared by all elements using this mixin.
//

// We assume that the keyboard changed the focus unless we have proof otherwise.
let focusedWithKeyboard = true;

// Flag used to track keyboard focus state across window blur/focus events.
let previousFocusedWithKeyboard;

// Shared event listener for all components using this mixin.
let windowFocusListener;

/**
 * Mixin which tracks a component's focus state so that it can render a focus
 * indication (e.g., a glowing outline) if and only if the user has used the
 * keyboard to interact with the component.
 *
 * This is modeled after the proposed
 * [focus-visible](https://github.com/WICG/focus-visible) feature for CSS.
 *
 * @module FocusVisibleMixin
 */
export default function FocusVisibleMixin(Base) {

  // The class prototype added by the mixin.
  return class FocusVisible extends Base {

    constructor() {
      // @ts-ignore
      super();
      this.addEventListener('blur', () => {
        this.setState({
          focusVisible: false
        });
      });
      this.addEventListener('focus', () => {
        this.setState({
          focusVisible: focusedWithKeyboard
        });

        // Remember how focus changed in case window loses focus.
        previousFocusedWithKeyboard = focusedWithKeyboard;

        // Go back to assuming use of the keyboard.
        focusedWithKeyboard = true;
      });
      this.addEventListener('mousedown', () => {
        // If an element receives focus, it won't be because of the keyboard.
        focusedWithKeyboard = false;
      });

      // We only want to start listening to window focus events if an element
      // using this mixin is actually instantiated, and we only do that for the
      // first such element. All elements can share that window focus listeners.
      if (windowFocusListener == null) {
        windowFocusListener = window.addEventListener('focus', windowFocused);

        // Firefox does not appear to listen to focus events on the window.
        // We listen to focus events on the document instead. There does not
        // appear to be a browser that listens to focus on both window and
        // document, so wiring up focus listeners to both seems to be safe.
        document.addEventListener('focus', windowFocused);
      }
    }

    get defaultState() {
      return Object.assign({}, super.defaultState, {
        focusVisible: false
      });
    }

    // For use with KeyboardMixin
    [symbols.keydown](event) {
      const result = super[symbols.keydown] && super[symbols.keydown](event);
      if (!this.state.focusVisible) {
        // User set focus on component with mouse, but is now using keyboard.
        previousFocusedWithKeyboard = true;
        this.setState({
          focusVisible: true
        });
      }
      return result;
    }

    get updates() {
      const base = super.updates || {};
      const outline = base.style && base.style.outline ||
        !this.state.focusVisible && 'none' ||
        undefined;
      return merge(base, {
        style: {
          outline
        }
      });
    }
  }
}

// The window has regained focus after having lost it. If the last element that
// had the focus obtained the focus via the keyboard, set our keyboard input
// flag. That previously-focused element is about to receive a focus event, and
// the handler for that can then treat the situation as if the focus was
// obtained via the keyboard. That helps a keyboard user reacquire the focused
// element when returning to the window.
function windowFocused() {
  focusedWithKeyboard = previousFocusedWithKeyboard;
}
<|endoftext|>


<commit_before>import classNames from 'classnames';
import React from 'react';
import ReactDOM from 'react-dom';

import BindMixin from '../Mixin/BindMixin';
import Util from '../Util/Util';

class ItemCheckbox extends Util.mixin(BindMixin) {
  get methodsToBind() {
    return ['handleChange'];
  }

  componentDidMount() {
    super.componentDidMount(...arguments);
    this.updateCheckbox();
  }

  componentDidUpdate() {
    super.componentDidUpdate(...arguments);
    this.updateCheckbox();
  }

  updateCheckbox() {
    let {props, refs} = this;
    let checkbox = ReactDOM.findDOMNode(refs.checkbox);

    if (props.checked != null) {
      checkbox.checked = props.checked;
    }

    let indeterminate = props.indeterminate;
    if (indeterminate != null) {
      checkbox.indeterminate = indeterminate;
    }
  }

  handleChange(event) {
    this.props.handleEvent(
      'change',
      // We don't pass back the indeterminate value because the indeterminate
      // value is solely determined by the parent.
      this.props.name, event.target.checked, event
    );
  }

  getLabel() {
    let label = this.props.label;
    if (!label) {
      return null;
    }

    return (

        {label}

    );
  }

  render() {
    let {props} = this;

    let labelClass = classNames({
      'mute': props.disabled,
      [props.labelClass]: !!props.labelClass
    });

    return (

        <input
          onChange={this.handleChange}
          disabled={props.disabled}
          ref="checkbox"
          type="checkbox" />

          <svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
            <g className="icon icon-svg-checkbox-indeterminate">
              <path d="M5,9.75 L11,9.75 C11.4142136,9.75 11.75,9.41421356 11.75,9 C11.75,8.58578644 11.4142136,8.25 11,8.25 L5,8.25 C4.58578644,8.25 4.25,8.58578644 4.25,9 C4.25,9.41421356 4.58578644,9.75 5,9.75 L5,9.75 Z" fill="#000000" fillOpacity="0.13"></path>
              <path d="M5,8.75 L11,8.75 C11.4142136,8.75 11.75,8.41421356 11.75,8 C11.75,7.58578644 11.4142136,7.25 11,7.25 L5,7.25 C4.58578644,7.25 4.25,7.58578644 4.25,8 C4.25,8.41421356 4.58578644,8.75 5,8.75 L5,8.75 Z" fill="#ffffff"></path>
            </g>
            <g className="icon icon-svg-checkbox-checked">
              <path d="M6.37547375,12.4433526 C6.66651906,12.8810343 7.30583183,12.8913338 7.61082475,12.4632544 L12.0274757,6.26416941 C12.2678262,5.92682021 12.1891933,5.45850202 11.8518441,5.21815145 C11.5144949,4.97780088 11.0461767,5.0564338 10.8058262,5.393783 L7.02648971,10.7134266 L5.62452625,8.60511675 C5.39516713,8.26020042 4.92962491,8.1665228 4.58470858,8.39588191 C4.23979226,8.62524103 4.14611463,9.09078326 4.37547375,9.43569958 L6.37547375,12.4433526 Z" fill="#000000" fillOpacity="0.13"></path>
              <path d="M6.37547375,11.4433526 C6.66651906,11.8810343 7.30583183,11.8913338 7.61082475,11.4632544 L12.0274757,5.26416941 C12.2678262,4.92682021 12.1891933,4.45850202 11.8518441,4.21815145 C11.5144949,3.97780088 11.0461767,4.0564338 10.8058262,4.393783 L7.02648971,9.71342659 L5.62452625,7.60511675 C5.39516713,7.26020042 4.92962491,7.1665228 4.58470858,7.39588191 C4.23979226,7.62524103 4.14611463,8.09078326 4.37547375,8.43569958 L6.37547375,11.4433526 Z" fill="#ffffff"></path>
            </g>
          </svg>

        {this.getLabel()}

    );
  }
}

ItemCheckbox.defaultProps = {
  handleChange: function () {},
  labelClass: 'form-row-element form-element-checkbox'
};

ItemCheckbox.propTypes = {
  // Optional value for setting the checked state of the checkbox,
  // should be either true for 'checked' or false 'unchecked'
  checked: React.PropTypes.bool,
  // Optional value for setting disabled state
  disabled: React.PropTypes.bool,
  // Optional. Which field property is currently being edited
  // (usually passed down from form definition)
  editing: React.PropTypes.string,
  // Function to handle change event
  // (usually passed down from FieldCheckbox)
  handleChange: React.PropTypes.func,
  // Optional value for setting the indeterminate state of the checkbox,
  // should be either true or false
  indeterminate: React.PropTypes.bool,
  // Optional label for field
  label: React.PropTypes.node,
  // name of the field property
  // (usually passed down from form definition)
  name: React.PropTypes.string.isRequired,

  // Classes
  labelClass: React.PropTypes.string
};

module.exports = ItemCheckbox;
<commit_msg>Add checkboxLabelClass for itemCheckbox<commit_after>import classNames from 'classnames';
import React from 'react';
import ReactDOM from 'react-dom';

import BindMixin from '../Mixin/BindMixin';
import Util from '../Util/Util';

class ItemCheckbox extends Util.mixin(BindMixin) {
  get methodsToBind() {
    return ['handleChange'];
  }

  componentDidMount() {
    super.componentDidMount(...arguments);
    this.updateCheckbox();
  }

  componentDidUpdate() {
    super.componentDidUpdate(...arguments);
    this.updateCheckbox();
  }

  updateCheckbox() {
    let {props, refs} = this;
    let checkbox = ReactDOM.findDOMNode(refs.checkbox);

    if (props.checked != null) {
      checkbox.checked = props.checked;
    }

    let indeterminate = props.indeterminate;
    if (indeterminate != null) {
      checkbox.indeterminate = indeterminate;
    }
  }

  handleChange(event) {
    this.props.handleEvent(
      'change',
      // We don't pass back the indeterminate value because the indeterminate
      // value is solely determined by the parent.
      this.props.name, event.target.checked, event
    );
  }

  getLabel() {
    let label = this.props.label;
    if (!label) {
      return null;
    }

    return (

        {label}

    );
  }

  render() {
    let {props} = this;

    let labelClass = classNames({
      'mute': props.disabled,
      [props.labelClass]: !!props.labelClass
    });

    return (

        <input
          onChange={this.handleChange}
          disabled={props.disabled}
          ref="checkbox"
          type="checkbox" />

          <svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
            <g className="icon icon-svg-checkbox-indeterminate">
              <path d="M5,9.75 L11,9.75 C11.4142136,9.75 11.75,9.41421356 11.75,9 C11.75,8.58578644 11.4142136,8.25 11,8.25 L5,8.25 C4.58578644,8.25 4.25,8.58578644 4.25,9 C4.25,9.41421356 4.58578644,9.75 5,9.75 L5,9.75 Z" fill="#000000" fillOpacity="0.13"></path>
              <path d="M5,8.75 L11,8.75 C11.4142136,8.75 11.75,8.41421356 11.75,8 C11.75,7.58578644 11.4142136,7.25 11,7.25 L5,7.25 C4.58578644,7.25 4.25,7.58578644 4.25,8 C4.25,8.41421356 4.58578644,8.75 5,8.75 L5,8.75 Z" fill="#ffffff"></path>
            </g>
            <g className="icon icon-svg-checkbox-checked">
              <path d="M6.37547375,12.4433526 C6.66651906,12.8810343 7.30583183,12.8913338 7.61082475,12.4632544 L12.0274757,6.26416941 C12.2678262,5.92682021 12.1891933,5.45850202 11.8518441,5.21815145 C11.5144949,4.97780088 11.0461767,5.0564338 10.8058262,5.393783 L7.02648971,10.7134266 L5.62452625,8.60511675 C5.39516713,8.26020042 4.92962491,8.1665228 4.58470858,8.39588191 C4.23979226,8.62524103 4.14611463,9.09078326 4.37547375,9.43569958 L6.37547375,12.4433526 Z" fill="#000000" fillOpacity="0.13"></path>
              <path d="M6.37547375,11.4433526 C6.66651906,11.8810343 7.30583183,11.8913338 7.61082475,11.4632544 L12.0274757,5.26416941 C12.2678262,4.92682021 12.1891933,4.45850202 11.8518441,4.21815145 C11.5144949,3.97780088 11.0461767,4.0564338 10.8058262,4.393783 L7.02648971,9.71342659 L5.62452625,7.60511675 C5.39516713,7.26020042 4.92962491,7.1665228 4.58470858,7.39588191 C4.23979226,7.62524103 4.14611463,8.09078326 4.37547375,8.43569958 L6.37547375,11.4433526 Z" fill="#ffffff"></path>
            </g>
          </svg>

        {this.getLabel()}

    );
  }
}

ItemCheckbox.defaultProps = {
  checkboxLabelClass: 'form-element-checkbox-label',
  handleChange: function () {},
  labelClass: 'form-row-element form-element-checkbox'
};

ItemCheckbox.propTypes = {
  // Optional value for setting the checked state of the checkbox,
  // should be either true for 'checked' or false 'unchecked'
  checked: React.PropTypes.bool,
  // Optional value for setting disabled state
  disabled: React.PropTypes.bool,
  // Optional. Which field property is currently being edited
  // (usually passed down from form definition)
  editing: React.PropTypes.string,
  // Function to handle change event
  // (usually passed down from FieldCheckbox)
  handleChange: React.PropTypes.func,
  // Optional value for setting the indeterminate state of the checkbox,
  // should be either true or false
  indeterminate: React.PropTypes.bool,
  // Optional label for field
  label: React.PropTypes.node,
  // name of the field property
  // (usually passed down from form definition)
  name: React.PropTypes.string.isRequired,

  // Classes
  checkboxLabelClass: React.PropTypes.string,
  labelClass: React.PropTypes.string
};

module.exports = ItemCheckbox;
<|endoftext|>


<commit_before>export default {
  coreModules: [
    'meteor/accounts-base',
    'meteor/blaze',
    'meteor/check',
    'meteor/ddp-client',
    'meteor/ddp-rate-limiter',
    'meteor/ejson',
    'meteor/email',
    'meteor/http',
    'meteor/check',
    'meteor/meteor',
    'meteor/mongo',
    'meteor/random',
    'meteor/reactive-var',
    'meteor/session',
    'meteor/templating',
    'meteor/tracker',
  ],
};
<commit_msg>Add namedExports to meteor environment<commit_after>export default {
  coreModules: [
    'meteor/accounts-base',
    'meteor/blaze',
    'meteor/check',
    'meteor/ddp-client',
    'meteor/ddp-rate-limiter',
    'meteor/ejson',
    'meteor/email',
    'meteor/http',
    'meteor/check',
    'meteor/meteor',
    'meteor/mongo',
    'meteor/random',
    'meteor/reactive-var',
    'meteor/session',
    'meteor/templating',
    'meteor/tracker',
  ],

  namedExports: {
    'meteor/accounts-base': ['AccountsClient', 'Accounts', 'AccountsServer'],
    'meteor/blaze': ['Blaze'],
    'meteor/check': ['check', 'Match'],
    'meteor/ddp-client': ['DDP'],
    'meteor/ddp-rate-limiter': ['DDPRateLimiter'],
    'meteor/ejson': ['EJSON'],
    'meteor/email': ['Email'],
    'meteor/http': ['HTTP'],
    'meteor/meteor': ['Meteor'],
    'meteor/mongo': ['Mongo'],
    'meteor/random': ['Random'],
    'meteor/reactive-var': ['ReactiveVar'],
    'meteor/session': ['Session'],
    'meteor/templating': ['Template'],
    'meteor/tracker': ['Tracker'],
  },
};
<|endoftext|>


<commit_before>import * as asn1js from "asn1js";
import { getParametersValue, clearProps } from "pvutils";
import CertID from "./CertID.js";
import Extension from "./Extension.js";
import Extensions from "./Extensions.js";
//**************************************************************************************
/**
 * Class from RFC6960
 */
export default class SingleResponse
{
	//**********************************************************************************
	/**
	 * Constructor for SingleResponse class
	 * @param {Object} [parameters={}]
	 * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
	 */
	constructor(parameters = {})
	{
		//region Internal properties of the object
		/**
		 * @type {CertID}
		 * @desc certID
		 */
		this.certID = getParametersValue(parameters, "certID", SingleResponse.defaultValues("certID"));
		/**
		 * @type {Object}
		 * @desc certStatus
		 */
		this.certStatus = getParametersValue(parameters, "certStatus", SingleResponse.defaultValues("certStatus"));
		/**
		 * @type {Date}
		 * @desc thisUpdate
		 */
		this.thisUpdate = getParametersValue(parameters, "thisUpdate", SingleResponse.defaultValues("thisUpdate"));

		if("nextUpdate" in parameters)
			/**
			 * @type {Date}
			 * @desc nextUpdate
			 */
			this.nextUpdate = getParametersValue(parameters, "nextUpdate", SingleResponse.defaultValues("nextUpdate"));

		if("singleExtensions" in parameters)
			/**
			 * @type {Array.<Extension>}
			 * @desc singleExtensions
			 */
			this.singleExtensions = getParametersValue(parameters, "singleExtensions", SingleResponse.defaultValues("singleExtensions"));
		//endregion

		//region If input argument array contains "schema" for this object
		if("schema" in parameters)
			this.fromSchema(parameters.schema);
		//endregion
	}
	//**********************************************************************************
	/**
	 * Return default values for all class members
	 * @param {string} memberName String name for a class member
	 */
	static defaultValues(memberName)
	{
		switch(memberName)
		{
			case "certID":
				return new CertID();
			case "certStatus":
				return {};
			case "thisUpdate":
			case "nextUpdate":
				return new Date(0, 0, 0);
			case "singleExtensions":
				return [];
			default:
				throw new Error(`Invalid member name for SingleResponse class: ${memberName}`);
		}
	}
	//**********************************************************************************
	/**
	 * Compare values with default values for all class members
	 * @param {string} memberName String name for a class member
	 * @param {*} memberValue Value to compare with default value
	 */
	static compareWithDefault(memberName, memberValue)
	{
		switch(memberName)
		{
			case "certID":
				// noinspection OverlyComplexBooleanExpressionJS
				return ((CertID.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) &&
						(CertID.compareWithDefault("issuerNameHash", memberValue.issuerNameHash)) &&
						(CertID.compareWithDefault("issuerKeyHash", memberValue.issuerKeyHash)) &&
						(CertID.compareWithDefault("serialNumber", memberValue.serialNumber)));
			case "certStatus":
				return (Object.keys(memberValue).length === 0);
			case "thisUpdate":
			case "nextUpdate":
				return (memberValue === SingleResponse.defaultValues(memberName));
			default:
				throw new Error(`Invalid member name for SingleResponse class: ${memberName}`);
		}
	}
	//**********************************************************************************
	/**
	 * Return value of pre-defined ASN.1 schema for current class
	 *
	 * ASN.1 schema:
	 * ```asn1
	 * SingleResponse ::= SEQUENCE {
	 *    certID                       CertID,
	 *    certStatus                   CertStatus,
	 *    thisUpdate                   GeneralizedTime,
	 *    nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
	 *    singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
	 *
	 * CertStatus ::= CHOICE {
	 *    good        [0]     IMPLICIT NULL,
	 *    revoked     [1]     IMPLICIT RevokedInfo,
	 *    unknown     [2]     IMPLICIT UnknownInfo }
	 *
	 * RevokedInfo ::= SEQUENCE {
	 *    revocationTime              GeneralizedTime,
	 *    revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
	 *
	 * UnknownInfo ::= NULL
	 * ```
	 *
	 * @param {Object} parameters Input parameters for the schema
	 * @returns {Object} asn1js schema object
	 */
	static schema(parameters = {})
	{
		/**
		 * @type {Object}
		 * @property {string} [blockName]
		 * @property {string} [certID]
		 * @property {string} [certStatus]
		 * @property {string} [thisUpdate]
		 * @property {string} [nextUpdate]
		 * @property {string} [singleExtensions]
		 */
		const names = getParametersValue(parameters, "names", {});

		return (new asn1js.Sequence({
			name: (names.blockName || ""),
			value: [
				CertID.schema(names.certID || {}),
				new asn1js.Choice({
					value: [
						new asn1js.Primitive({
							name: (names.certStatus || ""),
							idBlock: {
								tagClass: 3, // CONTEXT-SPECIFIC
								tagNumber: 0 // [0]
							},
							lenBlockLength: 1 // The length contains one byte 0x00
						}), // IMPLICIT NULL (no "valueBlock")
						new asn1js.Constructed({
							name: (names.certStatus || ""),
							idBlock: {
								tagClass: 3, // CONTEXT-SPECIFIC
								tagNumber: 1 // [1]
							},
							value: [
								new asn1js.GeneralizedTime(),
								new asn1js.Constructed({
									optional: true,
									idBlock: {
										tagClass: 3, // CONTEXT-SPECIFIC
										tagNumber: 0 // [0]
									},
									value: [new asn1js.Enumerated()]
								})
							]
						}),
						new asn1js.Primitive({
							name: (names.certStatus || ""),
							idBlock: {
								tagClass: 3, // CONTEXT-SPECIFIC
								tagNumber: 2 // [2]
							},
							lenBlock: { length: 1 }
						}) // IMPLICIT NULL (no "valueBlock")
					]
				}),
				new asn1js.GeneralizedTime({ name: (names.thisUpdate || "") }),
				new asn1js.Constructed({
					optional: true,
					idBlock: {
						tagClass: 3, // CONTEXT-SPECIFIC
						tagNumber: 0 // [0]
					},
					value: [new asn1js.GeneralizedTime({ name: (names.nextUpdate || "") })]
				}),
				new asn1js.Constructed({
					optional: true,
					idBlock: {
						tagClass: 3, // CONTEXT-SPECIFIC
						tagNumber: 1 // [1]
					},
					value: [Extensions.schema(names.singleExtensions || {})]
				}) // EXPLICIT SEQUENCE value
			]
		}));
	}
	//**********************************************************************************
	/**
	 * Convert parsed asn1js object into current class
	 * @param {!Object} schema
	 */
	fromSchema(schema)
	{
		//region Clear input data first
		clearProps(schema, [
			"certID",
			"certStatus",
			"thisUpdate",
			"nextUpdate",
			"singleExtensions"
		]);
		//endregion

		//region Check the schema is valid
		const asn1 = asn1js.compareSchema(schema,
			schema,
			SingleResponse.schema({
				names: {
					certID: {
						names: {
							blockName: "certID"
						}
					},
					certStatus: "certStatus",
					thisUpdate: "thisUpdate",
					nextUpdate: "nextUpdate",
					singleExtensions: {
						names: {
							blockName:
								"singleExtensions"
						}
					}
				}
			})
		);

		if(asn1.verified === false)
			throw new Error("Object's schema was not verified against input data for SingleResponse");
		//endregion

		//region Get internal properties from parsed schema
		this.certID = new CertID({ schema: asn1.result.certID });
		this.certStatus = asn1.result.certStatus;
		this.thisUpdate = asn1.result.thisUpdate.toDate();
		if("nextUpdate" in asn1.result)
			this.nextUpdate = asn1.result.nextUpdate.toDate();

		if("singleExtensions" in asn1.result)
			this.singleExtensions = Array.from(asn1.result.singleExtensions.valueBlock.value, element => new Extension({ schema: element }));
		//endregion
	}
	//**********************************************************************************
	/**
	 * Convert current object to asn1js object and set correct values
	 * @returns {Object} asn1js object
	 */
	toSchema()
	{
		//region Create value array for output sequence
		const outputArray = [];

		outputArray.push(this.certID.toSchema());
		outputArray.push(this.certStatus);
		outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.thisUpdate }));
		if("nextUpdate" in this)
			outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.nextUpdate }));

		if("singleExtensions" in this)
		{
			outputArray.push(new asn1js.Sequence({
				value: Array.from(this.singleExtensions, element => element.toSchema())
			}));
		}
		//endregion

		//region Construct and return new ASN.1 schema for this object
		return (new asn1js.Sequence({
			value: outputArray
		}));
		//endregion
	}
	//**********************************************************************************
	/**
	 * Convertion for the class to JSON object
	 * @returns {Object}
	 */
	toJSON()
	{
		const _object = {
			certID: this.certID.toJSON(),
			certStatus: this.certStatus.toJSON(),
			thisUpdate: this.thisUpdate
		};

		if("nextUpdate" in this)
			_object.nextUpdate = this.nextUpdate;

		if("singleExtensions" in this)
			_object.singleExtensions = Array.from(this.singleExtensions, element => element.toJSON());

		return _object;
	}
	//**********************************************************************************
}
//**************************************************************************************
<commit_msg>Fix SingleResponse.nextUpdate that should be wrapped in a constructed component<commit_after>import * as asn1js from "asn1js";
import { getParametersValue, clearProps } from "pvutils";
import CertID from "./CertID.js";
import Extension from "./Extension.js";
import Extensions from "./Extensions.js";
//**************************************************************************************
/**
 * Class from RFC6960
 */
export default class SingleResponse
{
	//**********************************************************************************
	/**
	 * Constructor for SingleResponse class
	 * @param {Object} [parameters={}]
	 * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from
	 */
	constructor(parameters = {})
	{
		//region Internal properties of the object
		/**
		 * @type {CertID}
		 * @desc certID
		 */
		this.certID = getParametersValue(parameters, "certID", SingleResponse.defaultValues("certID"));
		/**
		 * @type {Object}
		 * @desc certStatus
		 */
		this.certStatus = getParametersValue(parameters, "certStatus", SingleResponse.defaultValues("certStatus"));
		/**
		 * @type {Date}
		 * @desc thisUpdate
		 */
		this.thisUpdate = getParametersValue(parameters, "thisUpdate", SingleResponse.defaultValues("thisUpdate"));

		if("nextUpdate" in parameters)
			/**
			 * @type {Date}
			 * @desc nextUpdate
			 */
			this.nextUpdate = getParametersValue(parameters, "nextUpdate", SingleResponse.defaultValues("nextUpdate"));

		if("singleExtensions" in parameters)
			/**
			 * @type {Array.<Extension>}
			 * @desc singleExtensions
			 */
			this.singleExtensions = getParametersValue(parameters, "singleExtensions", SingleResponse.defaultValues("singleExtensions"));
		//endregion

		//region If input argument array contains "schema" for this object
		if("schema" in parameters)
			this.fromSchema(parameters.schema);
		//endregion
	}
	//**********************************************************************************
	/**
	 * Return default values for all class members
	 * @param {string} memberName String name for a class member
	 */
	static defaultValues(memberName)
	{
		switch(memberName)
		{
			case "certID":
				return new CertID();
			case "certStatus":
				return {};
			case "thisUpdate":
			case "nextUpdate":
				return new Date(0, 0, 0);
			case "singleExtensions":
				return [];
			default:
				throw new Error(`Invalid member name for SingleResponse class: ${memberName}`);
		}
	}
	//**********************************************************************************
	/**
	 * Compare values with default values for all class members
	 * @param {string} memberName String name for a class member
	 * @param {*} memberValue Value to compare with default value
	 */
	static compareWithDefault(memberName, memberValue)
	{
		switch(memberName)
		{
			case "certID":
				// noinspection OverlyComplexBooleanExpressionJS
				return ((CertID.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) &&
						(CertID.compareWithDefault("issuerNameHash", memberValue.issuerNameHash)) &&
						(CertID.compareWithDefault("issuerKeyHash", memberValue.issuerKeyHash)) &&
						(CertID.compareWithDefault("serialNumber", memberValue.serialNumber)));
			case "certStatus":
				return (Object.keys(memberValue).length === 0);
			case "thisUpdate":
			case "nextUpdate":
				return (memberValue === SingleResponse.defaultValues(memberName));
			default:
				throw new Error(`Invalid member name for SingleResponse class: ${memberName}`);
		}
	}
	//**********************************************************************************
	/**
	 * Return value of pre-defined ASN.1 schema for current class
	 *
	 * ASN.1 schema:
	 * ```asn1
	 * SingleResponse ::= SEQUENCE {
	 *    certID                       CertID,
	 *    certStatus                   CertStatus,
	 *    thisUpdate                   GeneralizedTime,
	 *    nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
	 *    singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
	 *
	 * CertStatus ::= CHOICE {
	 *    good        [0]     IMPLICIT NULL,
	 *    revoked     [1]     IMPLICIT RevokedInfo,
	 *    unknown     [2]     IMPLICIT UnknownInfo }
	 *
	 * RevokedInfo ::= SEQUENCE {
	 *    revocationTime              GeneralizedTime,
	 *    revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
	 *
	 * UnknownInfo ::= NULL
	 * ```
	 *
	 * @param {Object} parameters Input parameters for the schema
	 * @returns {Object} asn1js schema object
	 */
	static schema(parameters = {})
	{
		/**
		 * @type {Object}
		 * @property {string} [blockName]
		 * @property {string} [certID]
		 * @property {string} [certStatus]
		 * @property {string} [thisUpdate]
		 * @property {string} [nextUpdate]
		 * @property {string} [singleExtensions]
		 */
		const names = getParametersValue(parameters, "names", {});

		return (new asn1js.Sequence({
			name: (names.blockName || ""),
			value: [
				CertID.schema(names.certID || {}),
				new asn1js.Choice({
					value: [
						new asn1js.Primitive({
							name: (names.certStatus || ""),
							idBlock: {
								tagClass: 3, // CONTEXT-SPECIFIC
								tagNumber: 0 // [0]
							},
							lenBlockLength: 1 // The length contains one byte 0x00
						}), // IMPLICIT NULL (no "valueBlock")
						new asn1js.Constructed({
							name: (names.certStatus || ""),
							idBlock: {
								tagClass: 3, // CONTEXT-SPECIFIC
								tagNumber: 1 // [1]
							},
							value: [
								new asn1js.GeneralizedTime(),
								new asn1js.Constructed({
									optional: true,
									idBlock: {
										tagClass: 3, // CONTEXT-SPECIFIC
										tagNumber: 0 // [0]
									},
									value: [new asn1js.Enumerated()]
								})
							]
						}),
						new asn1js.Primitive({
							name: (names.certStatus || ""),
							idBlock: {
								tagClass: 3, // CONTEXT-SPECIFIC
								tagNumber: 2 // [2]
							},
							lenBlock: { length: 1 }
						}) // IMPLICIT NULL (no "valueBlock")
					]
				}),
				new asn1js.GeneralizedTime({ name: (names.thisUpdate || "") }),
				new asn1js.Constructed({
					optional: true,
					idBlock: {
						tagClass: 3, // CONTEXT-SPECIFIC
						tagNumber: 0 // [0]
					},
					value: [new asn1js.GeneralizedTime({ name: (names.nextUpdate || "") })]
				}),
				new asn1js.Constructed({
					optional: true,
					idBlock: {
						tagClass: 3, // CONTEXT-SPECIFIC
						tagNumber: 1 // [1]
					},
					value: [Extensions.schema(names.singleExtensions || {})]
				}) // EXPLICIT SEQUENCE value
			]
		}));
	}
	//**********************************************************************************
	/**
	 * Convert parsed asn1js object into current class
	 * @param {!Object} schema
	 */
	fromSchema(schema)
	{
		//region Clear input data first
		clearProps(schema, [
			"certID",
			"certStatus",
			"thisUpdate",
			"nextUpdate",
			"singleExtensions"
		]);
		//endregion

		//region Check the schema is valid
		const asn1 = asn1js.compareSchema(schema,
			schema,
			SingleResponse.schema({
				names: {
					certID: {
						names: {
							blockName: "certID"
						}
					},
					certStatus: "certStatus",
					thisUpdate: "thisUpdate",
					nextUpdate: "nextUpdate",
					singleExtensions: {
						names: {
							blockName:
								"singleExtensions"
						}
					}
				}
			})
		);

		if(asn1.verified === false)
			throw new Error("Object's schema was not verified against input data for SingleResponse");
		//endregion

		//region Get internal properties from parsed schema
		this.certID = new CertID({ schema: asn1.result.certID });
		this.certStatus = asn1.result.certStatus;
		this.thisUpdate = asn1.result.thisUpdate.toDate();
		if("nextUpdate" in asn1.result)
			this.nextUpdate = asn1.result.nextUpdate.toDate();

		if("singleExtensions" in asn1.result)
			this.singleExtensions = Array.from(asn1.result.singleExtensions.valueBlock.value, element => new Extension({ schema: element }));
		//endregion
	}
	//**********************************************************************************
	/**
	 * Convert current object to asn1js object and set correct values
	 * @returns {Object} asn1js object
	 */
	toSchema()
	{
		//region Create value array for output sequence
		const outputArray = [];

		outputArray.push(this.certID.toSchema());
		outputArray.push(this.certStatus);
		outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.thisUpdate }));
		if("nextUpdate" in this)
		{
			outputArray.push(new asn1js.Constructed({
					idBlock: {
						tagClass: 3, // CONTEXT-SPECIFIC
						tagNumber: 0 // [0]
					},
					value: [new asn1js.GeneralizedTime({ valueDate: (this.nextUpdate ) })]
				}))
		}

		if("singleExtensions" in this)
		{
			outputArray.push(new asn1js.Sequence({
				value: Array.from(this.singleExtensions, element => element.toSchema())
			}));
		}
		//endregion

		//region Construct and return new ASN.1 schema for this object
		return (new asn1js.Sequence({
			value: outputArray
		}));
		//endregion
	}
	//**********************************************************************************
	/**
	 * Convertion for the class to JSON object
	 * @returns {Object}
	 */
	toJSON()
	{
		const _object = {
			certID: this.certID.toJSON(),
			certStatus: this.certStatus.toJSON(),
			thisUpdate: this.thisUpdate
		};

		if("nextUpdate" in this)
			_object.nextUpdate = this.nextUpdate;

		if("singleExtensions" in this)
			_object.singleExtensions = Array.from(this.singleExtensions, element => element.toJSON());

		return _object;
	}
	//**********************************************************************************
}
//**************************************************************************************
<|endoftext|>