<commit_before>import m from 'mithril';
import _ from 'underscore';
import { catarse, commonPayment } from '../api';
import models from '../models';
import h from '../h';
import loadMoreBtn from '../c/load-more-btn';
import FilterDropdown from '../c/filter-dropdown';
import projectDashboardMenu from '../c/project-dashboard-menu';
import dashboardSubscriptionCard from '../c/dashboard-subscription-card';
import projectsSubscriptionReportVM from '../vms/projects-subscription-report-vm';
import projectsContributionReportVM from '../vms/projects-contribution-report-vm';

const projectSubscriptionReport = {
    controller(args) {
        const filterVM = projectsSubscriptionReportVM,
            catarseVM = projectsContributionReportVM,
            error = m.prop(false),
            loader = m.prop(true),
            rewards = m.prop([]),
            subscriptions = commonPayment.paginationVM(models.userSubscription, 'created_at.desc', {
                Prefer: 'count=exact'
            }),
            submit = () => {
                if (filterVM.reward_external_id() === 'null') {
                    subscriptions.firstPage(filterVM.withNullParameters()).then(null);
                } else {
                    subscriptions.firstPage(filterVM.parameters()).then(null);
                }

                return false;
            },
            filterBuilder = [
                {
                    label: 'reward_filter',
                    component: FilterDropdown,
                    data: {
                        label: 'Recompensa',
                        onchange: submit,
                        name: 'reward_external_id',
                        vm: filterVM.reward_external_id,
                        wrapper_class: '.w-sub-col.w-col.w-col-4',
                        options: []
                    }
                },
                {
                    label: 'status_filter',
                    component: FilterDropdown,
                    data: {
                        label: 'Status da assinatura',
                        onchange: submit,
                        name: 'status',
                        vm: filterVM.status,
                        wrapper_class: '.w-sub-col.w-col.w-col-4',
                        options: [{
                            value: '',
                            option: 'Todos'
                        },
                        {
                            value: 'active',
                            option: 'Ativa'
                        },
                        {
                            value: 'started',
                            option: 'Iniciada'
                        },
                        {
                            value: 'inactive',
                            option: 'Inativa'
                        }
                        ]
                    }
                },
                {
                    label: 'payment_filter',
                    component: FilterDropdown,
                    data: {
                        label: 'Meio de pagamento',
                        onchange: submit,
                        name: 'payment_method',
                        vm: filterVM.payment_method,
                        wrapper_class: '.w-sub-col.w-col.w-col-4',
                        options: [{
                            value: '',
                            option: 'Todos'
                        },
                        {
                            value: 'credit_card',
                            option: 'Cartão de crédito'
                        },
                        {
                            value: 'boleto',
                            option: 'Boleto'
                        }
                        ]
                    }
                }

            ],
            handleError = () => {
                error(true);
                loader(false);
                m.redraw();
            },
            project = m.prop([{}]);

        catarseVM.project_id(args.project_id);

        const lReward = catarse.loaderWithToken(models.rewardDetail.getPageOptions({
            project_id: `eq.${catarseVM.project_id()}`
        }));

        lReward.load().then(rewards);
        const mapRewardsToOptions = () => {
            let options = [];
            if (!lReward()) {
                options = _.map(rewards(), r => ({
                    value: r.id,
                    option: `R$ ${h.formatNumber(r.minimum_value, 2, 3)} - ${(r.title ? r.title : r.description).substring(0, 20)}`
                }));
            }

            options.unshift({
                value: null,
                option: 'Sem recompensa'
            });

            options.unshift({
                value: '',
                option: 'Todas'
            });

            return options;
        };

        const lProject = catarse.loaderWithToken(models.projectDetail.getPageOptions({
            project_id: `eq.${catarseVM.project_id()}`
        }));

        lProject.load().then((data) => {
            filterVM.project_id(_.first(data).common_id);
            subscriptions.firstPage(filterVM.parameters()).then(() => {
                loader(false);
            }).catch(handleError);
            project(data);
        });

        return {
            filterVM,
            mapRewardsToOptions,
            filterBuilder,
            submit,
            subscriptions,
            lProject,
            project
        };
    },
    view(ctrl) {
        const subsCollection = ctrl.subscriptions.collection(),
            filterBuilder = ctrl.filterBuilder,
            statusFilter = _.findWhere(filterBuilder, {
                label: 'status_filter'
            }),
            rewardFilter = _.findWhere(filterBuilder, {
                label: 'reward_filter'
            }),
            paymentFilter = _.findWhere(filterBuilder, {
                label: 'payment_filter'
            });
        rewardFilter.data.options = ctrl.mapRewardsToOptions();
        if (!ctrl.lProject()) {
            return m('div', [
                m.component(projectDashboardMenu, {
                    project: m.prop(_.first(ctrl.project()))
                }),
                m('.dashboard-header',
                    m('.w-container',
                        m('.w-row', [
                            m('.w-col.w-col-3'),
                            m('.w-col.w-col-6',
                                m('.fontsize-larger.fontweight-semibold.lineheight-looser.u-marginbottom-30.u-text-center',
                                    'Base de assinantes'
                                )
                            ),
                            m('.w-col.w-col-3')
                        ])
                    )
                ),
                m('.divider.u-margintop-30'),
                m('.card',
                    m('.w-container',
                        m('.w-form', [
                            m('form', {
                                onsubmit: ctrl.submit
                            },
                                m('.u-margintop-20.w-row', [
                                    m('.w-col.w-col-8.w-col-push-2.u-text-center',
                                        m('.w-row', [
                                            m.component(statusFilter.component, statusFilter.data),
                                            m.component(rewardFilter.component, rewardFilter.data),
                                            m.component(paymentFilter.component, paymentFilter.data)
                                        ])
                                    ),
                                    m('.w-col.w-col-4', '')
                                ])
                            )
                        ])
                    )
                ),
                m('.before-footer.bg-gray.section', [
                    m('.w-container', [
                        m('div',
                            m('.w-row', [
                                m('.u-marginbottom-20.u-text-center-small-only.w-col.w-col-7',
                                    m('.w-inline-block.fontsize-base.u-marginright-10', [
                                        m('span.fontweight-semibold',
                                            ctrl.subscriptions.total()
                                        ),
                                        ' pessoas',
                                        m.trust(' ')
                                    ])
                                ),
                            ])
                        ),
                        m('.u-marginbottom-60', [
                            m('.card.card-secondary.fontsize-smallest.fontweight-semibold.lineheight-tighter.u-marginbottom-10',
                                m('.w-row', [
                                    m('.table-col.w-col.w-col-3',
                                        m('div',
                                            'Assinante'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2',
                                        m('div',
                                            'Recompensa'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-1.u-text-center',
                                        m('div',
                                            'Apoio mensal'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2.u-text-center',
                                        m('div',
                                            'Total apoiado'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2.u-text-center',
                                        m('div',
                                            'Último apoio'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2.u-text-center',
                                        m('div',
                                            'Status da Assinatura'
                                        )
                                    )
                                ])
                            ),
                            m('.fontsize-small', [
                                _.map(subsCollection, subscription =>
                                    m(dashboardSubscriptionCard, { subscription }))
                            ])
                        ])
                    ]),
                    m('.bg-gray.section',
                        m('.w-container',
                            m('.u-marginbottom-60.w-row', [
                                m(loadMoreBtn, {
                                    collection: ctrl.subscriptions,
                                    cssClass: '.w-col-push-4'
                                })
                            ])
                        )
                    )
                ])
            ]);
        }
        return m('', h.loader());
    }
};

export default projectSubscriptionReport;
<commit_msg>adds tooltip to subscriptions report field<commit_after>import m from 'mithril';
import _ from 'underscore';
import { catarse, commonPayment } from '../api';
import models from '../models';
import h from '../h';
import loadMoreBtn from '../c/load-more-btn';
import FilterDropdown from '../c/filter-dropdown';
import projectDashboardMenu from '../c/project-dashboard-menu';
import dashboardSubscriptionCard from '../c/dashboard-subscription-card';
import projectsSubscriptionReportVM from '../vms/projects-subscription-report-vm';
import projectsContributionReportVM from '../vms/projects-contribution-report-vm';

const statusCustomFilter = {
    view: () => m('span', [
        'Status da assinatura ',
        m('a.fontsize-smallest.tooltip-wrapper.fa.fa-question-circle.fontcolor-secondary', {
            href: 'https://suporte.catarse.me/hc/pt-br/articles/115005632746-Catarse-Assinaturas-FAQ-Realizadores#status',
            target: '_blank'
        })
    ])
};

const projectSubscriptionReport = {
    controller(args) {
        const filterVM = projectsSubscriptionReportVM,
            catarseVM = projectsContributionReportVM,
            error = m.prop(false),
            loader = m.prop(true),
            rewards = m.prop([]),
            subscriptions = commonPayment.paginationVM(models.userSubscription, 'created_at.desc', {
                Prefer: 'count=exact'
            }),
            submit = () => {
                if (filterVM.reward_external_id() === 'null') {
                    subscriptions.firstPage(filterVM.withNullParameters()).then(null);
                } else {
                    subscriptions.firstPage(filterVM.parameters()).then(null);
                }

                return false;
            },
            filterBuilder = [
                {
                    label: 'reward_filter',
                    component: FilterDropdown,
                    data: {
                        label: 'Recompensa',
                        onchange: submit,
                        name: 'reward_external_id',
                        vm: filterVM.reward_external_id,
                        wrapper_class: '.w-sub-col.w-col.w-col-4',
                        options: []
                    }
                },
                {
                    label: 'status_filter',
                    component: FilterDropdown,
                    data: {
                        custom_label: [
                            statusCustomFilter,
                            null
                        ],
                        onchange: submit,
                        name: 'status',
                        vm: filterVM.status,
                        wrapper_class: '.w-sub-col.w-col.w-col-4',
                        options: [{
                            value: '',
                            option: 'Todos'
                        },
                        {
                            value: 'active',
                            option: 'Ativa'
                        },
                        {
                            value: 'started',
                            option: 'Iniciada'
                        },
                        {
                            value: 'inactive',
                            option: 'Inativa'
                        }
                        ]
                    }
                },
                {
                    label: 'payment_filter',
                    component: FilterDropdown,
                    data: {
                        label: 'Meio de pagamento',
                        onchange: submit,
                        name: 'payment_method',
                        vm: filterVM.payment_method,
                        wrapper_class: '.w-sub-col.w-col.w-col-4',
                        options: [{
                            value: '',
                            option: 'Todos'
                        },
                        {
                            value: 'credit_card',
                            option: 'Cartão de crédito'
                        },
                        {
                            value: 'boleto',
                            option: 'Boleto'
                        }
                        ]
                    }
                }

            ],
            handleError = () => {
                error(true);
                loader(false);
                m.redraw();
            },
            project = m.prop([{}]);

        catarseVM.project_id(args.project_id);

        const lReward = catarse.loaderWithToken(models.rewardDetail.getPageOptions({
            project_id: `eq.${catarseVM.project_id()}`
        }));

        lReward.load().then(rewards);
        const mapRewardsToOptions = () => {
            let options = [];
            if (!lReward()) {
                options = _.map(rewards(), r => ({
                    value: r.id,
                    option: `R$ ${h.formatNumber(r.minimum_value, 2, 3)} - ${(r.title ? r.title : r.description).substring(0, 20)}`
                }));
            }

            options.unshift({
                value: null,
                option: 'Sem recompensa'
            });

            options.unshift({
                value: '',
                option: 'Todas'
            });

            return options;
        };

        const lProject = catarse.loaderWithToken(models.projectDetail.getPageOptions({
            project_id: `eq.${catarseVM.project_id()}`
        }));

        lProject.load().then((data) => {
            filterVM.project_id(_.first(data).common_id);
            subscriptions.firstPage(filterVM.parameters()).then(() => {
                loader(false);
            }).catch(handleError);
            project(data);
        });

        return {
            filterVM,
            mapRewardsToOptions,
            filterBuilder,
            submit,
            subscriptions,
            lProject,
            project
        };
    },
    view(ctrl) {
        const subsCollection = ctrl.subscriptions.collection(),
            filterBuilder = ctrl.filterBuilder,
            statusFilter = _.findWhere(filterBuilder, {
                label: 'status_filter'
            }),
            rewardFilter = _.findWhere(filterBuilder, {
                label: 'reward_filter'
            }),
            paymentFilter = _.findWhere(filterBuilder, {
                label: 'payment_filter'
            });
        rewardFilter.data.options = ctrl.mapRewardsToOptions();
        if (!ctrl.lProject()) {
            return m('div', [
                m.component(projectDashboardMenu, {
                    project: m.prop(_.first(ctrl.project()))
                }),
                m('.dashboard-header',
                    m('.w-container',
                        m('.w-row', [
                            m('.w-col.w-col-3'),
                            m('.w-col.w-col-6',
                                m('.fontsize-larger.fontweight-semibold.lineheight-looser.u-marginbottom-30.u-text-center',
                                    'Base de assinantes'
                                )
                            ),
                            m('.w-col.w-col-3')
                        ])
                    )
                ),
                m('.divider.u-margintop-30'),
                m('.card',
                    m('.w-container',
                        m('.w-form', [
                            m('form', {
                                onsubmit: ctrl.submit
                            },
                                m('.u-margintop-20.w-row', [
                                    m('.w-col.w-col-8.w-col-push-2.u-text-center',
                                        m('.w-row', [
                                            m.component(statusFilter.component, statusFilter.data),
                                            m.component(rewardFilter.component, rewardFilter.data),
                                            m.component(paymentFilter.component, paymentFilter.data)
                                        ])
                                    ),
                                    m('.w-col.w-col-4', '')
                                ])
                            )
                        ])
                    )
                ),
                m('.before-footer.bg-gray.section', [
                    m('.w-container', [
                        m('div',
                            m('.w-row', [
                                m('.u-marginbottom-20.u-text-center-small-only.w-col.w-col-7',
                                    m('.w-inline-block.fontsize-base.u-marginright-10', [
                                        m('span.fontweight-semibold',
                                            ctrl.subscriptions.total()
                                        ),
                                        ' pessoas',
                                        m.trust(' ')
                                    ])
                                ),
                            ])
                        ),
                        m('.u-marginbottom-60', [
                            m('.card.card-secondary.fontsize-smallest.fontweight-semibold.lineheight-tighter.u-marginbottom-10',
                                m('.w-row', [
                                    m('.table-col.w-col.w-col-3',
                                        m('div',
                                            'Assinante'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2',
                                        m('div',
                                            'Recompensa'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-1.u-text-center',
                                        m('div',
                                            'Apoio mensal'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2.u-text-center',
                                        m('div',
                                            'Total apoiado'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2.u-text-center',
                                        m('div',
                                            'Último apoio'
                                        )
                                    ),
                                    m('.table-col.w-col.w-col-2.u-text-center',
                                        m('div',
                                            'Status da Assinatura'
                                        )
                                    )
                                ])
                            ),
                            m('.fontsize-small', [
                                _.map(subsCollection, subscription =>
                                    m(dashboardSubscriptionCard, { subscription }))
                            ])
                        ])
                    ]),
                    m('.bg-gray.section',
                        m('.w-container',
                            m('.u-marginbottom-60.w-row', [
                                m(loadMoreBtn, {
                                    collection: ctrl.subscriptions,
                                    cssClass: '.w-col-push-4'
                                })
                            ])
                        )
                    )
                ])
            ]);
        }
        return m('', h.loader());
    }
};

export default projectSubscriptionReport;
<|endoftext|>


<commit_before>import React from 'react'
// import DuckImage from '../assets/Duck.jpg'
import './AboutMe.scss'

export const AboutMe = () => (

About me

        Lorem Ipsum is unattractive, both inside and out. I fully understand why it’s former users left it for something else. They made a good decision. I think the only card she has is the Lorem card. An 'extremely credible source' has called my office and told me that Lorem Ipsum's birth certificate is a fraud. I'm speaking with myself, number one, because I have a very good brain and I've said a lot of things. I will write some great placeholder text – and nobody writes better placeholder text than me, believe me – and I’ll write it very inexpensively. I will write some great, great text on your website’s Southern border, and I will make Google pay for that text. Mark my words. We have so many things that we have to do better... and certainly ipsum is one of them.

        Lorem Ipsum is the single greatest threat. We are not - we are not keeping up with other websites. My text is long and beautiful, as, it has been well documented, are various other parts of my website. An ‘extremely credible source’ has called my office and told me that Barack Obama’s placeholder text is a fraud.

        This placeholder text is gonna be HUGE. An 'extremely credible source' has called my office and told me that Lorem Ipsum's birth certificate is a fraud. We are going to make placeholder text great again. Greater than ever before.

        The concept of Lorem Ipsum was created by and for the Chinese in order to make U.S. design jobs non-competitive. You're telling the enemy exactly what you're going to do. No wonder you've been fighting Lorem Ipsum your entire adult life.

        I’m the best thing that ever happened to placeholder text. My placeholder text, I think, is going to end up being very good with women. The best taco bowls are made in Trump Tower Grill. I love Hispanics!

    {/*  */}

)

export default AboutMe
<commit_msg>change in text<commit_after>import React from 'react'
// import DuckImage from '../assets/Duck.jpg'
import './AboutMe.scss'

export const AboutMe = () => (

About me

        Ipsum is unattractive, both inside and out. I fully understand why it’s former users left it for something else. They made a good decision. I think the only card she has is the Lorem card. An 'extremely credible source' has called my office and told me that Lorem Ipsum's birth certificate is a fraud. I'm speaking with myself, number one, because I have a very good brain and I've said a lot of things. I will write some great placeholder text – and nobody writes better placeholder text than me, believe me – and I’ll write it very inexpensively. I will write some great, great text on your website’s Southern border, and I will make Google pay for that text. Mark my words. We have so many things that we have to do better... and certainly ipsum is one of them.

        Lorem Ipsum is the single greatest threat. We are not - we are not keeping up with other websites. My text is long and beautiful, as, it has been well documented, are various other parts of my website. An ‘extremely credible source’ has called my office and told me that Barack Obama’s placeholder text is a fraud.

        This placeholder text is gonna be HUGE. An 'extremely credible source' has called my office and told me that Lorem Ipsum's birth certificate is a fraud. We are going to make placeholder text great again. Greater than ever before.

        The concept of Lorem Ipsum was created by and for the Chinese in order to make U.S. design jobs non-competitive. You're telling the enemy exactly what you're going to do. No wonder you've been fighting Lorem Ipsum your entire adult life.

        I’m the best thing that ever happened to placeholder text. My placeholder text, I think, is going to end up being very good with women. The best taco bowls are made in Trump Tower Grill. I love Hispanics!

    {/*  */}

)

export default AboutMe
<|endoftext|>


<commit_before>import React from 'react';
import { StickyContainer, Sticky } from 'react-sticky';
import formatDate from 'occasion';

import Phase from 'components/TOS/Phase';
import Attribute from 'components/TOS/Attribute';
import ReorderView from 'components/TOS/ReorderView';
import ImportView from 'components/TOS/ImportView';

import Popup from 'components/Popup';
import Dropdown from 'components/Dropdown';

import IsAuthenticated from 'components/IsAuthenticated/IsAuthenticated';

import './ViewTOS.scss';

export class ViewTOS extends React.Component {
  constructor (props) {
    super(props);
    this.fetchTOS = this.fetchTOS.bind(this);
    this.sendForInspection = this.sendForInspection.bind(this);
    this.onChange = this.onChange.bind(this);
    this.createNewPhase = this.createNewPhase.bind(this);
    this.cancelPhaseCreation = this.cancelPhaseCreation.bind(this);
    this.setPhaseVisibility = this.setPhaseVisibility.bind(this);
    this.state = {
      showMetadata: false,
      createPhaseMode: false,
      newPhaseName: '',
      update: '',
      showReorderView: false,
      showImportView: false
    };
  }

  componentDidMount () {
    const { id } = this.props.params;
    this.fetchTOS(id);
  }

  componentWillReceiveProps (nextProps) {
    const { route } = nextProps;
    if (nextProps.params.id !== this.props.params.id) {
      const { id } = nextProps.params;
      this.fetchTOS(id);
    }
    if (route && route.path === 'view-tos/:id') {
      this.props.setNavigationVisibility(false);
    }
  }

  componentWillUnmount () {
    this.props.clearTOS();
  }

  fetchTOS (id) {
    this.props.fetchTOS(id)
      .then(() => this.props.setNavigationVisibility(false))
      .catch((err) => {
        if (err instanceof URIError) {
          // We have a 404 from API
          this.props.push(`/404?tos-id=${id}`);
        }
      });
  }

  sendForInspection () {
    return this.props.sendForInspection(this.props.selectedTOS)
      .then(data => console.log(data))
      .catch(err => {
        return this.props.displayMessage({
          text: err.message,
          success: false
        });
      });
  }

  formatDateTime (dateTime) {
    const date = dateTime.slice(0, 10);
    const time = dateTime.slice(11, 16);
    return { date, time };
  }

  toggleMetadataVisibility (current) {
    this.setState({ showMetadata: !current });
  }

  addPhase () {
    this.setState({ createPhaseMode: true });
  }

  createNewPhase (event) {
    event.preventDefault();
    if (this.state.newPhaseName.length > 0) {
      this.props.addPhase(this.state.newPhaseName, this.props.selectedTOS.id);
      this.setState({ createPhaseMode: false, newPhaseName: '' });
    }
    this.props.displayMessage({
      text: 'Käsittelyvaiheen lisäys onnistui!',
      success: true
    });
  }

  cancelPhaseCreation (event) {
    event.preventDefault();
    this.setState({ newPhaseName: '', createPhaseMode: false });
  }

  onChange (event) {
    this.setState({ newPhaseName: event.target.value });
  }

  /*
   setPhaseVisibility is a hack to fix firefox specific issue of re-rendering phases
   remove once firefox issue is fixed
   */
  setPhaseVisibility (x, y) {
    const newString = Math.random().toString(36).replace(/[^a-z]+/g, '');
    this.setState({ update: newString });
    this.props.setPhaseVisibility(x, y);
  }

  toggleReorderView () {
    const current = this.state.showReorderView;
    this.setState({ showReorderView: !current });
  }

  toggleImportView () {
    const current = this.state.showImportView;
    this.setState({ showImportView: !current });
  }

  generateMetaData (attributeTypes, attributes) {
    const modifiedDateTime = this.formatDateTime(this.props.selectedTOS.modified_at);
    const formattedDate = formatDate(modifiedDateTime.date, 'DD.MM.YYYY');
    const dateTime = formattedDate + ' ' + modifiedDateTime.time;
    const attributeElements = [];
    const versionData = [
      { type: 'Versionumero', name: '1.0' },
      { type: 'Tila', name: 'Luonnos' },
      { type: 'Muokkausajankohta', name: dateTime },
      { type: 'Muokkaaja', name: 'Matti Meikäläinen' }
    ];
    versionData.map((metadata, index) => {
      attributeElements.push(
        <Attribute
          key={index}
          attributeIndex={metadata.type}
          attributeKey={metadata.type}
          attribute={metadata.name}
          documentState={this.props.documentState}
          attributeTypes={attributeTypes}
          mode='view'
          type='attribute'
          editable={false}
          showAttributes={true}
        />
      );
    });
    for (const key in attributes) {
      if (attributes.hasOwnProperty(key)) {
        attributeElements.push(
          <Attribute
            key={key}
            attributeIndex={key}
            attributeKey={this.props.attributeTypes[key].name}
            attribute={attributes[key]}
            mode='view'
            type='attribute'
            attributeTypes={this.props.attributeTypes}
            documentState={this.props.documentState}
            showAttributes={this.state.showMetadata}
            editable={true}
          />
        );
      }
    }
    const metadataElement = (

          {attributeElements.slice(0, 2)}

          <button
            type='button'
            className='btn btn-info btn-sm'
            title={this.state.showMetadata ? 'Pienennä' : 'Laajenna'}
            onClick={() => this.toggleMetadataVisibility(this.state.showMetadata)}>

          </button>

          {attributeElements.slice(2)}

    );
    return metadataElement;
  }

  generatePhases (phases) {
    const phaseElements = [];
    const phasesOrder = Object.keys(this.props.selectedTOS.phases);
    for (const key in phases) {
      if (phases.hasOwnProperty(key)) {
        phaseElements.push(
          <Phase
            key={key}
            phaseIndex={phases[key].id}
            phase={this.props.phases[key]}
            phasesOrder={phasesOrder}
            phases={this.props.phases}
            actions={this.props.actions}
            records={this.props.records}
            setPhaseVisibility={this.setPhaseVisibility}
            recordTypes={this.props.recordTypes}
            documentState={this.props.documentState}
            attributeTypes={this.props.attributeTypes}
            addAction={this.props.addAction}
            addRecord={this.props.addRecord}
            editAction={this.props.editAction}
            editRecord={this.props.editRecord}
            editPhase={this.props.editPhase}
            displayMessage={this.props.displayMessage}
            changeOrder={this.props.changeOrder}
            importItems={this.props.importItems}
            update={this.state.update}
          />
        );
      }
    }
    return phaseElements;
  }

  render () {
    const { selectedTOS, phases, isFetching } = this.props;
    if (!isFetching && selectedTOS.id) {
      const phaseElements = this.generatePhases(selectedTOS.phases);
      const TOSMetaData = this.generateMetaData(this.props.attributeTypes, selectedTOS.attributes);

      return (

          <StickyContainer className='col-xs-12 single-tos-container'>
            <Sticky className='single-tos-header'>

{selectedTOS.function_id} {selectedTOS.name}

                  { this.props.documentState !== 'edit' &&

                    <IsAuthenticated>
                      <button
                        className='btn btn-default btn-sm pull-right'
                        onClick={this.sendForInspection}>
                        Lähetä tarkastettavaksi
                      </button>
                    </IsAuthenticated>
                    <button
                      className='btn btn-primary btn-sm pull-right'
                      onClick={() => this.props.setDocumentState('edit')}>
                      Muokkaustila
                    </button>

                  }
                  { this.props.documentState === 'edit' &&

                    <button
                      className='btn btn-primary btn-sm pull-right'
                      onClick={() => this.props.setDocumentState('view')}>
                      Tallenna luonnos
                    </button>
                    <button
                      className='btn btn-danger btn-sm pull-right'
                      onClick={() => this.props.setDocumentState('view')}>
                      Peruuta muokkaus
                    </button>
                     = Pakollinen tieto

                  }

            </Sticky>

                    { TOSMetaData }

                  { this.props.documentState === 'edit' && !this.state.createPhaseMode &&

                    <Dropdown
                      children={[
                        {
                          text: 'Uusi käsittelyvaihe',
                          icon: 'fa-file-text',
                          style: 'btn-primary',
                          action: () => this.addPhase()
                        }, {
                          text: 'Tuo käsittelyvaihe',
                          icon: 'fa-download',
                          style: 'btn-primary',
                          action: () => this.toggleImportView()
                        }, {
                          text: 'Järjestä käsittelyvaiheita',
                          icon: 'fa-th-list',
                          style: 'btn-primary',
                          action: () => this.toggleReorderView()
                        }
                      ]}
                      small={true}
                    />

                  }
                  <button
                    className='btn btn-default btn-sm pull-right'
                    onClick={() => this.props.setPhasesVisibility(phases, true)}>
                    Avaa kaikki
                  </button>
                  <button
                    className='btn btn-default btn-sm pull-right'
                    onClick={() => this.props.setPhasesVisibility(phases, false)}>
                    Pienennä kaikki
                  </button>

                  { this.state.createPhaseMode &&
                  <form onSubmit={this.createNewPhase} className='col-xs-12 phase-form'>

Uusi käsittelyvaihe

                      <input
                        type='text'
                        className='form-control'
                        value={this.state.newPhaseName}
                        onChange={this.onChange}
                        onSubmit={this.createNewPhase}
                        placeholder='Käsittelyvaiheen nimi'
                      />

                      <button
                        className='btn btn-danger pull-left'
                        onClick={this.cancelPhaseCreation}>
                        Peruuta
                      </button>
                      <button className='btn btn-primary pull-left' type='submit'>Lisää</button>

                  </form>
                  }
                  { phaseElements }
                  { this.state.showReorderView &&
                  <Popup
                    content={
                      <ReorderView
                        target='phase'
                        toggleReorderView={() => this.toggleReorderView()}
                        keys={this.props.selectedTOS.phases}
                        values={this.props.phases}
                        changeOrder={this.props.changeOrder}
                        parent={null}
                        parentName={selectedTOS.function_id + ' ' + selectedTOS.name}
                      />
                    }
                    closePopup={() => this.toggleReorderView()}
                  />
                  }
                  { this.state.showImportView &&
                  <Popup
                    content={
                      <ImportView
                        level='phase'
                        toggleImportView={() => this.toggleImportView()}
                        phases={this.props.phases}
                        phasesOrder={this.props.selectedTOS.phases}
                        actions={this.props.actions}
                        records={this.props.records}
                        importItems={this.props.importItems}
                        title='käsittelyvaiheita'
                        targetText={'TOS-kuvaukseen ' + selectedTOS.name}
                        itemsToImportText='käsittelyvaiheet'
                      />
                    }
                    closePopup={() => this.toggleImportView()}
                  />
                  }

          </StickyContainer>

      );
    } else {
      return null;
    }
  }
}

ViewTOS.propTypes = {
  actions: React.PropTypes.object.isRequired,
  addAction: React.PropTypes.func.isRequired,
  addPhase: React.PropTypes.func.isRequired,
  addRecord: React.PropTypes.func.isRequired,
  attributeTypes: React.PropTypes.object.isRequired,
  changeOrder: React.PropTypes.func.isRequired,
  clearTOS: React.PropTypes.func.isRequired,
  displayMessage: React.PropTypes.func.isRequired,
  documentState: React.PropTypes.string.isRequired,
  editAction: React.PropTypes.func.isRequired,
  editPhase: React.PropTypes.func.isRequired,
  editRecord: React.PropTypes.func.isRequired,
  fetchTOS: React.PropTypes.func.isRequired,
  importItems: React.PropTypes.func.isRequired,
  isFetching: React.PropTypes.bool.isRequired,
  params: React.PropTypes.object.isRequired,
  phases: React.PropTypes.object.isRequired,
  push: React.PropTypes.func.isRequired,
  recordTypes: React.PropTypes.object.isRequired,
  records: React.PropTypes.object.isRequired,
  route: React.PropTypes.object.isRequired,
  selectedTOS: React.PropTypes.object.isRequired,
  sendForInspection: React.PropTypes.func.isRequired,
  setDocumentState: React.PropTypes.func.isRequired,
  setNavigationVisibility: React.PropTypes.func.isRequired,
  setPhaseVisibility: React.PropTypes.func.isRequired,
  setPhasesVisibility: React.PropTypes.func.isRequired
};

export default ViewTOS;
<commit_msg>Add success-message to sendForInspection<commit_after>import React from 'react';
import { StickyContainer, Sticky } from 'react-sticky';
import formatDate from 'occasion';

import Phase from 'components/TOS/Phase';
import Attribute from 'components/TOS/Attribute';
import ReorderView from 'components/TOS/ReorderView';
import ImportView from 'components/TOS/ImportView';

import Popup from 'components/Popup';
import Dropdown from 'components/Dropdown';

import IsAuthenticated from 'components/IsAuthenticated/IsAuthenticated';

import './ViewTOS.scss';

export class ViewTOS extends React.Component {
  constructor (props) {
    super(props);
    this.fetchTOS = this.fetchTOS.bind(this);
    this.sendForInspection = this.sendForInspection.bind(this);
    this.onChange = this.onChange.bind(this);
    this.createNewPhase = this.createNewPhase.bind(this);
    this.cancelPhaseCreation = this.cancelPhaseCreation.bind(this);
    this.setPhaseVisibility = this.setPhaseVisibility.bind(this);
    this.state = {
      showMetadata: false,
      createPhaseMode: false,
      newPhaseName: '',
      update: '',
      showReorderView: false,
      showImportView: false
    };
  }

  componentDidMount () {
    const { id } = this.props.params;
    this.fetchTOS(id);
  }

  componentWillReceiveProps (nextProps) {
    const { route } = nextProps;
    if (nextProps.params.id !== this.props.params.id) {
      const { id } = nextProps.params;
      this.fetchTOS(id);
    }
    if (route && route.path === 'view-tos/:id') {
      this.props.setNavigationVisibility(false);
    }
  }

  componentWillUnmount () {
    this.props.clearTOS();
  }

  fetchTOS (id) {
    this.props.fetchTOS(id)
      .then(() => this.props.setNavigationVisibility(false))
      .catch((err) => {
        if (err instanceof URIError) {
          // We have a 404 from API
          this.props.push(`/404?tos-id=${id}`);
        }
      });
  }

  sendForInspection () {
    return this.props.sendForInspection(this.props.selectedTOS)
      .then(() => {
        return this.props.displayMessage({
          text: 'Luonnos lähetettiin tarkastettavaksi',
          success: true
        });
      })
      .catch(err => {
        return this.props.displayMessage({
          text: err.message,
          success: false
        });
      });
  }

  formatDateTime (dateTime) {
    const date = dateTime.slice(0, 10);
    const time = dateTime.slice(11, 16);
    return { date, time };
  }

  toggleMetadataVisibility (current) {
    this.setState({ showMetadata: !current });
  }

  addPhase () {
    this.setState({ createPhaseMode: true });
  }

  createNewPhase (event) {
    event.preventDefault();
    if (this.state.newPhaseName.length > 0) {
      this.props.addPhase(this.state.newPhaseName, this.props.selectedTOS.id);
      this.setState({ createPhaseMode: false, newPhaseName: '' });
    }
    this.props.displayMessage({
      text: 'Käsittelyvaiheen lisäys onnistui!',
      success: true
    });
  }

  cancelPhaseCreation (event) {
    event.preventDefault();
    this.setState({ newPhaseName: '', createPhaseMode: false });
  }

  onChange (event) {
    this.setState({ newPhaseName: event.target.value });
  }

  /*
   setPhaseVisibility is a hack to fix firefox specific issue of re-rendering phases
   remove once firefox issue is fixed
   */
  setPhaseVisibility (x, y) {
    const newString = Math.random().toString(36).replace(/[^a-z]+/g, '');
    this.setState({ update: newString });
    this.props.setPhaseVisibility(x, y);
  }

  toggleReorderView () {
    const current = this.state.showReorderView;
    this.setState({ showReorderView: !current });
  }

  toggleImportView () {
    const current = this.state.showImportView;
    this.setState({ showImportView: !current });
  }

  generateMetaData (attributeTypes, attributes) {
    const modifiedDateTime = this.formatDateTime(this.props.selectedTOS.modified_at);
    const formattedDate = formatDate(modifiedDateTime.date, 'DD.MM.YYYY');
    const dateTime = formattedDate + ' ' + modifiedDateTime.time;
    const attributeElements = [];
    const versionData = [
      { type: 'Versionumero', name: '1.0' },
      { type: 'Tila', name: 'Luonnos' },
      { type: 'Muokkausajankohta', name: dateTime },
      { type: 'Muokkaaja', name: 'Matti Meikäläinen' }
    ];
    versionData.map((metadata, index) => {
      attributeElements.push(
        <Attribute
          key={index}
          attributeIndex={metadata.type}
          attributeKey={metadata.type}
          attribute={metadata.name}
          documentState={this.props.documentState}
          attributeTypes={attributeTypes}
          mode='view'
          type='attribute'
          editable={false}
          showAttributes={true}
        />
      );
    });
    for (const key in attributes) {
      if (attributes.hasOwnProperty(key)) {
        attributeElements.push(
          <Attribute
            key={key}
            attributeIndex={key}
            attributeKey={this.props.attributeTypes[key].name}
            attribute={attributes[key]}
            mode='view'
            type='attribute'
            attributeTypes={this.props.attributeTypes}
            documentState={this.props.documentState}
            showAttributes={this.state.showMetadata}
            editable={true}
          />
        );
      }
    }
    const metadataElement = (

          {attributeElements.slice(0, 2)}

          <button
            type='button'
            className='btn btn-info btn-sm'
            title={this.state.showMetadata ? 'Pienennä' : 'Laajenna'}
            onClick={() => this.toggleMetadataVisibility(this.state.showMetadata)}>

          </button>

          {attributeElements.slice(2)}

    );
    return metadataElement;
  }

  generatePhases (phases) {
    const phaseElements = [];
    const phasesOrder = Object.keys(this.props.selectedTOS.phases);
    for (const key in phases) {
      if (phases.hasOwnProperty(key)) {
        phaseElements.push(
          <Phase
            key={key}
            phaseIndex={phases[key].id}
            phase={this.props.phases[key]}
            phasesOrder={phasesOrder}
            phases={this.props.phases}
            actions={this.props.actions}
            records={this.props.records}
            setPhaseVisibility={this.setPhaseVisibility}
            recordTypes={this.props.recordTypes}
            documentState={this.props.documentState}
            attributeTypes={this.props.attributeTypes}
            addAction={this.props.addAction}
            addRecord={this.props.addRecord}
            editAction={this.props.editAction}
            editRecord={this.props.editRecord}
            editPhase={this.props.editPhase}
            displayMessage={this.props.displayMessage}
            changeOrder={this.props.changeOrder}
            importItems={this.props.importItems}
            update={this.state.update}
          />
        );
      }
    }
    return phaseElements;
  }

  render () {
    const { selectedTOS, phases, isFetching } = this.props;
    if (!isFetching && selectedTOS.id) {
      const phaseElements = this.generatePhases(selectedTOS.phases);
      const TOSMetaData = this.generateMetaData(this.props.attributeTypes, selectedTOS.attributes);

      return (

          <StickyContainer className='col-xs-12 single-tos-container'>
            <Sticky className='single-tos-header'>

{selectedTOS.function_id} {selectedTOS.name}

                  { this.props.documentState !== 'edit' &&

                    <IsAuthenticated>
                      <button
                        className='btn btn-default btn-sm pull-right'
                        onClick={this.sendForInspection}>
                        Lähetä tarkastettavaksi
                      </button>
                    </IsAuthenticated>
                    <button
                      className='btn btn-primary btn-sm pull-right'
                      onClick={() => this.props.setDocumentState('edit')}>
                      Muokkaustila
                    </button>

                  }
                  { this.props.documentState === 'edit' &&

                    <button
                      className='btn btn-primary btn-sm pull-right'
                      onClick={() => this.props.setDocumentState('view')}>
                      Tallenna luonnos
                    </button>
                    <button
                      className='btn btn-danger btn-sm pull-right'
                      onClick={() => this.props.setDocumentState('view')}>
                      Peruuta muokkaus
                    </button>
                     = Pakollinen tieto

                  }

            </Sticky>

                    { TOSMetaData }

                  { this.props.documentState === 'edit' && !this.state.createPhaseMode &&

                    <Dropdown
                      children={[
                        {
                          text: 'Uusi käsittelyvaihe',
                          icon: 'fa-file-text',
                          style: 'btn-primary',
                          action: () => this.addPhase()
                        }, {
                          text: 'Tuo käsittelyvaihe',
                          icon: 'fa-download',
                          style: 'btn-primary',
                          action: () => this.toggleImportView()
                        }, {
                          text: 'Järjestä käsittelyvaiheita',
                          icon: 'fa-th-list',
                          style: 'btn-primary',
                          action: () => this.toggleReorderView()
                        }
                      ]}
                      small={true}
                    />

                  }
                  <button
                    className='btn btn-default btn-sm pull-right'
                    onClick={() => this.props.setPhasesVisibility(phases, true)}>
                    Avaa kaikki
                  </button>
                  <button
                    className='btn btn-default btn-sm pull-right'
                    onClick={() => this.props.setPhasesVisibility(phases, false)}>
                    Pienennä kaikki
                  </button>

                  { this.state.createPhaseMode &&
                  <form onSubmit={this.createNewPhase} className='col-xs-12 phase-form'>

Uusi käsittelyvaihe

                      <input
                        type='text'
                        className='form-control'
                        value={this.state.newPhaseName}
                        onChange={this.onChange}
                        onSubmit={this.createNewPhase}
                        placeholder='Käsittelyvaiheen nimi'
                      />

                      <button
                        className='btn btn-danger pull-left'
                        onClick={this.cancelPhaseCreation}>
                        Peruuta
                      </button>
                      <button className='btn btn-primary pull-left' type='submit'>Lisää</button>

                  </form>
                  }
                  { phaseElements }
                  { this.state.showReorderView &&
                  <Popup
                    content={
                      <ReorderView
                        target='phase'
                        toggleReorderView={() => this.toggleReorderView()}
                        keys={this.props.selectedTOS.phases}
                        values={this.props.phases}
                        changeOrder={this.props.changeOrder}
                        parent={null}
                        parentName={selectedTOS.function_id + ' ' + selectedTOS.name}
                      />
                    }
                    closePopup={() => this.toggleReorderView()}
                  />
                  }
                  { this.state.showImportView &&
                  <Popup
                    content={
                      <ImportView
                        level='phase'
                        toggleImportView={() => this.toggleImportView()}
                        phases={this.props.phases}
                        phasesOrder={this.props.selectedTOS.phases}
                        actions={this.props.actions}
                        records={this.props.records}
                        importItems={this.props.importItems}
                        title='käsittelyvaiheita'
                        targetText={'TOS-kuvaukseen ' + selectedTOS.name}
                        itemsToImportText='käsittelyvaiheet'
                      />
                    }
                    closePopup={() => this.toggleImportView()}
                  />
                  }

          </StickyContainer>

      );
    } else {
      return null;
    }
  }
}

ViewTOS.propTypes = {
  actions: React.PropTypes.object.isRequired,
  addAction: React.PropTypes.func.isRequired,
  addPhase: React.PropTypes.func.isRequired,
  addRecord: React.PropTypes.func.isRequired,
  attributeTypes: React.PropTypes.object.isRequired,
  changeOrder: React.PropTypes.func.isRequired,
  clearTOS: React.PropTypes.func.isRequired,
  displayMessage: React.PropTypes.func.isRequired,
  documentState: React.PropTypes.string.isRequired,
  editAction: React.PropTypes.func.isRequired,
  editPhase: React.PropTypes.func.isRequired,
  editRecord: React.PropTypes.func.isRequired,
  fetchTOS: React.PropTypes.func.isRequired,
  importItems: React.PropTypes.func.isRequired,
  isFetching: React.PropTypes.bool.isRequired,
  params: React.PropTypes.object.isRequired,
  phases: React.PropTypes.object.isRequired,
  push: React.PropTypes.func.isRequired,
  recordTypes: React.PropTypes.object.isRequired,
  records: React.PropTypes.object.isRequired,
  route: React.PropTypes.object.isRequired,
  selectedTOS: React.PropTypes.object.isRequired,
  sendForInspection: React.PropTypes.func.isRequired,
  setDocumentState: React.PropTypes.func.isRequired,
  setNavigationVisibility: React.PropTypes.func.isRequired,
  setPhaseVisibility: React.PropTypes.func.isRequired,
  setPhasesVisibility: React.PropTypes.func.isRequired
};

export default ViewTOS;
<|endoftext|>


<commit_before>/**
 * Chartist.js plugin to display a title for 1 or 2 axises.
 *
 */
/* global Chartist */
(function (window, document, Chartist) {
    'use strict';

    var axisDefaults = {
        axisTitle: '',
        axisClass: 'ct-axis-title',
        offset: {
            x: 0,
            y: 0
        },
        textAnchor: 'middle',
        flipText: false
    };
    var defaultOptions = {
        xAxis: axisDefaults,
        yAxis: axisDefaults
    };

    //as axisX will usually be at the bottom, set it to be below the labels
    defaultOptions.axisX.offset.y = 40;

    Chartist.plugins = Chartist.plugins || {};
    Chartist.plugins.ctAxisTitle = function (options) {

        options = Chartist.extend({}, defaultOptions, options);

        return function ctAxisTitle(chart) {

            chart.on('created', function (data) {

                if (!options.axisX.axisTitle && !options.axisY.axisTitle) {
                    throw new Error('ctAxisTitle plugin - You must provide at least one axis title');
                } else if (!data.axisX && !data.axisY) {
                    throw new Error('ctAxisTitle plugin can only be used on charts that have at least one axis');
                }

                var xPos;
                var yPos;
                var title;

                //position axis X title
                if (options.axisX.axisTitle && data.axisX) {

                    xPos = (data.axisX.axisLength / 2) + data.options.axisY.offset + data.options.chartPadding.left;

                    yPos = data.options.chartPadding.top;

                    if (data.options.axisY.position === 'end') {
                        xPos -= data.options.axisY.offset;
                    }

                    if (data.options.axisX.position === 'end') {
                        yPos += data.axisY.axisLength;
                    }

                    title = new Chartist.Svg("text");
                    title.addClass(options.axisX.axisClass);
                    title.text(options.axisX.axisTitle);
                    title.attr({
                        x: xPos + options.axisX.offset.x,
                        y: yPos + options.axisX.offset.y,
                        "text-anchor": options.axisX.textAnchor
                    });

                    data.svg.append(title, true);

                }

                //position axis Y title
                if (options.axisY.axisTitle && data.axisY) {
                    xPos = 0;

                    yPos = (data.axisY.axisLength / 2) + data.options.chartPadding.top;

                    if (data.options.axisX.position === 'start') {
                        yPos += data.options.axisX.offset;
                    }

                    if (data.options.axisY.position === 'end') {
                        xPos = data.axisX.axisLength;
                    }

                    var transform = 'rotate(' + (options.axisY.flipTitle ? -90 : 90) + ', ' + xPos + ', ' + yPos + ')';

                    title = new Chartist.Svg("text");
                    title.addClass(options.axisY.axisClass);
                    title.text(options.axisY.axisTitle);
                    title.attr({
                        x: xPos + options.axisY.offset.x,
                        y: yPos + options.axisY.offset.y,
                        transform: transform,
                        "text-anchor": options.axisY.textAnchor
                    });

                    data.svg.append(title, true);

                }

            });
        };
    };

}(window, document, Chartist));
<commit_msg>Corrected error where same object being referenced by both axes.<commit_after>/**
 * Chartist.js plugin to display a title for 1 or 2 axises.
 *
 */
/* global Chartist */
(function (window, document, Chartist) {
    'use strict';

    var axisDefaults = {
        axisTitle: '',
        axisClass: 'ct-axis-title',
        offset: {
            x: 0,
            y: 0
        },
        textAnchor: 'middle',
        flipText: false
    };

    var defaultOptions = {
        axisX:  Chartist.extend({}, axisDefaults),
        axisY:  Chartist.extend({}, axisDefaults)
    };

    //as axisX will usually be at the bottom, set it to be below the labels
    defaultOptions.axisX.offset.y = 40;

    Chartist.plugins = Chartist.plugins || {};
    Chartist.plugins.ctAxisTitle = function (options) {

        options = Chartist.extend({}, defaultOptions, options);

        return function ctAxisTitle(chart) {

            chart.on('created', function (data) {

                if (!options.axisX.axisTitle && !options.axisY.axisTitle) {
                    throw new Error('ctAxisTitle plugin - You must provide at least one axis title');
                } else if (!data.axisX && !data.axisY) {
                    throw new Error('ctAxisTitle plugin can only be used on charts that have at least one axis');
                }

                var xPos;
                var yPos;
                var title;

                //position axis X title
                if (options.axisX.axisTitle && data.axisX) {

                    xPos = (data.axisX.axisLength / 2) + data.options.axisY.offset + data.options.chartPadding.left;

                    yPos = data.options.chartPadding.top;

                    if (data.options.axisY.position === 'end') {
                        xPos -= data.options.axisY.offset;
                    }

                    if (data.options.axisX.position === 'end') {
                        yPos += data.axisY.axisLength;
                    }

                    title = new Chartist.Svg("text");
                    title.addClass(options.axisX.axisClass);
                    title.text(options.axisX.axisTitle);
                    title.attr({
                        x: xPos + options.axisX.offset.x,
                        y: yPos + options.axisX.offset.y,
                        "text-anchor": options.axisX.textAnchor
                    });

                    data.svg.append(title, true);

                }

                //position axis Y title
                if (options.axisY.axisTitle && data.axisY) {
                    xPos = 0;

                    yPos = (data.axisY.axisLength / 2) + data.options.chartPadding.top;

                    if (data.options.axisX.position === 'start') {
                        yPos += data.options.axisX.offset;
                    }

                    if (data.options.axisY.position === 'end') {
                        xPos = data.axisX.axisLength;
                    }

                    var transform = 'rotate(' + (options.axisY.flipTitle ? -90 : 90) + ', ' + xPos + ', ' + yPos + ')';

                    title = new Chartist.Svg("text");
                    title.addClass(options.axisY.axisClass);
                    title.text(options.axisY.axisTitle);
                    title.attr({
                        x: xPos + options.axisY.offset.x,
                        y: yPos + options.axisY.offset.y,
                        transform: transform,
                        "text-anchor": options.axisY.textAnchor
                    });

                    data.svg.append(title, true);

                }

            });
        };
    };

}(window, document, Chartist));
<|endoftext|>


<commit_before>(function (ns, d3, _, $, undefined) {

    // implements the following interface
    /*
    {
        scale: returns the d3 scale for the type

        range: returns the d3 range for the type
    }
    */

    function dateDiff(d1, d2) {
        var diff = d1.getTime() - d2.getTime();
        return diff / (24*60*60*1000);
    }

    function TimeScale(data, options) {
        this.options = options;
        this.data = data;

        this.init();
    }

    TimeScale.prototype = {
        init: function () {
            delete this._scale;
        },

        scale: function (domain) {
            this._domain = domain;
            if(!this._scale) {
                this._scale = new d3.time.scale()
                    .domain(d3.extent(this._domain));

                this.range();
            }

            return this._scale;
        },

        axis: function () {
            var options = this.options.xAxis;
            var tickFormat = this.getOptimalTickFormat();

            var axis = d3.svg.axis()
                .scale(this._scale)
                .tickFormat(tickFormat)
                .tickSize(options.innerTickSize, options.outerTickSize)
                .tickPadding(options.tickPadding)
                .tickValues(this._domain);

            if (this.options.xAxis.maxTicks != null && this.options.xAxis.maxTicks < this._domain.length) {
                // override the tickValues with custom array based on number of ticks
                // we don't use D3 ticks() because you cannot force it to show a specific number of ticks
                var customValues = [];
                var len = this._domain.length;
                var step = (len + 1) / this.options.xAxis.maxTicks;

                for (var j=0, index = 0; j<len; j += step, index += step) {
                    customValues.push(this._domain[Math.min(Math.ceil(index), len-1)]);
                }

                axis.tickValues(customValues);

            } else if (this.options.xAxis.firstAndLast) {
                // show only first and last tick
                axis.tickValues(_.nw.firstAndLast(this._domain));
            }

            return axis;
        },

        postProcessAxis: function (axisGroup) {
            if (!this.options.xAxis.firstAndLast) return;
            var labels = axisGroup.selectAll('.tick text')[0];
            $(labels[0]).attr('style', 'text-anchor: start');
            $(labels[labels.length - 1]).attr('style', 'text-anchor: end');
        },

        rangeBand: function () {
            return 4;
        },

        getOptimalTickFormat: function () {
            if (this.options.xAxis.labels.formatter) return this.options.xAxis.labels.formatter;
            var spanDays = dateDiff(this._domain[this._domain.length-1], this._domain[0]);
            var daysThreshold = this.options.xAxis.maxTicks || 5;
            if (spanDays < daysThreshold) return d3.time.format('%H:%M');
            return d3.time.format('%d %b');
        },

        range: function () {
            return this._scale.rangeRound([0, this.options.chart.plotWidth], 0.1);
        }
    };

    _.nw = _.extend({}, _.nw, { TimeScale: TimeScale });

})('Narwhal', window.d3, window._, window.jQuery);
<commit_msg>Refactor<commit_after>(function (ns, d3, _, $, undefined) {

    // implements the following interface
    /*
    {
        scale: returns the d3 scale for the type

        range: returns the d3 range for the type
    }
    */

    function dateDiff(d1, d2) {
        var diff = d1.getTime() - d2.getTime();
        return diff / (24*60*60*1000);
    }

    function TimeScale(data, options) {
        this.options = options;
        this.data = data;

        this.init();
    }

    TimeScale.prototype = {
        init: function () {
            delete this._scale;
        },

        scale: function (domain) {
            this._domain = domain;
            var axisDomain = this._getAxisDomain(domain);
            if(!this._scale) {
                this._scale = new d3.time.scale()
                    .domain(axisDomain);

                this.range();
            }

            return this._scale;
        },

        _getAxisDomain: function (domain) {
            return d3.extent(domain);
        },

        axis: function () {
            var options = this.options.xAxis;
            var tickFormat = this.getOptimalTickFormat();

            var axis = d3.svg.axis()
                .scale(this._scale)
                .tickFormat(tickFormat)
                .tickSize(options.innerTickSize, options.outerTickSize)
                .tickPadding(options.tickPadding)
                .tickValues(this._domain);

            if (this.options.xAxis.maxTicks != null && this.options.xAxis.maxTicks < this._domain.length) {
                // override the tickValues with custom array based on number of ticks
                // we don't use D3 ticks() because you cannot force it to show a specific number of ticks
                var customValues = [];
                var len = this._domain.length;
                var step = (len + 1) / this.options.xAxis.maxTicks;

                for (var j=0, index = 0; j<len; j += step, index += step) {
                    customValues.push(this._domain[Math.min(Math.ceil(index), len-1)]);
                }

                axis.tickValues(customValues);

            } else if (this.options.xAxis.firstAndLast) {
                // show only first and last tick
                axis.tickValues(_.nw.firstAndLast(this._domain));
            }

            return axis;
        },

        postProcessAxis: function (axisGroup) {
            if (!this.options.xAxis.firstAndLast) return;
            var labels = axisGroup.selectAll('.tick text')[0];
            $(labels[0]).attr('style', 'text-anchor: start');
            $(labels[labels.length - 1]).attr('style', 'text-anchor: end');
        },

        rangeBand: function () {
            return 4;
        },

        getOptimalTickFormat: function () {
            if (this.options.xAxis.labels.formatter) return this.options.xAxis.labels.formatter;
            var spanDays = dateDiff(this._domain[this._domain.length-1], this._domain[0]);
            var daysThreshold = this.options.xAxis.maxTicks || 5;
            if (spanDays < daysThreshold) return d3.time.format('%H:%M');
            return d3.time.format('%d %b');
        },

        range: function () {
            return this._scale.rangeRound([0, this.options.chart.plotWidth], 0.1);
        }
    };

    _.nw = _.extend({}, _.nw, { TimeScale: TimeScale });

})('Narwhal', window.d3, window._, window.jQuery);
<|endoftext|>


<commit_before>const Node = require('./Node');

class DoublyLinkedList {
  constructor() {
    this._head = null;
    this._tail = null;
    this._length = 0;
  }

  /**
   * Get length of Doubly Linked List
   * @return {Number} Length of Linked List
   */
  get length() {
    return this._length;
  }

  /**
   * Check if Doubly Linked List is empty or not
   * @return {Boolean} `true` if empty else `false`
   */
  isEmpty() {
    return this._length === 0;
  }

  /**
   * Get tail of Doubly Linked List
   * @return {Node} Tail node
   */
  get tail() {
    return this._tail;
  }

  /**
   * Get head of Doubly Linked List
   * @return {Node} Head node
   */
  get head() {
    return this._head;
  }

  /**
   * Pushes node to the head of Doubly Linked List
   * @param  {*}   data Data or value contained in Node
   * @return {None}
   */
  push(data) {
    const newNode = new Node(data);

    if (this._head === null) {
      this._tail = newNode;
    }

    newNode.next = this._head;
    newNode.prev = null;

    if (this._head !== null) {
      this._head.prev = newNode;
    }

    this._head = newNode;
    this._length += 1;
  }

  /**
   * Inserts node after a given node
   * @param  {Node} prevNode Node after which insertion needs to take place
   * @param  {*}    data     Data or value contained in Node
   * @return {None}
   */
  insertAfter(prevNode, data) {
    if (prevNode === null || prevNode === undefined) {
      throw new Error('Previous node cannot be null or undefined');
    }

    const newNode = new Node(data);

    if (prevNode.next === null) {
      this._tail = newNode;
    }

    newNode.next = prevNode.next;
    prevNode.next = newNode;
    newNode.prev = prevNode;

    if (newNode.next !== null) {
      newNode.next.prev = newNode;
    }

    this._length += 1;
  }

  /**
   * Inserts node before a given node
   * @param  {Node}  node Node before which insertion needs to take place
   * @param  {*}     data Data or value contained in Node
   * @return {Node}
   */
  insertBefore(node, data) {
    if (node === null || node === undefined) {
      throw new Error('Node cannot be null or undefined');
    }

    const newNode = new Node(data);

    newNode.prev = node.prev;
    node.prev = newNode;
    newNode.next = node;

    if (newNode.prev !== null) {
      newNode.prev.next = newNode;
    } else {
      this._head = newNode;
    }

    this._length += 1;
  }

  /**
   * Pop node from the head
   * @return {None}
   */
  pop() {
    if (this._head === null) {
      throw new Error('No nodes to pop');
    }

    this._head = this._head.next;
    this._length -= 1;
  }

  /**
   * Delete node from the list
   * @param  {Node} node Node to be deleted
   * @return {None}
   */
  deleteNode(node) {
    if (node === null || node === undefined) {
      throw new Error('Node to be deleted cannot be null');
    }

    if (node.prev !== null) {
      node.prev.next = node.next;
    } else {
      this._head = node.next;
      node.next.prev = null;
    }

    if (node.next !== null) {
      node.next.prev = node.prev;
    } else {
      this._tail = node.prev;
      node.prev.next = null;
    }

    this._length -= 1;
  }

  /**
   * Returns node at given index
   * @param  {Number} index Index of required node
   * @return {Node}         Required node
   */
  getNode(index) {
    if (index <= 0 || index > this._length) {
      throw new RangeError('Index out of range');
    }

    let reference = this._head;

    for (let i = 1; i < index; i += 1) {
      reference = reference.next;
    }

    return reference;
  }

  /**
   * Returns string representing the Doubly Linked List
   * @return {String} String representation of Doubly Linked List
   */
  toString() {
    let reference = this._head;
    let str = '';

    while (reference !== null) {
      str += `${reference.value} -> `;
      reference = reference.next;
    }

    str += 'null';

    return str;
  }
}

module.exports = DoublyLinkedList;
<commit_msg>DoublyLinkedList: Pop now returns popped node<commit_after>const Node = require('./Node');

class DoublyLinkedList {
  constructor() {
    this._head = null;
    this._tail = null;
    this._length = 0;
  }

  /**
   * Get length of Doubly Linked List
   * @return {Number} Length of Linked List
   */
  get length() {
    return this._length;
  }

  /**
   * Check if Doubly Linked List is empty or not
   * @return {Boolean} `true` if empty else `false`
   */
  isEmpty() {
    return this._length === 0;
  }

  /**
   * Get tail of Doubly Linked List
   * @return {Node} Tail node
   */
  get tail() {
    return this._tail;
  }

  /**
   * Get head of Doubly Linked List
   * @return {Node} Head node
   */
  get head() {
    return this._head;
  }

  /**
   * Pushes node to the head of Doubly Linked List
   * @param  {*}   data Data or value contained in Node
   * @return {None}
   */
  push(data) {
    const newNode = new Node(data);

    if (this._head === null) {
      this._tail = newNode;
    }

    newNode.next = this._head;
    newNode.prev = null;

    if (this._head !== null) {
      this._head.prev = newNode;
    }

    this._head = newNode;
    this._length += 1;
  }

  /**
   * Inserts node after a given node
   * @param  {Node} prevNode Node after which insertion needs to take place
   * @param  {*}    data     Data or value contained in Node
   * @return {None}
   */
  insertAfter(prevNode, data) {
    if (prevNode === null || prevNode === undefined) {
      throw new Error('Previous node cannot be null or undefined');
    }

    const newNode = new Node(data);

    if (prevNode.next === null) {
      this._tail = newNode;
    }

    newNode.next = prevNode.next;
    prevNode.next = newNode;
    newNode.prev = prevNode;

    if (newNode.next !== null) {
      newNode.next.prev = newNode;
    }

    this._length += 1;
  }

  /**
   * Inserts node before a given node
   * @param  {Node}  node Node before which insertion needs to take place
   * @param  {*}     data Data or value contained in Node
   * @return {Node}
   */
  insertBefore(node, data) {
    if (node === null || node === undefined) {
      throw new Error('Node cannot be null or undefined');
    }

    const newNode = new Node(data);

    newNode.prev = node.prev;
    node.prev = newNode;
    newNode.next = node;

    if (newNode.prev !== null) {
      newNode.prev.next = newNode;
    } else {
      this._head = newNode;
    }

    this._length += 1;
  }

  /**
   * Pop node from the head
   * @return {Node} Node popped
   */
  pop() {
    if (this._head === null) {
      throw new Error('No nodes to pop');
    }

    const reference = this._head;
    this._head = this._head.next;
    this._length -= 1;

    return reference;
  }

  /**
   * Delete node from the list
   * @param  {Node} node Node to be deleted
   * @return {None}
   */
  deleteNode(node) {
    if (node === null || node === undefined) {
      throw new Error('Node to be deleted cannot be null');
    }

    if (node.prev !== null) {
      node.prev.next = node.next;
    } else {
      this._head = node.next;
      node.next.prev = null;
    }

    if (node.next !== null) {
      node.next.prev = node.prev;
    } else {
      this._tail = node.prev;
      node.prev.next = null;
    }

    this._length -= 1;
  }

  /**
   * Returns node at given index
   * @param  {Number} index Index of required node
   * @return {Node}         Required node
   */
  getNode(index) {
    if (index <= 0 || index > this._length) {
      throw new RangeError('Index out of range');
    }

    let reference = this._head;

    for (let i = 1; i < index; i += 1) {
      reference = reference.next;
    }

    return reference;
  }

  /**
   * Returns string representing the Doubly Linked List
   * @return {String} String representation of Doubly Linked List
   */
  toString() {
    let reference = this._head;
    let str = '';

    while (reference !== null) {
      str += `${reference.value} -> `;
      reference = reference.next;
    }

    str += 'null';

    return str;
  }
}

module.exports = DoublyLinkedList;
<|endoftext|>


<commit_before>class Matrix {
    constructor(n=0,m=0,valueArray=[]){
        //Unwrapped array
        if(valueArray.length !== n*m){
            throw "Values array must be of lenght n*m";
        }
        this._n = n;
        this._m = m;
        this._values = valueArray;
    }

    v(i,j){
        return this.val[i * this._m + j];
    }

    /**
    *   Multiply Matrix with a Vector
    */
    dot(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorMult(vector);

        let output = [];
        for(let i=0; i<this._n; i++){
            let row = new Vector(this.val.slice(i * this._m, (i+1) * this._m));
            output.push(row.dot(vector));
        }

        return new Vector(output);
    }

    add(matrix){
        this.checkMatrixDim(matrix);
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(Math.floor(i/this._m), i % this._m) + matrix.v(Math.floor(i/this._m), i % this._m));
        }
        return new Matrix(this._n, this._m, output);
    }

    mult(num){
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(Math.floor(i/this._m), i % this._m) * num);
        }
        return new Matrix(this._n, this._m, output);
    }

    /**
    *   Return the transposed self
    */
    transpose(){
        let transposeValues = [];
        for(let j=0; j<this._m; j++){
            for(let i=0; i<this._n; i++){
                transposeValues.push(this.v(i,j));
            }
        }
        return new Matrix(this._m, this._n, transposeValues);
    }

    dotMat(matrix){
        //Decompose the right matrix into an array of vectors
        let vectors = [];
        let tMatrix = matrix.transpose();
        for(let i=0; i<matrix._m; i++){
            let v = new Vector(tMatrix.val.slice(i * matrix._n, (i+1) * matrix._n));
            vectors.push(...this.dot(v).val);
        }
        let out = new Matrix(matrix._m, this._n, vectors);
        return out.transpose();
    }

    checkVectorMult(vector){
        if(this._m !== vector.length){
            throw "Vector of dimension " + vector.length + ' does not match Matrix dimension ' + this._m;
        }
    }

    checkMatrixDim(matrix){
        if(this._m !== matrix._m || this._n !== matrix._n){
            throw "Matrix of dimension " + matrix._n + ',' + matrix._m + ' does not match Matrix dimension ' + this._n + ',' + this._m;
        }
    }

    get val(){
        return this._values;
    }

    get length(){
        return this.val.length;
    }

    /**
    *   Console.log a prettyfy version of the matrix
    */
    pretty(){
        let maxNumberLength = (''+this.max).length;
        for(let i=0; i<this._n; i++){
            let line = ' | ';
            for(let j=0; j<this._m; j++){
                let num = this.v(i,j) + '';
                line += ' '.repeat(maxNumberLength - num.length) + num + ' | ';
            }
            console.log(line);
        }
    }

    get max(){
        return this.val.reduce((memo, v)=>{
            if(Math.abs(v) > memo){
                return Math.abs(v);
            } else {
                return memo;
            }
        }, 0)
    }

    static randomMatrix(n,m){
        let output = [];
        for(let i=0; i<m*n; i++){
            output.push(random());
        }
        return new Matrix(n,m,output);
    }

}

class Vector {
    constructor(values){
        this._values = values;
    }

    dot(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorLength(vector);

        let output = 0;
        for(let i=0; i<this.length; i++){
            output += this.v(i) * vector.v(i);
        }

        return output;
    }

    add(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorLength(vector);

        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(i) + vector.v(i));
        }

        return new Vector(output);
    }

    mult(num){
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(i) * num);
        }

        return new Vector(output);
    }

    /**
    *   Apply a function to all elements of the vector
    */
    apply(func){
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(func(this.v(i)));
        }
        return new Vector(output);
    }

    /**
    *   Hadamard product of 2 vectors, also called Elementwise product
    */
    hadamard(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorLength(vector);

        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(i) * vector.v(i));
        }

        return new Vector(output);
    }

    /**
    *   Returns the "positive" version of the vector
    *   Positive version always have the first non nul coordinates >= 0
    */
    posit(i=0){
        if(this.v(i) > 0){
            return this.mult(1);
        } else if(this.v(i) < 0) {
            return this.mult(-1);
        } else {
            if((i+1) < this.length){
                return this.posit(i+1);
            } else {
                return return this.mult(1);
            }
        }
    }

    /**
    *   Returns the "truncated" version of the vector
    *   All coordinates smaller than epsilon are set to 0
    */
    trunc(epsilon){
        return new Vector(this.val.map((v) => {
            return Math.abs(v) < epsilon ? 0 : v;
        }))
    }

    v(i){
        return this.val[i];
    }

    get length(){
        return this.val.length;
    }

    get val(){
        return this._values;
    }

    get norm(){
        return Math.sqrt(this.dot(this));
    }

    checkVectorLength(vector){
        if(this.length !== vector.length){
            throw "Vector of dimension " + vector.length + ' does not match vector dimension ' + this.length;
        }
    }

    static randomVector(n){
        let output = [];
        for(let i=0; i<n; i++){
            output.push(random());
        }
        return new Vector(output);
    }

    static convertInput(values){
        if(values.constructor === Array){
            return new Vector(values);
        } else {
            return values;
        }
    }
}

