<commit_before>import AppContext from '../../AppContext';
import MemberAvatar from '../common/MemberGravatar';
import ActionButton from '../common/ActionButton';
import Switch from '../common/Switch';
import isPreviewMode from '../../utils/is-preview-mode';

const React = require('react');

export const AccountHomePageStyles = `
    .gh-portal-account-header {
        display: flex;
        flex-direction: column;
        align-items: center;
        margin-bottom: 20px;
    }

    .gh-portal-account-footer {
        display: flex;
        margin-top: -16px;
    }

    .gh-portal-account-footer.paid {
        margin-top: 12px;
    }

    .gh-portal-account-footermenu {
        display: flex;
        list-style: none;
        padding: 0;
        margin: 0;
    }

    .gh-portal-account-footermenu li {
        margin-right: 16px;
    }

    .gh-portal-account-footermenu li:last-of-type {
        margin-right: 0;
    }

    .gh-portal-accountdetail-section {
        display: flex;
        align-items: flex-start;
        margin-bottom: 40px;
    }

    .gh-portal-accountdetail-section:first-of-type {
        margin-top: 32px;
        margin-bottom: 22px;
    }

    .gh-portal-account-divider {
        margin: 12px -32px;
        border: none;
        border-bottom: 1px solid #EDEDED;
    }

    .gh-portal-account-divider:last-of-type {
        margin-bottom: 40px;
    }

    .gh-portal-btn-accountdetail {
        height: 36px;
        font-size: 1.3rem;
        width: 88px;
        padding: 0 12px;
    }

    .gh-portal-accountdetail-data {
        line-height: 1em;
        margin-top: 4px;
        color: #777;
    }

    .gh-portal-accountdetail-data.small {
        font-size: 1.3rem;
        margin-top: 5px;
    }

    .gh-portal-setting-heading.paid-home {
        font-weight: 600;
    }

    /* Avatar styles */
    .gh-portal-avatar-container {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        width: 64px;
        height: 64px;
        margin-bottom: 8px;
        border-radius: 999px;
        box-shadow: 0 0 0 3px #fff;
    }
`;

const Divider = () => {
    return (

    );
};

const UserAvatar = ({avatar}) => {
    return (

            <MemberAvatar gravatar={avatar} style={{userIcon: {color: '#525252', width: '45px', height: '45px'}}} />

    );
};

const AccountFooter = ({onLogout, onSettings, brandColor}) => {
    return (

Contact support

                    {onSettings
                        ?

Settings

                        : null
                    }

Logout

    );
};

const UserHeader = ({member}) => {
    const avatar = member.avatar_image;
    return (

            <UserAvatar avatar={avatar} />

Your Account

    );
};

class FreeAccountHomePage extends React.Component {
    static contextType = AppContext;

    handleSignout(e) {
        e.preventDefault();
        this.context.onAction('signout');
    }

    openSettings(e) {
        this.context.onAction('switchPage', {
            page: 'accountProfile',
            lastPage: 'accountHome'
        });
    }

    openSubscribe(e) {
        this.context.onAction('switchPage', {
            page: 'accountPlan',
            lastPage: 'accountHome'
        });
    }

    renderSubscribeButton() {
        const {is_stripe_configured: isStripeConfigured} = this.context.site;

        if (isStripeConfigured) {
            return (
                <ActionButton label="Subscribe now" onClick={() => this.openSubscribe()} brandColor={this.context.brandColor} />
            );
        }

        return null;
    }

    renderAccountDetail(e) {
        const {name, firstname, email} = this.context.member;
        const {title: siteTitle} = this.context.site;

        return (

                    Hey {firstname || name || email}!
                    You are subscribed to free updates from {siteTitle}, but you don't have a paid subscription to unlock full access

                {this.renderSubscribeButton()}

        );
    }

    render() {
        const {member, brandColor} = this.context;
        return (

                <UserHeader member={member} />
                {this.renderAccountDetail()}
                <AccountFooter onLogout={e => this.handleSignout(e)} onSettings={e => this.openSettings(e)} brandColor={brandColor} />

        );
    }
}

class PaidAccountHomePage extends React.Component {
    static contextType = AppContext;

    handleSignout(e) {
        e.preventDefault();
        this.context.onAction('signout');
    }

    renderAccountWelcome() {
        const {name, firstname, email} = this.context.member;
        const siteTitle = this.context.site.title;

        return (

                    Hey {firstname || name || email}!
                    You have an active {siteTitle} account with access to all areas. Get in touch if you have any problems or need some help getting things updated, and thanks for subscribing.

        );
    }

    getPlanLabel({amount = 0, currency_symbol: currencySymbol = '$', interval}) {
        return `${currencySymbol}${amount / 100} / ${interval}`;
    }

    getCardLabel({defaultCardLast4}) {
        if (defaultCardLast4) {
            return `**** **** **** ${defaultCardLast4}`;
        }
        return `Complimentary`;
    }

    openEditProfile() {
        this.context.onAction('switchPage', {
            page: 'accountProfile',
            lastPage: 'accountHome'
        });
    }

    openUpdatePlan() {
        const {is_stripe_configured: isStripeConfigured} = this.context.site;
        if (isStripeConfigured) {
            this.context.onAction('switchPage', {
                page: 'accountPlan',
                lastPage: 'accountHome'
            });
        }
    }

    onEditBilling() {
        this.context.onAction('editBilling');
    }

    onToggleSubscription(e, subscribed) {
        this.context.onAction('updateMember', {subscribed: !subscribed});
    }

    renderAccountDetails() {
        const {name, email, subscriptions, subscribed} = this.context.member;

        const {
            plan,
            default_payment_card_last4: defaultCardLast4
        } = subscriptions[0];

        return (

Profile

{name}

{email}

                    <button className='gh-portal-btn gh-portal-btn-accountdetail' onClick={e => this.openEditProfile(e)}>Edit</button>

Plan

{this.getPlanLabel(plan)}

                    <button className='gh-portal-btn gh-portal-btn-accountdetail' onClick={e => this.openUpdatePlan(e)}>Change</button>

Billing Info

{this.getCardLabel({defaultCardLast4})}

                    <button className='gh-portal-btn gh-portal-btn-accountdetail' onClick={e => this.onEditBilling(e)}>Update</button>

Newsletter

You are subscribed to email newsletters

                        <Switch onToggle={(e) => {
                            this.onToggleSubscription(e, subscribed);
                        }} checked={subscribed} />

        );
    }

    render() {
        const {member, brandColor} = this.context;
        return (

                <UserHeader member={member} />
                {this.renderAccountWelcome()}
                <Divider />
                {this.renderAccountDetails()}
                <Divider />
                <AccountFooter onLogout={e => this.handleSignout(e)} brandColor={brandColor} />

        );
    }
}
export default class AccountHomePage extends React.Component {
    static contextType = AppContext;

    componentDidMount() {
        const {member} = this.context;
        if (!member && !isPreviewMode()) {
            this.context.onAction('switchPage', {
                page: 'signup'
            });
        }
    }

    render() {
        const {member} = this.context;
        if (member) {
            if (member.paid) {
                return (
                    <PaidAccountHomePage />
                );
            }
            return (
                <FreeAccountHomePage />
            );
        }
        return null;
    }
}<commit_msg>Applied brandcolor to account icon<commit_after>import AppContext from '../../AppContext';
import MemberAvatar from '../common/MemberGravatar';
import ActionButton from '../common/ActionButton';
import Switch from '../common/Switch';
import isPreviewMode from '../../utils/is-preview-mode';

const React = require('react');

export const AccountHomePageStyles = `
    .gh-portal-account-header {
        display: flex;
        flex-direction: column;
        align-items: center;
        margin-bottom: 20px;
    }

    .gh-portal-account-footer {
        display: flex;
        margin-top: -16px;
    }

    .gh-portal-account-footer.paid {
        margin-top: 12px;
    }

    .gh-portal-account-footermenu {
        display: flex;
        list-style: none;
        padding: 0;
        margin: 0;
    }

    .gh-portal-account-footermenu li {
        margin-right: 16px;
    }

    .gh-portal-account-footermenu li:last-of-type {
        margin-right: 0;
    }

    .gh-portal-accountdetail-section {
        display: flex;
        align-items: flex-start;
        margin-bottom: 40px;
    }

    .gh-portal-accountdetail-section:first-of-type {
        margin-top: 32px;
        margin-bottom: 22px;
    }

    .gh-portal-account-divider {
        margin: 12px -32px;
        border: none;
        border-bottom: 1px solid #EDEDED;
    }

    .gh-portal-account-divider:last-of-type {
        margin-bottom: 40px;
    }

    .gh-portal-btn-accountdetail {
        height: 36px;
        font-size: 1.3rem;
        width: 88px;
        padding: 0 12px;
    }

    .gh-portal-accountdetail-data {
        line-height: 1em;
        margin-top: 4px;
        color: #777;
    }

    .gh-portal-accountdetail-data.small {
        font-size: 1.3rem;
        margin-top: 5px;
    }

    .gh-portal-setting-heading.paid-home {
        font-weight: 600;
    }

    /* Avatar styles */
    .gh-portal-avatar-container {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        width: 64px;
        height: 64px;
        margin-bottom: 8px;
        border-radius: 999px;
        box-shadow: 0 0 0 3px #fff;
    }
`;

const Divider = () => {
    return (

    );
};

const UserAvatar = ({avatar, brandColor}) => {
    return (

            <MemberAvatar gravatar={avatar} style={{userIcon: {color: brandColor, width: '45px', height: '45px'}}} />

    );
};

