<commit_before>import { Trans, t } from "@lingui/macro";
import { withI18n } from "@lingui/react";
import PropTypes from "prop-types";
import React from "react";
import { Link } from "react-router";

import Breadcrumb from "../../../components/Breadcrumb";
import BreadcrumbTextContent from "../../../components/BreadcrumbTextContent";
import MesosStateStore from "../../../stores/MesosStateStore";
import Page from "../../../components/Page";
import TaskDetail from "../../../../../plugins/services/src/js/pages/task-details/TaskDetail";
import VirtualNetworksStore from "../../../stores/VirtualNetworksStore";

const dontScrollRoutes = [/\/files\/view.*$/, /\/logs.*$/];

const NetworksDetailTaskBreadcrumbs = ({
  overlayID,
  overlay,
  taskID,
  task
}) => {
  const crumbs = [
    <Breadcrumb key={0} title="Networks">
      <BreadcrumbTextContent>
        <Trans render={<Link to="/networking/networks" />}>Networks</Trans>
      </BreadcrumbTextContent>
    </Breadcrumb>
  ];

  let overlayName = overlayID;
  if (overlay) {
    overlayName = overlay.getName();
    crumbs.push(
      <Breadcrumb key={1} title={overlayName}>
        <BreadcrumbTextContent>
          <Link to={`/networking/networks/${overlayName}`}>{overlayName}</Link>
        </BreadcrumbTextContent>
      </Breadcrumb>
    );
  } else {
    crumbs.push(
      <Breadcrumb key={1} title={overlayID}>
        <BreadcrumbTextContent>{overlayID}</BreadcrumbTextContent>
      </Breadcrumb>
    );
  }

  if (task) {
    const taskName = task.getName();
    crumbs.push(
      <Breadcrumb key={2} title={taskName}>
        <BreadcrumbTextContent>
          <Link to={`/networking/networks/${overlayName}/tasks/${taskName}`}>
            {taskName}
          </Link>
        </BreadcrumbTextContent>
      </Breadcrumb>
    );
  } else {
    crumbs.push(
      <Breadcrumb key={2} title={taskID}>
        <BreadcrumbTextContent>{taskID}</BreadcrumbTextContent>
      </Breadcrumb>
    );
  }

  return <Page.Header.Breadcrumbs iconID="networking" breadcrumbs={crumbs} />;
};

class VirtualNetworkTaskPage extends React.Component {
  render() {
    const { location, params, routes, i18n } = this.props;
    const { overlayName, taskID } = params;

    const routePrefix = `/networking/networks/${overlayName}/tasks/${taskID}`;
    const tabs = [
      {
        label: i18n._(t`Details`),
        routePath: routePrefix + "/details"
      },
      { label: i18n._(t`Files`), routePath: routePrefix + "/files" },
      { label: i18n._(t`Logs`), routePath: routePrefix + "/logs" }
    ];

    const task = MesosStateStore.getTaskFromTaskID(taskID);

    const overlay = VirtualNetworksStore.getOverlays().findItem(overlay => {
      return overlay.getName() === overlayName;
    });

    let breadcrumbs;
    if (task != null) {
      breadcrumbs = (
        <NetworksDetailTaskBreadcrumbs
          overlayID={overlayName}
          overlay={overlay}
          taskID={taskID}
          taskName={task.getName()}
        />
      );
    } else {
      breadcrumbs = <NetworksDetailTaskBreadcrumbs />;
    }

    const dontScroll = dontScrollRoutes.some(regex => {
      return regex.test(location.pathname);
    });

    return (
      <Page dontScroll={dontScroll}>
        <Page.Header
          breadcrumbs={breadcrumbs}
          tabs={tabs}
          iconID="networking"
        />
        <TaskDetail params={params} routes={routes}>
          {this.props.children}
        </TaskDetail>
      </Page>
    );
  }
}

VirtualNetworkTaskPage.propTypes = {
  params: PropTypes.object,
  routes: PropTypes.array
};

module.exports = withI18n()(VirtualNetworkTaskPage);
<commit_msg>fix(VirtualNetworkTaskPage): remove unnecessary use of HOC<commit_after>import { Trans } from "@lingui/macro";
import { i18nMark } from "@lingui/react";
import PropTypes from "prop-types";
import React from "react";
import { Link } from "react-router";

import Breadcrumb from "../../../components/Breadcrumb";
import BreadcrumbTextContent from "../../../components/BreadcrumbTextContent";
import MesosStateStore from "../../../stores/MesosStateStore";
import Page from "../../../components/Page";
import TaskDetail from "../../../../../plugins/services/src/js/pages/task-details/TaskDetail";
import VirtualNetworksStore from "../../../stores/VirtualNetworksStore";

const dontScrollRoutes = [/\/files\/view.*$/, /\/logs.*$/];

const NetworksDetailTaskBreadcrumbs = ({
  overlayID,
  overlay,
  taskID,
  task
}) => {
  const crumbs = [
    <Breadcrumb key={0} title="Networks">
      <BreadcrumbTextContent>
        <Trans render={<Link to="/networking/networks" />}>Networks</Trans>
      </BreadcrumbTextContent>
    </Breadcrumb>
  ];

  let overlayName = overlayID;
  if (overlay) {
    overlayName = overlay.getName();
    crumbs.push(
      <Breadcrumb key={1} title={overlayName}>
        <BreadcrumbTextContent>
          <Link to={`/networking/networks/${overlayName}`}>{overlayName}</Link>
        </BreadcrumbTextContent>
      </Breadcrumb>
    );
  } else {
    crumbs.push(
      <Breadcrumb key={1} title={overlayID}>
        <BreadcrumbTextContent>{overlayID}</BreadcrumbTextContent>
      </Breadcrumb>
    );
  }

  if (task) {
    const taskName = task.getName();
    crumbs.push(
      <Breadcrumb key={2} title={taskName}>
        <BreadcrumbTextContent>
          <Link to={`/networking/networks/${overlayName}/tasks/${taskName}`}>
            {taskName}
          </Link>
        </BreadcrumbTextContent>
      </Breadcrumb>
    );
  } else {
    crumbs.push(
      <Breadcrumb key={2} title={taskID}>
        <BreadcrumbTextContent>{taskID}</BreadcrumbTextContent>
      </Breadcrumb>
    );
  }

  return <Page.Header.Breadcrumbs iconID="networking" breadcrumbs={crumbs} />;
};

class VirtualNetworkTaskPage extends React.Component {
  render() {
    const { location, params, routes } = this.props;
    const { overlayName, taskID } = params;

    const routePrefix = `/networking/networks/${overlayName}/tasks/${taskID}`;
    const tabs = [
      {
        label: i18nMark("Details"),
        routePath: routePrefix + "/details"
      },
      {
        label: i18nMark("Files"),
        routePath: routePrefix + "/files"
      },
      {
        label: i18nMark("Logs"),
        routePath: routePrefix + "/logs"
      }
    ];

    const task = MesosStateStore.getTaskFromTaskID(taskID);

    const overlay = VirtualNetworksStore.getOverlays().findItem(overlay => {
      return overlay.getName() === overlayName;
    });

    let breadcrumbs;
    if (task != null) {
      breadcrumbs = (
        <NetworksDetailTaskBreadcrumbs
          overlayID={overlayName}
          overlay={overlay}
          taskID={taskID}
          taskName={task.getName()}
        />
      );
    } else {
      breadcrumbs = <NetworksDetailTaskBreadcrumbs />;
    }

    const dontScroll = dontScrollRoutes.some(regex => {
      return regex.test(location.pathname);
    });

    return (
      <Page dontScroll={dontScroll}>
        <Page.Header
          breadcrumbs={breadcrumbs}
          tabs={tabs}
          iconID="networking"
        />
        <TaskDetail params={params} routes={routes}>
          {this.props.children}
        </TaskDetail>
      </Page>
    );
  }
}

VirtualNetworkTaskPage.propTypes = {
  params: PropTypes.object,
  routes: PropTypes.array
};

module.exports = VirtualNetworkTaskPage;
<|endoftext|>


<commit_before>/**
 * Vosao CMS. Simple CMS for Google App Engine.
 *
 * Copyright (C) 2009-2010 Vosao development team.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * email: vosao.dev@gmail.com
 */

var parentURL = null;
var root = null;
var page = null;
var showTitle = $.cookie("pages.showTitle") != 'names';

$(function() {
    $("#page-dialog").dialog({ width: 400, autoOpen: false });
	Vosao.initJSONRpc(loadData);
	$('#cancelDlgButton').click(onPageCancel);
    $('#pageForm').submit(function() {onSave(); return false;});
    $('#title').change(onTitleChange);
    renderShowTitle();
});

function loadData() {
	loadTree();
	loadUser();
}

function loadTree() {
	Vosao.jsonrpc.pageService.getTree(function(r) {
		root = r;
		$('#pages-tree').html(renderPage(r));
		$("#pages-tree").treeview({
			animated: "fast",
			collapsed: true,
			unique: true,
			persist: "cookie",
			cookieId: "pageTree"
		});
		$('.content-link').each(function () {
			$(this).mouseover(function(event) {
				$('.page_edit').hide()
				$(event.target).siblings('.page_edit').show()
			});
		});
	});
}

function renderPage(vo) {
	var pageUrl = encodeURIComponent(vo.entity.friendlyURL);
	var title = showTitle ? vo.entity.title : vo.entity.pageFriendlyURL;
	if (!title) {
		title = '/';
	}
	var p = vo.entity.hasPublishedVersion ? 'published' : 'unpublished';
	var published_msg = messages(p);
	var published_link = ' ';
	if (!vo.entity.hasPublishedVersion) {
		published_link = ' '
			+ '';
	}
	var html = '
 ' + published_link

			+ ' '
			+ title + ' '

			+ ''

			+ ' '

			+ ''
			+ ' '

			+ ''
			+ ' '

			+ ''
			+ ''

			+ '';
	if (vo.children.list.length > 0) {
		html += '
';
		$.each(vo.children.list, function(n, value) {
			html += renderPage(value);
		});
		html += '
';
	}
	return html + '
';
}

function loadUser() {
	Vosao.jsonrpc.userService.getLoggedIn(function(r) {
		if (!r.admin) {
		    $('#structuresTab').hide();
		}
	});
}

function onPageRemove(url) {
	if (confirm(messages('are_you_sure'))) {
		Vosao.jsonrpc.pageService.remove(function(r) {
			Vosao.showServiceMessages(r);
			loadData();
		}, url);
	}
}

function onPageAdd(parent) {
	$('#ui-dialog-title-page-dialog').text(messages('pages.new_page'));
	parentURL = parent == '/' ? '' : parent;
	$('#page-dialog').dialog('open');
	$('#parentURL').html(parentURL + '/');
	$('#title').val('');
	$('#url').val('');
	$('#url').removeAttr('disabled');
	$('#title').focus();
	page = null;
}

function onPageCancel() {
	$('#page-dialog').dialog('close');
}