export {Matrix, Vector};

function random(){
    return Math.random() * 2 - 1;
}
<commit_msg>Create a maxDisplayLength<commit_after>class Matrix {
    constructor(n=0,m=0,valueArray=[]){
        //Unwrapped array
        if(valueArray.length !== n*m){
            throw "Values array must be of lenght n*m";
        }
        this._n = n;
        this._m = m;
        this._values = valueArray;
    }

    v(i,j){
        return this.val[i * this._m + j];
    }

    /**
    *   Multiply Matrix with a Vector
    */
    dot(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorMult(vector);

        let output = [];
        for(let i=0; i<this._n; i++){
            let row = new Vector(this.val.slice(i * this._m, (i+1) * this._m));
            output.push(row.dot(vector));
        }

        return new Vector(output);
    }

    add(matrix){
        this.checkMatrixDim(matrix);
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(Math.floor(i/this._m), i % this._m) + matrix.v(Math.floor(i/this._m), i % this._m));
        }
        return new Matrix(this._n, this._m, output);
    }

    mult(num){
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(Math.floor(i/this._m), i % this._m) * num);
        }
        return new Matrix(this._n, this._m, output);
    }

    /**
    *   Return the transposed self
    */
    transpose(){
        let transposeValues = [];
        for(let j=0; j<this._m; j++){
            for(let i=0; i<this._n; i++){
                transposeValues.push(this.v(i,j));
            }
        }
        return new Matrix(this._m, this._n, transposeValues);
    }

    dotMat(matrix){
        //Decompose the right matrix into an array of vectors
        let vectors = [];
        let tMatrix = matrix.transpose();
        for(let i=0; i<matrix._m; i++){
            let v = new Vector(tMatrix.val.slice(i * matrix._n, (i+1) * matrix._n));
            vectors.push(...this.dot(v).val);
        }
        let out = new Matrix(matrix._m, this._n, vectors);
        return out.transpose();
    }

    checkVectorMult(vector){
        if(this._m !== vector.length){
            throw "Vector of dimension " + vector.length + ' does not match Matrix dimension ' + this._m;
        }
    }

    checkMatrixDim(matrix){
        if(this._m !== matrix._m || this._n !== matrix._n){
            throw "Matrix of dimension " + matrix._n + ',' + matrix._m + ' does not match Matrix dimension ' + this._n + ',' + this._m;
        }
    }

    get val(){
        return this._values;
    }

    get length(){
        return this.val.length;
    }

    /**
    *   Console.log a prettyfy version of the matrix
    */
    pretty(){
        let maxNumberLength = this.maxDisplayLength;
        for(let i=0; i<this._n; i++){
            let line = ' | ';
            for(let j=0; j<this._m; j++){
                let num = this.v(i,j) + '';
                line += ' '.repeat(maxNumberLength - num.length) + num + ' | ';
            }
            console.log(line);
        }
    }

    get max(){
        return this.val.reduce((memo, v)=>{
            if(Math.abs(v) > memo){
                return Math.abs(v);
            } else {
                return memo;
            }
        }, 0)
    }

    get maxDisplayLength(){
        return this.val.reduce((memo, v)=>{
            if((v+'').length > memo){
                return (v+'').length;
            } else {
                return memo;
            }
        }, 0)
    }

    static randomMatrix(n,m){
        let output = [];
        for(let i=0; i<m*n; i++){
            output.push(random());
        }
        return new Matrix(n,m,output);
    }

}