const AccountFooter = ({onLogout, onSettings, brandColor}) => {
    return (

Contact support

                    {onSettings
                        ?

Settings

                        : null
                    }

Logout

    );
};

const UserHeader = ({member, brandColor}) => {
    const avatar = member.avatar_image;
    return (

            <UserAvatar avatar={avatar} brandColor={brandColor} />

Your Account

    );
};

class FreeAccountHomePage extends React.Component {
    static contextType = AppContext;

    handleSignout(e) {
        e.preventDefault();
        this.context.onAction('signout');
    }

    openSettings(e) {
        this.context.onAction('switchPage', {
            page: 'accountProfile',
            lastPage: 'accountHome'
        });
    }

    openSubscribe(e) {
        this.context.onAction('switchPage', {
            page: 'accountPlan',
            lastPage: 'accountHome'
        });
    }

    renderSubscribeButton() {
        const {is_stripe_configured: isStripeConfigured} = this.context.site;

        if (isStripeConfigured) {
            return (
                <ActionButton label="Subscribe now" onClick={() => this.openSubscribe()} brandColor={this.context.brandColor} />
            );
        }

        return null;
    }

    renderAccountDetail(e) {
        const {name, firstname, email} = this.context.member;
        const {title: siteTitle} = this.context.site;

        return (

                    Hey {firstname || name || email}!
                    You are subscribed to free updates from {siteTitle}, but you don't have a paid subscription to unlock full access

                {this.renderSubscribeButton()}

        );
    }

    render() {
        const {member, brandColor} = this.context;
        return (

                <UserHeader member={member} brandColor={brandColor} />
                {this.renderAccountDetail()}
                <AccountFooter onLogout={e => this.handleSignout(e)} onSettings={e => this.openSettings(e)} brandColor={brandColor} />

        );
    }
}

class PaidAccountHomePage extends React.Component {
    static contextType = AppContext;

    handleSignout(e) {
        e.preventDefault();
        this.context.onAction('signout');
    }

    renderAccountWelcome() {
        const {name, firstname, email} = this.context.member;
        const siteTitle = this.context.site.title;

        return (

                    Hey {firstname || name || email}!
                    You have an active {siteTitle} account with access to all areas. Get in touch if you have any problems or need some help getting things updated, and thanks for subscribing.

        );
    }

    getPlanLabel({amount = 0, currency_symbol: currencySymbol = '$', interval}) {
        return `${currencySymbol}${amount / 100} / ${interval}`;
    }

    getCardLabel({defaultCardLast4}) {
        if (defaultCardLast4) {
            return `**** **** **** ${defaultCardLast4}`;
        }
        return `Complimentary`;
    }

    openEditProfile() {
        this.context.onAction('switchPage', {
            page: 'accountProfile',
            lastPage: 'accountHome'
        });
    }

    openUpdatePlan() {
        const {is_stripe_configured: isStripeConfigured} = this.context.site;
        if (isStripeConfigured) {
            this.context.onAction('switchPage', {
                page: 'accountPlan',
                lastPage: 'accountHome'
            });
        }
    }

    onEditBilling() {
        this.context.onAction('editBilling');
    }

    onToggleSubscription(e, subscribed) {
        this.context.onAction('updateMember', {subscribed: !subscribed});
    }

    renderAccountDetails() {
        const {name, email, subscriptions, subscribed} = this.context.member;

        const {
            plan,
            default_payment_card_last4: defaultCardLast4
        } = subscriptions[0];

        return (

Profile

{name}

{email}

                    <button className='gh-portal-btn gh-portal-btn-accountdetail' onClick={e => this.openEditProfile(e)}>Edit</button>

Plan

{this.getPlanLabel(plan)}

                    <button className='gh-portal-btn gh-portal-btn-accountdetail' onClick={e => this.openUpdatePlan(e)}>Change</button>

Billing Info

{this.getCardLabel({defaultCardLast4})}

                    <button className='gh-portal-btn gh-portal-btn-accountdetail' onClick={e => this.onEditBilling(e)}>Update</button>

Newsletter

You are subscribed to email newsletters

                        <Switch onToggle={(e) => {
                            this.onToggleSubscription(e, subscribed);
                        }} checked={subscribed} />

        );
    }

    render() {
        const {member, brandColor} = this.context;
        return (

                <UserHeader member={member} brandColor={brandColor} />
                {this.renderAccountWelcome()}
                <Divider />
                {this.renderAccountDetails()}
                <Divider />
                <AccountFooter onLogout={e => this.handleSignout(e)} brandColor={brandColor} />

        );
    }
}
export default class AccountHomePage extends React.Component {
    static contextType = AppContext;

    componentDidMount() {
        const {member} = this.context;
        if (!member && !isPreviewMode()) {
            this.context.onAction('switchPage', {
                page: 'signup'
            });
        }
    }

    render() {
        const {member} = this.context;
        if (member) {
            if (member.paid) {
                return (
                    <PaidAccountHomePage />
                );
            }
            return (
                <FreeAccountHomePage />
            );
        }
        return null;
    }
}<|endoftext|>


<commit_before>let aDefault = {
    'ho-oh': 'hooh',
    'bounty': 'porygonz-shiny',
    'tech': 'vileplume',
    'lectro': 'noivern',
    'ngb': 'ampharos',
    'amph': 'ampharos-mega',
    'shep': 'ampharos-mega',
    'fable': 'flygon-shiny',
    'thane': 'absol',
    'semper': 'flygon',
    'monk': 'weavile',
    'baru': 'arcanine',
    'ace': 'suicune',
    'quote': 'sableye',
    'stall': 'sableye-mega',
    'surv': 'espeon',
    'josh': 'staraptor',
    'luc': 'lucario',
    'fluffy': 'leafeon',
    'fug': 'rayquaza',
    'sol': 'solrock',
    'cell': 'gengar',
    'dom': 'charizard',
    'hiccup': 'spinda',
    'runtime': 'lapras',
    'curtis': 'reuniclus',
    'type: null': 'typenull',
    'type null': 'typenull',
    'mr. mime': 'mrmime',
    'mr mime': 'mrmime',
    'mime jr.': 'mimejr',
    'mime jr': 'mimejr',
    'tapu koko': 'tapukoko',
    'tapu lele': 'tapulele',
    'tapu bulu': 'tapubulu',
    'tapu fini': 'tapufini'
}

let custom = {
    'matt': 'meowstic',
    'erebus': 'meowstic',
    'blue': 'popplio',
    'emily': 'luxio',
    'flare': 'flareon',
    'hound': 'houndoom',
    'zytom': 'lurantis',
    'jenn': 'bellossom',
    'skul': 'totodile',
    'orn': 'decidueye-shiny',
    'jordan': 'dewott',
    'mene': 'cosmog',
    'minty': 'archeops',
    'sapph': 'glaceon',
    'swed': 'vaporeon',
    'pally': 'lilligant',
    'thirst': 'lilligant'
}

exports.aliases = (id) => {
    console.log(id);
    if (id == 111504456838819840) {
        console.log('returning default');
        return aDefault;
    } else {
        console.log('returning custom');
        return Object.assign(aDefault, custom);
    }
}<commit_msg>Did I fix it???<commit_after>let aDefault = {
    'ho-oh': 'hooh',
    'bounty': 'porygonz-shiny',
    'tech': 'vileplume',
    'lectro': 'noivern',
    'ngb': 'ampharos',
    'amph': 'ampharos-mega',
    'shep': 'ampharos-mega',
    'fable': 'flygon-shiny',
    'thane': 'absol',
    'semper': 'flygon',
    'monk': 'weavile',
    'baru': 'arcanine',
    'ace': 'suicune',
    'quote': 'sableye',
    'stall': 'sableye-mega',
    'surv': 'espeon',
    'josh': 'staraptor',
    'luc': 'lucario',
    'fluffy': 'leafeon',
    'fug': 'rayquaza',
    'sol': 'solrock',
    'cell': 'gengar',
    'dom': 'charizard',
    'hiccup': 'spinda',
    'runtime': 'lapras',
    'curtis': 'reuniclus',
    'type: null': 'typenull',
    'type null': 'typenull',
    'mr. mime': 'mrmime',
    'mr mime': 'mrmime',
    'mime jr.': 'mimejr',
    'mime jr': 'mimejr',
    'tapu koko': 'tapukoko',
    'tapu lele': 'tapulele',
    'tapu bulu': 'tapubulu',
    'tapu fini': 'tapufini'
}

let custom = {
    'matt': 'meowstic',
    'erebus': 'meowstic',
    'blue': 'popplio',
    'emily': 'luxio',
    'flare': 'flareon',
    'hound': 'houndoom',
    'zytom': 'lurantis',
    'jenn': 'bellossom',
    'skul': 'totodile',
    'orn': 'decidueye-shiny',
    'jordan': 'dewott',
    'mene': 'cosmog',
    'minty': 'archeops',
    'sapph': 'glaceon',
    'swed': 'vaporeon',
    'pally': 'lilligant',
    'thirst': 'lilligant'
}

exports.aliases = (id) => {
    let toReturn = {};
    Object.assign(toReturn, aDefault);
    if (id == 111504456838819840) {
        console.log('returning default');
        return toReturn;
    } else {
        console.log('returning custom');
        return Object.assign(toReturn, custom);
    }
}<|endoftext|>


<commit_before>var Web3 = require('web3');
var web3 = new Web3();
var elasticsearch = require('elasticsearch');
var config = require('config');

