<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import reactMixin from 'react-mixin';
import autoBind from 'react-autobind';
import Reflux from 'reflux';
import {actions} from '../actions';
import {bem} from '../bem';
import {stores} from '../stores';
import mixins from '../mixins';
import DocumentTitle from 'react-document-title';
import SharingForm from './permissions/sharingForm';
import ProjectSettings from './modalForms/projectSettings';
import ConnectProjects from './modalForms/connectProjects';
import FormMedia from './modalForms/formMedia';
import DataTable from './table';
import ProjectExportsCreator from 'js/components/projectDownloads/projectExportsCreator';
import ProjectExportsList from 'js/components/projectDownloads/projectExportsList';
import {PROJECT_SETTINGS_CONTEXTS} from '../constants';
import FormMap from './map';
import RESTServices from './RESTServices';
import ui from '../ui';
import {ROUTES} from '../constants.es6';

export class FormSubScreens extends React.Component {
  constructor(props){
    super(props);
    this.state = {};
    autoBind(this);
  }
  componentDidMount () {
    this.listenTo(stores.asset, this.dmixAssetStoreChange);
    var uid = this.props.params.assetid || this.props.uid || this.props.params.uid;
    if (this.props.randdelay && uid) {
      window.setTimeout(()=>{
        actions.resources.loadAsset({id: uid});
      }, Math.random() * 3000);
    } else if (uid) {
      actions.resources.loadAsset({id: uid});
    }
  }
  render () {
    let permAccess = this.userCan('view_submissions', this.state) || this.userCan('partial_submissions', this.state);

    if (!this.state.permissions)
      return false;

    if ((this.props.location.pathname == `/forms/${this.state.uid}/settings` || this.props.location.pathname == `/forms/${this.state.uid}/settings/sharing`) &&
        // TODO: Once "Manage Project" permission is added, remove "Edit Form" access here
        !this.userCan('change_asset', this.state)) {
      return (<ui.AccessDeniedMessage/>);
    }

    if (this.props.location.pathname == `/forms/${this.state.uid}/settings/rest` && !permAccess) {
      return (<ui.AccessDeniedMessage/>);
    }

    var iframeUrl = '';
    var report__base = '';
    var deployment__identifier = '';

    if (this.state.uid != undefined) {
      if (this.state.deployment__identifier != undefined) {
        deployment__identifier = this.state.deployment__identifier;
        report__base = deployment__identifier.replace('/forms/', '/reports/');
      }
      switch(this.props.location.pathname) {
        case ROUTES.FORM_REPORT_OLD.replace(':uid', this.state.uid):
          iframeUrl = report__base+'/digest.html';
          break;
        case ROUTES.FORM_TABLE.replace(':uid', this.state.uid):
          return <DataTable asset={this.state} />;
        case `/forms/${this.state.uid}/data/table-legacy`:
          iframeUrl = report__base+'/export.html';
          break;
        case ROUTES.FORM_GALLERY.replace(':uid', this.state.uid):
          iframeUrl = deployment__identifier+'/photos';
          break;
        case ROUTES.FORM_MAP.replace(':uid', this.state.uid):
          return <FormMap asset={this.state} />;
        case ROUTES.FORM_MAP_BY
            .replace(':uid', this.state.uid)
            .replace(':viewby', this.props.params.viewby):
          return <FormMap asset={this.state} viewby={this.props.params.viewby}/>;
        case ROUTES.FORM_DOWNLOADS.replace(':uid', this.state.uid):
          return this.renderProjectDownloads();
        case ROUTES.FORM_SETTINGS.replace(':uid', this.state.uid):
          return this.renderSettingsEditor();
        case ROUTES.FORM_MEDIA.replace(':uid', this.state.uid):
          return this.renderUpload();
        case ROUTES.FORM_SHARING.replace(':uid', this.state.uid):
          return this.renderSharing();
        case ROUTES.FORM_RECORDS.replace(':uid', this.state.uid):
          return this.renderRecords();
        case ROUTES.FORM_REST.replace(':uid', this.state.uid):
          return <RESTServices asset={this.state} />;
        case ROUTES.FORM_REST_HOOK
            .replace(':uid', this.state.uid)
            .replace(':hook', this.props.params.hookUid):
          return <RESTServices asset={this.state} hookUid={this.props.params.hookUid}/>;
        case ROUTES.FORM_KOBOCAT.replace(':uid', this.state.uid):
          iframeUrl = deployment__identifier+'/form_settings';
          break;
        case ROUTES.FORM_RESET.replace(':uid', this.state.uid):
          return this.renderReset();
      }
    }

    var docTitle = this.state.name || t('Untitled');

    return (
        <DocumentTitle title={`${docTitle} | KoboToolbox`}>
          <bem.FormView>
            <bem.FormView__cell m='iframe'>
              <iframe src={iframeUrl} />
            </bem.FormView__cell>
          </bem.FormView>
        </DocumentTitle>
      );
  }
  renderSettingsEditor() {
    var docTitle = this.state.name || t('Untitled');
    return (
        <DocumentTitle title={`${docTitle} | KoboToolbox`}>
          <bem.FormView m='form-settings'>
            <ProjectSettings
              context={PROJECT_SETTINGS_CONTEXTS.EXISTING}
              formAsset={this.state}
            />
          </bem.FormView>
        </DocumentTitle>
    );
  }
  renderProjectDownloads() {
    var docTitle = this.state.name || t('Untitled');
    return (
      <DocumentTitle title={`${docTitle} | KoboToolbox`}>
        <bem.FormView className='project-downloads'>
          <ProjectExportsCreator asset={this.state} />
          <ProjectExportsList asset={this.state} />
        </bem.FormView>
      </DocumentTitle>
    );
  }
  renderSharing() {
    const uid = this.props.params.assetid || this.props.params.uid;
    return (
      <bem.FormView m='form-settings-sharing'>
        <SharingForm uid={uid} />
      </bem.FormView>
    );
  }
  renderRecords() {
    return (
      <bem.FormView>
        <ConnectProjects asset={this.state}/>
      </bem.FormView>
    );
  }
  renderReset() {
    return (
      <bem.Loading>
        <bem.Loading__inner>
          <i />
          {t('loading...')}
        </bem.Loading__inner>
      </bem.Loading>
    );
  }

  renderUpload() {
    return (
      <FormMedia asset={this.state}/>
    );
  }
}

reactMixin(FormSubScreens.prototype, Reflux.ListenerMixin);
reactMixin(FormSubScreens.prototype, mixins.dmix);
reactMixin(FormSubScreens.prototype, mixins.permissions);
reactMixin(FormSubScreens.prototype, mixins.contextRouter);

FormSubScreens.contextTypes = {
  router: PropTypes.object
};

export default FormSubScreens;
<commit_msg>remove unused route<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import reactMixin from 'react-mixin';
import autoBind from 'react-autobind';
import Reflux from 'reflux';
import {actions} from '../actions';
import {bem} from '../bem';
import {stores} from '../stores';
import mixins from '../mixins';
import DocumentTitle from 'react-document-title';
import SharingForm from './permissions/sharingForm';
import ProjectSettings from './modalForms/projectSettings';
import ConnectProjects from './modalForms/connectProjects';
import FormMedia from './modalForms/formMedia';
import DataTable from './table';
import ProjectExportsCreator from 'js/components/projectDownloads/projectExportsCreator';
import ProjectExportsList from 'js/components/projectDownloads/projectExportsList';
import {PROJECT_SETTINGS_CONTEXTS} from '../constants';
import FormMap from './map';
import RESTServices from './RESTServices';
import ui from '../ui';
import {ROUTES} from '../constants.es6';

export class FormSubScreens extends React.Component {
  constructor(props){
    super(props);
    this.state = {};
    autoBind(this);
  }
  componentDidMount () {
    this.listenTo(stores.asset, this.dmixAssetStoreChange);
    var uid = this.props.params.assetid || this.props.uid || this.props.params.uid;
    if (this.props.randdelay && uid) {
      window.setTimeout(()=>{
        actions.resources.loadAsset({id: uid});
      }, Math.random() * 3000);
    } else if (uid) {
      actions.resources.loadAsset({id: uid});
    }
  }
  render () {
    let permAccess = this.userCan('view_submissions', this.state) || this.userCan('partial_submissions', this.state);

    if (!this.state.permissions)
      return false;

    if ((this.props.location.pathname == `/forms/${this.state.uid}/settings` || this.props.location.pathname == `/forms/${this.state.uid}/settings/sharing`) &&
        // TODO: Once "Manage Project" permission is added, remove "Edit Form" access here
        !this.userCan('change_asset', this.state)) {
      return (<ui.AccessDeniedMessage/>);
    }

    if (this.props.location.pathname == `/forms/${this.state.uid}/settings/rest` && !permAccess) {
      return (<ui.AccessDeniedMessage/>);
    }

    var iframeUrl = '';
    var report__base = '';
    var deployment__identifier = '';

    if (this.state.uid != undefined) {
      if (this.state.deployment__identifier != undefined) {
        deployment__identifier = this.state.deployment__identifier;
        report__base = deployment__identifier.replace('/forms/', '/reports/');
      }
      switch(this.props.location.pathname) {
        case ROUTES.FORM_REPORT_OLD.replace(':uid', this.state.uid):
          iframeUrl = report__base+'/digest.html';
          break;
        case ROUTES.FORM_TABLE.replace(':uid', this.state.uid):
          return <DataTable asset={this.state} />;
        case ROUTES.FORM_GALLERY.replace(':uid', this.state.uid):
          iframeUrl = deployment__identifier+'/photos';
          break;
        case ROUTES.FORM_MAP.replace(':uid', this.state.uid):
          return <FormMap asset={this.state} />;
        case ROUTES.FORM_MAP_BY
            .replace(':uid', this.state.uid)
            .replace(':viewby', this.props.params.viewby):
          return <FormMap asset={this.state} viewby={this.props.params.viewby}/>;
        case ROUTES.FORM_DOWNLOADS.replace(':uid', this.state.uid):
          return this.renderProjectDownloads();
        case ROUTES.FORM_SETTINGS.replace(':uid', this.state.uid):
          return this.renderSettingsEditor();
        case ROUTES.FORM_MEDIA.replace(':uid', this.state.uid):
          return this.renderUpload();
        case ROUTES.FORM_SHARING.replace(':uid', this.state.uid):
          return this.renderSharing();
        case ROUTES.FORM_RECORDS.replace(':uid', this.state.uid):
          return this.renderRecords();
        case ROUTES.FORM_REST.replace(':uid', this.state.uid):
          return <RESTServices asset={this.state} />;
        case ROUTES.FORM_REST_HOOK
            .replace(':uid', this.state.uid)
            .replace(':hook', this.props.params.hookUid):
          return <RESTServices asset={this.state} hookUid={this.props.params.hookUid}/>;
        case ROUTES.FORM_KOBOCAT.replace(':uid', this.state.uid):
          iframeUrl = deployment__identifier+'/form_settings';
          break;
        case ROUTES.FORM_RESET.replace(':uid', this.state.uid):
          return this.renderReset();
      }
    }

    var docTitle = this.state.name || t('Untitled');

    return (
        <DocumentTitle title={`${docTitle} | KoboToolbox`}>
          <bem.FormView>
            <bem.FormView__cell m='iframe'>
              <iframe src={iframeUrl} />
            </bem.FormView__cell>
          </bem.FormView>
        </DocumentTitle>
      );
  }
  renderSettingsEditor() {
    var docTitle = this.state.name || t('Untitled');
    return (
        <DocumentTitle title={`${docTitle} | KoboToolbox`}>
          <bem.FormView m='form-settings'>
            <ProjectSettings
              context={PROJECT_SETTINGS_CONTEXTS.EXISTING}
              formAsset={this.state}
            />
          </bem.FormView>
        </DocumentTitle>
    );
  }
  renderProjectDownloads() {
    var docTitle = this.state.name || t('Untitled');
    return (
      <DocumentTitle title={`${docTitle} | KoboToolbox`}>
        <bem.FormView className='project-downloads'>
          <ProjectExportsCreator asset={this.state} />
          <ProjectExportsList asset={this.state} />
        </bem.FormView>
      </DocumentTitle>
    );
  }
  renderSharing() {
    const uid = this.props.params.assetid || this.props.params.uid;
    return (
      <bem.FormView m='form-settings-sharing'>
        <SharingForm uid={uid} />
      </bem.FormView>
    );
  }
  renderRecords() {
    return (
      <bem.FormView>
        <ConnectProjects asset={this.state}/>
      </bem.FormView>
    );
  }
  renderReset() {
    return (
      <bem.Loading>
        <bem.Loading__inner>
          <i />
          {t('loading...')}
        </bem.Loading__inner>
      </bem.Loading>
    );
  }