class Vector {
    constructor(values){
        this._values = values;
    }

    dot(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorLength(vector);

        let output = 0;
        for(let i=0; i<this.length; i++){
            output += this.v(i) * vector.v(i);
        }

        return output;
    }

    add(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorLength(vector);

        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(i) + vector.v(i));
        }

        return new Vector(output);
    }

    mult(num){
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(i) * num);
        }

        return new Vector(output);
    }

    /**
    *   Apply a function to all elements of the vector
    */
    apply(func){
        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(func(this.v(i)));
        }
        return new Vector(output);
    }

    /**
    *   Hadamard product of 2 vectors, also called Elementwise product
    */
    hadamard(vector){
        vector = Vector.convertInput(vector);
        this.checkVectorLength(vector);

        let output = [];
        for(let i=0; i<this.length; i++){
            output.push(this.v(i) * vector.v(i));
        }

        return new Vector(output);
    }

    /**
    *   Returns the "positive" version of the vector
    *   Positive version always have the first non nul coordinates >= 0
    */
    posit(i=0){
        if(this.v(i) > 0){
            return this.mult(1);
        } else if(this.v(i) < 0) {
            return this.mult(-1);
        } else {
            if((i+1) < this.length){
                return this.posit(i+1);
            } else {
                return return this.mult(1);
            }
        }
    }

    /**
    *   Returns the "truncated" version of the vector
    *   All coordinates smaller than epsilon are set to 0
    */
    trunc(epsilon){
        return new Vector(this.val.map((v) => {
            return Math.abs(v) < epsilon ? 0 : v;
        }))
    }

    v(i){
        return this.val[i];
    }

    get length(){
        return this.val.length;
    }

    get val(){
        return this._values;
    }

    get norm(){
        return Math.sqrt(this.dot(this));
    }

    checkVectorLength(vector){
        if(this.length !== vector.length){
            throw "Vector of dimension " + vector.length + ' does not match vector dimension ' + this.length;
        }
    }

    static randomVector(n){
        let output = [];
        for(let i=0; i<n; i++){
            output.push(random());
        }
        return new Vector(output);
    }

    static convertInput(values){
        if(values.constructor === Array){
            return new Vector(values);
        } else {
            return values;
        }
    }
}

