<commit_before>import React from 'react';

import { withStyles } from '@material-ui/core/styles';

const styles = {

};

class Adapters extends React.Component {

    render() {
        return (

                Adapters

        );
    }

}

export default withStyles(styles)(Adapters);<commit_msg>Work in progress<commit_after>import React from 'react';

import { withStyles } from '@material-ui/core/styles';
//import { MdContactPhone } from 'react-icons/md';

import Avatar from '@material-ui/core/Avatar';
import Grid from '@material-ui/core/Grid';
import IconButton from '@material-ui/core/IconButton';
import LinearProgress from '@material-ui/core/LinearProgress';
import Paper from '@material-ui/core/Paper';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';

import AddIcon from '@material-ui/icons/Add';
import AddToPhotosIcon from '@material-ui/icons/AddToPhotos';
import BuildIcon from '@material-ui/icons/Build';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import DeleteForeverIcon from '@material-ui/icons/DeleteForever';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import HelpIcon from '@material-ui/icons/Help';
import PublishIcon from '@material-ui/icons/Publish';
import RefreshIcon from '@material-ui/icons/Refresh';

import { FaGithub as GithubIcon } from 'react-icons/fa';

import { blue } from '@material-ui/core/colors';
import { green } from '@material-ui/core/colors';

const styles = theme => ({
    root:{
        marginBottom: theme.spacing(2)
    },
    smallAvatar: {
        width: theme.spacing(3),
        height: theme.spacing(3)
    },
    table: {
        tableLayout: 'fixed',
        minWidth: 960,
        '& td': {
            whiteSpace: 'nowrap',
            overflow: 'hidden',
            textOverflow: 'ellipsis'
        }
    },
    hidden: {
        visibility: 'hidden'
    },
    name: {
        flexWrap: 'nowrap',
        width: 300
    },
    description: {
        width: 600
    },
    keywords: {

    },
    installed: {
        width: 120
    },
    available: {
        width: 100
    },
    license: {
        width: 150
    },
    install:{
        width: 220
    },
    green: {
        color: green[500]
    },
    blue: {
        color: blue[700]
    },
    category: {
        backgroundColor: theme.palette.background.default,
    },
    grow: {
        flexGrow: 1
    }
});

class Adapters extends React.Component {

    constructor(props) {

        super(props);

        this.state = {
            lastUpdate: 0,
            repository: {},
            installed: {},
            instances: {},
            categories: [],
            hostData: {},
            hostOs: '',
            nodeJsVersion: '',
            init: false
        };

        this.t = props.t;
    }

    componentDidMount() {
        if(this.props.ready) {
            this.getAdaptersInfo(this.props.currentHost, true);
        }
    }

    componentDidUpdate() {
        if(!this.state.init && this.props.ready) {
            this.getAdaptersInfo(this.props.currentHost, true);
        }
    }

    async getAdaptersInfo(update, updateRepo) {
        if (!this.props.currentHost) {
            return;
        }

        if (update) {
            // Do not update too often
            if (new Date().getTime() - this.state.lastUpdate > 1000) {

                const currentHost = this.props.currentHost;

                try {
                    const hostData = await this.props.socket.getHostInfo(currentHost);
                    const nodeJsVersion = hostData['Node.js'].replace('v', '');
                    const hostOs = hostData.os;

                    const repository = await this.props.socket.getRepository(currentHost, {repo: this.props.systemConfig.common.activeRepo, update: updateRepo});
                    const installed = await this.props.socket.getInstalled(currentHost);
                    const instances = await this.props.socket.getAdapterInstances();
                    const categories = {};
                    const categoriesSorted = [];

                    Object.keys(installed).forEach(value => {

                        const adapter = installed[value];

                        if (!adapter.controller && value !== 'hosts') {
                            if (!repository[value]) {
                                repository[value] = adapter;
                            }
                        }
                    });

                    Object.keys(repository).forEach(value => {

                        const adapter = repository[value];

                        if (!adapter.controller) {

                            const type = adapter.type;
                            const installedInGroup = installed[value];

                            if (!categories[type]) {
                                categories[type] = {
                                    name: type,
                                    translation: this.t(type + '_group'),
                                    expanded: false,
                                    count: 1,
                                    installed: installedInGroup ? 1 : 0
                                };
                            } else {
                                categories[type].count++;
                                if (installedInGroup) {
                                    categories[type].installed++;
                                }
                            }
                        }
                    });

                    Object.keys(instances).forEach(value => {

                        const instance = instances[value];
                        const name = instance.common.name;
                        const enabled = instance.common.enabled;

                        if (installed[name]) {
                            if (installed[name].count) {
                                installed[name].count++;
                            } else {
                                installed[name].count = 1;
                            }

                            if (enabled) {
                                if (installed[name].enabled) {
                                    installed[name].enabled++;
                                } else {
                                    installed[name].enabled = 1;
                                }
                            }
                        }
                    });

                    Object.keys(categories).forEach(value => {
                        categoriesSorted.push(categories[value]);
                    });

                    categoriesSorted.sort((a, b) => {

                        const result = b.installed - a.installed;

                        return result !== 0 ? result : a.translation  b.translation ? 1 : 0;
                    });

                    this.setState({
                        lastUpdate: Date.now(),
                        hostData,
                        hostOs,
                        nodeJsVersion,
                        repository,
                        installed,
                        instances,
                        categories: categoriesSorted,
                        init: true
                    });
                } catch(error) {
                    console.error(error);
                }
            }
        }
    }

    toggleCategory(category) {

        const categories = this.state.categories;
        categories[category].expanded = !categories[category].expanded;

        this.setState({
            categories
        });
    }

    getRows() {
        const rows = [];
        const { classes } = this.props;

        Object.keys(this.state.categories).forEach(value => {

            const category = this.state.categories[value];
            const categoryName = category.name;

            rows.push(
                <TableRow
                    key={ categoryName }
                    className={ classes.category }
                >
                    <TableCell>
                        <Grid container spacing={ 1 } alignItems="center" className={ classes.name }>
                            <Grid item>
                                <IconButton
                                    size="small"
                                    onClick={ () => this.toggleCategory(value) }
                                >
                                    { category.expanded ? <ExpandMoreIcon /> : <ChevronRightIcon />}
                                </IconButton>
                            </Grid>
                            <Grid item>
                                { category.translation }
                            </Grid>
                        </Grid>
                    </TableCell>
                    <TableCell>
                        <Typography component="span" variant="body2" className={ classes.green }>
                            { category.installed }
                        </Typography>
                        { ` ${this.t('of')} ` }
                        <Typography component="span" variant="body2" className={ classes.blue }>
                            { category.count }
                        </Typography>
                        { ` ${this.t('Adapters from this Group installed')}` }
                    </TableCell>
                    <TableCell />
                    <TableCell />
                    <TableCell />
                    <TableCell />
                    <TableCell />
                </TableRow>
            );

            if (category.expanded) {

                Object.keys(this.state.repository).forEach(value => {

                    const adapter = this.state.repository[value];

                    if (!adapter.controller && adapter.type === categoryName) {

                        const installed = this.state.installed[value];

                        const title = (adapter.title.toString() || '').replace('ioBroker Visualisation - ', '');
                        const desc = adapter.desc ? adapter.desc[this.props.lang] || adapter.desc['en'] : '';
                        const image = installed ? installed.localIcon : adapter.extIcon;

                        if (title instanceof Object || !desc) {
                            console.log(adapter);
                        }

                        rows.push(
                            <TableRow
                                key={ value }
                                hover
                            >
                                <TableCell>
                                    <Grid container spacing={ 1 } alignItems="center" className={ classes.name }>
                                        <Grid item>
                                            <Avatar
                                                variant="square"
                                                alt={ title.toString() }
                                                src={ image }
                                                className={ classes.smallAvatar }
                                            />
                                        </Grid>
                                        <Grid item>
                                            { title.toString() }
                                        </Grid>
                                    </Grid>
                                </TableCell>
                                <TableCell>
                                    { desc }
                                </TableCell>
                                <TableCell>
                                    { adapter.keywords && adapter.keywords.join(' ') }
                                </TableCell>
                                <TableCell>
                                    { installed && `${installed.version} (${installed.count}${installed.count !== installed.enabled ? '~' : ''})` }
                                </TableCell>
                                <TableCell>
                                    { adapter.version }
                                </TableCell>
                                <TableCell>
                                    { adapter.license }
                                </TableCell>
                                <TableCell>
                                    <IconButton size="small">
                                        <AddIcon />
                                    </IconButton>
                                    <IconButton size="small">
                                        <HelpIcon />
                                    </IconButton>
                                    { this.props.expertMode &&
                                        <IconButton size="small" className={ !installed ? classes.hidden : '' }>
                                            <PublishIcon />
                                        </IconButton>
                                    }
                                    <IconButton size="small" className={ !installed ? classes.hidden : '' }>
                                        <DeleteForeverIcon />
                                    </IconButton>
                                    { this.props.expertMode &&
                                        <IconButton size="small" className={ !installed ? classes.hidden : '' }>
                                            <AddToPhotosIcon />
                                        </IconButton>
                                    }
                                    { this.props.expertMode &&
                                        <IconButton size="small" className={ !installed ? classes.hidden : '' }>
                                            <BuildIcon />
                                        </IconButton>
                                    }
                                </TableCell>
                            </TableRow>
                        );
                    }
                });
            }
        });

        return rows;
    }

    render() {

        if (!this.state.init) {
            return <LinearProgress />
        }

        const { classes } = this.props;

        return (
            <Paper className={ classes.root }>
                <Grid
                    container
                    direction="column"
                    className={ classes.flexContainer }
                >
                    <Grid
                        item
                        container
                        alignItems="center"
                    >
                        <IconButton>
                            <RefreshIcon />
                        </IconButton>
                        <IconButton>
                            <GithubIcon />
                        </IconButton>

                        <TextField label={ this.t('Filter') } />

                    </Grid>
                    <TableContainer className={ classes.container }>

                            <TableHead>
                                <TableRow>
                                    <TableCell className={ classes.name }>
                                        <Typography>{ this.t('Name') }</Typography>
                                    </TableCell>
                                    <TableCell className={ classes.description }>
                                        <Typography>{ this.t('Description') }</Typography>
                                    </TableCell>
                                    <TableCell className={ classes.keywords }>
                                        <Typography>{ this.t('Keywords') }</Typography>
                                    </TableCell>
                                    <TableCell className={ classes.installed }>
                                        <Typography>{ this.t('Installed') }</Typography>
                                    </TableCell>
                                    <TableCell className={ classes.available }>
                                        <Typography>{ this.t('Available') }</Typography>
                                    </TableCell>
                                    <TableCell className={ classes.license }>
                                        <Typography>{ this.t('License') }</Typography>
                                    </TableCell>
                                    <TableCell className={ classes.install }>
                                        <Typography>{ this.t('Install') }</Typography>
                                    </TableCell>
                                </TableRow>
                            </TableHead>
                            <TableBody>
                                { this.getRows() }
                            </TableBody>

                    </TableContainer>
                </Grid>
            </Paper>
        );
    }
}