  renderUpload() {
    return (
      <FormMedia asset={this.state}/>
    );
  }
}

reactMixin(FormSubScreens.prototype, Reflux.ListenerMixin);
reactMixin(FormSubScreens.prototype, mixins.dmix);
reactMixin(FormSubScreens.prototype, mixins.permissions);
reactMixin(FormSubScreens.prototype, mixins.contextRouter);

FormSubScreens.contextTypes = {
  router: PropTypes.object
};

export default FormSubScreens;
<|endoftext|>


<commit_before>import React from 'react';
import autoBind from 'react-autobind';
import ReactDOM from 'react-dom';
import _ from 'underscore';
import Chart from 'chart.js';
import bem from '../bem';
import $ from 'jquery';

import {t, assign} from '../utils';

class ReportTable extends React.Component {
  constructor(props) {
    super(props);
  }
  formatNumber(x) {
    if (isNaN(x))
      return x;
    return x.toFixed(2);
  }
  render () {
    let th = [''], rows = [];
    if (this.props.type === 'numerical') {
      th = [t('Mean'), t('Median'), t('Mode'), t('Standard deviation')];
      if (this.props.rows)
        th.unshift('');
      if (this.props.values)
        var v = this.props.values
      return (

              {th.map((t,i)=>{
                return ({t}	);
              })}

          {this.props.values &&

                {this.formatNumber(v.mean) || t('N/A')}
                {this.formatNumber(v.median) || t('N/A')}
                {this.formatNumber(v.mode) || t('N/A')}
                {this.formatNumber(v.stdev) || t('N/A')}

          }
          {this.props.rows &&

              {this.props.rows.map((r)=>{
                return (

                      {r[0]}
                      {this.formatNumber(r[1].mean) || t('N/A')}
                      {this.formatNumber(r[1].median) || t('N/A')}
                      {this.formatNumber(r[1].mode) || t('N/A')}
                      {this.formatNumber(r[1].stdev) || t('N/A')}

                  );
              })}

          }

      );
    }
    if (this.props.type === 'regular') {
      th = [t('Value'), t('Frequency'), t('Percentage')];
      rows = this.props.rows;
    } else {
      if (this.props.rows.length > 0) {
        if (this.props.responseLabels)
          th = th.concat(this.props.responseLabels);
        else
          th = th.concat(this.props.rows[0][1].responses);
        this.props.rows.map((row, i)=> {
          var rowitem = row[2] ? [row[2]] : [row[0]];
          rowitem = rowitem.concat(row[1].percentages);
          rows.push(rowitem);
        });
      }
    }

    if (rows.length === 0) {
      return false;
    }

    return (

              {th.map((t,i)=>{
                return ({t}	);
              })}

            {rows.map((row)=>{
              return (

                    {row.map((r,i)=>{
                      return ({r}	);
                    })}

                );
            })}

      )
  }
};

class ReportViewItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      reportTable: false
    };
    this.itemChart = false;
    autoBind(this);
  }
  componentDidMount () {
    this.prepareTable(this.props.data);
    if (this.props.data.show_graph) {
      this.loadChart();
    }
  }
  componentWillReceiveProps(nextProps) {
    this.prepareTable(nextProps.data);
  }
  componentDidUpdate (prevProps) {
    // refreshes a chart right after render()
    // TODO: ideally this shouldn't refresh a chart if it hasn't changed
    if (this.props.data.show_graph) {
      this.loadChart();
    }
  }
  loadChart() {
    var canvas = ReactDOM.findDOMNode(this.refs.canvas);
    var opts = this.buildChartOptions();
    if (this.itemChart) {
      this.itemChart.destroy();
      this.itemChart = new Chart(canvas, opts);
    } else {
      this.itemChart = new Chart(canvas, opts);
    }
  }
  prepareTable(d) {
    var reportTable = [];
    if (d.percentages && d.responses && d.frequencies) {
      reportTable = _.zip(
          d.responseLabels || d.responses,
          d.frequencies,
          d.percentages,
        );
    }

    if (d.mean)
      reportTable = false;

    this.setState({reportTable: reportTable});
  }
  buildChartOptions () {
    var data = this.props.data;
    var chartType = this.props.style.report_type || 'bar';

    var maxPercentage = 100;
    var barPercentage = 0.5;
    var showLegend = false;

    // TODO: set as default globally in a higher level (PM)
    var colors = this.buildChartColors();

    var baseColor = colors[0];
    Chart.defaults.global.elements.rectangle.backgroundColor = baseColor;
    Chart.defaults.global.elements.line.borderColor = baseColor;
    Chart.defaults.global.elements.line.backgroundColor = 'rgba(255, 255, 255, 0.1)';
    Chart.defaults.global.elements.point.backgroundColor = baseColor;
    Chart.defaults.global.elements.point.radius = 4;
    Chart.defaults.global.elements.arc.backgroundColor = baseColor;
    Chart.defaults.global.maintainAspectRatio = false;

    if (chartType === 'donut') {
      chartType = 'pie';
    }

    if (chartType === 'area') {
      chartType = 'line';
    }

    if (chartType === 'horizontal') {
      chartType = 'horizontalBar';
    }

    if (chartType === 'vertical' || chartType === 'bar_chart') {
      chartType = 'bar';
    }

    var datasets = [];

    if (data.values != undefined) {
      data.responseLabels.forEach(function(r, i){
        data.responseLabels[i] = r.length > 25 ? r.substring(0,22) + '...' : r;
      });
      var allPercentages = [];
      data.values.forEach(function(val, i){
        var item = {};
        var choiceLabel = val[2] || val[0];
        item.label = choiceLabel.length > 20 ? choiceLabel.substring(0,17) + '...' : choiceLabel;
        item.data = val[1].percentages;
        allPercentages = [...new Set([...allPercentages ,...val[1].percentages])];
        item.backgroundColor = colors[i];
        datasets.push(item);
      });

      maxPercentage = Math.max.apply(Math, allPercentages);
      barPercentage = 0.9;
      showLegend = true;
    } else {
      maxPercentage = Math.max.apply(Math, data.percentages);
      datasets.push({data: data.percentages});
      if (data.responseLabels) {
        data.responseLabels.forEach(function(r, i){
          data.responseLabels[i] = r.length > 25 ? r.substring(0,22) + '...' : r;
        });
      }
      if (data.responses) {
        data.responses.forEach(function(r, i){
          data.responses[i] = r.length > 25 ? r.substring(0,22) + '...' : r;
        });
      }
    }

    maxPercentage = maxPercentage < 85 ? ((parseInt(maxPercentage/10, 10)+1)*10) : 100;
    var opts = {
      type: chartType,
      data: {
          labels: data.responseLabels || data.responses,
          datasets: datasets
      },
      options: {
        // events: [''],
        legend: {
          display: showLegend
        },
        animation: {
          duration: 500
        },
        scales: {
          xAxes: [{
            ticks: {
              autoSkip:false,
              beginAtZero: true,
              max: maxPercentage
            },
            barPercentage: barPercentage,
            // gridLines: {
            //   display: chartType == 'horizontalBar' ? true : false
            // }
          }],
          yAxes: [{
            ticks: {
              autoSkip:false,
              beginAtZero: true,
              max: maxPercentage
            },
            barPercentage: barPercentage,
            // gridLines: {
            //   display: chartType == 'horizontalBar' ? false : true
            // }
          }]
        },
      }
    };

    if (chartType === 'pie') {
      opts.options.legend.display = true;
      opts.data.datasets[0].backgroundColor = colors;
      opts.options.scales.xAxes = [];
      opts.options.scales.yAxes = [];

      if (this.props.style.report_type === 'donut') {
        opts.options.cutoutPercentage = 50;
      }
    }

    if (this.props.style.report_type === 'area') {
      opts.data.datasets[0].backgroundColor = colors[0];
    }

    return opts;
  }
  buildChartColors () {
    var colors = this.props.style.report_colors || [
      'rgba(52, 106, 200, 0.8)',
      'rgba(252, 74, 124, 0.8)',
      'rgba(250, 213, 99, 0.8)',
      'rgba(113, 230, 33, 0.8)',
      'rgba(78, 203, 255, 0.8)',
      'rgba(253, 190, 76, 0.8)',
      'rgba(77, 124, 244, 0.8)',
      'rgba(33, 231, 184, 0.8)'
    ];

    var c1 = colors.slice(0).map((c,i)=>{
      c = c.replace("1)", "0.75)");
      return c.replace("0.8", "0.5");
    });
    colors = colors.concat(c1);

    var c2 = colors.slice(0).map((c,i)=>{
      c = c.replace("1)", "0.5)");
      return c.replace("0.8", "0.25");
    });
    colors = colors.concat(c2);

    return colors;
  }
  render () {
    let p = this.props,
      d = p.data,
      r = p.row,
      _type = r.type,
      name = p.name;

    if (!_type) {
      console.error('No type given for row: ', p);
      return
{'Error displaying row: '}{p.kuid}
;
    }
    if (_type.select_one || _type.select_multiple) {
      _type = _.keys(_type)[0];
    }
    _type = JSON.stringify(_type);
    return (

        <bem.ReportView__itemHeading>

            {p.label}

          <bem.ReportView__headingMeta>

              {
                t('Type: ') + _type + t('. ')
              }

              {
                t('#1 out of #2 respondents answered this question. ')
                  .replace('#1', d.provided)
                  .replace('#2', d.total_count)
              }

              {
                t('(# were without data.)').replace('#', d.not_provided)
              }

          </bem.ReportView__headingMeta>
          {d.show_graph &&
            <button className="mdl-button mdl-button--icon report-button__question-settings"
                  onClick={this.props.triggerQuestionSettings}
                  data-question={name}
                  data-tip={t('Override Graph Style')}>

            </button>
          }
        </bem.ReportView__itemHeading>
        <bem.ReportView__itemContent>
          {d.show_graph &&
            <bem.ReportView__chart
                style={{width: this.props.style.graphWidth + 'px'}}>
              <canvas ref="canvas" />
            </bem.ReportView__chart>
          }
          {this.state.reportTable && ! d.values &&
            <ReportTable rows={this.state.reportTable} type='regular'/>
          }
          {d.values && d.values[0][1].percentages &&
            <ReportTable rows={d.values} responseLabels={d.responseLabels} type='disaggregated' />
          }
          {d.values && d.values[0][1].mean &&
            <ReportTable rows={d.values} type='numerical' />
          }
          {d.mean &&
            <ReportTable values={d} type='numerical'/>
          }
        </bem.ReportView__itemContent>

      );
  }
};