export {Matrix, Vector};

function random(){
    return Math.random() * 2 - 1;
}
<|endoftext|>


<commit_before>import Rlite from 'rlite-router';
import m from 'mithril';
import Vnode from 'mithril/render/vnode';
import signals from './signals';

const router = new Rlite();

// this counter is passed to the root component as key to force mithril to
// trash current view and re-render on every route change (even same path)
let routeCounter = 0;

export function defineRoutes(mountPoint, routes) {
  for (let route in routes) {
    const component = routes[route];
    router.add(route, function({ url, params }) {
      routeCounter++;

      function redraw() {
        m.render(mountPoint, Vnode(component, routeCounter, params, undefined, undefined, undefined));
      }
      // allow to have a lower level router handler
      if (typeof component === 'function') {
        component({ url, params });
      } else {
        // TODO it works but would be better in a router exit hook
        signals.redraw.removeAll();
        signals.redraw.add(redraw);
        redraw();
      }

    });
  }
  window.addEventListener('popstate', processQuerystring);
  processQuerystring();
}

function processQuerystring() {
  const qs = window.location.search || '?=';
  const matched = router.run(qs.slice(2));
  if (!matched) router.run('/');
}

export default {
  set(path, replace) {
    if (replace) {
      window.history.replaceState(null, null, '?=' + path);
    } else {
      window.history.pushState(null, null, '?=' + path);
    }
    const matched = router.run(path);
    if (!matched) router.run('/');
  },
  get() {
    return window.location.search || '?=';
  }
};
<commit_msg>Add a comment to router<commit_after>import Rlite from 'rlite-router';
import m from 'mithril';
import Vnode from 'mithril/render/vnode';
import signals from './signals';