var index = config.get('elasticsearch.index');

web3.setProvider(new web3.providers.HttpProvider(config.get('ethereum.provider')));

var abi = require('./config/' + process.env.NODE_ENV + '.abi.json');
var contract = web3.eth.contract(abi);

var client = new elasticsearch.Client({
  host: config.get('elasticsearch.host')
});

var callbacks = require('./config/' + process.env.NODE_ENV + '.callbacks.js');
callbacks.onInit();

var lastBlockNumber;
var lastLogIndex;

// Get last log processed.
client.get({
  index: index,
  type: 'elastic-ethereum',
  id: 0
}, function (error, response) {
  if (!error) {
    lastBlockNumber = response._source.lastBlockNumber;
    lastLogIndex = response._source.lastLogIndex;
  }
  else {
    lastBlockNumber = 0;
    callbacks.onCreate();
  }

  watch();
});

function watch() {
  var filter = web3.eth.filter({fromBlock: lastBlockNumber, toBlock: 'latest', address: config.get('ethereum.contract_address')});

  filter.watch(function(error, result) {
    // Check if we have indexed this log before.
    if (result.blockNumber == lastBlockNumber && result.logIndex <= lastLogIndex)  {
      return;
    }

    console.log(result.blockNumber + ':' + result.logIndex);

    // Delete documents.
    var deletes = callbacks.getDeletes(result);
    for (type in deletes) {
      for (id in deletes[type]) {
        client.delete({
          index: index,
          type: type,
          id: deletes[type][id]
        }, function (error, response) {
          console.log(response);
        });
      }
    }

    // Index documents.
    var documents = callbacks.getDocuments(result);
    for (type in documents) {
      for (id in documents[type]) {
        client.index({
          index: index,
          type: type,
          id: id,
          body: documents[type][id]
        }, function (error, response) {
          console.log(response);
        });
      }
    }

    client.index({
      index: index,
      type: 'elastic-ethereum',
      id: 0,
      body: {
        lastBlockNumber: result.blockNumber,
        lastLogIndex: result.logIndex
      }
    }, function (error, response) {
      console.log(response);
    });

  });
}
<commit_msg>Make some variables global so they can be used in callbacks.<commit_after>var Web3 = require('web3');
web3 = new Web3();
var elasticsearch = require('elasticsearch');
var config = require('config');

index = config.get('elasticsearch.index');

web3.setProvider(new web3.providers.HttpProvider(config.get('ethereum.provider')));

var abi = require('./config/' + process.env.NODE_ENV + '.abi.json');
contract = web3.eth.contract(abi);

client = new elasticsearch.Client({
  host: config.get('elasticsearch.host')
});

var callbacks = require('./config/' + process.env.NODE_ENV + '.callbacks.js');
callbacks.onInit();

var lastBlockNumber;
var lastLogIndex;

// Get last log processed.
client.get({
  index: index,
  type: 'elastic-ethereum',
  id: 0
}, function (error, response) {
  if (!error) {
    lastBlockNumber = response._source.lastBlockNumber;
    lastLogIndex = response._source.lastLogIndex;
  }
  else {
    lastBlockNumber = 0;
    callbacks.onCreate();
  }

  watch();
});

function watch() {
  var filter = web3.eth.filter({fromBlock: lastBlockNumber, toBlock: 'latest', address: config.get('ethereum.contract_address')});

  filter.watch(function(error, result) {
    // Check if we have indexed this log before.
    if (result.blockNumber == lastBlockNumber && result.logIndex <= lastLogIndex)  {
      return;
    }

    console.log(result.blockNumber + ':' + result.logIndex);

    // Delete documents.
    var deletes = callbacks.getDeletes(result);
    for (type in deletes) {
      for (id in deletes[type]) {
        client.delete({
          index: index,
          type: type,
          id: deletes[type][id]
        }, function (error, response) {
          console.log(response);
        });
      }
    }

    // Index documents.
    var documents = callbacks.getDocuments(result);
    for (type in documents) {
      for (id in documents[type]) {
        client.index({
          index: index,
          type: type,
          id: id,
          body: documents[type][id]
        }, function (error, response) {
          console.log(response);
        });
      }
    }

    client.index({
      index: index,
      type: 'elastic-ethereum',
      id: 0,
      body: {
        lastBlockNumber: result.blockNumber,
        lastLogIndex: result.logIndex
      }
    }, function (error, response) {
      console.log(response);
    });

  });
}
<|endoftext|>


<commit_before>import fileSaver from 'file-saver';
import API from 'src/util/api';
import UI from 'src/util/ui';
import {getData} from './jpaths';
import SD from './libs/SD';
import * as GUI from './nmrGUI';
import CCE from './libs/CCE';

const Ranges = SD.Ranges;
const NMR = SD.NMR;

const nmr1hOndeTemplates = {
    full: {
        type: 'object',
        properties: {
            integral: {
                type: 'number',
                title: 'value to fit the spectrum integral',
                label: 'Integral'
            },
            noiseFactor: {
                type: 'number',
                title: 'Mutiplier of the auto-detected noise level',
                label: 'noiseFactor'
            },
            clean: {
                type: 'number',
                title: 'Delete signals with integration less than input value',
                label: 'clean'
            },
            compile: {
                type: 'boolean',
                title: 'Compile the multiplets',
                label: 'compile'
            },
            optimize: {
                type: 'boolean',
                title: 'Optimize the peaks to fit the spectrum',
                label: 'optimize'
            },
            integralFn: {
                type: 'string',
                title: 'Type of integration',
                label: 'Integral type',
                enum: [
                    'sum',
                    'peaks'
                ]
            },
            type: {
                type: 'string',
                title: 'Nucleus',
                label: 'Nucleus',
                editable: false
            },
            removeImpurities: {
                type: 'object',
                label: 'Remove solvent impurities',
                properties: {
                    useIt: {
                        type: 'boolean',
                        label: 'Remove Impurities',
                    },
                    error: {
                        type: 'number',
                        label: 'Tolerance',
                        title: 'Allowed error in ppm'
                    }
                }
            }
        }
    },
    short: {
        type: 'object',
        properties: {
            integral: {
                type: 'number',
                title: 'Total integral value',
                label: 'Integral'
            },
            removeImpurities: {
                type: 'object',
                label: 'Remove solvent impurities',
                properties: {
                    useIt: {
                        type: 'boolean',
                        label: 'Remove Impurities',
                    },
                    error: {
                        type: 'number',
                        label: 'Tolerance',
                        title: 'Allowed error in ppm'
                    }
                }
            }
        }
    }
};
API.cache('nmr1hOndeTemplates', nmr1hOndeTemplates);

class Nmr1dManager {
    constructor(sample) {
        this.spectra = {};
        this.sample = sample;
        this.initializeNMROptions();
    }

    handleAction(action) {
        switch (action.name) {
            case 'updateRanges':
                this.updateIntegrals();
                break;
            case 'downloadSVG':
                var blob = new Blob([action.value + ''], {type: 'application/jcamp-dx;charset=utf-8'});
                fileSaver(blob, 'spectra.svg');
                break;
            case 'toggleNMR1hAdvancedOptions':
                var advancedOptions1H = !API.cache('nmr1hAdvancedOptions');
                API.cache('nmr1hAdvancedOptions', advancedOptions1H);
                if (advancedOptions1H) {
                    API.createData('nmr1hOndeTemplate', API.cache('nmr1hOndeTemplates').full);
                } else {
                    API.createData('nmr1hOndeTemplate', API.cache('nmr1hOndeTemplates').short);
                }
                break;
            case 'resetNMR1d':
                var type = action.name.replace(/[^0-9]/g, '');

                type = type + 'd';
                API.createData('blackNMR' + type, null);
                API.createData('annotationNMR' + type, null);
                API.createData('acsNMR' + type, null);
                break;
            case 'switchNMRLayer':
                var goToLayer = action.value.dimension > 1 ? 'nmr2D' : 'Default layer';
                API.switchToLayer(goToLayer);
                if (action.value.dimension > 1) {
                    if (action.value.jcamp) {
                        API.createData('blackNMR2d', action.value.jcamp.data);
                    } else {
                        API.createData('blackNMR2d', null);
                    }

                } else {
                    if (action.value.jcamp) {
                        API.createData('blackNMR1d', action.value.jcamp.data);
                    } else {
                        API.createData('blackNMR1d', null);
                    }
                }
                break;
            case 'executePeakPicking':
                var currentNmr = API.getData('currentNmr');
                if (currentNmr.dimension > 1) {
                    if (typeof UI !== 'undefined') {
                        UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                    }
                    return false;
                }
                this._autoRanges(currentNmr);
                break;
            case 'nmrChanged':
                this.updateIntegralOptions();
                this._createNMRannotationsAndACS();
                break;
            default:
                return false;
        }
        return true;
    }

    updateIntegralOptions() {
        const nmr = API.getData('currentNmr');
        if (nmr.dimension > 1) {
            return;
        }
        if (nmr.nucleus && nmr.nucleus[0].replace(/[0-9]/, '') !== 'H') {
            return;
        }

        if (!nmr.range || !nmr.range.length) {
            this.updateIntegralOptionsFromMF();
        } else {
            this.updateIntegralOptionsFromRanges();
        }
    }