export default ReportViewItem;
<commit_msg>fix reports label issue<commit_after>import React from 'react';
import autoBind from 'react-autobind';
import ReactDOM from 'react-dom';
import _ from 'underscore';
import Chart from 'chart.js';
import bem from '../bem';
import $ from 'jquery';

import {t, assign} from '../utils';

class ReportTable extends React.Component {
  constructor(props) {
    super(props);
  }
  formatNumber(x) {
    if (isNaN(x))
      return x;
    return x.toFixed(2);
  }
  render () {
    let th = [''], rows = [];
    if (this.props.type === 'numerical') {
      th = [t('Mean'), t('Median'), t('Mode'), t('Standard deviation')];
      if (this.props.rows)
        th.unshift('');
      if (this.props.values)
        var v = this.props.values
      return (

              {th.map((t,i)=>{
                return ({t}	);
              })}

          {this.props.values &&

                {this.formatNumber(v.mean) || t('N/A')}
                {this.formatNumber(v.median) || t('N/A')}
                {this.formatNumber(v.mode) || t('N/A')}
                {this.formatNumber(v.stdev) || t('N/A')}

          }
          {this.props.rows &&

              {this.props.rows.map((r)=>{
                return (

                      {r[0]}
                      {this.formatNumber(r[1].mean) || t('N/A')}
                      {this.formatNumber(r[1].median) || t('N/A')}
                      {this.formatNumber(r[1].mode) || t('N/A')}
                      {this.formatNumber(r[1].stdev) || t('N/A')}

                  );
              })}

          }

      );
    }
    if (this.props.type === 'regular') {
      th = [t('Value'), t('Frequency'), t('Percentage')];
      rows = this.props.rows;
    } else {
      if (this.props.rows.length > 0) {
        if (this.props.responseLabels)
          th = th.concat(this.props.responseLabels);
        else
          th = th.concat(this.props.rows[0][1].responses);
        this.props.rows.map((row, i)=> {
          var rowitem = row[2] ? [row[2]] : [row[0]];
          rowitem = rowitem.concat(row[1].percentages);
          rows.push(rowitem);
        });
      }
    }

    if (rows.length === 0) {
      return false;
    }

    return (

              {th.map((t,i)=>{
                return ({t}	);
              })}

            {rows.map((row)=>{
              return (

                    {row.map((r,i)=>{
                      return ({r}	);
                    })}

                );
            })}

      )
  }
};

class ReportViewItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      reportTable: false
    };
    this.itemChart = false;
    autoBind(this);
  }
  componentDidMount () {
    this.prepareTable(this.props.data);
    if (this.props.data.show_graph) {
      this.loadChart();
    }
  }
  componentWillReceiveProps(nextProps) {
    this.prepareTable(nextProps.data);
  }
  componentDidUpdate (prevProps) {
    // refreshes a chart right after render()
    // TODO: ideally this shouldn't refresh a chart if it hasn't changed
    if (this.props.data.show_graph) {
      this.loadChart();
    }
  }
  loadChart() {
    var canvas = ReactDOM.findDOMNode(this.refs.canvas);
    var opts = this.buildChartOptions();
    if (this.itemChart) {
      this.itemChart.destroy();
      this.itemChart = new Chart(canvas, opts);
    } else {
      this.itemChart = new Chart(canvas, opts);
    }
  }
  prepareTable(d) {
    var reportTable = [];
    if (d.percentages && d.responses && d.frequencies) {
      reportTable = _.zip(
          d.responseLabels || d.responses,
          d.frequencies,
          d.percentages,
        );
    }

    if (d.mean)
      reportTable = false;

    this.setState({reportTable: reportTable});
  }
  buildChartOptions () {
    var data = this.props.data;
    var chartType = this.props.style.report_type || 'bar';

    var maxPercentage = 100;
    var barPercentage = 0.5;
    var showLegend = false;

    // TODO: set as default globally in a higher level (PM)
    var colors = this.buildChartColors();

    var baseColor = colors[0];
    Chart.defaults.global.elements.rectangle.backgroundColor = baseColor;
    Chart.defaults.global.elements.line.borderColor = baseColor;
    Chart.defaults.global.elements.line.backgroundColor = 'rgba(255, 255, 255, 0.1)';
    Chart.defaults.global.elements.point.backgroundColor = baseColor;
    Chart.defaults.global.elements.point.radius = 4;
    Chart.defaults.global.elements.arc.backgroundColor = baseColor;
    Chart.defaults.global.maintainAspectRatio = false;

    if (chartType === 'donut') {
      chartType = 'pie';
    }

    if (chartType === 'area') {
      chartType = 'line';
    }

    if (chartType === 'horizontal') {
      chartType = 'horizontalBar';
    }

    if (chartType === 'vertical' || chartType === 'bar_chart') {
      chartType = 'bar';
    }

    var datasets = [];

    if (data.values != undefined) {
      if (data.responseLabels) {
        data.responseLabels.forEach(function(r, i){
          data.responseLabels[i] = r.length > 25 ? r.substring(0,22) + '...' : r;
        });
      }
      var allPercentages = [];
      data.values.forEach(function(val, i){
        var item = {};
        var choiceLabel = val[2] || val[0];
        item.label = choiceLabel.length > 20 ? choiceLabel.substring(0,17) + '...' : choiceLabel;
        item.data = val[1].percentages;
        allPercentages = [...new Set([...allPercentages ,...val[1].percentages])];
        item.backgroundColor = colors[i];
        datasets.push(item);
      });

      maxPercentage = Math.max.apply(Math, allPercentages);
      barPercentage = 0.9;
      showLegend = true;
    } else {
      maxPercentage = Math.max.apply(Math, data.percentages);
      datasets.push({data: data.percentages});
      if (data.responseLabels) {
        data.responseLabels.forEach(function(r, i){
          data.responseLabels[i] = r.length > 25 ? r.substring(0,22) + '...' : r;
        });
      }
      if (data.responses) {
        data.responses.forEach(function(r, i){
          data.responses[i] = r.length > 25 ? r.substring(0,22) + '...' : r;
        });
      }
    }

    maxPercentage = maxPercentage < 85 ? ((parseInt(maxPercentage/10, 10)+1)*10) : 100;
    var opts = {
      type: chartType,
      data: {
          labels: data.responseLabels || data.responses,
          datasets: datasets
      },
      options: {
        // events: [''],
        legend: {
          display: showLegend
        },
        animation: {
          duration: 500
        },
        scales: {
          xAxes: [{
            ticks: {
              autoSkip:false,
              beginAtZero: true,
              max: maxPercentage
            },
            barPercentage: barPercentage,
            // gridLines: {
            //   display: chartType == 'horizontalBar' ? true : false
            // }
          }],
          yAxes: [{
            ticks: {
              autoSkip:false,
              beginAtZero: true,
              max: maxPercentage
            },
            barPercentage: barPercentage,
            // gridLines: {
            //   display: chartType == 'horizontalBar' ? false : true
            // }
          }]
        },
      }
    };

    if (chartType === 'pie') {
      opts.options.legend.display = true;
      opts.data.datasets[0].backgroundColor = colors;
      opts.options.scales.xAxes = [];
      opts.options.scales.yAxes = [];

      if (this.props.style.report_type === 'donut') {
        opts.options.cutoutPercentage = 50;
      }
    }

    if (this.props.style.report_type === 'area') {
      opts.data.datasets[0].backgroundColor = colors[0];
    }

    return opts;
  }
  buildChartColors () {
    var colors = this.props.style.report_colors || [
      'rgba(52, 106, 200, 0.8)',
      'rgba(252, 74, 124, 0.8)',
      'rgba(250, 213, 99, 0.8)',
      'rgba(113, 230, 33, 0.8)',
      'rgba(78, 203, 255, 0.8)',
      'rgba(253, 190, 76, 0.8)',
      'rgba(77, 124, 244, 0.8)',
      'rgba(33, 231, 184, 0.8)'
    ];

    var c1 = colors.slice(0).map((c,i)=>{
      c = c.replace("1)", "0.75)");
      return c.replace("0.8", "0.5");
    });
    colors = colors.concat(c1);

    var c2 = colors.slice(0).map((c,i)=>{
      c = c.replace("1)", "0.5)");
      return c.replace("0.8", "0.25");
    });
    colors = colors.concat(c2);

    return colors;
  }
  render () {
    let p = this.props,
      d = p.data,
      r = p.row,
      _type = r.type,
      name = p.name;

    if (!_type) {
      console.error('No type given for row: ', p);
      return
{'Error displaying row: '}{p.kuid}
;
    }
    if (_type.select_one || _type.select_multiple) {
      _type = _.keys(_type)[0];
    }
    _type = JSON.stringify(_type);
    return (

        <bem.ReportView__itemHeading>

            {p.label}

          <bem.ReportView__headingMeta>

              {
                t('Type: ') + _type + t('. ')
              }

              {
                t('#1 out of #2 respondents answered this question. ')
                  .replace('#1', d.provided)
                  .replace('#2', d.total_count)
              }

              {
                t('(# were without data.)').replace('#', d.not_provided)
              }

          </bem.ReportView__headingMeta>
          {d.show_graph &&
            <button className="mdl-button mdl-button--icon report-button__question-settings"
                  onClick={this.props.triggerQuestionSettings}
                  data-question={name}
                  data-tip={t('Override Graph Style')}>

            </button>
          }
        </bem.ReportView__itemHeading>
        <bem.ReportView__itemContent>
          {d.show_graph &&
            <bem.ReportView__chart
                style={{width: this.props.style.graphWidth + 'px'}}>
              <canvas ref="canvas" />
            </bem.ReportView__chart>
          }
          {this.state.reportTable && ! d.values &&
            <ReportTable rows={this.state.reportTable} type='regular'/>
          }
          {d.values && d.values[0][1].percentages &&
            <ReportTable rows={d.values} responseLabels={d.responseLabels} type='disaggregated' />
          }
          {d.values && d.values[0][1].mean &&
            <ReportTable rows={d.values} type='numerical' />
          }
          {d.mean &&
            <ReportTable values={d} type='numerical'/>
          }
        </bem.ReportView__itemContent>

      );
  }
};

export default ReportViewItem;
<|endoftext|>


<commit_before>Template.accordion.onRendered(function() {
    // set template var into session
    Session.set('template', this.data.template);

    // activate accordion
    $('.ui.accordion').accordion();
});

Template.accordion.helpers({
    template: function () {
        return Session.get('template');
    }
});
<commit_msg>using reactivevar for template name<commit_after>Template.accordion.onCreated(function () {
    this.templateName = new ReactiveVar();
});