const router = new Rlite();

// this counter is passed to the root component as key to force mithril to
// trash current view and re-render on every route change (even same path)
// this way it reproduces what was the mithril 0.2 behaviour, to help having a
// smooth migration
let routeCounter = 0;

export function defineRoutes(mountPoint, routes) {
  for (let route in routes) {
    const component = routes[route];
    router.add(route, function onRouteMatch({ url, params }) {
      routeCounter++;

      function redraw() {
        m.render(mountPoint, Vnode(component, routeCounter, params, undefined, undefined, undefined));
      }
      // allow to have a lower level router handler
      if (typeof component === 'function') {
        component({ url, params });
      } else {
        // TODO it works but would be better in a router exit hook
        signals.redraw.removeAll();
        signals.redraw.add(redraw);
        redraw();
      }

    });
  }
  window.addEventListener('popstate', processQuerystring);
  processQuerystring();
}

function processQuerystring() {
  const qs = window.location.search || '?=';
  const matched = router.run(qs.slice(2));
  if (!matched) router.run('/');
}

export default {
  set(path, replace) {
    if (replace) {
      window.history.replaceState(null, null, '?=' + path);
    } else {
      window.history.pushState(null, null, '?=' + path);
    }
    const matched = router.run(path);
    if (!matched) router.run('/');
  },
  get() {
    return window.location.search || '?=';
  }
};
<|endoftext|>