export default withStyles(styles)(Adapters);<|endoftext|>


<commit_before><commit_msg>chaining has always bothered me, dont worry nothing to see here<commit_after><|endoftext|>


<commit_before>var callMemberFunctions = true;
var xmlDeclaration = true;
var xmlVersion = "1.0";
var xmlEncoding = "UTF-8";
var attributeString = "@";
var valueString = "#";
var prettyPrinting = true;
var indentString = "\t";

module.exports = function (root, data, options) {

    return toXML(init(root, data, options));
};

// Initialization
var init = function(root, data, options) {

    // Error checking for root element
    if (typeof root !== "string")
        throw new Error("root element must be a string");

    // Error checking and variable initialization for options
    if (typeof options === "object" && options !== null) {

        if ("declaration" in options) {

            if ("include" in options.declaration) {

                if (typeof options.declaration.include === "boolean")
                    xmlDeclaration = options.declaration.include;
                else
                    throw new Error("declaration.include option must be a boolean");
            }

            if ("encoding" in options.declaration) {

                if (typeof options.declaration.encoding === "string" || options.declaration.encoding === null)
                    xmlEncoding = options.declaration.encoding;
                else
                    throw new Error("declaration.encoding option must be a string or null");
            }
        }
        if ("attributeString" in options) {

            if (typeof options.attributeString === "string")
                attributeString = options.attributeString;
            else
                throw new Error("attributeString option must be a string");
        }
        if ("valueString" in options) {

            if (typeof options.valueString === "string")
                valueString = options.valueString;
            else
                throw new Error("valueString option must be a string");
        }
        if ("prettyPrinting" in options) {

            if ("enabled" in options.prettyPrinting) {

                if (typeof options.prettyPrinting.enabled === "boolean")
                    prettyPrinting = options.prettyPrinting.enabled;
                else
                    throw new Error("prettyPrinting.enabled option must be a boolean");
            }

            if ("indentString" in options.prettyPrinting) {

                if (typeof options.prettyPrinting.indentString === "string")
                    indentString = options.prettyPrinting.indentString;
                else
                    throw new Error("prettyPrinting.indentString option must be a string");
            }
        }
        if ("callMemberFunctions" in options) {
            if (typeof options.callMemberFunctions === "boolean")
                callMemberFunctions = options.callMemberFunctions;
            else
                throw new Error("callMemberFunctions option must be a boolean");
        }
    }

    // Error checking and variable initialization for data
    if (typeof data !== "string" && typeof data !== "object")
        throw new Error("data must be an object or a string");

    if (typeof data === "string")
        data = JSON.parse(data);

    var tempData = {};
    tempData[root] = data; // Add root element to object

    return tempData;
};

// Convert object to XML
var toXML = function(object) {

    // Initialize arguments, if necessary
    var xml = arguments[1] || "";
    var level = arguments[2] || 0;

    for (var property in object) {

        // Arrays
        if (Object.prototype.toString.call(object[property]) === "[object Array]") {

            // Create separate object for each array element and pass to this function
            for (var i = 0; i < object[property].length; i++) {

                var obj = {};
                obj[property] = object[property][i];

                xml = toXML(obj, xml, level);
            }
        }
        // JSON-type objects with properties
        else if (Object.prototype.toString.call(object[property]) === "[object Object]") {

            xml += addIndent("<" + property, level);

            // Add attributes
            var lengthExcludingAttributes = Object.keys(object[property]).length;
            if (Object.prototype.toString.call(object[property][attributeString]) === "[object Object]") {

                lengthExcludingAttributes -= 1;
                for (var attribute in object[property][attributeString])
                    xml += " " + attribute + "=\"" + toString(object[property][attributeString][attribute]) + "\"";
            }

            if (lengthExcludingAttributes === 0) // Empty object
                xml += addBreak("/>");
            else if (lengthExcludingAttributes === 1 && valueString in object[property]) // Value string only
                xml += addBreak(">" + toString(object[property][valueString]) + "</" + property + ">");
            else { // Object with properties

                xml += addBreak(">");

                // Create separate object for each property and pass to this function
                for (var subProperty in object[property]) {

                    if (subProperty !== attributeString) {

                        var tempObject = {};
                        tempObject[subProperty] = object[property][subProperty];

                        xml = toXML(tempObject, xml, level + 1);
                    }
                }

                xml += addBreak(addIndent("</" + property + ">", level));
            }
        }
        // Everything else
        else {

            xml += addBreak(addIndent("<" + property + ">" + toString(object[property]) + "</" + property + ">", level));
        }
    }

    // Finalize XML at end of process
    if (level === 0) {

        // Strip trailing whitespace
        xml = xml.replace(/\s+$/g, '');

        // Add XML declaration
        if (xmlDeclaration)
            if (xmlEncoding === null)
                xml = addBreak("<?xml version=\"" + xmlVersion + "\"?>") + xml;
            else
                xml = addBreak("<?xml version=\"" + xmlVersion + "\" encoding=\"" + xmlEncoding + "\"?>") + xml;
    }

    return xml;
};

// Add indenting to data for pretty printing
var addIndent = function(data, level) {

    if (prettyPrinting) {

        var indent = "";
        for (var i = 0; i < level; i++) {
            indent += indentString;
        }
        data = indent + data;
    }

    return data;
};

// Add line break to data for pretty printing
var addBreak = function(data) {

    return prettyPrinting ? data + "\n" : data;
};

