<commit_before>define([
	"dojo/_base/declare", "dojo/_base/lang",
	"dojo/on", "dojo/topic", "dojo/when", "dojo/request", "dojo/dom-construct",
	"dijit/popup", "dijit/TooltipDialog", "dijit/Dialog",
	"./ContainerActionBar", "FileSaver",
	"./ProteinFamiliesGrid", "./GridContainer", "./DownloadTooltipDialog", "../util/PathJoin", "./SelectionToGroup"
], function(declare, lang,
			on, Topic, when, request, domConstruct,
			popup, TooltipDialog, Dialog,
			ContainerActionBar, saveAs,
			ProteinFamiliesGrid, GridContainer, DownloadTooltipDialog, PathJoin, SelectionToGroup){

	var vfc = ['
View FASTA DNA
',
		'
View FASTA Proteins
'
	].join("\n");

	var viewFASTATT = new TooltipDialog({
		content: vfc, onMouseLeave: function(){
			popup.close(viewFASTATT);
		}
	});

	on(viewFASTATT.domNode, "click", function(evt){
		var rel = evt.target.attributes.rel.value;
		var sel = viewFASTATT.selection;
		delete viewFASTATT.selection;

		Topic.publish("/navigate", {href: "/view/FASTA/" + rel + "/" + sel, target: "blank"});
	});

	var dfc = '
Download Table As...

Text

CSV
';

	var downloadTT = new TooltipDialog({
		content: dfc, onMouseLeave: function(){
			popup.close(downloadTT);
		}
	});

	var downloadSelectionTT = new DownloadTooltipDialog({});
	downloadSelectionTT.startup();

	return declare([GridContainer], {
		gridCtor: ProteinFamiliesGrid,
		containerType: "proteinfamily_data",
		facetFields: [],
		maxGenomeCount: 500,
		showAutoFilterMessage: false,
		constructor: function(options){

			this.topicId = options.topicId;

			Topic.subscribe(this.topicId , lang.hitch(this, function(){
				var key = arguments[0], value = arguments[1];

				switch(key){
					case "updatePfState":
						this.pfState = value;
						break;
					default:
						break;
				}
			}));
		},
		buildQuery: function(){
			return "";
		},
		_setQueryAttr: function(query){
			//block default query handler for now.
		},
		_setStateAttr: function(state){
			this.inherited(arguments);
			if(!state){
				return;
			}
			// console.log("ProteinFamiliesGridContainer _setStateAttr: ", state);
			if(this.grid){
				// console.log("   call set state on this.grid: ", this.grid);
				Topic.publish(this.topicId, "showLoadingMask");
				this.grid.set('state', state);
			}else{
				// console.log("No Grid Yet (ProteinFamiliesGridContainer)");
			}

			this._set("state", state);
		},
		createFilterPanel: function(opts){
			this.containerActionBar = this.filterPanel = new ContainerActionBar({
				region: "top",
				layoutPriority: 7,
				splitter: true,
				"className": "BrowserHeader",
				dataModel: this.dataModel,
				facetFields: this.facetFields,
				state: lang.mixin({}, this.state),
				enableAnchorButton: false,
				currentContainerWidget: this
			});
		},
		containerActions: GridContainer.prototype.containerActions.concat([
			[
				"DownloadTable",
				"fa icon-download fa-2x",
				{
					label: "DOWNLOAD",
					multiple: false,
					validTypes: ["*"],
					tooltip: "Download Table",
					tooltipDialog: downloadTT
				},
				function(){

					downloadTT.set("content", dfc);

					on(downloadTT.domNode, "div:click", lang.hitch(this, function(evt){
						var rel = evt.target.attributes.rel.value;
						var DELIMITER, ext;
						if(rel === 'text/csv'){
							DELIMITER = ',';
							ext = 'csv';
						}else{
							DELIMITER = '\t';
							ext = 'txt';
						}

						var data  = this.grid.store.query("", {sort: this.grid.store.sort});

						var headers = ["Family ID", "Proteins", "Genomes", "Description", "Min AA Length", "Max AA Length", "Mean", "Std Dev"];
						var content = [];
						data.forEach(function(row){
							content.push([row.family_id, row.feature_count, row.genome_count, '"' + row.description + '"', row.aa_length_min, row.aa_length_max, row.aa_length_mean, row.aa_length_std].join(DELIMITER));
						})

						saveAs(new Blob([headers.join(DELIMITER) + '\n' + content.join('\n')], {type: rel}), 'PATRIC_protein_families.' + ext);

						popup.close(downloadTT);
					}));

					popup.open({
						popup: this.containerActionBar._actions.DownloadTable.options.tooltipDialog,
						around: this.containerActionBar._actions.DownloadTable.button,
						orient: ["below"]
					});
				},
				true
			]
		]),
		selectionActions: GridContainer.prototype.selectionActions.concat([
			[
				"DownloadSelection",
				"fa icon-download fa-2x",
				{
					label: "DWNLD",
					multiple: true,
					validTypes: ["*"],
					ignoreDataType: true,
					tooltip: "Download Selection",
					max: 5000,
					tooltipDialog: downloadSelectionTT,
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					var query = "and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))&select(feature_id)&limit(25000)";

					var self = this;

					when(request.post(PathJoin(window.App.dataAPI, '/genome_feature/'), {
						handleAs: 'json',
						headers: {
							'Accept': "application/json",
							'Content-Type': "application/rqlquery+x-www-form-urlencoded",
							'X-Requested-With': null,
							'Authorization': (window.App.authorizationToken || "")
						},
						data: query
					}), function(response){

						self.selectionActionBar._actions.DownloadSelection.options.tooltipDialog.set("selection", response);
						self.selectionActionBar._actions.DownloadSelection.options.tooltipDialog.set("containerType", "feature_data");

						setTimeout(lang.hitch(self, function(){
							popup.open({
								popup: this.selectionActionBar._actions.DownloadSelection.options.tooltipDialog,
								around: this.selectionActionBar._actions.DownloadSelection.button,
								orient: ["below"]
							});
						}), 10);
					});
				},
				false
			],
			[
				"ViewFASTA",
				"fa icon-fasta fa-2x",
				{
					label: "FASTA",
					ignoreDataType: true,
					multiple: true,
					validTypes: ["*"],
					tooltip: "View FASTA Data",
					tooltipDialog: viewFASTATT
				},
				function(selection){

					viewFASTATT.selection = "?and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))";

					popup.open({
						popup: this.selectionActionBar._actions.ViewFASTA.options.tooltipDialog,
						around: this.selectionActionBar._actions.ViewFASTA.button,
						orient: ["below"]
					});
				},
				false
			], [
				"MultipleSeqAlignmentFeatures",
				"fa icon-alignment fa-2x",
				{
					label: "MSA",
					ignoreDataType: true,
					multiple: false,
					validTypes: ["*"],
					tooltip: "Multiple Sequence Alignment",
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					query = "and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))";

					Topic.publish("/navigate", {href: "/view/MSA/?" + query, target: "blank"});
				},
				false
			], [
				"ViewProteinFamiliesMembers",
				"fa icon-group fa-2x",
				{
					label: "Members",
					multiple: true,
					validTypes: ["*"],
					tooltip: "View Family Members",
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					var query = "?and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(sel){
							return sel.family_id;
						}).join(',') + ")))";

					Topic.publish("/navigate", {href: "/view/FeatureList/" + query + "#view_tab=features", target: "blank"});
				},
				false
			], [
				"AddGroup",
				"fa icon-object-group fa-2x",
				{
					label: "GROUP",
					ignoreDataType: true,
					multiple: true,
					validTypes: ["*"],
					requireAuth: true,
					max: 100,
					tooltip: "Add selection to a new or existing group",
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					var query = "and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))&select(feature_id)&limit(25000)";

					when(request.post(PathJoin(window.App.dataAPI, '/genome_feature/'), {
						handleAs: 'json',
						headers: {
							'Accept': "application/json",
							'Content-Type': "application/rqlquery+x-www-form-urlencoded",
							'X-Requested-With': null,
							'Authorization': (window.App.authorizationToken || "")
						},
						data: query
					}), function(featureIds){

						var dlg = new Dialog({title: "Add selected items to group"});
						var stg = new SelectionToGroup({
							selection: featureIds,
							type: "feature_group",
							path: ""
						});
						on(dlg.domNode, "dialogAction", function(){
							dlg.hide();
							setTimeout(function(){
								dlg.destroy();
							}, 2000);
						});
						domConstruct.place(stg.domNode, dlg.containerNode, "first");
						stg.startup();
						dlg.startup();
						dlg.show();
					});
				},
				false
			]

		])
	});
});
<commit_msg>enable genome group creation on Protein Families tab.<commit_after>define([
	"dojo/_base/declare", "dojo/_base/lang",
	"dojo/on", "dojo/topic", "dojo/when", "dojo/request", "dojo/dom-construct",
	"dijit/popup", "dijit/TooltipDialog", "dijit/Dialog",
	"./ContainerActionBar", "FileSaver",
	"./ProteinFamiliesGrid", "./GridContainer", "./DownloadTooltipDialog", "../util/PathJoin", "./SelectionToGroup"
], function(declare, lang,
			on, Topic, when, request, domConstruct,
			popup, TooltipDialog, Dialog,
			ContainerActionBar, saveAs,
			ProteinFamiliesGrid, GridContainer, DownloadTooltipDialog, PathJoin, SelectionToGroup){

	var vfc = ['
View FASTA DNA
',
		'
View FASTA Proteins
'
	].join("\n");

	var viewFASTATT = new TooltipDialog({
		content: vfc, onMouseLeave: function(){
			popup.close(viewFASTATT);
		}
	});

	on(viewFASTATT.domNode, "click", function(evt){
		var rel = evt.target.attributes.rel.value;
		var sel = viewFASTATT.selection;
		delete viewFASTATT.selection;

		Topic.publish("/navigate", {href: "/view/FASTA/" + rel + "/" + sel, target: "blank"});
	});

	var dfc = '
Download Table As...

Text

CSV
';

	var downloadTT = new TooltipDialog({
		content: dfc, onMouseLeave: function(){
			popup.close(downloadTT);
		}
	});

	var downloadSelectionTT = new DownloadTooltipDialog({});
	downloadSelectionTT.startup();

	return declare([GridContainer], {
		gridCtor: ProteinFamiliesGrid,
		containerType: "proteinfamily_data",
		facetFields: [],
		maxGenomeCount: 500,
		showAutoFilterMessage: false,
		constructor: function(options){

			this.topicId = options.topicId;

			Topic.subscribe(this.topicId , lang.hitch(this, function(){
				var key = arguments[0], value = arguments[1];

				switch(key){
					case "updatePfState":
						this.pfState = value;
						break;
					default:
						break;
				}
			}));
		},
		buildQuery: function(){
			return "";
		},
		_setQueryAttr: function(query){
			//block default query handler for now.
		},
		_setStateAttr: function(state){
			this.inherited(arguments);
			if(!state){
				return;
			}
			// console.log("ProteinFamiliesGridContainer _setStateAttr: ", state);
			if(this.grid){
				// console.log("   call set state on this.grid: ", this.grid);
				Topic.publish(this.topicId, "showLoadingMask");
				this.grid.set('state', state);
			}else{
				// console.log("No Grid Yet (ProteinFamiliesGridContainer)");
			}

			this._set("state", state);
		},
		createFilterPanel: function(opts){
			this.containerActionBar = this.filterPanel = new ContainerActionBar({
				region: "top",
				layoutPriority: 7,
				splitter: true,
				"className": "BrowserHeader",
				dataModel: this.dataModel,
				facetFields: this.facetFields,
				state: lang.mixin({}, this.state),
				enableAnchorButton: false,
				currentContainerWidget: this
			});
		},
		containerActions: GridContainer.prototype.containerActions.concat([
			[
				"DownloadTable",
				"fa icon-download fa-2x",
				{
					label: "DOWNLOAD",
					multiple: false,
					validTypes: ["*"],
					tooltip: "Download Table",
					tooltipDialog: downloadTT
				},
				function(){

					downloadTT.set("content", dfc);

					on(downloadTT.domNode, "div:click", lang.hitch(this, function(evt){
						var rel = evt.target.attributes.rel.value;
						var DELIMITER, ext;
						if(rel === 'text/csv'){
							DELIMITER = ',';
							ext = 'csv';
						}else{
							DELIMITER = '\t';
							ext = 'txt';
						}

						var data  = this.grid.store.query("", {sort: this.grid.store.sort});

						var headers = ["Family ID", "Proteins", "Genomes", "Description", "Min AA Length", "Max AA Length", "Mean", "Std Dev"];
						var content = [];
						data.forEach(function(row){
							content.push([row.family_id, row.feature_count, row.genome_count, '"' + row.description + '"', row.aa_length_min, row.aa_length_max, row.aa_length_mean, row.aa_length_std].join(DELIMITER));
						})

						saveAs(new Blob([headers.join(DELIMITER) + '\n' + content.join('\n')], {type: rel}), 'PATRIC_protein_families.' + ext);

						popup.close(downloadTT);
					}));

					popup.open({
						popup: this.containerActionBar._actions.DownloadTable.options.tooltipDialog,
						around: this.containerActionBar._actions.DownloadTable.button,
						orient: ["below"]
					});
				},
				true
			]
		]),
		selectionActions: GridContainer.prototype.selectionActions.concat([
			[
				"DownloadSelection",
				"fa icon-download fa-2x",
				{
					label: "DWNLD",
					multiple: true,
					validTypes: ["*"],
					ignoreDataType: true,
					tooltip: "Download Selection",
					max: 5000,
					tooltipDialog: downloadSelectionTT,
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					var query = "and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))&select(feature_id)&limit(25000)";

					var self = this;

					when(request.post(PathJoin(window.App.dataAPI, '/genome_feature/'), {
						handleAs: 'json',
						headers: {
							'Accept': "application/json",
							'Content-Type': "application/rqlquery+x-www-form-urlencoded",
							'X-Requested-With': null,
							'Authorization': (window.App.authorizationToken || "")
						},
						data: query
					}), function(response){

						self.selectionActionBar._actions.DownloadSelection.options.tooltipDialog.set("selection", response);
						self.selectionActionBar._actions.DownloadSelection.options.tooltipDialog.set("containerType", "feature_data");

						setTimeout(lang.hitch(self, function(){
							popup.open({
								popup: this.selectionActionBar._actions.DownloadSelection.options.tooltipDialog,
								around: this.selectionActionBar._actions.DownloadSelection.button,
								orient: ["below"]
							});
						}), 10);
					});
				},
				false
			],
			[
				"ViewFASTA",
				"fa icon-fasta fa-2x",
				{
					label: "FASTA",
					ignoreDataType: true,
					multiple: true,
					validTypes: ["*"],
					tooltip: "View FASTA Data",
					tooltipDialog: viewFASTATT
				},
				function(selection){

					viewFASTATT.selection = "?and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))";

					popup.open({
						popup: this.selectionActionBar._actions.ViewFASTA.options.tooltipDialog,
						around: this.selectionActionBar._actions.ViewFASTA.button,
						orient: ["below"]
					});
				},
				false
			], [
				"MultipleSeqAlignmentFeatures",
				"fa icon-alignment fa-2x",
				{
					label: "MSA",
					ignoreDataType: true,
					multiple: false,
					validTypes: ["*"],
					tooltip: "Multiple Sequence Alignment",
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					query = "and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))";

					Topic.publish("/navigate", {href: "/view/MSA/?" + query, target: "blank"});
				},
				false
			], [
				"ViewProteinFamiliesMembers",
				"fa icon-group fa-2x",
				{
					label: "Members",
					multiple: true,
					validTypes: ["*"],
					tooltip: "View Family Members",
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					var query = "?and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(sel){
							return sel.family_id;
						}).join(',') + ")))";

					Topic.publish("/navigate", {href: "/view/FeatureList/" + query + "#view_tab=features", target: "blank"});
				},
				false
			], [
				"AddGroup",
				"fa icon-object-group fa-2x",
				{
					label: "GROUP",
					ignoreDataType: true,
					multiple: true,
					validTypes: ["*"],
					requireAuth: true,
					max: 100,
					tooltip: "Add selection to a new or existing group",
					validContainerTypes: ["proteinfamily_data"]
				},
				function(selection){

					var query = "and(in(genome_id,(" + this.pfState.genomeIds.join(',') + ")),in(" + this.pfState.familyType + "_id,(" + selection.map(function(s){
							return s.family_id;
						}).join(',') + ")))&select(feature_id,genome_id)&limit(25000)";

					when(request.post(PathJoin(window.App.dataAPI, '/genome_feature/'), {
						handleAs: 'json',
						headers: {
							'Accept': "application/json",
							'Content-Type': "application/rqlquery+x-www-form-urlencoded",
							'X-Requested-With': null,
							'Authorization': (window.App.authorizationToken || "")
						},
						data: query
					}), function(ids){

						var dlg = new Dialog({title: "Add selected items to group"});
						var stg = new SelectionToGroup({
							selection: ids,
							type: "feature_group",
							inputType: "feature_data",
							path: ""
						});
						on(dlg.domNode, "dialogAction", function(){
							dlg.hide();
							setTimeout(function(){
								dlg.destroy();
							}, 2000);
						});
						domConstruct.place(stg.domNode, dlg.containerNode, "first");
						stg.startup();
						dlg.startup();
						dlg.show();
					});
				},
				false
			]

		])
	});
});
<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'
import Collection from './index.js'
import InfiniteContainer from '../containers/infinite'
import { uid } from '../utils/random'
import FilterContext from '../utils/filter_context'
import FilterContextHelper from '../utils/filter_context_helper'
import ExportModal from './export-modal'
import Config from '../utils/config'
import _ from 'lodash'