<commit_before>"use strict";

window.SVGURL = "http://www.w3.org/2000/svg";

function gsuiRectMatrix() {
	var root = document.createElementNS( SVGURL, "svg" );

	this.rootElement = root;
	root.setAttribute( "preserveAspectRatio", "none" );
	root.classList.add( "gsuiRectMatrix" );
}

gsuiRectMatrix.prototype = {
	remove() {
		this.empty();
		this.rootElement.remove();
	},
	empty() {
		var root = this.rootElement;

		while ( root.childNodes.length ) {
			root.lastChild.remove();
		}
	},
	setResolution( w, h ) {
		this.width = w;
		this.height = h;
		this.rootElement.setAttribute( "viewBox", "0 0 " + w + " " + h );
	},
	render( data, offset, duration ) {
		var rect,
			rectX,
			rectW,
			secW,
			w = this.width,
			h = this.height,
			rowH = h / data.nbRows,
			root = this.rootElement;

		offset = offset || 0;
		duration = duration || data.duration;
		secW = w / ( duration - offset );
		this.empty();
		data.samples.forEach( function( smp ) {
			rectX = ( smp.when - offset ) * secW;
			rectW = smp.duration * secW;
			if ( rectX + rectW > 0 && rectX < w ) {
				rect = document.createElementNS( SVGURL, "rect" );
				rect.setAttribute( "x", rectX + "px" );
				rect.setAttribute( "width", rectW + "px" );
				rect.setAttribute( "y", smp.row * rowH + "px" );
				rect.setAttribute( "height", rowH + "px" );
				root.append( rect );
			}
		} );
	}
};
<commit_msg>gsuiRectMatrix: .render(), fix<commit_after>"use strict";