// Convert anything into a valid XML string representation
var toString = function(data) {

    // Recursive function used to handle nested functions
    var functionHelper = function(data) {

        if (callMemberFunctions && Object.prototype.toString.call(data) === "[object Function]")
            return (data() === undefined) ? data.toString() : functionHelper(data());
        else
            return data;
    };

    // Functions
    if (Object.prototype.toString.call(data) === "[object Function]")
        data = functionHelper(data);
    // Empty objects
    else if (Object.prototype.toString.call(data) === "[object Object]" && Object.keys(data).length === 0)
        data = "";

    // Cast data to string
    if (typeof data !== "string")
        data = (data === null || data === undefined) ? "" : data.toString();

    // Escape illegal XML characters
    data = data.replace(/&/g, "&")
        .replace(/</g, "<")
        .replace(/>/g, ">")
        .replace(/"/g, """)
        .replace(/'/g, "'");

    return data;
};
<commit_msg>Make linter happy<commit_after>"use strict";
var callMemberFunctions = true;
var xmlDeclaration = true;
var xmlVersion = "1.0";
var xmlEncoding = "UTF-8";
var attributeString = "@";
var valueString = "#";
var prettyPrinting = true;
var indentString = "\t";

/* globals module */

module.exports = function (root, data, options) {

    return toXML(init(root, data, options));
};

// Initialization
var init = function(root, data, options) {

    // Error checking for root element
    if (typeof root !== "string")
        throw new Error("root element must be a string");

    // Error checking and variable initialization for options
    if (typeof options === "object" && options !== null) {

        if ("declaration" in options) {

            if ("include" in options.declaration) {

                if (typeof options.declaration.include === "boolean")
                    xmlDeclaration = options.declaration.include;
                else
                    throw new Error("declaration.include option must be a boolean");
            }

            if ("encoding" in options.declaration) {

                if (typeof options.declaration.encoding === "string" || options.declaration.encoding === null)
                    xmlEncoding = options.declaration.encoding;
                else
                    throw new Error("declaration.encoding option must be a string or null");
            }
        }
        if ("attributeString" in options) {

            if (typeof options.attributeString === "string")
                attributeString = options.attributeString;
            else
                throw new Error("attributeString option must be a string");
        }
        if ("valueString" in options) {

            if (typeof options.valueString === "string")
                valueString = options.valueString;
            else
                throw new Error("valueString option must be a string");
        }
        if ("prettyPrinting" in options) {

            if ("enabled" in options.prettyPrinting) {

                if (typeof options.prettyPrinting.enabled === "boolean")
                    prettyPrinting = options.prettyPrinting.enabled;
                else
                    throw new Error("prettyPrinting.enabled option must be a boolean");
            }

            if ("indentString" in options.prettyPrinting) {

                if (typeof options.prettyPrinting.indentString === "string")
                    indentString = options.prettyPrinting.indentString;
                else
                    throw new Error("prettyPrinting.indentString option must be a string");
            }
        }
        if ("callMemberFunctions" in options) {
            if (typeof options.callMemberFunctions === "boolean")
                callMemberFunctions = options.callMemberFunctions;
            else
                throw new Error("callMemberFunctions option must be a boolean");
        }
    }

    // Error checking and variable initialization for data
    if (typeof data !== "string" && typeof data !== "object")
        throw new Error("data must be an object or a string");

    if (typeof data === "string")
        data = JSON.parse(data);

    var tempData = {};
    tempData[root] = data; // Add root element to object

    return tempData;
};

// Convert object to XML
var toXML = function(object) {

    // Initialize arguments, if necessary
    var xml = arguments[1] || "";
    var level = arguments[2] || 0;

    for (var property in object) {

        // Arrays
        if (Object.prototype.toString.call(object[property]) === "[object Array]") {

            // Create separate object for each array element and pass to this function
            for (var i = 0; i < object[property].length; i++) {

                var obj = {};
                obj[property] = object[property][i];

                xml = toXML(obj, xml, level);
            }
        }
        // JSON-type objects with properties
        else if (Object.prototype.toString.call(object[property]) === "[object Object]") {

            xml += addIndent("<" + property, level);

            // Add attributes
            var lengthExcludingAttributes = Object.keys(object[property]).length;
            if (Object.prototype.toString.call(object[property][attributeString]) === "[object Object]") {

                lengthExcludingAttributes -= 1;
                for (var attribute in object[property][attributeString])
                    xml += " " + attribute + "=\"" + toString(object[property][attributeString][attribute]) + "\"";
            }

            if (lengthExcludingAttributes === 0) // Empty object
                xml += addBreak("/>");
            else if (lengthExcludingAttributes === 1 && valueString in object[property]) // Value string only
                xml += addBreak(">" + toString(object[property][valueString]) + "</" + property + ">");
            else { // Object with properties

                xml += addBreak(">");

                // Create separate object for each property and pass to this function
                for (var subProperty in object[property]) {

                    if (subProperty !== attributeString) {

                        var tempObject = {};
                        tempObject[subProperty] = object[property][subProperty];

                        xml = toXML(tempObject, xml, level + 1);
                    }
                }

                xml += addBreak(addIndent("</" + property + ">", level));
            }
        }
        // Everything else
        else {

            xml += addBreak(addIndent("<" + property + ">" + toString(object[property]) + "</" + property + ">", level));
        }
    }

    // Finalize XML at end of process
    if (level === 0) {

        // Strip trailing whitespace
        xml = xml.replace(/\s+$/g, "");

        // Add XML declaration
        if (xmlDeclaration)
            if (xmlEncoding === null)
                xml = addBreak("<?xml version=\"" + xmlVersion + "\"?>") + xml;
            else
                xml = addBreak("<?xml version=\"" + xmlVersion + "\" encoding=\"" + xmlEncoding + "\"?>") + xml;
    }

    return xml;
};

// Add indenting to data for pretty printing
var addIndent = function(data, level) {

    if (prettyPrinting) {

        var indent = "";
        for (var i = 0; i < level; i++) {
            indent += indentString;
        }
        data = indent + data;
    }

    return data;
};

// Add line break to data for pretty printing
var addBreak = function(data) {

    return prettyPrinting ? data + "\n" : data;
};

// Convert anything into a valid XML string representation
var toString = function(data) {

    // Recursive function used to handle nested functions
    var functionHelper = function(data) {

        if (callMemberFunctions && Object.prototype.toString.call(data) === "[object Function]")
            return (data() === undefined) ? data.toString() : functionHelper(data());
        else
            return data;
    };

    // Functions
    if (Object.prototype.toString.call(data) === "[object Function]")
        data = functionHelper(data);
    // Empty objects
    else if (Object.prototype.toString.call(data) === "[object Object]" && Object.keys(data).length === 0)
        data = "";

    // Cast data to string
    if (typeof data !== "string")
        data = (data === null || data === undefined) ? "" : data.toString();

    // Escape illegal XML characters
    data = data.replace(/&/g, "&")
        .replace(/</g, "<")
        .replace(/>/g, ">")
        .replace(/"/g, """)
        .replace(/'/g, "'");

    return data;
};
<|endoftext|>


<commit_before>
import styles from './styles';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Icon, Modal } from 'antd';
import { Upload } from 'components/Nested';
import withAppConfig from 'utils/withAppConfig';
import withField from 'utils/withField';
import ImageTableCell from './ImageTableCell';

@withField
@withAppConfig('upload')
export default class ImageField extends Component {
	static propTypes = {
		max: PropTypes.number,
		render: PropTypes.func,
		strategy: PropTypes.string,
		getValue: PropTypes.func.isRequired,
	};

	static defaultProps = {
		max: 1,
		render: (src, records, index, props) =>
			<ImageTableCell {...props} url={src} />
		,
	};

	static contextTypes = {
		authStore: PropTypes.object.isRequired,
		appConfig: PropTypes.object.isRequired,
	};

	constructor(props, context) {
		super(props, context);

		const { strategy, getValue } = props;
		const { authStore } = context;
		const strategies = this.getAppConfig('strategies');
		const imagePath = this.getAppConfig('imagePath');
		const requireAccessToken = this.getAppConfig('requireAccessToken');
		const { accessTokenName } = context.appConfig.api;

		if (__DEV__ && strategy && !strategies.hasOwnProperty(strategy)) {
			console.warn(
				`Strategy "${strategy}" is NOT defined in config file`
			);
		}
		this._customRequest = strategies[strategy];

		// TODO: should suppport `accessToken` in header
		const search = requireAccessToken ?
			`?${accessTokenName}=${authStore.getAccessToken()}` : ''
		;
		this._uploadPath = imagePath + search;

		const state = {
			previewVisible: false,
			previewImage: '',
			fileList: [],
		};

		getValue()
			.split(',')
			.map((url) => url.trim())
			.filter(Boolean)
			.forEach((url, index) => state.fileList.push({ uid: -index, url }))
		;

		this.state = state;
	}

	_handleCloseModal = () => {
		this.setState({ previewVisible: false });
	};

	_handlePreview = (file) => {
		this.setState({
			previewImage: file.url || file.thumbUrl,
			previewVisible: true,
		});
	};

	_handleChange = ({ fileList }) => {
		this.setState({ fileList });
	};

	render() {
		const {
			props: {
				max, strategy,
				getValue,
				...other,
			},
			state: { previewVisible, previewImage, fileList },
			_customRequest,
			_uploadPath,
		} = this;

		const uploadButton = (

				<Icon style={styles.uploadButtonIcon} type="plus" />

		);

		return (

				<Upload
					{...other}
					style={styles.container}
					customRequest={_customRequest}
					action={_uploadPath}
					listType="picture-card"
					fileList={fileList}
					onPreview={this._handlePreview}
					onChange={this._handleChange}
					multi={max > 1}
					noFieldDecorator
				>
					{fileList.length < max ? uploadButton : null}
				</Upload>
				<Modal
					visible={previewVisible}
					footer={null}
					onCancel={this._handleCloseModal}
				>

				</Modal>

		);
	}
}
<commit_msg>add Image defaultValue<commit_after>
import styles from './styles';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Icon, Modal } from 'antd';
import { Upload } from 'components/Nested';
import withAppConfig from 'utils/withAppConfig';
import withField from 'utils/withField';
import ImageTableCell from './ImageTableCell';

@withField
@withAppConfig('upload')
export default class ImageField extends Component {
	static propTypes = {
		max: PropTypes.number,
		render: PropTypes.func,
		strategy: PropTypes.string,
		getValue: PropTypes.func.isRequired,
	};

	static defaultProps = {
		max: 1,
		render: (src, records, index, props) =>
			<ImageTableCell {...props} url={src} />
		,
	};

	static contextTypes = {
		authStore: PropTypes.object.isRequired,
		appConfig: PropTypes.object.isRequired,
	};

	constructor(props, context) {
		super(props, context);

		const { strategy, getValue } = props;
		const { authStore } = context;
		const strategies = this.getAppConfig('strategies');
		const imagePath = this.getAppConfig('imagePath');
		const requireAccessToken = this.getAppConfig('requireAccessToken');
		const { accessTokenName } = context.appConfig.api;

		if (__DEV__ && strategy && !strategies.hasOwnProperty(strategy)) {
			console.warn(
				`Strategy "${strategy}" is NOT defined in config file`
			);
		}
		this._customRequest = strategies[strategy];

		// TODO: should suppport `accessToken` in header
		const search = requireAccessToken ?
			`?${accessTokenName}=${authStore.getAccessToken()}` : ''
		;
		this._uploadPath = imagePath + search;

		const state = {
			previewVisible: false,
			previewImage: '',
			fileList: [],
		};

		getValue()
			.split(',')
			.map((url) => url.trim())
			.filter(Boolean)
			.forEach((url, index) => state.fileList.push({ uid: -index, url }))
		;

		this.state = state;
	}

	_handleCloseModal = () => {
		this.setState({ previewVisible: false });
	};

	_handlePreview = (file) => {
		this.setState({
			previewImage: file.url || file.thumbUrl,
			previewVisible: true,
		});
	};

	_handleChange = ({ fileList }) => {
		this.setState({ fileList });
	};

	render() {
		const {
			props: {
				max, strategy,
				getValue,
				...other,
			},
			state: { previewVisible, previewImage, fileList },
			_customRequest,
			_uploadPath,
		} = this;

		const uploadButton = (

				<Icon style={styles.uploadButtonIcon} type="plus" />

		);

		return (

				<Upload
					{...other}
					defaultValue={getValue()}
					style={styles.container}
					customRequest={_customRequest}
					action={_uploadPath}
					listType="picture-card"
					fileList={fileList}
					onPreview={this._handlePreview}
					onChange={this._handleChange}
					multi={max > 1}
					noFieldDecorator
				>
					{fileList.length < max ? uploadButton : null}
				</Upload>
				<Modal
					visible={previewVisible}
					footer={null}
					onCancel={this._handleCloseModal}
				>

				</Modal>

		);
	}
}
<|endoftext|>


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

  const os = require('os');
  const path = require('path');
  const KeysRouter = require('./keys-router');

  class KeysManager {
    constructor() {
      this._router = new KeysRouter(this);
      this._baseServer = null;
    }

    load(messageCenter, baseServer) {
      return Promise.resolve()
      .then(() => this._router.load(baseServer))
      .then(() => this._messageCenter = messageCenter);
    }

    createKey(path) {
      return this._messageCenter.sendRequest('base#Keys create', null, path);
    }
  }

  module.exports = KeysManager;

})();
<commit_msg>use object deconstruction to maintain native API<commit_after>(() => {
  'use strict';

  const os = require('os');
  const path = require('path');
  const KeysRouter = require('./keys-router');

  class KeysManager {
    constructor() {
      this._router = new KeysRouter(this);
      this._baseServer = null;
    }

    load(messageCenter, baseServer) {
      return Promise.resolve()
      .then(() => this._router.load(baseServer))
      .then(() => this._messageCenter = messageCenter);
    }

    createKey(path) {
      return this._messageCenter.sendRequest('base#Keys create', null, {filepath: path});
    }
  }

  module.exports = KeysManager;

})();
<|endoftext|>


<commit_before>/*!
 * thought <https://github.com/nknapp/thought>
 *
 * Copyright (c) 2015 Nils Knappmeier.
 * Released under the MIT license.
 */
var exec = require('./utils/exeq')
var semver = require('semver')

module.exports = function () {
  return exec('npm', ['--version'])
    .then(function (stdio) {
      if (semver.lt(stdio[0], '2.13.0')) {
        throw new Error('npm<2.13.0 will not execute the `version`-script in your package.json.\n' +
          'Please upgrade to at least 2.13.0.')
      } else {
        // eslint-disable-next-line no-console
        console.log('npm@' + stdio.trim() + ': OK')
      }
    })
}
<commit_msg>Fix removal of q (2)<commit_after>/*!
 * thought <https://github.com/nknapp/thought>
 *
 * Copyright (c) 2015 Nils Knappmeier.
 * Released under the MIT license.
 */