export default class InfiniteCollection extends React.Component {
  static contextTypes = {
    store: React.PropTypes.object,
    history: React.PropTypes.object
  }

  static defaultProps = {
    client: null,
    collectionActions: [],
    autoActions: true
  }

  constructor(props) {
    super(props)
    this.state = {
      view: 'table',
      sort: props.sort || { key: 'id', order: 'asc' },
      filters: {},
      showFilters: false,
      showExporter: false
    }
    this.id = props.id || uid()
  }

  render() {
    const exportUrlPrefix = Config.get('collections.exporter.urlPrefix', '')
    const modalOptions = {
      onCancel: this.closeExporter.bind(this),
      fields: this.props.columns,
      exportUrl: this.props.exportUrl || `${exportUrlPrefix}/${this.props.endpoint}`.replace(/([^:])\/+/gi, '$1/')
    }
    return (

        <InfiniteContainer ref="container" {...this.getContainerOptions()}>
          <LoadingCollection {...this.getCollectionProps()} />
        </InfiniteContainer>
        { this.state.showExporter ? <ExportModal {...modalOptions} /> : null }

    )
  }

  getContainerOptions() {
    return {
      endpoint: this.props.endpoint,
      endpointOptions: this.getQuery(),
      client: this.props.client,
      injectAs: "records",
      autoSync: false
    }
  }

  getCollectionProps() {
    return {
      ...this.props,
      ...this.getCallbacks(),
      id: this.id,
      saveVisibility: !!this.props.id,  // Only save visibility when an ID is set manually
      collectionActions: [
        { key: 'refresh', icon: 'refresh', label: 'Refresh', handler: this.refresh.bind(this) },
        { key: 'export', icon: 'download', label: 'Export', handler: this.openExporter.bind(this) },
        ...this.props.collectionActions
      ],
      recordActions: this.getRecordActions(),
      sort: this.state.sort,
      filterValues: this.state.filters,
      showFilters: this.state.showFilters
    }
  }

  getCallbacks() {
    return {
      onClickColumnHeader: col => {
        if(col === this.state.sort.key) {
          const order = this.state.sort.order === 'asc' ? 'desc' : 'asc'
          const key = this.state.sort.key
          this.setState({sort: {key, order}})
        }
        else {
          const order = 'asc'
          const key = col
          this.setState({sort: {key, order}})
        }
        _.defer(()=>this.refs.container.reset())
      },
      onFilterChange: filters => {
        this.setState({filters})
        _.defer(()=>this.refs.container.reset())
      },
      onShowFilters: () => this.setState({showFilters: true}),
      onHideFilters: () => this.setState({showFilters: false})
    }
  }