function onTitleChange() {
	var url = $("#url").val();
	var title = $("#title").val();
	if (url == '') {
		$("#url").val(Vosao.urlFromTitle(title));
	}
}

function validate(vo) {
	if (vo.title == '') {
		return messages('title_is_empty');
	}
	else {
		if (vo.title.indexOf(',') != -1) {
			return messages('pages.coma_not_allowed');
		}
	}
	if (vo.url == '') {
		return messages('pages.url_is_empty');
	}
	else {
		if (vo.url.indexOf('/') != -1) {
			return messages('pages.slash_not_allowed');
		}
	}
}

function onSave() {
	var vo = {
		id : page == null ? '' : String(page.id),
		title : $('#title').val(),
		url : $('#url').val(),
		friendlyUrl : parentURL + '/' + $('#url').val()
	};
	var error = validate(vo);
	if (!error) {
		Vosao.jsonrpc.pageService.savePage(function(r) {
			if (r.result == 'success') {
				Vosao.info(messages('pages.success_created'));
				$('#page-dialog').dialog('close');
				loadData();
			}
			else {
				showError(r.message);
			}
		}, Vosao.javaMap(vo));
	}
	else {
		showError(error);
	}
}

function showError(msg) {
	Vosao.errorMessage('#pageMessages', msg);
}

function onPagePublish(id) {
	if (confirm(messages('are_you_sure'))) {
		Vosao.jsonrpc.pageService.approve(function(r) {
			Vosao.showServiceMessages(r);
			loadData();
		}, id);
	}
}

function findPage(id) {
	return findChildPage(root, id);
}

function findChildPage(page, id) {
	if (page.entity.id == id) {
		return page;
	}
	var result = null;
	if (page.children.list.length > 0) {
		$.each(page.children.list, function(i,value) {
			var res = findChildPage(value, id);
			if (res != null) {
				result = res;
			}
		});
	}
	return result;
}

function onChangeTitle(id) {
	var pageItem = findPage(id);
	page = pageItem.entity;
	$('#ui-dialog-title-page-dialog').text(messages('pages.change_page'));
	parentURL = page.parentUrl == '/' ? '' : page.parentUrl;
	$('#page-dialog').dialog('open');
	$('#parentURL').html(parentURL + '/');
	$('#title').val(page.title);
	$('#url').val(page.pageFriendlyURL);
	$('#url').attr('disabled', pageItem.children.list.length > 0);
	$('#title').focus();
}

function onShowTitle(flag) {
	showTitle = flag;
	renderShowTitle();
	if (showTitle) {
		$.cookie("pages.showTitle", 'titles', {path:'/', expires: 10});
	}
	else {
		$.cookie("pages.showTitle", 'names', {path:'/', expires: 10});
	}
	loadData();
}

function renderShowTitle() {
	if (showTitle) {
		$('#showTitleDiv').html(''
				+ messages('show_names') + '');
	}
	else {
		$('#showTitleDiv').html(''
				+ messages('show_titles') + '');
	}
}<commit_msg>Fixed issue 328<commit_after>/**
 * Vosao CMS. Simple CMS for Google App Engine.
 *
 * Copyright (C) 2009-2010 Vosao development team.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * email: vosao.dev@gmail.com
 */

var parentURL = null;
var root = null;
var page = null;
var showTitle = $.cookie("pages.showTitle") != 'names';

$(function() {
    $("#page-dialog").dialog({ width: 400, autoOpen: false });
	Vosao.initJSONRpc(loadData);
	$('#cancelDlgButton').click(onPageCancel);
    $('#pageForm').submit(function() {onSave(); return false;});
    $('#title').change(onTitleChange);
    renderShowTitle();
});

function loadData() {
	loadTree();
	loadUser();
}

function loadTree() {
	Vosao.jsonrpc.pageService.getTree(function(r) {
		root = r;
		$('#pages-tree').html(renderPage(r));
		$("#pages-tree").treeview({
			animated: "fast",
			collapsed: true,
			unique: true,
			persist: "cookie",
			cookieId: "pageTree"
		});
		$('.content-link').each(function () {
			$(this).mouseover(function(event) {
				$('.page_edit').hide()
				$(event.target).siblings('.page_edit').show()
			});
		});
		$('#pages-tree li').each(function () {
			$(this).hover(function(event) {
				$('.page_edit').hide();
				$('> .page_edit', event.target).show();
			}, function(event) {
				//$('> .page_edit', event.target).hide();
			});
		});
	});
}

function renderPage(vo) {
	var pageUrl = encodeURIComponent(vo.entity.friendlyURL);
	var title = showTitle ? vo.entity.title : vo.entity.pageFriendlyURL;
	if (!title) {
		title = '/';
	}
	var p = vo.entity.hasPublishedVersion ? 'published' : 'unpublished';
	var published_msg = messages(p);
	var published_link = ' ';
	if (!vo.entity.hasPublishedVersion) {
		published_link = ' '
			+ '';
	}
	var html = '
 ' + published_link

			+ ' '
			+ title + ' '

			+ ''

			+ ' '

			+ ''
			+ ' '

			+ ''
			+ ' '

			+ ''
			+ ''

			+ '';
	if (vo.children.list.length > 0) {
		html += '
';
		$.each(vo.children.list, function(n, value) {
			html += renderPage(value);
		});
		html += '
';
	}
	return html + '
';
}

function loadUser() {
	Vosao.jsonrpc.userService.getLoggedIn(function(r) {
		if (!r.admin) {
		    $('#structuresTab').hide();
		}
	});
}

function onPageRemove(url) {
	if (confirm(messages('are_you_sure'))) {
		Vosao.jsonrpc.pageService.remove(function(r) {
			Vosao.showServiceMessages(r);
			loadData();
		}, url);
	}
}

function onPageAdd(parent) {
	$('#ui-dialog-title-page-dialog').text(messages('pages.new_page'));
	parentURL = parent == '/' ? '' : parent;
	$('#page-dialog').dialog('open');
	$('#parentURL').html(parentURL + '/');
	$('#title').val('');
	$('#url').val('');
	$('#url').removeAttr('disabled');
	$('#title').focus();
	page = null;
}

function onPageCancel() {
	$('#page-dialog').dialog('close');
}

function onTitleChange() {
	var url = $("#url").val();
	var title = $("#title").val();
	if (url == '') {
		$("#url").val(Vosao.urlFromTitle(title));
	}
}

function validate(vo) {
	if (vo.title == '') {
		return messages('title_is_empty');
	}
	else {
		if (vo.title.indexOf(',') != -1) {
			return messages('pages.coma_not_allowed');
		}
	}
	if (vo.url == '') {
		return messages('pages.url_is_empty');
	}
	else {
		if (vo.url.indexOf('/') != -1) {
			return messages('pages.slash_not_allowed');
		}
	}
}

function onSave() {
	var vo = {
		id : page == null ? '' : String(page.id),
		title : $('#title').val(),
		url : $('#url').val(),
		friendlyUrl : parentURL + '/' + $('#url').val()
	};
	var error = validate(vo);
	if (!error) {
		Vosao.jsonrpc.pageService.savePage(function(r) {
			if (r.result == 'success') {
				Vosao.info(messages('pages.success_created'));
				$('#page-dialog').dialog('close');
				loadData();
			}
			else {
				showError(r.message);
			}
		}, Vosao.javaMap(vo));
	}
	else {
		showError(error);
	}
}

function showError(msg) {
	Vosao.errorMessage('#pageMessages', msg);
}

function onPagePublish(id) {
	if (confirm(messages('are_you_sure'))) {
		Vosao.jsonrpc.pageService.approve(function(r) {
			Vosao.showServiceMessages(r);
			loadData();
		}, id);
	}
}

function findPage(id) {
	return findChildPage(root, id);
}

function findChildPage(page, id) {
	if (page.entity.id == id) {
		return page;
	}
	var result = null;
	if (page.children.list.length > 0) {
		$.each(page.children.list, function(i,value) {
			var res = findChildPage(value, id);
			if (res != null) {
				result = res;
			}
		});
	}
	return result;
}

function onChangeTitle(id) {
	var pageItem = findPage(id);
	page = pageItem.entity;
	$('#ui-dialog-title-page-dialog').text(messages('pages.change_page'));
	parentURL = page.parentUrl == '/' ? '' : page.parentUrl;
	$('#page-dialog').dialog('open');
	$('#parentURL').html(parentURL + '/');
	$('#title').val(page.title);
	$('#url').val(page.pageFriendlyURL);
	$('#url').attr('disabled', pageItem.children.list.length > 0);
	$('#title').focus();
}

function onShowTitle(flag) {
	showTitle = flag;
	renderShowTitle();
	if (showTitle) {
		$.cookie("pages.showTitle", 'titles', {path:'/', expires: 10});
	}
	else {
		$.cookie("pages.showTitle", 'names', {path:'/', expires: 10});
	}
	loadData();
}

function renderShowTitle() {
	if (showTitle) {
		$('#showTitleDiv').html(''
				+ messages('show_names') + '');
	}
	else {
		$('#showTitleDiv').html(''
				+ messages('show_titles') + '');
	}
}<|endoftext|>


<commit_before>import React from 'react';

// COMPONENTS
import BroadcastStats from './BroadcastStats.js';
import BroadcastLiveViewAUX from './BroadcastLiveViewAUX.js';
import BroadcastLiveViewSC from './BroadcastLiveViewSC.js';

// MATERIAL DESIGN
import Card from 'material-ui/lib/card/card';
import CardActions from '../../node_modules/material-ui/lib/card/card-actions';
import CardHeader from '../../node_modules/material-ui/lib/card/card-header';
import CardMedia from '../../node_modules/material-ui/lib/card/card-media';
import CardTitle from '../../node_modules/material-ui/lib/card/card-title';
import DropDownMenu from '../../node_modules/material-ui/lib/DropDownMenu';
import FlatButton from '../../node_modules/material-ui/lib/flat-button';
import FloatingActionButton from '../../node_modules/material-ui/lib/floating-action-button';
import Favorite from '../../node_modules/material-ui/lib/svg-icons/action/favorite';
import Face from '../../node_modules/material-ui/lib/svg-icons/action/face';
import TrendingUp from '../../node_modules/material-ui/lib/svg-icons/action/trending-up';
import MenuItem from '../../node_modules/material-ui/lib/menus/menu-item';
import Mic from '../../node_modules/material-ui/lib/svg-icons/av/mic';
import MicOff from '../../node_modules/material-ui/lib/svg-icons/av/mic-off';
import CardText from '../../node_modules/material-ui/lib/card/card-text';
import TextField from '../../node_modules/material-ui/lib/text-field';
import RaisedButton from '../../node_modules/material-ui/lib/raised-button';
import Colors from '../../node_modules/material-ui/lib/styles/colors';
import Tabs from '../../node_modules/material-ui/lib/tabs/tabs';
import Tab from '../../node_modules/material-ui/lib/tabs/tab';