var exec = require('./utils/exeq')
var semver = require('semver')

module.exports = function () {
  return exec('npm', ['--version'])
    .then(function (stdio) {
      if (semver.lt(stdio[0], '2.13.0')) {
        throw new Error('npm<2.13.0 will not execute the `version`-script in your package.json.\n' +
          'Please upgrade to at least 2.13.0.')
      } else {
        // eslint-disable-next-line no-console
        console.log('npm@' + stdio[0].trim() + ': OK')
      }
    })
}
<|endoftext|>


<commit_before>$.extend({
	getUrlQueryString:function(url) {
		if (url.length > 0) {
			// spliting the url and query string using question mark
			var splitUrl = url.split("?");

			// again spliting the data which will have & symbol
			var strUrl = (splitUrl.length>1) ? splitUrl[1].split("&") : 0;

			var i = 0;
			var iLen = strUrl.length;

			var str = '';
			var obj = {};

			// iterator to assign key pair values into obj variable
			for(i=0;i<iLen;i++) {
				str = strUrl[i].split("=");
				if (str[0].length > 0 && typeof str[1] !== 'undefined') {
					obj[str[0]] = decodeURIComponent(str[1]);
				}
			}

			// returning the value
			return Array.prototype.sort.call(obj);

		} else {
			return {};
		}
	}
});
<commit_msg>Adds spacing and single-quotes<commit_after>$.extend({
	getUrlQueryString:function(url) {
		if (url.length > 0) {
			// spliting the url and query string using question mark
			var splitUrl = url.split('?');

			// again spliting the data which will have & symbol
			var strUrl = (splitUrl.length > 1) ? splitUrl[1].split('&') : 0;

			var i = 0;
			var iLen = strUrl.length;

			var str = '';
			var obj = {};

			// iterator to assign key pair values into obj variable
			for(i=0; i<iLen; i++) {
				str = strUrl[i].split('=');
				if (str[0].length > 0 && typeof str[1] !== 'undefined') {
					obj[str[0]] = decodeURIComponent(str[1]);
				}
			}

			// returning the value
			return Array.prototype.sort.call(obj);

		} else {
			return {};
		}
	}
});
<|endoftext|>


<commit_before>'use strict';

const TIMERS = require('./timers.js');
const CDSTRINGS = require('./cdStrings.js');
const USERS = require('./users.js');

/*
  Chicken Dinner Idea:
    Players sign up using a chosen number of points.  Lobby is created for 5
    minutes.  After lobby closes, game begins.  Every two minutes, one or two
    players are chosen at random and one randomly wins(in the event of a single
    player chosen, they die).  Game goes until one player is remaining.  Top
    3 players get points back, 50%, 30%, 20%.  Game can go long and is only
    available once per hour.
*/

// Input: [chickendinner, 100]
async function serve(db, channel, userstate, client, message) {

  let amount = parseInt(message[1]);
  let cdStatus = TIMERS.showTimers()[channel].chickenDinner;
  let currentState = cdStatus.state;
  let participants = cdStatus.participants;

  console.log(currentState);

  // if no chicken dinner is running and game is available
  if (currentState === 'available' && cdStatus.activated) {
    cdStatus.state = 'lobby';
    participants.push(userstate['user-id']);
    // Send start warning in 2:30 minutes.
    // Not sure if I need a timer stored in the timer object for each channel
    // but it seemed safer to do it this way.
    client.say(channel, `@${userstate['display-name']} has challenged ` +
    'everyone to a "!chickendinner"! The battle begins in 5 minutes!');
    cdStatus.timer(startingSoon, 150000);
  } else if (currentState === 'lobby') {
    participants.push(userstate['user-id']);
  }

  function startingSoon() {
    client.say(channel, 'The battle for a !chickendinner will begin in ' +
    '2 minutes and 30 seconds!');
    cdStatus.timer(battleBegins, 150000);
  }

  function battleBegins() {
    client.say(channel, 'The battle for a !chickendinner has begin! '+
    'We should be receiving the first set of outcomes soon...');
    cdStatus.timer(cdFight, 120000);
  }

  async function cdFight() {

    if (participants.length <= 3) {

      // Do something here for the top 3

    } else {

      // Choose one or two random people and select one winner
      let singleParticipant = false;
      // % chance to get a single participant event
      let singleChance = 20;

      if (Math.round(Math.random()*100) <= singleChance) {
        singleParticipant = true;
      }

      let loser = participants[Math.floor(Math.random()*participants.length)];
      loser = await USERS.toDisplayName(loser);
      participants.splice(participants.indexOf(loser), 1);
      // If singleParticipant is true we just throw out the winner
      let winner = participants[Math.floor(Math.random()*participants.length)];
      winner = await USERS.toDisplayName(winner);

      if (singleParticipant) {
        // Single Participant outcome here
        let outcome = CDSTRINGS.solo[Math.floor(Math.random()*CDSTRINGS.solo.length)];
        outcome = outcome.replace('@L', loser);
        client.say(channel, outcome);
      } else {
        let outcome = CDSTRINGS.duo[Math.floor(Math.random()*CDSTRINGS.solo.length)];
        outcome = outcome.replace('@L', loser);
        outcome = outcome.replace('@W', winner);
        client.say(channel, outcome);
      }

    }
  }

}

module.exports = {
  serve
};<commit_msg>create function to select random element in an array<commit_after>'use strict';

const TIMERS = require('./timers.js');
const CDSTRINGS = require('./cdStrings.js');
const USERS = require('./users.js');

/*
  Chicken Dinner Idea:
    Players sign up using a chosen number of points.  Lobby is created for 5
    minutes.  After lobby closes, game begins.  Every two minutes, one or two
    players are chosen at random and one randomly wins(in the event of a single
    player chosen, they die).  Game goes until one player is remaining.  Top
    3 players get points back, 50%, 30%, 20%.  Game can go long and is only
    available once per hour.
*/

// Input: [chickendinner, 100]
async function serve(db, channel, userstate, client, message) {

  let amount = parseInt(message[1]);
  let cdStatus = TIMERS.showTimers()[channel].chickenDinner;
  let currentState = cdStatus.state;
  let participants = cdStatus.participants;

  console.log(currentState);

  // if no chicken dinner is running and game is available
  if (currentState === 'available' && cdStatus.activated) {
    cdStatus.state = 'lobby';
    participants.push(userstate['user-id']);
    // Send start warning in 2:30 minutes.
    // Not sure if I need a timer stored in the timer object for each channel
    // but it seemed safer to do it this way.
    client.say(channel, `@${userstate['display-name']} has challenged ` +
    'everyone to a "!chickendinner"! The battle begins in 5 minutes!');
    cdStatus.timer(startingSoon, 10000);
  } else if (currentState === 'lobby') {
    participants.push(userstate['user-id']);
  }

  function startingSoon() {
    client.say(channel, 'The battle for a !chickendinner will begin in ' +
    '2 minutes and 30 seconds!');
    cdStatus.timer(battleBegins, 10000);
  }

  function battleBegins() {
    client.say(channel, 'The battle for a !chickendinner has begin! '+
    'We should be receiving the first set of outcomes soon...');
    cdStatus.timer(cdFight, 10000);
  }

  async function cdFight() {

    if (participants.length <= 0) {

      // Do something here for the top 3

    } else {

      // Choose one or two random people and select one winner
      let singleParticipant = false;
      // % chance to get a single participant event
      let singleChance = 20;

      if (Math.round(Math.random()*100) <= singleChance) {
        singleParticipant = true;
      }

      let loser = randArray(participants);
      participants.splice(participants.indexOf(loser), 1);
      loser = await USERS.toDisplayName(loser);
      // If singleParticipant is true we just throw out the winner
      let winner = randArray(participants);
      winner = await USERS.toDisplayName(winner);

      if (singleParticipant) {
        // Single Participant outcome here
        let outcome = randArray(CDSTRINGS.solo);
        outcome = outcome.replace('@L', loser);
        client.say(channel, outcome);
      } else {
        let outcome = randArray(CDSTRINGS.duo);
        outcome = outcome.replace('@L', loser);
        outcome = outcome.replace('@W', winner);
        client.say(channel, outcome);
      }

    }
  }

}

function randArray(arr) {
  return arr[Math.floor(Math.random()*arr.length)];
}

module.exports = {
  serve
};<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {connect} from 'react-redux';
import Grid from '../grid'
import Word from '../word'
import NavBar from '../navBar';
import Alphabet from "../../constants/alphabet";

class WordEntryPage extends Component {
  constructor(props) {
    super(props);
    this.displayLetterCounter = this.displayLetterCounter.bind(this);
    this.getRemainingLetters = this.getRemainingLetters.bind(this);
    this.goToNextStep = this.goToNextStep.bind(this);
  }

  getRemainingLetters() {
    var lettersRemaining = [];
    for (var key in this.props.letters) {
      var letter = this.props.letters[key];
      if (!letter.wordId) {
        lettersRemaining.push(letter);
      }
    }
    return lettersRemaining
  }

  displayLetterCounter() {
    var dictionary = {};
    var lettersRemaining = this.getRemainingLetters()
    for (var key in this.props.letters) {
      var letter = this.props.letters[key];
      if (!letter.wordId) {
        lettersRemaining.push(letter);
      }
    }
    lettersRemaining.forEach((letter)=>{
      var char = letter.char.toUpperCase();
      if (dictionary[char]) {
        dictionary[char] ++
      } else {
        dictionary[char] = 1
      }
    });
    var letterCounters = Alphabet.split('').map((char) => {
      var letterClass = 'letter-'+char;
      if (/[aeiou]/.test(char)) {
        letterClass += " vowels"
      }
      if (!dictionary[char]) {
        var numberClass = "red"
      }
      return (

          {char}:
            {dictionary[char] || 0}

        )
      });

      return letterCounters
    }

    goToNextStep() {
      // save clues here
      this.props.goToNextStep()
    }

    render() {
      var letterCounters = this.displayLetterCounter();
      var wordIds = [];
      for (var wordId in this.props.words) {
        wordIds.push(wordId)
      }
      var wordComponents = wordIds.map((id)=>{
        return (
          <Word
            key={id}
            wordId={id}
            />
        );
      });
      var pageComplete = !this.getRemainingLetters().length;
      return (

          <NavBar pageComplete={pageComplete} goToNextStep={this.goToNextStep} />

              <Grid />

Letters Remaining

                {letterCounters}

                {wordComponents}

      );
    }
  }

  WordEntryPage.propTypes = {
  };

  function mapStateToProps(state, ownProps) {
    return {
      letters: state.letters,
      words: state.words
    };
  }

  export default connect(mapStateToProps)(WordEntryPage);
