<commit_before>import React, {Component, Fragment, createRef} from 'react';
import round from 'lodash/round';

import Table from 'src/Table';
import Switcher from 'src/Switcher';
import IconButton from 'src/IconButton';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import CircularLoading from 'src/CircularLoading';
import RaisedButton from 'src/RaisedButton';
import MaterialTextField from 'src/MaterialTextField';

import PropTypeDescTable from 'components/PropTypeDescTable';
import doc from 'assets/propTypes/Table.json';

import Util from 'vendors/Util';

import 'scss/containers/app/modules/layout/TableExamples.scss';

const LOADING_SYMBOL = Symbol('LOADING_SYMBOL');

class TableExamples extends Component {

    constructor(props) {

        super(props);

        this.tableRef = createRef();

        this.state = {
            data: this.generateData(),
            sorting: null,
            filter: ''
        };

        this.columns = [{
            headRenderer: 'ID',
            bodyRenderer: rowDate => rowDate[LOADING_SYMBOL] ?
                <CircularLoading/> : rowDate.id,
            footRenderer: 'Total',
            sortable: true,
            sortingProp: 'id'
        }, {
            width: 300,
            noWrap: true,
            headRenderer: 'Name',
            bodyRenderer: rowDate => rowDate.firstName && rowDate.lastName ?
                `${rowDate.firstName} ${rowDate.lastName}` : '',
            sortable: true,
            sortingProp: 'firstName'
        }, {
            align: Table.Align.RIGHT,
            headRenderer: 'Age',
            bodyRenderer: rowDate => rowDate.age,
            footRenderer: () =>
                <Fragment>

Average

{this.state.data.reduce((a, b) => a + b.age, 0) / this.state.data.length}

                </Fragment>,
            sortable: true,
            sortingProp: 'age'
        }, {
            headRenderer: 'Other Column',
            headAlign: Table.Align.CENTER,
            children: [{
                width: 300,
                headRenderer: 'Other Column 1',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 1` : ''
            }, {
                width: 300,
                headRenderer: 'Other Column 2',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 2` : ''
            }, {
                width: 300,
                headRenderer: 'Other Column 3',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 3` : ''
            }, {
                width: 300,
                headRenderer: 'Other Column 4',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 4` : ''
            }]
        }, {
            align: Table.Align.RIGHT,
            headRenderer: 'Deposit',
            bodyRenderer: rowDate => rowDate.deposit ? `$${rowDate.deposit}` : '',
            footRenderer: () =>
                <Fragment>

Sum

${this.state.data.reduce((a, b) => round(a + b.deposit, 2), 0)}

                </Fragment>,
            sortable: true,
            sortingProp: 'deposit'
        }, {
            headRenderer: 'Status',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <Switcher value={!rowData.disabled}
                          size="small"
                          onClick={e => e.stopPropagation()}/>
        }, {
            headRenderer: 'Action',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <IconButton iconCls="fas fa-trash-alt"
                            onClick={() => this.deleteRow(rowData.id)}/>
        }];

        this.pageSizes = [{
            value: 10,
            text: '10 / page'
        }, {
            value: 20,
            text: '20 / page'
        }, {
            value: 30,
            text: '30 / page'
        }, {
            value: 40,
            text: '40 / page'
        }, {
            value: 50,
            text: '50 / page'
        }];

    }

    getFixedColumns = () => {
        return this.columns.map(column => {
            if (['ID', 'Name'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.LEFT,
                    ...column
                };
            } else if (['Status', 'Action'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.RIGHT,
                    ...column
                };
            }
            return column;
        });
    };

    generateData = (size = 100, base = '', expanded = true) => {

        let data = [];
        for (let i = 0; i < size; i++) {

            const id = `${base ? `${base}-` : ''}${i}`,
                item = {
                    id,
                    firstName: `firstName${id}`,
                    lastName: `lastName${id}`,
                    age: Math.floor(Math.random() * 100),
                    deposit: round(Math.random() * 1000000, 2),
                    other: 'Other Content'
                };

            if (expanded && id.split('-').pop() === '0') {
                item.children = [{
                    [LOADING_SYMBOL]: true,
                    disabled: true
                }];
            }

            data.push(item);

        }

        return data;

    };

    deleteRow = id => {

        const {data} = this.state,
            newData = data.filter(item => item.id !== id);

        this.setState({
            data: newData
        });

    };

    handleSortChange = sorting => {
        this.setState({
            sorting
        });
        console.log('Sort Change Value: ', sorting);
    };

    handlePaginationChange = ({page, pageSize}) => {
        console.log(`page: ${page}, pageSize: ${pageSize}`);
    };

    handleDataUpdate = currentPageData => {
        console.log('Data Update Value: ', currentPageData);
    };

    handleSelect = (rowData, rowIndex, value) => {
        console.log('Select Value: ', rowData);
    };

    handleDeselect = (rowData, rowIndex, value) => {
        console.log('Deselect Value: ', rowData);
    };

    handleSelectAll = value => {
        console.log('Select All Value: ', value);
    };

    handleSeselectAll = value => {
        console.log('Deselect All Value: ', value);
    };

    handleChange = value => {
        console.log('Changed Value: ', value);
    };

    handleExpand = rowData => {

        console.log('Expand: ', rowData);

        const {data} = this.state;

        if (!rowData || !data || !rowData.children[0][LOADING_SYMBOL]) {
            return;
        }

        setTimeout(() => {

            Util.postOrderTraverse({
                children: data
            }, node => {
                if (node && node.id === rowData.id) {
                    node.children = this.generateData(10, node.id);
                    return false;
                }
            });

            this.setState({
                data
            });

        }, 1000);

    };

    handleCollapse = rowData => {
        console.log('Collapse: ', rowData);
    };

    collapseAllRows = () => {
        console.log('ref::', this.tableRef.current);
        this.tableRef && this.tableRef.current && this.tableRef.current.collapseAllRows();
    };

    handleFilter = filter => {
        this.setState({
            filter
        });
    };

    filterData = (data = this.state.data) => {

        const {filter} = this.state;

        if (!filter) {
            return data;
        }

        return data.filter(item => item && (
            (item.firstName && item.firstName.toUpperCase().includes(filter.toUpperCase()))
            ||
            (item.lastName && item.lastName.toUpperCase().includes(filter.toUpperCase()))
        ));

    };