import Paper from '../../node_modules/material-ui/lib/paper';

import ListItem from '../../node_modules/material-ui/lib/lists/list-item';
import Avatar from '../../node_modules/material-ui/lib/avatar';
import PlayCircleOutline from 'material-ui/lib/svg-icons/av/play-circle-outline';
import List from '../../node_modules/material-ui/lib/lists/list';

class BroadcastLiveView extends React.Component {
  render() {
    var partial;

    if (this.props.isLive === "AUX") {
      partial = (

            <canvas style={styles.visualizer} id="visualizer"></canvas>

          <BroadcastLiveViewAUX
            startBroadcast={this.props.startBroadcast}
            stopBroadcast={this.props.stopBroadcast}
            sourceInput={this.props.sourceInput}
            audioSources={this.props.state.audioSources}
            selectedSource={this.props.state.selectedSource}
            disabled={this.props.state.disabled} />

      )
    } else if (this.props.isLive === "SC") {
      partial = <BroadcastLiveViewSC
        submitSearch={this.props.submitSearch}
        addSongToQueue={this.props.addSongToQueue}
        removeSongFromQueue={this.props.removeSongFromQueue}
        currentSong={this.props.state.currentSong}
        handleMediaEnd={this.props.handleMediaEnd}
        startHTMLBroadcast={this.props.startHTMLBroadcast}
        stopHTMLBroadcast={this.props.stopHTMLBroadcast}
        loadMoreSongs={this.props.loadMoreSongs}
        songQueue={this.props.state.songQueue}
        endedSongQueue={this.props.state.endedSongQueue}
        favorites={this.props.state.favorites}
        searchResults={this.props.state.searchResults}
        disabled={this.props.state.disabled} />
    }

    return (

          <Card style={styles.mainBox}>

            <CardHeader
              onClick={this.props.goProfile}
              title={this.props.state.artistAlias}
              subtitle={this.props.state.artist}
              avatar={this.props.state.artistImage}
            />
            <CardMedia style={styles.streamImage}>

            </CardMedia>
            <CardTitle title={this.props.state.name}/>
            <CardText>
              {this.props.state.description}
            </CardText>
          </Card>
          <Card style={styles.box}>
            {partial}
          </Card>
          <Card style={styles.box}>
            <BroadcastStats
              listenerLiveCount={this.props.state.listenerLiveCount}
              listenerMaxCount={this.props.state.listenerMaxCount}
              heart={this.props.state.heartCount} />
          </Card>

    )
  }
}

var styles = {
  cardContainer:{
    'display': 'flex',
    'flexDirection':'row',
    'flexWrap': 'wrap'
  },

  box: {
    'flex': 2
  },

  mainBox: {
    'flex': 1,
    'maxWidth': '600px'
  },

  streamImage:{
    'maxWidth': '300px'
  },

  count:{
    'fontWeight': 'bold'
  },

  visualizer: {
    'width': '100%',
    'height': 200
  },

  visualizerContainer: {
    'height': 200,
    'margin': '5px',
    'border': '1px solid black'
  }
}

export default BroadcastLiveView;
<commit_msg>Changed call to stop stream (old one was duplicate code).<commit_after>import React from 'react';

// COMPONENTS
import BroadcastStats from './BroadcastStats.js';
import BroadcastLiveViewAUX from './BroadcastLiveViewAUX.js';
import BroadcastLiveViewSC from './BroadcastLiveViewSC.js';

// MATERIAL DESIGN
import Card from 'material-ui/lib/card/card';
import CardActions from '../../node_modules/material-ui/lib/card/card-actions';
import CardHeader from '../../node_modules/material-ui/lib/card/card-header';
import CardMedia from '../../node_modules/material-ui/lib/card/card-media';
import CardTitle from '../../node_modules/material-ui/lib/card/card-title';
import DropDownMenu from '../../node_modules/material-ui/lib/DropDownMenu';
import FlatButton from '../../node_modules/material-ui/lib/flat-button';
import FloatingActionButton from '../../node_modules/material-ui/lib/floating-action-button';
import Favorite from '../../node_modules/material-ui/lib/svg-icons/action/favorite';
import Face from '../../node_modules/material-ui/lib/svg-icons/action/face';
import TrendingUp from '../../node_modules/material-ui/lib/svg-icons/action/trending-up';
import MenuItem from '../../node_modules/material-ui/lib/menus/menu-item';
import Mic from '../../node_modules/material-ui/lib/svg-icons/av/mic';
import MicOff from '../../node_modules/material-ui/lib/svg-icons/av/mic-off';
import CardText from '../../node_modules/material-ui/lib/card/card-text';
import TextField from '../../node_modules/material-ui/lib/text-field';
import RaisedButton from '../../node_modules/material-ui/lib/raised-button';
import Colors from '../../node_modules/material-ui/lib/styles/colors';
import Tabs from '../../node_modules/material-ui/lib/tabs/tabs';
import Tab from '../../node_modules/material-ui/lib/tabs/tab';

import Paper from '../../node_modules/material-ui/lib/paper';

import ListItem from '../../node_modules/material-ui/lib/lists/list-item';
import Avatar from '../../node_modules/material-ui/lib/avatar';
import PlayCircleOutline from 'material-ui/lib/svg-icons/av/play-circle-outline';
import List from '../../node_modules/material-ui/lib/lists/list';

class BroadcastLiveView extends React.Component {
  render() {
    var partial;

    if (this.props.isLive === "AUX") {
      partial = (

            <canvas style={styles.visualizer} id="visualizer"></canvas>

          <BroadcastLiveViewAUX
            startBroadcast={this.props.startBroadcast}
            stopBroadcast={this.props.stopBroadcast}
            sourceInput={this.props.sourceInput}
            audioSources={this.props.state.audioSources}
            selectedSource={this.props.state.selectedSource}
            disabled={this.props.state.disabled} />

      )
    } else if (this.props.isLive === "SC") {
      partial = <BroadcastLiveViewSC
        submitSearch={this.props.submitSearch}
        addSongToQueue={this.props.addSongToQueue}
        removeSongFromQueue={this.props.removeSongFromQueue}
        currentSong={this.props.state.currentSong}
        handleMediaEnd={this.props.handleMediaEnd}
        startHTMLBroadcast={this.props.startHTMLBroadcast}
        stopBroadcast={this.props.stopBroadcast}
        loadMoreSongs={this.props.loadMoreSongs}
        songQueue={this.props.state.songQueue}
        endedSongQueue={this.props.state.endedSongQueue}
        favorites={this.props.state.favorites}
        searchResults={this.props.state.searchResults}
        disabled={this.props.state.disabled} />
    }

    return (

          <Card style={styles.mainBox}>

            <CardHeader
              onClick={this.props.goProfile}
              title={this.props.state.artistAlias}
              subtitle={this.props.state.artist}
              avatar={this.props.state.artistImage}
            />
            <CardMedia style={styles.streamImage}>

            </CardMedia>
            <CardTitle title={this.props.state.name}/>
            <CardText>
              {this.props.state.description}
            </CardText>
          </Card>
          <Card style={styles.box}>
            {partial}
          </Card>
          <Card style={styles.box}>
            <BroadcastStats
              listenerLiveCount={this.props.state.listenerLiveCount}
              listenerMaxCount={this.props.state.listenerMaxCount}
              heart={this.props.state.heartCount} />
          </Card>

    )
  }
}

var styles = {
  cardContainer:{
    'display': 'flex',
    'flexDirection':'row',
    'flexWrap': 'wrap'
  },

  box: {
    'flex': 2
  },

  mainBox: {
    'flex': 1,
    'maxWidth': '600px'
  },

  streamImage:{
    'maxWidth': '300px'
  },

  count:{
    'fontWeight': 'bold'
  },

  visualizer: {
    'width': '100%',
    'height': 200
  },

  visualizerContainer: {
    'height': 200,
    'margin': '5px',
    'border': '1px solid black'
  }
}

export default BroadcastLiveView;
<|endoftext|>


<commit_before>import Backbone from 'backbone';
import $ from 'jquery';
import _ from 'underscore';

import {SORT_DESC} from 'girder/constants';
import {DATE_SECOND, formatDate} from 'girder/misc';
import FileModel from 'girder/models/FileModel';
import {confirm} from 'girder/dialog';

import Collection from '../collections/Collection';
import Model from '../models/Model';
import UserModel from '../models/UserModel';
import View from '../view';
import {showAlertDialog} from '../common/utilities';
import router from '../router';

import ApplyMetadataSelectFilePageTemplate from './applyMetadataSelectFilePage.pug';
import ApplyMetadataPageTemplate from './applyMetadataPage.pug';
import './applyMetadataPage.styl';
import './datasetInfoWidget.styl';
import ApplyMetadataValidationPageTemplate from './applyMetadataValidationPage.pug';
import './applyMetadataValidationPage.styl';

// Model for a metadata file
const MetadataFileModel = Model.extend({
    name: function () {
        let time = formatDate(this.get('time'), DATE_SECOND);
        let fileName = this.get('file').name();
        let userName = this.get('user').name();
        return `${time} \u2014 ${fileName} \u2014 ${userName}`;
    }
});

// Collection of metadata files as returned by of DatasetModel.getRegisteredMetadata()
const MetadataFileCollection = Collection.extend({
    model: MetadataFileModel,

    // Sort in reverse chronological order
    sortField: 'time',
    sortDir: SORT_DESC,

    parse: function (data) {
        _.each(data, (item) => {
            item.file = new FileModel(item.file);
            item.user = new UserModel(item.user);

            // Use file ID as item ID
            item._id = item.file.id;
        });
        return data;
    }
});

// Model for a single metadata error or warning
const MetadataResultModel = Backbone.Model.extend({
    description: function () {
        return this.get('description');
    }
});

// Collection of metadata results, i.e. errors or warnings. The 'field' property
// should be set to the name of the field to parse in the response from the server.
// The list of items in the collection is meaningful only when initialized() is true.
const MetadataResultModelCollection = Backbone.Collection.extend({
    model: MetadataResultModel,
    field: null,

    _initialized: false,

    parse: function (resp) {
        this._initialized = true;
        return resp[this.field];
    },

    initialized: function () {
        return this._initialized;
    },

    uninitialize: function () {
        this._initialized = false;
        this.reset();
    }
});

// View for a collection of metadata files in a select tag.
// When user selects a file, a 'changed' event is triggered
// with the ID of the selected file as a parameter.
const ApplyMetadataSelectFileView = View.extend({
    events: {
        'change': 'fileChanged'
    },

    /**
     * @param {MetadataFileCollection} settings.collection
     */
    initialize: function (settings) {
        this.listenTo(this.collection, 'reset', this.render);
        this.render();
    },

    fileChanged: function () {
        let fileId = this.$('select').val();
        this.trigger('changed', fileId);
    },

    render: function () {
        // Destroy previous select2
        let select = this.$('#isic-apply-metadata-file-select');
        select.select2('destroy');

        this.$el.html(ApplyMetadataSelectFilePageTemplate({
            models: this.collection.toArray()
        }));

        // Set up select box
        let placeholder = 'Select a file...';
        if (!this.collection.isEmpty()) {
            placeholder += ` (${this.collection.length} available)`;
        }
        select = this.$('#isic-apply-metadata-file-select');
        select.select2({
            placeholder: placeholder,
            dropdownParent: this.$el
        });
        select.focus();

        return this;
    }
});