<commit_msg>fix letter counter bug<commit_after>import React, { Component, PropTypes } from 'react';
import {connect} from 'react-redux';
import Grid from '../grid'
import Word from '../word'
import NavBar from '../navBar';
import Alphabet from "../../constants/alphabet";

class WordEntryPage extends Component {
  constructor(props) {
    super(props);
    this.displayLetterCounter = this.displayLetterCounter.bind(this);
    this.getRemainingLetters = this.getRemainingLetters.bind(this);
    this.goToNextStep = this.goToNextStep.bind(this);
  }

  getRemainingLetters() {
    var lettersRemaining = [];
    for (var key in this.props.letters) {
      var letter = this.props.letters[key];
      if (!letter.wordId) {
        lettersRemaining.push(letter);
      }
    }
    return lettersRemaining
  }

  displayLetterCounter() {
    var dictionary = {};
    var lettersRemaining = this.getRemainingLetters()
    lettersRemaining.forEach((letter)=>{
      var char = letter.char.toUpperCase();
      if (dictionary[char]) {
        dictionary[char] ++
      } else {
        dictionary[char] = 1
      }
    });
    var letterCounters = Alphabet.split('').map((char) => {
      var letterClass = 'letter-'+char;
      if (/[aeiou]/.test(char)) {
        letterClass += " vowels"
      }
      if (!dictionary[char]) {
        var numberClass = "red"
      }
      return (

          {char}:
            {dictionary[char] || 0}

        )
      });

      return letterCounters
    }

    goToNextStep() {
      // save clues here
      this.props.goToNextStep()
    }

    render() {
      var letterCounters = this.displayLetterCounter();
      var wordIds = [];
      for (var wordId in this.props.words) {
        wordIds.push(wordId)
      }
      var wordComponents = wordIds.map((id)=>{
        return (
          <Word
            key={id}
            wordId={id}
            />
        );
      });
      var pageComplete = !this.getRemainingLetters().length;
      return (

          <NavBar pageComplete={pageComplete} goToNextStep={this.goToNextStep} />

              <Grid />

Letters Remaining

                {letterCounters}

                {wordComponents}

      );
    }
  }

  WordEntryPage.propTypes = {
  };

  function mapStateToProps(state, ownProps) {
    return {
      letters: state.letters,
      words: state.words
    };
  }

  export default connect(mapStateToProps)(WordEntryPage);
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var express = require('express');
var utils = require('lib/utils');
var accepts = require('lib/accepts')
var restrict = utils.restrict;
var pluck = utils.pluck;
var expose = utils.expose;
var api = require('lib/db-api');
var log = require('debug')('democracyos:citizen');

var app = module.exports = express();

/**
 * Limit request to json format only
 */

app.use(accepts('application/json'));

app.get('/citizen/me', restrict, function (req, res) {
  log('Request /citizen/me');

  log('Serving citizen %j', req.user.id);
  res.json(expose('id firstName lastName email gravatar() staff profilePictureUrl')(req.user));
});

app.get('/citizen/search', restrict, function (req, res) {
  var q = req.param('q');

  log('Request /citizen/search %j', q);

  api.citizen.search(q, function(err, citizens) {
    if (err) return _handleError(err, req, res);

    log('Serving citizens %j', pluck(citizens, 'id'));
    res.json(citizens.map(expose('id fullName gravatar() profilePictureUrl')));
  });
});

app.get('/citizen/lookup', function (req, res) {
  var ids = req.param('ids');

  log('Request /citizen/lookup %j', ids);

  if (!ids) return log('Cannot process without ids'), res.json(500,{});

  api.citizen.lookup(ids.split(','), function(err, citizens) {
    if (err) return _handleError(err, req, res);

    log('Serving citizens %j', pluck(citizens, 'id'));
    res.json(citizens.map(expose('id fullName gravatar() profilePictureUrl')));
  });
});

// This is a temporary hack while lookinf for a better solution to
// this error: 414 Request-URI Too Large
app.post('/citizen/lookup', function (req, res) {
  var ids = req.param('ids');

  log('Request /citizen/lookup %j', ids);

  if (!ids) return log('Cannot process without ids'), res.json(500,{});

  api.citizen.lookup(ids, function(err, citizens) {
    if (err) return _handleError(err, req, res);

    log('Serving citizens %j', pluck(citizens, 'id'));
    res.json(citizens.map(expose('id fullName gravatar() profilePictureUrl')));
  });
});

app.get('/citizen/:id', restrict, function (req, res) {
  log('Request /citizen/%s', req.params.id);

  api.citizen.get(req.params.id, function (err, citizen) {
    if (err) return _handleError(err, req, res);

    log('Serving citizen %j', citizen.id);
    res.json(expose('id fullName gravatar() profilePictureUrl')(citizen));
  });
});

function _handleError (err, req, res) {
  res.format({
    html: function() {
      // this should be handled better!
      // maybe with flash or even an
      // error page.
      log('Error found with html request %j', err);
      res.redirect('back');
    },
    json: function() {
      log("Error found: %j", err);
      res.json({ error: err });
    }
  })
}<commit_msg>[citizen] - Add delivering notifications to client<commit_after>/**
 * Module dependencies.
 */

var express = require('express');
var utils = require('lib/utils');
var accepts = require('lib/accepts')
var restrict = utils.restrict;
var pluck = utils.pluck;
var expose = utils.expose;
var api = require('lib/db-api');
var log = require('debug')('democracyos:citizen');

var app = module.exports = express();

/**
 * Limit request to json format only
 */

app.use(accepts('application/json'));

app.get('/citizen/me', restrict, function (req, res) {
  log('Request /citizen/me');

  log('Serving citizen %j', req.user.id);
  res.json(expose('id firstName lastName email gravatar() staff profilePictureUrl notifications')(req.user));
});

app.get('/citizen/search', restrict, function (req, res) {
  var q = req.param('q');

  log('Request /citizen/search %j', q);

  api.citizen.search(q, function(err, citizens) {
    if (err) return _handleError(err, req, res);

    log('Serving citizens %j', pluck(citizens, 'id'));
    res.json(citizens.map(expose('id fullName gravatar() profilePictureUrl notifications')));
  });
});

app.get('/citizen/lookup', function (req, res) {
  var ids = req.param('ids');

  log('Request /citizen/lookup %j', ids);

  if (!ids) return log('Cannot process without ids'), res.json(500,{});

  api.citizen.lookup(ids.split(','), function(err, citizens) {
    if (err) return _handleError(err, req, res);

    log('Serving citizens %j', pluck(citizens, 'id'));
    res.json(citizens.map(expose('id fullName gravatar() profilePictureUrl notifications')));
  });
});

// This is a temporary hack while lookinf for a better solution to
// this error: 414 Request-URI Too Large
app.post('/citizen/lookup', function (req, res) {
  var ids = req.param('ids');

  log('Request /citizen/lookup %j', ids);

  if (!ids) return log('Cannot process without ids'), res.json(500,{});

  api.citizen.lookup(ids, function(err, citizens) {
    if (err) return _handleError(err, req, res);

    log('Serving citizens %j', pluck(citizens, 'id'));
    res.json(citizens.map(expose('id fullName gravatar() profilePictureUrl notifications')));
  });
});

app.get('/citizen/:id', restrict, function (req, res) {
  log('Request /citizen/%s', req.params.id);

  api.citizen.get(req.params.id, function (err, citizen) {
    if (err) return _handleError(err, req, res);

    log('Serving citizen %j', citizen.id);
    res.json(expose('id fullName gravatar() profilePictureUrl notifications')(citizen));
  });
});

function _handleError (err, req, res) {
  res.format({
    html: function() {
      // this should be handled better!
      // maybe with flash or even an
      // error page.
      log('Error found with html request %j', err);
      res.redirect('back');
    },
    json: function() {
      log("Error found: %j", err);
      res.json({ error: err });
    }
  })
}<|endoftext|>


<commit_before>/*
 * Copyright 2009-2010 Roland Huss
 *
 * 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.
 */

/* =================================
 * Jolokia Javascript Client library
 * =================================
 */