window.SVGURL = "http://www.w3.org/2000/svg";

function gsuiRectMatrix() {
	var root = document.createElementNS( SVGURL, "svg" );

	this.rootElement = root;
	root.setAttribute( "preserveAspectRatio", "none" );
	root.classList.add( "gsuiRectMatrix" );
}

gsuiRectMatrix.prototype = {
	remove() {
		this.empty();
		this.rootElement.remove();
	},
	empty() {
		var root = this.rootElement;

		while ( root.childNodes.length ) {
			root.lastChild.remove();
		}
	},
	setResolution( w, h ) {
		this.width = w;
		this.height = h;
		this.rootElement.setAttribute( "viewBox", "0 0 " + w + " " + h );
	},
	render( data, offset, duration ) {
		var rect,
			rectX,
			rectW,
			secW,
			w = this.width,
			h = this.height,
			rowH = h / data.nbRows,
			root = this.rootElement;

		offset = offset || 0;
		duration = duration || data.duration;
		secW = w / duration;
		this.empty();
		data.samples.forEach( function( smp ) {
			rectX = ( smp.when - offset ) * secW;
			rectW = smp.duration * secW;
			if ( rectX + rectW > 0 && rectX < w ) {
				rect = document.createElementNS( SVGURL, "rect" );
				rect.setAttribute( "x", rectX + "px" );
				rect.setAttribute( "width", rectW + "px" );
				rect.setAttribute( "y", smp.row * rowH + "px" );
				rect.setAttribute( "height", rowH + "px" );
				root.append( rect );
			}
		} );
	}
};
<|endoftext|>