// View to select a registered metadata file, validate the metadata, and save
// the metadata to the dataset if validation is successful.
const ApplyMetadataView = View.extend({
    events: {
        'click #isic-apply-metadata-download-button': function () {
            // Download selected metadata file
            let fileModel = new FileModel({_id: this.file.id});
            fileModel.download();
        },

        'click #isic-apply-metadata-validate-button': function () {
            let save = false;
            this.validateMetadata(save);
        },

        'click #isic-apply-metadata-save': function () {
            // Show confirmation dialog
            confirm({
                text: '
Really save metadata?
',
                escapedHtml: true,
                yesText: 'Save',
                yesClass: 'btn-primary',
                confirmCallback: () => {
                    // Ensure dialog is hidden before continuing. Otherwise,
                    // when validateMetadata() displays its modal alert dialog,
                    // the Bootstrap-created element with class "modal-backdrop"
                    // is erroneously not removed.
                    $('#g-dialog-container').on('hidden.bs.modal', () => {
                        let save = true;
                        this.validateMetadata(save);
                    });
                }
            });
        }
    },

    /**
     * @param {DatasetModel} settings.dataset
     */
    initialize: function (settings) {
        this.dataset = settings.dataset;

        // Registered metadata files
        this.files = new MetadataFileCollection();

        // Selected metadata file
        this.file = null;

        // Errors and warnings in the selected metadata file
        this.errors = new MetadataResultModelCollection();
        this.errors.field = 'errors';
        this.warnings = new MetadataResultModelCollection();
        this.warnings.field = 'warnings';

        this.selectFileView = new ApplyMetadataSelectFileView({
            collection: this.files,
            parentView: this
        });

        this.listenTo(this.selectFileView, 'changed', this.fileChanged);
        this.listenTo(this.errors, 'reset', this.resultsChanged);
        this.listenTo(this.warnings, 'reset', this.resultsChanged);

        this.dataset
            .getRegisteredMetadata()
            .done((resp) => {
                this.files.reset(resp, {parse: true});
            });

        this.render();
    },

    fileChanged: function (fileId) {
        this.file = this.files.get(fileId);
        this.errors.uninitialize();

        // Enable action buttons
        this.$('#isic-apply-metadata-download-button, #isic-apply-metadata-validate-button').girderEnable(true);
    },

    resultsChanged: function () {
        this.renderValidationContainer();

        let allowSave = this.errors.initialized() && this.errors.isEmpty();
        this.$('#isic-apply-metadata-save').toggleClass('hidden', !allowSave);
    },

    render: function () {
        this.$el.html(ApplyMetadataPageTemplate({
            dataset: this.dataset
        }));

        this.selectFileView.setElement(
            this.$('#isic-apply-metadata-select-file-container')).render();

        this.renderValidationContainer();

        return this;
    },

    renderValidationContainer: function () {
        this.$('#isic-apply-metadata-validation-container').html(
            ApplyMetadataValidationPageTemplate({
                errors: this.errors,
                warnings: this.warnings,
                file: this.file
            }));

        return this;
    },

    validateMetadata: function (save) {
        this.dataset
            .applyMetadata(this.file.id, save)
            .done((resp) => {
                this.errors.reset(resp, {parse: true});
                this.warnings.reset(resp, {parse: true});

                if (save) {
                    showAlertDialog({
                        text: '
Metadata saved.
',
                        escapedHtml: true,
                        callback: () => {
                            router.navigate('', {trigger: true});
                        }
                    });
                }
            })
            .fail((err) => {
                showAlertDialog({text: `Error: ${err.responseJSON.message}`});
            });
    }
});

export default ApplyMetadataView;
<commit_msg>Metadata: Set field in collection constructor<commit_after>import Backbone from 'backbone';
import $ from 'jquery';
import _ from 'underscore';

import {SORT_DESC} from 'girder/constants';
import {DATE_SECOND, formatDate} from 'girder/misc';
import FileModel from 'girder/models/FileModel';
import {confirm} from 'girder/dialog';

import Collection from '../collections/Collection';
import Model from '../models/Model';
import UserModel from '../models/UserModel';
import View from '../view';
import {showAlertDialog} from '../common/utilities';
import router from '../router';

import ApplyMetadataSelectFilePageTemplate from './applyMetadataSelectFilePage.pug';
import ApplyMetadataPageTemplate from './applyMetadataPage.pug';
import './applyMetadataPage.styl';
import './datasetInfoWidget.styl';
import ApplyMetadataValidationPageTemplate from './applyMetadataValidationPage.pug';
import './applyMetadataValidationPage.styl';

// Model for a metadata file
const MetadataFileModel = Model.extend({
    name: function () {
        let time = formatDate(this.get('time'), DATE_SECOND);
        let fileName = this.get('file').name();
        let userName = this.get('user').name();
        return `${time} \u2014 ${fileName} \u2014 ${userName}`;
    }
});

// Collection of metadata files as returned by of DatasetModel.getRegisteredMetadata()
const MetadataFileCollection = Collection.extend({
    model: MetadataFileModel,

    // Sort in reverse chronological order
    sortField: 'time',
    sortDir: SORT_DESC,

    parse: function (data) {
        _.each(data, (item) => {
            item.file = new FileModel(item.file);
            item.user = new UserModel(item.user);

            // Use file ID as item ID
            item._id = item.file.id;
        });
        return data;
    }
});

// Model for a single metadata error or warning
const MetadataResultModel = Backbone.Model.extend({
    description: function () {
        return this.get('description');
    }
});

// Collection of metadata results, i.e. errors or warnings. The 'field' property
// should be set to the name of the field to parse in the response from the server.
// The list of items in the collection is meaningful only when initialized() is true.
const MetadataResultModelCollection = Backbone.Collection.extend({
    initialize: function (models, options) {
        this._field = options.field;
    },

    model: MetadataResultModel,

    _initialized: false,

    parse: function (resp) {
        this._initialized = true;
        return resp[this._field];
    },

    initialized: function () {
        return this._initialized;
    },

    uninitialize: function () {
        this._initialized = false;
        this.reset();
    }
});

// View for a collection of metadata files in a select tag.
// When user selects a file, a 'changed' event is triggered
// with the ID of the selected file as a parameter.
const ApplyMetadataSelectFileView = View.extend({
    events: {
        'change': 'fileChanged'
    },

    /**
     * @param {MetadataFileCollection} settings.collection
     */
    initialize: function (settings) {
        this.listenTo(this.collection, 'reset', this.render);
        this.render();
    },

    fileChanged: function () {
        let fileId = this.$('select').val();
        this.trigger('changed', fileId);
    },

    render: function () {
        // Destroy previous select2
        let select = this.$('#isic-apply-metadata-file-select');
        select.select2('destroy');

        this.$el.html(ApplyMetadataSelectFilePageTemplate({
            models: this.collection.toArray()
        }));

        // Set up select box
        let placeholder = 'Select a file...';
        if (!this.collection.isEmpty()) {
            placeholder += ` (${this.collection.length} available)`;
        }
        select = this.$('#isic-apply-metadata-file-select');
        select.select2({
            placeholder: placeholder,
            dropdownParent: this.$el
        });
        select.focus();

        return this;
    }
});

// View to select a registered metadata file, validate the metadata, and save
// the metadata to the dataset if validation is successful.
const ApplyMetadataView = View.extend({
    events: {
        'click #isic-apply-metadata-download-button': function () {
            // Download selected metadata file
            let fileModel = new FileModel({_id: this.file.id});
            fileModel.download();
        },

        'click #isic-apply-metadata-validate-button': function () {
            let save = false;
            this.validateMetadata(save);
        },

        'click #isic-apply-metadata-save': function () {
            // Show confirmation dialog
            confirm({
                text: '
Really save metadata?
',
                escapedHtml: true,
                yesText: 'Save',
                yesClass: 'btn-primary',
                confirmCallback: () => {
                    // Ensure dialog is hidden before continuing. Otherwise,
                    // when validateMetadata() displays its modal alert dialog,
                    // the Bootstrap-created element with class "modal-backdrop"
                    // is erroneously not removed.
                    $('#g-dialog-container').on('hidden.bs.modal', () => {
                        let save = true;
                        this.validateMetadata(save);
                    });
                }
            });
        }
    },

    /**
     * @param {DatasetModel} settings.dataset
     */
    initialize: function (settings) {
        this.dataset = settings.dataset;

        // Registered metadata files
        this.files = new MetadataFileCollection();

        // Selected metadata file
        this.file = null;

        // Errors and warnings in the selected metadata file
        this.errors = new MetadataResultModelCollection(null, {'field': 'errors'});
        this.warnings = new MetadataResultModelCollection(null, {'field': 'warnings'});

        this.selectFileView = new ApplyMetadataSelectFileView({
            collection: this.files,
            parentView: this
        });

        this.listenTo(this.selectFileView, 'changed', this.fileChanged);
        this.listenTo(this.errors, 'reset', this.resultsChanged);
        this.listenTo(this.warnings, 'reset', this.resultsChanged);

        this.dataset
            .getRegisteredMetadata()
            .done((resp) => {
                this.files.reset(resp, {parse: true});
            });

        this.render();
    },

    fileChanged: function (fileId) {
        this.file = this.files.get(fileId);
        this.errors.uninitialize();

        // Enable action buttons
        this.$('#isic-apply-metadata-download-button, #isic-apply-metadata-validate-button').girderEnable(true);
    },

    resultsChanged: function () {
        this.renderValidationContainer();

        let allowSave = this.errors.initialized() && this.errors.isEmpty();
        this.$('#isic-apply-metadata-save').toggleClass('hidden', !allowSave);
    },

    render: function () {
        this.$el.html(ApplyMetadataPageTemplate({
            dataset: this.dataset
        }));

        this.selectFileView.setElement(
            this.$('#isic-apply-metadata-select-file-container')).render();

        this.renderValidationContainer();

        return this;
    },

    renderValidationContainer: function () {
        this.$('#isic-apply-metadata-validation-container').html(
            ApplyMetadataValidationPageTemplate({
                errors: this.errors,
                warnings: this.warnings,
                file: this.file
            }));

        return this;
    },

    validateMetadata: function (save) {
        this.dataset
            .applyMetadata(this.file.id, save)
            .done((resp) => {
                this.errors.reset(resp, {parse: true});
                this.warnings.reset(resp, {parse: true});

                if (save) {
                    showAlertDialog({
                        text: '
Metadata saved.
',
                        escapedHtml: true,
                        callback: () => {
                            router.navigate('', {trigger: true});
                        }
                    });
                }
            })
            .fail((err) => {
                showAlertDialog({text: `Error: ${err.responseJSON.message}`});
            });
    }
});