    async updateIntegralsFromSpectrum() {
        const nmr = API.getData('currentNmr');
        const spectrum = await this._getNMR(nmr);
        if (spectrum && spectrum.sd && nmr.range && nmr.range.length > 0) {
            const ranges = new Ranges(nmr.range);
            var ppOptions = API.getData('nmr1hOptions');
            spectrum.updateIntegrals(ranges, {
                nH: Number(ppOptions.integral)
            });
        }
    }

    updateIntegrals(integral) {
        var ppOptions = API.getData('nmr1hOptions');
        var currentRanges = API.getData('currentNmrRanges');
        if (!currentRanges || currentRanges.length === 0) return;

        // We initialize ranges with the DataObject so that
        // the integral update is inplace
        var ranges = new Ranges(currentRanges);
        ranges.updateIntegrals({sum: Number(ppOptions.integral || integral)});
        currentRanges.triggerChange();
    }

    _getNMR(currentNMRLine) {
        var filename = String(currentNMRLine.getChildSync(['jcamp', 'filename']));
        return currentNMRLine.getChild(['jcamp', 'data']).then((jcamp) => {
            if (filename && this.spectra[filename]) {
                var spectrum = this.spectra[filename];
            } else {
                if (jcamp) {
                    jcamp = String(jcamp.get());
                    spectrum = NMR.fromJcamp(jcamp);
                    if (filename) {
                        this.spectra[filename] = spectrum;
                    }
                } else {
                    spectrum = new NMR();
                }
            }
            return spectrum;
        });
    }

    _autoRanges(nmrLine) {
        this._getNMR(nmrLine).then(nmrSpectrum => {
            var ppOptions = API.getData('nmr1hOptions').resurrect();
            var removeImpurityOptions = {};
            if (ppOptions.removeImpurities.useIt) {
                removeImpurityOptions = {
                    solvent: nmrLine.solvent,
                    nH: Number(ppOptions.integral),
                    error: ppOptions.removeImpurities.error
                };
            }
            var ranges = nmrSpectrum.getRanges({
                nH: Number(ppOptions.integral),
                realTop: true,
                thresholdFactor: Number(ppOptions.noiseFactor),
                clean: ppOptions.clean,
                compile: ppOptions.compile,
                from: ppOptions.from,
                to: ppOptions.to,
                optimize: ppOptions.optimize,
                integralType: ppOptions.integralFn,
                gsdOptions: {minMaxRatio: 0.001, smoothY: false, broadWidth: 0.004},
                removeImpurity: removeImpurityOptions
            });
            nmrLine.setChildSync(['range'], ranges);
        });
    }

    async _createNMRannotationsAndACS() {
        var nmrLine = API.getData('currentNmr');
        var ranges = nmrLine.range;
        var nmrSpectrum = await this._getNMR(nmrLine);
        var nucleus = nmrLine.nucleus[0];
        var observe = nmrLine.frequency;
        if (nmrSpectrum && nmrSpectrum.sd) {
            nucleus = nmrSpectrum.getNucleus(0);
            observe = nmrSpectrum.observeFrequencyX();
        }

        if (nmrSpectrum) {
            API.createData('annotationsNMR1d', GUI.annotations1D(ranges, {
                line: 1,
                fillColor: 'lightgreen',
                strokeWidth: 0
            }));
        }

        API.createData('acsNMR1d', SD.getACS(ranges, {
            rangeForMultiplet: true,
            nucleus,
            observe
        }));
    }

    getNumberHydrogens() {
        const mf = getData(this.sample, 'mf') + '';
        if (mf) {
            const chemcalc = CCE.analyseMF(mf);
            if (chemcalc && chemcalc.atoms && chemcalc.atoms.H) {
                return chemcalc.atoms.H || 100;
            }
        }
        return 100;
    }

    updateIntegralOptionsFromMF() {
        var options = API.getData('nmr1hOptions');
        const currentIntegral = Number(options.integral);
        const newIntegral = this.getNumberHydrogens();
        if (currentIntegral !== newIntegral) {
            options.setChildSync(['integral'], newIntegral);
        }
    }

    // todo : migrate this code to spectra-data-ranges
    getRangesTotalIntegral() {
        var ranges = API.getData('currentNmrRanges') || [];
        let sum = 0;
        for (const range of ranges) {
            sum += range.integral;
        }
        return sum;
    }

    updateIntegralOptionsFromRanges() {
        var options = API.getData('nmr1hOptions');
        const currentIntegral = Number(options.integral);
        const newIntegral = Math.round(this.getRangesTotalIntegral());
        if (currentIntegral !== newIntegral) {
            options.setChildSync(['integral'], newIntegral);
        }
    }

    async rangesHasChanged() {
        const ranges = API.getData('currentNmr').range;
        await this.updateIntegralsFromSpectrum();
        const newRangesID=this._getRangesID(ranges);

        var highlightWasUpdated = GUI.ensureRangesHighlight(ranges);
        if (highlightWasUpdated || this.previousRangesID !== newRangesID) {
            ranges.triggerChange();
            this._createNMRannotationsAndACS();
        }
        this.previousRangesID=newRangesID;
    }

    _getRangesID(ranges) {
        return ranges.map((range) => {
            return `i: ${Number(range.integral)} from: ${Number(range.from)} to: ${Number(range.to)}`;
        }).sort().join();
    }

    initializeNMROptions() {
        API.createData('nmr1hOptions', {
            noiseFactor: 0.8,
            clean: 0.5,
            compile: true,
            optimize: false,
            integralType: 'sum',
            integral: this.getNumberHydrogens(),
            type: '1H',
            removeImpurities: {
                useIt: false,
                error: 0.025
            }
        });

        API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short);
    }
}

module.exports = Nmr1dManager;
<commit_msg>ensure highlights when spectrum is selected<commit_after>import fileSaver from 'file-saver';
import API from 'src/util/api';
import UI from 'src/util/ui';
import {getData} from './jpaths';
import SD from './libs/SD';
import * as GUI from './nmrGUI';
import CCE from './libs/CCE';

const Ranges = SD.Ranges;
const NMR = SD.NMR;

const nmr1hOndeTemplates = {
    full: {
        type: 'object',
        properties: {
            integral: {
                type: 'number',
                title: 'value to fit the spectrum integral',
                label: 'Integral'
            },
            noiseFactor: {
                type: 'number',
                title: 'Mutiplier of the auto-detected noise level',
                label: 'noiseFactor'
            },
            clean: {
                type: 'number',
                title: 'Delete signals with integration less than input value',
                label: 'clean'
            },
            compile: {
                type: 'boolean',
                title: 'Compile the multiplets',
                label: 'compile'
            },
            optimize: {
                type: 'boolean',
                title: 'Optimize the peaks to fit the spectrum',
                label: 'optimize'
            },
            integralFn: {
                type: 'string',
                title: 'Type of integration',
                label: 'Integral type',
                enum: [
                    'sum',
                    'peaks'
                ]
            },
            type: {
                type: 'string',
                title: 'Nucleus',
                label: 'Nucleus',
                editable: false
            },
            removeImpurities: {
                type: 'object',
                label: 'Remove solvent impurities',
                properties: {
                    useIt: {
                        type: 'boolean',
                        label: 'Remove Impurities',
                    },
                    error: {
                        type: 'number',
                        label: 'Tolerance',
                        title: 'Allowed error in ppm'
                    }
                }
            }
        }
    },
    short: {
        type: 'object',
        properties: {
            integral: {
                type: 'number',
                title: 'Total integral value',
                label: 'Integral'
            },
            removeImpurities: {
                type: 'object',
                label: 'Remove solvent impurities',
                properties: {
                    useIt: {
                        type: 'boolean',
                        label: 'Remove Impurities',
                    },
                    error: {
                        type: 'number',
                        label: 'Tolerance',
                        title: 'Allowed error in ppm'
                    }
                }
            }
        }
    }
};
API.cache('nmr1hOndeTemplates', nmr1hOndeTemplates);

class Nmr1dManager {
    constructor(sample) {
        this.spectra = {};
        this.sample = sample;
        this.initializeNMROptions();
    }

    handleAction(action) {
        switch (action.name) {
            case 'updateRanges':
                this.updateIntegrals();
                break;
            case 'downloadSVG':
                var blob = new Blob([action.value + ''], {type: 'application/jcamp-dx;charset=utf-8'});
                fileSaver(blob, 'spectra.svg');
                break;
            case 'toggleNMR1hAdvancedOptions':
                var advancedOptions1H = !API.cache('nmr1hAdvancedOptions');
                API.cache('nmr1hAdvancedOptions', advancedOptions1H);
                if (advancedOptions1H) {
                    API.createData('nmr1hOndeTemplate', API.cache('nmr1hOndeTemplates').full);
                } else {
                    API.createData('nmr1hOndeTemplate', API.cache('nmr1hOndeTemplates').short);
                }
                break;
            case 'resetNMR1d':
                var type = action.name.replace(/[^0-9]/g, '');

                type = type + 'd';
                API.createData('blackNMR' + type, null);
                API.createData('annotationNMR' + type, null);
                API.createData('acsNMR' + type, null);
                break;
            case 'switchNMRLayer':
                var goToLayer = action.value.dimension > 1 ? 'nmr2D' : 'Default layer';
                API.switchToLayer(goToLayer);
                if (action.value.dimension > 1) {
                    if (action.value.jcamp) {
                        API.createData('blackNMR2d', action.value.jcamp.data);
                    } else {
                        API.createData('blackNMR2d', null);
                    }

                } else {
                    if (action.value.jcamp) {
                        API.createData('blackNMR1d', action.value.jcamp.data);
                    } else {
                        API.createData('blackNMR1d', null);
                    }
                }
                break;
            case 'executePeakPicking':
                var currentNmr = API.getData('currentNmr');
                if (currentNmr.dimension > 1) {
                    if (typeof UI !== 'undefined') {
                        UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                    }
                    return false;
                }
                this._autoRanges(currentNmr);
                break;
            case 'nmrChanged':
                this.updateIntegralOptions();
                this.ensureHighlights(false);
                break;
            default:
                return false;
        }
        return true;
    }