  getRecordActions() {
    return _.map(this.props.recordActions, action => {
      if(action.redirect) {
        return {
          ...action,
          handler: (id, data) => this.context.history.push(_.template(action.redirect)(data))
        }
      }
      else {
        return action
      }
    })
  }

  getQuery() {
    const sort = {[this.state.sort.key]: this.state.sort.order}
    const query = this.state.filters
    const parameters = FilterContextHelper.toQueryParams(new FilterContext({sort, query}))
    return parameters
  }

  refresh() {
    _.defer(()=>this.refs.container.reset())
  }

  openExporter() {
    this.setState({showExporter: true})
  }

  closeExporter() {
    this.setState({showExporter: false})
  }
}

const LoadingCollection = props => {
  const statusMappings = {
    'awaiting': 'SYNCING'
  }
  const tableStatus = _.get(statusMappings, props.status, 'READY')
  return (

      <Collection {...props} recordCount={props.totalRecords || 0} status={tableStatus} />

        { (!props.isAtEnd && !_.isEmpty(props.records))  ?

 : null }

  )
}
<commit_msg>Make collections use the API pathPrefix setting for export URLs by default<commit_after>import React from 'react'
import ReactDOM from 'react-dom'
import Collection from './index.js'
import InfiniteContainer from '../containers/infinite'
import { uid } from '../utils/random'
import FilterContext from '../utils/filter_context'
import FilterContextHelper from '../utils/filter_context_helper'
import ExportModal from './export-modal'
import Config from '../utils/config'
import _ from 'lodash'

export default class InfiniteCollection extends React.Component {
  static contextTypes = {
    store: React.PropTypes.object,
    history: React.PropTypes.object
  }

  static defaultProps = {
    client: null,
    collectionActions: [],
    autoActions: true
  }

  constructor(props) {
    super(props)
    this.state = {
      view: 'table',
      sort: props.sort || { key: 'id', order: 'asc' },
      filters: {},
      showFilters: false,
      showExporter: false
    }
    this.id = props.id || uid()
  }

  render() {
    const exportUrlPrefix = Config.get('api.pathPrefix', '')
    const modalOptions = {
      onCancel: this.closeExporter.bind(this),
      fields: this.props.columns,
      exportUrl: this.props.exportUrl || `${exportUrlPrefix}/${this.props.endpoint}`.replace(/([^:])\/+/gi, '$1/')
    }
    return (

        <InfiniteContainer ref="container" {...this.getContainerOptions()}>
          <LoadingCollection {...this.getCollectionProps()} />
        </InfiniteContainer>
        { this.state.showExporter ? <ExportModal {...modalOptions} /> : null }

    )
  }

  getContainerOptions() {
    return {
      endpoint: this.props.endpoint,
      endpointOptions: this.getQuery(),
      client: this.props.client,
      injectAs: "records",
      autoSync: false
    }
  }

  getCollectionProps() {
    return {
      ...this.props,
      ...this.getCallbacks(),
      id: this.id,
      saveVisibility: !!this.props.id,  // Only save visibility when an ID is set manually
      collectionActions: [
        { key: 'refresh', icon: 'refresh', label: 'Refresh', handler: this.refresh.bind(this) },
        { key: 'export', icon: 'download', label: 'Export', handler: this.openExporter.bind(this) },
        ...this.props.collectionActions
      ],
      recordActions: this.getRecordActions(),
      sort: this.state.sort,
      filterValues: this.state.filters,
      showFilters: this.state.showFilters
    }
  }

  getCallbacks() {
    return {
      onClickColumnHeader: col => {
        if(col === this.state.sort.key) {
          const order = this.state.sort.order === 'asc' ? 'desc' : 'asc'
          const key = this.state.sort.key
          this.setState({sort: {key, order}})
        }
        else {
          const order = 'asc'
          const key = col
          this.setState({sort: {key, order}})
        }
        _.defer(()=>this.refs.container.reset())
      },
      onFilterChange: filters => {
        this.setState({filters})
        _.defer(()=>this.refs.container.reset())
      },
      onShowFilters: () => this.setState({showFilters: true}),
      onHideFilters: () => this.setState({showFilters: false})
    }
  }

  getRecordActions() {
    return _.map(this.props.recordActions, action => {
      if(action.redirect) {
        return {
          ...action,
          handler: (id, data) => this.context.history.push(_.template(action.redirect)(data))
        }
      }
      else {
        return action
      }
    })
  }

  getQuery() {
    const sort = {[this.state.sort.key]: this.state.sort.order}
    const query = this.state.filters
    const parameters = FilterContextHelper.toQueryParams(new FilterContext({sort, query}))
    return parameters
  }

  refresh() {
    _.defer(()=>this.refs.container.reset())
  }

  openExporter() {
    this.setState({showExporter: true})
  }

  closeExporter() {
    this.setState({showExporter: false})
  }
}

const LoadingCollection = props => {
  const statusMappings = {
    'awaiting': 'SYNCING'
  }
  const tableStatus = _.get(statusMappings, props.status, 'READY')
  return (

      <Collection {...props} recordCount={props.totalRecords || 0} status={tableStatus} />

        { (!props.isAtEnd && !_.isEmpty(props.records))  ?

 : null }

  )
}
<|endoftext|>


<commit_before>const configuration = require("../configuration");
const ContentRegExpHandler = require("../content-regexp-handler.js");

const LogToggleHandler = {
    LogToggleHandler() {
        this.secure = true;

        this.ContentRegExpHandler(/^\.logtoggle/);
    },
    handle(message, storage) {
        let logStatus = storage.getFromGuildLevel(message.guild, "log.status", true,
            configuration.getConfig("log.status", true));

        logStatus = !logStatus;

        storage.saveOnGuildLevel(message.guild, "log", {
            status: logStatus
        });

        let logListener = (oldMember, newMember) => {
            let logChannelName = storage.getFromGuildLevel(message.guild, "log.channelName", true,
                configuration.getConfig("log.channelName", "log"));

            let logChannel = oldMember.guild.channels.find(c => c.name === logChannelName);

            if (!logChannel) {
                oldMember.guild.createChannel(logChannelName, "text")
                    .then(textChannel => {
                        console.log("Created channel: ", textChannel.name);
                        logChannel = textChannel;

                        handleStatusUpdate();
                    })
                    .catch(error => console.log("Error while creating log channel: " + error));
            } else {
                handleStatusUpdate();
            }

            function handleStatusUpdate() {
                if (!oldMember.voiceChannel) {
                    logChannel.send(`${oldMember.user} connected to ${newMember.voiceChannel}!`);
                } else if (!newMember.voiceChannel) {
                    logChannel.send(`${oldMember.user} disconnected from ${oldMember.voiceChannel}!`);
                } else {
                    if (oldMember.voiceChannel != newMember.voiceChannel) {
                        logChannel.send(`${oldMember.user} switched from ${oldMember.voiceChannel} to ${newMember.voiceChannel}`);
                    }
                }
            }

        };

        if (logStatus) {
            message.guild.client.on("voiceStateUpdate", logListener);
        } else {
            message.guild.client.removeListener("voiceStateUpdate", logListener);
        }

        message.channel.send(`Logging status: ${logStatus}`);
    }
};

Object.setPrototypeOf(LogToggleHandler, ContentRegExpHandler);

const LogStatusHandler = {
    LogStatusHandler() {
        this.secure = true;

        this.ContentRegExpHandler(/^\.logstatus/);
    },
    handle(message, storage) {
        let logStatus = storage.getFromGuildLevel(message.guild, "log.status", true,
            configuration.getConfig("log.status", true));

        message.channel.send(`Logging status: ${logStatus}`);
    }
};

Object.setPrototypeOf(LogStatusHandler, ContentRegExpHandler);

function registerHandlers(registerFunction) {
    const logToggleHandler = Object.create(LogToggleHandler);
    logToggleHandler.LogToggleHandler();

    const logStatusHandler = Object.create(LogStatusHandler);
    logStatusHandler.LogStatusHandler();

    registerFunction(logToggleHandler);
    registerFunction(logStatusHandler);
}

module.exports = {
    registerHandlers
};
<commit_msg>Bugfix for server-wide user logging<commit_after>const configuration = require("../configuration");
const ContentRegExpHandler = require("../content-regexp-handler.js");

const LogToggleHandler = {
    LogToggleHandler() {
        this.secure = true;

        this.ContentRegExpHandler(/^\.logtoggle/);
    },
    handle(message, storage) {
        let logStatus = storage.getFromGuildLevel(message.guild, "log.status", true,
            configuration.getConfig("log.status", true));

        logStatus = !logStatus;

        storage.saveOnGuildLevel(message.guild, "log", {
            status: logStatus
        });

        let logListener = (oldMember, newMember) => {
            let logStatus = storage.getFromGuildLevel(oldMember.guild, "log.status", true, true);

            if (logStatus) {
                let logChannelName = storage.getFromGuildLevel(oldMember.guild, "log.channelName", true,
                    configuration.getConfig("log.channelName", "log"));
                let logChannel = oldMember.guild.channels.find(c => c.name === logChannelName);

                if (!logChannel) {
                    oldMember.guild.createChannel(logChannelName, "text")
                        .then(textChannel => {
                            console.log("Created channel: ", textChannel.name);
                            logChannel = textChannel;

                            handleStatusUpdate(logChannel);
                        })
                        .catch(error => console.log("Error while creating log channel: " + error));
                } else {
                    handleStatusUpdate(logChannel);
                }
            }

            function handleStatusUpdate(logChannel) {
                if (!oldMember.voiceChannel) {
                    logChannel.send(`${oldMember.user} connected to ${newMember.voiceChannel}!`);
                } else if (!newMember.voiceChannel) {
                    logChannel.send(`${oldMember.user} disconnected from ${oldMember.voiceChannel}!`);
                } else {
                    if (oldMember.voiceChannel != newMember.voiceChannel) {
                        logChannel.send(`${oldMember.user} switched from ${oldMember.voiceChannel} to ${newMember.voiceChannel}`);
                    }
                }
            }
        };

        if (logStatus) {
            if (!message.client.listeners("voiceStateUpdate").includes(logListener)) {
                message.client.on("voiceStateUpdate", logListener);
            }
        } else {
            message.client.removeListener("voiceStateUpdate", logListener);
        }

        message.channel.send(`Logging status: ${logStatus}`);
    }
};