Template.accordion.onRendered(function() {
    // set template var
    this.templateName.set(this.data.template);

    // activate accordion
    $('.ui.accordion').accordion();
});

Template.accordion.helpers({
    template: function () {
        return Template.instance().templateName.get();
    }
});
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();

// Load Artist Controller to have access to CRUD methods
var artistCtrl = require('./Controllers/ArtistController');

var crudCtrl = require('../Core/Controllers/CRUDController');
var artistCtrl = new crudCtrl('Music/Models/Artist');

/* LIST */
router.get('/artist/',       artistCtrl.list);

/* GET */
router.get('/artist/:id',    artistCtrl.get);

/* CREATE */
router.post('/artist/',      artistCtrl.create);

/* UPDATE */
router.put('/artist/:id',    artistCtrl.update);

/* DELETE */
router.delete('/artist/:id', artistCtrl.delete);

module.exports = router;
<commit_msg>use new crud controller<commit_after>var express = require('express');
var router = express.Router();

// Load Artist Controller to have access to CRUD methods
/*var artistCtrl = require('./Controllers/ArtistController');*/

var CRUDController = require('../Core/Controllers/CRUDController');
var artistCtrl = new CRUDController('Music/Models/Artist');

/* LIST */
router.get('/artist/',       artistCtrl.list.bind(artistCtrl));

/* GET */
router.get('/artist/:id',    artistCtrl.get.bind(artistCtrl));

/* CREATE */
router.post('/artist/',      artistCtrl.create.bind(artistCtrl));

/* UPDATE */
router.put('/artist/:id',    artistCtrl.update.bind(artistCtrl));

/* DELETE */
router.delete('/artist/:id', artistCtrl.delete.bind(artistCtrl));

module.exports = router;
<|endoftext|>


<commit_before>// This file is part of meshoptimizer library and is distributed under the terms of MIT License.
// Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)

// This is the reference decoder implementation by Jasper St. Pierre.
// It follows the decoder interface and should be a drop-in replacement for the actual decoder from meshopt_decoder.js
// It is provided for educational value and is not recommended for use in production because it's not performance-optimized.

const MeshoptDecoder = {};
MeshoptDecoder.supported = true;
MeshoptDecoder.ready = Promise.resolve();

function assert(cond) {
    if (!cond) {
        throw new Error("Assertion failed");
    }
}

function dezig(v) {
    return ((v & 1) !== 0) ? ~(v >>> 1) : v >>> 1;
}

function copysign(mag, sign) {
    return Math.abs(mag) * Math.sign(sign);
}

MeshoptDecoder.decodeVertexBuffer = (target, elementCount, byteStride, source, filter) => {
    assert(source[0] === 0xA0);

    const maxBlockElements = Math.min((0x2000 / byteStride) & ~0x000F, 0x100);

    const deltas = new Uint8Array(0x10);

    const tailDataOffs = source.length - byteStride;

    // what deltas are stored relative to
    const tempData = source.slice(tailDataOffs, tailDataOffs + byteStride);

    let srcOffs = 0x01;

    // Attribute Blocks
    for (let dstElemBase = 0; dstElemBase < elementCount; dstElemBase += maxBlockElements) {
        const attrBlockElementCount = Math.min(elementCount - dstElemBase, maxBlockElements);
        const groupCount = ((attrBlockElementCount + 0x0F) & ~0x0F) >>> 4;
        const headerByteCount = ((groupCount + 0x03) & ~0x03) >>> 2;

        // Data blocks
        for (let byte = 0; byte < byteStride; byte++) {
            let headerBitsOffs = srcOffs;

            srcOffs += headerByteCount;
            for (let group = 0; group < groupCount; group++) {
                const mode = (source[headerBitsOffs] >>> ((group & 0x03) << 1)) & 0x03;
                if ((group & 0x03) === 0x03)
                    headerBitsOffs++;

                const dstElemGroup = dstElemBase + (group << 4);

                if (mode === 0) {
                    // bits 0: All 16 byte deltas are 0; the size of the encoded block is 0 bytes
                    deltas.fill(0x00);
                } else if (mode === 1) {
                    // bits 1: Deltas are using 2-bit sentinel encoding; the size of the encoded block is [4..20] bytes
                    const srcBase = srcOffs;
                    srcOffs += 0x04;
                    for (let m = 0; m < 0x10; m++) {
                        // 0 = >>> 6, 1 = >>> 4, 2 = >>> 2, 3 = >>> 0
                        const shift = (6 - ((m & 0x03) << 1));
                        let delta = (source[srcBase + (m >>> 2)] >>> shift) & 0x03;
                        if (delta === 3)
                            delta = source[srcOffs++];
                        deltas[m] = delta;
                    }
                } else if (mode === 2) {
                    // bits 2: Deltas are using 4-bit sentinel encoding; the size of the encoded block is [8..24] bytes
                    const srcBase = srcOffs;
                    srcOffs += 0x08;
                    for (let m = 0; m < 0x10; m++) {
                        // 0 = >>> 6, 1 = >>> 4, 2 = >>> 2, 3 = >>> 0
                        const shift = (m & 0x01) ? 0 : 4;
                        let delta = (source[srcBase + (m >>> 1)] >>> shift) & 0x0f;
                        if (delta === 0xf)
                            delta = source[srcOffs++];
                        deltas[m] = delta;
                    }
                } else {
                    // bits 3: All 16 byte deltas are stored verbatim; the size of the encoded block is 16 bytes
                    deltas.set(source.subarray(srcOffs, srcOffs + 0x10));
                    srcOffs += 0x10;
                }

                // go through and apply deltas to data
                for (let m = 0; m < 0x10; m++) {
                    const dstElem = dstElemGroup + m;
                    if (dstElem >= elementCount)
                        break;

                    const delta = dezig(deltas[m]);
                    const newValue = tempData[byte] + delta;
                    const dstOffs = dstElem * byteStride + byte;
                    target[dstOffs] = newValue;
                    tempData[byte] = newValue;
                }
            }
        }
    }

    // Filters - only applied if filter isn't undefined or NONE
    if (filter === 'OCTAHEDRAL') {
        assert(byteStride === 4 || byteStride === 8);
        assert(elementCount % 4 === 0);

        let values, intmax;
        if (byteStride === 4) {
            values = new Int8Array(target.buffer);
            intmax = 127;
        } else if (byteStride === 8) {
            values = new Int16Array(target.buffer);
            intmax = 32767;
        }

        for (let i = 0; i < 4 * elementCount; i += 4) {
            let x = values[i + 0], y = values[i + 1], one = values[i + 2];
            x /= one;
            y /= one;
            let z = 1.0 - Math.abs(x) - Math.abs(y);
            const t = Math.min(z, 0.0);
            x -= copysign(t, x);
            y -= copysign(t, y);
            const h = intmax / Math.hypot(x, y, z);
            values[i + 0] = Math.round(x * h);
            values[i + 1] = Math.round(y * h);
            values[i + 2] = Math.round(z * h);
            // keep values[i + 3] as is
        }
    } else if (filter === 'QUATERNION') {
        assert(byteStride === 8);
        assert(elementCount % 4 === 0);

        const values = new Int16Array(target.buffer);

        for (let i = 0; i < 4 * elementCount; i += 4) {
            const iw = values[i + 3];
            const maxc = iw & 0x03;
            const s = Math.SQRT1_2 / (iw | 0x03);
            let x = values[i + 0] * s;
            let y = values[i + 1] * s;
            let z = values[i + 2] * s;
            let w = Math.sqrt(Math.max(0.0, 1.0 - x**2 - y**2 - z**2));
            values[i + (maxc + 1) % 4] = Math.round(x * 32767);
            values[i + (maxc + 2) % 4] = Math.round(y * 32767);
            values[i + (maxc + 3) % 4] = Math.round(z * 32767);
            values[i + (maxc + 0) % 4] = Math.round(w * 32767);
        }
    } else if (filter === 'EXPONENTIAL') {
        assert(byteStride % 4 === 0);

        const input = new Int32Array(target.buffer);
        const output = new Float32Array(target.buffer);
        for (let i = 0; i < elementCount * (byteStride / 4); i++) {
            const v = input[i];
            const e = v >> 24;
            const m = (v << 8) >> 8;
            output[i] = 2.0**e * m;
        }
    }
};

function pushfifo(fifo, n) {
    for (let i = fifo.length - 1; i > 0; i--)
        fifo[i] = fifo[i - 1];
    fifo[0] = n;
}

MeshoptDecoder.decodeIndexBuffer = (target, count, byteStride, source) => {
    assert(source[0] === 0xE1);
    assert(count % 3 === 0);
    assert(byteStride === 2 || byteStride === 4);

    let dst;
    if (byteStride === 2)
        dst = new Uint16Array(target.buffer);
    else
        dst = new Uint32Array(target.buffer);

    const triCount = count / 3;

    let codeOffs = 0x01;
    let dataOffs = codeOffs + triCount;
    let codeauxOffs = source.length - 0x10;

    function readLEB128() {
        let n = 0;
        for (let i = 0; ; i += 7) {
            const b = source[dataOffs++];
            n |= (b & 0x7F) << i;

            if (b < 0x80)
                return n;
        }
    }

    let next = 0, last = 0;
    const edgefifo = new Uint32Array(32);
    const vertexfifo = new Uint32Array(16);

    function decodeIndex(v) {
        return (last += dezig(v));
    }

    let dstOffs = 0;
    for (let i = 0; i < triCount; i++) {
        const code = source[codeOffs++];
        const b0 = code >>> 4, b1 = code & 0x0F;

        if (b0 < 0x0F) {
            const a = edgefifo[(b0 << 1) + 0], b = edgefifo[(b0 << 1) + 1];
            let c = -1;

            if (b1 === 0x00) {
                c = next++;
                pushfifo(vertexfifo, c);
            } else if (b1 < 0x0D) {
                c = vertexfifo[b1];
            } else if (b1 === 0x0D) {
                c = --last;
                pushfifo(vertexfifo, c);
            } else if (b1 === 0x0E) {
                c = ++last;
                pushfifo(vertexfifo, c);
            } else if (b1 === 0x0F) {
                const v = readLEB128();
                c = decodeIndex(v);
                pushfifo(vertexfifo, c);
            }

            // fifo pushes happen backwards
            pushfifo(edgefifo, b); pushfifo(edgefifo, c);
            pushfifo(edgefifo, c); pushfifo(edgefifo, a);

            dst[dstOffs++] = a;
            dst[dstOffs++] = b;
            dst[dstOffs++] = c;
        } else /* if (b0 === 0x0F) */ {
            let a = -1, b = -1, c = -1;

            if (b1 < 0x0E) {
                const e = source[codeauxOffs + b1];
                const z = e >>> 4, w = e & 0x0F;
                a = next++;

                if (z === 0x00)
                    b = next++;
                else
                    b = vertexfifo[z - 1];

                if (w === 0x00)
                    c = next++;
                else
                    c = vertexfifo[w - 1];

                pushfifo(vertexfifo, a);
                if (z === 0x00)
                    pushfifo(vertexfifo, b);
                if (w === 0x00)
                    pushfifo(vertexfifo, c);
            } else {
                const e = source[dataOffs++];
                if (e === 0x00)
                    next = 0;

                const z = e >>> 4, w = e & 0x0F;

                if (b1 === 0x0E)
                    a = next++;
                else
                    a = decodeIndex(readLEB128());

                if (z === 0x00)
                    b = next++;
                else if (z === 0x0F)
                    b = decodeIndex(readLEB128());
                else
                    b = vertexfifo[z - 1];

                if (w === 0x00)
                    c = next++;
                else if (w === 0x0F)
                    c = decodeIndex(readLEB128());
                else
                    c = vertexfifo[w - 1];

                pushfifo(vertexfifo, a);
                if (z === 0x00 || z === 0x0F)
                    pushfifo(vertexfifo, b);
                if (w === 0x00 || w === 0x0F)
                    pushfifo(vertexfifo, c);
            }

            pushfifo(edgefifo, a); pushfifo(edgefifo, b);
            pushfifo(edgefifo, b); pushfifo(edgefifo, c);
            pushfifo(edgefifo, c); pushfifo(edgefifo, a);

            dst[dstOffs++] = a;
            dst[dstOffs++] = b;
            dst[dstOffs++] = c;
        }
    }
};