    getCurrentRanges() {
        const nmr = API.getData('currentNmr');
        if (nmr !== null) {
            return nmr.getChildSync(['range']);
        } else {
            return null;
        }
    }

    updateIntegralOptions() {
        const nmr = API.getData('currentNmr');
        if (nmr.dimension > 1) {
            return;
        }
        if (nmr.nucleus && nmr.nucleus[0].replace(/[0-9]/, '') !== 'H') {
            return;
        }

        if (!nmr.range || !nmr.range.length) {
            this.updateIntegralOptionsFromMF();
        } else {
            this.updateIntegralOptionsFromRanges();
        }
    }

    async updateIntegralsFromSpectrum() {
        const nmr = API.getData('currentNmr');
        const spectrum = await this._getNMR(nmr);
        if (spectrum && spectrum.sd && nmr.range && nmr.range.length > 0) {
            const ranges = new Ranges(nmr.range);
            var ppOptions = API.getData('nmr1hOptions');
            spectrum.updateIntegrals(ranges, {
                nH: Number(ppOptions.integral)
            });
        }
    }

    updateIntegrals(integral) {
        var ppOptions = API.getData('nmr1hOptions');
        var currentRanges = this.getCurrentRanges();
        if (!currentRanges || currentRanges.length === 0) return;

        // We initialize ranges with the DataObject so that
        // the integral update is inplace
        var ranges = new Ranges(currentRanges);
        ranges.updateIntegrals({sum: Number(ppOptions.integral || integral)});
        currentRanges.triggerChange();
    }

    _getNMR(currentNMRLine) {
        var filename = String(currentNMRLine.getChildSync(['jcamp', 'filename']));
        return currentNMRLine.getChild(['jcamp', 'data']).then((jcamp) => {
            if (filename && this.spectra[filename]) {
                var spectrum = this.spectra[filename];
            } else {
                if (jcamp) {
                    jcamp = String(jcamp.get());
                    spectrum = NMR.fromJcamp(jcamp);
                    if (filename) {
                        this.spectra[filename] = spectrum;
                    }
                } else {
                    spectrum = new NMR();
                }
            }
            return spectrum;
        });
    }

    _autoRanges(nmrLine) {
        this._getNMR(nmrLine).then(nmrSpectrum => {
            var ppOptions = API.getData('nmr1hOptions').resurrect();
            var removeImpurityOptions = {};
            if (ppOptions.removeImpurities.useIt) {
                removeImpurityOptions = {
                    solvent: nmrLine.solvent,
                    nH: Number(ppOptions.integral),
                    error: ppOptions.removeImpurities.error
                };
            }
            var ranges = nmrSpectrum.getRanges({
                nH: Number(ppOptions.integral),
                realTop: true,
                thresholdFactor: Number(ppOptions.noiseFactor),
                clean: ppOptions.clean,
                compile: ppOptions.compile,
                from: ppOptions.from,
                to: ppOptions.to,
                optimize: ppOptions.optimize,
                integralType: ppOptions.integralFn,
                gsdOptions: {minMaxRatio: 0.001, smoothY: false, broadWidth: 0.004},
                removeImpurity: removeImpurityOptions
            });
            nmrLine.setChildSync(['range'], ranges);
        });
    }

    async _createNMRannotationsAndACS() {
        var nmrLine = API.getData('currentNmr');
        var ranges = nmrLine.range;
        var nmrSpectrum = await this._getNMR(nmrLine);
        var nucleus = nmrLine.nucleus[0];
        var observe = nmrLine.frequency;
        if (nmrSpectrum && nmrSpectrum.sd) {
            nucleus = nmrSpectrum.getNucleus(0);
            observe = nmrSpectrum.observeFrequencyX();
        }

        if (nmrSpectrum) {
            API.createData('annotationsNMR1d', GUI.annotations1D(ranges, {
                line: 1,
                fillColor: 'lightgreen',
                strokeWidth: 0
            }));
        }

        API.createData('acsNMR1d', SD.getACS(ranges, {
            rangeForMultiplet: true,
            nucleus,
            observe
        }));
    }

    getNumberHydrogens() {
        const mf = getData(this.sample, 'mf') + '';
        if (mf) {
            const chemcalc = CCE.analyseMF(mf);
            if (chemcalc && chemcalc.atoms && chemcalc.atoms.H) {
                return chemcalc.atoms.H || 100;
            }
        }
        return 100;
    }

    updateIntegralOptionsFromMF() {
        var options = API.getData('nmr1hOptions');
        const currentIntegral = Number(options.integral);
        const newIntegral = this.getNumberHydrogens();
        if (currentIntegral !== newIntegral) {
            options.setChildSync(['integral'], newIntegral);
        }
    }

    // todo : migrate this code to spectra-data-ranges
    getRangesTotalIntegral() {
        var ranges = API.getData('currentNmrRanges') || [];
        let sum = 0;
        for (const range of ranges) {
            sum += range.integral;
        }
        return sum;
    }

    updateIntegralOptionsFromRanges() {
        var options = API.getData('nmr1hOptions');
        const currentIntegral = Number(options.integral);
        const newIntegral = Math.round(this.getRangesTotalIntegral());
        if (currentIntegral !== newIntegral) {
            options.setChildSync(['integral'], newIntegral);
        }
    }

    async rangesHasChanged() {
        const ranges = this.getCurrentRanges();
        await this.updateIntegralsFromSpectrum();
        const newRangesID = this._getRangesID(ranges);

        this.ensureHighlights(ranges, this.previousRangesID !== newRangesID);
        this.previousRangesID = newRangesID;
    }

    ensureHighlights(forceTrigger) {
        const ranges = this.getCurrentRanges();
        const highlightWasUpdated = GUI.ensureRangesHighlight(ranges);
        if (highlightWasUpdated || forceTrigger) {
            ranges.triggerChange();
            this._createNMRannotationsAndACS();
        }
    }

    _getRangesID(ranges) {
        return ranges.map((range) => {
            return `i: ${Number(range.integral)} from: ${Number(range.from)} to: ${Number(range.to)}`;
        }).sort().join();
    }

    initializeNMROptions() {
        API.createData('nmr1hOptions', {
            noiseFactor: 0.8,
            clean: 0.5,
            compile: true,
            optimize: false,
            integralType: 'sum',
            integral: this.getNumberHydrogens(),
            type: '1H',
            removeImpurities: {
                useIt: false,
                error: 0.025
            }
        });

        API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short);
    }
}

module.exports = Nmr1dManager;
<|endoftext|>


<commit_before>import * as util from "../util";

export function addOptionsExtensionsToView(inputView, spec) {
  var optionsView;
  var isContainerInput = inputView.matches("[data-lynx-hints~=container]");

  inputView.lynxConnectOptions = function () {
    var nearestOptionsView = util.findNearestView(inputView, "[data-lynx-name='" + spec.options + "']");

    if (optionsView && optionsView === nearestOptionsView) return;
    if (optionsView) inputView.lynxDisconnectOptions();
    if (!nearestOptionsView) return;

    var optionValueHint = isContainerInput ? spec.children.hints[0] : spec.hints[0];
    var optionValueViews = nearestOptionsView.querySelectorAll("[data-lynx-hints~='" + optionValueHint + "']");

    exports.initializeOptionsInterface(nearestOptionsView, inputView, isContainerInput);

    Array.from(optionValueViews).forEach(optionValueView => {
      var optionView = exports.findOptionView(nearestOptionsView, optionValueView);
      if (!optionView) return;
      exports.initializeOptionInterface(nearestOptionsView, optionView, optionValueView, inputView);
    });

    inputView.lynxDisconnectOptions = function () {
      if (!optionsView) return;
      optionsView.lynxDisconnectOptions();
      optionsView = null;
    };

    optionsView = nearestOptionsView;

    exports.raiseOptionsConnectedEvent(nearestOptionsView);
  };

  function disconnectOptions(evt) {
    if (evt.srcElement === inputView) {
      inputView.removeEventListener("jsua-attach", connectOptions);
      inputView.removeEventListener("jsua-detach", disconnectOptions);
    }

    inputView.lynxDisconnectOptions();
  }

  function connectOptions() {
    inputView.lynxConnectOptions();
  }

  inputView.addEventListener("jsua-attach", connectOptions);
  inputView.addEventListener("jsua-detach", disconnectOptions);
}

