<commit_before>const Client       = require('../../../base/client');
const BinarySocket = require('../../../base/socket');
const Dialog       = require('../../../common/attach_dom/dialog');
const localize     = require('../../../../_common/localize').localize;
const State        = require('../../../../_common/storage').State;

const Settings = (() => {
    const onLoad = () => {
        BinarySocket.wait('get_account_status').then(() => {
            $('.real').setVisibility(!Client.get('is_virtual'));

            const status = State.getResponse('get_account_status.status') || [];

            if (!/social_signup/.test(status)) {
                $('#change_password').setVisibility(1);
            }

            // Disabling Authentication button for SVG accounts
            if ((Client.get('landing_company_shortcode') === 'svg')) {
                $('#authenticate a')
                    .attr('href', '#')
                    .on('click',  () => {
                        Dialog.alert({
                            id               : 'authorize_svg_error',
                            localized_message: localize('You do not need to authenticate your account at this time.[_1]We will inform you when your account needs to be authenticated.', '
'),
                            localized_title  : localize('No authentication required'),
                            ok_text          : localize('Back to trading'),
                        });
                    });
            }

            // Professional Client menu should only be shown to maltainvest accounts.
            if ((Client.get('landing_company_shortcode') === 'maltainvest')) {
                const is_professional_client    = status.indexOf('professional') !== -1;
                const is_requested_professional = /professional_requested/.test(status);
                let localized_text = '';
                if (is_professional_client) {
                    localized_text = localize('You are categorised as a professional client.');
                } else if (is_requested_professional) {
                    localized_text = localize('Your application to be treated as a professional client is being processed.');
                } else { // is retail client
                    localized_text = localize('You are categorised as a retail client. Apply to be treated as a professional trader.');
                }
                $('#professional_client').setVisibility(1).find('p').text(localized_text);
            }

            $('#settings_container').setVisibility(1);
        });
    };

    return {
        onLoad,
    };
})();

module.exports = Settings;
<commit_msg>Fixed bugs of showing popup<commit_after>const Client       = require('../../../base/client');
const BinarySocket = require('../../../base/socket');
const Dialog       = require('../../../common/attach_dom/dialog');
const localize     = require('../../../../_common/localize').localize;
const State        = require('../../../../_common/storage').State;

const Settings = (() => {
    const onLoad = () => {
        BinarySocket.wait('get_account_status').then(() => {
            $('.real').setVisibility(!Client.get('is_virtual'));

            const status = State.getResponse('get_account_status.status') || [];

            if (!/social_signup/.test(status)) {
                $('#change_password').setVisibility(1);
            }

            // Disabling Authentication button for SVG accounts
            const is_authenticated                 = State.getResponse('get_account_status.status').includes('authenticated');
            const is_client_prompt_to_authenticate = State.getResponse('get_account_status.prompt_client_to_authenticate');
            const is_high_risk                     = Client.getRiskAssessment();
            const is_svg                           = Client.get('landing_company_shortcode') === 'svg';
            if (is_svg && !is_high_risk && !is_client_prompt_to_authenticate && !is_authenticated) {
                $('#authenticate a')
                    .attr('href', '#')
                    .on('click',  () => {
                        Dialog.alert({
                            id               : 'authorize_svg_error',
                            localized_message: localize('You do not need to authenticate your account at this time.[_1]We will inform you when your account needs to be authenticated.', '
'),
                            localized_title  : localize('No authentication required'),
                            ok_text          : localize('Back to trading'),
                        });
                    });
            }

            // Professional Client menu should only be shown to maltainvest accounts.
            if ((Client.get('landing_company_shortcode') === 'maltainvest')) {
                const is_professional_client    = status.indexOf('professional') !== -1;
                const is_requested_professional = /professional_requested/.test(status);
                let localized_text = '';
                if (is_professional_client) {
                    localized_text = localize('You are categorised as a professional client.');
                } else if (is_requested_professional) {
                    localized_text = localize('Your application to be treated as a professional client is being processed.');
                } else { // is retail client
                    localized_text = localize('You are categorised as a retail client. Apply to be treated as a professional trader.');
                }
                $('#professional_client').setVisibility(1).find('p').text(localized_text);
            }

            $('#settings_container').setVisibility(1);
        });
    };

    return {
        onLoad,
    };
})();

module.exports = Settings;
<|endoftext|>


<commit_before>describe('console', function () {
	it('should exist', function () {
		expect(window.console).toBeDefined();
	});

	it('should have method .out()', function () {
		expect(window.console.out).toBeDefined();
	});

	it('should have method .run()', function () {
		expect(window.console.run).toBeDefined();
	});

	it('should have method .findType()', function () {
		expect(window.console.findType).toBeDefined();
	});
});

describe('console.findType()', function () {
	it('should return .text and .type', function () {
		var foundType = console.findType(Math.PI);
		expect(foundType.type).toEqual('number:');
		expect(foundType.text).toEqual(3.141592653589793);
	});

	it('should stringify objects, arrays, and null values', function () {
		var obj = console.findType({"hello":"goodbye"}).text,
			arr = console.findType([1, 2, 3]).text,
			nl = console.findType(null).text;
		expect(obj).toEqual('{"hello":"goodbye"}');
		expect(arr).toEqual('[1,2,3]');
		expect(nl).toEqual('null');
	});

	it('should correctly identify numbers', function () {
		expect(console.findType(4).type).toEqual('number:');
		expect(console.findType(NaN).type).toEqual('number:');
		expect(console.findType("4").type).not.toEqual('number:');
	});

	it('should correctly identify booleans', function () {
		expect(console.findType(false).type).toEqual('boolean:');
		expect(console.findType(true).type).toEqual('boolean:');
		expect(console.findType('true').type).not.toEqual('boolean:');
	});

	it('should correctly identify strings', function () {
		expect(console.findType('Steve Perry').type).toEqual('string:');
		expect(console.findType(['Steve', 123][1]).type).not.toEqual('string:');
	});

	it('should correctly identify objects', function () {
		expect(console.findType({"name": "value"}).type).toEqual('object:');
	});

	it('should correctly identify arrays', function () {
		expect(console.findType(["one", "two", 3]).type).toEqual('array:');
	});

	it('should differentiate between objects and arrays', function () {
		expect(console.findType([1, 2, 3]).type).not.toEqual('object:');
		expect(console.findType({"an": "object"}).type).not.toEqual('array:');
	});

	it('should be able to identify undefined', function () {
		expect(console.findType(undefined).type).toEqual('undefined:');
		expect(console.findType('undefined').type).not.toEqual('undefined:');
	});

	it('should be able to identify null', function () {
		expect(console.findType(null).type).toEqual('null:');
		expect(console.findType(undefined).type).not.toEqual('null:');
		expect(console.findType('null').type).not.toEqual('null:');
	});

});

describe('console.out()', function () {

	it('should log the type and output of a given JS statement in the browser console (open console to check output).',
	function () {
		console.out(2);
		console.out('two');
		console.out([1, 1]);
		console.out({"one":"one"});
		console.out(NaN);
		console.out(undefined);
		console.out(null);
		console.out(true);
		expect(console.out('placeholder')).not.toBeDefined();
	});

	it('should log using the user-specified color given any valid css declaration (open console to check output)',
	function () {
		console.out("hex 3-digit: this should be invisible", {"color":"#fff"});
		console.out("color string: this should be blue", {"color":"blue"});
		console.out("hex 6-digit: this should be orange", {"color":"#ff9900"});
		console.out("rgb: this should be pink", {"color":"rgb(255,20,147)"});
		console.out("rgba: this should be really light pink", {"color":"rgba(255,20,147,0.2)"});
		console.out("hsl: this should be green", {"color":"hsl(120, 96%, 34%)"});
		console.out("hsla: this should be really light green", {"color":"hsla(120, 96%, 34%, 0.2)"});
		expect(console.out('placeholder')).not.toBeDefined();
	});

	it('should log function name, function arguments, and error status if given those parameters (open console to check output)',
	function () {
		console.out('error message', {
            "color": 'red',
            "fnName": 'someFunction',
            "fnArgs": '1, 2, 3',
            "error": true
        });
        console.out('success message', {
            "color": 'darkgreen',
            "fnName": 'anotherFunction',
            "fnArgs": '1, 2, 3'
        });
        expect(console.out('error message')).not.toBeDefined();
	});

});

describe('console.run()', function () {

	var ex;

	beforeEach(function () {
		ex = {
			"example": function (one, two, three) {
				return one + two + three;
			},
			"notAFunction": {
				"not": "function"
			}
		};
	});

	afterEach(function () {
		ex = null;
	});

	it('should run the given function', function () {
		spyOn(ex, 'example');
		console.run(ex.example);
		expect(ex.example).toHaveBeenCalled();
	});

	it('should call console.out() to print function output', function () {
		spyOn(console, 'out');
		console.run(ex.example);
		expect(console.out).toHaveBeenCalled();
	});

	it('should call console.out() for non-functions as well', function () {
		spyOn(console, 'out');
		console.run(ex.notAFunction);
		expect(console.out).toHaveBeenCalled();
	});

	it('should accept function arguments and run the function with those arguments', function () {
		expect(console.run(ex.example, 1, 1, 1)).toEqual(3);
	});

});<commit_msg>reorganize unit tests and add one spec<commit_after>describe('console', function () {
	it('should exist', function () {
		expect(window.console).toBeDefined();
	});

	it('should have method .out()', function () {
		expect(window.console.out).toBeDefined();
	});

	it('should have method .run()', function () {
		expect(window.console.run).toBeDefined();
	});

	it('should have method .findType()', function () {
		expect(window.console.findType).toBeDefined();
	});
});

describe('console.findType()', function () {
	it('should return .text and .type', function () {
		var foundType = console.findType(Math.PI);
		expect(foundType.type).toEqual('number:');
		expect(foundType.text).toEqual(3.141592653589793);
	});

	it('should stringify objects, arrays, and null values', function () {
		var obj = console.findType({"hello":"goodbye"}).text,
			arr = console.findType([1, 2, 3]).text,
			nl = console.findType(null).text;
		expect(obj).toEqual('{"hello":"goodbye"}');
		expect(arr).toEqual('[1,2,3]');
		expect(nl).toEqual('null');
	});

	it('should correctly identify numbers', function () {
		expect(console.findType(4).type).toEqual('number:');
		expect(console.findType(NaN).type).toEqual('number:');
		expect(console.findType("4").type).not.toEqual('number:');
	});

	it('should correctly identify booleans', function () {
		expect(console.findType(false).type).toEqual('boolean:');
		expect(console.findType(true).type).toEqual('boolean:');
		expect(console.findType('true').type).not.toEqual('boolean:');
	});

	it('should correctly identify strings', function () {
		expect(console.findType('Steve Perry').type).toEqual('string:');
		expect(console.findType(['Steve', 123][1]).type).not.toEqual('string:');
	});

	it('should be able to identify undefined', function () {
		expect(console.findType(undefined).type).toEqual('undefined:');
		expect(console.findType('undefined').type).not.toEqual('undefined:');
	});

	it('should correctly identify objects', function () {
		expect(console.findType({"name": "value"}).type).toEqual('object:');
	});

	it('should correctly identify arrays', function () {
		expect(console.findType(["one", "two", 3]).type).toEqual('array:');
	});

	it('should be able to identify null', function () {
		expect(console.findType(null).type).toEqual('null:');
		expect(console.findType(undefined).type).not.toEqual('null:');
		expect(console.findType('null').type).not.toEqual('null:');
	});

	it('should differentiate between objects, arrays, and null', function () {
		expect(console.findType([1, 2, 3]).type).not.toEqual('object:');
		expect(console.findType({"an": "object"}).type).not.toEqual('array:');
		expect(console.findType(null).type).not.toEqual('object:');
	});

});

describe('console.out()', function () {

	it('should log the type and output of a given JS statement in the browser console (open console to check output).',
	function () {
		console.out(2);
		console.out('two');
		console.out([1, 1]);
		console.out({"one":"one"});
		console.out(NaN);
		console.out(undefined);
		console.out(null);
		console.out(true);
		expect(console.out('placeholder')).not.toBeDefined();
	});

	it('should log using the user-specified color given any valid css declaration (open console to check output)',
	function () {
		console.out("hex 3-digit: this should be invisible", {"color":"#fff"});
		console.out("color string: this should be blue", {"color":"blue"});
		console.out("hex 6-digit: this should be orange", {"color":"#ff9900"});
		console.out("rgb: this should be pink", {"color":"rgb(255,20,147)"});
		console.out("rgba: this should be really light pink", {"color":"rgba(255,20,147,0.2)"});
		console.out("hsl: this should be green", {"color":"hsl(120, 96%, 34%)"});
		console.out("hsla: this should be really light green", {"color":"hsla(120, 96%, 34%, 0.2)"});
		expect(console.out('placeholder')).not.toBeDefined();
	});

	it('should log function name, function arguments, and error status if given those parameters (open console to check output)',
	function () {
		console.out('error message', {
            "color": 'red',
            "fnName": 'someFunction',
            "fnArgs": '1, 2, 3',
            "error": true
        });
        console.out('success message', {
            "color": 'darkgreen',
            "fnName": 'anotherFunction',
            "fnArgs": '1, 2, 3'
        });
        expect(console.out('error message')).not.toBeDefined();
	});

});

describe('console.run()', function () {

	var ex;

	beforeEach(function () {
		ex = {
			"example": function (one, two, three) {
				return one + two + three;
			},
			"notAFunction": {
				"not": "function"
			}
		};
	});

	afterEach(function () {
		ex = null;
	});

	it('should run the given function', function () {
		spyOn(ex, 'example');
		console.run(ex.example);
		expect(ex.example).toHaveBeenCalled();
	});

	it('should call console.out() to print function output', function () {
		spyOn(console, 'out');
		console.run(ex.example);
		expect(console.out).toHaveBeenCalled();
	});

	it('should call console.out() for non-functions as well', function () {
		spyOn(console, 'out');
		console.run(ex.notAFunction);
		expect(console.out).toHaveBeenCalled();
	});

	it('should accept function arguments and run the function with those arguments', function () {
		expect(console.run(ex.example, 1, 1, 1)).toEqual(3);
	});

});<|endoftext|>


<commit_before>/* exported ampEditorBlocks */
/* eslint no-magic-numbers: [ "error", { "ignore": [ 1, -1, 0 ] } ] */

var ampEditorBlocks = ( function() {
	var component = {

		/**
		 * Holds data.
		 */
		data: {
			dynamicBlocks: [],
			ampLayoutOptions: [
				{ value: 'nodisplay', label: 'No Display' },
				{ value: 'fixed', label: 'Fixed' }, // Not supported by amp-audio and amp-pixel.
				{ value: 'responsive', label: 'Responsive' }, // To ensure your AMP element displays, you must specify a width and height for the containing element.
				{ value: 'fixed-height', label: 'Fixed height' },
				{ value: 'fill', label: 'Fill' },
				{ value: 'container', label: 'Container' }, // Not supported by img and video.
				{ value: 'flex-item', label: 'Flex Item' },
				{ value: 'intrinsic', label: 'Intrinsic' } // Not supported by video.
			],
			defaultWidth: 600
		}
	};

	/**
	 * Set data, add filters.
	 *
	 * @param {Array} data Data.
	 */
	component.boot = function boot( data ) {
		_.extend( component.data, data );

		wp.hooks.addFilter( 'blocks.registerBlockType', 'ampEditorBlocks/addAttributes', component.addAMPAttributes );
		wp.hooks.addFilter( 'blocks.getSaveElement', 'ampEditorBlocks/filterSave', component.filterBlocksSave );
		wp.hooks.addFilter( 'blocks.BlockEdit', 'ampEditorBlocks/filterEdit', component.filterBlocksEdit );
		wp.hooks.addFilter( 'blocks.getSaveContent.extraProps', 'ampEditorBlocks/addLayoutAttribute', component.addAMPExtraProps );
	};

	/**
	 * Get layout options depending on the block.
	 *
	 * @param {string} blockName Block name.
	 * @return {[*]} Options.
	 */
	component.getLayoutOptions = function getLayoutOptions( blockName ) {
		var layoutOptions = [
				{ value: '', label: 'None' }
			],
			embedBlocks = [
				'core-embed/youtube',
				'core-embed/facebook',
				'core-embed/instagram'
			];

		_.each( component.data.ampLayoutOptions, function( option ) {
			// Exclude options from layout that are not supported.
			if ( 'core/image' === blockName || 'core/video' === blockName || 'core-embed/twitter' === blockName ) {
				if ( 'container' === option.value ) {
					return true;
				}
			} else if ( 'core/audio' === blockName ) {
				if ( -1 !== [ 'responsive', 'fill', 'container', 'flex-item', 'intrinsic' ].indexOf( option.value ) ) {
					return true;
				}
			} else if ( -1 !== embedBlocks.indexOf( blockName ) ) {
				if ( 'container' === option.value || 'intrinsic' === option.value ) {
					return true;
				}
			} else if (
				'core-embed/vimeo' === blockName ||
				'core-embed/dailymotion' === blockName ||
				'core-embed/hulu' === blockName ||
				'core-embed/reddit' === blockName
			) {
				if ( 'container' === option.value || 'intrinsic' === option.value || 'nodisplay' === option.value ) {
					return true;
				}
			} else if ( 'core-embed/soundcloud' === blockName ) {
				if ( 'fixed-height' !== option.value ) {
					return true;
				}
			}

			layoutOptions.push( { value: option.value, label: option.label } );
		} );

		return layoutOptions;
	};

	/**
	 * Add extra data-amp-layout attribute to save to DB.
	 *
	 * @param {Object} props Properties.
	 * @param {string} blockType Block type.
	 * @param {Object} attributes Attributes.
	 * @return {*} Props.
	 */
	component.addAMPExtraProps = function addAMPExtraProps( props, blockType, attributes ) {
		var ampAttributes = {};
		if ( ! attributes.ampLayout && ! attributes.ampNoLoading ) {
			return props;
		}

		if ( attributes.ampLayout ) {
			ampAttributes[ 'data-amp-layout' ] = attributes.ampLayout;
		}
		if ( attributes.ampNoLoading ) {
			ampAttributes[ 'data-amp-noloading' ] = attributes.ampNoLoading;
		}

		return _.assign( ampAttributes, props );
	};

	/**
	 * Add AMP attributes (in this test case just ampLayout) to every core block.
	 *
	 * @param {Object} settings Settings.
	 * @param {string} name Block name.
	 * @return {*} Settings.
	 */
	component.addAMPAttributes = function addAMPAttributes( settings, name ) {
		var mediaBlocks = [
			'core/image',
			'core/video',
			'core/audio'
		];

		// Gallery settings for shortcode.
		if ( 'core/shortcode' === name ) {
			if ( ! settings.attributes ) {
				settings.attributes = {};
			}
			settings.attributes.ampCarousel = {
				type: 'boolean'
			};
		}

		// Layout settings for embeds and media blocks.
		if ( 0 === name.indexOf( 'core-embed' ) || -1 !== mediaBlocks.indexOf( name ) ) {
			if ( ! settings.attributes ) {
				settings.attributes = {};
			}
			settings.attributes.ampLayout = {
				type: 'string'
			};
			settings.attributes.ampNoLoading = {
				type: 'boolean'
			};
		}
		return settings;
	};

	/**
	 * Filters blocks edit function of all blocks.
	 *
	 * @param {Function} BlockEdit Edit function.
	 * @return {Function} Edit function.
	 */
	component.filterBlocksEdit = function filterBlocksEdit( BlockEdit ) {
		var el = wp.element.createElement;

		return function( props ) {
			var attributes = props.attributes,
				isSelected = props.isSelected,
				name = props.name,
				ampLayout,
				inspectorControls,
				width;

			ampLayout = attributes.ampLayout;

			if ( 'core/shortcode' === name ) {
				// Lets remove amp-carousel from from edit view.
				if ( component.hasGalleryShortcodeCarouselAttribute( attributes.text || '' ) ) {
					props.setAttributes( { text: component.removeAmpCarouselFromShortcodeAtts( attributes.text ) } );
				}

				inspectorControls = component.setUpShortcodeInspectorControls( props );
				if ( '' === inspectorControls ) {
					// Return original.
					return [
						el( BlockEdit, _.assign( {
							key: 'original'
						}, props ) )
					];
				}
			} else {
				inspectorControls = component.setUpInspectorControls( props );
			}

			// For editor view, add a wrapper to any tags except for embeds, these will break due to embedding logic.
			if ( ! _.isEmpty( attributes.ampLayout ) && ! isSelected && -1 === name.indexOf( 'core-embed/' ) ) {
				if ( 'fixed-height' === attributes.ampLayout ) {
					width = 'auto';
				} else {
					width = component.data.defaultWidth;
				}
				// @todo Should we try to add width and height according to the layout?

				return [
					inspectorControls,
					el( 'amp-layout',
						{ key: 'amp', 'data-amp-layout': attributes.ampLayout, width: width, height: 400, children: el( BlockEdit, _.assign( {
							key: 'original'
						}, props ) ) }
					)
				];
			}

			// Return original.
			return [
				inspectorControls,
				el( BlockEdit, _.assign( {
					key: 'original',
					'data-amp-layout': ampLayout
				}, props ) )
			];
		};
	};

	/**
	 * Default setup for inspector controls.
	 *
	 * @param {Object} props Props.
	 * @return {Object|Element|*|{$$typeof, type, key, ref, props, _owner}} Inspector Controls.
	 */
	component.setUpInspectorControls = function setUpInspectorControls( props ) {
		var ampLayout = props.attributes.ampLayout,
			ampNoLoading = props.attributes.ampNoLoading,
			isSelected = props.isSelected,
			name = props.name,
			el = wp.element.createElement,
			InspectorControls = wp.blocks.InspectorControls,
			SelectControl = wp.components.SelectControl,
			ToggleControl = wp.components.ToggleControl,
			PanelBody = wp.components.PanelBody;

		return isSelected && (
			el( InspectorControls, { key: 'inspector' },
				el( PanelBody, { title: 'AMP Settings' },
					el( SelectControl, {
						label: 'AMP Layout',
						value: ampLayout,
						options: component.getLayoutOptions( name ),
						onChange: function( value ) {
							props.setAttributes( { ampLayout: value } );
						}
					} ),
					el( ToggleControl, {
						label: 'AMP Noloading',
						checked: ampNoLoading,
						onChange: function() {
							props.setAttributes( { ampNoLoading: ! ampNoLoading } );
						}
					} )
				)
			)
		);
	};

	/**
	 * Set up inspector controls for shortcode block.
	 * Adds ampCarousel attribute in case of gallery shortcode.
	 *
	 * @param {Object} props Props.
	 * @return {*} Inspector controls.
	 */
	component.setUpShortcodeInspectorControls = function setUpShortcodeInspectorControls( props ) {
		var ampCarousel = props.attributes.ampCarousel,
			isSelected = props.isSelected,
			el = wp.element.createElement,
			InspectorControls = wp.blocks.InspectorControls,
			ToggleControl = wp.components.ToggleControl,
			PanelBody = wp.components.PanelBody,
			toggleControl;

		if ( component.isGalleryShortcode( props.attributes ) ) {
			toggleControl = el( ToggleControl, {
				label: 'Display as AMP carousel',
				checked: ampCarousel,
				onChange: function() {
					props.setAttributes( { ampCarousel: ! ampCarousel } );
				}
			} );
			return isSelected && (
				el( InspectorControls, { key: 'inspector' },
					el( PanelBody, { title: 'AMP Settings' },
						toggleControl
					)
				)
			);
		}

		return '';
	};

	/**
	 * Filters blocks save function for core blocks except for dynamic blocks.
	 *
	 * @param {Object} element Element.
	 * @param {string} blockType Block type.
	 * @param {Object} attributes Attributes.
	 * @return {*} Output element.
	 */
	component.filterBlocksSave = function filterBlocksSave( element, blockType, attributes ) {
		var text;
		if ( 'core/shortcode' === blockType.name && component.isGalleryShortcode( attributes ) ) {
			if ( attributes.ampCarousel ) {
				// If the text contains amp-carousel, lets remove it.
				if ( component.hasGalleryShortcodeCarouselAttribute( attributes.text ) ) {
					text = component.removeAmpCarouselFromShortcodeAtts( attributes.text );

					return wp.element.createElement(
						wp.element.RawHTML,
						{},
						text
					);
				}

				// Else lets return original.
				return element;
			}

			// If the text already contains amp-carousel, return original.
			if ( component.hasGalleryShortcodeCarouselAttribute( attributes.text ) ) {
				return element;
			}

			// Add amp-carousel=false attribut to the shortcode.
			text = attributes.text.replace( '[gallery', '[gallery amp-carousel=false' );

			return wp.element.createElement(
				wp.element.RawHTML,
				{},
				text
			);
		}

		return element;
	};

	/**
	 * Removes amp-carousel=false from attributes.
	 *
	 * @param {string} shortcode Shortcode text.
	 * @return {string} Modified shortcode.
	 */
	component.removeAmpCarouselFromShortcodeAtts = function removeAmpCarouselFromShortcodeAtts( shortcode ) {
		return shortcode.replace( ' amp-carousel=false', '' );
	};

	/**
	 * Check if shortcode includes amp-carousel attribute.
	 *
	 * @param {string} text Shortcode.
	 * @return {boolean} If has amp-carousel.
	 */
	component.hasGalleryShortcodeCarouselAttribute = function galleryShortcodeHasCarouselAttribute( text ) {
		return -1 !== text.indexOf( 'amp-carousel=false' );
	};

	/**
	 * Check if shortcode is gallery shortcode.
	 *
	 * @param {Object} attributes Attributes.
	 * @return {boolean} If is gallery shortcode.
	 */
	component.isGalleryShortcode = function isGalleryShortcode( attributes ) {
		return attributes.text && -1 !== attributes.text.indexOf( 'gallery' );
	};

	return component;
}() );
<commit_msg>Add possible editor changes.<commit_after>/* exported ampEditorBlocks */
/* eslint no-magic-numbers: [ "error", { "ignore": [ 1, -1, 0 ] } ] */

var ampEditorBlocks = ( function() {
	var component = {

		/**
		 * Holds data.
		 */
		data: {
			dynamicBlocks: [],
			ampLayoutOptions: [
				{ value: 'nodisplay', label: 'No Display' },
				{ value: 'fixed', label: 'Fixed' }, // Not supported by amp-audio and amp-pixel.
				{ value: 'responsive', label: 'Responsive' }, // To ensure your AMP element displays, you must specify a width and height for the containing element.
				{ value: 'fixed-height', label: 'Fixed height' },
				{ value: 'fill', label: 'Fill' },
				{ value: 'container', label: 'Container' }, // Not supported by img and video.
				{ value: 'flex-item', label: 'Flex Item' },
				{ value: 'intrinsic', label: 'Intrinsic' } // Not supported by video.
			],
			defaultWidth: 608, // Max-width in the editor.
			defaultHeight: 400
		}
	};

	/**
	 * Set data, add filters.
	 *
	 * @param {Array} data Data.
	 */
	component.boot = function boot( data ) {
		_.extend( component.data, data );

		wp.hooks.addFilter( 'blocks.registerBlockType', 'ampEditorBlocks/addAttributes', component.addAMPAttributes );
		wp.hooks.addFilter( 'blocks.getSaveElement', 'ampEditorBlocks/filterSave', component.filterBlocksSave );
		wp.hooks.addFilter( 'blocks.BlockEdit', 'ampEditorBlocks/filterEdit', component.filterBlocksEdit );
		wp.hooks.addFilter( 'blocks.getSaveContent.extraProps', 'ampEditorBlocks/addLayoutAttribute', component.addAMPExtraProps );
	};

	/**
	 * Get layout options depending on the block.
	 *
	 * @param {string} blockName Block name.
	 * @return {[*]} Options.
	 */
	component.getLayoutOptions = function getLayoutOptions( blockName ) {
		var layoutOptions = [
				{ value: '', label: 'None' }
			],
			embedBlocks = [
				'core-embed/youtube',
				'core-embed/facebook',
				'core-embed/instagram'
			];

		_.each( component.data.ampLayoutOptions, function( option ) {
			// Exclude options from layout that are not supported.
			if ( 'core/image' === blockName || 'core/video' === blockName || 'core-embed/twitter' === blockName ) {
				if ( 'container' === option.value ) {
					return true;
				}
			} else if ( 'core/audio' === blockName ) {
				if ( -1 !== [ 'responsive', 'fill', 'container', 'flex-item', 'intrinsic' ].indexOf( option.value ) ) {
					return true;
				}
			} else if ( -1 !== embedBlocks.indexOf( blockName ) ) {
				if ( 'container' === option.value || 'intrinsic' === option.value ) {
					return true;
				}
			} else if (
				'core-embed/vimeo' === blockName ||
				'core-embed/dailymotion' === blockName ||
				'core-embed/hulu' === blockName ||
				'core-embed/reddit' === blockName
			) {
				if ( 'container' === option.value || 'intrinsic' === option.value || 'nodisplay' === option.value ) {
					return true;
				}
			} else if ( 'core-embed/soundcloud' === blockName ) {
				if ( 'fixed-height' !== option.value ) {
					return true;
				}
			}

			layoutOptions.push( { value: option.value, label: option.label } );
		} );

		return layoutOptions;
	};

	/**
	 * Add extra data-amp-layout attribute to save to DB.
	 *
	 * @param {Object} props Properties.
	 * @param {string} blockType Block type.
	 * @param {Object} attributes Attributes.
	 * @return {*} Props.
	 */
	component.addAMPExtraProps = function addAMPExtraProps( props, blockType, attributes ) {
		var ampAttributes = {};
		if ( ! attributes.ampLayout && ! attributes.ampNoLoading ) {
			return props;
		}

		if ( attributes.ampLayout ) {
			ampAttributes[ 'data-amp-layout' ] = attributes.ampLayout;
		}
		if ( attributes.ampNoLoading ) {
			ampAttributes[ 'data-amp-noloading' ] = attributes.ampNoLoading;
		}

		return _.assign( ampAttributes, props );
	};

	/**
	 * Add AMP attributes (in this test case just ampLayout) to every core block.
	 *
	 * @param {Object} settings Settings.
	 * @param {string} name Block name.
	 * @return {*} Settings.
	 */
	component.addAMPAttributes = function addAMPAttributes( settings, name ) {
		var mediaBlocks = [
			'core/image',
			'core/video',
			'core/audio'
		];

		// Gallery settings for shortcode.
		if ( 'core/shortcode' === name ) {
			if ( ! settings.attributes ) {
				settings.attributes = {};
			}
			settings.attributes.ampCarousel = {
				type: 'boolean'
			};
		}

		// Layout settings for embeds and media blocks.
		if ( 0 === name.indexOf( 'core-embed' ) || -1 !== mediaBlocks.indexOf( name ) ) {
			if ( ! settings.attributes ) {
				settings.attributes = {};
			}
			settings.attributes.ampLayout = {
				type: 'string'
			};
			settings.attributes.ampNoLoading = {
				type: 'boolean'
			};
		}
		return settings;
	};

	/**
	 * Filters blocks edit function of all blocks.
	 *
	 * @param {Function} BlockEdit Edit function.
	 * @return {Function} Edit function.
	 */
	component.filterBlocksEdit = function filterBlocksEdit( BlockEdit ) {
		var el = wp.element.createElement;

		return function( props ) {
			var attributes = props.attributes,
				name = props.name,
				ampLayout,
				inspectorControls;

			ampLayout = attributes.ampLayout;

			if ( 'core/shortcode' === name ) {
				// Lets remove amp-carousel from from edit view.
				if ( component.hasGalleryShortcodeCarouselAttribute( attributes.text || '' ) ) {
					props.setAttributes( { text: component.removeAmpCarouselFromShortcodeAtts( attributes.text ) } );
				}

				inspectorControls = component.setUpShortcodeInspectorControls( props );
				if ( '' === inspectorControls ) {
					// Return original.
					return [
						el( BlockEdit, _.assign( {
							key: 'original'
						}, props ) )
					];
				}
			} else {
				inspectorControls = component.setUpInspectorControls( props );
			}

			// For editor view, add a wrapper to any tags except for embeds, these will break due to embedding logic.
			if ( attributes.ampLayout && -1 === name.indexOf( 'core-embed/' ) ) {
				if ( 'core/image' === name ) {
					component.setImageBlockLayoutAttributes( props, attributes.ampLayout, inspectorControls );
				} else if ( 'nodisplay' === attributes.ampLayout ) {
					return [
						inspectorControls
					];
				}
			}

			// Return original.
			return [
				inspectorControls,
				el( BlockEdit, _.assign( {
					key: 'original',
					'data-amp-layout': ampLayout,
					style: 'height:100px;'
				}, props ) )
			];
		};
	};

	/**
	 * Set width and height in case of image block.
	 *
	 * @param {Object} props Props.
	 * @param {string} layout Layout.
	 * @param {Object} inspectorControls Inspector controls.
	 * @return {[*]} Void or block edit element.
	 */
	component.setImageBlockLayoutAttributes = function setImageBlockLayoutAttributes( props, layout, inspectorControls ) {
		var attributes = props.attributes;
		switch ( layout ) {
			case 'fixed-height':
			case 'responsive':
				props.setAttributes( { width: '' } );
				if ( ! attributes.height ) {
					props.setAttributes( { height: component.data.defaultHeight } );
				}
				break;

			case 'fixed':
				if ( ! attributes.height ) {
					props.setAttributes( { height: component.data.defaultHeight } );
				}
				if ( ! attributes.width ) {
					props.setAttributes( { width: component.data.defaultWidth } );
				}
				break;

			case 'fill':
				props.setAttributes( { height: component.data.defaultHeight } );
				props.setAttributes( { width: component.data.defaultWidth } );
				break;

			case 'nodisplay':
				return [
					inspectorControls
				];
		}
	};

	/**
	 * Default setup for inspector controls.
	 *
	 * @param {Object} props Props.
	 * @return {Object|Element|*|{$$typeof, type, key, ref, props, _owner}} Inspector Controls.
	 */
	component.setUpInspectorControls = function setUpInspectorControls( props ) {
		var ampLayout = props.attributes.ampLayout,
			ampNoLoading = props.attributes.ampNoLoading,
			isSelected = props.isSelected,
			name = props.name,
			el = wp.element.createElement,
			InspectorControls = wp.blocks.InspectorControls,
			SelectControl = wp.components.SelectControl,
			ToggleControl = wp.components.ToggleControl,
			PanelBody = wp.components.PanelBody,
			label = 'AMP Layout';

		if ( 'core/image' === name ) {
			label = 'AMP Layout (modifies width/height)';
		}

		return isSelected && (
			el( InspectorControls, { key: 'inspector' },
				el( PanelBody, { title: 'AMP Settings' },
					el( SelectControl, {
						label: label,
						value: ampLayout,
						options: component.getLayoutOptions( name ),
						onChange: function( value ) {
							props.setAttributes( { ampLayout: value } );
						}
					} ),
					el( ToggleControl, {
						label: 'AMP Noloading',
						checked: ampNoLoading,
						onChange: function() {
							props.setAttributes( { ampNoLoading: ! ampNoLoading } );
						}
					} )
				)
			)
		);
	};

	/**
	 * Set up inspector controls for shortcode block.
	 * Adds ampCarousel attribute in case of gallery shortcode.
	 *
	 * @param {Object} props Props.
	 * @return {*} Inspector controls.
	 */
	component.setUpShortcodeInspectorControls = function setUpShortcodeInspectorControls( props ) {
		var ampCarousel = props.attributes.ampCarousel,
			isSelected = props.isSelected,
			el = wp.element.createElement,
			InspectorControls = wp.blocks.InspectorControls,
			ToggleControl = wp.components.ToggleControl,
			PanelBody = wp.components.PanelBody,
			toggleControl;

		if ( component.isGalleryShortcode( props.attributes ) ) {
			toggleControl = el( ToggleControl, {
				label: 'Display as AMP carousel',
				checked: ampCarousel,
				onChange: function() {
					props.setAttributes( { ampCarousel: ! ampCarousel } );
				}
			} );
			return isSelected && (
				el( InspectorControls, { key: 'inspector' },
					el( PanelBody, { title: 'AMP Settings' },
						toggleControl
					)
				)
			);
		}

		return '';
	};

	/**
	 * Filters blocks' save function.
	 *
	 * @param {Object} element Element.
	 * @param {string} blockType Block type.
	 * @param {Object} attributes Attributes.
	 * @return {*} Output element.
	 */
	component.filterBlocksSave = function filterBlocksSave( element, blockType, attributes ) {
		var text;
		if ( 'core/shortcode' === blockType.name && component.isGalleryShortcode( attributes ) ) {
			if ( attributes.ampCarousel ) {
				// If the text contains amp-carousel, lets remove it.
				if ( component.hasGalleryShortcodeCarouselAttribute( attributes.text || '' ) ) {
					text = component.removeAmpCarouselFromShortcodeAtts( attributes.text );

					return wp.element.createElement(
						wp.element.RawHTML,
						{},
						text
					);
				}

				// Else lets return original.
				return element;
			}

			// If the text already contains amp-carousel, return original.
			if ( component.hasGalleryShortcodeCarouselAttribute( attributes.text || '' ) ) {
				return element;
			}

			// Add amp-carousel=false attribut to the shortcode.
			text = attributes.text.replace( '[gallery', '[gallery amp-carousel=false' );

			return wp.element.createElement(
				wp.element.RawHTML,
				{},
				text
			);
		}

		return element;
	};

	/**
	 * Removes amp-carousel=false from attributes.
	 *
	 * @param {string} shortcode Shortcode text.
	 * @return {string} Modified shortcode.
	 */
	component.removeAmpCarouselFromShortcodeAtts = function removeAmpCarouselFromShortcodeAtts( shortcode ) {
		return shortcode.replace( ' amp-carousel=false', '' );
	};

	/**
	 * Check if shortcode includes amp-carousel attribute.
	 *
	 * @param {string} text Shortcode.
	 * @return {boolean} If has amp-carousel.
	 */
	component.hasGalleryShortcodeCarouselAttribute = function galleryShortcodeHasCarouselAttribute( text ) {
		return -1 !== text.indexOf( 'amp-carousel=false' );
	};

	/**
	 * Check if shortcode is gallery shortcode.
	 *
	 * @param {Object} attributes Attributes.
	 * @return {boolean} If is gallery shortcode.
	 */
	component.isGalleryShortcode = function isGalleryShortcode( attributes ) {
		return attributes.text && -1 !== attributes.text.indexOf( 'gallery' );
	};

	return component;
}() );
<|endoftext|>


<commit_before>var
  Surrogate = require(".."),
  surrogate = new Surrogate({
    port: 1337,
    ip: "0.0.0.0",
    verbose: false,
    initialState: {
      birthday: null
    }
  });

surrogate.addJsonRoute({
  name: "set-info",
  method: "POST",
  path: "/api/person",
  handlers: {
    "set-person-success": {
      description: "Save the prson info",
      handler: function (request) {
        this.state.birthday = request.payload.birthday;
        this.cookies.hasBirthday = true;
        return { status: "OK" };
      }
    }
  }
});

surrogate.addHtmlRoute({
  name: "get-info",
  method: "GET",
  path: "/api/person",
  handlers: {
    "get-person-success": {
      description: "Return info about the person.",
      handler: function (request, selectedOption) {
        var
          name = request.query.name || "Tommy Joe",
          birthday = this.state.birthday ?
            "has a birthday on " + this.state.birthday + "." :
            "has no birthday.";

        return selectedOption(name + " " + birthday);
      },
      optionHelperText: "What should birthday info be wrapped in?",
      optionsType: "selectOne",
      options: {
        "wrap in body": function (str) {
          return "" + str + "";
        },
        "wrap in html": function (str) {
          return "" + str + "";
        }
      }
    },
    "get-person-error": {
      description: "Return an error instead of the person's info.",
      handler: function (request) {
        throw new Surrogate.HttpErr({
          code: 401,
          payload: "can't do that right now..."
        });
      }
    }
  }
});

surrogate.addHapiRoute({
  name: "restart"
  method: "POST",
  path: "/surrogate/api/restart",
  handler: function (request, reply) {
    surrogate.restart(function () {
      reply("OK")
        .type("text/plain")
        .code(200);
    });
  }
});

surrogate.start();
<commit_msg>update example<commit_after>var
  Surrogate = require(".."),
  surrogate = new Surrogate({
    port: 1337,
    ip: "0.0.0.0",
    verbose: false,
    initialState: {
      birthday: null
    }
  });

surrogate.jsonRoute({
  name: "set-info",
  method: "POST",
  path: "/api/person",
  handlers: {
    "set-person-success": {
      description: "Save the prson info",
      handler: function (request) {
        this.state.birthday = request.payload.birthday;
        this.cookies.hasBirthday = true;
        return { status: "OK" };
      }
    }
  }
});

surrogate.htmlRoute({
  name: "get-info",
  method: "GET",
  path: "/api/person",
  handlers: {
    "get-person-success": {
      description: "Return info about the person.",
      handler: function (request, selectedOption) {
        var
          name = request.query.name || "Tommy Joe",
          birthday = this.state.birthday ?
            "has a birthday on " + this.state.birthday + "." :
            "has no birthday.";

        return selectedOption(name + " " + birthday);
      },
      optionsHelperText: "What should birthday info be wrapped in?",
      optionsType: "selectOne",
      options: {
        "wrap in body": function (str) {
          return "" + str + "";
        },
        "wrap in html": function (str) {
          return "" + str + "";
        }
      }
    },
    "get-person-error": {
      description: "Return an error instead of the person's info.",
      handler: function (request) {
        throw new Surrogate.HttpErr({
          code: 401,
          payload: "can't do that right now..."
        });
      }
    }
  }
});

surrogate.hapiRoute({
  name: "restart"
  method: "POST",
  path: "/surrogate/api/restart",
  handler: function (request, reply) {
    surrogate.restart(function () {
      reply("OK")
        .type("text/plain")
        .code(200);
    });
  }
});

surrogate.start();
<|endoftext|>


<commit_before>import { mapState, mapGetters } from 'vuex';
import CoreBase from 'kolibri.coreVue.components.CoreBase';
import CoreTable from 'kolibri.coreVue.components.CoreTable';
import { ContentNodeKinds, CollectionKinds } from 'kolibri.coreVue.vuex.constants';
import router from 'kolibri.coreVue.router';
import ContentIcon from 'kolibri.coreVue.components.ContentIcon';
import meanBy from 'lodash/meanBy';
import maxBy from 'lodash/maxBy';
import find from 'lodash/find';
import map from 'lodash/map';
import ElapsedTime from 'kolibri.coreVue.components.ElapsedTime';
import filter from 'lodash/filter';
import get from 'lodash/get';
import orderBy from 'lodash/orderBy';
import { PageNames } from '../constants';
import { LastPages } from '../constants/lastPagesConstants';
import { STATUSES } from '../modules/classSummary/constants';
import TopNavbar from './TopNavbar';
import { coachStrings, coachStringsMixin } from './common/commonCoachStrings';
import Answer from './common/Answer';
import AverageScoreTooltip from './common/AverageScoreTooltip';
import BackLink from './common/BackLink';
import TruncatedItemList from './common/TruncatedItemList';
import LessonActive from './common/LessonActive';
import LessonStatus from './common/LessonStatus';
import MasteryModel from './common/MasteryModel';
import Recipients from './common/Recipients';
import Score from './common/Score';
import TimeDuration from './common/TimeDuration';
import QuizActive from './common/QuizActive';
import QuizLessonDetailsHeader from './common/QuizLessonDetailsHeader';
import QuizStatus from './common/QuizStatus';
import HeaderTable from './common/HeaderTable';
import HeaderTableRow from './common/HeaderTable/HeaderTableRow';
import HeaderTabs from './common/HeaderTabs';
import HeaderTab from './common/HeaderTabs/HeaderTab';
import StatusSummary from './common/status/StatusSummary';
import StatusSimple from './common/status/StatusSimple';
import HelpNeeded from './common/status/HelpNeeded';
import Placeholder from './common/Placeholder';
import StatusElapsedTime from './common/StatusElapsedTime';
import { VERBS, ICONS } from './common/status/constants';

function formatPageTitle() {
  // To get a page title, each coach route should have
  // meta.titleParts defined, which is an array of coachStrings tr keys
  // or special all-caps strings that get mapped to names.
  const parts = this.$route.meta.titleParts || [];
  const classSummary = this.$store.state.classSummary;
  const { params } = this.$route;

  let strings = parts.map(part => {
    try {
      switch (part) {
        case 'GROUP_NAME':
          return classSummary.groupMap[params.groupId].name;
        case 'CLASS_NAME':
          return classSummary.name;
        case 'LEARNER_NAME':
          return classSummary.learnerMap[params.learnerId].name;
        case 'LESSON_NAME':
          return classSummary.lessonMap[params.lessonId].title;
        case 'QUIZ_NAME':
          return classSummary.examMap[params.quizId].title;
        case 'EXERCISE_NAME':
          return classSummary.contentMap[params.exerciseId].title;
        case 'RESOURCE_NAME':
          return classSummary.contentMap[params.resourceId].title;
        default:
          return coachStrings.$tr(part);
      }
    } catch (err) {
      // TODO - make this error handling cleaner
      return '';
    }
  });

  if (this.isRtl) {
    strings = strings.reverse();
  }
  return strings.join(' - ');
}

export const CoachCoreBase = {
  extends: CoreBase,
  mixins: [coachStringsMixin],
  props: {
    // Gives each Coach page a default title of 'Coach – [Class Name]'
    appBarTitle: {
      type: String,
      default() {
        let facilityName;
        // Using coachStrings.$tr() here because mixins are not applied
        // prior to props being processed.
        const { facility_id, name } = this.$store.state.classSummary;
        if (
          facility_id &&
          this.$store.state.core.facilities.length > 1 &&
          this.$store.getters.isSuperuser
        ) {
          const match = find(this.$store.state.core.facilities, { id: facility_id }) || {};
          facilityName = match.name;
        }
        if (facilityName && name) {
          return coachStrings.$tr('coachLabelWithOneTwoNames', {
            name1: facilityName,
            name2: name,
          });
        } else if (name) {
          return coachStrings.$tr('coachLabelWithOneName', { name });
        } else {
          return coachStrings.$tr('coachLabel');
        }
      },
    },
    pageTitle: {
      type: String,
      default() {
        return formatPageTitle.call(this);
      },
    },
  },
};

export default {
  components: {
    CoreBase: CoachCoreBase,
    CoreTable,
    ContentIcon,
    TopNavbar,
    Answer,
    AverageScoreTooltip,
    BackLink,
    TruncatedItemList,
    LessonActive,
    LessonStatus,
    MasteryModel,
    Recipients,
    Score,
    TimeDuration,
    QuizActive,
    QuizLessonDetailsHeader,
    QuizStatus,
    HeaderTable,
    ElapsedTime,
    HeaderTableRow,
    HeaderTabs,
    HeaderTab,
    StatusSummary,
    StatusSimple,
    HelpNeeded,
    Placeholder,
    StatusElapsedTime,
  },
  mixins: [coachStringsMixin],
  computed: {
    ...mapGetters(['isAdmin', 'isCoach', 'isSuperuser']),
    ...mapState('classSummary', { classId: 'id', className: 'name' }),
    ...mapState('classSummary', [
      'adHocGroupsMap',
      'coachMap',
      'learnerMap',
      'groupMap',
      'examMap',
      'examLearnerStatusMap',
      'contentMap',
      'contentNodeMap',
      'contentLearnerStatusMap',
      'lessonMap',
    ]),
    ...mapGetters('classSummary', [
      'coaches',
      'learners',
      'groups',
      'exams',
      'examStatuses',
      'content',
      'contentStatuses',
      'adHocGroups',
      'lessons',
      'lessonStatuses',
      'lessonLearnerStatusMap',
      'notificationModuleData',
      'getGroupNames',
      'getGroupNamesForLearner',
      'getAdHocLearners',
      'getLearnersForGroups',
      'getLearnersForExam',
      'getLearnersForLesson',
      'getRecipientNamesForExam',
      'getRecipientNamesForLesson',
      'getContentStatusObjForLearner',
      'getContentStatusTally',
      'getExamStatusObjForLearner',
      'getExamStatusTally',
      'getLessonStatusStringForLearner',
      'getLessonStatusTally',
      'getContentAvgTimeSpent',
      'getExamAvgScore',
    ]),
    userIsAuthorized() {
      if (this.isSuperuser) {
        return true;
      }
      if (this.$route.name === 'CoachClassListPage') {
        return this.isCoach || this.isAdmin;
      }
      return this.$store.getters.userIsAuthorizedForCoach;
    },
    PageNames() {
      return PageNames;
    },
    ContentNodeKinds() {
      return ContentNodeKinds;
    },
    CollectionKinds() {
      return CollectionKinds;
    },
    VERBS() {
      return VERBS;
    },
    ICONS() {
      return ICONS;
    },
    STATUSES() {
      return STATUSES;
    },
    _() {
      return {
        maxBy,
        meanBy,
        orderBy,
        map,
        filter,
      };
    },
  },
  methods: {
    // This is a safer way to get the content kind to quickly patch #6552
    contentIdIsForExercise(contentId) {
      return get(this.contentMap, [contentId, 'kind']) === 'exercise';
    },
    classRoute(name, params = {}, query = {}) {
      if (this.classId) {
        params.classId = this.classId;
      }
      return router.getRoute(name, params, query);
    },
    // Set the backLinkQuery to set the correct exit behavior
    // for ReportsLessonExerciseLearnerPage and ReportsQuizLearnerPage.
    backRouteForQuery(query) {
      const lastPage = query.last;

      switch (lastPage) {
        case LastPages.HOME_PAGE:
          return this.classRoute('HomePage', {});
        case LastPages.HOME_ACTIVITY:
          return this.classRoute('HomeActivityPage', {});
        case LastPages.GROUP_ACTIVITY:
          return this.classRoute('ReportsGroupActivityPage', {
            groupId: this.$route.query.last_id,
          });
        case LastPages.LEARNER_ACTIVITY:
          return this.classRoute('ReportsLearnerActivityPage', {
            learnerId: this.$route.query.last_id,
          });
        case LastPages.EXERCISE_LEARNER_LIST:
          return this.classRoute('ReportsLessonExerciseLearnerListPage', {
            exerciseId: this.$route.query.exerciseId,
          });
        case LastPages.EXERCISE_LEARNER_LIST_BY_GROUPS:
          return this.classRoute(
            'ReportsLessonExerciseLearnerListPage',
            {
              exerciseId: this.$route.query.exerciseId,
            },
            {
              groups: 'true',
            }
          );
        case LastPages.EXERCISE_QUESTION_LIST:
          return this.classRoute('ReportsLessonExerciseQuestionListPage', {
            exerciseId: this.$route.query.exerciseId,
          });
        case LastPages.RESOURCE_LEARNER_LIST:
          return this.classRoute('ReportsLessonResourceLearnerListPage', {
            resourceId: this.$route.query.resourceId,
          });
        case LastPages.RESOURCE_LEARNER_LIST_BY_GROUPS:
          return this.classRoute(
            'ReportsLessonResourceLearnerListPage',
            {
              resourceId: this.$route.query.resourceId,
            },
            {
              groups: 'true',
            }
          );
        default:
          return null;
      }
    },
    /**
     * @param {Object[]} statuses
     * @param {Date|null} statuses[].last_activity
     * @return {Date|null}
     */
    maxLastActivity(statuses) {
      const max = this._.maxBy(statuses, 'last_activity');
      return max && max.last_activity ? max.last_activity : null;
    },
  },
};
<commit_msg>remove ref to Answer component - removed in a recent commit<commit_after>import { mapState, mapGetters } from 'vuex';
import CoreBase from 'kolibri.coreVue.components.CoreBase';
import CoreTable from 'kolibri.coreVue.components.CoreTable';
import { ContentNodeKinds, CollectionKinds } from 'kolibri.coreVue.vuex.constants';
import router from 'kolibri.coreVue.router';
import ContentIcon from 'kolibri.coreVue.components.ContentIcon';
import meanBy from 'lodash/meanBy';
import maxBy from 'lodash/maxBy';
import find from 'lodash/find';
import map from 'lodash/map';
import ElapsedTime from 'kolibri.coreVue.components.ElapsedTime';
import filter from 'lodash/filter';
import get from 'lodash/get';
import orderBy from 'lodash/orderBy';
import { PageNames } from '../constants';
import { LastPages } from '../constants/lastPagesConstants';
import { STATUSES } from '../modules/classSummary/constants';
import TopNavbar from './TopNavbar';
import { coachStrings, coachStringsMixin } from './common/commonCoachStrings';
import AverageScoreTooltip from './common/AverageScoreTooltip';
import BackLink from './common/BackLink';
import TruncatedItemList from './common/TruncatedItemList';
import LessonActive from './common/LessonActive';
import LessonStatus from './common/LessonStatus';
import MasteryModel from './common/MasteryModel';
import Recipients from './common/Recipients';
import Score from './common/Score';
import TimeDuration from './common/TimeDuration';
import QuizActive from './common/QuizActive';
import QuizLessonDetailsHeader from './common/QuizLessonDetailsHeader';
import QuizStatus from './common/QuizStatus';
import HeaderTable from './common/HeaderTable';
import HeaderTableRow from './common/HeaderTable/HeaderTableRow';
import HeaderTabs from './common/HeaderTabs';
import HeaderTab from './common/HeaderTabs/HeaderTab';
import StatusSummary from './common/status/StatusSummary';
import StatusSimple from './common/status/StatusSimple';
import HelpNeeded from './common/status/HelpNeeded';
import Placeholder from './common/Placeholder';
import StatusElapsedTime from './common/StatusElapsedTime';
import { VERBS, ICONS } from './common/status/constants';

function formatPageTitle() {
  // To get a page title, each coach route should have
  // meta.titleParts defined, which is an array of coachStrings tr keys
  // or special all-caps strings that get mapped to names.
  const parts = this.$route.meta.titleParts || [];
  const classSummary = this.$store.state.classSummary;
  const { params } = this.$route;

  let strings = parts.map(part => {
    try {
      switch (part) {
        case 'GROUP_NAME':
          return classSummary.groupMap[params.groupId].name;
        case 'CLASS_NAME':
          return classSummary.name;
        case 'LEARNER_NAME':
          return classSummary.learnerMap[params.learnerId].name;
        case 'LESSON_NAME':
          return classSummary.lessonMap[params.lessonId].title;
        case 'QUIZ_NAME':
          return classSummary.examMap[params.quizId].title;
        case 'EXERCISE_NAME':
          return classSummary.contentMap[params.exerciseId].title;
        case 'RESOURCE_NAME':
          return classSummary.contentMap[params.resourceId].title;
        default:
          return coachStrings.$tr(part);
      }
    } catch (err) {
      // TODO - make this error handling cleaner
      return '';
    }
  });

  if (this.isRtl) {
    strings = strings.reverse();
  }
  return strings.join(' - ');
}

export const CoachCoreBase = {
  extends: CoreBase,
  mixins: [coachStringsMixin],
  props: {
    // Gives each Coach page a default title of 'Coach – [Class Name]'
    appBarTitle: {
      type: String,
      default() {
        let facilityName;
        // Using coachStrings.$tr() here because mixins are not applied
        // prior to props being processed.
        const { facility_id, name } = this.$store.state.classSummary;
        if (
          facility_id &&
          this.$store.state.core.facilities.length > 1 &&
          this.$store.getters.isSuperuser
        ) {
          const match = find(this.$store.state.core.facilities, { id: facility_id }) || {};
          facilityName = match.name;
        }
        if (facilityName && name) {
          return coachStrings.$tr('coachLabelWithOneTwoNames', {
            name1: facilityName,
            name2: name,
          });
        } else if (name) {
          return coachStrings.$tr('coachLabelWithOneName', { name });
        } else {
          return coachStrings.$tr('coachLabel');
        }
      },
    },
    pageTitle: {
      type: String,
      default() {
        return formatPageTitle.call(this);
      },
    },
  },
};

export default {
  components: {
    CoreBase: CoachCoreBase,
    CoreTable,
    ContentIcon,
    TopNavbar,
    AverageScoreTooltip,
    BackLink,
    TruncatedItemList,
    LessonActive,
    LessonStatus,
    MasteryModel,
    Recipients,
    Score,
    TimeDuration,
    QuizActive,
    QuizLessonDetailsHeader,
    QuizStatus,
    HeaderTable,
    ElapsedTime,
    HeaderTableRow,
    HeaderTabs,
    HeaderTab,
    StatusSummary,
    StatusSimple,
    HelpNeeded,
    Placeholder,
    StatusElapsedTime,
  },
  mixins: [coachStringsMixin],
  computed: {
    ...mapGetters(['isAdmin', 'isCoach', 'isSuperuser']),
    ...mapState('classSummary', { classId: 'id', className: 'name' }),
    ...mapState('classSummary', [
      'adHocGroupsMap',
      'coachMap',
      'learnerMap',
      'groupMap',
      'examMap',
      'examLearnerStatusMap',
      'contentMap',
      'contentNodeMap',
      'contentLearnerStatusMap',
      'lessonMap',
    ]),
    ...mapGetters('classSummary', [
      'coaches',
      'learners',
      'groups',
      'exams',
      'examStatuses',
      'content',
      'contentStatuses',
      'adHocGroups',
      'lessons',
      'lessonStatuses',
      'lessonLearnerStatusMap',
      'notificationModuleData',
      'getGroupNames',
      'getGroupNamesForLearner',
      'getAdHocLearners',
      'getLearnersForGroups',
      'getLearnersForExam',
      'getLearnersForLesson',
      'getRecipientNamesForExam',
      'getRecipientNamesForLesson',
      'getContentStatusObjForLearner',
      'getContentStatusTally',
      'getExamStatusObjForLearner',
      'getExamStatusTally',
      'getLessonStatusStringForLearner',
      'getLessonStatusTally',
      'getContentAvgTimeSpent',
      'getExamAvgScore',
    ]),
    userIsAuthorized() {
      if (this.isSuperuser) {
        return true;
      }
      if (this.$route.name === 'CoachClassListPage') {
        return this.isCoach || this.isAdmin;
      }
      return this.$store.getters.userIsAuthorizedForCoach;
    },
    PageNames() {
      return PageNames;
    },
    ContentNodeKinds() {
      return ContentNodeKinds;
    },
    CollectionKinds() {
      return CollectionKinds;
    },
    VERBS() {
      return VERBS;
    },
    ICONS() {
      return ICONS;
    },
    STATUSES() {
      return STATUSES;
    },
    _() {
      return {
        maxBy,
        meanBy,
        orderBy,
        map,
        filter,
      };
    },
  },
  methods: {
    // This is a safer way to get the content kind to quickly patch #6552
    contentIdIsForExercise(contentId) {
      return get(this.contentMap, [contentId, 'kind']) === 'exercise';
    },
    classRoute(name, params = {}, query = {}) {
      if (this.classId) {
        params.classId = this.classId;
      }
      return router.getRoute(name, params, query);
    },
    // Set the backLinkQuery to set the correct exit behavior
    // for ReportsLessonExerciseLearnerPage and ReportsQuizLearnerPage.
    backRouteForQuery(query) {
      const lastPage = query.last;

      switch (lastPage) {
        case LastPages.HOME_PAGE:
          return this.classRoute('HomePage', {});
        case LastPages.HOME_ACTIVITY:
          return this.classRoute('HomeActivityPage', {});
        case LastPages.GROUP_ACTIVITY:
          return this.classRoute('ReportsGroupActivityPage', {
            groupId: this.$route.query.last_id,
          });
        case LastPages.LEARNER_ACTIVITY:
          return this.classRoute('ReportsLearnerActivityPage', {
            learnerId: this.$route.query.last_id,
          });
        case LastPages.EXERCISE_LEARNER_LIST:
          return this.classRoute('ReportsLessonExerciseLearnerListPage', {
            exerciseId: this.$route.query.exerciseId,
          });
        case LastPages.EXERCISE_LEARNER_LIST_BY_GROUPS:
          return this.classRoute(
            'ReportsLessonExerciseLearnerListPage',
            {
              exerciseId: this.$route.query.exerciseId,
            },
            {
              groups: 'true',
            }
          );
        case LastPages.EXERCISE_QUESTION_LIST:
          return this.classRoute('ReportsLessonExerciseQuestionListPage', {
            exerciseId: this.$route.query.exerciseId,
          });
        case LastPages.RESOURCE_LEARNER_LIST:
          return this.classRoute('ReportsLessonResourceLearnerListPage', {
            resourceId: this.$route.query.resourceId,
          });
        case LastPages.RESOURCE_LEARNER_LIST_BY_GROUPS:
          return this.classRoute(
            'ReportsLessonResourceLearnerListPage',
            {
              resourceId: this.$route.query.resourceId,
            },
            {
              groups: 'true',
            }
          );
        default:
          return null;
      }
    },
    /**
     * @param {Object[]} statuses
     * @param {Date|null} statuses[].last_activity
     * @return {Date|null}
     */
    maxLastActivity(statuses) {
      const max = this._.maxBy(statuses, 'last_activity');
      return max && max.last_activity ? max.last_activity : null;
    },
  },
};
<|endoftext|>


<commit_before>/*
 * grunt-serve
 * https://github.com/lud2k/grunt-serve
 *
 * Copyright (c) 2014 Ludovic Cabre
 * Licensed under the MIT license.
 */

'use strict';

// requires
var connect = require('connect'),
	http = require('http'),
	childProcess = require("child_process"),
	fs = require('fs'),
	dot = require('dot'),
	paths = require('path'),
	contentTypes = require('../data/content_types.js');

// load all template files
var loadTemplate = function(name) {
		return dot.template(fs.readFileSync(paths.join(__dirname, '..', 'pages', name)))
	},
	indexTmpl = loadTemplate('index.html'),
	notFoundTmpl = loadTemplate('not_found.html'),
	directoryTmpl = loadTemplate('directory.html'),
	errorTmpl = loadTemplate('error.html'),
	successTmpl = loadTemplate('success.html'),
	gruntErrorTmpl = loadTemplate('grunt_error.html'),
	missingTmpl = loadTemplate('missing.html'),
	unauthTmpl = loadTemplate('unauthorized.html');

/**
 * Definition of the exported method that will be called by Grunt on initialization.
 */
module.exports = function(grunt) {
	// register serve task
	grunt.registerTask('serve', 'Starts a http server that can be called to run tasks.', function() {
		// control when the task should end
	    var done = this.async();

		// get options
		var options = this.options({
			port: 9000,
			silently: false,
			serve: {
				path: process.cwd()
			}
		});

		// start an HTTP server
		http.createServer(function(request, response) {
			try {
				var cert = fs.readFileSync('public.pem');
				jwt.verify(token,cert,{algorithms: ['RS256']}, function(err, payload){
					if(err){
						err = {
							name: 'JsonWebTokenError',
							message: 'invalid signature'
						}
						render(response, 401, unauthTmpl);
						jwt.forget();
					} else{
						// forward request
					handleRequest(request, response, grunt, options);
					}
				})
			} catch(e) {
				// show error
			    render(response, 500, errorTmpl, {
			    	error: 'Unexpected JavaScript exception "'+e+'"
'+(e && e.stack ? e.stack.replace(/\n+/g, '
') : '')
			    });
			}
		}).listen(options.port);

		// handle SIGINT signal properly
		process.on('SIGINT', function() {
			// terminate task
		    done();
		});

    	// a few messages
        grunt.log.write('Server is running on port '+options.port+'...\n');
        grunt.log.write('Press CTRL+C at any time to terminate it.\n');
	});
}

/**
 * Handles all requests to the server.
 * Each call with trigger a call to the following function.
 */
function handleRequest(request, response, grunt, options) {
	// get url from request
	var url = require('url').parse(request.url),
		path = unescape(url.pathname);

	// main page request?
	if (path == '/') {
		render(response, 200, indexTmpl, {
	    	host: request.headers.host,
	    	aliases: mapToArray(options.aliases, 'name'),
	    	files: filesInDirectory(grunt, options, '.')
	    });
		return;
	}

	// is this url for /task/?
	if (path.substr(0, 6) == '/task/') {
		// get parameters
		var match = /\/task\/([^\/]+)(\/(.+))?/.exec(path);
		if (match) {
			var tasks = match[1].split(','),
				output = match[3];

			// run tasks
			executeTasks(request, response, grunt, options, tasks, output, null);
			return;
		}
	}

	// is this url contains virtual root? If so, remove it
	if (options.virtualRoot) {
		if (path.indexOf(options.virtualRoot) === 0) {
			path = path.substr(options.virtualRoot.length);
		}
	}

	// does this path match an alias?
	var aliasName = path.substr(1);
	var aliases = options.aliases;
	if (aliases && aliases[aliasName]) {
		// get alias configuration
		var tasks = aliases[aliasName].tasks,
			output = aliases[aliasName].output,
			contentType = aliases[aliasName].contentType;

		if (!tasks) throw "No tasks were defined for alias: "+aliasName;

		// run tasks
		executeTasks(request, response, grunt, options, tasks, output, contentType);
		return;
	}

	// is this path a file?
	var file = paths.join(options.serve.path, path.substr(1));
    if (grunt.file.exists(file)) {
    	var stats = fs.statSync(file);
    	if (stats.isDirectory()) {
    		// show directory content
    		render(response, 200, directoryTmpl, {
    	    	files: filesInDirectory(grunt, options, path.substr(1))
    	    });

    	} else {
    		// return file
    		write(response, 200, grunt, file);
    	}
    } else {
    	render(response, 404, notFoundTmpl);
    }
}

/**
 * Runs Grunt to execute the given tasks.
 */
function executeTasks(request, response, grunt, options, tasks, output, contentType) {
	// execute tasks
	childProcess.exec('grunt '+tasks.join(' '), function(error, stdout, stderr) {
		try {
			// should we print the stdout?
			if (!options.silently) {
				// print stdout
				console.log(stdout);

				// print stderr (if any)
				if (stderr) {
					console.log(stderr);
				}
			}

			// any error? write logs and return
			if (stderr || error) {
			    render(response, 500, gruntErrorTmpl, {
			    	tasks: tasks,
			    	stdout: formatStdout(stdout),
			    	stderr: formatStdout(stderr)
			    });
				return;
			}

		    // the the output stdout?
		    if (output == 'stdout' || !output) {
			    // write stdout
		    	render(response, 200, successTmpl, {
		    		output: formatStdout(stdout)
		    	});

		    } else {
		    	// requested output file exists?
				if (grunt.file.exists(output)) {
					// write file
		    		write(response, 200, grunt, output, contentType);
				} else {
					// show file not found
				    render(response, 500, missingTmpl, {
				    	output: output
				    });
				}
		    }
		} catch(e) {
			// show error
		    render(response, 500, errorTmpl, {
		    	error: 'Unexpected JavaScript exception "'+e+'"
'+(e && e.stack ? e.stack.replace(/\n+/g, '
') : '')
		    });
		}
	});
}

/**
 * Renders an html page and ends the request.
 */
function render(response, code, template, data) {
	var html = template(data);
	if (!response.headersSent) {
	    response.writeHead(code, {"Content-Type": "text/html"});
	}
    response.end(html);
}

/**
 * Writes a file's content to the output and ends the request.
 */
function write(response, code, grunt, file, contentType) {
	var data = fs.readFileSync(file);
	if (!response.headersSent) {
	    response.writeHead(200, headersForOutput(file, contentType));
	}
	response.end(data);
}

/**
 * Converts a map to an array adding the key to the value.
 */
function mapToArray(map, name) {
	var ret = [];
	for (var key in map) {
		map[key][name] = key;
		ret.push(map[key]);
	}
	return ret;
}

/**
 * Returns the list of files in the given directory.
 */
function filesInDirectory(grunt, options, path) {
	var ret = [],
		fullPath = paths.join(options.serve.path, path),
		files = fs.readdirSync(fullPath);

	// for each file
	for (var i=0; i<files.length; i++) {
		var file = files[i],
			stats = fs.statSync(paths.join(fullPath, file)),
			isDir = stats.isDirectory();

		// skip ., .. and hidden files
		if (file.charAt(0) == '.') continue;

		ret.push({
			path: path ? path + '/' + file : file,
			name: file,
			isDir: isDir
		});
	}

	return ret;
}

/**
 * Returns the headers that fits the best the output.
 * Will also add headers to prevent caching.
 */
function headersForOutput(path, contentType) {
	// disable caching
	var ret = {
		'Cache-Control': 'no-cache, no-store, must-revalidate',
		'Pragma': 'no-cache',
		'Expires': '0'
	}

	// try to auto detect the content type
	if (!contentType) {
		contentType = contentTypes(path);
		if (contentType) {
			ret['Content-Type'] = contentType;
		}
	}

	return ret;
}

/**
 * Converts Grunt's stdout into html.
 * (keeping the colors the same)
 */
function formatStdout(stdout) {
	var regex = /\x1B\[(\d+)m/g,
		opened = false,
		colors = {
			'0': '#000000',
			'30': '#000000',
			'31': '#CC0000',
			'32': '#00CC00',
			'33': '#CCCC00',
			'34': '#00CC00',
			'35': '#CC00CC',
			'36': '#00CCCC',
			'37': '#999999'
		},
		match;

	// replace all colors markers by html
	while ((match = regex.exec(stdout))) {
		var code = match[1]+'',
			start = stdout.substr(0, match.index),
			end = stdout.substr(match.index+3+code.length);

		if (code) {
			var colorEnd = opened ? '' : '',
				colorStart = '';
			stdout = start + colorEnd + colorStart + end;

		} else {
			stdout = start + end;
		}

		opened = true;
	}

	// replace all line return by the html equivalent
	return stdout.replace(/\n+/g, '
');
}
<commit_msg>read token<commit_after>/*
 * grunt-serve
 * https://github.com/lud2k/grunt-serve
 *
 * Copyright (c) 2014 Ludovic Cabre
 * Licensed under the MIT license.
 */

'use strict';

// requires
var connect = require('connect'),
	http = require('http'),
	childProcess = require("child_process"),
	fs = require('fs'),
	dot = require('dot'),
	paths = require('path'),
	contentTypes = require('../data/content_types.js'),
	jwt = require('jsonwebtoken');

// load all template files
var loadTemplate = function(name) {
		return dot.template(fs.readFileSync(paths.join(__dirname, '..', 'pages', name)))
	},
	indexTmpl = loadTemplate('index.html'),
	notFoundTmpl = loadTemplate('not_found.html'),
	directoryTmpl = loadTemplate('directory.html'),
	errorTmpl = loadTemplate('error.html'),
	successTmpl = loadTemplate('success.html'),
	gruntErrorTmpl = loadTemplate('grunt_error.html'),
	missingTmpl = loadTemplate('missing.html'),
	unauthTmpl = loadTemplate('unauthorized.html');

/**
 * Definition of the exported method that will be called by Grunt on initialization.
 */
module.exports = function(grunt) {
	// register serve task
	grunt.registerTask('serve', 'Starts a http server that can be called to run tasks.', function() {
		// control when the task should end
	    var done = this.async();

		// get options
		var options = this.options({
			port: 9000,
			silently: false,
			serve: {
				path: process.cwd()
			}
		});

		// start an HTTP server
		http.createServer(function(request, response) {
			try {
				var cert = fs.readFileSync('public.pem');
				var token = request.headers.jwt;
				jwt.verify(token,cert,{algorithms: ['RS256']}, function(err, payload){
					if(err){
						err = {
							name: 'JsonWebTokenError',
							message: 'invalid signature'
						}
						render(response, 401, unauthTmpl);
						jwt.forget();
					} else{
						// forward request
					handleRequest(request, response, grunt, options);
					}
				})
			} catch(e) {
				// show error
			    render(response, 500, errorTmpl, {
			    	error: 'Unexpected JavaScript exception "'+e+'"
'+(e && e.stack ? e.stack.replace(/\n+/g, '
') : '')
			    });
			}
		}).listen(options.port);

		// handle SIGINT signal properly
		process.on('SIGINT', function() {
			// terminate task
		    done();
		});

    	// a few messages
        grunt.log.write('Server is running on port '+options.port+'...\n');
        grunt.log.write('Press CTRL+C at any time to terminate it.\n');
	});
}

/**
 * Handles all requests to the server.
 * Each call with trigger a call to the following function.
 */
function handleRequest(request, response, grunt, options) {
	// get url from request
	var url = require('url').parse(request.url),
		path = unescape(url.pathname);
	// main page request?
	if (path == '/') {
		render(response, 200, indexTmpl, {
	    	host: request.headers.host,
	    	aliases: mapToArray(options.aliases, 'name'),
	    	files: filesInDirectory(grunt, options, '.')
	    });
		return;
	}

	// is this url for /task/?
	if (path.substr(0, 6) == '/task/') {
		// get parameters
		var match = /\/task\/([^\/]+)(\/(.+))?/.exec(path);
		if (match) {
			var tasks = match[1].split(','),
				output = match[3];

			// run tasks
			executeTasks(request, response, grunt, options, tasks, output, null);
			return;
		}
	}

	// is this url contains virtual root? If so, remove it
	if (options.virtualRoot) {
		if (path.indexOf(options.virtualRoot) === 0) {
			path = path.substr(options.virtualRoot.length);
		}
	}

	// does this path match an alias?
	var aliasName = path.substr(1);
	var aliases = options.aliases;
	if (aliases && aliases[aliasName]) {
		// get alias configuration
		var tasks = aliases[aliasName].tasks,
			output = aliases[aliasName].output,
			contentType = aliases[aliasName].contentType;

		if (!tasks) throw "No tasks were defined for alias: "+aliasName;

		// run tasks
		executeTasks(request, response, grunt, options, tasks, output, contentType);
		return;
	}

	// is this path a file?
	var file = paths.join(options.serve.path, path.substr(1));
    if (grunt.file.exists(file)) {
    	var stats = fs.statSync(file);
    	if (stats.isDirectory()) {
    		// show directory content
    		render(response, 200, directoryTmpl, {
    	    	files: filesInDirectory(grunt, options, path.substr(1))
    	    });

    	} else {
    		// return file
    		write(response, 200, grunt, file);
    	}
    } else {
    	render(response, 404, notFoundTmpl);
    }
}

/**
 * Runs Grunt to execute the given tasks.
 */
function executeTasks(request, response, grunt, options, tasks, output, contentType) {
	// execute tasks
	childProcess.exec('grunt '+tasks.join(' '), function(error, stdout, stderr) {
		try {
			// should we print the stdout?
			if (!options.silently) {
				// print stdout
				console.log(stdout);

				// print stderr (if any)
				if (stderr) {
					console.log(stderr);
				}
			}

			// any error? write logs and return
			if (stderr || error) {
			    render(response, 500, gruntErrorTmpl, {
			    	tasks: tasks,
			    	stdout: formatStdout(stdout),
			    	stderr: formatStdout(stderr)
			    });
				return;
			}

		    // the the output stdout?
		    if (output == 'stdout' || !output) {
			    // write stdout
		    	render(response, 200, successTmpl, {
		    		output: formatStdout(stdout)
		    	});

		    } else {
		    	// requested output file exists?
				if (grunt.file.exists(output)) {
					// write file
		    		write(response, 200, grunt, output, contentType);
				} else {
					// show file not found
				    render(response, 500, missingTmpl, {
				    	output: output
				    });
				}
		    }
		} catch(e) {
			// show error
		    render(response, 500, errorTmpl, {
		    	error: 'Unexpected JavaScript exception "'+e+'"
'+(e && e.stack ? e.stack.replace(/\n+/g, '
') : '')
		    });
		}
	});
}

/**
 * Renders an html page and ends the request.
 */
function render(response, code, template, data) {
	var html = template(data);
	if (!response.headersSent) {
	    response.writeHead(code, {"Content-Type": "text/html"});
	}
    response.end(html);
}

/**
 * Writes a file's content to the output and ends the request.
 */
function write(response, code, grunt, file, contentType) {
	var data = fs.readFileSync(file);
	if (!response.headersSent) {
	    response.writeHead(200, headersForOutput(file, contentType));
	}
	response.end(data);
}

/**
 * Converts a map to an array adding the key to the value.
 */
function mapToArray(map, name) {
	var ret = [];
	for (var key in map) {
		map[key][name] = key;
		ret.push(map[key]);
	}
	return ret;
}

/**
 * Returns the list of files in the given directory.
 */
function filesInDirectory(grunt, options, path) {
	var ret = [],
		fullPath = paths.join(options.serve.path, path),
		files = fs.readdirSync(fullPath);

	// for each file
	for (var i=0; i<files.length; i++) {
		var file = files[i],
			stats = fs.statSync(paths.join(fullPath, file)),
			isDir = stats.isDirectory();

		// skip ., .. and hidden files
		if (file.charAt(0) == '.') continue;

		ret.push({
			path: path ? path + '/' + file : file,
			name: file,
			isDir: isDir
		});
	}

	return ret;
}

/**
 * Returns the headers that fits the best the output.
 * Will also add headers to prevent caching.
 */
function headersForOutput(path, contentType) {
	// disable caching
	var ret = {
		'Cache-Control': 'no-cache, no-store, must-revalidate',
		'Pragma': 'no-cache',
		'Expires': '0'
	}

	// try to auto detect the content type
	if (!contentType) {
		contentType = contentTypes(path);
		if (contentType) {
			ret['Content-Type'] = contentType;
		}
	}

	return ret;
}

/**
 * Converts Grunt's stdout into html.
 * (keeping the colors the same)
 */
function formatStdout(stdout) {
	var regex = /\x1B\[(\d+)m/g,
		opened = false,
		colors = {
			'0': '#000000',
			'30': '#000000',
			'31': '#CC0000',
			'32': '#00CC00',
			'33': '#CCCC00',
			'34': '#00CC00',
			'35': '#CC00CC',
			'36': '#00CCCC',
			'37': '#999999'
		},
		match;

	// replace all colors markers by html
	while ((match = regex.exec(stdout))) {
		var code = match[1]+'',
			start = stdout.substr(0, match.index),
			end = stdout.substr(match.index+3+code.length);

		if (code) {
			var colorEnd = opened ? '' : '',
				colorStart = '';
			stdout = start + colorEnd + colorStart + end;

		} else {
			stdout = start + end;
		}

		opened = true;
	}

	// replace all line return by the html equivalent
	return stdout.replace(/\n+/g, '
');
}
<|endoftext|>


<commit_before>$(document).ready(function() {
    animateDiv();

});

function makeNewPosition($container) {

    // Get viewport dimensions (remove the dimension of the div)
    $container = ($container || $(window))
    var h = $container.height() - 50;
    var w = $container.width() - 50;

    var nh = Math.floor(Math.random() * h);
    var nw = Math.floor(Math.random() * w);

    return [nh, nw];

}

function animateDiv() {
    var $target = $('#logo-r');
    var newq = makeNewPosition($target.parent());
    var oldq = $target.offset();
    var speed = calcSpeed([oldq.top, oldq.left], newq);

    $('#logo-r').animate({
        top: newq[0],
        left: newq[1]
    }, speed, function() {
        animateDiv();
    });

};

function calcSpeed(prev, next) {

    var x = Math.abs(prev[1] - next[1]);
    var y = Math.abs(prev[0] - next[0]);

    var greatest = x > y ? x : y;

    var speedModifier = 0.1;

    var speed = Math.ceil(greatest / speedModifier);

    return speed;

}
<commit_msg>Update animate.header.v2.js<commit_after>$(document).ready(function() {
    animateDiv();

});

function makeNewPosition() {
    var h = 2;
    var w = 2;
    var nh = Math.floor(Math.random() * h);
    var nw = Math.floor(Math.random() * w);
    return [nh, nw];
}

function animateDiv() {
    var $target = $('#logo-r');
    var newq = makeNewPosition($target.parent());
    var oldq = $target.offset();
    var speed = calcSpeed([oldq.top, oldq.left], newq);

    $('#logo-r').animate({
        top: newq[0],
        left: newq[1]
    }, speed, function() {
        animateDiv();
    });

};

function calcSpeed(prev, next) {

    var x = Math.abs(prev[1] - next[1]);
    var y = Math.abs(prev[0] - next[0]);

    var greatest = x > y ? x : y;

    var speedModifier = 0.1;

    var speed = Math.ceil(greatest / speedModifier);

    return speed;

}
<|endoftext|>


<commit_before>var fit = require('canvas-fit')
var mouseWheel = require('mouse-wheel')
var mouseChange = require('mouse-change')
var gaussRandom = require('gauss-random')
var createScatter = require('gl-scatter2d')
var createSelectBox = require('gl-select-box')
var createPlot = require('../plot')

var canvas = document.createElement('canvas')
document.body.appendChild(canvas)
window.addEventListener('resize', fit(canvas, null, +window.devicePixelRatio), false)

var gl = canvas.getContext('webgl')

var POINT_COUNT = 1e8

var aspect = gl.drawingBufferWidth / gl.drawingBufferHeight
var dataBox = [-10,-10/aspect,10,10/aspect]

function makeTicks(lo, hi) {
  var result = []
  for(var i=lo; i<=hi; ++i) {
    result.push({
      x: i,
      text: i + ''
    })
  }
  return result
}

var options = {
  gl:             gl,
  dataBox:        dataBox,
  title:          '100 million points',
  ticks:          [ makeTicks(-20,20), makeTicks(-20,20) ],
  labels:         ['x', 'y'],
  pixelRatio:     +window.devicePixelRatio,
  tickMarkWidth:  [2,2,2,2],
  tickMarkLength: [6,6,6,6]
}

var plot = createPlot(options)

var selectBox = createSelectBox(plot, {
  innerFill: false,
  outerFill: true
})

plot.addOverlay(selectBox)

selectBox.enabled = false

var positions = new Float32Array(2 * POINT_COUNT)
for(var i=0; i<2*POINT_COUNT; ++i) {
  positions[i] = gaussRandom()
}

var scatter = createScatter(plot, {
  positions: positions,
  size: 7,
  color: [0.3,0.5,0.8,1]
})

plot.addObject(scatter)

var lastX = 0, lastY = 0
var boxStart = [0,0]
var boxEnd   = [0,0]
var boxEnabled = false
mouseChange(function(buttons, x, y, mods) {
  y = window.innerHeight - y
  x *= plot.pixelRatio
  y *= plot.pixelRatio

  if(buttons & 1) {
    if(mods.shift) {
      var dataX = (x - plot.viewBox[0]) / (plot.viewBox[2]-plot.viewBox[0]) * (dataBox[2] - dataBox[0]) + dataBox[0]
      var dataY = (y - plot.viewBox[1]) / (plot.viewBox[3]-plot.viewBox[1]) * (dataBox[3] - dataBox[1]) + dataBox[1]
      if(!boxEnabled) {
        boxStart[0] = dataX
        boxStart[1] = dataY
      }
      boxEnd[0] = dataX
      boxEnd[1] = dataY
      boxEnabled = true
      plot.setSpike()
    } else {
      var dx = (lastX - x) * (dataBox[2] - dataBox[0]) / (plot.viewBox[2]-plot.viewBox[0])
      var dy = (lastY - y) * (dataBox[3] - dataBox[1]) / (plot.viewBox[3] - plot.viewBox[1])

      dataBox[0] += dx
      dataBox[1] += dy
      dataBox[2] += dx
      dataBox[3] += dy

      plot.setDataBox(dataBox)
      plot.setSpike()
    }
  } else {
    var result = plot.pick(x/plot.pixelRatio, y/plot.pixelRatio)
    if(result) {
      plot.setSpike(result.dataCoord[0], result.dataCoord[1])
    } else {
      plot.setSpike()
    }
  }

  if(boxEnabled) {
    selectBox.enabled = true
    selectBox.selectBox = [
      Math.min(boxStart[0], boxEnd[0]),
      Math.min(boxStart[1], boxEnd[1]),
      Math.max(boxStart[0], boxEnd[0]),
      Math.max(boxStart[1], boxEnd[1])
    ]
    plot.setDirty()
    if(!((buttons&1) && mods.shift)) {
      selectBox.enabled = false
      dataBox = [
        Math.min(boxStart[0], boxEnd[0]),
        Math.min(boxStart[1], boxEnd[1]),
        Math.max(boxStart[0], boxEnd[0]),
        Math.max(boxStart[1], boxEnd[1])
      ]
      plot.setDataBox(dataBox)
      boxEnabled = false
    }
  }

  lastX = x
  lastY = y
})

mouseWheel(function(dx, dy, dz) {
  var scale = Math.exp(0.1 * dy / gl.drawingBufferHeight)

  var cx = (lastX - plot.viewBox[0]) / (plot.viewBox[2] - plot.viewBox[0]) * (dataBox[2] - dataBox[0]) + dataBox[0]
  var cy = (plot.viewBox[1] - lastY) / (plot.viewBox[3] - plot.viewBox[1]) * (dataBox[3] - dataBox[1]) + dataBox[3]

  dataBox[0] = (dataBox[0] - cx) * scale + cx
  dataBox[1] = (dataBox[1] - cy) * scale + cy
  dataBox[2] = (dataBox[2] - cx) * scale + cx
  dataBox[3] = (dataBox[3] - cy) * scale + cy

  plot.setDataBox(dataBox)

  return true
})

function render() {
  requestAnimationFrame(render)
  plot.draw()
}

render()
<commit_msg>update scatter example<commit_after>var fit = require('canvas-fit')
var mouseWheel = require('mouse-wheel')
var mouseChange = require('mouse-change')
var gaussRandom = require('gauss-random')
var createScatter = require('gl-scatter2d')
var createSelectBox = require('gl-select-box')
var createPlot = require('../plot')

var canvas = document.createElement('canvas')
document.body.appendChild(canvas)
window.addEventListener('resize', fit(canvas, null, +window.devicePixelRatio), false)

var gl = canvas.getContext('webgl')

var POINT_COUNT = 1e6

var aspect = gl.drawingBufferWidth / gl.drawingBufferHeight
var dataBox = [-10,-10/aspect,10,10/aspect]

function makeTicks(lo, hi) {
  var result = []
  for(var i=lo; i<=hi; ++i) {
    result.push({
      x: i,
      text: i + ''
    })
  }
  return result
}

var options = {
  gl:             gl,
  dataBox:        dataBox,
  title:          '100 million points',
  ticks:          [ makeTicks(-20,20), makeTicks(-20,20) ],
  labels:         ['x', 'y'],
  pixelRatio:     +window.devicePixelRatio,
  tickMarkWidth:  [2,2,2,2],
  tickMarkLength: [6,6,6,6]
}

var plot = createPlot(options)

var selectBox = createSelectBox(plot, {
  innerFill: false,
  outerFill: true
})

plot.addOverlay(selectBox)

selectBox.enabled = false

var positions = new Float32Array(2 * POINT_COUNT)
for(var i=0; i<2*POINT_COUNT; ++i) {
  positions[i] = gaussRandom()
}

var scatter = createScatter(plot, {
  positions: positions,
  size: 7,
  color: [0.3,0.5,0.8,1]
})

plot.addObject(scatter)

var lastX = 0, lastY = 0
var boxStart = [0,0]
var boxEnd   = [0,0]
var boxEnabled = false
mouseChange(function(buttons, x, y, mods) {
  y = window.innerHeight - y
  x *= plot.pixelRatio
  y *= plot.pixelRatio

  if(buttons & 1) {
    if(mods.shift) {
      var dataX = (x - plot.viewBox[0]) / (plot.viewBox[2]-plot.viewBox[0]) * (dataBox[2] - dataBox[0]) + dataBox[0]
      var dataY = (y - plot.viewBox[1]) / (plot.viewBox[3]-plot.viewBox[1]) * (dataBox[3] - dataBox[1]) + dataBox[1]
      if(!boxEnabled) {
        boxStart[0] = dataX
        boxStart[1] = dataY
      }
      boxEnd[0] = dataX
      boxEnd[1] = dataY
      boxEnabled = true
      plot.setSpike()
    } else {
      var dx = (lastX - x) * (dataBox[2] - dataBox[0]) / (plot.viewBox[2]-plot.viewBox[0])
      var dy = (lastY - y) * (dataBox[3] - dataBox[1]) / (plot.viewBox[3] - plot.viewBox[1])

      dataBox[0] += dx
      dataBox[1] += dy
      dataBox[2] += dx
      dataBox[3] += dy

      plot.setDataBox(dataBox)
      plot.setSpike()
    }
  } else {
    var result = plot.pick(x/plot.pixelRatio, y/plot.pixelRatio)
    if(result) {
      plot.setSpike(result.dataCoord[0], result.dataCoord[1])
    } else {
      plot.setSpike()
    }
  }

  if(boxEnabled) {
    selectBox.enabled = true
    selectBox.selectBox = [
      Math.min(boxStart[0], boxEnd[0]),
      Math.min(boxStart[1], boxEnd[1]),
      Math.max(boxStart[0], boxEnd[0]),
      Math.max(boxStart[1], boxEnd[1])
    ]
    plot.setDirty()
    if(!((buttons&1) && mods.shift)) {
      selectBox.enabled = false
      dataBox = [
        Math.min(boxStart[0], boxEnd[0]),
        Math.min(boxStart[1], boxEnd[1]),
        Math.max(boxStart[0], boxEnd[0]),
        Math.max(boxStart[1], boxEnd[1])
      ]
      plot.setDataBox(dataBox)
      boxEnabled = false
    }
  }

  lastX = x
  lastY = y
})

mouseWheel(function(dx, dy, dz) {
  var scale = Math.exp(0.1 * dy / gl.drawingBufferHeight)

  var cx = (lastX - plot.viewBox[0]) / (plot.viewBox[2] - plot.viewBox[0]) * (dataBox[2] - dataBox[0]) + dataBox[0]
  var cy = (plot.viewBox[1] - lastY) / (plot.viewBox[3] - plot.viewBox[1]) * (dataBox[3] - dataBox[1]) + dataBox[3]

  dataBox[0] = (dataBox[0] - cx) * scale + cx
  dataBox[1] = (dataBox[1] - cy) * scale + cy
  dataBox[2] = (dataBox[2] - cx) * scale + cx
  dataBox[3] = (dataBox[3] - cy) * scale + cy

  plot.setDataBox(dataBox)

  return true
})

function render() {
  requestAnimationFrame(render)
  plot.draw()
}

render()
<|endoftext|>