MeshoptDecoder.decodeIndexSequence = (target, count, byteStride, source) => {
    assert(source[0] === 0xD1);
    assert(byteStride === 2 || byteStride === 4);

    let dst;
    if (byteStride === 2)
        dst = new Uint16Array(target.buffer);
    else
        dst = new Uint32Array(target.buffer);

    let dataOffs = 0x01;

    function readLEB128() {
        let n = 0;
        for (let i = 0; ; i += 7) {
            const b = source[dataOffs++];
            n |= (b & 0x7F) << i;

            if (b < 0x80)
                return n;
        }
    }

    const last = new Uint32Array(2);

    for (let i = 0; i < count; i++) {
        const v = readLEB128();
        const b = (v & 0x01);
        const delta = dezig(v >>> 1);
        dst[i] = (last[b] += delta);
    }
};

MeshoptDecoder.decodeGltfBuffer = (target, count, size, source, mode, filter) => {
    var table = {
        ATTRIBUTES: MeshoptDecoder.decodeVertexBuffer,
        TRIANGLES: MeshoptDecoder.decodeIndexBuffer,
        INDICES: MeshoptDecoder.decodeIndexSequence,
    };
    assert(table[mode] !== undefined);
    table[mode](target, count, size, source, filter);
};

// node.js interface:
// for (let k in MeshoptDecoder) { exports[k] = MeshoptDecoder[k]; }

export { MeshoptDecoder };
<commit_msg>Remove incorrect assertions<commit_after>// This file is part of meshoptimizer library and is distributed under the terms of MIT License.
// Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)

// This is the reference decoder implementation by Jasper St. Pierre.
// It follows the decoder interface and should be a drop-in replacement for the actual decoder from meshopt_decoder.js
// It is provided for educational value and is not recommended for use in production because it's not performance-optimized.

const MeshoptDecoder = {};
MeshoptDecoder.supported = true;
MeshoptDecoder.ready = Promise.resolve();

function assert(cond) {
    if (!cond) {
        throw new Error("Assertion failed");
    }
}

function dezig(v) {
    return ((v & 1) !== 0) ? ~(v >>> 1) : v >>> 1;
}

function copysign(mag, sign) {
    return Math.abs(mag) * Math.sign(sign);
}

MeshoptDecoder.decodeVertexBuffer = (target, elementCount, byteStride, source, filter) => {
    assert(source[0] === 0xA0);

    const maxBlockElements = Math.min((0x2000 / byteStride) & ~0x000F, 0x100);

    const deltas = new Uint8Array(0x10);

    const tailDataOffs = source.length - byteStride;

    // what deltas are stored relative to
    const tempData = source.slice(tailDataOffs, tailDataOffs + byteStride);

    let srcOffs = 0x01;

    // Attribute Blocks
    for (let dstElemBase = 0; dstElemBase < elementCount; dstElemBase += maxBlockElements) {
        const attrBlockElementCount = Math.min(elementCount - dstElemBase, maxBlockElements);
        const groupCount = ((attrBlockElementCount + 0x0F) & ~0x0F) >>> 4;
        const headerByteCount = ((groupCount + 0x03) & ~0x03) >>> 2;

        // Data blocks
        for (let byte = 0; byte < byteStride; byte++) {
            let headerBitsOffs = srcOffs;

            srcOffs += headerByteCount;
            for (let group = 0; group < groupCount; group++) {
                const mode = (source[headerBitsOffs] >>> ((group & 0x03) << 1)) & 0x03;
                if ((group & 0x03) === 0x03)
                    headerBitsOffs++;

                const dstElemGroup = dstElemBase + (group << 4);

                if (mode === 0) {
                    // bits 0: All 16 byte deltas are 0; the size of the encoded block is 0 bytes
                    deltas.fill(0x00);
                } else if (mode === 1) {
                    // bits 1: Deltas are using 2-bit sentinel encoding; the size of the encoded block is [4..20] bytes
                    const srcBase = srcOffs;
                    srcOffs += 0x04;
                    for (let m = 0; m < 0x10; m++) {
                        // 0 = >>> 6, 1 = >>> 4, 2 = >>> 2, 3 = >>> 0
                        const shift = (6 - ((m & 0x03) << 1));
                        let delta = (source[srcBase + (m >>> 2)] >>> shift) & 0x03;
                        if (delta === 3)
                            delta = source[srcOffs++];
                        deltas[m] = delta;
                    }
                } else if (mode === 2) {
                    // bits 2: Deltas are using 4-bit sentinel encoding; the size of the encoded block is [8..24] bytes
                    const srcBase = srcOffs;
                    srcOffs += 0x08;
                    for (let m = 0; m < 0x10; m++) {
                        // 0 = >>> 6, 1 = >>> 4, 2 = >>> 2, 3 = >>> 0
                        const shift = (m & 0x01) ? 0 : 4;
                        let delta = (source[srcBase + (m >>> 1)] >>> shift) & 0x0f;
                        if (delta === 0xf)
                            delta = source[srcOffs++];
                        deltas[m] = delta;
                    }
                } else {
                    // bits 3: All 16 byte deltas are stored verbatim; the size of the encoded block is 16 bytes
                    deltas.set(source.subarray(srcOffs, srcOffs + 0x10));
                    srcOffs += 0x10;
                }

                // go through and apply deltas to data
                for (let m = 0; m < 0x10; m++) {
                    const dstElem = dstElemGroup + m;
                    if (dstElem >= elementCount)
                        break;

                    const delta = dezig(deltas[m]);
                    const newValue = tempData[byte] + delta;
                    const dstOffs = dstElem * byteStride + byte;
                    target[dstOffs] = newValue;
                    tempData[byte] = newValue;
                }
            }
        }
    }

    // Filters - only applied if filter isn't undefined or NONE
    if (filter === 'OCTAHEDRAL') {
        assert(byteStride === 4 || byteStride === 8);

        let values, intmax;
        if (byteStride === 4) {
            values = new Int8Array(target.buffer);
            intmax = 127;
        } else if (byteStride === 8) {
            values = new Int16Array(target.buffer);
            intmax = 32767;
        }

        for (let i = 0; i < 4 * elementCount; i += 4) {
            let x = values[i + 0], y = values[i + 1], one = values[i + 2];
            x /= one;
            y /= one;
            let z = 1.0 - Math.abs(x) - Math.abs(y);
            const t = Math.min(z, 0.0);
            x -= copysign(t, x);
            y -= copysign(t, y);
            const h = intmax / Math.hypot(x, y, z);
            values[i + 0] = Math.round(x * h);
            values[i + 1] = Math.round(y * h);
            values[i + 2] = Math.round(z * h);
            // keep values[i + 3] as is
        }
    } else if (filter === 'QUATERNION') {
        assert(byteStride === 8);

        const values = new Int16Array(target.buffer);

        for (let i = 0; i < 4 * elementCount; i += 4) {
            const iw = values[i + 3];
            const maxc = iw & 0x03;
            const s = Math.SQRT1_2 / (iw | 0x03);
            let x = values[i + 0] * s;
            let y = values[i + 1] * s;
            let z = values[i + 2] * s;
            let w = Math.sqrt(Math.max(0.0, 1.0 - x**2 - y**2 - z**2));
            values[i + (maxc + 1) % 4] = Math.round(x * 32767);
            values[i + (maxc + 2) % 4] = Math.round(y * 32767);
            values[i + (maxc + 3) % 4] = Math.round(z * 32767);
            values[i + (maxc + 0) % 4] = Math.round(w * 32767);
        }
    } else if (filter === 'EXPONENTIAL') {
        assert(byteStride % 4 === 0);

        const input = new Int32Array(target.buffer);
        const output = new Float32Array(target.buffer);
        for (let i = 0; i < elementCount * (byteStride / 4); i++) {
            const v = input[i];
            const e = v >> 24;
            const m = (v << 8) >> 8;
            output[i] = 2.0**e * m;
        }
    }
};

function pushfifo(fifo, n) {
    for (let i = fifo.length - 1; i > 0; i--)
        fifo[i] = fifo[i - 1];
    fifo[0] = n;
}

MeshoptDecoder.decodeIndexBuffer = (target, count, byteStride, source) => {
    assert(source[0] === 0xE1);
    assert(count % 3 === 0);
    assert(byteStride === 2 || byteStride === 4);

    let dst;
    if (byteStride === 2)
        dst = new Uint16Array(target.buffer);
    else
        dst = new Uint32Array(target.buffer);

    const triCount = count / 3;

    let codeOffs = 0x01;
    let dataOffs = codeOffs + triCount;
    let codeauxOffs = source.length - 0x10;

    function readLEB128() {
        let n = 0;
        for (let i = 0; ; i += 7) {
            const b = source[dataOffs++];
            n |= (b & 0x7F) << i;

            if (b < 0x80)
                return n;
        }
    }

    let next = 0, last = 0;
    const edgefifo = new Uint32Array(32);
    const vertexfifo = new Uint32Array(16);

    function decodeIndex(v) {
        return (last += dezig(v));
    }

    let dstOffs = 0;
    for (let i = 0; i < triCount; i++) {
        const code = source[codeOffs++];
        const b0 = code >>> 4, b1 = code & 0x0F;

        if (b0 < 0x0F) {
            const a = edgefifo[(b0 << 1) + 0], b = edgefifo[(b0 << 1) + 1];
            let c = -1;

            if (b1 === 0x00) {
                c = next++;
                pushfifo(vertexfifo, c);
            } else if (b1 < 0x0D) {
                c = vertexfifo[b1];
            } else if (b1 === 0x0D) {
                c = --last;
                pushfifo(vertexfifo, c);
            } else if (b1 === 0x0E) {
                c = ++last;
                pushfifo(vertexfifo, c);
            } else if (b1 === 0x0F) {
                const v = readLEB128();
                c = decodeIndex(v);
                pushfifo(vertexfifo, c);
            }

            // fifo pushes happen backwards
            pushfifo(edgefifo, b); pushfifo(edgefifo, c);
            pushfifo(edgefifo, c); pushfifo(edgefifo, a);

            dst[dstOffs++] = a;
            dst[dstOffs++] = b;
            dst[dstOffs++] = c;
        } else /* if (b0 === 0x0F) */ {
            let a = -1, b = -1, c = -1;

            if (b1 < 0x0E) {
                const e = source[codeauxOffs + b1];
                const z = e >>> 4, w = e & 0x0F;
                a = next++;

                if (z === 0x00)
                    b = next++;
                else
                    b = vertexfifo[z - 1];

                if (w === 0x00)
                    c = next++;
                else
                    c = vertexfifo[w - 1];

                pushfifo(vertexfifo, a);
                if (z === 0x00)
                    pushfifo(vertexfifo, b);
                if (w === 0x00)
                    pushfifo(vertexfifo, c);
            } else {
                const e = source[dataOffs++];
                if (e === 0x00)
                    next = 0;

                const z = e >>> 4, w = e & 0x0F;

                if (b1 === 0x0E)
                    a = next++;
                else
                    a = decodeIndex(readLEB128());

                if (z === 0x00)
                    b = next++;
                else if (z === 0x0F)
                    b = decodeIndex(readLEB128());
                else
                    b = vertexfifo[z - 1];

                if (w === 0x00)
                    c = next++;
                else if (w === 0x0F)
                    c = decodeIndex(readLEB128());
                else
                    c = vertexfifo[w - 1];

                pushfifo(vertexfifo, a);
                if (z === 0x00 || z === 0x0F)
                    pushfifo(vertexfifo, b);
                if (w === 0x00 || w === 0x0F)
                    pushfifo(vertexfifo, c);
            }

            pushfifo(edgefifo, a); pushfifo(edgefifo, b);
            pushfifo(edgefifo, b); pushfifo(edgefifo, c);
            pushfifo(edgefifo, c); pushfifo(edgefifo, a);

            dst[dstOffs++] = a;
            dst[dstOffs++] = b;
            dst[dstOffs++] = c;
        }
    }
};