export function initializeOptionsInterface(optionsView, inputView, isContainerInput) {
  optionsView.lynxOptions = [];

  optionsView.lynxToggleOption = function (optionView) {
    if (isContainerInput) {
      optionView.lynxToggleSelected();

      if (optionView.lynxGetSelected()) {
        inputView.lynxAddValue(optionView.lynxGetValue());
      } else {
        inputView.lynxRemoveValue(optionView.lynxGetValue());
      }
    } else {
      let selectedOptionView = optionsView.querySelector("[data-lynx-option-selected=true]");

      optionView.lynxToggleSelected();
      if (selectedOptionView && selectedOptionView !== optionView) selectedOptionView.lynxToggleSelected();

      if (optionView.lynxGetSelected()) {
        inputView.lynxSetValue( optionView.lynxGetValue() );
      } else {
        inputView.lynxClearValue();
      }
    }
  };

  function inputChanged() {
    var values = inputView.lynxGetValue();

    if (!Array.isArray(values)) values = [values];

    optionsView.lynxOptions.forEach(optionView => {
      var selected = values.indexOf(optionView.lynxGetValue()) > -1;
      optionView.lynxSetSelected(selected);
    });
  }

  inputView.addEventListener("change", inputChanged);

  optionsView.lynxDisconnectOptions = function () {
    inputView.removeEventListener("change", inputChanged);
    var optionViews = optionsView.lynxOptions;
    optionsView.lynxOptions.forEach(optionView => optionView.lynxDisconnectOption());
    delete optionsView.lynxOptions;
    delete optionsView.lynxToggleOption;
    delete optionsView.lynxDisconnectOptions;
    exports.raiseOptionsDisonnectedEvent(optionsView, optionViews);
  };
}

export function initializeOptionInterface(optionsView, optionView, optionValueView, inputView) {
  optionView.lynxSetSelected = function (selected) {
    if (selected === optionView.lynxGetSelected()) return;
    optionView.setAttribute("data-lynx-option-selected", selected);
    exports.raiseOptionSelectedChangeEvent(optionView);
  };

  optionView.lynxGetSelected = function () {
    var selected = optionView.getAttribute("data-lynx-option-selected");
    return "true" === selected;
  };

  if (optionView !== optionValueView) {
    optionView.lynxGetValue = function () {
      return optionValueView.lynxGetValue();
    };
  }

  optionView.lynxToggleSelected = function () {
    if (optionView.lynxGetSelected()) {
      optionView.lynxSetSelected(false);
    } else {
      optionView.lynxSetSelected(true);
    }
  };

  function optionClicked(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    optionsView.lynxToggleOption(optionView);
  }

  optionView.addEventListener("click", optionClicked);

  optionView.lynxDisconnectOption = function () {
    optionView.removeEventListener("click", optionClicked);
    optionView.removeAttribute("data-lynx-option-selected");
    delete optionView.lynxSetSelected;
    delete optionView.lynxGetSelected;
    if (optionView !== optionValueView) delete optionView.lynxGetValue;
    delete optionView.lynxToggleSelected;
    delete optionView.lynxDisconnectOption;
  };

  optionsView.lynxOptions.push(optionView);
  optionView.setAttribute("data-lynx-option-selected", false);
  optionView.lynxSetSelected( inputView.lynxHasValue( optionView.lynxGetValue() ) );
}

export function raiseOptionSelectedChangeEvent(optionView) {
  var changeEvent = document.createEvent("Event");

  if (optionView.lynxGetSelected()) {
    changeEvent.initEvent("lynx-option-selected", true, false);
  } else {
    changeEvent.initEvent("lynx-option-deselected", true, false);
  }

  optionView.dispatchEvent(changeEvent);
}

export function raiseOptionsConnectedEvent(optionsView) {
  var changeEvent = document.createEvent("Event");
  changeEvent.initEvent("lynx-options-connected", true, false);
  optionsView.dispatchEvent(changeEvent);
}

export function raiseOptionsDisonnectedEvent(optionsView, optionViews) {
  var changeEvent = document.createEvent("Event");
  changeEvent.initEvent("lynx-options-disconnected", true, false);
  changeEvent.lynxOptions = optionViews;
  optionsView.dispatchEvent(changeEvent);
}

export function findOptionView(optionsView, optionValueView) {
  var currentView = optionValueView;

  do {
    if (currentView.matches("[data-lynx-option=true]")) return currentView;
    currentView = currentView.parentElement;
  } while (currentView !== optionsView);

  return null;
}
<commit_msg>Options Should Recalculate On Attach<commit_after>import * as util from "../util";

export function addOptionsExtensionsToView(inputView, spec) {
  var optionsView, appView;
  var isContainerInput = inputView.matches("[data-lynx-hints~=container]");

  inputView.lynxConnectOptions = function () {
    var nearestOptionsView = util.findNearestView(inputView, "[data-lynx-name='" + spec.options + "']");

    if (optionsView) inputView.lynxDisconnectOptions();
    if (!nearestOptionsView) return;

    var optionValueHint = isContainerInput ? spec.children.hints[0] : spec.hints[0];
    var optionValueViews = nearestOptionsView.querySelectorAll("[data-lynx-hints~='" + optionValueHint + "']");

    exports.initializeOptionsInterface(nearestOptionsView, inputView, isContainerInput);

    Array.from(optionValueViews).forEach(optionValueView => {
      var optionView = exports.findOptionView(nearestOptionsView, optionValueView);
      if (!optionView) return;
      exports.initializeOptionInterface(nearestOptionsView, optionView, optionValueView, inputView);
    });

    inputView.lynxDisconnectOptions = function () {
      if (!optionsView) return;
      optionsView.lynxDisconnectOptions();
      optionsView = null;
    };

    optionsView = nearestOptionsView;

    exports.raiseOptionsConnectedEvent(nearestOptionsView);
  };

  function onAppViewAttach() {
    inputView.lynxConnectOptions();
  }

  function onInputViewDetach(evt) {
    if (evt.srcElement === inputView) {
      inputView.removeEventListener("jsua-detach", onInputViewDetach);
    }

    if (appView) {
      appView.removeEventListener("jsua-attach", onAppViewAttach);
    }

    inputView.lynxDisconnectOptions();
  }

  function onInputViewAttach() {
    inputView.removeEventListener("jsua-attach", onInputViewAttach);

    appView = util.findNearestAncestorView(inputView, "[data-jsua-context~=app]");

    if (!appView) {
      console.log("Unable to find ancestor view matching [data-jsua-context~=app]. (Lynx Options)");
      inputView.lynxConnectOptions();
    } else {
      appView.addEventListener("jsua-attach", onAppViewAttach);
    }
  }

  inputView.addEventListener("jsua-attach", onInputViewAttach);
  inputView.addEventListener("jsua-detach", onInputViewDetach);
}

export function initializeOptionsInterface(optionsView, inputView, isContainerInput) {
  optionsView.lynxOptions = [];

  optionsView.lynxToggleOption = function (optionView) {
    if (isContainerInput) {
      optionView.lynxToggleSelected();

      if (optionView.lynxGetSelected()) {
        inputView.lynxAddValue(optionView.lynxGetValue());
      } else {
        inputView.lynxRemoveValue(optionView.lynxGetValue());
      }
    } else {
      let selectedOptionView = optionsView.querySelector("[data-lynx-option-selected=true]");

      optionView.lynxToggleSelected();
      if (selectedOptionView && selectedOptionView !== optionView) selectedOptionView.lynxToggleSelected();

      if (optionView.lynxGetSelected()) {
        inputView.lynxSetValue( optionView.lynxGetValue() );
      } else {
        inputView.lynxClearValue();
      }
    }
  };

  function inputChanged() {
    var values = inputView.lynxGetValue();

    if (!Array.isArray(values)) values = [values];

    optionsView.lynxOptions.forEach(optionView => {
      var selected = values.indexOf(optionView.lynxGetValue()) > -1;
      optionView.lynxSetSelected(selected);
    });
  }

  inputView.addEventListener("change", inputChanged);

  optionsView.lynxDisconnectOptions = function () {
    inputView.removeEventListener("change", inputChanged);
    var optionViews = optionsView.lynxOptions;
    optionsView.lynxOptions.forEach(optionView => optionView.lynxDisconnectOption());
    delete optionsView.lynxOptions;
    delete optionsView.lynxToggleOption;
    delete optionsView.lynxDisconnectOptions;
    exports.raiseOptionsDisonnectedEvent(optionsView, optionViews);
  };
}

export function initializeOptionInterface(optionsView, optionView, optionValueView, inputView) {
  optionView.lynxSetSelected = function (selected) {
    if (selected === optionView.lynxGetSelected()) return;
    optionView.setAttribute("data-lynx-option-selected", selected);
    exports.raiseOptionSelectedChangeEvent(optionView);
  };

  optionView.lynxGetSelected = function () {
    var selected = optionView.getAttribute("data-lynx-option-selected");
    return "true" === selected;
  };

  if (optionView !== optionValueView) {
    optionView.lynxGetValue = function () {
      return optionValueView.lynxGetValue();
    };
  }

  optionView.lynxToggleSelected = function () {
    if (optionView.lynxGetSelected()) {
      optionView.lynxSetSelected(false);
    } else {
      optionView.lynxSetSelected(true);
    }
  };

  function optionClicked(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    optionsView.lynxToggleOption(optionView);
  }

  optionView.addEventListener("click", optionClicked);

  optionView.lynxDisconnectOption = function () {
    optionView.removeEventListener("click", optionClicked);
    optionView.removeAttribute("data-lynx-option-selected");
    delete optionView.lynxSetSelected;
    delete optionView.lynxGetSelected;
    if (optionView !== optionValueView) delete optionView.lynxGetValue;
    delete optionView.lynxToggleSelected;
    delete optionView.lynxDisconnectOption;
  };

  optionsView.lynxOptions.push(optionView);
  optionView.setAttribute("data-lynx-option-selected", false);
  optionView.lynxSetSelected( inputView.lynxHasValue( optionView.lynxGetValue() ) );
}