    render() {

        const {data, sorting, filter} = this.state,
            filteredData = this.filterData(data);

        return (

Table

                    Table
                     are used to display data and to organize it.

Examples

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Normal"/>

A simple Table example.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onDataUpdate={this.handleDataUpdate}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head & Foot"/>

                                You can config isHeadFixed to fix the Head,
                                and config isFootFixed to fix the Foot.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   scroll={{
                                       maxHeight: 320
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onDataUpdate={this.handleDataUpdate}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Columns"/>

                                You can config fixed in columns to fix the column
                                Left or Right.

                            <Table className="example-table"
                                   columns={this.getFixedColumns()}
                                   data={data}
                                   scroll={{
                                       width: 1200
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onDataUpdate={this.handleDataUpdate}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head, Foot and Columns"/>

                                <RaisedButton className="action-button"
                                              value="Collapse All Rows"
                                              onClick={this.collapseAllRows}/>

                                <MaterialTextField className="filter"
                                                   label="Filter"
                                                   value={filter}
                                                   onChange={this.handleFilter}/>

                            <Table ref={this.tableRef}
                                   className="example-table"
                                   data={filteredData}
                                   columns={this.getFixedColumns()}
                                   sorting={sorting}
                                   selectMode={Table.SelectMode.MULTI_SELECT}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   isFootHidden={!filteredData || filteredData.length < 1}
                                   scroll={{
                                       width: 1200,
                                       height: filteredData && filteredData.length > 0 ? 320 : 0
                                   }}
                                   useFullPagination={true}
                                   paginationTotalRenderer={total => Self Defined Total: {total}}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onDataUpdate={this.handleDataUpdate}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="No Data"/>

No Data Table example.

                </Widget>

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
}

export default TableExamples;
<commit_msg>update TableExamples<commit_after>import React, {Component, Fragment, createRef} from 'react';
import round from 'lodash/round';

import Table from 'src/Table';
import Switcher from 'src/Switcher';
import IconButton from 'src/IconButton';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import CircularLoading from 'src/CircularLoading';
import RaisedButton from 'src/RaisedButton';
import MaterialTextField from 'src/MaterialTextField';

import PropTypeDescTable from 'components/PropTypeDescTable';
import doc from 'assets/propTypes/Table.json';

import Util from 'vendors/Util';

import 'scss/containers/app/modules/layout/TableExamples.scss';

const LOADING_SYMBOL = Symbol('LOADING_SYMBOL');

class TableExamples extends Component {

    constructor(props) {

        super(props);

        this.tableRef = createRef();

        this.state = {
            data: this.generateData(),
            sorting: null,
            filter: ''
        };

        this.columns = [{
            headRenderer: 'ID',
            bodyRenderer: rowDate => rowDate[LOADING_SYMBOL] ?
                <CircularLoading/> : rowDate.id,
            footRenderer: 'Total',
            sortable: true,
            sortingProp: 'id'
        }, {
            width: 300,
            noWrap: true,
            headRenderer: 'Name',
            bodyRenderer: rowDate => rowDate.firstName && rowDate.lastName ?
                `${rowDate.firstName} ${rowDate.lastName}` : '',
            sortable: true,
            sortingProp: 'firstName'
        }, {
            align: Table.Align.RIGHT,
            headRenderer: 'Age',
            bodyRenderer: rowDate => rowDate.age,
            footRenderer: () =>
                <Fragment>

Average

{this.state.data.reduce((a, b) => a + b.age, 0) / this.state.data.length}

                </Fragment>,
            sortable: true,
            sortingProp: 'age'
        }, {
            headRenderer: 'Other Column',
            headAlign: Table.Align.CENTER,
            children: [{
                width: 300,
                headRenderer: 'Other Column 1',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 1` : ''
            }, {
                width: 300,
                headRenderer: 'Other Column 2',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 2` : ''
            }, {
                width: 300,
                headRenderer: 'Other Column 3',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 3` : ''
            }, {
                width: 300,
                headRenderer: 'Other Column 4',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 4` : ''
            }]
        }, {
            align: Table.Align.RIGHT,
            headRenderer: 'Deposit',
            bodyRenderer: rowDate => rowDate.deposit ? `$${rowDate.deposit}` : '',
            footRenderer: () =>
                <Fragment>

Sum

${this.state.data.reduce((a, b) => round(a + b.deposit, 2), 0)}

                </Fragment>,
            sortable: true,
            sortingProp: 'deposit'
        }, {
            headRenderer: 'Status',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <Switcher value={!rowData.disabled}
                          size="small"
                          onClick={e => e.stopPropagation()}/>
        }, {
            headRenderer: 'Action',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <IconButton iconCls="fas fa-trash-alt"
                            onClick={() => this.deleteRow(rowData.id)}/>
        }];

        this.pageSizes = [{
            value: 10,
            text: '10 / page'
        }, {
            value: 20,
            text: '20 / page'
        }, {
            value: 30,
            text: '30 / page'
        }, {
            value: 40,
            text: '40 / page'
        }, {
            value: 50,
            text: '50 / page'
        }];

    }

    getFixedColumns = () => {
        return this.columns.map(column => {
            if (['ID', 'Name'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.LEFT,
                    ...column
                };
            } else if (['Status', 'Action'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.RIGHT,
                    ...column
                };
            }
            return column;
        });
    };

    generateData = (size = 100, base = '', expanded = true) => {

        let data = [];
        for (let i = 0; i < size; i++) {

            const id = `${base ? `${base}-` : ''}${i}`,
                item = {
                    id,
                    firstName: `firstName${id}`,
                    lastName: `lastName${id}`,
                    age: Math.floor(Math.random() * 100),
                    deposit: round(Math.random() * 1000000, 2),
                    other: 'Other Content'
                };

            if (expanded && id.split('-').pop() === '0') {
                item.children = [{
                    [LOADING_SYMBOL]: true,
                    disabled: true
                }];
            }

            data.push(item);

        }

        return data;

    };

    deleteRow = id => {

        const {data} = this.state,
            newData = data.filter(item => item.id !== id);

        this.setState({
            data: newData
        });

    };

    handleSortChange = sorting => {
        this.setState({
            sorting
        });
        console.log('Sort Change Value: ', sorting);
    };

    handlePaginationChange = ({page, pageSize}) => {
        console.log(`page: ${page}, pageSize: ${pageSize}`);
    };

    handleSelect = (rowData, rowIndex, value) => {
        console.log('Select Value: ', rowData);
    };

    handleDeselect = (rowData, rowIndex, value) => {
        console.log('Deselect Value: ', rowData);
    };

    handleSelectAll = value => {
        console.log('Select All Value: ', value);
    };

    handleSeselectAll = value => {
        console.log('Deselect All Value: ', value);
    };

    handleChange = value => {
        console.log('Changed Value: ', value);
    };

    handleExpand = rowData => {

        console.log('Expand: ', rowData);

        const {data} = this.state;

        if (!rowData || !data || !rowData.children[0][LOADING_SYMBOL]) {
            return;
        }

        setTimeout(() => {

            Util.postOrderTraverse({
                children: data
            }, node => {
                if (node && node.id === rowData.id) {
                    node.children = this.generateData(10, node.id);
                    return false;
                }
            });

            this.setState({
                data
            });

        }, 1000);

    };

    handleCollapse = rowData => {
        console.log('Collapse: ', rowData);
    };

    collapseAllRows = () => {
        console.log('ref::', this.tableRef.current);
        this.tableRef && this.tableRef.current && this.tableRef.current.collapseAllRows();
    };

    handleFilter = filter => {
        this.setState({
            filter
        });
    };

    filterData = (data = this.state.data) => {

        const {filter} = this.state;

        if (!filter) {
            return data;
        }

        return data.filter(item => item && (
            (item.firstName && item.firstName.toUpperCase().includes(filter.toUpperCase()))
            ||
            (item.lastName && item.lastName.toUpperCase().includes(filter.toUpperCase()))
        ));

    };

    render() {

        const {data, sorting, filter} = this.state,
            filteredData = this.filterData(data);

        return (

Table

                    Table
                     are used to display data and to organize it.

Examples

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Normal"/>

A simple Table example.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head & Foot"/>

                                You can config isHeadFixed to fix the Head,
                                and config isFootFixed to fix the Foot.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   scroll={{
                                       maxHeight: 320
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Columns"/>

                                You can config fixed in columns to fix the column
                                Left or Right.

                            <Table className="example-table"
                                   columns={this.getFixedColumns()}
                                   data={data}
                                   scroll={{
                                       width: 1200
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head, Foot and Columns"/>

                                <RaisedButton className="action-button"
                                              value="Collapse All Rows"
                                              onClick={this.collapseAllRows}/>

                                <MaterialTextField className="filter"
                                                   label="Filter"
                                                   value={filter}
                                                   onChange={this.handleFilter}/>

                            <Table ref={this.tableRef}
                                   className="example-table"
                                   data={filteredData}
                                   columns={this.getFixedColumns()}
                                   sorting={sorting}
                                   selectMode={Table.SelectMode.MULTI_SELECT}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   isFootHidden={!filteredData || filteredData.length < 1}
                                   scroll={{
                                       width: 1200,
                                       height: filteredData && filteredData.length > 0 ? 320 : 0
                                   }}
                                   useFullPagination={true}
                                   paginationTotalRenderer={total => Self Defined Total: {total}}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="No Data"/>

No Data Table example.

                </Widget>

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
}

export default TableExamples;
<|endoftext|>


<commit_before>var gulp = require('gulp'),
	plugins = require('gulp-load-plugins')(),

	pkg = require('./package.json'),
	extend = require('node.extend'),
	jshint_stylish = require('jshint-stylish'),
	del = require('del'),
	argv = require('yargs').argv,

	banner = '/*\n\t<%=pkg.name%> v<%=pkg.version%>\n\t(C) 2010 - 2015 VREM Software Development\n\t<%= pkg.homepage %>\n\tLicense: <%=pkg.license%>\n*/\n',
	srcdir = 'app',
	dstdir = 'dist',
	cmpdir = 'bower_components',
	dataname = pkg.name+'Usage.js',

	showColor = argv.color === undefined || argv.color === null ? true : argv.color,

	files = {
		other: {
			src: [srcdir+'/'+dataname, srcdir+'/favicon.ico'],
			dest: dstdir
		},
		js: {
			src: [srcdir+'/**/*.js', cmpdir+'/angularUtils-pagination/dirPagination.js'],
			libs: [
				cmpdir+'/angular/angular.min.js',
				cmpdir+'/angular-route/angular-route.min.js',
				cmpdir+'/underscore/underscore-min.js',
				cmpdir+'/momentjs/min/moment.min.js',
				cmpdir+'/d3/d3.min.js',
				cmpdir+'/n3-line-chart/build/line-chart.min.js'
			],
			dest: dstdir+'/js',
			temp: pkg.name+'.js',
			name: pkg.name+'.min.js',
			excludes: ['!'+srcdir+'/**/'+dataname, '!'+srcdir+'/**/*.Test.js']
		},
		test: {
			libs: [cmpdir+'/angular-mocks/angular-mocks.js'],
			excludes: srcdir+'/**/!('+dataname+').js'
		},
		e2e : {
			src: 'e2e/**/*.Test.js'
		},
		css: {
			src: [srcdir+'/css/*.css'],
			libs: cmpdir+'/bootstrap/dist/css/bootstrap.min.css',
			dest: dstdir+'/css',
			name: pkg.name+'.min.css'
		},
		templates:  {
			src: srcdir+'/**/**.tpl.html',
			module: 'BWMonApp',
			dest: srcdir
		},
		html:  {
			src: srcdir+'/index.tpl.html',
			name: 'index.html',
			prod: {
				preprocess: {context: {PRODUCTION: true}},
				dest: dstdir,
			},
			dev: {
				preprocess: {context: {DEVELOPMENT: true}},
				dest: srcdir,
			}
		},
		version: {
			src: ['./package.json', './bower.json'],
			dest: './',
			message: 'bumps package version',
			filter: 'package.json'
		},
		release: {
			src: [dstdir+'/**/*', '!'+dstdir+'/'+dataname, 'server/'+pkg.name+'*.sh'],
			name: pkg.name+'.tar',
			dest: 'release'
		}
	},
	objectExists = function(object) {
		return typeof object != "undefined";
	},
	karma = function(done, config) {
		var Server = require('karma').Server,
			defaults = {
				basePath: __dirname,
				files: [].concat(files.js.libs, files.test.libs, files.js.src, files.test.excludes, files.templates.src),
				configFile: __dirname+'/config/karma.conf.js',
				colors: showColor
			},
			parameters = extend(defaults, config);
		new Server(parameters, done).start();
	},
	version = function(type) {
		return gulp.src(files.version.src)
			.pipe(plugins.bump({type: type}))
			.pipe(gulp.dest(files.version.dest));
	};

gulp.task('uglify:clean', function() {
	return del.sync(dstdir);
});

gulp.task('templates:clean', function() {
	return del.sync(files.templates.dstdir+'/templates.js');
});

gulp.task('html:clean', function() {
	return del.sync(files.html.prod.dest+'/'+files.html.name);
});

gulp.task('devhtml:clean', function() {
	return del.sync(files.html.dev.dest+'/'+files.html.name);
});

gulp.task('devhtml', ['devhtml:clean'], function() {
	return gulp
		.src(files.html.src)
		.pipe(plugins.rename(files.html.name))
		.pipe(plugins.preprocess(files.html.dev.preprocess))
		.pipe(gulp.dest(files.html.dev.dest));
});

gulp.task('jshint', function() {
	var src = [].concat(files.js.src, files.e2e.src, files.js.excludes);
	return gulp
		.src(src)
		.pipe(plugins.jshint())
		.pipe(plugins.jshint.reporter(jshint_stylish))
		.pipe(plugins.jshint.reporter('fail'));
});

gulp.task('test', ['jshint', 'devhtml'], function(done) { karma(done); });
gulp.task('test_auto', ['jshint', 'devhtml'], function(done) { karma(done, {autoWatch: true, singleRun: false}); });
gulp.task('coverage', ['jshint', 'devhtml'], function(done) { karma(done, {reporters: ['coverage']}); });

gulp.task('cssmin', function() {
	return gulp
		.src(files.css.src)
		.pipe(plugins.minifyCss())
		.pipe(plugins.concat(files.css.name))
		.pipe(gulp.dest(files.css.dest));
});

gulp.task('csslibs', function() {
	return gulp
		.src(files.css.libs)
		.pipe(gulp.dest(files.css.dest));
});

gulp.task('jslibs', function() {
	return gulp
		.src(files.js.libs)
		.pipe(gulp.dest(files.js.dest));
});

gulp.task('templates', ['templates:clean'], function() {
	return gulp
		.src(files.templates.src)
		.pipe(plugins.htmlmin())
		.pipe(plugins.angularTemplatecache({module: files.templates.module}))
		.pipe(gulp.dest(files.templates.dest));
});

gulp.task('uglify', ['uglify:clean', 'templates', 'test'], function() {
	var src = [].concat(files.js.src, files.js.excludes);
	return gulp
		.src(src)
		.pipe(plugins.concat(files.js.temp, {newLine: ';'}))
		.pipe(gulp.dest(files.js.dest))
		.pipe(plugins.rename(files.js.name))
		.pipe(plugins.uglify({mangle: false}))
		.pipe(plugins.header(banner, {pkg: pkg}))
		.pipe(gulp.dest(files.js.dest));
});

gulp.task('html', ['html:clean'], function() {
	return gulp
		.src(files.html.src)
		.pipe(plugins.rename(files.html.name))
		.pipe(plugins.preprocess(files.html.prod.preprocess))
		.pipe(gulp.dest(files.html.prod.dest));
});

gulp.task('other', function() {
	return gulp
		.src(files.other.src)
		.pipe(gulp.dest(files.other.dest));
});

gulp.task('webserver', ['jslibs', 'uglify', 'csslibs', 'cssmin', 'html', 'other'], function() {
	plugins.connect.server({
		root: dstdir,
		port: 8080
	});
});

gulp.task('webdriverUpdate', plugins.protractor.webdriver_update);

gulp.task('e2e', ['webdriverUpdate', 'webserver'], function() {
	return gulp
		.src(__dirname+files.e2e.src)
		.pipe(plugins.protractor.protractor({configFile: __dirname+'/config/protractor.conf.js'}));
});

gulp.task('build', ['e2e'], function() {
	plugins.connect.serverClose();
	return del(files.js.dest+'/'+files.js.temp);
});

gulp.task('watch', function() {
	var src = [].concat(files.main.src, files.test.src, files.e2e.src);
	gulp.watch(src, ['jshint']);
});

gulp.task('default', ['build']);

/*
 * Development Web Server for manual testing
 */
gulp.task('devwebserver', ['devhtml'], function() {
	plugins.connect.server({
		root: srcdir+'/..',
		port: 8080,
		livereload: true
	});
});

/*
 * Release Management: Version, Git and Release
 */
gulp.task('version:patch', function() { return version('patch'); });
gulp.task('version:minor', function() { return version('minor'); });
gulp.task('version:major', function() { return version('major'); });

gulp.task('git:tag', function() {
	return gulp.src(files.version.src)
		.pipe(plugins.git.commit(files.version.message))
		.pipe(plugins.filter(files.version.filter))
		.pipe(plugins.tagVersion());
});

gulp.task('release:clean', function() {
	return del.sync(files.release.dest);
});

gulp.task('release', ['release:clean'], function() {
	return gulp
		.src(files.release.src)
		.pipe(plugins.tar(files.release.name))
		.pipe(plugins.gzip({gzipOptions: {level: 9}}))
		.pipe(gulp.dest(files.release.dest));
});

/*
 * Clean
 */
gulp.task('clean', ['uglify:clean', 'templates:clean', 'html:clean', 'devhtml:clean']);
<commit_msg>cleanup windows gulp protractor specs issue<commit_after>var gulp = require('gulp'),
	plugins = require('gulp-load-plugins')(),

	pkg = require('./package.json'),
	extend = require('node.extend'),
	jshint_stylish = require('jshint-stylish'),
	del = require('del'),
	argv = require('yargs').argv,

	banner = '/*\n\t<%=pkg.name%> v<%=pkg.version%>\n\t(C) 2010 - 2015 VREM Software Development\n\t<%= pkg.homepage %>\n\tLicense: <%=pkg.license%>\n*/\n',
	srcdir = 'app',
	dstdir = 'dist',
	cmpdir = 'bower_components',
	dataname = pkg.name+'Usage.js',

	showColor = argv.color === undefined || argv.color === null ? true : argv.color,

	files = {
		other: {
			src: [srcdir+'/'+dataname, srcdir+'/favicon.ico'],
			dest: dstdir
		},
		js: {
			src: [srcdir+'/**/*.js', cmpdir+'/angularUtils-pagination/dirPagination.js'],
			libs: [
				cmpdir+'/angular/angular.min.js',
				cmpdir+'/angular-route/angular-route.min.js',
				cmpdir+'/underscore/underscore-min.js',
				cmpdir+'/momentjs/min/moment.min.js',
				cmpdir+'/d3/d3.min.js',
				cmpdir+'/n3-line-chart/build/line-chart.min.js'
			],
			dest: dstdir+'/js',
			temp: pkg.name+'.js',
			name: pkg.name+'.min.js',
			excludes: ['!'+srcdir+'/**/'+dataname, '!'+srcdir+'/**/*.Test.js']
		},
		test: {
			libs: [cmpdir+'/angular-mocks/angular-mocks.js'],
			excludes: srcdir+'/**/!('+dataname+').js'
		},
		e2e : {
			src: 'e2e/**/*.Test.js'
		},
		css: {
			src: [srcdir+'/css/*.css'],
			libs: cmpdir+'/bootstrap/dist/css/bootstrap.min.css',
			dest: dstdir+'/css',
			name: pkg.name+'.min.css'
		},
		templates:  {
			src: srcdir+'/**/**.tpl.html',
			module: 'BWMonApp',
			dest: srcdir
		},
		html:  {
			src: srcdir+'/index.tpl.html',
			name: 'index.html',
			prod: {
				preprocess: {context: {PRODUCTION: true}},
				dest: dstdir,
			},
			dev: {
				preprocess: {context: {DEVELOPMENT: true}},
				dest: srcdir,
			}
		},
		version: {
			src: ['./package.json', './bower.json'],
			dest: './',
			message: 'bumps package version',
			filter: 'package.json'
		},
		release: {
			src: [dstdir+'/**/*', '!'+dstdir+'/'+dataname, 'server/'+pkg.name+'*.sh'],
			name: pkg.name+'.tar',
			dest: 'release'
		}
	},
	objectExists = function(object) {
		return typeof object != "undefined";
	},
	karma = function(done, config) {
		var Server = require('karma').Server,
			defaults = {
				basePath: __dirname,
				files: [].concat(files.js.libs, files.test.libs, files.js.src, files.test.excludes, files.templates.src),
				configFile: __dirname+'/config/karma.conf.js',
				colors: showColor
			},
			parameters = extend(defaults, config);
		new Server(parameters, done).start();
	},
	version = function(type) {
		return gulp.src(files.version.src)
			.pipe(plugins.bump({type: type}))
			.pipe(gulp.dest(files.version.dest));
	};

gulp.task('uglify:clean', function() {
	return del.sync(dstdir);
});

gulp.task('templates:clean', function() {
	return del.sync(files.templates.dstdir+'/templates.js');
});

gulp.task('html:clean', function() {
	return del.sync(files.html.prod.dest+'/'+files.html.name);
});

gulp.task('devhtml:clean', function() {
	return del.sync(files.html.dev.dest+'/'+files.html.name);
});

gulp.task('devhtml', ['devhtml:clean'], function() {
	return gulp
		.src(files.html.src)
		.pipe(plugins.rename(files.html.name))
		.pipe(plugins.preprocess(files.html.dev.preprocess))
		.pipe(gulp.dest(files.html.dev.dest));
});

gulp.task('jshint', function() {
	var src = [].concat(files.js.src, files.e2e.src, files.js.excludes);
	return gulp
		.src(src)
		.pipe(plugins.jshint())
		.pipe(plugins.jshint.reporter(jshint_stylish))
		.pipe(plugins.jshint.reporter('fail'));
});

gulp.task('test', ['jshint', 'devhtml'], function(done) { karma(done); });
gulp.task('test_auto', ['jshint', 'devhtml'], function(done) { karma(done, {autoWatch: true, singleRun: false}); });
gulp.task('coverage', ['jshint', 'devhtml'], function(done) { karma(done, {reporters: ['coverage']}); });

gulp.task('cssmin', function() {
	return gulp
		.src(files.css.src)
		.pipe(plugins.minifyCss())
		.pipe(plugins.concat(files.css.name))
		.pipe(gulp.dest(files.css.dest));
});

gulp.task('csslibs', function() {
	return gulp
		.src(files.css.libs)
		.pipe(gulp.dest(files.css.dest));
});

gulp.task('jslibs', function() {
	return gulp
		.src(files.js.libs)
		.pipe(gulp.dest(files.js.dest));
});

gulp.task('templates', ['templates:clean'], function() {
	return gulp
		.src(files.templates.src)
		.pipe(plugins.htmlmin())
		.pipe(plugins.angularTemplatecache({module: files.templates.module}))
		.pipe(gulp.dest(files.templates.dest));
});

gulp.task('uglify', ['uglify:clean', 'templates', 'test'], function() {
	var src = [].concat(files.js.src, files.js.excludes);
	return gulp
		.src(src)
		.pipe(plugins.concat(files.js.temp, {newLine: ';'}))
		.pipe(gulp.dest(files.js.dest))
		.pipe(plugins.rename(files.js.name))
		.pipe(plugins.uglify({mangle: false}))
		.pipe(plugins.header(banner, {pkg: pkg}))
		.pipe(gulp.dest(files.js.dest));
});

gulp.task('html', ['html:clean'], function() {
	return gulp
		.src(files.html.src)
		.pipe(plugins.rename(files.html.name))
		.pipe(plugins.preprocess(files.html.prod.preprocess))
		.pipe(gulp.dest(files.html.prod.dest));
});

gulp.task('other', function() {
	return gulp
		.src(files.other.src)
		.pipe(gulp.dest(files.other.dest));
});

gulp.task('webserver', ['jslibs', 'uglify', 'csslibs', 'cssmin', 'html', 'other'], function() {
	plugins.connect.server({
		root: dstdir,
		port: 8080
	});
});

gulp.task('webdriverUpdate', plugins.protractor.webdriver_update);

gulp.task('e2e', ['webdriverUpdate', 'webserver'], function() {
	return gulp
		.src('../'+files.e2e.src)
		.pipe(plugins.protractor.protractor({configFile: 'config/protractor.conf.js'}));
});

gulp.task('build', ['e2e'], function() {
	plugins.connect.serverClose();
	return del(files.js.dest+'/'+files.js.temp);
});

gulp.task('watch', function() {
	var src = [].concat(files.main.src, files.test.src, files.e2e.src);
	gulp.watch(src, ['jshint']);
});

gulp.task('default', ['build']);

/*
 * Development Web Server for manual testing
 */
gulp.task('devwebserver', ['devhtml'], function() {
	plugins.connect.server({
		root: srcdir+'/..',
		port: 8080,
		livereload: true
	});
});

/*
 * Release Management: Version, Git and Release
 */
gulp.task('version:patch', function() { return version('patch'); });
gulp.task('version:minor', function() { return version('minor'); });
gulp.task('version:major', function() { return version('major'); });

gulp.task('git:tag', function() {
	return gulp.src(files.version.src)
		.pipe(plugins.git.commit(files.version.message))
		.pipe(plugins.filter(files.version.filter))
		.pipe(plugins.tagVersion());
});

gulp.task('release:clean', function() {
	return del.sync(files.release.dest);
});

gulp.task('release', ['release:clean'], function() {
	return gulp
		.src(files.release.src)
		.pipe(plugins.tar(files.release.name))
		.pipe(plugins.gzip({gzipOptions: {level: 9}}))
		.pipe(gulp.dest(files.release.dest));
});

/*
 * Clean
 */
gulp.task('clean', ['uglify:clean', 'templates:clean', 'html:clean', 'devhtml:clean']);
<|endoftext|>


<commit_before>var gulp = require('gulp'),
    gutil = require('gulp-util'),
    sass = require('gulp-sass'),
    coffee = require('gulp-coffee'),
    watch = require('gulp-watch'),
    uglify = require('gulp-uglify'),
    concat = require('gulp-concat'),
    browserify = require('gulp-browserify'),
    rename = require('gulp-rename'),
    connect = require('gulp-connect');
    gzip = require('gulp-gzip');
    fs = require('fs');
    s3 = require('gulp-s3');

var dest = './dist';
var paths = {
  main_stylesheet: ['./src/stylesheets/app.scss'],
  stylesheets: ['./src/stylesheets/*.scss'],
  main_javascript: ['./src/javascripts/app.coffee'],
  javascripts: ['./src/javascripts/**/*.coffee'],
  html: ['./src/html/podigee-podcast-player.html', './src/html/embed-example.html'],
  images: ['./src/images/**'],
  fonts: ['./vendor/fonts/**'],
  themes: {
    html: ['./src/themes/**/index.html'],
    css: ['./src/themes/**/*.scss']
  }
};

gulp.task('upload', function() {
  awsCredentials = JSON.parse(fs.readFileSync('./aws.json'))
  return gulp.src('build/**')
    .pipe(s3(awsCredentials, {
      uploadPath: "/podigee-podcast-player/",
      headers: {'x-amz-acl': 'public-read'}
    }))
})

gulp.task('stylesheets', function() {
  return gulp.src(paths.main_stylesheet)
    .pipe(sass({style: 'compressed'}))
    .pipe(gulp.dest('./build/stylesheets'))
    .pipe(gzip())
    .pipe(gulp.dest('./build/stylesheets'))
    .pipe(connect.reload())
})

gulp.task('javascripts', function() {
  gulp.src(paths.main_javascript, {read: false})
    .pipe(browserify({
      transform: ['coffeeify'],
      extensions: ['.coffee']
    }))
    //.pipe(uglify())
    .pipe(rename('podigee-podcast-player.js'))
    .pipe(gulp.dest('./build/javascripts'))
    .pipe(gzip())
    .pipe(gulp.dest('./build/javascripts'))
    .pipe(connect.reload())
})

gulp.task('html', function() {
  gulp.src(paths.html)
    .pipe(gulp.dest('./build'))
    .pipe(connect.reload())
})

gulp.task('images', function() {
  gulp.src(paths.images)
    .pipe(gulp.dest('./build/images'))
    .pipe(connect.reload())
})

gulp.task('fonts', function() {
  gulp.src(paths.fonts)
    .pipe(gulp.dest('./build/fonts'))
    .pipe(connect.reload())
})

gulp.task('themes', function() {
  gulp.src(paths.themes.html)
    .pipe(gulp.dest('./build/themes'))
    .pipe(connect.reload())

  gulp.src(paths.themes.css)
    .pipe(sass({style: 'compressed'}))
    .pipe(gulp.dest('./build/themes'))
    .pipe(connect.reload())
})

gulp.task('default', ['stylesheets', 'javascripts', 'html', 'images', 'fonts', 'themes'])

gulp.task('watch', function() {
  // Watch .scss files
  gulp.watch(paths.stylesheets, ['stylesheets'])
  // Watch .js files
  gulp.watch(paths.javascripts, ['javascripts'])
  // Watch .html files
  gulp.watch(paths.html, ['html'])
  // Watch images files
  gulp.watch(paths.images, ['images'])
  // Watch theme files
  gulp.watch(paths.themes.html, ['themes'])
  gulp.watch(paths.themes.css, ['themes'])
})

gulp.task('connect', function() {
  connect.server({
    root: [__dirname],
    livereload: true
  });
});

// Serve
gulp.task('serve', ['default', 'connect', 'watch']);
<commit_msg>update gulpfile settings<commit_after>var gulp = require('gulp'),
    gutil = require('gulp-util'),
    sass = require('gulp-sass'),
    coffee = require('gulp-coffee'),
    watch = require('gulp-watch'),
    uglify = require('gulp-uglify'),
    concat = require('gulp-concat'),
    browserify = require('gulp-browserify'),
    rename = require('gulp-rename'),
    connect = require('gulp-connect');
    gzip = require('gulp-gzip');
    fs = require('fs');
    s3 = require('gulp-s3');

var dest = './dist';
var paths = {
  main_stylesheet: ['./src/stylesheets/app.scss'],
  stylesheets: ['./src/stylesheets/*.scss'],
  main_javascript: ['./src/javascripts/app.coffee'],
  javascripts: ['./src/javascripts/**/*.coffee'],
  html: ['./src/html/podigee-podcast-player.html', './src/html/embed-example.html'],
  images: ['./src/images/**'],
  fonts: ['./vendor/fonts/**'],
  themes: {
    html: ['./src/themes/**/index.html'],
    css: ['./src/themes/**/*.scss']
  }
};

gulp.task('upload', function() {
  awsCredentials = JSON.parse(fs.readFileSync('./aws.json'))
  return gulp.src('build/**')
    .pipe(s3(awsCredentials, {
      uploadPath: "/podcast-player/",
      headers: {'x-amz-acl': 'public-read'}
    }))
})

gulp.task('stylesheets', function() {
  return gulp.src(paths.main_stylesheet)
    .pipe(sass({style: 'compressed'}))
    .pipe(gulp.dest('./build/stylesheets'))
    .pipe(gzip())
    .pipe(gulp.dest('./build/stylesheets'))
    .pipe(connect.reload())
})

gulp.task('javascripts', function() {
  gulp.src(paths.main_javascript, {read: false})
    .pipe(browserify({
      transform: ['coffeeify'],
      extensions: ['.coffee']
    }))
    .pipe(uglify())
    .pipe(rename('podigee-podcast-player.js'))
    .pipe(gulp.dest('./build/javascripts'))
    .pipe(gzip())
    .pipe(gulp.dest('./build/javascripts'))
    .pipe(connect.reload())
})

gulp.task('html', function() {
  gulp.src(paths.html)
    .pipe(gulp.dest('./build'))
    .pipe(connect.reload())
})

gulp.task('images', function() {
  gulp.src(paths.images)
    .pipe(gulp.dest('./build/images'))
    .pipe(connect.reload())
})

gulp.task('fonts', function() {
  gulp.src(paths.fonts)
    .pipe(gulp.dest('./build/fonts'))
    .pipe(connect.reload())
})

gulp.task('themes', function() {
  gulp.src(paths.themes.html)
    .pipe(gulp.dest('./build/themes'))
    .pipe(connect.reload())

  gulp.src(paths.themes.css)
    .pipe(sass({style: 'compressed'}))
    .pipe(gulp.dest('./build/themes'))
    .pipe(connect.reload())
})

gulp.task('default', ['stylesheets', 'javascripts', 'html', 'images', 'fonts', 'themes'])

gulp.task('watch', function() {
  // Watch .scss files
  gulp.watch(paths.stylesheets, ['stylesheets'])
  // Watch .js files
  gulp.watch(paths.javascripts, ['javascripts'])
  // Watch .html files
  gulp.watch(paths.html, ['html'])
  // Watch images files
  gulp.watch(paths.images, ['images'])
  // Watch theme files
  gulp.watch(paths.themes.html, ['themes'])
  gulp.watch(paths.themes.css, ['themes'])
})

gulp.task('connect', function() {
  connect.server({
    host: '0.0.0.0',
    root: [__dirname],
    livereload: true
  });
});

// Serve
gulp.task('serve', ['default', 'connect', 'watch']);
<|endoftext|>


<commit_before>if (typeof(Alchemy) === 'undefined') {
	var Alchemy = {};
}

(function ($) {

	$.extend(Alchemy, {

		getOverlaySpinner : function (options) {
			var defaults = {
				x: '400',
				y: '300'
			};
			var settings = $.extend({}, defaults, options);
			var $spinner_container = $('
').css({width: settings.x, height: settings.y});
			var $spinner = $('');
			$spinner_container.append($spinner);
			$spinner.css({
				position: 'absolute',
				width: 32,
				height: 32,
				left: '50%',
				top: '50%',
				marginLeft: '-16px',
				marginTop: '-16px'
			});
			return $spinner_container;
		},

		AjaxErrorHandler : function($dialog, status, textStatus, errorThrown) {
			var $div = $('
');
			var $errorDiv = $('
');
			$dialog.html($div);
			$div.append($errorDiv);
			if (status === 0) {
				$errorDiv.append('
The server does not respond!
');
				$errorDiv.append('
Please start server and try again.
');
			} else {
				$errorDiv.append('
'+errorThrown+' ('+status+')
');
				$errorDiv.append('
Please check log and try again.
');
			}
		},

		ToolbarButton : function(options) {
			var $btn = $('

'), $lnk;
			if (options.buttonId) $btn.attr({'id': options.buttonId});
			$lnk = $('');
			$lnk.click(options.onClick);
			$lnk.append('');
			$btn.append($lnk);
			$btn.append('
'+options.buttonLabel+'');
			return $btn;
		},

		openConfirmWindow : function (options) {
			var $confirmation = $('

');
			$confirmation.appendTo('body');
			$confirmation.html('
'+options.message+'
');
			Alchemy.ConfirmationWindow = $confirmation.dialog({
				resizable: false,
				minHeight: 100,
				minWidth: 300,
				modal: true,
				title: options.title,
				show: "fade",
				hide: "fade",
				buttons: [
					{
						text: options.cancelLabel,
						click: function() {
							$(this).dialog("close");
						}
					},
					{
						text: options.okLabel,
						click: function() {
							$(this).dialog("close");
							options.okCallback();
						}
					}
				],
				open: function () {
					Alchemy.ButtonObserver('#alchemyConfirmation .button');
				},
				close: function() {
					$('#alchemyConfirmation').remove();
				}
			});
		},

		confirmToDeleteWindow : function (url, title, message, okLabel, cancelLabel) {
			var $confirmation = $('

');
			$confirmation.appendTo('body');
			$confirmation.html('
'+message+'
');
			Alchemy.ConfirmationWindow = $confirmation.dialog({
				resizable: false,
				minHeight: 100,
				minWidth: 300,
				modal: true,
				title: title,
				show: "fade",
				hide: "fade",
				buttons: [
					{
						text: cancelLabel,
						click: function() {
							$(this).dialog("close");
						}
					},
					{
						text: okLabel,
						click: function() {
							$(this).dialog("close");
							$.ajax({
								url: url,
								type: 'DELETE'
							});
						}
					}
				],
				open: function () {
					Alchemy.ButtonObserver('#alchemyConfirmation .button');
				},
				close: function() {
					$('#alchemyConfirmation').remove();
				}
			});
		},

		openWindow : function (action_url, title, size_x, size_y, resizable, modal, overflow) {
			overflow == undefined ? overflow = false: overflow = overflow;
			if (size_x === 'fullscreen') {
				size_x = $(window).width() - 50;
				size_y = $(window).height() - 50;
			}
			var $dialog = $('

');
			$dialog.appendTo('body');
			$dialog.html(Alchemy.getOverlaySpinner({x: size_x === 'auto' ? 400 : size_x, y: size_y === 'auto' ? 300 : size_y}));
			Alchemy.CurrentWindow = $dialog.dialog({
				modal: modal,
				minWidth: size_x === 'auto' ? 400 : size_x,
				minHeight: size_y === 'auto' ? 300 : size_y,
				title: title,
				resizable: resizable,
				show: "fade",
				hide: "fade",
				width: size_x,
				open: function (event, ui) {
					$.ajax({
						url: action_url,
						success: function(data, textStatus, XMLHttpRequest) {
							$dialog.html(data);
							$dialog.css({overflow: overflow ? 'visible' : 'auto'});
							$dialog.dialog('widget').css({overflow: overflow ? 'visible' : 'hidden'});
							if (size_x === 'auto') {
								$dialog.dialog('widget').css({
									left: (($(window).width() / 2) - ($dialog.width() / 2))
								});
							}
							if (size_y === 'auto') {
								$dialog.dialog('widget').css({
									top: ($(window).height() - $dialog.dialog('widget').height()) / 2
								});
							}
							Alchemy.SelectBox('#alchemyOverlay select');
							Alchemy.Datepicker('#alchemyOverlay input.date, #alchemyOverlay input[type="date"]');
							Alchemy.ButtonObserver('#alchemyOverlay .button');
						},
						error: function(XMLHttpRequest, textStatus, errorThrown) {
							Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
						},
						complete: function(jqXHR, textStatus) {
							Alchemy.enableButton('.button.disabled');
						}
					});
				},
				beforeClose: function() {
					$(".sb.open").triggerAll("close");
				},
				close: function () {
					$dialog.remove();
				}
			});
		},

		closeCurrentWindow : function() {
			if (Alchemy.CurrentWindow) {
				Alchemy.CurrentWindow.dialog('close');
				Alchemy.CurrentWindow = null;
			} else {
				$('#alchemyOverlay').dialog('close');
			}
			return true;
		},

		zoomImage : function(url, title, width, height) {
			var window_height = height;
			var window_width = width;
			var $doc_width = $(window).width();
			var $doc_height = $(window).height();
			if (width > $doc_width) {
				window_width = $doc_width - 50;
			}
			if (height > $doc_height) {
				window_height = $doc_height - 50;
			}
			var $dialog = $('

');
			$dialog.appendTo('body');
			$dialog.html(Alchemy.getOverlaySpinner({x: width, y: height}));
			$dialog.dialog({
				modal: false,
				minWidth: window_width < 320 ? 320 : window_width,
				minHeight: window_height < 240 ? 240 : window_height,
				title: title,
				show: "fade",
				hide: "fade",
				open: function (event, ui) {
					$.ajax({
						url: url,
						success: function(data, textStatus, XMLHttpRequest) {
							$dialog.html(data);
						},
						error: function(XMLHttpRequest, textStatus, errorThrown) {
							Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
						}
					});
				},
				close: function () {
					$dialog.remove();
				}
			});
			return false;
		},

		openTrashWindow : function (page_id, title) {
			var size_x = 380, size_y = 270;
			if (size_x === 'fullscreen') {
				size_x = $(window).width() - 50;
				size_y = $(window).height() - 50;
			}
			var $dialog = $('

');
			$dialog.appendTo('body');
			$dialog.html(Alchemy.getOverlaySpinner({x: size_x, y: size_y}));

			Alchemy.trashWindow = $dialog.dialog({
				modal: false,
				width: 380,
				minHeight: 450,
				maxHeight: $(window).height() - 50,
				title: title,
				resizable: false,
				show: "fade",
				hide: "fade",
				open: function (event, ui) {
					$.ajax({
						url: Alchemy.routes.admin_trash_path(page_id),
						success: function(data, textStatus, XMLHttpRequest) {
							$dialog.html(data);
							// Need this for DragnDrop elements into elements window.
							// Badly this is screwing up maxHeight option
							$dialog.css({overflow: 'visible'}).dialog('widget').css({overflow: 'visible'});
						},
						error: function(XMLHttpRequest, textStatus, errorThrown) {
							Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
						}
					});
				},
				close: function () {
					$dialog.remove();
				}
			});
		},

		refreshTrashWindow: function(page_id) {
			if ($('#alchemyTrashWindow').length > 0) {
				$('#alchemyTrashWindow').html(Alchemy.getOverlaySpinner({x: 380, y: 270}));
				$.get(Alchemy.routes.admin_trash_path(page_id), function(html) {
					$('#alchemyTrashWindow').html(html);
				});
			}
		}

	});
})(jQuery);
<commit_msg>fixing button enabling after window load<commit_after>if (typeof(Alchemy) === 'undefined') {
	var Alchemy = {};
}

(function ($) {

	$.extend(Alchemy, {

		getOverlaySpinner : function (options) {
			var defaults = {
				x: '400',
				y: '300'
			};
			var settings = $.extend({}, defaults, options);
			var $spinner_container = $('
').css({width: settings.x, height: settings.y});
			var $spinner = $('');
			$spinner_container.append($spinner);
			$spinner.css({
				position: 'absolute',
				width: 32,
				height: 32,
				left: '50%',
				top: '50%',
				marginLeft: '-16px',
				marginTop: '-16px'
			});
			return $spinner_container;
		},

		AjaxErrorHandler : function($dialog, status, textStatus, errorThrown) {
			var $div = $('
');
			var $errorDiv = $('
');
			$dialog.html($div);
			$div.append($errorDiv);
			if (status === 0) {
				$errorDiv.append('
The server does not respond!
');
				$errorDiv.append('
Please start server and try again.
');
			} else {
				$errorDiv.append('
'+errorThrown+' ('+status+')
');
				$errorDiv.append('
Please check log and try again.
');
			}
		},

		ToolbarButton : function(options) {
			var $btn = $('

'), $lnk;
			if (options.buttonId) $btn.attr({'id': options.buttonId});
			$lnk = $('');
			$lnk.click(options.onClick);
			$lnk.append('');
			$btn.append($lnk);
			$btn.append('
'+options.buttonLabel+'');
			return $btn;
		},

		openConfirmWindow : function (options) {
			var $confirmation = $('

');
			$confirmation.appendTo('body');
			$confirmation.html('
'+options.message+'
');
			Alchemy.ConfirmationWindow = $confirmation.dialog({
				resizable: false,
				minHeight: 100,
				minWidth: 300,
				modal: true,
				title: options.title,
				show: "fade",
				hide: "fade",
				buttons: [
					{
						text: options.cancelLabel,
						click: function() {
							$(this).dialog("close");
						}
					},
					{
						text: options.okLabel,
						click: function() {
							$(this).dialog("close");
							options.okCallback();
						}
					}
				],
				open: function () {
					Alchemy.ButtonObserver('#alchemyConfirmation .button');
				},
				close: function() {
					$('#alchemyConfirmation').remove();
				}
			});
		},

		confirmToDeleteWindow : function (url, title, message, okLabel, cancelLabel) {
			var $confirmation = $('

');
			$confirmation.appendTo('body');
			$confirmation.html('
'+message+'
');
			Alchemy.ConfirmationWindow = $confirmation.dialog({
				resizable: false,
				minHeight: 100,
				minWidth: 300,
				modal: true,
				title: title,
				show: "fade",
				hide: "fade",
				buttons: [
					{
						text: cancelLabel,
						click: function() {
							$(this).dialog("close");
						}
					},
					{
						text: okLabel,
						click: function() {
							$(this).dialog("close");
							$.ajax({
								url: url,
								type: 'DELETE'
							});
						}
					}
				],
				open: function () {
					Alchemy.ButtonObserver('#alchemyConfirmation .button');
				},
				close: function() {
					$('#alchemyConfirmation').remove();
				}
			});
		},

		openWindow : function (action_url, title, size_x, size_y, resizable, modal, overflow) {
			overflow == undefined ? overflow = false: overflow = overflow;
			if (size_x === 'fullscreen') {
				size_x = $(window).width() - 50;
				size_y = $(window).height() - 50;
			}
			var $dialog = $('

');
			$dialog.appendTo('body');
			$dialog.html(Alchemy.getOverlaySpinner({x: size_x === 'auto' ? 400 : size_x, y: size_y === 'auto' ? 300 : size_y}));
			Alchemy.CurrentWindow = $dialog.dialog({
				modal: modal,
				minWidth: size_x === 'auto' ? 400 : size_x,
				minHeight: size_y === 'auto' ? 300 : size_y,
				title: title,
				resizable: resizable,
				show: "fade",
				hide: "fade",
				width: size_x,
				open: function (event, ui) {
					$.ajax({
						url: action_url,
						success: function(data, textStatus, XMLHttpRequest) {
							$dialog.html(data);
							$dialog.css({overflow: overflow ? 'visible' : 'auto'});
							$dialog.dialog('widget').css({overflow: overflow ? 'visible' : 'hidden'});
							if (size_x === 'auto') {
								$dialog.dialog('widget').css({
									left: (($(window).width() / 2) - ($dialog.width() / 2))
								});
							}
							if (size_y === 'auto') {
								$dialog.dialog('widget').css({
									top: ($(window).height() - $dialog.dialog('widget').height()) / 2
								});
							}
							Alchemy.SelectBox('#alchemyOverlay select');
							Alchemy.Datepicker('#alchemyOverlay input.date, #alchemyOverlay input[type="date"]');
							Alchemy.ButtonObserver('#alchemyOverlay .button');
						},
						error: function(XMLHttpRequest, textStatus, errorThrown) {
							Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
						},
						complete: function(jqXHR, textStatus) {
							Alchemy.enableButton('.button');
						}
					});
				},
				beforeClose: function() {
					$(".sb.open").triggerAll("close");
				},
				close: function () {
					$dialog.remove();
				}
			});
		},

		closeCurrentWindow : function() {
			if (Alchemy.CurrentWindow) {
				Alchemy.CurrentWindow.dialog('close');
				Alchemy.CurrentWindow = null;
			} else {
				$('#alchemyOverlay').dialog('close');
			}
			return true;
		},

		zoomImage : function(url, title, width, height) {
			var window_height = height;
			var window_width = width;
			var $doc_width = $(window).width();
			var $doc_height = $(window).height();
			if (width > $doc_width) {
				window_width = $doc_width - 50;
			}
			if (height > $doc_height) {
				window_height = $doc_height - 50;
			}
			var $dialog = $('

');
			$dialog.appendTo('body');
			$dialog.html(Alchemy.getOverlaySpinner({x: width, y: height}));
			$dialog.dialog({
				modal: false,
				minWidth: window_width < 320 ? 320 : window_width,
				minHeight: window_height < 240 ? 240 : window_height,
				title: title,
				show: "fade",
				hide: "fade",
				open: function (event, ui) {
					$.ajax({
						url: url,
						success: function(data, textStatus, XMLHttpRequest) {
							$dialog.html(data);
						},
						error: function(XMLHttpRequest, textStatus, errorThrown) {
							Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
						}
					});
				},
				close: function () {
					$dialog.remove();
				}
			});
			return false;
		},

		openTrashWindow : function (page_id, title) {
			var size_x = 380, size_y = 270;
			if (size_x === 'fullscreen') {
				size_x = $(window).width() - 50;
				size_y = $(window).height() - 50;
			}
			var $dialog = $('

');
			$dialog.appendTo('body');
			$dialog.html(Alchemy.getOverlaySpinner({x: size_x, y: size_y}));

			Alchemy.trashWindow = $dialog.dialog({
				modal: false,
				width: 380,
				minHeight: 450,
				maxHeight: $(window).height() - 50,
				title: title,
				resizable: false,
				show: "fade",
				hide: "fade",
				open: function (event, ui) {
					$.ajax({
						url: Alchemy.routes.admin_trash_path(page_id),
						success: function(data, textStatus, XMLHttpRequest) {
							$dialog.html(data);
							// Need this for DragnDrop elements into elements window.
							// Badly this is screwing up maxHeight option
							$dialog.css({overflow: 'visible'}).dialog('widget').css({overflow: 'visible'});
						},
						error: function(XMLHttpRequest, textStatus, errorThrown) {
							Alchemy.AjaxErrorHandler($dialog, XMLHttpRequest.status, textStatus, errorThrown);
						}
					});
				},
				close: function () {
					$dialog.remove();
				}
			});
		},

		refreshTrashWindow: function(page_id) {
			if ($('#alchemyTrashWindow').length > 0) {
				$('#alchemyTrashWindow').html(Alchemy.getOverlaySpinner({x: 380, y: 270}));
				$.get(Alchemy.routes.admin_trash_path(page_id), function(html) {
					$('#alchemyTrashWindow').html(html);
				});
			}
		}

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


<commit_before>/* globals __dirname */
/* globals process */
 /* eslint-disable no-invalid-this */

const gulp = require('gulp');
const nodemon = require('gulp-nodemon');
const plumber = require('gulp-plumber');
const livereload = require('gulp-livereload');
const mocha = require('gulp-mocha');
const gulpsync = require('gulp-sync')(gulp);
const eslint = require('gulp-eslint');
const istanbul = require('gulp-istanbul');
const pm2 = require('pm2');

gulp.task('develop', function() {
  livereload.listen();
  nodemon({
    script: 'app.js',
    ext: 'js coffee jade',
    stdout: false,
  }).on('readable', function() {
    this.stdout.on('data', function(chunk) {
      if (/^Express server listening on port/.test(chunk)) {
        livereload.changed(__dirname);
      }
    });
    this.stdout.pipe(process.stdout);
    this.stderr.pipe(process.stderr);
  });
});

gulp.task('default', [
  'develop',
]);

gulp.task('lint-fix', () => {
  return gulp.src(['**/*.js', '!node_modules/**', '!coverage/**'])
    .pipe(plumber())
    .pipe(eslint({ fix: true }))
    .pipe(eslint.format())
    .pipe(gulp.dest('.'));
});

gulp.task('pre-test', () => {
  return gulp.src([
    './app.js',
    './app/**/*.js',
    './config/*.js',
    './data/*.js',
    './data/**/*.js',
    './db/*.js',
    './models/*.js',
    '!./node_modules/',
    '!./public/',
    '!./tests/',
    '!./coverage/',
    ])
    .pipe(istanbul({
      includeUntested: true,
    }))
    .pipe(istanbul.hookRequire());
});

gulp.task('test:lint', () => {
  return gulp.src(['**/*.js', '!./node_modules/', '!coverage/**'])
    .pipe(plumber())
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
});

gulp.task('test:unit', () => {
  return gulp.src([
    './tests/unit/**/*.js',
    './tests/integration/**/*.js',
    ], { read: false })
    .pipe(plumber())
    .pipe(mocha({
      colors: false,
      reporter: 'nyan',
    }))
    .on('error', (err) => {
      process.exit(2);
    })
    .pipe(istanbul.writeReports());
});

gulp.task('test', gulpsync.sync([
  'pre-test',
  'test:lint',
  'test:unit',
]));

gulp.task('serve', () => {
  pm2.connect(false, () => {
    pm2.start({
      name: 'app',
      script: './node_modules/gulp/bin/gulp.js',
      args: 'develop',
      force: true,
    }, (err, apps) => {
      pm2.disconnect();
      if (err) {
        process.exit(2);
      }
    });
  });
});
<commit_msg>Extract separate Integration tests gulp task.<commit_after>/* globals __dirname */
/* globals process */
 /* eslint-disable no-invalid-this */

const gulp = require('gulp');
const nodemon = require('gulp-nodemon');
const plumber = require('gulp-plumber');
const livereload = require('gulp-livereload');
const mocha = require('gulp-mocha');
const gulpsync = require('gulp-sync')(gulp);
const eslint = require('gulp-eslint');
const istanbul = require('gulp-istanbul');
const pm2 = require('pm2');

gulp.task('develop', function() {
  livereload.listen();
  nodemon({
    script: 'app.js',
    ext: 'js coffee jade',
    stdout: false,
  }).on('readable', function() {
    this.stdout.on('data', function(chunk) {
      if (/^Express server listening on port/.test(chunk)) {
        livereload.changed(__dirname);
      }
    });
    this.stdout.pipe(process.stdout);
    this.stderr.pipe(process.stderr);
  });
});

gulp.task('default', [
  'develop',
]);

gulp.task('lint-fix', () => {
  return gulp.src(['**/*.js', '!node_modules/**', '!coverage/**'])
    .pipe(plumber())
    .pipe(eslint({ fix: true }))
    .pipe(eslint.format())
    .pipe(gulp.dest('.'));
});

gulp.task('pre-test', () => {
  return gulp.src([
    './app.js',
    './app/**/*.js',
    './config/*.js',
    './data/*.js',
    './data/**/*.js',
    './db/*.js',
    './models/*.js',
    '!./node_modules/',
    '!./public/',
    '!./tests/',
    '!./coverage/',
    ])
    .pipe(istanbul({
      includeUntested: true,
    }))
    .pipe(istanbul.hookRequire());
});

gulp.task('test:lint', () => {
  return gulp.src(['**/*.js', '!./node_modules/', '!coverage/**'])
    .pipe(plumber())
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
});

gulp.task('test:unit', () => {
  return gulp.src('./tests/unit/**/*.js', { read: false })
    .pipe(plumber())
    .pipe(mocha({
      colors: false,
      reporter: 'nyan',
    }))
    .on('error', (err) => {
      process.exit(2);
    })
    .pipe(istanbul.writeReports());
});

gulp.task('test:integration', () => {
  return gulp.src('./tests/integration/**/*.js', { read: false })
    .pipe(plumber())
    .pipe(mocha({
      colors: false,
      reporter: 'nyan',
    }))
    .on('error', (err) => {
      process.exit(2);
    })
    .pipe(istanbul.writeReports());
});

gulp.task('test', gulpsync.sync([
  'pre-test',
  'test:lint',
  'test:unit',
  'test:integration',
]));

gulp.task('serve', () => {
  pm2.connect(false, () => {
    pm2.start({
      name: 'app',
      script: './node_modules/gulp/bin/gulp.js',
      args: 'develop',
      force: true,
    }, (err, apps) => {
      pm2.disconnect();
      if (err) {
        process.exit(2);
      }
    });
  });
});
<|endoftext|>


<commit_before>angular.module("Directory.audioFiles.controllers", ['ngPlayer'])
.controller("AudioFileCtrl", ['$scope', '$timeout', '$modal', '$q', 'Player', 'Me', 'TimedText', 'AudioFile', '$http', function($scope, $timeout, $modal, $q, Player, Me, TimedText, AudioFile, $http) {
  $scope.fileUrl = $scope.audioFile.url;

  $scope.downloadLinks = [
      {
        text: 'Text Format',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.txt"
      },
      {
        text: 'SRT Format (Captions)',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.srt"
      },
      {
        text: 'XML Format (W3C Transcript)',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.xml"
      },
      {
        text: 'JSON Format',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.json"
      }
  ];
  $scope.item.formattedTitle = $scope.item.title.replace("'", "'");

  $scope.embedCodesModal = $modal({template: '/assets/items/embed_codes.html', persist: true, show: false, backdrop: 'static', scope: $scope, modalClass: 'embed-codes-modal'});

  $scope.showEmbedCodesModal = function() {
    $q.when($scope.embedCodesModal).then(function(modalEl) {
      modalEl.modal('show');
    });
  };

  $scope.play = function () {
    $scope.audioFile = new AudioFile($scope.audioFile);
    $scope.audioFile.itemId = $scope.item.id;
    $scope.audioFile.createListen();
    Player.play($scope.fileUrl);
    mixpanel.track("Audio play",
      {"Item": $scope.item.title,
       "Collection": $scope.collection.title});
  }

  $scope.player = Player;

  $scope.isPlaying = function () {
    return $scope.isLoaded() && !Player.paused();
  }

  $scope.isLoaded = function () {
    return Player.nowPlayingUrl() == $scope.fileUrl;
  }

  $scope.$on('transcriptSeek', function(event, time) {
    event.stopPropagation();
    $scope.play();
    $scope.player.seekTo(time);
  });

  Me.authenticated(function (me) {

    if (me.canEdit($scope.item) && $scope.item.imageFiles.slice(-1)[0]) {
      $scope.downloadLinks.unshift({
        text: 'Image File',
        target: '_self',
        href: $scope.item.imageFiles.slice(-1)[0].url.full[0]
      });
    }

    if (me.canEdit($scope.item)) {
      $scope.downloadLinks.unshift({
        text: 'Audio File',
        target: '_self',
        href: $scope.audioFile.original
      });
    }

    $scope.saveText = function(text) {
      var tt = new TimedText(text);
      tt.update();
    };

    $scope.orderTranscript = function () {
      $scope.audioFile = new AudioFile($scope.audioFile);
      $scope.audioFile.itemId = $scope.item.id;
      $scope.orderTranscriptModal = $modal({template: "/assets/audio_files/order_transcript.html", persist: false, show: true, backdrop: 'static', scope: $scope, modalClass: 'order-transcript-modal'});
      return;
    };

    $scope.addToAmara = function () {
      $scope.audioFile = new AudioFile($scope.audioFile);
      $scope.audioFile.itemId = $scope.item.id;
      var filename = $scope.audioFile.filename;
      return $scope.audioFile.addToAmara(me).then( function (task) {

        var msg = '"' + filename + '" added. ' +
        'View or ' +
        'edit the transcript on Amara.';

        var alert = new Alert();
        alert.category = 'add_to_amara';
        alert.status   = 'Added';
        alert.progress = 1;
        alert.message  = msg;
        alert.add();
      });
    };

    $scope.showOrderTranscript = function () {
      return (new AudioFile($scope.audioFile)).canOrderTranscript(me);
    };

    $scope.showTranscriptOrdered = function () {
      return (new AudioFile($scope.audioFile)).isTranscriptOrdered();
    };

    $scope.showSendToAmara = function () {
      return (new AudioFile($scope.audioFile)).canSendToAmara(me);
    };

    $scope.showOnAmara = function () {
      return (new AudioFile($scope.audioFile)).isOnAmara();
    };

    $scope.addToAmaraTask = function () {
      return (new AudioFile($scope.audioFile)).taskForType('add_to_amara');
    };

  });

}])
.controller("OrderTranscriptFormCtrl", ['$scope', '$window', '$q', 'Me', 'AudioFile', function($scope, $window, $q, Me, AudioFile) {

  Me.authenticated(function (me) {

    $scope.length = function() {
      var mins = (new AudioFile($scope.audioFile)).durationMinutes();
      var label = "minutes";
      if (mins == 1) { label = "minute"; }
      return (mins + ' ' + label);
    }

    $scope.price = function() {
      return (new AudioFile($scope.audioFile)).transcribePrice();
    }

    $scope.submit = function () {
      $scope.audioFile.orderTranscript(me);
      $scope.clear();
      return;
    }

  });

  $scope.clear = function () {
    $scope.hideOrderTranscriptModal();
  }

  $scope.hideOrderTranscriptModal = function () {
    $q.when($scope.orderTranscriptModal).then( function (modalEl) {
      modalEl.modal('hide');
    });
  }

}])
.controller("OrderPremiumTranscriptFormCtrl", ['$scope', '$window', '$q', '$modal', 'Me', 'AudioFile', function($scope, $window, $q, $modal, Me, AudioFile) {

  Me.authenticated(function (me) {

    // this event fired by account controller on CC form submit
    // if the onDemandRequiresCC var is true (set below)
    $scope.$on('userHasValidCC', function(event, audioFile) {
      $scope.audioFile.orderPremiumTranscript(me).then(function(respTask) {
        $scope.$emit('premiumTranscriptOrdered', $scope.audioFile);
      }).
      catch(function(data) {
        console.log("caught error on orderPremiumTranscript", data);
      });
    });

    // handle 'submit' button click on Order Premium Transcript form.
    $scope.submit = function () {

      // check if user has CC on file. If not, prompt for one before ordering.
      if (!me.hasCard) {
        $scope.clear();  // close window immediately.
        $scope.onDemandRequiresCC = true;
        $scope.orderPremiumCCModal = $modal({template: '/assets/account/credit_card_ondemand.html', persist: true, show: true, backdrop: 'static', scope: $scope});
        //track in Mixpanel
        mixpanel.track(
          "Ordered Premium Transcript",{
            "User": $scope.currentUser.name + ' ' + $scope.currentUser.email}
            );
      }
      else {
        $scope.audioFile.orderPremiumTranscript(me).then(function(respTask) {
          //console.log("then, got respTask: ", respTask);
          $scope.$emit('premiumTranscriptOrdered', $scope.audioFile);
        }).
        catch(function(data) {
          console.log("caught error on orderPremiumTranscript", data);
        });
      }

      // close window no matter what.
      $scope.clear();
    }

  });

  $scope.clear = function () {
    $scope.hideOrderPremiumTranscriptModal();
  }

  $scope.hideOrderPremiumTranscriptModal = function () {
    $q.when($scope.orderPremiumTranscriptModal).then( function (modalEl) {
      modalEl.modal('hide');
    });
  }

}])
.controller("PersistentPlayerCtrl", ["$scope", 'Player', function ($scope, Player) {
  $scope.player = Player;
  $scope.collapsed = false;

  $scope.collapse = function () {
    $scope.collapsed = !$scope.collapsed;
  };

}]);
<commit_msg>set audio.item title when clicking play button from audio_file controller #985<commit_after>angular.module("Directory.audioFiles.controllers", ['ngPlayer'])
.controller("AudioFileCtrl", ['$scope', '$timeout', '$modal', '$q', 'Player', 'Me', 'TimedText', 'AudioFile', '$http', function($scope, $timeout, $modal, $q, Player, Me, TimedText, AudioFile, $http) {
  $scope.fileUrl = $scope.audioFile.url;

  $scope.downloadLinks = [
      {
        text: 'Text Format',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.txt"
      },
      {
        text: 'SRT Format (Captions)',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.srt"
      },
      {
        text: 'XML Format (W3C Transcript)',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.xml"
      },
      {
        text: 'JSON Format',
        target: '_self',
        href: "/api/items/" + $scope.item.id + "/audio_files/" + $scope.audioFile.id + "/transcript.json"
      }
  ];
  $scope.item.formattedTitle = $scope.item.title.replace("'", "'");

  $scope.embedCodesModal = $modal({template: '/assets/items/embed_codes.html', persist: true, show: false, backdrop: 'static', scope: $scope, modalClass: 'embed-codes-modal'});

  $scope.showEmbedCodesModal = function() {
    $q.when($scope.embedCodesModal).then(function(modalEl) {
      modalEl.modal('show');
    });
  };

  $scope.play = function () {
    $scope.audioFile = new AudioFile($scope.audioFile);
    $scope.audioFile.itemId = $scope.item.id;
    $scope.audioFile.createListen();
    Player.play($scope.fileUrl, $scope.item.getTitle());
    mixpanel.track("Audio play",
      {"Item": $scope.item.title,
       "Collection": $scope.collection.title});
  }

  $scope.player = Player;

  $scope.isPlaying = function () {
    return $scope.isLoaded() && !Player.paused();
  }

  $scope.isLoaded = function () {
    return Player.nowPlayingUrl() == $scope.fileUrl;
  }

  $scope.$on('transcriptSeek', function(event, time) {
    event.stopPropagation();
    $scope.play();
    $scope.player.seekTo(time);
  });

  Me.authenticated(function (me) {

    if (me.canEdit($scope.item) && $scope.item.imageFiles.slice(-1)[0]) {
      $scope.downloadLinks.unshift({
        text: 'Image File',
        target: '_self',
        href: $scope.item.imageFiles.slice(-1)[0].url.full[0]
      });
    }

    if (me.canEdit($scope.item)) {
      $scope.downloadLinks.unshift({
        text: 'Audio File',
        target: '_self',
        href: $scope.audioFile.original
      });
    }

    $scope.saveText = function(text) {
      var tt = new TimedText(text);
      tt.update();
    };

    $scope.orderTranscript = function () {
      $scope.audioFile = new AudioFile($scope.audioFile);
      $scope.audioFile.itemId = $scope.item.id;
      $scope.orderTranscriptModal = $modal({template: "/assets/audio_files/order_transcript.html", persist: false, show: true, backdrop: 'static', scope: $scope, modalClass: 'order-transcript-modal'});
      return;
    };

    $scope.addToAmara = function () {
      $scope.audioFile = new AudioFile($scope.audioFile);
      $scope.audioFile.itemId = $scope.item.id;
      var filename = $scope.audioFile.filename;
      return $scope.audioFile.addToAmara(me).then( function (task) {

        var msg = '"' + filename + '" added. ' +
        'View or ' +
        'edit the transcript on Amara.';

        var alert = new Alert();
        alert.category = 'add_to_amara';
        alert.status   = 'Added';
        alert.progress = 1;
        alert.message  = msg;
        alert.add();
      });
    };

    $scope.showOrderTranscript = function () {
      return (new AudioFile($scope.audioFile)).canOrderTranscript(me);
    };

    $scope.showTranscriptOrdered = function () {
      return (new AudioFile($scope.audioFile)).isTranscriptOrdered();
    };

    $scope.showSendToAmara = function () {
      return (new AudioFile($scope.audioFile)).canSendToAmara(me);
    };

    $scope.showOnAmara = function () {
      return (new AudioFile($scope.audioFile)).isOnAmara();
    };

    $scope.addToAmaraTask = function () {
      return (new AudioFile($scope.audioFile)).taskForType('add_to_amara');
    };

  });

}])
.controller("OrderTranscriptFormCtrl", ['$scope', '$window', '$q', 'Me', 'AudioFile', function($scope, $window, $q, Me, AudioFile) {

  Me.authenticated(function (me) {

    $scope.length = function() {
      var mins = (new AudioFile($scope.audioFile)).durationMinutes();
      var label = "minutes";
      if (mins == 1) { label = "minute"; }
      return (mins + ' ' + label);
    }

    $scope.price = function() {
      return (new AudioFile($scope.audioFile)).transcribePrice();
    }

    $scope.submit = function () {
      $scope.audioFile.orderTranscript(me);
      $scope.clear();
      return;
    }

  });

  $scope.clear = function () {
    $scope.hideOrderTranscriptModal();
  }

  $scope.hideOrderTranscriptModal = function () {
    $q.when($scope.orderTranscriptModal).then( function (modalEl) {
      modalEl.modal('hide');
    });
  }

}])
.controller("OrderPremiumTranscriptFormCtrl", ['$scope', '$window', '$q', '$modal', 'Me', 'AudioFile', function($scope, $window, $q, $modal, Me, AudioFile) {

  Me.authenticated(function (me) {

    // this event fired by account controller on CC form submit
    // if the onDemandRequiresCC var is true (set below)
    $scope.$on('userHasValidCC', function(event, audioFile) {
      $scope.audioFile.orderPremiumTranscript(me).then(function(respTask) {
        $scope.$emit('premiumTranscriptOrdered', $scope.audioFile);
      }).
      catch(function(data) {
        console.log("caught error on orderPremiumTranscript", data);
      });
    });

    // handle 'submit' button click on Order Premium Transcript form.
    $scope.submit = function () {

      // check if user has CC on file. If not, prompt for one before ordering.
      if (!me.hasCard) {
        $scope.clear();  // close window immediately.
        $scope.onDemandRequiresCC = true;
        $scope.orderPremiumCCModal = $modal({template: '/assets/account/credit_card_ondemand.html', persist: true, show: true, backdrop: 'static', scope: $scope});
        //track in Mixpanel
        mixpanel.track(
          "Ordered Premium Transcript",{
            "User": $scope.currentUser.name + ' ' + $scope.currentUser.email}
            );
      }
      else {
        $scope.audioFile.orderPremiumTranscript(me).then(function(respTask) {
          //console.log("then, got respTask: ", respTask);
          $scope.$emit('premiumTranscriptOrdered', $scope.audioFile);
        }).
        catch(function(data) {
          console.log("caught error on orderPremiumTranscript", data);
        });
      }

      // close window no matter what.
      $scope.clear();
    }

  });

  $scope.clear = function () {
    $scope.hideOrderPremiumTranscriptModal();
  }

  $scope.hideOrderPremiumTranscriptModal = function () {
    $q.when($scope.orderPremiumTranscriptModal).then( function (modalEl) {
      modalEl.modal('hide');
    });
  }

}])
.controller("PersistentPlayerCtrl", ["$scope", 'Player', function ($scope, Player) {
  $scope.player = Player;
  $scope.collapsed = false;

  $scope.collapse = function () {
    $scope.collapsed = !$scope.collapsed;
  };

}]);
<|endoftext|>


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

'use strict';

// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var pagespeed = require('psi');
var reload = browserSync.reload;

var AUTOPREFIXER_BROWSERS = [
  'ie >= 8',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize Images
gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}));
});

// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
  return gulp.src([
    '.tmp/*',
    '!.tmp/*.html',
    'node_modules/apache-server-configs/dist/.htaccess'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}));
});

// Copy Web Fonts To Dist
gulp.task('fonts', function () {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest('dist/fonts'))
    .pipe($.size({title: 'fonts'}));
});

// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
      'app/styles/*.scss',
      'app/styles/**/*.css'
    ])
    .pipe($.plumber())
    .pipe($.changed('styles', {extension: '.scss'}))
    .pipe($.rubySass({
        style: 'expanded',
        precision: 10,
        compass: true
      })
      .on('error', console.error.bind(console))
    )
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/styles'))
    .pipe($.size({title: 'styles'}));
});

gulp.task('cmq', function () {
  gulp.src('./dist/styles/*.css')
    .pipe($.combineMediaQueries({
          log: true
    }))
    // Concatenate And Minify Styles
    .pipe($.csso())
    .pipe(gulp.dest('dist/styles'))
    .pipe($.size({title: 'Media Queries'}));
});

// Scan Your HTML For Assets & Optimize Them

gulp.task('html' ,function () {
  var assets = $.useref.assets({searchPath: '.tmp'});

  return gulp.src('.tmp/**/*.html')
    .pipe(assets)
    // Concatenate And Minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Remove Any Unused CSS
    // Note: If not using the Style Guide, you can delete it from
    // the next line to only include styles your project uses.
    .pipe($.if('*.css', $.uncss({
      html: [
        '.tmp/index.html',
        '.tmp/sign-up/index.html',
        '.tmp/privacy-policy/index.html',
        '.tmp/plans-pricing/index.html',
        '.tmp/terms-of-service/index.html'
      ],
      // CSS Selectors for UnCSS to ignore
      ignore: [
        /.navdrawer-container.open/,
        /.app-bar.open/,
        /.ibutton-*/,
        /#header/
      ]
    })))
    // Concatenate And Minify Styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Update Production Style Guide Paths
    //.pipe($.replace('components/components.css', 'components/main.min.css'))
    // Minify Any HTML
    .pipe($.if('*.html', $.minifyHtml()))
    // Output Files
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

gulp.task('html:inline', function () {
    return gulp.src('./.tmp/**/*.html')
        .pipe($.inlineSource('./app'))
        .pipe(gulp.dest('./dist'));
});

gulp.task('html:jekyll', function () {
    gulp.src(['./app/index.html', './app/_layouts/*.html', './app/_posts/*.{markdown,md}'])
        .pipe($.plumber())
        .pipe($.jekyll({
            source: './app/',
            destination: './.tmp/',
            bundleExec: true
        }))
        .pipe(gulp.dest('./dist/'));
});

// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist/*', '!dist/.git']));

// Watch Files For Changes & Reload
gulp.task('serve', ['html:jekyll','styles'], function () {
  browserSync({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: ['.tmp', 'app']
  });

  gulp.watch(['app/**/*.html'], ['html:jekyll', 'styles']);
  gulp.watch(['app/**/*.{html,md,markdown}'], ['html:jekyll', 'styles']);
  gulp.watch(['app/styles/**/*.{scss,css}'], ['styles']);
  gulp.watch(['app/scripts/**/*.js'], ['jshint']);
  gulp.watch(['app/images/**/*'], reload);
  gulp.watch(['.tmp/**'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
  browserSync({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist'
  });
});

// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
  runSequence('html:jekyll', 'styles', ['html', 'jshint', 'images', 'fonts', 'copy'], 'html:inline', 'cmq', cb);
});

// Run PageSpeed Insights
// Update `url` below to the public URL for your site
gulp.task('pagespeed', pagespeed.bind(null, {
  // By default, we use the PageSpeed Insights
  // free (no API key) tier. You can use a Google
  // Developer API key if you have one. See
  // http://goo.gl/RkN0vE for info key: 'YOUR_API_KEY'
  url: 'http://getroadmap.github.io/roadmap-site/',
  strategy: 'mobile'
}));

gulp.task('bump:major', function () {
  gulp.src(['./package.json'])
    .pipe($.bump({type:'major'}))
    .pipe(gulp.dest('./'));
});

gulp.task('bump:minor', function () {
  gulp.src(['./bower.json', './package.json'])
    .pipe($.bump({type:'minor'}))
    .pipe(gulp.dest('./'));
});

gulp.task('bump:patch', function () {
  gulp.src(['./bower.json', './package.json'])
    .pipe($.bump({type:'patch'}))
    .pipe(gulp.dest('./'));
});

// Load custom tasks from the `tasks` directory
try { require('require-dir')('tasks'); } catch (err) {}
<commit_msg>update gulp process for customers<commit_after>/**
 *
 *  Web Starter Kit
 *  Copyright 2014 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

'use strict';

// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var pagespeed = require('psi');
var reload = browserSync.reload;

var AUTOPREFIXER_BROWSERS = [
  'ie >= 8',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src('app/scripts/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize Images
gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}));
});

// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
  return gulp.src([
    '.tmp/*',
    '!.tmp/*.html',
    'node_modules/apache-server-configs/dist/.htaccess'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}));
});

// Copy Web Fonts To Dist
gulp.task('fonts', function () {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest('dist/fonts'))
    .pipe($.size({title: 'fonts'}));
});

// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
      'app/styles/*.scss',
      'app/styles/**/*.css'
    ])
    .pipe($.plumber())
    .pipe($.changed('styles', {extension: '.scss'}))
    .pipe($.rubySass({
        style: 'expanded',
        precision: 10,
        compass: true
      })
      .on('error', console.error.bind(console))
    )
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/styles'))
    .pipe($.size({title: 'styles'}));
});

gulp.task('cmq', function () {
  gulp.src('./dist/styles/*.css')
    .pipe($.combineMediaQueries({
          log: true
    }))
    // Concatenate And Minify Styles
    .pipe($.csso())
    .pipe(gulp.dest('dist/styles'))
    .pipe($.size({title: 'Media Queries'}));
});

// Scan Your HTML For Assets & Optimize Them

gulp.task('html' ,function () {
  var assets = $.useref.assets({searchPath: '.tmp'});

  return gulp.src('.tmp/**/*.html')
    .pipe(assets)
    // Concatenate And Minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Remove Any Unused CSS
    // Note: If not using the Style Guide, you can delete it from
    // the next line to only include styles your project uses.
    .pipe($.if('*.css', $.uncss({
      html: [
        '.tmp/index.html',
        '.tmp/sign-up/index.html',
        '.tmp/privacy-policy/index.html',
        '.tmp/plans-pricing/index.html',
        '.tmp/terms-of-service/index.html'
      ],
      // CSS Selectors for UnCSS to ignore
      ignore: [
        /.navdrawer-container.open/,
        /.app-bar.open/,
        /.ibutton-*/,
        /#header/
      ]
    })))
    // Concatenate And Minify Styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.csso()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Update Production Style Guide Paths
    //.pipe($.replace('components/components.css', 'components/main.min.css'))
    // Minify Any HTML
    .pipe($.if('*.html', $.minifyHtml()))
    // Output Files
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

gulp.task('html:inline', function () {
    return gulp.src('./.tmp/**/*.html')
        .pipe($.inlineSource('./app'))
        .pipe(gulp.dest('./dist'));
});

gulp.task('html:jekyll', function () {
    gulp.src(['./app/index.html', './app/_layouts/*.html', './app/_posts/*.{markdown,md}', './app/_customers/*.{markdown,md}'])
        .pipe($.plumber())
        .pipe($.jekyll({
            source: './app/',
            destination: './.tmp/',
            bundleExec: true
        }))
        .on('error', console.error.bind(console))
        .pipe(gulp.dest('./dist/'));
});

// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist/*', '!dist/.git']));

// Watch Files For Changes & Reload
gulp.task('serve', ['html:jekyll','styles'], function () {
  browserSync({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: ['.tmp', 'app']
  });

  gulp.watch(['app/**/*.html'], ['html:jekyll', 'styles']);
  gulp.watch(['app/**/*.{html,md,markdown}'], ['html:jekyll', 'styles']);
  gulp.watch(['app/styles/**/*.{scss,css}'], ['styles']);
  gulp.watch(['app/scripts/**/*.js'], ['jshint']);
  gulp.watch(['app/images/**/*'], reload);
  gulp.watch(['.tmp/**'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
  browserSync({
    notify: false,
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist'
  });
});

// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
  runSequence('html:jekyll', 'styles', ['html', 'jshint', 'images', 'fonts', 'copy'], 'html:inline', 'cmq', cb);
});

// Run PageSpeed Insights
// Update `url` below to the public URL for your site
gulp.task('pagespeed', pagespeed.bind(null, {
  // By default, we use the PageSpeed Insights
  // free (no API key) tier. You can use a Google
  // Developer API key if you have one. See
  // http://goo.gl/RkN0vE for info key: 'YOUR_API_KEY'
  url: 'http://getroadmap.github.io/roadmap-site/',
  strategy: 'mobile'
}));

gulp.task('bump:major', function () {
  gulp.src(['./package.json'])
    .pipe($.bump({type:'major'}))
    .pipe(gulp.dest('./'));
});

gulp.task('bump:minor', function () {
  gulp.src(['./bower.json', './package.json'])
    .pipe($.bump({type:'minor'}))
    .pipe(gulp.dest('./'));
});

gulp.task('bump:patch', function () {
  gulp.src(['./bower.json', './package.json'])
    .pipe($.bump({type:'patch'}))
    .pipe(gulp.dest('./'));
});

// Load custom tasks from the `tasks` directory
try { require('require-dir')('tasks'); } catch (err) {}
<|endoftext|>