var Jolokia = (function($) {

    // Default paramerters for GET and POST requests
    var DEFAULT_CLIENT_PARAMS = {
        type: "POST",
        jsonp: false
    };

    var GET_AJAX_PARAMS = {
        type: "GET"
    };

    var POST_AJAX_PARAMS = {
        type: "POST",
        processData: false,
        dataType: "json"
    };

    function Jolokia(param) {

        // If called without 'new', we are constructing an object
        // nevertheless
        if ( !(this instanceof arguments.callee) ) {
            return new Jolokia(param);
        }

        if (param == null || param.url == null) {
            throw new SyntaxError("No URL given");
        }
        $.extend(this,DEFAULT_CLIENT_PARAMS,param);

        /**
         * The request method using one or more JSON requests
         * and sending it to the target URL.
         */
        this.request = function(request,params) {
            var opts = $.extend({},this,params);
            var ajax_params = {};

            if (opts.method == "POST" || $.isArray(request)) {
                $.extend(ajax_params,POST_AJAX_PARAMS);
                ajax_params.data = JSON.stringify(request);
                ajax_params.url = opts.url;
            } else {
                $.extend(ajax_params,GET_AJAX_PARAMS);
                ajax_params.dataType = opts.jsonp ? "jsonp" : "json";
                ajax_params.url = createGetUrl(opts.url,request);
            }

            // Callbacks
            if (params.success) {
                var success_callbacks = $.isArray(params.success) ? params.success : [ params.success ],
                        idx = 0,
                        length = success_callbacks.length;
                ajax_params.success = function(data,textStatus,xmlRequest) {
                    success_callbacks[idx++ % length](data,textStatus,xmlRequest);
                };
                $.ajax(ajax_params);
            }
        };
    }

    // ======================================================================================================
    // GET-Request handling

    /**
     * Create the URL used for a GET request
     *
     * @param base_url to request to
     * @param request the request to convert to URL format
     */
    function createGetUrl(base_url, request) {
        var type = request.type;
        if (type == null) {
            throw new Error("No request type given for building a GET request");
        }
        type = type.toLowerCase();
        var extractor = GET_URL_EXTRACTORS[type];
        if (extractor == null) {
            throw new Error("Unknown request type " + type);
        }
        var parts = extractor(request);
        var url = type;
        for (var i = 0; i < parts.length; i++) {
            url += "/" + escapePart(parts[i]);
        }
        return base_url + "/" + url;
    }

    // Extractors used for preparing a GET request, i.e. for creating a stack
    // of arguments which gets appended to create the proper access URL
    // key: lowercase request type
    var GET_URL_EXTRACTORS = {
        "read" : function(request) {
            return appendPath([ request.mbean, request.attribute ],request.path);
        },
        "write" : function(request) {
            return appendPath([ request.mbean, request.attribute, valueToString(request.value) ],request.path);
        },
        "exec" : function(request) {
            var ret = [ request.mbean, request.operation ];
            if (request.arguments && request.arguments.length > 0) {
                $.each(request.arguments,function(index,value) {
                    ret.push(valueToString(value));
                });
            }
            return ret;
        },
        "version": function() {
            return [];
        },
        "search": function(request) {
            return [ request.mbean ];
        },
        "list": function(request) {
            return appendPath([],request.path);
        }
    };

    function escapePart(part) {
        // TODO: Escaping of slashes
        return part;
    }

    // Split up a path and append it to a given array
    function appendPath(array,path) {
         return path ? $.merge(array,path.split(/\//)) : array;
    }

    // Convert a value to a string for passing it to the Jolokia agent via
    // a get request (write, exec). Value can be either a single object or an array
    function valueToString(value) {
        if (value == null) {
            return "[null]";
        }
        if ($.isArray(value)) {
            var ret = "";
            for (var i = 0; i < value.length; i++) {
                ret += value == null ? "[null]" : singleValueToString(value[i]);
                if (i < value.length - 1) {
                    ret += ",";
                }
            }
            return ret;
        } else {
            return singleValueToString(value);
        }
    }

    // Single value conversion for write/exec GET requests
    function singleValueToString(value) {
        if ( typeof value === "string" && value.length == 0) {
            return "\"\"";
        } else {
            return value.toString();
        }
    }

    // ===============================================================================================

    // Return back constructor function
    return Jolokia;

})(jQuery);
<commit_msg>Fixed logo<commit_after>/*
 * Copyright 2009-2010 Roland Huss
 *
 * 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.
 */

/* =================================
 * Jolokia Javascript Client library
 * =================================
 *
 * Requires jQuery and json2.js (if no native JSON.stringify() support is available)
 */

var Jolokia = (function($) {

    // Default paramerters for GET and POST requests
    var DEFAULT_CLIENT_PARAMS = {
        type: "POST",
        jsonp: false
    };

    var GET_AJAX_PARAMS = {
        type: "GET"
    };

    var POST_AJAX_PARAMS = {
        type: "POST",
        processData: false,
        dataType: "json"
    };

    function Jolokia(param) {

        // If called without 'new', we are constructing an object
        // nevertheless
        if ( !(this instanceof arguments.callee) ) {
            return new Jolokia(param);
        }

        if (param == null || param.url == null) {
            throw new SyntaxError("No URL given");
        }
        $.extend(this,DEFAULT_CLIENT_PARAMS,param);

        /**
         * The request method using one or more JSON requests
         * and sending it to the target URL.
         *
         * @param request the request to send
         * @param params parameters used for sending the request
         */
        this.request = function(request,params) {
            var opts = $.extend({},this,params);
            var ajax_params = {};

            if (opts.method == "POST" || $.isArray(request)) {
                $.extend(ajax_params,POST_AJAX_PARAMS);
                ajax_params.data = JSON.stringify(request);
                ajax_params.url = opts.url;
            } else {
                $.extend(ajax_params,GET_AJAX_PARAMS);
                ajax_params.dataType = opts.jsonp ? "jsonp" : "json";
                ajax_params.url = createGetUrl(opts.url,request);
            }

            // Callbacks
            if (params.success) {
                var success_callbacks = $.isArray(params.success) ? params.success : [ params.success ],
                        idx = 0,
                        length = success_callbacks.length;
                ajax_params.success = function(data,textStatus,xmlRequest) {
                    success_callbacks[idx++ % length](data,textStatus,xmlRequest);
                };
                $.ajax(ajax_params);
            }
        };
    }

    // ======================================================================================================
    // GET-Request handling

    /**
     * Create the URL used for a GET request
     *
     * @param base_url to request to
     * @param request the request to convert to URL format
     */
    function createGetUrl(base_url, request) {
        var type = request.type;
        if (type == null) {
            throw new Error("No request type given for building a GET request");
        }
        type = type.toLowerCase();
        var extractor = GET_URL_EXTRACTORS[type];
        if (extractor == null) {
            throw new Error("Unknown request type " + type);
        }
        var parts = extractor(request);
        var url = type;
        for (var i = 0; i < parts.length; i++) {
            url += "/" + escapePart(parts[i]);
        }
        return base_url + "/" + url;
    }

    // Extractors used for preparing a GET request, i.e. for creating a stack
    // of arguments which gets appended to create the proper access URL
    // key: lowercase request type
    var GET_URL_EXTRACTORS = {
        "read" : function(request) {
            return appendPath([ request.mbean, request.attribute ],request.path);
        },
        "write" : function(request) {
            return appendPath([ request.mbean, request.attribute, valueToString(request.value) ],request.path);
        },
        "exec" : function(request) {
            var ret = [ request.mbean, request.operation ];
            if (request.arguments && request.arguments.length > 0) {
                $.each(request.arguments,function(index,value) {
                    ret.push(valueToString(value));
                });
            }
            return ret;
        },
        "version": function() {
            return [];
        },
        "search": function(request) {
            return [ request.mbean ];
        },
        "list": function(request) {
            return appendPath([],request.path);
        }
    };

    function escapePart(part) {
        // TODO: Escaping of slashes
        return part;
    }

    // Split up a path and append it to a given array
    function appendPath(array,path) {
         return path ? $.merge(array,path.split(/\//)) : array;
    }

    // Convert a value to a string for passing it to the Jolokia agent via
    // a get request (write, exec). Value can be either a single object or an array
    function valueToString(value) {
        if (value == null) {
            return "[null]";
        }
        if ($.isArray(value)) {
            var ret = "";
            for (var i = 0; i < value.length; i++) {
                ret += value == null ? "[null]" : singleValueToString(value[i]);
                if (i < value.length - 1) {
                    ret += ",";
                }
            }
            return ret;
        } else {
            return singleValueToString(value);
        }
    }

    // Single value conversion for write/exec GET requests
    function singleValueToString(value) {
        if ( typeof value === "string" && value.length == 0) {
            return "\"\"";
        } else {
            return value.toString();
        }
    }

    // ===============================================================================================

    // Return back exported function/constructor
    return Jolokia;

})(jQuery);
<|endoftext|>


<commit_before>import React from 'react';
import Snackbar from 'material-ui/Snackbar';
import {connect} from 'react-redux';
import {getLastError} from '../ErrorReducer';
import {Map} from 'immutable';

class ErrorSnackbar extends React.PureComponent {
  static defaultProps = {
    error: null
  };

  constructor(props) {
    super(props);
    this.state = {
      open: false
    };
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.error !== nextProps.error) {
      this.setState({open: true});
    }
  }

  handleRequestClose = () => {
    this.setState({open: false});
  }

  render() {
    const {error} = this.props;
    const {open} = this.state;
    let message = '';
    if (typeof error === 'string') {
      message = error;
    } else if (Map.isMap(error)) {
      message = error.get('message') || error.get('errmsg') || error.get('msg') || error.get('name');
    }
    return (<Snackbar
      bodyStyle={{
        backgroundColor: 'rgba(100, 0, 0, 0.87)'
      }}
      open={message
        ? open
        : false}
      message={message}
      autoHideDuration={3333}
      onRequestClose={this.handleRequestClose}/>);
  }
}

function mapStateToProps(store) {
  const error = getLastError(store);
  return {error};
}

export default connect(mapStateToProps)(ErrorSnackbar);
<commit_msg>Add ErrorSnackbar use immutable render mixin.<commit_after>import {Map} from 'immutable';
import React from 'react';
import Snackbar from 'material-ui/Snackbar';
import {connect} from 'react-redux';
import {shouldComponentUpdate} from 'react-immutable-render-mixin';
import {getLastError} from '../ErrorReducer';

class ErrorSnackbar extends React.PureComponent {
  static defaultProps = {
    error: null
  };

  constructor(props) {
    super(props);
    this.shouldComponentUpdate = shouldComponentUpdate.bind(this);
    this.state = {
      open: false
    };
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.error !== nextProps.error) {
      this.setState({open: true});
    }
  }

  handleRequestClose = () => {
    this.setState({open: false});
  }

  render() {
    const {error} = this.props;
    const {open} = this.state;
    let message = '';
    if (typeof error === 'string') {
      message = error;
    } else if (Map.isMap(error)) {
      message = error.get('message') || error.get('errmsg') || error.get('msg') || error.get('name');
    }
    return (<Snackbar
      bodyStyle={{
        backgroundColor: 'rgba(100, 0, 0, 0.87)'
      }}
      open={message
        ? open
        : false}
      message={message}
      autoHideDuration={3333}
      onRequestClose={this.handleRequestClose}/>);
  }
}

function mapStateToProps(store) {
  const error = getLastError(store);
  return {error};
}

export default connect(mapStateToProps)(ErrorSnackbar);
<|endoftext|>


<commit_before>// client.js - main client file that does most of the processing
'use strict';

var fs           = require('fs'),
    constants    = require('crypto').constants,
    request      = require('request'),
    util         = require('util'),
    EventEmitter = require('events').EventEmitter,
    Client       = require('./client').Client,
    qs           = require('querystring'),
    async        = require('async'),
    path         = require('path'),
    flatten      = require('flatten'),
    throttler    = require('./throttle'),
    pjson        = require('./../../package.json'),
    failCodes = {
      400: 'Bad Request',
      401: 'Not Authorized',
      403: 'Forbidden',
      404: 'Item not found',
      405: 'Method not Allowed',
      409: 'Conflict',
      422: 'Unprocessable Entity',   // zendesk sends this one back when you re-use an organization name
      429: 'Too Many Requests',
      500: 'Internal Server Error',
      503: 'Service Unavailable'
    };

Client = exports.Client = function (options) {
  this.options = options;
  this.sideLoad = [];
  this.userAgent = 'node-zendesk/' + pjson.version + ' (node/' + process.versions.node + ')';
  // Each client has its own cookies to isolate authentication between clients
  this._request = request.defaults({
    jar:      this.options.get('no-cookies') ? false : request.jar(),
    encoding: this.options.get('encoding') || null,
    timeout:  this.options.get('timeout')  || 240000,
    proxy:    this.options.get('proxy')    || null,
    secureOptions: constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1,
    forever: true,
    pool: {maxSockets: 100}
  });

  if (!this.jsonAPINames) {
    this.jsonAPINames = [];
  }

  if ('function' !== typeof this.options.get) {
    this.options.get = function (key) {
      return this[key];
    };
  }

};

util.inherits(Client, EventEmitter);

Client.prototype.request = function (method, uri) {
  var options, url, self = this, res, args = Array.prototype.slice.call(arguments),
      callback = args.pop(),
      body     = 'object' === typeof args[args.length - 1] && !Array.isArray(args[args.length - 1]) && args.pop(),
      auth     = this.options.get('password') ? ':' + this.options.get('password') : '/token:' + this.options.get('token'),
      encoded  = new Buffer(this.options.get('username') + auth).toString('base64'),
      proxy    = this.options.get('proxy'),
      useOAuth = this.options.get('oauth'),
      token    = this.options.get('token'),
      asUser   = this.options.get('asUser');

  url = assembleUrl(self, uri);

  if (options) { // is this ever used?
    self.options.headers = options;
  } else {
    self.options.headers = {
      'Content-Type': 'application/json',
      'Accept':       'application/json',
      'User-Agent':   self.userAgent,
      'Content-Length': body.length
    };
  }

  if(asUser){
    self.options.headers['X-On-Behalf-Of'] = asUser;
  }

  if (useOAuth) {// token is an oauth token obtained from OAuth2
    self.options.headers.Authorization = 'Bearer ' + token;
  } else {// token is an API token obtained from the Zendesk Settings UI
    self.options.headers.Authorization = 'Basic ' + encoded;
  }

  self.options.uri = url;
  self.options.method = method || 'GET';

  if ('GET' === method) {
    self.options.body = undefined;
  } else if (body) {
    self.options.body = JSON.stringify(body);
  } else if ('GET' !== method && 'application/json' === self.options.headers['Content-Type']) {
    self.options.body = '{}';
  }

  if (proxy) {
    self.options.proxy = proxy;
  }

  self.emit('debug::request', self.options);

  return this._request(self.options, function (err, response, result) {
    requestCallback(self, err, response, result, callback);
  });
};

Client.prototype.requestAll = function (method, uri) {
  var args         = Array.prototype.slice.call(arguments),
      callbackOpt  = args.pop(),
      nextPage     = 'Not Null!',
      bodyList     = [],
      statusList   = [],
      responseList = [],
      resultList   = [],
      self         = this,
      throttle     = this.options.get('throttle'),
      __request = Client.prototype.request;

  var errorCb, nextCb, completeCb;
  if ( typeof callbackOpt === 'function' ) {
    errorCb = callbackOpt;
    nextCb = function () {};
    completeCb = function (statusList, bodyList, responseList, resultList) {
      callbackOpt(null, statusList, bodyList, responseList, resultList)
    };
  } else {
    errorCb = callbackOpt.error;
    nextCb = callbackOpt.next;
    completeCb = callbackOpt.complete;
  }

  if ( throttle ) {
     __request = throttler( this, Client.prototype.request, throttle );
  }

  function processPage(status, body, response, result) {
    if(completeCb) { // only accumulate pages if a completeCb is provided
      statusList.push(status);
      bodyList.push(body);
      responseList.push(response);
      resultList.push(result);
    }
    nextPage = result ? result.next_page : null;
    nextCb(status, body, response, result, nextPage);
  }

  return __request.apply(this, args.concat(function (error, status, body, response, result) {
    if (error) {
      return errorCb(error);
    }
    processPage(status, body, response, result);
    async.whilst(
      function () {
        if (nextPage !== null) {
          return nextPage;
        } else {
          nextPage = '';
          return nextPage;
        }
      },
      function (cb) {
        __request.apply(self, ['GET', nextPage, function (error, status, body, response, result) {
          if (error) {
            return cb(error);
          }
          processPage(status, body, response, result);
          cb(null);
        }]);
      },
      function (err) {
        if (err) {
          return errorCb(err);
        } else if(completeCb) {
          return completeCb(statusList, flatten(bodyList), responseList, resultList);
        }
      }
      );
  }));
};

Client.prototype.requestUpload = function (uri, file, callback) {
  var self     = this,
      out,
      auth     = this.options.get('password') ? ':' + this.options.get('password') : '/token:' + this.options.get('token'),
      encoded  = new Buffer(this.options.get('username') + auth).toString('base64'),
      useOAuth = this.options.get('oauth'),
      token    = this.options.get('token'),
      uploadOptions = self.options;

  self.options.uri = assembleUrl(self, uri);
  self.options.method = 'POST';

  self.options.headers = {'Content-Type': 'application/binary'};

  if (useOAuth) {
    self.options.headers.Authorization = 'Bearer ' + token;
  } else {
    self.options.headers.Authorization = 'Basic ' + encoded;
  }

  out = this._request(self.options, function (err, response, result) {
    requestCallback(self, err, response, result, callback);
  });

  fs.createReadStream(file).pipe(out); // pipe the file!

};

Client.prototype.setSideLoad = function(arr){
  var self = this;
  self.sideLoad = arr;
}

function checkRequestResponse(self, response, result, callback) {
  var statusCode, error, retryAfter, res;

  if (!result) { // should this really be an error?
    error = new Error('Zendesk returned an empty result');
    error.statusCode = 204;
    return callback(error);
  }
  try {
    statusCode = response.statusCode;
    res = JSON.parse(result);
  }
  catch (ex) {
     // Emit Errors
    self.emit('debug::error', {exception: ex, code: statusCode, request: self.options, result: result});
  }

  self.emit('debug::response', {statusCode: statusCode, result: result});

  retryAfter = response.headers['retry-after'];
  if (retryAfter) {
    error = new Error('Zendesk rate limits 200 requests per minute');
    error.statusCode = 429;
    error.result = result;
    error.retryAfter = retryAfter;
    return callback(error);
  }

  if (failCodes[statusCode]) {
    error = new Error('Zendesk Error (' + statusCode + '): ' + failCodes[statusCode]);
    error.statusCode = statusCode;
    error.result = result;
    error.retryAfter = null;
    return callback(error);
  }

  return callback(null, res);
}

function requestCallback(self, err, response, result, callback) {
  if (err) {
    return callback(err);
  }

  checkRequestResponse(self, response, result, function(err, res) {
    if (err) {
      return callback(err);
    }
    var body = null;
    if (res) {
      if (self.jsonAPINames){
        for (var i = 0; i < self.jsonAPINames.length; i++){
          if (res.hasOwnProperty(self.jsonAPINames[i].toString())){
            body = res[self.jsonAPINames[i].toString()];
            break;
          }
        }
      }

      if (!body) {
        body = res;
      }
      if (self.hasOwnProperty('sideLoadMap')){
        body = populateFields(body, res, self.sideLoadMap);
      }
    } else {
      body = '';
    }

    return callback(null, response.statusCode, body, response, res);
  });

}

function populateFields(data, response, map){
  if (Array.isArray(data)){
    for (var i = 0; i < data.length; i++){
      var record = data[i];
      populateRecord(record);
    }
  } else {
    populateRecord(data);
  }
  return data;

  function populateRecord(record){
    for (var i = 0; i < map.length; i++){
      var field   = map[i].field;
      var name    = map[i].name;
      var dataset = map[i].dataset;

      if (record.hasOwnProperty(field) && response.hasOwnProperty(dataset)){
        //If specifying all, then put everything in response[dataset] to record[name]
        if ( map[i].hasOwnProperty('all') && map[i].all === true ){
          record[name] = response[dataset];
        } else {
          var key = 'id';
          if (map[i].hasOwnProperty('dataKey')){
            key = map[i].dataKey;
          }
          if (map[i].hasOwnProperty('array') && map[i].array){
            record[name] = findAllRecordsById(response[dataset], key, record[field]);
          } else {
            record[name] = findOneRecordById(response[dataset], key, record[field]);
          }
        }
      }
    }
    return record;
  }
}

function findAllRecordsById(data, key, id){
  var arr = [];
  for (var i = 0; i < data.length; i++){
    if (data[i][key] === id){
      arr.push(data[i]);
    }
  }
  return arr;
}

function findOneRecordById(data, key, id){
  for (var i = 0; i < data.length; i++){
    if (data[i][key] === id){
      return data[i];
    }
  }
  return null;
}

function assembleUrl(self, uri) {
  var lastElement,
      params = '';

  if ('object' === typeof uri && Array.isArray(uri)) {
    lastElement = uri.pop();
    if (lastElement) {
      // we have received an object ex. {"sort_by":"id","sort_order":"desc"}
      if ('object' === typeof lastElement) {
        if (self.sideLoad.length){
          lastElement.include = self.sideLoad.join(',');
        }
        params = '?' + qs.stringify(lastElement);
      }
      // we have received a query string ex. '?sort_by=id&sort_order=desc'
      else if (0 === lastElement.toString().indexOf('?')) {
        if (self.sideLoad.length){
          lastElement += '&include='+ self.sideLoad.join(',');
        }
        params = lastElement;
      }
      else {
        if (self.sideLoad.length){
          params = '?include=' + self.sideLoad.join(',');
        }
        uri.push(lastElement);
      }
    }
    return self.options.get('remoteUri') + '/' + uri.join('/') + '.json' + params;
  }
  else if ('string' === typeof uri && uri.indexOf(self.options.get('remoteUri')) === -1) {
    return self.options.get('remoteUri') + uri;
  }
  else {
    return uri;
  }
}
<commit_msg>Returning promises if no callback is given to the requests<commit_after>// client.js - main client file that does most of the processing
'use strict';

var fs           = require('fs'),
    constants    = require('crypto').constants,
    request      = require('request'),
    util         = require('util'),
    EventEmitter = require('events').EventEmitter,
    Client       = require('./client').Client,
    qs           = require('querystring'),
    async        = require('async'),
    path         = require('path'),
    flatten      = require('flatten'),
    throttler    = require('./throttle'),
    pjson        = require('./../../package.json'),
    failCodes = {
      400: 'Bad Request',
      401: 'Not Authorized',
      403: 'Forbidden',
      404: 'Item not found',
      405: 'Method not Allowed',
      409: 'Conflict',
      422: 'Unprocessable Entity',   // zendesk sends this one back when you re-use an organization name
      429: 'Too Many Requests',
      500: 'Internal Server Error',
      503: 'Service Unavailable'
    };

Client = exports.Client = function (options) {
  this.options = options;
  this.sideLoad = [];
  this.userAgent = 'node-zendesk/' + pjson.version + ' (node/' + process.versions.node + ')';
  // Each client has its own cookies to isolate authentication between clients
  this._request = request.defaults({
    jar:      this.options.get('no-cookies') ? false : request.jar(),
    encoding: this.options.get('encoding') || null,
    timeout:  this.options.get('timeout')  || 240000,
    proxy:    this.options.get('proxy')    || null,
    secureOptions: constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1,
    forever: true,
    pool: {maxSockets: 100}
  });

  if (!this.jsonAPINames) {
    this.jsonAPINames = [];
  }

  if ('function' !== typeof this.options.get) {
    this.options.get = function (key) {
      return this[key];
    };
  }

};

util.inherits(Client, EventEmitter);

Client.prototype.request = function (method, uri) {
  var options, url, self = this, res, args = Array.prototype.slice.call(arguments),
      callback = args.pop(),
      body     = 'object' === typeof args[args.length - 1] && !Array.isArray(args[args.length - 1]) && args.pop(),
      auth     = this.options.get('password') ? ':' + this.options.get('password') : '/token:' + this.options.get('token'),
      encoded  = new Buffer(this.options.get('username') + auth).toString('base64'),
      proxy    = this.options.get('proxy'),
      useOAuth = this.options.get('oauth'),
      token    = this.options.get('token'),
      asUser   = this.options.get('asUser');

  url = assembleUrl(self, uri);

  if (options) { // is this ever used?
    self.options.headers = options;
  } else {
    self.options.headers = {
      'Content-Type': 'application/json',
      'Accept':       'application/json',
      'User-Agent':   self.userAgent,
      'Content-Length': body.length
    };
  }

  if(asUser){
    self.options.headers['X-On-Behalf-Of'] = asUser;
  }

  if (useOAuth) {// token is an oauth token obtained from OAuth2
    self.options.headers.Authorization = 'Bearer ' + token;
  } else {// token is an API token obtained from the Zendesk Settings UI
    self.options.headers.Authorization = 'Basic ' + encoded;
  }

  self.options.uri = url;
  self.options.method = method || 'GET';

  if ('GET' === method) {
    self.options.body = undefined;
  } else if (body) {
    self.options.body = JSON.stringify(body);
  } else if ('GET' !== method && 'application/json' === self.options.headers['Content-Type']) {
    self.options.body = '{}';
  }

  if (proxy) {
    self.options.proxy = proxy;
  }

  self.emit('debug::request', self.options);

  return new Promise(function(resolve, reject) {
    self._request(self.options, function (err, response) {
      if (callback) return requestCallback(self, err, response, result, callback);
      return (error) ? reject(err) : resolve(response);
    });
  });
};

Client.prototype.requestAll = function (method, uri) {
  var args         = Array.prototype.slice.call(arguments),
      callbackOpt  = args.pop(),
      nextPage     = 'Not Null!',
      bodyList     = [],
      statusList   = [],
      responseList = [],
      resultList   = [],
      self         = this,
      throttle     = this.options.get('throttle'),
      __request = Client.prototype.request;

  return new Promise(function(resolve, reject) {

    var errorCb, nextCb, completeCb;
    if ( typeof callbackOpt === 'function' ) {
      errorCb = callbackOpt;
      nextCb = function () {};
      completeCb = function (statusList, bodyList, responseList, resultList) {
        callbackOpt(null, statusList, bodyList, responseList, resultList)
      };
    } else {
      errorCb = callbackOpt.error || reject;
      nextCb = callbackOpt.next || resolve;
      completeCb = callbackOpt.complete;
    }

    if ( throttle ) {
       __request = throttler( this, Client.prototype.request, throttle );
    }

    function processPage(status, body, response, result) {
      if(completeCb) { // only accumulate pages if a completeCb is provided
        statusList.push(status);
        bodyList.push(body);
        responseList.push(response);
        resultList.push(result);
      }
      nextPage = result ? result.next_page : null;
      nextCb(status, body, response, result, nextPage);
    }

    return __request.apply(this, args.concat(function (error, status, body, response, result) {
      if (error) {
        return errorCb(error);
      }
      processPage(status, body, response, result);
      async.whilst(
        function () {
          if (nextPage !== null) {
            return nextPage;
          } else {
            nextPage = '';
            return nextPage;
          }
        },
        function (cb) {
          __request.apply(self, ['GET', nextPage, function (error, status, body, response, result) {
            if (error) {
              return cb(error);
            }
            processPage(status, body, response, result);
            cb(null);
          }]);
        },
        function (err) {
          if (err) {
            return errorCb(err);
          } else if(completeCb) {
            return completeCb(statusList, flatten(bodyList), responseList, resultList);
          }
        }
        );
    }));
  });
};

Client.prototype.requestUpload = function (uri, file, callback) {
  var self     = this,
      out,
      auth     = this.options.get('password') ? ':' + this.options.get('password') : '/token:' + this.options.get('token'),
      encoded  = new Buffer(this.options.get('username') + auth).toString('base64'),
      useOAuth = this.options.get('oauth'),
      token    = this.options.get('token'),
      uploadOptions = self.options;

  self.options.uri = assembleUrl(self, uri);
  self.options.method = 'POST';

  self.options.headers = {'Content-Type': 'application/binary'};

  if (useOAuth) {
    self.options.headers.Authorization = 'Bearer ' + token;
  } else {
    self.options.headers.Authorization = 'Basic ' + encoded;
  }

  return new Promise(function(resolve, reject) {
    out = this._request(self.options, function (err, response, result) {
      if (callback) {
        callback(self, err, response, result, callback);
      } else {
        return (err) ? reject(err) : resolve(response);
      }
    });

    fs.createReadStream(file).pipe(out); // pipe the file!
  });
};

Client.prototype.setSideLoad = function(arr){
  var self = this;
  self.sideLoad = arr;
}

function checkRequestResponse(self, response, result, callback) {
  var statusCode, error, retryAfter, res;

  if (!result) { // should this really be an error?
    error = new Error('Zendesk returned an empty result');
    error.statusCode = 204;
    return callback(error);
  }
  try {
    statusCode = response.statusCode;
    res = JSON.parse(result);
  }
  catch (ex) {
     // Emit Errors
    self.emit('debug::error', {exception: ex, code: statusCode, request: self.options, result: result});
  }

  self.emit('debug::response', {statusCode: statusCode, result: result});

  retryAfter = response.headers['retry-after'];
  if (retryAfter) {
    error = new Error('Zendesk rate limits 200 requests per minute');
    error.statusCode = 429;
    error.result = result;
    error.retryAfter = retryAfter;
    return callback(error);
  }

  if (failCodes[statusCode]) {
    error = new Error('Zendesk Error (' + statusCode + '): ' + failCodes[statusCode]);
    error.statusCode = statusCode;
    error.result = result;
    error.retryAfter = null;
    return callback(error);
  }

  return callback(null, res);
}

function requestCallback(self, err, response, result, callback) {
  if (err) {
    return callback(err);
  }

  checkRequestResponse(self, response, result, function(err, res) {
    if (err) {
      return callback(err);
    }
    var body = null;
    if (res) {
      if (self.jsonAPINames){
        for (var i = 0; i < self.jsonAPINames.length; i++){
          if (res.hasOwnProperty(self.jsonAPINames[i].toString())){
            body = res[self.jsonAPINames[i].toString()];
            break;
          }
        }
      }

      if (!body) {
        body = res;
      }
      if (self.hasOwnProperty('sideLoadMap')){
        body = populateFields(body, res, self.sideLoadMap);
      }
    } else {
      body = '';
    }

    return callback(null, response.statusCode, body, response, res);
  });

}

function populateFields(data, response, map){
  if (Array.isArray(data)){
    for (var i = 0; i < data.length; i++){
      var record = data[i];
      populateRecord(record);
    }
  } else {
    populateRecord(data);
  }
  return data;

  function populateRecord(record){
    for (var i = 0; i < map.length; i++){
      var field   = map[i].field;
      var name    = map[i].name;
      var dataset = map[i].dataset;

      if (record.hasOwnProperty(field) && response.hasOwnProperty(dataset)){
        //If specifying all, then put everything in response[dataset] to record[name]
        if ( map[i].hasOwnProperty('all') && map[i].all === true ){
          record[name] = response[dataset];
        } else {
          var key = 'id';
          if (map[i].hasOwnProperty('dataKey')){
            key = map[i].dataKey;
          }
          if (map[i].hasOwnProperty('array') && map[i].array){
            record[name] = findAllRecordsById(response[dataset], key, record[field]);
          } else {
            record[name] = findOneRecordById(response[dataset], key, record[field]);
          }
        }
      }
    }
    return record;
  }
}

function findAllRecordsById(data, key, id){
  var arr = [];
  for (var i = 0; i < data.length; i++){
    if (data[i][key] === id){
      arr.push(data[i]);
    }
  }
  return arr;
}

function findOneRecordById(data, key, id){
  for (var i = 0; i < data.length; i++){
    if (data[i][key] === id){
      return data[i];
    }
  }
  return null;
}

function assembleUrl(self, uri) {
  var lastElement,
      params = '';

  if ('object' === typeof uri && Array.isArray(uri)) {
    lastElement = uri.pop();
    if (lastElement) {
      // we have received an object ex. {"sort_by":"id","sort_order":"desc"}
      if ('object' === typeof lastElement) {
        if (self.sideLoad.length){
          lastElement.include = self.sideLoad.join(',');
        }
        params = '?' + qs.stringify(lastElement);
      }
      // we have received a query string ex. '?sort_by=id&sort_order=desc'
      else if (0 === lastElement.toString().indexOf('?')) {
        if (self.sideLoad.length){
          lastElement += '&include='+ self.sideLoad.join(',');
        }
        params = lastElement;
      }
      else {
        if (self.sideLoad.length){
          params = '?include=' + self.sideLoad.join(',');
        }
        uri.push(lastElement);
      }
    }
    return self.options.get('remoteUri') + '/' + uri.join('/') + '.json' + params;
  }
  else if ('string' === typeof uri && uri.indexOf(self.options.get('remoteUri')) === -1) {
    return self.options.get('remoteUri') + uri;
  }
  else {
    return uri;
  }
}
<|endoftext|>