MeshoptDecoder.decodeIndexSequence = (target, count, byteStride, source) => {
    assert(source[0] === 0xD1);
    assert(byteStride === 2 || byteStride === 4);

    let dst;
    if (byteStride === 2)
        dst = new Uint16Array(target.buffer);
    else
        dst = new Uint32Array(target.buffer);

    let dataOffs = 0x01;

    function readLEB128() {
        let n = 0;
        for (let i = 0; ; i += 7) {
            const b = source[dataOffs++];
            n |= (b & 0x7F) << i;

            if (b < 0x80)
                return n;
        }
    }

    const last = new Uint32Array(2);

    for (let i = 0; i < count; i++) {
        const v = readLEB128();
        const b = (v & 0x01);
        const delta = dezig(v >>> 1);
        dst[i] = (last[b] += delta);
    }
};

MeshoptDecoder.decodeGltfBuffer = (target, count, size, source, mode, filter) => {
    var table = {
        ATTRIBUTES: MeshoptDecoder.decodeVertexBuffer,
        TRIANGLES: MeshoptDecoder.decodeIndexBuffer,
        INDICES: MeshoptDecoder.decodeIndexSequence,
    };
    assert(table[mode] !== undefined);
    table[mode](target, count, size, source, filter);
};

// node.js interface:
// for (let k in MeshoptDecoder) { exports[k] = MeshoptDecoder[k]; }

export { MeshoptDecoder };
<|endoftext|>


<commit_before>ds.models.cell = function(data) {
  "use strict";

  var self = limivorous.observable()
                       .extend(ds.models.item, {item_type: 'cell'})
                       .extend(ds.models.container)
                       .property('span')
                       .property('offset')
                       .property('align')
                       .build()

  if (data) {
    self.span = data.span || self.span;
    self.offset = data.offset;
    self.align = data.align;
  }
  ds.models.item.init(self, data)
  ds.models.container.init(self, data)

  self.interactive_properties = function() {
    return [
      ds.models.property({name: 'style'}),
      ds.models.property({name: 'css_class'}),
      ds.models.property({name: 'height'}),
      ds.models.property({name: 'span'}),
      ds.models.property({name: 'offset'}),
      ds.models.property({name: 'align'})
    ]
  }

  self.toJSON = function() {
    var data = ds.models.container.json(self, ds.models.item.json(self))
    if (self.span)
      data.span = self.span
    if (self.offset)
      data.offset = self.offset
    if (self.align)
      data.align = self.align
    return data
  }

  return self;
};
<commit_msg>Default cells to span3<commit_after>ds.models.cell = function(data) {
  "use strict";

  var self = limivorous.observable()
                       .extend(ds.models.item, {item_type: 'cell'})
                       .extend(ds.models.container)
                       .property('span', { init: 3 })
                       .property('offset')
                       .property('align')
                       .build()

  if (data) {
    self.span = data.span || self.span;
    self.offset = data.offset;
    self.align = data.align;
  }
  ds.models.item.init(self, data)
  ds.models.container.init(self, data)

  self.interactive_properties = function() {
    return [
      ds.models.property({name: 'style'}),
      ds.models.property({name: 'css_class'}),
      ds.models.property({name: 'height'}),
      ds.models.property({name: 'span'}),
      ds.models.property({name: 'offset'}),
      ds.models.property({name: 'align'})
    ]
  }

  self.toJSON = function() {
    var data = ds.models.container.json(self, ds.models.item.json(self))
    if (self.span)
      data.span = self.span
    if (self.offset)
      data.offset = self.offset
    if (self.align)
      data.align = self.align
    return data
  }

  return self;
};
<|endoftext|>


<commit_before>var RootView = require("../views/root");
var Backbone = require("backbone");
var ConversationModel = require("../models/conversation");
var ParticipantModel = require("../models/participant");
var bbFetch = require("../net/bbFetch");
var ConversationsCollection = require("../collections/conversations");
var InboxView = require("../views/inbox");
var HomepageView = require("../views/homepage");
var CreateConversationFormView = require("../views/create-conversation-form");
var ConversationDetailsView = require("../views/conversation-details");
var ConversationGatekeeperView = require("../views/conversationGatekeeperView");
var ConversationGatekeeperViewCreateUser = require("../views/conversationGatekeeperViewCreateUser");
var ConversationView = require("../views/conversation-view");
var CreateUserFormView = require("../views/create-user-form");
var LoginFormView = require("../views/login-form");
var LandingPageView = require("../views/landing-page");
var PasswordResetView = require("../views/passwordResetView");
var PasswordResetInitView = require("../views/passwordResetInitView");
var ShareLinkView = require("../views/share-link-view");
var PolisStorage = require("../util/polisStorage");
var $ = require("jquery");

function authenticated() {
  return PolisStorage.uid();
}