Object.setPrototypeOf(LogToggleHandler, ContentRegExpHandler);

const LogStatusHandler = {
    LogStatusHandler() {
        this.secure = true;

        this.ContentRegExpHandler(/^\.logstatus/);
    },
    handle(message, storage) {
        let logStatus = storage.getFromGuildLevel(message.guild, "log.status", true,
            configuration.getConfig("log.status", true));

        message.channel.send(`Logging status: ${logStatus}`);
    }
};

Object.setPrototypeOf(LogStatusHandler, ContentRegExpHandler);

function registerHandlers(registerFunction) {
    const logToggleHandler = Object.create(LogToggleHandler);
    logToggleHandler.LogToggleHandler();

    const logStatusHandler = Object.create(LogStatusHandler);
    logStatusHandler.LogStatusHandler();

    registerFunction(logToggleHandler);
    registerFunction(logStatusHandler);
}

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


<commit_before>'use strict';

/**
 * Global modules
 */
var nodemailer = require('nodemailer');
var htmlToText = require('html-to-text');
var _ = require('lodash');

/**
 * Private constants
 */
var _SUBJECT = '[NewSprint] Sprint Newsletter';

/**
 * Try to send the newsletter
 * @param {string}  htmlData  The HTML of the newsletter
 * @param {object} configuration Configuration for the job
 * @param {object} paths Paths of the module and executation
 * @param {function} callback Async callback
 */
function init(html, configuration, paths, callback) {

	//Check if the configuration for the email exists
	if (_.has(configuration, 'sprint.mail')) {

		//Mail options
		var mailOptions = {
			subject: _.has(configuration, 'sprint.mail.subject') ? configuration.sprint.mail.subject : _SUBJECT,
			text: htmlToText.fromString(html),
			html: html
		};

		//Create the transport
		var transporter = nodemailer.createTransport();

		//Try to send
		transporter.sendMail(_.assign(mailOptions, configuration.sprint.mail), function(err, info) {

			//Check errors
			if (err) {

				callback('There was an error sending the newsletter: ' + err);

				//Ok!
			} else {

				//Check if there errors in the response
				if (info.errors.length) {

					callback('There was an error sending the newsletter: ' + info.errors.join(' '));

				} else {

					callback();

				}

			}

		});

	} else {

		callback('To send the newsletter is required some neccesary information in your sprint file (mail.from, mail.to, mail.subject). Skipping... \n https://github.com/rodati/newsprint#sprintjson-optional');

	}

}

/**
 * Public methods exported
 */
module.exports = {
	init: init
};
<commit_msg>Show errors on debug<commit_after>'use strict';

/**
 * Global modules
 */
var nodemailer = require('nodemailer');
var htmlToText = require('html-to-text');
var _ = require('lodash');

/**
 * Private constants
 */
var _SUBJECT = '[NewSprint] Sprint Newsletter';

/**
 * Try to send the newsletter
 * @param {string}  htmlData  The HTML of the newsletter
 * @param {object} configuration Configuration for the job
 * @param {object} paths Paths of the module and executation
 * @param {function} callback Async callback
 */
function init(html, configuration, paths, callback) {

	//Check if the configuration for the email exists
	if (_.has(configuration, 'sprint.mail')) {

		//Mail options
		var mailOptions = {
			subject: _.has(configuration, 'sprint.mail.subject') ? configuration.sprint.mail.subject : _SUBJECT,
			text: htmlToText.fromString(html),
			html: html
		};

		//Create the transport
		var transporter = nodemailer.createTransport();

		//Try to send
		transporter.sendMail(_.assign(mailOptions, configuration.sprint.mail), function(err, info) {

			//Check errors
			if (err) {

				libs.logger.debug(JSON.stringify(err));

				callback('There was an error sending the newsletter: ' + err);

				//Ok!
			} else {

				//Check if there errors in the response
				if (info.errors.length) {

					libs.logger.debug(JSON.stringify(info.errors));

					callback('There was an error sending the newsletter: ' + info.errors.join(' '));

				} else {

					callback();

				}

			}

		});

	} else {

		callback('To send the newsletter is required some neccesary information in your sprint file (mail.from, mail.to, mail.subject). Skipping... \n https://github.com/rodati/newsprint#sprintjson-optional');

	}

}

/**
 * Public methods exported
 */
module.exports = {
	init: init
};
<|endoftext|>


<commit_before>var userIds = ['GeorgMeier'].map(u => u.toLowerCase());
var perfType = 'bullet';
var perf = {
  "gl": {
    "r": 2500,
    "d": 150,
    "v": 0.06
  },
  "nb": NumberInt(0),
  "re": [ ]
};

userIds.forEach(id => {
  var user = db.user4.findOne({_id:id});
  if (user && (!user.perfs[perfType] || !user.perfs[perfType].nb))
    db.user4.update({_id:id},{$set:{['perfs.' + perfType]: perf}});
  db.tournament_player.update(
    {uid:id,r:1500,m:150},
    {$set:{r:NumberInt(perf.gl.r),m:NumberInt(perf.gl.r/10)}},
    {multi:1});
});
<commit_msg>update mongo script<commit_after>var userIds = ['GeorgMeier'].map(u => u.toLowerCase());
var perfType = 'bullet';
var perf = {
  "gl": {
    "r": 2500,
    "d": 150,
    "v": 0.06
  },
  "nb": NumberInt(0),
  "re": [ ]
};