export default ApplyMetadataView;
<|endoftext|>


<commit_before>/**
 * Aifang Javascript Framework.
 * Copyright 2012 ANJUKE Inc. All rights reserved.
 *
 *
 * 这是ajax核心文件，
 *
 *
 * @path: ajax/ajax.js
 * @author: Jock
 * @version: 1.0.1
 * @date: 2012/10/19
 *
 */

(function (J, W) {

    /**
     * 初始配置
     * @param {Boolean} async                 是否异步请求。默认为true（异步）
     * @param {String | Object} data         需要发送的数据。
     * @param {Object} headers               要设置的头信息
     * @return {Function} onSuccess           请求成功时触发，      function(XMLHttpRequest xhr, string responseText)
     * @return {Function} onFailure           请求失败时触发，      function(XMLHttpRequest xhr)
     * @return {Function} onBeforerequest     发送请求之前触发，    function(XMLHttpRequest xhr)
     * @return {Function} onTimeout           发送请求超时触发，    function(XMLHttpRequest xhr)
     * @param {String} cache                 是否需要缓存，默认为true（缓存）
     */
    var defaultOpts = {
        url:'',
        async:true,
        data:'',
        callback:'',
        headers:'',
        onSuccess:'',
        onFailure:'',
        onBeforerequest:'',
        onTimeout:'',
        cache:true,
        timeout:0, // 毫秒
        type:''
    }, encode = encodeURIComponent, ajaxObj, D = document, head = D.head || D.getElementsByTagName( "head" )[0], aboutBlank = 'about:blank';

    function Ajax(url, options, method) {

        var xhr, opts = defaultOpts, eventHandlers = {}, timerHander, timeout;

        J.isString(url) ? (opts.url = url) : (opts = J.mix(opts, url || {}, true));
        J.isFunction(options) ? (opts.onSuccess = options) : (opts = J.mix(opts, options || {}, true));

        timeout = parseInt(opts.timeout);

        if(opts.url == '') return null;

        method = method.toUpperCase();

        J.each("onSuccess onFailure onBeforerequest onTimeout".split(' '), function (i, k) {
            eventHandlers[k] = opts[k];
        });

        if (opts.type == 'jsonp') {
            method == 'GET' ? getJSONP() : postJSONP();
        } else {
            return ajax();
        }

        function unloadDispose(callback){
            var U = 'unload';
            if (J.ua.ie)
                W.attachEvent('on'+U, callback);
            else
                W.addEventListener(U, callback, false);
        }

        function clearTimeOut(){
            (timeout > 0 && timerHander) && clearTimeout(timerHander);
        }

        function domDispose(element, container, isAbort, state){
            if (isAbort || !state || /loaded|complete/.test(state)) {
                clearTimeOut();
                if(head && element){
                    element.src = aboutBlank;
                    element.onload = element.onreadystatechange = null;
                    element = container||element;
                    if (element && element.parentNode) {
                        head.removeChild(element);
                    }
                    element = undefined;
                }
                isAbort && fire('Failure');
            }
        }

        function domLoad(element, container){
            element.onload = element.onreadystatechange = function (_, isAbort) {
                if (isAbort || !element.readyState || /loaded|complete/.test(element.readyState)) {
                    domDispose(element, container, isAbort, element.readyState)
                }
            };
            if (timeout > 0) {
                timerHander = setTimeout(function () {
                    fire("Timeout");
                    domDispose(element, container, true)
                }, timeout);
            }
        }

        function getJSONP() {
            var script = D.createElement('script');
            domLoad(script);
            script.async = opts.async;
            script.charset = 'utf-8';
            script.src = buildUrl();
            head.insertBefore( script, head.firstChild );
        }

        function postJSONP() {
            var guid = 'J__RGID' + J.getTime().toString(16),
                sojContainer = D.createElement('div'),
                form = D.createElement('form'),
                inputs = [], items = opts.data;

            sojContainer.innerHTML = '';
            sojContainer.style.display = 'none';

            for (var k in items) {
                inputs.push("<input type='hidden' name='" + k + "' value='" + items[k] + "' />")
            }
            opts.callback && inputs.push("<input type='hidden' name='callback' value='" + opts.callback + "' />");
            form.innerHTML = inputs.join('');
            form.action = opts.url;
            form.method = 'post';
            form.target = guid;
            sojContainer.appendChild(form);
            head.appendChild( sojContainer, head.firstChild );

            var a = D.getElementById(guid);

            unloadDispose( function(){
                domDispose(head, sojContainer, true);
            } );

            a && domLoad(a, sojContainer);

            form.submit();
            form.action = aboutBlank;
            form.method = 'get';
            form.target = '_self';
        }

        function ajax() {
            try {
                var async = opts.async, headers = opts.headers, data = opts.data, aUrl;

                xhr = getXHR();

                headers['X-Request-With'] = 'XMLHttpRequest';

                if (method == 'GET') {
                    aUrl = buildUrl();
                    data = null
                } else {
                    aUrl = opts.url;
                    if (data && !J.isString(data)) (data = param(data));
                }

                xhr.open(method, aUrl, async);

                if (async) {
                    xhr.onreadystatechange = stateChangeHandler;
                }

                // 在open之后再进行http请求头设定
                if (method == 'POST') {
                    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                }

                for (var key in headers) {
                    if (headers.hasOwnProperty(key)) {
                        xhr.setRequestHeader(key, headers[key]);
                    }
                }

                fire('Beforerequest');

                if (timeout) {
                    timerHander = setTimeout(function () {
                        xhr.onreadystatechange = function () {
                        };
                        xhr.abort();
                        fire("Timeout");
                    }, parseInt(timeout));
                }

                xhr.send(data);

                if (!async) {
                    stateChangeHandler();
                }
            } catch (ex) {
                fire('Failure');
            }
            return xhr;
        }

        function buildUrl() {
            var data = opts.data, url = opts.url;
            if (data && !J.isString(data)) (data = param(data));
            if (method == "GET") {
                data && (url += fn() + data);
                (opts.type == 'jsonp' && opts.callback) && (url += fn() + 'callback=' + opts.callback);
                opts.cache || (url += fn() + 'J' + J.getTime())
            }
            function fn() {
                return url.indexOf('?') > 0 ? '&' : '?'
            }

            return url;
        }

        function param(a) {
            var s = [ ];

            function add(key, value) {
                s[ s.length ] = encode(key) + '=' + encode(value);
            }

            for (var j in a)
                add(j, J.isFunction(a[j]) ? a[j]() : a[j]);
            return s.join("&").replace(/%20/g, "+");
        }

        /**
         * readyState发生变更时调用
         *
         * @ignore
         */
        function stateChangeHandler() {
            if (xhr.readyState == 4) {
                try {
                    var stat = xhr.status;
                } catch (ex) {
                    // 在请求时，如果网络中断，Firefox会无法取得status
                    fire('Failure');
                    return;
                }
                if ((stat >= 200 && stat < 300) || stat == 304 || stat == 1223) {
                    fire('Success');
                } else {
                    fire('Failure');
                }
                xhr.onreadystatechange = function () {};
                if (opts.async) {
                    xhr = null;
                }
            }
        }

        /**
         * 获取XMLHttpRequest对象
         *
         * @ignore
         * @return {XMLHttpRequest} XMLHttpRequest对象
         */
        function getXHR() {
            if (W.ActiveXObject) {
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                    try {
                        return new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (e) {
                    }
                }
            }
            if (W.XMLHttpRequest) {
                return new XMLHttpRequest();
            }
        }

        /**
         * 触发事件
         *
         * @ignore
         * @param {String} type 事件类型
         */
        function fire(type) {
            type = 'on' + type;
            var handler = eventHandlers[type], responseRet;
            if (handler) {
                clearTimeOut();
                if (type != 'onSuccess') {
                    handler(xhr);
                } else {
                    try {
                        responseRet = (opts.type == 'json') ? (new Function("return (" + xhr.responseText + ")"))() : xhr.responseText
                    } catch (error) {
                        return handler(xhr);
                    }
                    handler(responseRet);
                }
            }
        }

    }

    ajaxObj = J.add('ajax');

    J.each('get post'.split(' '), function (i, v) {
        /**
         *
         * 发送一个get请求
         *
         * @grammar J.get(url | options [,function | options])
         *
         *    options.url               String
         *    options.data              Object | String
         *    options.type              String
         *    options.timeout           Int
         *    options.onSuccess         Function
         *    options.onFailure         Function
         *    options.onBeforerequest   Function
         *    options.async,            Boolean
         *
         *
         * @name J.ajax.get
         * @param {String|Object} options 请求的url或参数配置
         * @param {Object|Function} options 参数配置或者回调函数
         * @return {Object}
         *
         */

        /**
         * 发送一个post请求
         *
         * @grammar J.post(url | options [,function | options])
         *
         *    options.url               String
         *    options.data              Object | String
         *    options.type              String
         *    options.timeout           Int
         *    options.onSuccess         Function
         *    options.onFailure         Function
         *    options.onBeforerequest   Function
         *    options.async,            Boolean
         *
         *
         * @name J.ajax.post
         * @param {String|Object} options 请求的url或参数配置
         * @param {Object|Function} options 参数配置或者回调函数
         * @return {Object}
         *
         */

        ajaxObj[v] = function (url, options) {
            return new Ajax(url, options, v)
        };
    });

    J.mix(J, ajaxObj);

})(J, window);<commit_msg>modify ajax jsonp post<commit_after>/**
 * Aifang Javascript Framework.
 * Copyright 2012 ANJUKE Inc. All rights reserved.
 *
 *
 * 这是ajax核心文件，
 *
 *
 * @path: ajax/ajax.js
 * @author: Jock
 * @version: 1.0.1
 * @date: 2012/10/19
 *
 */