var polisRouter = Backbone.Router.extend({
  routes: {
    "homepage": "homepageView",
    "conversation/create": "createConversation",
    "conversation/view/:id(/:zinvite)": "conversationView",
    "user/create": "createUser",
    "user/login":"login",
    "settings": "deregister",
    "inbox(/:filter)": "inbox",
    "pwresetinit" : "pwResetInit",
    "": "landingPageView"
    // see others in the initialize method
  },
  initialize: function(options) {
    this.route(/([0-9]+)/, "conversationView");  // zid
    this.route(/([0-9]+)\/(.*)/, "conversationView"); // zid/zinvite
    this.route(/^ot\/([0-9]+)\/(.*)/, "conversationViewWithSuzinvite"); // zid/suzinvite
    this.route(/^pwreset\/(.*)/, "pwReset");
    this.route(/^demo\/(.*)/, "demoConversation");
  },
  bail: function() {
    this.navigate("/", {trigger: true});
  },
  landingPageView: function() {
    if (!authenticated()) {
      this.navigate("user/create", {trigger: true});
      // RootView.getInstance().setView(new LandingPageView());
      // RootView.getInstance().setView(new CreateUserFormView({
      //   model : new Backbone.Model({
      //     // zinvite: zinvite,
      //     create: true
      //   })
      // }));
    } else {
      // this.inbox();
      this.navigate("inbox", {trigger: true});
    }
  },
  deregister: function() {
    window.deregister();
  },
  gotoShareView: function(conversationModel) {
    var that = this;
    var shareLinkView = new ShareLinkView({
      model: conversationModel
    });
    shareLinkView.on("done", function() {
      var zid = conversationModel.get("zid");
      var zinvite = conversationModel.get("zinvites")[0];
      var path = zid + (zinvite ? "/" + zinvite : "");
      that.navigate(path, {trigger: true});
    });
    RootView.getInstance().setView(shareLinkView);
  },
  inbox: function(filter){
    if (!authenticated()) { return this.bail(); }
    // TODO add to inboxview init
    // conversationsCollection.fetch({
    //     data: $.param({
    //         is_active: false,
    //         is_draft: false,
    //     }),
    //     processData: true,
    // });
    var filterAttrs = {};
    if (filter) {
      switch(filter) {
        case "closed":
          filterAttrs.is_active = false;
          filterAttrs.is_draft = false;
        break;
        case "active":
          filterAttrs.is_active = true;
        break;
        default:
          filterAttrs.is_active = true;
        break;
      }
    }
    var conversationsCollection = new ConversationsCollection();
    // Let the InboxView filter the conversationsCollection.
    var inboxView = new InboxView($.extend(filterAttrs, {
      collection: conversationsCollection
    }));
    RootView.getInstance().setView(inboxView);
  },
  homepageView: function(){
    var homepage = new HomepageView();
    RootView.getInstance().setView(homepage);
  },
  createConversation: function(){
    if (!authenticated()) { return this.bail(); }
    function onFail(err) {
      alert("failed to create new conversation");
      console.dir(err);
    }
    var that = this;
    conversationsCollection = new ConversationsCollection();

    var model = new ConversationModel({
      is_draft: true,
      is_active: true // TODO think
    });

    model.save().then(function(data) {
      model.set("zid", data.zid);

      var ptpt = new ParticipantModel({
        zid: data.zid
      });
      return ptpt.save();
    }).then(function(ptptAttrs) {
      var createConversationFormView = new CreateConversationFormView({
        model: model,
        collection: conversationsCollection,
        pid: ptptAttrs.pid,
        add: true
      });
      that.listenTo(createConversationFormView, "all", function(eventName, data) {
        if (eventName === "done") {
          var suurls = data;
            if (suurls) {
            var suurlsCsv = ["xid, url"];
            var len = suurls.xids.length;
            var xids = suurls.xids;
            var urls = suurls.urls;
            for (var i = 0; i < len; i++) {
              suurlsCsv.push(xids[i] + "," + urls[i]);
            }
            model.set("suurls", suurlsCsv);
          }
          that.gotoShareView(model);
          // that.navigate("inbox", {trigger: true});
          //that.inbox();
        }
      });
      RootView.getInstance().setView(createConversationFormView);
      $("[data-toggle='checkbox']").each(function() {
        var $checkbox = $(this);
        $checkbox.checkbox();
      });
    }, function(err) {
      // try with an oinvite
      var oinvite = window.prompt("Please enter beta invite code:");
      return $.ajax({
        url: "/v3/users",
        type: "PUT",
        data: {
          oinvite: oinvite,
          is_owner: true
        }
      }).done(function() {
        // Try again now that we should have permissions to create conversations.
        that.createConversation();
      });
    }).fail(onFail);
  },
  doLaunchConversation: function(ptptModel) {
    var zid = ptptModel.get("zid");
    var pid = ptptModel.get("pid");

    // Assumes you have a pid already.
    var model = new ConversationModel({
        zid: zid
    });
    bbFetch(model).then(function() {
      var conversationView = new ConversationView({
        pid: pid,
        model: model
      });
      RootView.getInstance().setView(conversationView);
    },function(e) {
      console.error("error loading conversation model", e);
      setTimeout(function() { that.conversationView(zid); }, 5000); // retry
    });
  },
  demoConversation: function(zid) {
    var ptpt = new ParticipantModel({
      zid: zid,
      pid: -123 // DEMO_MODE
    });

    // NOTE: not posting the model

    this.doLaunchConversation(ptpt);
  },
  conversationViewWithSuzinvite: function(zid, suzinvite) {
    return this.conversationView(zid, suzinvite, true);
  },
  conversationView: function(zid, zinvite, singleUse) {					//THE CONVERzATION, VISUALIZATION, VOTING, ETC.
    if (!zinvite && !authenticated()) { return this.bail(); }

    var that = this;

    var suzinvite;
    if (singleUse) {
      suzinvite = zinvite;
    }

    var uid = PolisStorage.uid();

    if (!uid) {
        console.log("trying to load conversation, but no auth");
        // Not signed in.
        // Or not registered.

        if (singleUse) {

          $.ajax({
            url: "/v3/joinWithSuzinvite",
            type: "POST",
            dataType: "json",
            xhrFields: {
                withCredentials: true
            },
            // crossDomain: true,
            data: {
              zid: zid,
              suzinvite: suzinvite
            }
          }).then(function(data) {
            that.conversationView(zid);
          }, function(err) {
            if (err.responseText === "polis_err_no_matching_suzinvite") {
              alert("Sorry, this single-use URL has been used.");
            } else {
              that.conversationGatekeeper(zid, uid, suzinvite, singleUse).done(function(ptptData) {
                that.conversationView(zid);
              });
            }
          });
        } else {
          this.doCreateUserFromGatekeeper(zid, zinvite, singleUse).done(function() {
            // Try again, should be ready now.
            that.conversationView(zid, zinvite);
          });
        }
    } else {
      // join conversation (may already have joined)
      var ptpt = new ParticipantModel({
        zid: zid,
        zinvite: zinvite
      });
      ptpt.save().then(function() {
        // Participant record was created, or already existed.
        // Go to the conversation.
        that.doLaunchConversation(ptpt);
      }, function(err) {
        that.conversationGatekeeper(zid, uid, zinvite).done(function(ptptData) {
          that.conversationView(zid, zinvite);
        });
      });
    }
    //  else {
    //   // Found a pid for that zid.
    //   // Go to the conversation.
    //   that.doLaunchConversation(zid);
    // }
  },
  // assumes the user already exists.
  conversationGatekeeper: function(zid, uid, zinvite, singleUse) {
    var dfd = $.Deferred();
    var params = {
      zid: zid,
      uid: uid,
    };
    if (singleUse) {
      params.suzinvite = zinvite
    } else {
      params.zinvite = zinvite;
    }
    var gatekeeperView = new ConversationGatekeeperView(params);
    gatekeeperView.on("done", dfd.resolve);
    RootView.getInstance().setView(gatekeeperView);
    return dfd.promise();
  },
  doCreateUserFromGatekeeper: function(zid, zinvite, singleUse) {
    var dfd = $.Deferred();

    var params = {
        zid: zid,
        create: true, // do we need this?
    };
    if (singleUse) {
        params.suzinvite = zinvite;
    } else {
        params.zinvite = zinvite;
    }
    var model = new ConversationModel(params);
    bbFetch(model).then(function() {
      var createUserFormView = new ConversationGatekeeperViewCreateUser({
        model : model
      });
      createUserFormView.on("authenticated", dfd.resolve);
      RootView.getInstance().setView(createUserFormView);
    },function(e) {
      console.error("error loading conversation model", e);
      setTimeout(function() { that.conversationView(zid); }, 5000); // retry
    });
    return dfd.promise();
  },
  doCreateUser: function(zinvite){
    var dfd = $.Deferred();

    var createUserFormView = new CreateUserFormView({
      model : new Backbone.Model({
        zinvite: zinvite,
        create: true
      })
    });
    createUserFormView.on("authenticated", dfd.resolve);
    RootView.getInstance().setView(createUserFormView);
    return dfd.promise();
  },
  createUser: function(){
    var that = this;
    this.doLogin(true).done(function() {
    // this.doCreateUser().done(function() {
      that.navigate("inbox", {trigger: true});
      // that.inbox();
    });
  },
  pwReset: function(pwresettoken) {
    var view = new PasswordResetView({
      pwresettoken: pwresettoken
    });
    RootView.getInstance().setView(view);
  },
  pwResetInit: function() {
    var view = new PasswordResetInitView();
    RootView.getInstance().setView(view);
  },
  doLogin: function(create) {
    var dfd = $.Deferred();
    var gatekeeperView = new ConversationGatekeeperViewCreateUser({
      model: new Backbone.Model({
        create: create
      })
    });
    gatekeeperView.on("authenticated", dfd.resolve);
    RootView.getInstance().setView(gatekeeperView);
    return dfd.promise();
  },
  login: function(zid){
    var that = this;
    this.doLogin(false).done(function() {
      if (zid) {
        // Redirect to a specific conversation after the user signs in.
        // TODO think - do we want to use this route for this scenario, it's probably handled by the other gatekeeper functions.
        that.conversationView(zid);
      } else {
        that.navigate("inbox", {trigger: true});
      }
    });
  }
});

 module.exports = polisRouter;<commit_msg>suzinvite fixes NOTE contains crappy crappy 5am code duplication<commit_after>var RootView = require("../views/root");
var Backbone = require("backbone");
var ConversationModel = require("../models/conversation");
var ParticipantModel = require("../models/participant");
var bbFetch = require("../net/bbFetch");
var ConversationsCollection = require("../collections/conversations");
var InboxView = require("../views/inbox");
var HomepageView = require("../views/homepage");
var CreateConversationFormView = require("../views/create-conversation-form");
var ConversationDetailsView = require("../views/conversation-details");
var ConversationGatekeeperView = require("../views/conversationGatekeeperView");
var ConversationGatekeeperViewCreateUser = require("../views/conversationGatekeeperViewCreateUser");
var ConversationView = require("../views/conversation-view");
var CreateUserFormView = require("../views/create-user-form");
var LoginFormView = require("../views/login-form");
var LandingPageView = require("../views/landing-page");
var PasswordResetView = require("../views/passwordResetView");
var PasswordResetInitView = require("../views/passwordResetInitView");
var ShareLinkView = require("../views/share-link-view");
var PolisStorage = require("../util/polisStorage");
var $ = require("jquery");

function authenticated() {
  return PolisStorage.uid();
}