userIds.forEach(id => {
  var user = db.user4.findOne({_id:id});
  if (user && (!user.perfs[perfType] || !user.perfs[perfType].nb))
    db.user4.update({_id:id},{$set:{['perfs.' + perfType]: perf}});
  db.tournament_player.update(
    {uid:id,r:1500,m:1500},
    {$set:{r:NumberInt(perf.gl.r),m:NumberInt(perf.gl.r)}},
    {multi:1});
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
  oref0 Nightscout profile update tool

  Checks the ISF / Basal profile in Nightscout and updates the profile if
  necessary to match the profile collected by OpenAPS

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.

*/

var crypto = require('crypto');
var request = require('request');
var _ = require('lodash');

if (!module.parent) {

    var argv = require('yargs')
        .usage("$0 profile.json NSURL api-secret [--preview]")
        .option('preview', {
            alias: 'p'
            , describe: "Give a preview of the outcome without uploading"
            , default: false
        })
        .strict(true)
        .help('help');

    function usage() {
        argv.showHelp();
    }

    var params = argv.argv;
    var errors = [];
    var warnings = [];

    var profile_input = params._[0];

    if ([null, '--help', '-h', 'help'].indexOf(profile_input) > 0) {
        usage();
        process.exit(0);
    }

    var nsurl = params._[1];
    var apisecret = params._[2];
    var headers = {
      'content-type': 'application/json'
    };

    if (!profile_input || !nsurl || !apisecret) {
        usage();
        process.exit(1);
    }

    if (apisecret.indexOf('token=') !== 0 && apisecret.length !== 40) {
        var shasum = crypto.createHash('sha1');
        shasum.update(String(apisecret));
        apisecret = shasum.digest('hex');
        geturl = nsurl + '/api/v1/profile/current';
        headers['api-secret'] = apisecret;
    } else {
        geturl = nsurl + '/api/v1/profile/current?' + apisecret;
    }

    try {
        var cwd = process.cwd();
        var profiledata = require(cwd + '/' + profile_input);

        // Rudimentary check that the profile is valid

        if (!profiledata.dia
          || profiledata.basalprofile.length < 1
          || profiledata.bg_targets.length < 1
          || profiledata.isfProfile.length < 1 )
          { throw "Profile JSON missing data"; }

    } catch (e) {
        return console.error('Could not parse input data: ', e);
    }

    var options = {
        uri: geturl
        , json: true
        , headers
    };

    request(options, function(error, res, data) {
        if (error || res.statusCode !== 200) {
            console.log('Loading current profile from Nightscout failed: ' + res.statusCode);
            process.exit(1);
        }

        var original_profile = data;
        var new_profile = _.cloneDeep(data);

        if (!data.defaultProfile) {
            console.error('Nightscout profile missing data');
            process.exit(1);
        }

        var profile_id = data.defaultProfile;
        var profile_store = new_profile.store[profile_id];

        profile_store.dia = profiledata.dia;

        // Basals

        var new_basal = [];

        _.forEach(profiledata.basalprofile, function(basalentry) {

            var newEntry = {
                time: '' + basalentry.start.substring(0, 5)
                , value: '' + +(Math.round(basalentry.rate + 'e+3') + 'e-3')
                , timeAsSeconds: '' + basalentry.minutes * 60
            };

            new_basal.push(newEntry);

        });

        profile_store.basal = new_basal;

        // BG Targets

        var new_target_low = [];
        var new_target_high = [];

        _.forEach(profiledata.bg_targets.targets, function(target_entry) {

            var time = target_entry.start.substring(0, 5);
            var seconds = parseInt(time.substring(0, 2)) * 60 * 60 + parseInt(time.substring(3, 5)) * 60;
            var low_value = Math.round(target_entry.low);
            var high_value = Math.round(target_entry.high);

            if (new_profile.units === 'mmol' && profiledata.bg_targets.units === 'mg/dL') {
                low_value = +(Math.round(target_entry.low / 18 + 'e+1') + 'e-1');
                high_value = +(Math.round(target_entry.high / 18 + 'e+1') + 'e-1');
            }

            var new_low_entry = {
                time: '' + time
                , value: '' + low_value
                , timeAsSeconds: '' + seconds
            };

            var new_high_entry = {
                time: '' + time
                , value: '' + high_value
                , timeAsSeconds: '' + seconds

            };

            new_target_low.push(new_low_entry);
            new_target_high.push(new_high_entry);
        });

        profile_store.target_low = new_target_low;
        profile_store.target_high = new_target_high;

        // ISF

        var new_sens = [];

        _.forEach(profiledata.isfProfile.sensitivities, function(isf_entry) {

            var value = Math.round(isf_entry.sensitivity);

            if (new_profile.units === 'mmol' && profiledata.isfProfile.units === 'mg/dL') {
                value = +(Math.round(isf_entry.sensitivity / 18 + 'e+1') + 'e-1');
            }

            var new_isf_entry = {
                time: isf_entry.start.substring(0, 5)
                , value: '' + value
                , timeAsSeconds: '' + isf_entry.offset * 60
            };

            new_sens.push(new_isf_entry);
        });

        profile_store.sens = new_sens;

        // Carb ratios

        var new_carb_ratios = [];

        _.forEach(profiledata.carb_ratios.schedule, function(carb_entry) {

            var new_entry = {
                time: carb_entry.start.substring(0, 5)
                , value: '' + carb_entry.ratio
                , timeAsSeconds: '' + carb_entry.offset * 60
            };

            new_carb_ratios.push(new_entry);
        });

        profile_store.carbratio = new_carb_ratios;

        // change dates & remove Mongo ID from new profile to create a new object
        // Inserts the new profile with name "OpenAPS Autosync" to not overwrite
        // human-entered data

        var upload_profile;

        if (profile_id !== 'OpenAPS Autosync') {
            upload_profile = _.cloneDeep(data);
        } else {
            upload_profile = new_profile;
        }

        var do_upload = !_.isEqual(original_profile, new_profile);

        if (do_upload) {

            var d = new Date();
            profile_store.startDate = d.toISOString();

            if (profile_id !== 'OpenAPS Autosync') {
                upload_profile.defaultProfile = 'OpenAPS Autosync';
                upload_profile.store['OpenAPS Autosync'] = profile_store;
            }

            delete upload_profile._id;

            upload_profile.startDate = profile_store.startDate;
            upload_profile.created_at = profile_store.startDate;
            upload_profile.mills = d.getTime();
        }

        // render preview

        if (params.preview) {

            if (_.isEqual(original_profile, new_profile)) {
                console.log('Profile in Nightscout and OpenAPS are identical');
            } else {
                console.log('Profile in Nightscout and OpenAPS differ');
                console.log('-------------- Nightscout Profile ----------------');
                console.log(JSON.stringify(original_profile, null, 2));
                console.log('-------------- New profile from OpenAPS data ----------------');
                console.log(JSON.stringify(upload_profile, null, 2));
            }

            process.exit(0);
        }

        if (do_upload) {
            var nsheaders = {
                'Content-Type': 'application/json'
            };

            console.log('Profile changed, uploading to Nightscout');

            nsurl += '/api/v1/profile';

            if (apisecret.indexOf('token=') === 0) {
                nsurl = nsurl + '?' + apisecret;
            } else {
                nsheaders['API-SECRET'] = apisecret;
            }

            options = {
                uri: nsurl
                , json: true
                , method: 'POST'
                , headers: nsheaders
                , body: upload_profile
            };

            request(options, function(error, res, data) {
                if (error || res.statusCode !== 200) {
                    console.log(error);
                    console.log(res.body);
                } else {
                    console.log('Profile uploaded to Nightscout');
                }
            });
        } else {
            console.log('Profiles match, no upload needed');
        }
    });
}
<commit_msg>Allow oref0-upload-profile to also switch to new profile (#1285)<commit_after>#!/usr/bin/env node

/*
  oref0 Nightscout profile update tool

  Checks the ISF / Basal profile in Nightscout and updates the profile if
  necessary to match the profile collected by OpenAPS

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.

*/

var crypto = require('crypto');
var request = require('request');
var _ = require('lodash');

if (!module.parent) {

    var argv = require('yargs')
        .usage("$0 profile.json NSURL api-secret [--preview] [--switch]")
        .option('preview', {
            alias: 'p'
            , describe: "Give a preview of the outcome without uploading"
            , default: false
        })
        .option('switch', {
            default: false
            , describe: "Issue Profile Switch event to enable this profile"
        })
        .strict(true)
        .help('help');

    function usage() {
        argv.showHelp();
    }

    var params = argv.argv;
    var errors = [];
    var warnings = [];

    var profile_input = params._[0];

    if ([null, '--help', '-h', 'help'].indexOf(profile_input) > 0) {
        usage();
        process.exit(0);
    }

    var nsurl = params._[1];
    var apisecret = params._[2];
    var headers = {
      'content-type': 'application/json'
    };

    if (!profile_input || !nsurl || !apisecret) {
        usage();
        process.exit(1);
    }

    if (apisecret.indexOf('token=') !== 0 && apisecret.length !== 40) {
        var shasum = crypto.createHash('sha1');
        shasum.update(String(apisecret));
        apisecret = shasum.digest('hex');
        geturl = nsurl + '/api/v1/profile/current';
        headers['api-secret'] = apisecret;
    } else {
        geturl = nsurl + '/api/v1/profile/current?' + apisecret;
    }

    try {
        var cwd = process.cwd();
        var profiledata = require(cwd + '/' + profile_input);

        // Rudimentary check that the profile is valid

        if (!profiledata.dia
          || profiledata.basalprofile.length < 1
          || profiledata.bg_targets.length < 1
          || profiledata.isfProfile.length < 1 )
          { throw "Profile JSON missing data"; }

    } catch (e) {
        return console.error('Could not parse input data: ', e);
    }

    var options = {
        uri: geturl
        , json: true
        , headers
    };

    request(options, function(error, res, data) {
        if (error || res.statusCode !== 200) {
            console.log('Loading current profile from Nightscout failed: ' + res.statusCode);
            process.exit(1);
        }

        var original_profile = data;
        var new_profile = _.cloneDeep(data);

        if (!data.defaultProfile) {
            console.error('Nightscout profile missing data');
            process.exit(1);
        }

        var profile_id = data.defaultProfile;
        var profile_store = new_profile.store[profile_id];

        profile_store.dia = profiledata.dia;

        // Basals

        var new_basal = [];

        _.forEach(profiledata.basalprofile, function(basalentry) {

            var newEntry = {
                time: '' + basalentry.start.substring(0, 5)
                , value: '' + +(Math.round(basalentry.rate + 'e+3') + 'e-3')
                , timeAsSeconds: '' + basalentry.minutes * 60
            };

            new_basal.push(newEntry);

        });

        profile_store.basal = new_basal;

        // BG Targets

        var new_target_low = [];
        var new_target_high = [];

        _.forEach(profiledata.bg_targets.targets, function(target_entry) {

            var time = target_entry.start.substring(0, 5);
            var seconds = parseInt(time.substring(0, 2)) * 60 * 60 + parseInt(time.substring(3, 5)) * 60;
            var low_value = Math.round(target_entry.low);
            var high_value = Math.round(target_entry.high);

            if (new_profile.units === 'mmol' && profiledata.bg_targets.units === 'mg/dL') {
                low_value = +(Math.round(target_entry.low / 18 + 'e+1') + 'e-1');
                high_value = +(Math.round(target_entry.high / 18 + 'e+1') + 'e-1');
            }

            var new_low_entry = {
                time: '' + time
                , value: '' + low_value
                , timeAsSeconds: '' + seconds
            };

            var new_high_entry = {
                time: '' + time
                , value: '' + high_value
                , timeAsSeconds: '' + seconds

            };

            new_target_low.push(new_low_entry);
            new_target_high.push(new_high_entry);
        });

        profile_store.target_low = new_target_low;
        profile_store.target_high = new_target_high;

        // ISF

        var new_sens = [];

        _.forEach(profiledata.isfProfile.sensitivities, function(isf_entry) {

            var value = Math.round(isf_entry.sensitivity);

            if (new_profile.units === 'mmol' && profiledata.isfProfile.units === 'mg/dL') {
                value = +(Math.round(isf_entry.sensitivity / 18 + 'e+1') + 'e-1');
            }

            var new_isf_entry = {
                time: isf_entry.start.substring(0, 5)
                , value: '' + value
                , timeAsSeconds: '' + isf_entry.offset * 60
            };

            new_sens.push(new_isf_entry);
        });

        profile_store.sens = new_sens;

        // Carb ratios

        var new_carb_ratios = [];

        _.forEach(profiledata.carb_ratios.schedule, function(carb_entry) {

            var new_entry = {
                time: carb_entry.start.substring(0, 5)
                , value: '' + carb_entry.ratio
                , timeAsSeconds: '' + carb_entry.offset * 60
            };

            new_carb_ratios.push(new_entry);
        });

        profile_store.carbratio = new_carb_ratios;

        // change dates & remove Mongo ID from new profile to create a new object
        // Inserts the new profile with name "OpenAPS Autosync" to not overwrite
        // human-entered data

        var upload_profile;

        if (profile_id !== 'OpenAPS Autosync') {
            upload_profile = _.cloneDeep(data);
        } else {
            upload_profile = new_profile;
        }

        var do_upload = !_.isEqual(original_profile, new_profile);

        if (do_upload) {

            var d = new Date();
            profile_store.startDate = d.toISOString();

            if (profile_id !== 'OpenAPS Autosync') {
                upload_profile.defaultProfile = 'OpenAPS Autosync';
                upload_profile.store['OpenAPS Autosync'] = profile_store;
            }

            delete upload_profile._id;

            upload_profile.startDate = profile_store.startDate;
            upload_profile.created_at = profile_store.startDate;
            upload_profile.mills = d.getTime();
        }

        // render preview

        if (params.preview) {

            if (_.isEqual(original_profile, new_profile)) {
                console.log('Profile in Nightscout and OpenAPS are identical');
            } else {
                console.log('Profile in Nightscout and OpenAPS differ');
                console.log('-------------- Nightscout Profile ----------------');
                console.log(JSON.stringify(original_profile, null, 2));
                console.log('-------------- New profile from OpenAPS data ----------------');
                console.log(JSON.stringify(upload_profile, null, 2));
            }

            process.exit(0);
        }

        if (do_upload) {
            var nsheaders = {
                'Content-Type': 'application/json'
            };

            console.log('Profile changed, uploading to Nightscout');

            var nsurl_upload = nsurl + '/api/v1/profile';

            if (apisecret.indexOf('token=') === 0) {
                nsurl_upload = nsurl_upload + '?' + apisecret;
            } else {
                nsheaders['API-SECRET'] = apisecret;
            }

            options = {
                uri: nsurl_upload
                , json: true
                , method: 'POST'
                , headers: nsheaders
                , body: upload_profile
            };

            request(options, function(error, res, data) {
                if (error || res.statusCode !== 200) {
                    console.log(error);
                    console.log(res.body);
                } else {
                    console.log('Profile uploaded to Nightscout');
                }
            });
            if (params.switch) {
                var nsheaders = {
                    'Content-Type': 'application/json'
                };

                console.log('Switching profile');

                var nsurl_switch = nsurl + '/api/v1/treatments.json';

                if (apisecret.indexOf('token=') === 0) {
                    nsurl_switch = nsurl_switch + '?' + apisecret;
                } else {
                    nsheaders['API-SECRET'] = apisecret;
                }

                var switch_event = {};
                switch_event['enteredBy'] = 'OpenAPS';
                switch_event['eventType'] = 'Profile Switch';
                switch_event['duration'] = 0;
                switch_event['profile'] = 'OpenAPS Autosync';
                switch_event['reason'] = 'Applying uploaded profile';
                switch_event['notes'] = 'Applying uploaded profile';

                switch_options = {
                    uri: nsurl_switch
                    , json: true
                    , method: 'POST'
                    , headers: nsheaders
                    , body: switch_event
                };

                request(switch_options, function(error, res, data) {
                    if (error || res.statusCode !== 200) {
                        console.log(error);
                        console.log(res.body);
                    } else {
                        console.log('Profile switch event sent to Nightscout');
                    }
                });
            }
        } else {
            console.log('Profiles match, no upload needed');
        }
    });
}
<|endoftext|>


<commit_before>#!/bin/env node

'use strict';

const chokidar = require('chokidar');
const co = require('co');
const fs = require('fs-extra');
const fsp = require('thenify-all')(fs);
const path = require('path');
const program = require('commander');

const debug = require('../lib/util/debug')('bin:import');
const die = require('../lib/util/die');
const home = require('../lib/config/home');
const imp = require('../lib/import/import');

var processChain = Promise.resolve();
const importFiles = {};
const createdDirs = {};

program
    .usage('<file>')
    .option('-l, --limit <number>', 'Limit of files to import', Number)
    .option('-w, --watch', 'Watch files')
    .option('--continuous', 'Continuous mode. When import is finished, wait for some time and then import again')
    .option('--wait <time>', 'Wait time in minutes between imports for continuous mode (default: 1)', Number, 1)
    .option('-c --config <path>', 'Path to custom config file')
    .parse(process.argv);

function doContinuous(waitTime) {
    importAll().then(
        () => setTimeout(doContinuous, waitTime),
        err => die(err.message || err)
    );
}

const importAll = co.wrap(function*() {
    const homeDir = getHomeDir();
    const files = yield findFiles(homeDir);
    const limit = program.limit || files.length;
    debug(`${files.length} files and limit is ${limit}`);
    const min = Math.min(limit, files.length);
    for (var i = 0; i < min; i++) {
        var file = files[i];
        yield processFile2(file.database, file.importName, homeDir, file.path);
    }
});

const findFiles = co.wrap(function*(homeDir){
    let files = [];

    const databases = yield fsp.readdir(homeDir);
    for (const database of databases) {
        if (database === 'node_modules') continue;
        const databasePath = path.join(homeDir, database);
        const stat = yield fsp.stat(databasePath);
        if (!stat.isDirectory()) continue;

        const importNames = yield fsp.readdir(databasePath);
        for (const importName of importNames) {
            if (importName === 'node_modules') continue;
            const importNamePath = path.join(databasePath, importName);
            const stat = yield fsp.stat(importNamePath);
            if (!stat.isDirectory()) continue;

            try {
                const importConfigPath = path.join(importNamePath, 'import');
                const importConfig = require(importConfigPath);
                if (importConfig && Array.isArray(importConfig.source)) {
                    for (const source of importConfig.source) {
                        try {
                            const sourcePath = path.resolve(importNamePath, source);
                            const sourceToProcessPath = path.join(sourcePath, 'to_process');
                            const stat = yield fsp.stat(sourceToProcessPath);
                            if (stat.isDirectory()) {
                                const fileList = yield getFilesToProcess(sourceToProcessPath);
                                const objFiles = fileList.map(file => ({database, importName, path: file}));
                                files = files.concat(objFiles);
                            }
                        } catch (e) {
                            // ignore
                        }
                    }
                }
            } catch (e) {
                // ignore
            }

            try {
                const toProcessPath = path.join(importNamePath, 'to_process');
                const stat = yield fsp.stat(toProcessPath);
                if (stat.isDirectory()) {
                    const fileList = yield getFilesToProcess(toProcessPath);
                    const objFiles = fileList.map(file => ({database, importName, path: file}));
                    files = files.concat(objFiles);
                }
            } catch (e) {
                // ignore
            }
        }
    }

    return files;
});

function getFilesToProcess(directory) {
    return new Promise((resolve, reject) => {
        const items = [];
        fs.walk(directory)
            .on('data', function (item) {
                if (item.stats.isFile()) {
                    items.push(item.path);
                }
            })
            .on('end', function () {
                resolve(items);
            })
            .on('error', function (error) {
                reject(error);
            });
    });
}

function getHomeDir() {
    let homeDir = home.homeDir;
    if (!homeDir) {
        die('homeDir must be set to import all');
    }
    return homeDir;
}

function checkFile(homeDir, p) {
    p = path.resolve(homeDir, p);
    const relpath = path.relative(homeDir, p);
    const elements = relpath.split('/');
    if (elements.length < 4) return false;
    if (elements[2] !== 'to_process') return false;
    if (hasImportFile(path.resolve(homeDir, elements[0] + '/' + elements[1]))) {
        return {
            database: elements[0],
            importName: elements[1]
        };
    }
}

function processFile(database, importName, homeDir, p) {
    debug.trace(`process file ${p}`);
    p = path.resolve(homeDir, p);
    let parsedPath = path.parse(p);

    processChain = processChain.then(() => {
        return imp.import(database, importName, p);
    }).then(() => {
        // mv to processed
        return new Promise(function (resolve, reject) {
            let dir = path.join(parsedPath.dir, '../processed/' + getMonth());
            createDir(dir);
            tryRename(p, path.join(dir, parsedPath.base), resolve, reject);
        });
    }).catch(e => {
        // mv to errored
        return new Promise(function (resolve, reject) {
            if (e.message.startsWith('no import config')) {
                debug.warn('no import configuration found, skipping this file');
                return resolve();
            }
            debug.error(e + '\n' + e.stack);
            let dir = path.join(parsedPath.dir, '../errored/' + getMonth());
            createDir(dir);
            tryRename(p, path.join(dir, parsedPath.base), resolve, reject);
        });
    });

    return processChain;
}

function* processFile2(database, importName, filePath) {
    debug.trace(`process file ${filePath}`);
    const parsedPath = path.parse(filePath);
    const splitParsedPath = parsedPath.dir.split('/');
    const to_process = splitParsedPath.indexOf('to_process');
    if (to_process === -1) {
        throw new Error('to_process not found in path. This should not happen');
    }

    try {
        yield imp.import(database, importName, filePath);
        // success, move to processed
        yield moveFile(filePath, parsedPath.base, splitParsedPath, to_process, 'processed');
    } catch (e) {
        // error, move to errored
        if (e.message.startsWith('no import config')) {
            debug.warn('no import configuration found, skipping this file');
            return;
        }
        debug.error(e + '\n' + e.stack);
        yield moveFile(filePath, parsedPath.base, splitParsedPath, to_process, 'errored');
    }
}

function* moveFile(filePath, fileName, splitParsedPath, to_process, dest) {
    const base = splitParsedPath.slice(0, to_process).join('/');
    let subdir;
    if (splitParsedPath.length - to_process > 1) {
        subdir = splitParsedPath.slice(to_process + 1).join('/');
    } else {
        subdir = getMonth();
    }
    const destination = path.join(base, dest, subdir, fileName);
    yield tryMove(filePath, destination);
}

function* tryMove(from, to, suffix) {
    if (suffix > 1000) {
        throw new Error('tryMove: too many retries');
    }
    if (!suffix) {
        suffix = 0;
    }
    var newTo = to;
    if (suffix > 0) {
        newTo += '.' + suffix;
    }
    try {
        yield fsp.move(from, newTo);
    } catch (e) {
        if (e.code !== 'EEXIST') {
            throw new Error(`Could could rename ${from} to ${newTo}: ${e}`);
        }
        yield tryMove(from, to, ++suffix);
    }
}

function tryRename(from, to, resolve, reject, suffix) {
    if (!suffix) {
        suffix = 0;
    }
    var newTo = to;
    if (suffix > 0) {
        newTo += '.' + suffix;
    }
    fs.access(newTo, function (err) {
        if (err) {
            if (err.code !== 'ENOENT') {
                debug.error(`Could could rename ${from} to ${newTo}: ${err}`);
                return reject(err);
            } else {
                return fs.rename(from, newTo, function (err) {
                    if (err) return reject(err);
                    resolve();
                });
            }
        }
        // file exists. retry with another name
        return tryRename(from, to, resolve, reject, ++suffix);
    });
}

function hasImportFile(p) {
    if (importFiles[p]) return true;
    const importFile = path.join(p, 'import.js');
    try {
        fs.accessSync(importFile);
        importFiles[p] = true;
        return true;
    } catch (e) {
        return false;
    }
}

function createDir(dir) {
    if (createdDirs[dir]) return;

    fs.mkdirpSync(dir);
    createdDirs[dir] = true;
}

function getMonth() {
    var now = new Date();
    return now.getFullYear() + ('0' + (now.getMonth() + 1)).slice(-2);
}

let prom = Promise.resolve();
if (program.args[0]) {
    debug(`file argument: ${program.args[0]}`);
    // TODO add 2 arguments: db and import names
    throw new Error('not ready');
    //const file = path.resolve(program.args[0]);
    //
    //prom = prom.then(() => {
    //    return imp.import(config, file);
    //});
} else if (program.watch) {
    // watch files to import
    let homeDir = getHomeDir();
    debug(`watch ${homeDir}`);
    chokidar.watch(homeDir, {
        ignored: /[\/\\](\.|processed|errored|node_modules)/,
        persistent: true
    }).on('all', function (event, p) {
        debug.trace(`watch event: ${event} - ${p}`);
        let file = checkFile(homeDir, p);
        if (event !== 'add' && event !== 'change' || !file) {
            return;
        }
        processFile(file.database, file.importName, homeDir, p);
    });
} else if (program.continuous) {
    debug('continuous');
    const waitTime = program.wait * 60;
    doContinuous(waitTime);
} else {
    debug('no watch');
    prom = prom.then(importAll);
}

prom.then(function () {
    debug('finished');
}, function (err) {
    die(err.message || err);
});
<commit_msg>import: remove homeDir<commit_after>#!/bin/env node

'use strict';

const chokidar = require('chokidar');
const co = require('co');
const fs = require('fs-extra');
const fsp = require('thenify-all')(fs);
const path = require('path');
const program = require('commander');

const debug = require('../lib/util/debug')('bin:import');
const die = require('../lib/util/die');
const home = require('../lib/config/home');
const imp = require('../lib/import/import');

var processChain = Promise.resolve();
const importFiles = {};
const createdDirs = {};

program
    .usage('<file>')
    .option('-l, --limit <number>', 'Limit of files to import', Number)
    .option('-w, --watch', 'Watch files')
    .option('--continuous', 'Continuous mode. When import is finished, wait for some time and then import again')
    .option('--wait <time>', 'Wait time in minutes between imports for continuous mode (default: 1)', Number, 1)
    .option('-c --config <path>', 'Path to custom config file')
    .parse(process.argv);

function doContinuous(waitTime) {
    importAll().then(
        () => setTimeout(doContinuous, waitTime),
        err => die(err.message || err)
    );
}

const importAll = co.wrap(function*() {
    const homeDir = getHomeDir();
    const files = yield findFiles(homeDir);
    const limit = program.limit || files.length;
    debug(`${files.length} files and limit is ${limit}`);
    const min = Math.min(limit, files.length);
    for (var i = 0; i < min; i++) {
        var file = files[i];
        yield processFile2(file.database, file.importName, file.path);
    }
});

const findFiles = co.wrap(function*(homeDir){
    let files = [];

    const databases = yield fsp.readdir(homeDir);
    for (const database of databases) {
        if (database === 'node_modules') continue;
        const databasePath = path.join(homeDir, database);
        const stat = yield fsp.stat(databasePath);
        if (!stat.isDirectory()) continue;

        const importNames = yield fsp.readdir(databasePath);
        for (const importName of importNames) {
            if (importName === 'node_modules') continue;
            const importNamePath = path.join(databasePath, importName);
            const stat = yield fsp.stat(importNamePath);
            if (!stat.isDirectory()) continue;

            try {
                const importConfigPath = path.join(importNamePath, 'import');
                const importConfig = require(importConfigPath);
                if (importConfig && Array.isArray(importConfig.source)) {
                    for (const source of importConfig.source) {
                        try {
                            const sourcePath = path.resolve(importNamePath, source);
                            const sourceToProcessPath = path.join(sourcePath, 'to_process');
                            const stat = yield fsp.stat(sourceToProcessPath);
                            if (stat.isDirectory()) {
                                const fileList = yield getFilesToProcess(sourceToProcessPath);
                                const objFiles = fileList.map(file => ({database, importName, path: file}));
                                files = files.concat(objFiles);
                            }
                        } catch (e) {
                            // ignore
                        }
                    }
                }
            } catch (e) {
                // ignore
            }

            try {
                const toProcessPath = path.join(importNamePath, 'to_process');
                const stat = yield fsp.stat(toProcessPath);
                if (stat.isDirectory()) {
                    const fileList = yield getFilesToProcess(toProcessPath);
                    const objFiles = fileList.map(file => ({database, importName, path: file}));
                    files = files.concat(objFiles);
                }
            } catch (e) {
                // ignore
            }
        }
    }

    return files;
});

function getFilesToProcess(directory) {
    return new Promise((resolve, reject) => {
        const items = [];
        fs.walk(directory)
            .on('data', function (item) {
                if (item.stats.isFile()) {
                    items.push(item.path);
                }
            })
            .on('end', function () {
                resolve(items);
            })
            .on('error', function (error) {
                reject(error);
            });
    });
}

function getHomeDir() {
    let homeDir = home.homeDir;
    if (!homeDir) {
        die('homeDir must be set to import all');
    }
    return homeDir;
}

function checkFile(homeDir, p) {
    p = path.resolve(homeDir, p);
    const relpath = path.relative(homeDir, p);
    const elements = relpath.split('/');
    if (elements.length < 4) return false;
    if (elements[2] !== 'to_process') return false;
    if (hasImportFile(path.resolve(homeDir, elements[0] + '/' + elements[1]))) {
        return {
            database: elements[0],
            importName: elements[1]
        };
    }
}

function processFile(database, importName, homeDir, p) {
    debug.trace(`process file ${p}`);
    p = path.resolve(homeDir, p);
    let parsedPath = path.parse(p);

    processChain = processChain.then(() => {
        return imp.import(database, importName, p);
    }).then(() => {
        // mv to processed
        return new Promise(function (resolve, reject) {
            let dir = path.join(parsedPath.dir, '../processed/' + getMonth());
            createDir(dir);
            tryRename(p, path.join(dir, parsedPath.base), resolve, reject);
        });
    }).catch(e => {
        // mv to errored
        return new Promise(function (resolve, reject) {
            if (e.message.startsWith('no import config')) {
                debug.warn('no import configuration found, skipping this file');
                return resolve();
            }
            debug.error(e + '\n' + e.stack);
            let dir = path.join(parsedPath.dir, '../errored/' + getMonth());
            createDir(dir);
            tryRename(p, path.join(dir, parsedPath.base), resolve, reject);
        });
    });

    return processChain;
}

function* processFile2(database, importName, filePath) {
    debug.trace(`process file ${filePath}`);
    const parsedPath = path.parse(filePath);
    const splitParsedPath = parsedPath.dir.split('/');
    const to_process = splitParsedPath.indexOf('to_process');
    if (to_process === -1) {
        throw new Error('to_process not found in path. This should not happen');
    }

    try {
        yield imp.import(database, importName, filePath);
        // success, move to processed
        yield moveFile(filePath, parsedPath.base, splitParsedPath, to_process, 'processed');
    } catch (e) {
        // error, move to errored
        if (e.message.startsWith('no import config')) {
            debug.warn('no import configuration found, skipping this file');
            return;
        }
        debug.error(e + '\n' + e.stack);
        yield moveFile(filePath, parsedPath.base, splitParsedPath, to_process, 'errored');
    }
}

function* moveFile(filePath, fileName, splitParsedPath, to_process, dest) {
    const base = splitParsedPath.slice(0, to_process).join('/');
    let subdir;
    if (splitParsedPath.length - to_process > 1) {
        subdir = splitParsedPath.slice(to_process + 1).join('/');
    } else {
        subdir = getMonth();
    }
    const destination = path.join(base, dest, subdir, fileName);
    yield tryMove(filePath, destination);
}

function* tryMove(from, to, suffix) {
    if (suffix > 1000) {
        throw new Error('tryMove: too many retries');
    }
    if (!suffix) {
        suffix = 0;
    }
    var newTo = to;
    if (suffix > 0) {
        newTo += '.' + suffix;
    }
    try {
        yield fsp.move(from, newTo);
    } catch (e) {
        if (e.code !== 'EEXIST') {
            throw new Error(`Could could rename ${from} to ${newTo}: ${e}`);
        }
        yield tryMove(from, to, ++suffix);
    }
}

function tryRename(from, to, resolve, reject, suffix) {
    if (!suffix) {
        suffix = 0;
    }
    var newTo = to;
    if (suffix > 0) {
        newTo += '.' + suffix;
    }
    fs.access(newTo, function (err) {
        if (err) {
            if (err.code !== 'ENOENT') {
                debug.error(`Could could rename ${from} to ${newTo}: ${err}`);
                return reject(err);
            } else {
                return fs.rename(from, newTo, function (err) {
                    if (err) return reject(err);
                    resolve();
                });
            }
        }
        // file exists. retry with another name
        return tryRename(from, to, resolve, reject, ++suffix);
    });
}

function hasImportFile(p) {
    if (importFiles[p]) return true;
    const importFile = path.join(p, 'import.js');
    try {
        fs.accessSync(importFile);
        importFiles[p] = true;
        return true;
    } catch (e) {
        return false;
    }
}

function createDir(dir) {
    if (createdDirs[dir]) return;

    fs.mkdirpSync(dir);
    createdDirs[dir] = true;
}

function getMonth() {
    var now = new Date();
    return now.getFullYear() + ('0' + (now.getMonth() + 1)).slice(-2);
}

let prom = Promise.resolve();
if (program.args[0]) {
    debug(`file argument: ${program.args[0]}`);
    // TODO add 2 arguments: db and import names
    throw new Error('not ready');
    //const file = path.resolve(program.args[0]);
    //
    //prom = prom.then(() => {
    //    return imp.import(config, file);
    //});
} else if (program.watch) {
    // watch files to import
    let homeDir = getHomeDir();
    debug(`watch ${homeDir}`);
    chokidar.watch(homeDir, {
        ignored: /[\/\\](\.|processed|errored|node_modules)/,
        persistent: true
    }).on('all', function (event, p) {
        debug.trace(`watch event: ${event} - ${p}`);
        let file = checkFile(homeDir, p);
        if (event !== 'add' && event !== 'change' || !file) {
            return;
        }
        processFile(file.database, file.importName, homeDir, p);
    });
} else if (program.continuous) {
    debug('continuous');
    const waitTime = program.wait * 60;
    doContinuous(waitTime);
} else {
    debug('no watch');
    prom = prom.then(importAll);
}

prom.then(function () {
    debug('finished');
}, function (err) {
    die(err.message || err);
});
<|endoftext|>


<commit_before>(function ($ns) {
    var showContentOnload = function (className) {
        var
            list = $("nav ul.tabs")
            ,items = list.find("li")
            ,container = $("ul.tabs-container")
            ,URLHash = location.hash
            ,handle = null
            ,id = null
        ;

        container.find("li").hide();

        if( URLHash.isSet() )
            handle = items.findByHref(URLHash);
        else
            handle = items.find("a." + className);

        id = handle.attr('href');

        container.find("li" + id).show();

        // selected = container.find("li.#{tabAnchor.attr("class")}")
        // selected = container.find("li#{tabAnchor.attr("href")}")
        //  if selected.length == 0
        //    url = $(this).data("url")
        //    if url
        //      content = $("

").addClass tabAnchor.attr("class")
        //      container.append content

        //      format = $(this).data("format")
        //      if !format
        //        format = "js"

        //      $.get url, {format: format},
        //        (data, status, xhr)->
        //          if format == "html"
        //            content.html data
    };

    var selectTabOnload = function (jqObj, selectedClassName) {
        var
            list = $("nav ul.tabs")
            ,items = list.find("li")
            ,anchors = items.find("a")
            ,URLHash = location.hash
            ,selectedDefault = items.find("a." + selectedClassName)
            ,handle = null
            ,URLPath = null
            ,anchorSearch = null
            ,parent = jqObj.closest("ul.tabs")
        ;

        if( URLHash.isSet() ) {
            selectTab(parent.findByHref(URLHash), selectedClassName);
        } else {
            URLPath = location.pathname.match(/[a-z\/_-]+[a-z]+/);
            anchorSearch = items.findByHref(URLPath);

            if(anchorSearch.length != 0) {
                selectTab(anchorSearch, selectedClassName);
            } else {
                selectedDefault.removeAttr('href');
            }

            anchorSearch.removeAttr('href');
        }
    };

    var showContent = function (handle) {
        var
            parentContainer = $(handle.target).closest(".tabs-wrapper").find("ul.tabs-container")
            ,id = $(handle.target).attr('href')
        ;
        parentContainer.find("li").hide()
        parentContainer.find("li" + id).show();
    };

    var selectTab = function (handle, selectedClassName) {
        var obj = null;
        if(handle instanceof jQuery.Event) {
            handle = $(handle.target);
        } else {
            if(handle instanceof jQuery) {
                handle = $(handle);
            }
        }

        var parent  = handle.closest("ul.tabs");
        parent.find("a").removeClass(selectedClassName);

        handle.addClass(selectedClassName);
    };

    // $ns.tabs = {
    $ns.tabs = function (jqObj) {

        this.initWith = function (selectedClassName) {
            selectTabOnload(jqObj, selectedClassName);

            // verificar o href, dependendo, irá redirecionar. Caso em que essas linhas abaixo não devem ser carregadas.
            jqObj.click( function (e) {
                selectTab(e, selectedClassName);

                //aqui deverá vir a lógica de como carregar o conteúdo, se via ajax, por exemplo

                showContent(e);
            });
        }

        return this;

    };

})(DO.ui)
;<commit_msg>ajusta showContentOnLoad<commit_after>(function ($namespace) {

    var showContentOnload = function (jqObj, selectedClassName) {
        var
            parent = jqObj.closest(".tabs-wrapper")
            ,list = parent.find("ul.tabs")
            ,items = list.find("li")
            ,container = parent.find("ul.tabs-container")
            ,URLHash = location.hash
            ,handle = null
            ,id = null
        ;

        container.find("li").hide();

        if( URLHash.isSet() )
            handle = items.findAnchorByHref(URLHash);
        else
            handle = items.find("a." + className);

        id = handle.attr('href');

        container.find("li" + id).show();

        // selected = container.find("li.#{tabAnchor.attr("class")}")
        // selected = container.find("li#{tabAnchor.attr("href")}")
        //  if selected.length == 0
        //    url = $(this).data("url")
        //    if url
        //      content = $("

").addClass tabAnchor.attr("class")
        //      container.append content

        //      format = $(this).data("format")
        //      if !format
        //        format = "js"

        //      $.get url, {format: format},
        //        (data, status, xhr)->
        //          if format == "html"
        //            content.html data
    };

    var selectTabOnload = function (jqObj, selectedClassName) {
        var
            parent = jqObj.closest(".tabs-wrapper")
            ,list = parent.find("ul.tabs")
            ,items = list.find("li")
            ,selectedDefault = items.find("a." + selectedClassName)
            ,URLPath = null
            ,anchorSearch = null
            ,URLHash = location.hash
        ;

        if( URLHash.isSet() ) {
            selectTab(list.findAnchorByHref(URLHash), selectedClassName);
        }
        else {
            URLPath = location.pathname.match(/[a-z\/_-]+[a-z]+/);
            anchorSearch = items.findAnchorByHref(URLPath);

            if(anchorSearch.length != 0) {
                selectTab(anchorSearch, selectedClassName);
            } else {
                selectedDefault.removeAttr('href');
            }

            anchorSearch.removeAttr('href');
        }
    };

    var showContent = function (handle) {
        var
            parentContainer = $(handle.target).closest(".tabs-wrapper").find("ul.tabs-container")
            ,id = $(handle.target).attr('href')
        ;
        parentContainer.find("li").hide()
        parentContainer.find("li" + id).show();
    };

    var selectTab = function (handle, selectedClassName) {
        var obj = null;
        if(handle instanceof jQuery.Event) {
            handle = $(handle.target);
        } else {
            if(handle instanceof jQuery) {
                handle = $(handle);
            }
        }

        var parent  = handle.closest("ul.tabs");
        parent.find("a").removeClass(selectedClassName);

        handle.addClass(selectedClassName);
    };

    $namespace.tabs = function (jqObj) {

        this.initWith = function (selectedClassName) {
            selectTabOnload(jqObj, selectedClassName);
            showContentOnload(jqObj, selectedClassName);

            // verificar o href, dependendo, irá redirecionar. Caso em que essas linhas abaixo não devem ser carregadas.
            jqObj.click( function (e) {
                selectTab(e, selectedClassName);

                //aqui deverá vir a lógica de como carregar o conteúdo, se via ajax, por exemplo

                showContent(e);
            });
        }

        return this;

    };

})(DO.ui)
;<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for Docker is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */
var fs = require('fs')
var AdmZip = require('adm-zip')
var zip = new AdmZip()
var config = require('spm-agent').Config
var util = require('util')
var ls = require('ls')
var os = require('os')
var path = require('path')

var dockerInfo = {}
var systemInfo = {}
function printDockerInfo (err, info) {
  if (!err) {
    dockerInfo.dockerInfo = info
  }
  createZipFile()
}
try {
  dockerInfo.socketDetails = fs.statSync('/var/run/docker.sock')
  systemInfo = {
    operatingSystem: os.type() + ', ' + os.platform() + ', ' + os.release() + ', ' + os.arch(),
    processVersions: process.versions,
    processEnvironment: process.env,
    dockerInfo: dockerInfo
  }
  var Docker = require('dockerode')
  var docker = new Docker()
  docker.info(printDockerInfo)
} catch (ex) {
  dockerInfo = ex
  console.log(ex)
  createZipFile()
}

function createZipFile () {
  var cfgDumpFileName = path.join(os.tmpdir(), 'spm-cfg-dump.txt')
  var logfiles = ls(config.logger.dir + '/*')
  console.log('Adding file ' + cfgDumpFileName)
  logfiles.forEach(function (f) {
    console.log('Adding file ' + f.file)
    zip.addLocalFile(f.full)
  })
  console.log(util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo, {depth: 10}))
  fs.writeFileSync(cfgDumpFileName, util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo))
  zip.addLocalFile(cfgDumpFileName)
  var archFileName = path.join(os.tmpdir(), 'sematext-diagnose.zip')
  zip.writeZip(archFileName)
  console.log('Sematext diagnostics info is in  ' + archFileName)
  console.log('Copy the file with "docker cp sematext-agent:' + archFileName + ' ." to your docker host')
  console.log('Please e-mail the file to support@sematext.com')
  fs.unlink(cfgDumpFileName, function () {})
}
<commit_msg>changed 'docker cp' instructions<commit_after>#!/usr/bin/env node
/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for Docker is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */
var fs = require('fs')
var AdmZip = require('adm-zip')
var zip = new AdmZip()
var config = require('spm-agent').Config
var util = require('util')
var ls = require('ls')
var os = require('os')
var path = require('path')

var dockerInfo = {}
var systemInfo = {}
function printDockerInfo (err, info) {
  if (!err) {
    dockerInfo.dockerInfo = info
  }
  createZipFile()
}
try {
  dockerInfo.socketDetails = fs.statSync('/var/run/docker.sock')
  systemInfo = {
    operatingSystem: os.type() + ', ' + os.platform() + ', ' + os.release() + ', ' + os.arch(),
    processVersions: process.versions,
    processEnvironment: process.env,
    dockerInfo: dockerInfo
  }
  var Docker = require('dockerode')
  var docker = new Docker()
  docker.info(printDockerInfo)
} catch (ex) {
  dockerInfo = ex
  console.log(ex)
  createZipFile()
}

function createZipFile () {
  var cfgDumpFileName = path.join(os.tmpdir(), 'spm-cfg-dump.txt')
  var logfiles = ls(config.logger.dir + '/*')
  console.log('Adding file ' + cfgDumpFileName)
  logfiles.forEach(function (f) {
    console.log('Adding file ' + f.file)
    zip.addLocalFile(f.full)
  })
  console.log(util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo, {depth: 10}))
  fs.writeFileSync(cfgDumpFileName, util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo))
  zip.addLocalFile(cfgDumpFileName)
  var archFileName = path.join(os.tmpdir(), 'sematext-diagnose.zip')
  zip.writeZip(archFileName)
  console.log('Sematext diagnostics info is in  ' + archFileName)
  console.log('Run "docker cp sematext-agent:' + archFileName + ' ." to copy the file to the docker host')
  console.log('Please e-mail the file to support@sematext.com')
  fs.unlink(cfgDumpFileName, function () {})
}
<|endoftext|>