export function raiseOptionSelectedChangeEvent(optionView) {
  var changeEvent = document.createEvent("Event");

  if (optionView.lynxGetSelected()) {
    changeEvent.initEvent("lynx-option-selected", true, false);
  } else {
    changeEvent.initEvent("lynx-option-deselected", true, false);
  }

  optionView.dispatchEvent(changeEvent);
}

export function raiseOptionsConnectedEvent(optionsView) {
  var changeEvent = document.createEvent("Event");
  changeEvent.initEvent("lynx-options-connected", true, false);
  optionsView.dispatchEvent(changeEvent);
}

export function raiseOptionsDisonnectedEvent(optionsView, optionViews) {
  var changeEvent = document.createEvent("Event");
  changeEvent.initEvent("lynx-options-disconnected", true, false);
  changeEvent.lynxOptions = optionViews;
  optionsView.dispatchEvent(changeEvent);
}

export function findOptionView(optionsView, optionValueView) {
  var currentView = optionValueView;

  do {
    if (currentView.matches("[data-lynx-option=true]")) return currentView;
    currentView = currentView.parentElement;
  } while (currentView !== optionsView);

  return null;
}
<|endoftext|>


<commit_before>
var mime = require('mime'),
    uuid = require('node-uuid'),
    aws = require('aws-sdk'),
    express = require('express');

function checkTrailingSlash(path) {
    if (path && path[path.length-1] != '/') {
        path += '/';
    }
    return path;
}

function S3Router(options) {

    var S3_BUCKET = options.bucket,
        getFileKeyDir = options.getFileKeyDir || function() { return ""; };

    if (!S3_BUCKET) {
        throw new Error("S3_BUCKET is required.");
    }

    var router = express.Router();

    /**
     * Redirects image requests with a temporary signed URL, giving access
     * to GET an image.
     */
    router.get(/\/img\/(.*)/, function(req, res) {
        var params = {
            Bucket: S3_BUCKET,
            Key: checkTrailingSlash(getFileKeyDir(req)) + req.params[0]
        };
        var s3 = new aws.S3();
        s3.getSignedUrl('getObject', params, function(err, url) {
            res.redirect(url);
        });
    });

    /**
     * Returns an object with `signedUrl` and `publicUrl` properties that
     * give temporary access to PUT an object in an S3 bucket.
     */
    router.get('/sign', function(req, res) {
        var filename = uuid.v4() + "_" + req.query.objectName;
        var mimeType = mime.lookup(filename);
        var fileKey = getFileKeyDir(req) + '/' + filename;

        var s3 = new aws.S3();
        var params = {
            Bucket: S3_BUCKET,
            Key: fileKey,
            Expires: 60,
            ContentType: mimeType,
            ACL: 'private'
        };
        s3.getSignedUrl('putObject', params, function(err, data) {
            if (err) {
                console.log(err);
                return res.send(500, "Cannot create S3 signed URL");
            }
            res.json({
                signedUrl: data,
                publicUrl: '/s3/img/' + filename,
                filename: filename
            });
        });
    });

    return router;
}

module.exports = S3Router;
<commit_msg>Add option for ACL<commit_after>
var mime = require('mime'),
    uuid = require('node-uuid'),
    aws = require('aws-sdk'),
    express = require('express');

function checkTrailingSlash(path) {
    if (path && path[path.length-1] != '/') {
        path += '/';
    }
    return path;
}

function S3Router(options) {

    var S3_BUCKET = options.bucket,
        ACL = options.ACL,
        getFileKeyDir = options.getFileKeyDir || function() { return ""; };

    if (!S3_BUCKET) {
        throw new Error("S3_BUCKET is required.");
    }

    var router = express.Router();

    /**
     * Redirects image requests with a temporary signed URL, giving access
     * to GET an image.
     */
    router.get(/\/img\/(.*)/, function(req, res) {
        var params = {
            Bucket: S3_BUCKET,
            Key: checkTrailingSlash(getFileKeyDir(req)) + req.params[0]
        };
        var s3 = new aws.S3();
        s3.getSignedUrl('getObject', params, function(err, url) {
            res.redirect(url);
        });
    });

    /**
     * Returns an object with `signedUrl` and `publicUrl` properties that
     * give temporary access to PUT an object in an S3 bucket.
     */
    router.get('/sign', function(req, res) {
        var filename = uuid.v4() + "_" + req.query.objectName;
        var mimeType = mime.lookup(filename);
        var fileKey = getFileKeyDir(req) + '/' + filename;

        var s3 = new aws.S3();
        var params = {
            Bucket: S3_BUCKET,
            Key: fileKey,
            Expires: 60,
            ContentType: mimeType,
            ACL: options.ACL ? options.ACL : 'private'
        };
        s3.getSignedUrl('putObject', params, function(err, data) {
            if (err) {
                console.log(err);
                return res.send(500, "Cannot create S3 signed URL");
            }
            res.json({
                signedUrl: data,
                publicUrl: '/s3/img/' + filename,
                filename: filename
            });
        });
    });

    return router;
}

module.exports = S3Router;
<|endoftext|>


<commit_before>/**
 * Taken, CommonJS-ified, and heavily modified from:
 * https://github.com/flyingsparx/NodeDirectUploader
 */

S3Upload.prototype.signingUrl = '/sign-s3';
S3Upload.prototype.fileElement = null;

S3Upload.prototype.onFinishS3Put = function(signResult) {
    return console.log('base.onFinishS3Put()', signResult.publicUrl);
};

S3Upload.prototype.onProgress = function(percent, status) {
    return console.log('base.onProgress()', percent, status);
};

S3Upload.prototype.onError = function(status) {
    return console.log('base.onError()', status);
};

function S3Upload(options) {
    if (options == null) {
        options = {};
    }
    for (option in options) {
        if (options.hasOwnProperty(option)) {
            this[option] = options[option];
        }
    }
    this.handleFileSelect(this.fileElement);
}

S3Upload.prototype.handleFileSelect = function(fileElement) {
    this.onProgress(0, 'Upload started.');
    var files = fileElement.files;
    var result = [];
    for (var i=0; i < files.length; i++) {
        var f = files[i];
        result.push(this.uploadFile(f));
    }
    return result;
};

S3Upload.prototype.createCORSRequest = function(method, url) {
    var xhr = new XMLHttpRequest();

    if (xhr.withCredentials != null) {
        xhr.open(method, url, true);
    }
    else if (typeof XDomainRequest !== "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
    }
    else {
        xhr = null;
    }
    return xhr;
};

S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
    var xhr = new XMLHttpRequest();
    var fileName = file.name.replace(/[^\w]/g, "");
    xhr.open('GET', this.signingUrl + '?objectName=' + fileName, true);
    xhr.overrideMimeType && xhr.overrideMimeType('text/plain; charset=x-user-defined');
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var result;
            try {
                result = JSON.parse(xhr.responseText);
            } catch (error) {
                this.onError('Invalid signing server response JSON: ' + xhr.responseText);
                return false;
            }
            return callback(result);
        } else if (xhr.readyState === 4 && xhr.status !== 200) {
            return this.onError('Could not contact request signing server. Status = ' + xhr.status);
        }
    }.bind(this);
    return xhr.send();
};

S3Upload.prototype.uploadToS3 = function(file, signResult) {
    var xhr = this.createCORSRequest('PUT', signResult.signedUrl);
    if (!xhr) {
        this.onError('CORS not supported');
    } else {
        xhr.onload = function() {
            if (xhr.status === 200) {
                this.onProgress(100, 'Upload completed.');
                return this.onFinishS3Put(signResult);
            } else {
                return this.onError('Upload error: ' + xhr.status);
            }
        }.bind(this);
        xhr.onerror = function() {
            return this.onError('XHR error.');
        }.bind(this);
        xhr.upload.onprogress = function(e) {
            var percentLoaded;
            if (e.lengthComputable) {
                percentLoaded = Math.round((e.loaded / e.total) * 100);
                return this.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
            }
        }.bind(this);
    }
    xhr.setRequestHeader('Content-Type', file.type);
    xhr.setRequestHeader('x-amz-acl', 'public-read');
    return xhr.send(file);
};

S3Upload.prototype.uploadFile = function(file) {
    return this.executeOnSignedUrl(file, function(signResult) {
        return this.uploadToS3(file, signResult);
    }.bind(this));
};

module.exports = S3Upload;
<commit_msg>add underscore to preserve space-like character<commit_after>/**
 * Taken, CommonJS-ified, and heavily modified from:
 * https://github.com/flyingsparx/NodeDirectUploader
 */

S3Upload.prototype.signingUrl = '/sign-s3';
S3Upload.prototype.fileElement = null;

S3Upload.prototype.onFinishS3Put = function(signResult) {
    return console.log('base.onFinishS3Put()', signResult.publicUrl);
};

S3Upload.prototype.onProgress = function(percent, status) {
    return console.log('base.onProgress()', percent, status);
};

S3Upload.prototype.onError = function(status) {
    return console.log('base.onError()', status);
};

function S3Upload(options) {
    if (options == null) {
        options = {};
    }
    for (option in options) {
        if (options.hasOwnProperty(option)) {
            this[option] = options[option];
        }
    }
    this.handleFileSelect(this.fileElement);
}

S3Upload.prototype.handleFileSelect = function(fileElement) {
    this.onProgress(0, 'Upload started.');
    var files = fileElement.files;
    var result = [];
    for (var i=0; i < files.length; i++) {
        var f = files[i];
        result.push(this.uploadFile(f));
    }
    return result;
};