(function (J, W) {

    /**
     * 初始配置
     * @param {Boolean} async                 是否异步请求。默认为true（异步）
     * @param {String | Object} data         需要发送的数据。
     * @param {Object} headers               要设置的头信息
     * @return {Function} onSuccess           请求成功时触发，      function(XMLHttpRequest xhr, string responseText)
     * @return {Function} onFailure           请求失败时触发，      function(XMLHttpRequest xhr)
     * @return {Function} onBeforerequest     发送请求之前触发，    function(XMLHttpRequest xhr)
     * @return {Function} onTimeout           发送请求超时触发，    function(XMLHttpRequest xhr)
     * @param {String} cache                 是否需要缓存，默认为true（缓存）
     */
    var defaultOpts = {
        url:'',
        async:true,
        data:'',
        callback:'',
        headers:'',
        onSuccess:'',
        onFailure:'',
        onBeforerequest:'',
        onTimeout:'',
        cache:true,
        timeout:0, // 毫秒
        type:''
    }, encode = encodeURIComponent, ajaxObj, D = document, head = D.head || D.getElementsByTagName( "head" )[0], aboutBlank = 'about:blank', I = 0;

    function Ajax(url, options, method) {

        var xhr, opts = defaultOpts, eventHandlers = {}, timerHander, timeout;

        J.isString(url) ? (opts.url = url) : (opts = J.mix(opts, url || {}, true));
        J.isFunction(options) ? (opts.onSuccess = options) : (opts = J.mix(opts, options || {}, true));

        timeout = parseInt(opts.timeout);

        if(opts.url == '') return null;

        method = method.toUpperCase();

        J.each("onSuccess onFailure onBeforerequest onTimeout".split(' '), function (i, k) {
            eventHandlers[k] = opts[k];
        });

        if (opts.type == 'jsonp') {
            method == 'GET' ? getJSONP() : postJSONP();
        } else {
            return ajax();
        }

        function clearTimeOut(){
            (timeout > 0 && timerHander) && clearTimeout(timerHander);
        }

        function domDispose(element, container){
            clearTimeOut();
            if(head && element){
                element.onload = element.onreadystatechange = null;
                element = container||element;
                if (element && element.parentNode) {
                    head.removeChild(element);
                }
                element = undefined;
            }
        }

        function domLoad(element, container){
            element.onload = element.onreadystatechange = function (_, isAbort) {
                if (isAbort || !element.readyState || /loaded|complete/.test(element.readyState)) {
                    isAbort && fire('Failure');
                    domDispose(element, container);
                }
            };
            if (timeout > 0) {
                timerHander = setTimeout(function () {
                    fire("Timeout");
                    domDispose(element, container)
                }, timeout);
            }
        }

        function getJSONP() {
            var script = D.createElement('script');
            domLoad(script);
            script.async = opts.async;
            script.charset = 'utf-8';
            script.src = buildUrl();
            head.insertBefore( script, head.firstChild );
        }

        function postJSONP() {
            var guid = 'J__RGID' + J.getTime().toString(16) + (++I),
                sojContainer = D.createElement('div'),
                form = D.createElement('form'),
                inputs = [], items = opts.data;

            sojContainer.innerHTML = '';
            sojContainer.style.display = 'none';

            for (var k in items) {
                inputs.push("<input type='hidden' name='" + k + "' value='" + items[k] + "' />")
            }
            opts.callback && inputs.push("<input type='hidden' name='callback' value='" + opts.callback + "' />");
            form.innerHTML = inputs.join('');
            form.action = opts.url;
            form.method = 'post';
            form.target = guid;
            sojContainer.appendChild(form);
            head.appendChild( sojContainer, head.firstChild );

            var a = D.getElementById(guid);

            a && domLoad(a, sojContainer);

            form.submit();
            form.action = aboutBlank;
            form.method = 'get';
            form.target = '_self';
        }

        function ajax() {
            try {
                var async = opts.async, headers = opts.headers, data = opts.data, aUrl;

                xhr = getXHR();

                headers['X-Request-With'] = 'XMLHttpRequest';

                if (method == 'GET') {
                    aUrl = buildUrl();
                    data = null
                } else {
                    aUrl = opts.url;
                    if (data && !J.isString(data)) (data = param(data));
                }

                xhr.open(method, aUrl, async);

                if (async) {
                    xhr.onreadystatechange = stateChangeHandler;
                }

                // 在open之后再进行http请求头设定
                if (method == 'POST') {
                    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                }

                for (var key in headers) {
                    if (headers.hasOwnProperty(key)) {
                        xhr.setRequestHeader(key, headers[key]);
                    }
                }

                fire('Beforerequest');

                if (timeout) {
                    timerHander = setTimeout(function () {
                        xhr.onreadystatechange = function () {
                        };
                        xhr.abort();
                        fire("Timeout");
                    }, parseInt(timeout));
                }

                xhr.send(data);

                if (!async) {
                    stateChangeHandler();
                }
            } catch (ex) {
                fire('Failure');
            }
            return xhr;
        }

        function buildUrl() {
            var data = opts.data, url = opts.url;
            if (data && !J.isString(data)) (data = param(data));
            if (method == "GET") {
                data && (url += fn() + data);
                (opts.type == 'jsonp' && opts.callback) && (url += fn() + 'callback=' + opts.callback);
                opts.cache || (url += fn() + 'J' + J.getTime())
            }
            function fn() {
                return url.indexOf('?') > 0 ? '&' : '?'
            }

            return url;
        }

        function param(a) {
            var s = [ ];

            function add(key, value) {
                s[ s.length ] = encode(key) + '=' + encode(value);
            }

            for (var j in a)
                add(j, J.isFunction(a[j]) ? a[j]() : a[j]);
            return s.join("&").replace(/%20/g, "+");
        }

        /**
         * readyState发生变更时调用
         *
         * @ignore
         */
        function stateChangeHandler() {
            if (xhr.readyState == 4) {
                try {
                    var stat = xhr.status;
                } catch (ex) {
                    // 在请求时，如果网络中断，Firefox会无法取得status
                    fire('Failure');
                    return;
                }
                if ((stat >= 200 && stat < 300) || stat == 304 || stat == 1223) {
                    fire('Success');
                } else {
                    fire('Failure');
                }
                xhr.onreadystatechange = function () {};
                if (opts.async) {
                    xhr = null;
                }
            }
        }

        /**
         * 获取XMLHttpRequest对象
         *
         * @ignore
         * @return {XMLHttpRequest} XMLHttpRequest对象
         */
        function getXHR() {
            if (W.ActiveXObject) {
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP");
                } catch (e) {
                    try {
                        return new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (e) {
                    }
                }
            }
            if (W.XMLHttpRequest) {
                return new XMLHttpRequest();
            }
        }

        /**
         * 触发事件
         *
         * @ignore
         * @param {String} type 事件类型
         */
        function fire(type) {
            type = 'on' + type;
            var handler = eventHandlers[type], responseRet;
            if (handler) {
                clearTimeOut();
                if (type != 'onSuccess') {
                    handler(xhr);
                } else {
                    try {
                        responseRet = (opts.type == 'json') ? (new Function("return (" + xhr.responseText + ")"))() : xhr.responseText
                    } catch (error) {
                        return handler(xhr);
                    }
                    handler(responseRet);
                }
            }
        }

    }

    ajaxObj = J.add('ajax');

    J.each('get post'.split(' '), function (i, v) {
        /**
         *
         * 发送一个get请求
         *
         * @grammar J.get(url | options [,function | options])
         *
         *    options.url               String
         *    options.data              Object | String
         *    options.type              String
         *    options.timeout           Int
         *    options.onSuccess         Function
         *    options.onFailure         Function
         *    options.onBeforerequest   Function
         *    options.async,            Boolean
         *
         *
         * @name J.ajax.get
         * @param {String|Object} options 请求的url或参数配置
         * @param {Object|Function} options 参数配置或者回调函数
         * @return {Object}
         *
         */

        /**
         * 发送一个post请求
         *
         * @grammar J.post(url | options [,function | options])
         *
         *    options.url               String
         *    options.data              Object | String
         *    options.type              String
         *    options.timeout           Int
         *    options.onSuccess         Function
         *    options.onFailure         Function
         *    options.onBeforerequest   Function
         *    options.async,            Boolean
         *
         *
         * @name J.ajax.post
         * @param {String|Object} options 请求的url或参数配置
         * @param {Object|Function} options 参数配置或者回调函数
         * @return {Object}
         *
         */

        ajaxObj[v] = function (url, options) {
            return new Ajax(url, options, v)
        };
    });

    J.mix(J, ajaxObj);

})(J, window);<|endoftext|>


<commit_before>import {
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLString,
  GraphQLInt,
  GraphQLList
} from 'graphql';

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions,
} from 'graphql-relay';

let count = 0;

// http://stackoverflow.com/questions/10834796/validate-that-a-string-is-a-positive-integer
function isNormalInteger(str) {
    var n = ~~Number(str);
    return String(n) === str && n >= 0;
}

var typenames_count = {};

function sanitize(name) {
  let clean = name.replace(/\./g, '_').replace(/\//g, '_');
  if (typenames_count[clean]) {
    typenames_count[clean] = typenames_count[clean] + 1;
    clean = clean + '_' + (typenames_count[clean] - 1);
  } else {
    typenames_count[clean] = 1;
  }
  return clean;
}

function schemaFromArrayOfObjects(name, data, sheetSchemas, getRowFromSheetById) {
  return new GraphQLObjectType({
    name: sanitize(name),
    fields: () => {
      var firstRow = data[0];
      var fieldsFromData = {};
      // inferring types (Int or String) from first row
      Object.keys(firstRow).forEach(fieldName => {
        var val = firstRow[fieldName];
        var type;
        var relation = false;
        var normalizedName = fieldName;
        var sheetName = fieldName.slice(0, -2);
        if (fieldName.slice(fieldName.length - 2, fieldName.length) === 'Id') {
          normalizedName = sheetName;
          type = sheetSchemas[sheetName];
          relation = true;
        } else {
          type = isNormalInteger(val) ? GraphQLInt : GraphQLString;
        }
        fieldsFromData[normalizedName] = {
          type,
          description: 'Example value: ' + val,
          resolve: (row) => {
            if (relation) {
              return getRowFromSheetById(sheetName, row[fieldName]);
            }
            return row[fieldName];
          }
        }
      });
      return fieldsFromData;
    },
  });
}

function schemaFromSpreadSheet(name, obj, returnTheTypeOnly) {
  var sheetSchemas = {};
  var fieldsFromData = {};
  Object.keys(obj).reverse().forEach(sheetName => {
    var normalizedName = sheetName.replace(/s$/,'');
    sheetSchemas[normalizedName] = schemaFromArrayOfObjects(normalizedName, obj[sheetName], sheetSchemas,
      (sheet, id) => obj[(sheet + 's').replace(/ss$/,'s')].find(r => r.id === id));
    var args = {
      row: {
        type: GraphQLInt,
      },
    };
    var firstRow = obj[sheetName][0];
    var keys = Object.keys(firstRow);
    keys.forEach(key => {
      var val = firstRow[key];
      args[key] = {
        type: isNormalInteger(val) ? GraphQLInt : GraphQLString
      }
    })
    fieldsFromData[normalizedName] = {
      type: sheetSchemas[normalizedName],
      description: sheetName + ' sheet',
      args,
      resolve: (root, a) => {
        if (typeof(a.row) !== "undefined") {
          return obj[sheetName][a.row];
        }
        if (Object.keys(a||{}).length > 0) {
          var k = Object.keys(a)[0];
          return obj[sheetName].find(r => {
            return r[k] == a[k];
          })
        }
      },
    }
    fieldsFromData[normalizedName + 's'] = {
      type: new GraphQLList(sheetSchemas[normalizedName]),
      description: '',
      args: connectionArgs,
      resolve: (root, args) => obj[sheetName],
    }
  });
  let ot = new GraphQLObjectType({
    name: sanitize(name),
    description: 'File ' + name,
    fields: () => fieldsFromData,
  });
  if (returnTheTypeOnly) {
    return ot;
  }
  return new GraphQLSchema({
    query: ot
  });
}

function schemaFromSpreadSheetsObj(data) {
  typenames_count = {};
  var fieldsFromData = {};
  Object.keys(data).forEach(k => {
    fieldsFromData[k] = {
      name: k,
      type: schemaFromSpreadSheet(k, data[k], true),
      resolve: () => data[k],
    }
  })
  return new GraphQLSchema({
    query: new GraphQLObjectType({
      name: 'root',
      fields: () => fieldsFromData,
    }),
  });
}

module.exports.schemaFromSpreadSheet = schemaFromSpreadSheet;
module.exports.schemaFromSpreadSheetsObj = schemaFromSpreadSheetsObj;
<commit_msg>ID type for id field<commit_after>import {
  GraphQLID,
  GraphQLSchema,
  GraphQLObjectType,
  GraphQLString,
  GraphQLInt,
  GraphQLList
} from 'graphql';

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions,
} from 'graphql-relay';