var polisRouter = Backbone.Router.extend({
  routes: {
    "homepage": "homepageView",
    "conversation/create": "createConversation",
    "conversation/view/:id(/:zinvite)": "conversationView",
    "user/create": "createUser",
    "user/login":"login",
    "settings": "deregister",
    "inbox(/:filter)": "inbox",
    "pwresetinit" : "pwResetInit",
    "": "landingPageView"
    // see others in the initialize method
  },
  initialize: function(options) {
    this.route(/([0-9]+)/, "conversationView");  // zid
    this.route(/([0-9]+)\/(.*)/, "conversationView"); // zid/zinvite
    this.route(/^ot\/([0-9]+)\/(.*)/, "conversationViewWithSuzinvite"); // zid/suzinvite
    this.route(/^pwreset\/(.*)/, "pwReset");
    this.route(/^demo\/(.*)/, "demoConversation");
  },
  bail: function() {
    this.navigate("/", {trigger: true});
  },
  landingPageView: function() {
    if (!authenticated()) {
      this.navigate("user/create", {trigger: true});
      // RootView.getInstance().setView(new LandingPageView());
      // RootView.getInstance().setView(new CreateUserFormView({
      //   model : new Backbone.Model({
      //     // zinvite: zinvite,
      //     create: true
      //   })
      // }));
    } else {
      // this.inbox();
      this.navigate("inbox", {trigger: true});
    }
  },
  deregister: function() {
    window.deregister();
  },
  gotoShareView: function(conversationModel) {
    var that = this;
    var shareLinkView = new ShareLinkView({
      model: conversationModel
    });
    shareLinkView.on("done", function() {
      var zid = conversationModel.get("zid");
      var zinvite = conversationModel.get("zinvites")[0];
      var path = zid + (zinvite ? "/" + zinvite : "");
      that.navigate(path, {trigger: true});
    });
    RootView.getInstance().setView(shareLinkView);
  },
  inbox: function(filter){
    if (!authenticated()) { return this.bail(); }
    // TODO add to inboxview init
    // conversationsCollection.fetch({
    //     data: $.param({
    //         is_active: false,
    //         is_draft: false,
    //     }),
    //     processData: true,
    // });
    var filterAttrs = {};
    if (filter) {
      switch(filter) {
        case "closed":
          filterAttrs.is_active = false;
          filterAttrs.is_draft = false;
        break;
        case "active":
          filterAttrs.is_active = true;
        break;
        default:
          filterAttrs.is_active = true;
        break;
      }
    }
    var conversationsCollection = new ConversationsCollection();
    // Let the InboxView filter the conversationsCollection.
    var inboxView = new InboxView($.extend(filterAttrs, {
      collection: conversationsCollection
    }));
    RootView.getInstance().setView(inboxView);
  },
  homepageView: function(){
    var homepage = new HomepageView();
    RootView.getInstance().setView(homepage);
  },
  createConversation: function(){
    if (!authenticated()) { return this.bail(); }
    function onFail(err) {
      alert("failed to create new conversation");
      console.dir(err);
    }
    var that = this;
    conversationsCollection = new ConversationsCollection();

    var model = new ConversationModel({
      is_draft: true,
      is_active: true // TODO think
    });

    model.save().then(function(data) {
      model.set("zid", data.zid);

      var ptpt = new ParticipantModel({
        zid: data.zid
      });
      return ptpt.save();
    }).then(function(ptptAttrs) {
      var createConversationFormView = new CreateConversationFormView({
        model: model,
        collection: conversationsCollection,
        pid: ptptAttrs.pid,
        add: true
      });
      that.listenTo(createConversationFormView, "all", function(eventName, data) {
        if (eventName === "done") {
          var suurls = data;
            if (suurls) {
            var suurlsCsv = ["xid, url"];
            var len = suurls.xids.length;
            var xids = suurls.xids;
            var urls = suurls.urls;
            for (var i = 0; i < len; i++) {
              suurlsCsv.push(xids[i] + "," + urls[i]);
            }
            model.set("suurls", suurlsCsv);
          }
          that.gotoShareView(model);
          // that.navigate("inbox", {trigger: true});
          //that.inbox();
        }
      });
      RootView.getInstance().setView(createConversationFormView);
      $("[data-toggle='checkbox']").each(function() {
        var $checkbox = $(this);
        $checkbox.checkbox();
      });
    }, function(err) {
      // try with an oinvite
      var oinvite = window.prompt("Please enter beta invite code:");
      return $.ajax({
        url: "/v3/users",
        type: "PUT",
        data: {
          oinvite: oinvite,
          is_owner: true
        }
      }).done(function() {
        // Try again now that we should have permissions to create conversations.
        that.createConversation();
      });
    }).fail(onFail);
  },
  doLaunchConversation: function(ptptModel) {
    var zid = ptptModel.get("zid");
    var pid = ptptModel.get("pid");

    // Assumes you have a pid already.
    var model = new ConversationModel({
        zid: zid
    });
    bbFetch(model).then(function() {
      var conversationView = new ConversationView({
        pid: pid,
        model: model
      });
      RootView.getInstance().setView(conversationView);
    },function(e) {
      console.error("error loading conversation model", e);
      setTimeout(function() { that.conversationView(zid); }, 5000); // retry
    });
  },
  demoConversation: function(zid) {
    var ptpt = new ParticipantModel({
      zid: zid,
      pid: -123 // DEMO_MODE
    });

    // NOTE: not posting the model

    this.doLaunchConversation(ptpt);
  },
  conversationViewWithSuzinvite: function(zid, suzinvite) {
    return this.conversationView(zid, suzinvite, true);
  },
  conversationView: function(zid, zinvite, singleUse) {					//THE CONVERzATION, VISUALIZATION, VOTING, ETC.
    if (!zinvite && !authenticated()) { return this.bail(); }

    var that = this;

    var suzinvite;
    if (singleUse) {
      suzinvite = zinvite;
    }

    var uid = PolisStorage.uid();

    if (!uid) {
        console.log("trying to load conversation, but no auth");
        // Not signed in.
        // Or not registered.

        if (singleUse) {

          $.ajax({
            url: "/v3/joinWithSuzinvite",
            type: "POST",
            dataType: "json",
            xhrFields: {
                withCredentials: true
            },
            // crossDomain: true,
            data: {
              zid: zid,
              suzinvite: suzinvite
            }
          }).then(function(data) {
            that.conversationView(zid);
          }, function(err) {
            if (err.responseText === "polis_err_no_matching_suzinvite") {
              alert("Sorry, this single-use URL has been used.");
            } else {
              that.conversationGatekeeper(zid, uid, suzinvite, singleUse).done(function(ptptData) {
                that.conversationView(zid);
              });
            }
          });
        } else {
          this.doCreateUserFromGatekeeper(zid, zinvite, singleUse).done(function() {
            // Try again, should be ready now.
            that.conversationView(zid, zinvite);
          });
        }
    } else {
      var params = {
        zid: zid,
      };
      if (singleUse) {
        params.suzinvite = suzinvite;
      } else {
        params.zinvite = zinvite;
      }

      if (singleUse) {
        // join conversation (may already have joined)
        var ptpt = new ParticipantModel(params);
        ptpt.save().then(function() {
          // Participant record was created, or already existed.
          // Go to the conversation.
          that.doLaunchConversation(ptpt);
        }, function(err) {
          $.ajax({
            url: "/v3/joinWithSuzinvite",
            type: "POST",
            dataType: "json",
            xhrFields: {
                withCredentials: true
            },
            // crossDomain: true,
            data: {
              zid: zid,
              suzinvite: suzinvite
            }
          }).then(function(data) {
            that.conversationView(zid);
          }, function(err) {
            if (err.responseText === "polis_err_no_matching_suzinvite") {
              alert("Sorry, this single-use URL has been used.");
            } else {
              that.conversationGatekeeper(zid, uid, suzinvite, singleUse).done(function(ptptData) {
                that.conversationView(zid);
              });
            }
          });
        });
      } else {
        // join conversation (may already have joined)
        var ptpt = new ParticipantModel(params);
        ptpt.save().then(function() {
          // Participant record was created, or already existed.
          // Go to the conversation.
          that.doLaunchConversation(ptpt);
        }, function(err) {
          that.conversationGatekeeper(zid, uid, zinvite).done(function(ptptData) {
            that.conversationView(zid, zinvite);
          });
        });
      }
    }
    //  else {
    //   // Found a pid for that zid.
    //   // Go to the conversation.
    //   that.doLaunchConversation(zid);
    // }
  },
  // assumes the user already exists.
  conversationGatekeeper: function(zid, uid, zinvite, singleUse) {
    var dfd = $.Deferred();
    var params = {
      zid: zid,
      uid: uid,
    };
    if (singleUse) {
      params.suzinvite = zinvite
    } else {
      params.zinvite = zinvite;
    }
    var gatekeeperView = new ConversationGatekeeperView(params);
    gatekeeperView.on("done", dfd.resolve);
    RootView.getInstance().setView(gatekeeperView);
    return dfd.promise();
  },
  doCreateUserFromGatekeeper: function(zid, zinvite, singleUse) {
    var dfd = $.Deferred();

    var params = {
        zid: zid,
        create: true, // do we need this?
    };
    if (singleUse) {
        params.suzinvite = zinvite;
    } else {
        params.zinvite = zinvite;
    }
    var model = new ConversationModel(params);
    bbFetch(model).then(function() {
      var createUserFormView = new ConversationGatekeeperViewCreateUser({
        model : model
      });
      createUserFormView.on("authenticated", dfd.resolve);
      RootView.getInstance().setView(createUserFormView);
    },function(e) {
      console.error("error loading conversation model", e);
      setTimeout(function() { that.conversationView(zid); }, 5000); // retry
    });
    return dfd.promise();
  },
  doCreateUser: function(zinvite){
    var dfd = $.Deferred();

    var createUserFormView = new CreateUserFormView({
      model : new Backbone.Model({
        zinvite: zinvite,
        create: true
      })
    });
    createUserFormView.on("authenticated", dfd.resolve);
    RootView.getInstance().setView(createUserFormView);
    return dfd.promise();
  },
  createUser: function(){
    var that = this;
    this.doLogin(true).done(function() {
    // this.doCreateUser().done(function() {
      that.navigate("inbox", {trigger: true});
      // that.inbox();
    });
  },
  pwReset: function(pwresettoken) {
    var view = new PasswordResetView({
      pwresettoken: pwresettoken
    });
    RootView.getInstance().setView(view);
  },
  pwResetInit: function() {
    var view = new PasswordResetInitView();
    RootView.getInstance().setView(view);
  },
  doLogin: function(create) {
    var dfd = $.Deferred();
    var gatekeeperView = new ConversationGatekeeperViewCreateUser({
      model: new Backbone.Model({
        create: create
      })
    });
    gatekeeperView.on("authenticated", dfd.resolve);
    RootView.getInstance().setView(gatekeeperView);
    return dfd.promise();
  },
  login: function(zid){
    var that = this;
    this.doLogin(false).done(function() {
      if (zid) {
        // Redirect to a specific conversation after the user signs in.
        // TODO think - do we want to use this route for this scenario, it's probably handled by the other gatekeeper functions.
        that.conversationView(zid);
      } else {
        that.navigate("inbox", {trigger: true});
      }
    });
  }
});

 module.exports = polisRouter;<|endoftext|>


<commit_before>import React, {useEffect} from 'react'
import PropTypes from 'prop-types'
import {LoadMask} from 'tocco-ui'
import {notifier} from 'tocco-app-extensions'

import Dialog from '../Start'
import Secret from '../Secret'
import Verification from '../Verification'
import Result from '../Result'

const stages = {
  Start: 0,
  Secret: 1,
  Verification: 2,
  Result: 3
}

const TwoFactorConnector = ({initialize, stage}) => {
  useEffect(() => {
    initialize()
  }, [])

  const renderContent = () => {
    switch (stage) {
      case stages.Start:
        return <Dialog/>
      case stages.Secret:
        return <Secret/>
      case stages.Verification:
        return <Verification/>
      case stages.Result:
        return <Result/>
      default:
        return <LoadMask/>
    }
  }

  return

    <notifier.Notifier/>
    {renderContent()}

}

TwoFactorConnector.propTypes = {
  stage: PropTypes.number,
  initialize: PropTypes.func.isRequired,
  twoFactorActive: PropTypes.bool,
  secret: PropTypes.shape({
    text: PropTypes.string,
    uri: PropTypes.string
  })
}

export default TwoFactorConnector
<commit_msg>style(two-factor-connector): rename component<commit_after>import React, {useEffect} from 'react'
import PropTypes from 'prop-types'
import {LoadMask} from 'tocco-ui'
import {notifier} from 'tocco-app-extensions'

import Start from '../Start'
import Secret from '../Secret'
import Verification from '../Verification'
import Result from '../Result'

const stages = {
  Start: 0,
  Secret: 1,
  Verification: 2,
  Result: 3
}

const TwoFactorConnector = ({initialize, stage}) => {
  useEffect(() => {
    initialize()
  }, [])

  const renderContent = () => {
    switch (stage) {
      case stages.Start:
        return <Start/>
      case stages.Secret:
        return <Secret/>
      case stages.Verification:
        return <Verification/>
      case stages.Result:
        return <Result/>
      default:
        return <LoadMask/>
    }
  }

  return

    <notifier.Notifier/>
    {renderContent()}

}

TwoFactorConnector.propTypes = {
  stage: PropTypes.number,
  initialize: PropTypes.func.isRequired,
  twoFactorActive: PropTypes.bool,
  secret: PropTypes.shape({
    text: PropTypes.string,
    uri: PropTypes.string
  })
}

export default TwoFactorConnector
<|endoftext|>


<commit_before>'use strict';

const Boom = require('boom');
const User = require('../models/user');
const Tweet = require('../models/tweet');

exports.findAll = {
  auth: false,

  handler: function (request, reply) {
    Tweet.find({})
    .sort({ createdAt: 'desc' })
    .limit(50)
    .populate('creator')
    .exec().then((tweets) => {
      reply(tweets);
    }).catch((error) => {
      reply(Boom.badImplementation('error accessing db'));
    });
  },
};

exports.findAllByUser = {
  auth: false,

  handler: function (request, reply) {

  },
};

exports.findOne = {
  auth: false,

  handler: function (request, reply) {

  },
};

exports.create = {
  auth: false,

  handler: function (request, reply) {

  },
};

exports.deleteOne = {
  auth: false,

  handler: function (request, reply) {

  },
};
<commit_msg>Add get tweet by id<commit_after>'use strict';

const Boom = require('boom');
const User = require('../models/user');
const Tweet = require('../models/tweet');

exports.findAll = {
  auth: false,

  handler: function (request, reply) {
    Tweet.find({})
    .sort({ createdAt: 'desc' })
    .limit(50)
    .populate('creator')
    .exec().then((tweets) => {
      reply(tweets);
    }).catch((error) => {
      reply(Boom.badImplementation('error accessing db'));
    });
  },
};

exports.findAllByUser = {
  auth: false,

  handler: function (request, reply) {

  },
};

exports.findOne = {
  auth: false,

  handler: function (request, reply) {
    Tweet.findOne({ _id: request.params.id }).populate('creator').exec().then((tweet) => {
      if (tweet) {
        reply(tweet);
      } else {
        reply(Boom.notFound('id not found'));
      }
    }).catch((error) => {
      reply(Boom.notFound('id not found'));
    });
  },
};

exports.create = {
  auth: false,

  handler: function (request, reply) {

  },
};

exports.deleteOne = {
  auth: false,

  handler: function (request, reply) {

  },
};
<|endoftext|>