S3Upload.prototype.createCORSRequest = function(method, url) {
    var xhr = new XMLHttpRequest();

    if (xhr.withCredentials != null) {
        xhr.open(method, url, true);
    }
    else if (typeof XDomainRequest !== "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
    }
    else {
        xhr = null;
    }
    return xhr;
};

S3Upload.prototype.executeOnSignedUrl = function(file, callback) {
    var xhr = new XMLHttpRequest();
    var fileName = file.name.replace(/[^\w]/g, "_");
    xhr.open('GET', this.signingUrl + '?objectName=' + fileName, true);
    xhr.overrideMimeType && xhr.overrideMimeType('text/plain; charset=x-user-defined');
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var result;
            try {
                result = JSON.parse(xhr.responseText);
            } catch (error) {
                this.onError('Invalid signing server response JSON: ' + xhr.responseText);
                return false;
            }
            return callback(result);
        } else if (xhr.readyState === 4 && xhr.status !== 200) {
            return this.onError('Could not contact request signing server. Status = ' + xhr.status);
        }
    }.bind(this);
    return xhr.send();
};

S3Upload.prototype.uploadToS3 = function(file, signResult) {
    var xhr = this.createCORSRequest('PUT', signResult.signedUrl);
    if (!xhr) {
        this.onError('CORS not supported');
    } else {
        xhr.onload = function() {
            if (xhr.status === 200) {
                this.onProgress(100, 'Upload completed.');
                return this.onFinishS3Put(signResult);
            } else {
                return this.onError('Upload error: ' + xhr.status);
            }
        }.bind(this);
        xhr.onerror = function() {
            return this.onError('XHR error.');
        }.bind(this);
        xhr.upload.onprogress = function(e) {
            var percentLoaded;
            if (e.lengthComputable) {
                percentLoaded = Math.round((e.loaded / e.total) * 100);
                return this.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing.' : 'Uploading.');
            }
        }.bind(this);
    }
    xhr.setRequestHeader('Content-Type', file.type);
    xhr.setRequestHeader('x-amz-acl', 'public-read');
    return xhr.send(file);
};

S3Upload.prototype.uploadFile = function(file) {
    return this.executeOnSignedUrl(file, function(signResult) {
        return this.uploadToS3(file, signResult);
    }.bind(this));
};

module.exports = S3Upload;
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var WriteData = require('sivart-data/WriteBuildData');

// Get info
var logDir = process.env.SIVART_BASE_LOG_DIR;
var repoName = process.env.TRAVIS_REPO_SLUG;
var branch = process.env.TRAVIS_BRANCH;
var buildId = process.env.SIVART_BUILD_ID;
var buildNumber = process.env.SIVART_BUILD_NUMBER;
var writeData = new WriteData(repoName);

// Save environment (for internal debugging)
fs.writeFileSync(path.join(logDir, 'environment.json'), JSON.stringify(process.env));

// Save all files in logDir...
var files = fs.readdirSync(logDir).map(function(file) {
  return path.join(logDir, file);
});

// ..and save these files too
files.push(
  '/tmp/user-script.sh',
  '/tmp/user-script.log',
  '/var/log/startupscript.log'
);

// Save files to here within bucket
//  branch name / build id / build number
var basepath = path.join(branch, String(buildId), String(buildNumber));
writeData.writeFilesToBucket(basepath, files, function(failures) {
  if (failures) {
    // write out errors to default error bucket
    var errorWriteData = new WriteData('error');
    fs.writeFileSync('/tmp/save.error.json', JSON.stringify({ data:
      {
        logDir: logDir,
        repoName: repoName,
        branch: branch,
        buildId: buildId,
        buildNumber: buildNumber,
        failures: failures
      }
    }, null, ' '));
    errorWriteData.writeFileToBucket('/tmp/save.error.json', new Date().getTime + '.json', function() {
      process.exit(1);
    });
  }
});
<commit_msg>save branch files under 'branch-*' to make them easier to find later<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var WriteData = require('sivart-data/WriteBuildData');

// Get info
var logDir = process.env.SIVART_BASE_LOG_DIR;
var repoName = process.env.TRAVIS_REPO_SLUG;
var branch = process.env.TRAVIS_BRANCH;
var buildId = process.env.SIVART_BUILD_ID;
var buildNumber = process.env.SIVART_BUILD_NUMBER;
var writeData = new WriteData(repoName);

// Save environment (for internal debugging)
fs.writeFileSync(path.join(logDir, 'environment.json'), JSON.stringify(process.env));

// Save all files in logDir...
var files = fs.readdirSync(logDir).map(function(file) {
  return path.join(logDir, file);
});

// ..and save these files too
files.push(
  '/tmp/user-script.sh',
  '/tmp/user-script.log',
  '/var/log/startupscript.log'
);

// Save files to here within bucket
//  branch name / build id / build number
var basepath = path.join('branch-' + branch, String(buildId), String(buildNumber));
writeData.writeFilesToBucket(basepath, files, function(failures) {
  if (failures) {
    // write out errors to default error bucket
    var errorWriteData = new WriteData('error');
    fs.writeFileSync('/tmp/save.error.json', JSON.stringify({ data:
      {
        logDir: logDir,
        repoName: repoName,
        branch: branch,
        buildId: buildId,
        buildNumber: buildNumber,
        failures: failures
      }
    }, null, ' '));
    errorWriteData.writeFileToBucket('/tmp/save.error.json', new Date().getTime + '.json', function() {
      process.exit(1);
    });
  }
});
<|endoftext|>


<commit_before>var React = require('react');
var ReactDOM = require('react-dom');

var ExerciseBox = React.createClass({
  handleSubmit(e){

    e.preventDefault();

    var problem = ReactDOM.findDOMNode(this.refs.problem).value.trim();
    var answer = ReactDOM.findDOMNode(this.refs.answer).value.trim();

    if(!problem){
      return;
    }

    var data = ({problem: problem, answer: answer})

  $.ajax({
     url: this.props.url,
     dataType: 'json',
     data: data,
     type:'POST',
     success: function(response){
       console.log("posting data!",data, response)
       document.location='/post_exercise'
     }.bind(this),
     error: function(xhr, status, err){
       console.log("not posting data!")
       console.error(this.props.url, status, err.toString());
     }.bind(this)
   })
 },
 handleUpdate(id){

    var id = id;
    var problem = React.findDOMNode(this.refs.problem).value.trim();
    var answer = React.findDOMNode(this.refs.answer).value.trim();

    console.log(id);
    if(!problem){
      return;
    }

    var data = ({problem: problem, answer: answer});

    $.ajax({
      url: this.props.url + id,
      dataType: 'json',
      data: data,
      type:'PUT',
      success: function(response){
        console.log("Updating Exercise!", data, response)
        document.location='/post_exercise'
      }.bind(this),
      error: function(xhr, status, err){
        console.log("Did not <update></update>!")
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    })
  },

 render: function() {
   return (

Enter New Exercises

        <form>

              Exercise Problem
              <textarea rows="15" type="text" className="form-control" ref="problem" placeholder="Exercise Problem" />

              Exercise Answer
              <textarea rows="15" type="text" ref="answer" className="form-control" placeholder="Exercise Answer" />

              <button onClick={this.handleSubmit} type="submit" className="btn btn-default"> Submit </button>

        </form>

    )
  }
});

ReactDOM.render(<ExerciseBox url='/api/exercises/'/>, document.getElementById('post-exercise'));
<commit_msg>postExerciseBox.js is linted<commit_after>var React = require('react');
var ReactDOM = require('react-dom');

var ExerciseBox = React.createClass({
  propTypes: {
   url: React.PropTypes.string.isRequired
 },
  handleSubmit(e) {

   e.preventDefault();

   var problem = ReactDOM.findDOMNode(this.refs.problem).value.trim();
   var answer = ReactDOM.findDOMNode(this.refs.answer).value.trim();

   if (!problem) {
     return;
   }

   var data = ({problem: problem, answer: answer});

   $.ajax({
     url: this.props.url,
     dataType: 'json',
     data: data,
     type: 'POST',
     success: function(response) {
       console.log('posting data!', data, response);
       document.location = '/post_exercise';
     },
     error: function(xhr, status, err) {
       console.log('not posting data!');
       console.error(this.props.url, status, err.toString());
     }.bind(this)
   });
 },
  handleUpdate(id) {

   var problem = React.findDOMNode(this.refs.problem).value.trim();
   var answer = React.findDOMNode(this.refs.answer).value.trim();

   console.log(id);
   if (!problem) {
     return;
   }

   var data = ({problem: problem, answer: answer});

   $.ajax({
     url: this.props.url + id,
     dataType: 'json',
     data: data,
     type: 'PUT',
     success: function(response) {
       console.log('Updating Exercise!', data, response);
       document.location = '/post_exercise';
     },
     error: function(xhr, status, err) {
       console.log('Did not <update></update>!');
       console.error(this.props.url, status, err.toString());
     }.bind(this)
   });
 },

  render: function() {
   return (

Enter New Exercises

       <form>

             Exercise Problem
             <textarea rows="15" type="text" className="form-control" ref="problem" placeholder="Exercise Problem" />

             Exercise Answer
             <textarea rows="15" type="text" ref="answer" className="form-control" placeholder="Exercise Answer" />

             <button onClick={this.handleSubmit} type="submit" className="btn btn-default"> Submit </button>

       </form>

   );
 }
});

ReactDOM.render(<ExerciseBox url = "/api/exercises/"/>, document.getElementById('post-exercise'));
<|endoftext|>