let count = 0;

// http://stackoverflow.com/questions/10834796/validate-that-a-string-is-a-positive-integer
function isNormalInteger(str) {
    var n = ~~Number(str);
    return String(n) === str && n >= 0;
}

var typenames_count = {};

function sanitize(name) {
  let clean = name.replace(/\./g, '_').replace(/\//g, '_');
  if (typenames_count[clean]) {
    typenames_count[clean] = typenames_count[clean] + 1;
    clean = clean + '_' + (typenames_count[clean] - 1);
  } else {
    typenames_count[clean] = 1;
  }
  return clean;
}

function schemaFromArrayOfObjects(name, data, sheetSchemas, getRowFromSheetById) {
  return new GraphQLObjectType({
    name: sanitize(name),
    fields: () => {
      var firstRow = data[0];
      var fieldsFromData = {};
      // inferring types (Int or String) from first row
      Object.keys(firstRow).forEach(fieldName => {
        var val = firstRow[fieldName];
        var type;
        var relation = false;
        var normalizedName = fieldName;
        var sheetName = fieldName.slice(0, -2);
        if (fieldName.slice(fieldName.length - 2, fieldName.length) === 'Id') {
          normalizedName = sheetName;
          type = sheetSchemas[sheetName];
          relation = true;
        } else if (fieldName === 'id'){
          type = GraphQLID;
        } else {
          type = isNormalInteger(val) ? GraphQLInt : GraphQLString;
        }
        fieldsFromData[normalizedName] = {
          type,
          description: 'Example value: ' + val,
          resolve: (row) => {
            if (relation) {
              return getRowFromSheetById(sheetName, row[fieldName]);
            }
            return row[fieldName];
          }
        }
      });
      return fieldsFromData;
    },
  });
}

function schemaFromSpreadSheet(name, obj, returnTheTypeOnly) {
  var sheetSchemas = {};
  var fieldsFromData = {};
  Object.keys(obj).reverse().forEach(sheetName => {
    var normalizedName = sheetName.replace(/s$/,'');
    sheetSchemas[normalizedName] = schemaFromArrayOfObjects(normalizedName, obj[sheetName], sheetSchemas,
      (sheet, id) => obj[(sheet + 's').replace(/ss$/,'s')].find(r => r.id === id));
    var args = {
      row: {
        type: GraphQLInt,
      },
    };
    var firstRow = obj[sheetName][0];
    var keys = Object.keys(firstRow);
    keys.forEach(key => {
      var val = firstRow[key];
      args[key] = {
        type: isNormalInteger(val) ? GraphQLInt : GraphQLString
      }
    })
    fieldsFromData[normalizedName] = {
      type: sheetSchemas[normalizedName],
      description: sheetName + ' sheet',
      args,
      resolve: (root, a) => {
        if (typeof(a.row) !== "undefined") {
          return obj[sheetName][a.row];
        }
        if (Object.keys(a||{}).length > 0) {
          var k = Object.keys(a)[0];
          return obj[sheetName].find(r => {
            return r[k] == a[k];
          })
        }
      },
    }
    fieldsFromData[normalizedName + 's'] = {
      type: new GraphQLList(sheetSchemas[normalizedName]),
      description: '',
      args: connectionArgs,
      resolve: (root, args) => obj[sheetName],
    }
  });
  let ot = new GraphQLObjectType({
    name: sanitize(name),
    description: 'File ' + name,
    fields: () => fieldsFromData,
  });
  if (returnTheTypeOnly) {
    return ot;
  }
  return new GraphQLSchema({
    query: ot
  });
}

function schemaFromSpreadSheetsObj(data) {
  typenames_count = {};
  var fieldsFromData = {};
  Object.keys(data).forEach(k => {
    fieldsFromData[k] = {
      name: k,
      type: schemaFromSpreadSheet(k, data[k], true),
      resolve: () => data[k],
    }
  })
  return new GraphQLSchema({
    query: new GraphQLObjectType({
      name: 'root',
      fields: () => fieldsFromData,
    }),
  });
}

module.exports.schemaFromSpreadSheet = schemaFromSpreadSheet;
module.exports.schemaFromSpreadSheetsObj = schemaFromSpreadSheetsObj;
<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events').EventEmitter;
const Pool = require('./pool.js');
const Message = require('./message.js');
const Logger = require('./log.js');

const DEFAULT_OPTIONS = {
  host: 'localhost',
  port: 11211,
  autoreconnect: false,
  commandTimeout: 2000,
  reconnectDuration: 2000,
  maxRetryConnectCount: 10
};

/**
 * Memcached client
 *
 * Specs:
 *   - Manage connection pools
 *   - Support automatic reconnection
 *   - Command queueing, and run when reconnected
 *   - Non-exiting when connection closed unexpectedly
 *
 * Protocol specification
 * @see https://github.com/memcached/memcached/blob/master/doc/protocol.txt
 */
class Memcached extends EventEmitter {

  /**
   v Constructor
   * @param {Object} options - Connect options
   */
  constructor(options) {
    super();

    this.queue = [];
    this.conn = null;
    this.running = false;
    this.clientClosed = false;

    this.options = Object.assign(DEFAULT_OPTIONS, options || {});
  }

  /**
   * Validate key signature
   *
   * @param {String} key key name
   * @return {Void} -
   * @throws Error
   */
  validateKey(key) {
    if (key.length > 250) {
      throw new Error('Key size limit exceeded. Key size must be under the 250 bytes');
    }
    // Key string must not contain control characters and whitespece
    if (/[\u0000-\u001F|\u007f|\u0080-\u009f|\s]/.test(key)) {
      throw new Error('Invalid key. Key must not contain control characters and whitespace');
    }
  }

  /**
   * Connect to memcached server
   *
   * @return {Void} -
   */
  connect() {
    return new Promise(resolve => {
      const c = Pool.pull(this.options.host, this.options.port, this.options);
      this.conn = c.connection;

      if (c.created) {
        this.conn.on('mc.error', () => this.emit('mc.error'));
        this.conn.on('timeout', () => this.emit('timeout'));
        this.conn.on('connect', () => {
          this.emit('connect');
          resolve(this);
        });
        this.conn.on('close', () => this.emit('close'));
      } else {
        // We need to a bit delay to emit connect event if connection returns by pool
        setTimeout(() => {
          this.emit('connect');
          resolve(this);
        }, 10);
      }
    });
  }

  /**
   * Close connection from client
   *
   * @return {Void} -
   */
  close() {
    try {
      // Not that this closing connect is expected by user.
      // So we do not try to reconnect
      this.conn.close();
    } catch (e) {
      Logger.error(e);
    }
  }

  /**
   * Send "add" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  add(key, value, isCompress = 0, expires = 0) {
    return this.store('add', key, value, isCompress, expires);
  }

  /**
   * Send "replace" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  replace(key, value, isCompress = 0, expires = 0) {
    return this.store('replace', key, value, isCompress, expires);
  }

  /**
   * Send "append" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  append(key, value, isCompress = 0, expires = 0) {
    return this.store('append', key, value, isCompress, expires);
  }

  /**
   * Send "prepend" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  prepend(key, value, isCompress = 0, expires = 0) {
    return this.store('prepend', key, value, isCompress, expires);
  }

  /**
   * Send "set" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  set(key, value, isCompress = 0, expires = 0) {
    return this.store('set', key, value, isCompress, expires);
  }

  /**
   * Create stored command and send, and handle reply
   *
   * @param {String} commandName command name
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   * @resolve {Void}
   * @reject {Void}
   */
  store(commandName, key, value, isCompress, expires) {
    this.validateKey(key);
    const stringValue = value.toString();
    const byteSize = (value instanceof Buffer) ? value.byteLength : Buffer.byteLength(value, 'utf8');
    const command = [
      `${commandName} ${key} ${isCompress ? 1 : 0} ${expires} ${byteSize}`,
      (value instanceof Buffer) ? value.toString('utf8') : stringValue
    ];
    return this.conn.command(command)
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.EXISTS:
          case Message.STORED:
          case Message.NOT_STORED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }

  /**
   * Send "cas" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @param {String} unique cas unique
   * @return {Promise} -
   * @resolve {String} reply code
   * @reject {String} reply code
   */
  cas(key, value, isCompress = 0, expires = 0, unique = '') {
    this.validateKey(key);
    const byteSize = (value instanceof Buffer) ? Buffer.length : Buffer.byteLength(value, 'utf8');
    const command = [
      `cas ${key} ${isCompress ? 1 : 0} ${expires} ${byteSize} ${unique}`,
      (value instanceof Buffer) ? value.toString('utf8') : value
    ];
    return this.conn.command(command)
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.STORED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }

  /**
   * Get cache data from supplied key
   *
   * @param {Array} keys cache key
   * @return {Promise} -
   * @resolve {String|Object|null} cache data
   *   If single key was supplied, return string. Otherwise return key mapped Object
   * @reject {Void}
   */
  get(...keys) {
    keys.forEach(k => this.validateKey(k));
    return this.conn.command([`get ${keys.join(' ')}`])
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.END:
            return Promise.resolve(null);
          case Message.ERROR:
          case Message.SERVER_ERROR:
          case Message.CLIENT_ERROR:
            return Promise.reject(code);
          default:
            if (keys.length === 1) {
              return Promise.resolve(message.getValue());
            }
            const values = message.getBulkValues();
            keys.forEach(k => {
              if (!values.hasOwnProperty(k)) {
                values[k] = null;
              }
            });
            return Promise.resolve(values);
        }
      })
    ;
  }

  /**
   * Get cache data from supplied key with cas unique
   *
   * @param {...String} key cache key list
   * @return {Promise} -
   * @resolve {Object|null} cache data map by key
   * @reject {Void}
   */
  gets(...keys) {
    keys.forEach(k => this.validateKey(k));
    return this.conn.command([`gets ${keys.join(' ')}`])
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.END:
            return Promise.resolve(null);
          case Message.ERROR:
          case Message.SERVER_ERROR:
          case Message.CLIENT_ERROR:
            return Promise.reject(code);
          default:
            if (keys.length === 1) {
              return Promise.resolve(message.getObjectValue());
            }
            const values = message.getBulkObjectValues();
            keys.forEach(k => {
              if (!values.hasOwnProperty(k)) {
                values[k] = null;
              }
            });
            return Promise.resolve(values);
        }
      })
    ;
  }

  /**
   * Delete cache data from supplied key
   *
   * @param {String} key cache key
   * @return {Promise} -
   * @resolve {Void}
   * @reject {Void}
   */
  delete(key) {
    this.validateKey(key);
    return this.conn.command([`delete ${key}`])
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.DELETED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }

  /**
   * Increment data from supplied key
   *
   * @param {String} key cache key
   * @param {Number} value increment value
   * @return {Promise} -
   * @resolve {Number} Incremented value
   * @reject {Void}
   */
  incr(key, value = 1) {
    return this.incrOrDecr('incr', key, value);
  }

  /**
   * Decrement data from supplied key
   *
   * @param {String} key cache key
   * @param {Number} value decrement value
   * @return {Promise} -
   * @resolve {Number} Decremented value
   * @reject {Void}
   */
  decr(key, value = 1) {
    return this.incrOrDecr('decr', key, value);
  }

  /**
   * Send "incr" or "decr" command
   *
   * @param {String} commandName command name
   * @param {String} key cache key
   * @param {Number} value increment or decrement value
   * @return {Promise} -
   * @resolve {Number}
   * @reject {Void}
   */
  incrOrDecr(commandName, key, value) {
    this.validateKey(key);
    const command = [`${commandName} ${key} ${value}`];
    return this.conn.command(command)
      .then(message => {
        const result = parseInt(message.rawData, 10);
        if (!isNaN(result)) {
          return Promise.resolve(result);
        }
        return Promise.reject(message.code);
      })
    ;
  }

  /**
   * Update expired time for key
   *
   * @param {String} key cache key
   * @param {Number} expires update expired time
   * @return {Promise} -
   * @resolve {Void}
   * @reject {Void}
   */
  touch(key, expires) {
    this.validateKey(key);
    const command = [`touch ${key} ${expires}`];
    return this.conn.command(command)
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.TOUCHED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }
}

module.exports = Memcached;

<commit_msg>Update memcached.js<commit_after>'use strict';

const EventEmitter = require('events').EventEmitter;
const Pool = require('./pool.js');
const Message = require('./message.js');
const Logger = require('./log.js');

const DEFAULT_OPTIONS = {
  host: 'localhost',
  port: 11211,
  autoreconnect: false,
  commandTimeout: 2000,
  reconnectDuration: 2000,
  maxRetryConnectCount: 10
};

/**
 * Memcached client
 *
 * Specs:
 *   - Manage connection pools
 *   - Support automatic reconnection
 *   - Command queueing, and run when reconnected
 *   - Non-exiting when connection closed unexpectedly
 *
 * Protocol specification
 * @see https://github.com/memcached/memcached/blob/master/doc/protocol.txt
 */
class Memcached extends EventEmitter {

  /**
   v Constructor
   * @param {Object} options - Connect options
   */
  constructor(options) {
    super();

    this.queue = [];
    this.conn = null;
    this.running = false;
    this.clientClosed = false;

    this.options = Object.assign(DEFAULT_OPTIONS, options || {});
  }

  /**
   * Validate key signature
   *
   * @param {String} key key name
   * @return {Void} -
   * @throws Error
   */
  validateKey(key) {
    if (key.length > 250) {
      throw new Error('Key size limit exceeded. Key size must be under the 250 bytes');
    }
    // Key string must not contain control characters and whitespece
    if (/[\u0000-\u001F|\u007f|\u0080-\u009f|\s]/.test(key)) {
      throw new Error('Invalid key. Key must not contain control characters and whitespace');
    }
  }

  /**
   * Connect to memcached server
   *
   * @return {Void} -
   */
  connect() {
    return new Promise(resolve => {
      const c = Pool.pull(this.options.host, this.options.port, this.options);
      this.conn = c.connection;

      if (c.created) {
        this.conn.on('mc.error', () => this.emit('mc.error'));
        this.conn.on('timeout', () => this.emit('timeout'));
        this.conn.on('connect', () => {
          this.emit('connect');
          resolve(this);
        });
        this.conn.on('close', () => this.emit('close'));
      } else {
        // We need to a bit delay to emit connect event if connection returns by pool
        setTimeout(() => {
          this.emit('connect');
          resolve(this);
        }, 10);
      }
    });
  }

  /**
   * Close connection from client
   *
   * @return {Void} -
   */
  close() {
    try {
      // Not that this closing connect is expected by user.
      // So we do not try to reconnect
      this.conn.close();
    } catch (e) {
      Logger.error(e);
    }
  }

  /**
   * Send "add" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  add(key, value, isCompress = 0, expires = 0) {
    return this.store('add', key, value, isCompress, expires);
  }

  /**
   * Send "replace" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  replace(key, value, isCompress = 0, expires = 0) {
    return this.store('replace', key, value, isCompress, expires);
  }

  /**
   * Send "append" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  append(key, value, isCompress = 0, expires = 0) {
    return this.store('append', key, value, isCompress, expires);
  }

  /**
   * Send "prepend" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  prepend(key, value, isCompress = 0, expires = 0) {
    return this.store('prepend', key, value, isCompress, expires);
  }

  /**
   * Send "set" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   */
  set(key, value, isCompress = 0, expires = 0) {
    return this.store('set', key, value, isCompress, expires);
  }

  /**
   * Create stored command and send, and handle reply
   *
   * @param {String} commandName command name
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @return {Promise} -
   * @resolve {Void}
   * @reject {Void}
   */
  store(commandName, key, value, isCompress, expires) {
    this.validateKey(key);
    const stringValue = value.toString();
    const byteSize = (value instanceof Buffer) ? value.byteLength : Buffer.byteLength(stringValue, 'utf8');
    const command = [
      `${commandName} ${key} ${isCompress ? 1 : 0} ${expires} ${byteSize}`,
      (value instanceof Buffer) ? value.toString('utf8') : stringValue
    ];
    return this.conn.command(command)
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.EXISTS:
          case Message.STORED:
          case Message.NOT_STORED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }

  /**
   * Send "cas" command
   *
   * @param {String} key cache key
   * @param {String|Buffer} value store value
   * @param {Booelan} isCompress flag of data should be compressed
   * @param {Number} expires time to cache has expired (if supplied zero, the value is persitent)
   * @param {String} unique cas unique
   * @return {Promise} -
   * @resolve {String} reply code
   * @reject {String} reply code
   */
  cas(key, value, isCompress = 0, expires = 0, unique = '') {
    this.validateKey(key);
    const byteSize = (value instanceof Buffer) ? Buffer.length : Buffer.byteLength(value, 'utf8');
    const command = [
      `cas ${key} ${isCompress ? 1 : 0} ${expires} ${byteSize} ${unique}`,
      (value instanceof Buffer) ? value.toString('utf8') : value
    ];
    return this.conn.command(command)
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.STORED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }

  /**
   * Get cache data from supplied key
   *
   * @param {Array} keys cache key
   * @return {Promise} -
   * @resolve {String|Object|null} cache data
   *   If single key was supplied, return string. Otherwise return key mapped Object
   * @reject {Void}
   */
  get(...keys) {
    keys.forEach(k => this.validateKey(k));
    return this.conn.command([`get ${keys.join(' ')}`])
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.END:
            return Promise.resolve(null);
          case Message.ERROR:
          case Message.SERVER_ERROR:
          case Message.CLIENT_ERROR:
            return Promise.reject(code);
          default:
            if (keys.length === 1) {
              return Promise.resolve(message.getValue());
            }
            const values = message.getBulkValues();
            keys.forEach(k => {
              if (!values.hasOwnProperty(k)) {
                values[k] = null;
              }
            });
            return Promise.resolve(values);
        }
      })
    ;
  }

  /**
   * Get cache data from supplied key with cas unique
   *
   * @param {...String} key cache key list
   * @return {Promise} -
   * @resolve {Object|null} cache data map by key
   * @reject {Void}
   */
  gets(...keys) {
    keys.forEach(k => this.validateKey(k));
    return this.conn.command([`gets ${keys.join(' ')}`])
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.END:
            return Promise.resolve(null);
          case Message.ERROR:
          case Message.SERVER_ERROR:
          case Message.CLIENT_ERROR:
            return Promise.reject(code);
          default:
            if (keys.length === 1) {
              return Promise.resolve(message.getObjectValue());
            }
            const values = message.getBulkObjectValues();
            keys.forEach(k => {
              if (!values.hasOwnProperty(k)) {
                values[k] = null;
              }
            });
            return Promise.resolve(values);
        }
      })
    ;
  }

  /**
   * Delete cache data from supplied key
   *
   * @param {String} key cache key
   * @return {Promise} -
   * @resolve {Void}
   * @reject {Void}
   */
  delete(key) {
    this.validateKey(key);
    return this.conn.command([`delete ${key}`])
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.DELETED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }

  /**
   * Increment data from supplied key
   *
   * @param {String} key cache key
   * @param {Number} value increment value
   * @return {Promise} -
   * @resolve {Number} Incremented value
   * @reject {Void}
   */
  incr(key, value = 1) {
    return this.incrOrDecr('incr', key, value);
  }

  /**
   * Decrement data from supplied key
   *
   * @param {String} key cache key
   * @param {Number} value decrement value
   * @return {Promise} -
   * @resolve {Number} Decremented value
   * @reject {Void}
   */
  decr(key, value = 1) {
    return this.incrOrDecr('decr', key, value);
  }

  /**
   * Send "incr" or "decr" command
   *
   * @param {String} commandName command name
   * @param {String} key cache key
   * @param {Number} value increment or decrement value
   * @return {Promise} -
   * @resolve {Number}
   * @reject {Void}
   */
  incrOrDecr(commandName, key, value) {
    this.validateKey(key);
    const command = [`${commandName} ${key} ${value}`];
    return this.conn.command(command)
      .then(message => {
        const result = parseInt(message.rawData, 10);
        if (!isNaN(result)) {
          return Promise.resolve(result);
        }
        return Promise.reject(message.code);
      })
    ;
  }

  /**
   * Update expired time for key
   *
   * @param {String} key cache key
   * @param {Number} expires update expired time
   * @return {Promise} -
   * @resolve {Void}
   * @reject {Void}
   */
  touch(key, expires) {
    this.validateKey(key);
    const command = [`touch ${key} ${expires}`];
    return this.conn.command(command)
      .then(message => {
        const code = message.code;
        switch (code) {
          case Message.TOUCHED:
            return Promise.resolve(code);
          default:
            return Promise.reject(code);
        }
      })
    ;
  }
}

module.exports = Memcached;

<|endoftext|>