<commit_before>angular.module('ngDatum')
.directive('ndBarchart', function() {
  function tlate(x, y){return 'translate(' + x + ',' + y + ')';}
  function clog(x){console.log(x);}

  function link(scope, element, attr) {

    var fanciness = [];
    if(attr.fanciness){
      fanciness = attr.fanciness.split(',').map(function(val){ return val.trim(); });
    }

    //ADJUST FONT DYNAMICALLY
    var simpleDates = {
      'short': '%b-%d',
      'med':   '%b-%d \'%y',
      'long':  ''
    };

    //time formats
    //time formatting choosing time.scale
    var customMargins = scope.margins || {};
    var customSize    = scope.size    || {};
    var labels        = scope.labels  || {};
    var margin        = {};

    //TODO: figure out how to make this flexible
    //for CSV/TSV
    var xItems = labels.x || 'NEED X LABEL';
    var yItems = labels.y || 'NEED Y LABEL';

    margin.left   = customMargins.left   || 30;
    margin.right  = customMargins.right  || 30;
    margin.top    = customMargins.top    || 50;
    margin.bottom = customMargins.bottom || 55; //can handle "long date"

    var width  = (customSize.width  || 800) - margin.left - margin.right;
    var height = (customSize.height || 400) - margin.top  - margin.bottom;

    //figure out how to manage different time formats
    //unix time, check for existence of string length and a dash?
    if(scope.timeformat){
      var temp = scope.timeformat.format;
      var timeformat = (simpleDates[temp]) ? simpleDates[temp] : temp;
      var format = d3.time.format(timeformat);
      scope.dataSet.forEach(function(element){
          element[xItems] = format(new Date(element[xItems]));
      });
    }

    var xScale = d3.scale.ordinal()
        .domain(scope.dataSet.map(function(val){ return val[xItems]; }))
        .rangeBands([0, width], 0.1);

    var minYLabel = d3.min(scope.dataSet, function(d){ return d[yItems]; });
    var maxYLabel = d3.max(scope.dataSet, function(d){ return d[yItems]; });
    //shouldnt make this min - max on y scale default,
    //should give option to be 0 - max on y scale
    var yScale = d3.scale.linear()
        .domain([
          minYLabel,
          maxYLabel
        ])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom');

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left');

    //SVG
    var svg = d3.select(element[0]).append('svg')
        .attr('width',  width  + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .attr('class', 'svgContainer');

    //INNER SPACE on SVG
    var innerSpace = svg.append('g')
        .attr('transform', tlate(margin.left, margin.top))
        .attr('class', 'innerSpace');

    //X AXIS TEXT
    innerSpace.append('g')
              .attr('transform', tlate(0, height))
              .attr('class', 'x axis')
              .call(xAxis)
              .selectAll('text')
                  .style('text-anchor', 'end')
                  .attr('dx', '-.8em')
                  .attr('dy', '.30em')
                  .attr('font-size', 11)
                  .attr('transform', function(d){ return 'rotate(-45)'; });
                  //potentially only need rotation if the words are too big
                  //leave by default? dynamically check?

    //Y AXIS LEGEND TEXT
    var yAxisLegend = innerSpace.append('g')
                                  .attr('class', 'y axis')
                                  .call(yAxis)
                                  .append('text')
                                      .attr('y', -4)
                                      .attr('dy', '.61em')
                                      .attr('transform', 'rotate(-90)')
                                      .style('text-anchor', 'end')
                                      .style('fill', 'slategrey')
                                      // .attr('font-size', 22)
                                      .text(yItems.charAt(0).toUpperCase() + yItems.slice(1));
                                      //simple in that it uses the property on the object
                                      //but is limiting in that doesnt have custom name outside
                                      //of this option for the y label

    //BARS
    var bars = innerSpace.selectAll('.bar')
              .data(scope.dataSet)
              .enter().append('rect')
                  .attr('class', 'bar')
                  .attr('x', xScale(0))
                  .attr('y', yScale(0))
                  .attr('height', 0);

      ///////////////////////////////////////////////////////////////////////////////////
      //FANCINESS FOR BARS
      ///////////////////////////////////////////////////////////////////////////////////

      //TODO remove repeatability
      fanciness.push('defaultVis'); //in case they dont have any BAR appearance animations
      var fancyFunks = {};

      //BAR simple appearance
      fancyFunks.emphasizeLow = function(){
        bars.style('opacity', function(d){ return 1 - (0.5 * d[yItems] / maxYLabel); });
      };
      fancyFunks.emphasizeHigh = function(){
        bars.style('opacity', function(d){ return 0.5 + (0.5 * d[yItems] / maxYLabel); });
      };
      fancyFunks.tip = function(){
        var tooltip = d3.select(element[0]).append('div')
                            .attr('class', 'bobby')
                            .style('position', 'absolute')
                            .style('z-index', '10')
                            .style('visibility', 'hidden')
                            .html('a SIMPLE tooltip');

        bars.on("mouseover", function(d, i){
          tooltip.html(''+d[xItems] +'
'+ d[yItems]+'');
          return tooltip.style("visibility", "visible");
        })
        .on("mousemove", function(){ return tooltip.style("top", (event.pageY-12)+"px").style("left",(event.pageX+12)+"px");})
        .on("mouseout",  function(){ return tooltip.style("visibility", "hidden");});
      };

      //BAR appearance animations (only one per)
      var fancyBarAnim = ['bounceUp', 'bounceDown', 'grow'];

      //use default bar animation if they dont have any bar animations listed in the attribute
      //that collide with our fancyBarAnim list a couple lines above here
      fancyFunks.defaultVis = function(){
        var useDefaultVis = fanciness.every(function(elem){
          if(fancyBarAnim.indexOf(elem) === -1) return true;
        });

        if(useDefaultVis){
          bars.attr('x', function(d){ return xScale(d[xItems]); })
            .attr('y', function(d){ return yScale(d[yItems]); })
            .attr('width', xScale.rangeBand())
            .attr('height', function(d){ return height - yScale(d[yItems]); });
        }
      };

      fancyFunks.bounceUp = function(){
        bars.transition()
              .attr('x', function(d,i){ return xScale(d[xItems]); })
              .attr('y', function(d,i){ return yScale(d[yItems]); })
              .duration(2000)
              .delay(50)
              .ease('elastic')
              .attr('width', xScale.rangeBand())
              .attr('height', function(d){ return height - yScale(d[yItems]); });
      };

      fancyFunks.grow = function(){
        bars.transition()
            .duration(1000)
            .attr('x', function(d,i){ return xScale(d[xItems]); })
            .attr('y', function(d,i){ return yScale(d[yItems]); })
            .attr('width', xScale.rangeBand())
            .attr('height', function(d){ return height - yScale(d[yItems]); });
      };

      //activate given fanciness options
      fanciness.forEach(function(val){
        fancyFunks[val]();
      });

    //OLD TOOLTIP

    //create tooltip and correlating event handlers
    // var tooltip = d3.select(element[0]).append('div')
    //     .attr('class', 'tooltip')
    //     .style('opacity', 0);

    // bars.on('mouseover', function(d){
    //   tooltip.transition()
    //      .duration(200)
    //      .style('opacity', .9)

    //   tooltip.html(''+d[xItems] +'
'+ d[yItems])
    //          .style('left', (d3.event.pageX) + 'px')
    //          .style('top', (d3.event.pageY - 28) + 'px')
    // })

    // bars.on('mouseout', function(d){
    //   tooltip.transition()
    //           .duration(500)
    //           .style('opacity',0)
    // })

  }//end link()

  return {
    restrict: 'E',
    scope: { dataSet:'=data', margins:'=', size:'=', labels:'=', timeformat:'='},
    link: link
  };
});<commit_msg>added stepGrow<commit_after>angular.module('ngDatum')
.directive('ndBarchart', function() {
  function tlate(x, y){return 'translate(' + x + ',' + y + ')';}
  function clog(x){console.log(x);}

  function link(scope, element, attr) {

    var fanciness = [];
    if(attr.fanciness){
      fanciness = attr.fanciness.split(',').map(function(val){ return val.trim(); });
    }

    //ADJUST FONT DYNAMICALLY
    var simpleDates = {
      'short': '%b-%d',
      'med':   '%b-%d \'%y',
      'long':  ''
    };

    //time formats
    //time formatting choosing time.scale
    var customMargins = scope.margins || {};
    var customSize    = scope.size    || {};
    var labels        = scope.labels  || {};
    var margin        = {};

    //TODO: figure out how to make this flexible
    //for CSV/TSV
    var xItems = labels.x || 'NEED X LABEL';
    var yItems = labels.y || 'NEED Y LABEL';

    margin.left   = customMargins.left   || 30;
    margin.right  = customMargins.right  || 30;
    margin.top    = customMargins.top    || 50;
    margin.bottom = customMargins.bottom || 55; //can handle "long date"

    var width  = (customSize.width  || 800) - margin.left - margin.right;
    var height = (customSize.height || 400) - margin.top  - margin.bottom;

    //figure out how to manage different time formats
    //unix time, check for existence of string length and a dash?
    if(scope.timeformat){
      var temp = scope.timeformat.format;
      var timeformat = (simpleDates[temp]) ? simpleDates[temp] : temp;
      var format = d3.time.format(timeformat);
      scope.dataSet.forEach(function(element){
          element[xItems] = format(new Date(element[xItems]));
      });
    }

    var xScale = d3.scale.ordinal()
        .domain(scope.dataSet.map(function(val){ return val[xItems]; }))
        .rangeBands([0, width], 0.1);

    var minYLabel = d3.min(scope.dataSet, function(d){ return d[yItems]; });
    var maxYLabel = d3.max(scope.dataSet, function(d){ return d[yItems]; });
    //shouldnt make this min - max on y scale default,
    //should give option to be 0 - max on y scale
    var yScale = d3.scale.linear()
        .domain([
          minYLabel,
          maxYLabel
        ])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom');

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left');

    //SVG
    var svg = d3.select(element[0]).append('svg')
        .attr('width',  width  + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .attr('class', 'svgContainer');

    //INNER SPACE on SVG
    var innerSpace = svg.append('g')
        .attr('transform', tlate(margin.left, margin.top))
        .attr('class', 'innerSpace');

    //X AXIS TEXT
    innerSpace.append('g')
              .attr('transform', tlate(0, height))
              .attr('class', 'x axis')
              .call(xAxis)
              .selectAll('text')
                  .style('text-anchor', 'end')
                  .attr('dx', '-.8em')
                  .attr('dy', '.30em')
                  .attr('font-size', 11)
                  .attr('transform', function(d){ return 'rotate(-45)'; });
                  //potentially only need rotation if the words are too big
                  //leave by default? dynamically check?

    //Y AXIS LEGEND TEXT
    var yAxisLegend = innerSpace.append('g')
                                  .attr('class', 'y axis')
                                  .call(yAxis)
                                  .append('text')
                                      .attr('y', -4)
                                      .attr('dy', '.61em')
                                      .attr('transform', 'rotate(-90)')
                                      .style('text-anchor', 'end')
                                      .style('fill', 'slategrey')
                                      // .attr('font-size', 22)
                                      .text(yItems.charAt(0).toUpperCase() + yItems.slice(1));
                                      //simple in that it uses the property on the object
                                      //but is limiting in that doesnt have custom name outside
                                      //of this option for the y label

    //BARS
    var bars = innerSpace.selectAll('.bar')
              .data(scope.dataSet)
              .enter().append('rect')
                  .attr('class', 'bar')
                  .attr('x', xScale(0))
                  .attr('y', yScale(0))
                  .attr('height', 0);

      ///////////////////////////////////////////////////////////////////////////////////
      //FANCINESS FOR BARS
      ///////////////////////////////////////////////////////////////////////////////////

      //TODO remove repeatability
      fanciness.push('defaultVis'); //in case they dont have any BAR appearance animations
      var fancyFunks = {};

      //BAR simple appearance
      fancyFunks.emphasizeLow = function(){
        bars.style('opacity', function(d){ return 1 - (0.5 * d[yItems] / maxYLabel); });
      };
      fancyFunks.emphasizeHigh = function(){
        bars.style('opacity', function(d){ return 0.5 + (0.5 * d[yItems] / maxYLabel); });
      };
      fancyFunks.tip = function(){
        var tooltip = d3.select(element[0]).append('div')
                            .attr('class', 'bobby')
                            .style('position', 'absolute')
                            .style('z-index', '10')
                            .style('visibility', 'hidden')
                            .html('a SIMPLE tooltip');

        bars.on("mouseover", function(d, i){
          tooltip.html(''+d[xItems] +'
'+ d[yItems]+'');
          return tooltip.style("visibility", "visible");
        })
        .on("mousemove", function(){ return tooltip.style("top", (event.pageY-12)+"px").style("left",(event.pageX+12)+"px");})
        .on("mouseout",  function(){ return tooltip.style("visibility", "hidden");});
      };

      //BAR appearance animations (only one per)
      var fancyBarAnim = ['bounceUp', 'bounceDown', 'grow'];

      //use default bar animation if they dont have any bar animations listed in the attribute
      //that collide with our fancyBarAnim list a couple lines above here
      fancyFunks.defaultVis = function(){
        var useDefaultVis = fanciness.every(function(elem){
          if(fancyBarAnim.indexOf(elem) === -1) return true;
        });

        if(useDefaultVis){
          bars.attr('x', function(d){ return xScale(d[xItems]); })
            .attr('y', function(d){ return yScale(d[yItems]); })
            .attr('width', xScale.rangeBand())
            .attr('height', function(d){ return height - yScale(d[yItems]); });
        }
      };

      fancyFunks.bounceUp = function(){
        bars.transition()
              .attr('x', function(d,i){ return xScale(d[xItems]); })
              .attr('y', function(d,i){ return yScale(d[yItems]); })
              .duration(2000)
              .delay(50)
              .ease('elastic')
              .attr('width', xScale.rangeBand())
              .attr('height', function(d){ return height - yScale(d[yItems]); });
      };

      fancyFunks.grow = function(){
        bars.transition()
            .duration(1000)
            .attr('x', function(d,i){ return xScale(d[xItems]); })
            .attr('y', function(d,i){ return yScale(d[yItems]); })
            .attr('width', xScale.rangeBand())
            .attr('height', function(d){ return height - yScale(d[yItems]); });
      };

      //prototype NOT TESTED
      fancyFunks.stepGrow = function(){
        bars.transition()
            .duration(function(d,i){
              return parseInt(i + '00' );
            })
            .attr('x', function(d,i){ return xScale(d[xItems]); })
            .attr('y', function(d,i){ return yScale(d[yItems]); })
            .attr('width', xScale.rangeBand())
            .attr('height', function(d){ return height - yScale(d[yItems]); });
      };

      //activate given fanciness options
      fanciness.forEach(function(val){
        fancyFunks[val]();
      });

    //OLD TOOLTIP

    //create tooltip and correlating event handlers
    // var tooltip = d3.select(element[0]).append('div')
    //     .attr('class', 'tooltip')
    //     .style('opacity', 0);

    // bars.on('mouseover', function(d){
    //   tooltip.transition()
    //      .duration(200)
    //      .style('opacity', .9)

    //   tooltip.html(''+d[xItems] +'
'+ d[yItems])
    //          .style('left', (d3.event.pageX) + 'px')
    //          .style('top', (d3.event.pageY - 28) + 'px')
    // })

    // bars.on('mouseout', function(d){
    //   tooltip.transition()
    //           .duration(500)
    //           .style('opacity',0)
    // })

  }//end link()

  return {
    restrict: 'E',
    scope: { dataSet:'=data', margins:'=', size:'=', labels:'=', timeformat:'='},
    link: link
  };
});<|endoftext|>


<commit_before>/* eslint-disable react/jsx-sort-props */
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { Grid, Row, Col, Image, Button } from '@freecodecamp/react-bootstrap';

import ShowProjectLinks from './ShowProjectLinks';
import FreeCodeCampLogo from '../assets/icons/FreeCodeCampLogo';
// eslint-disable-next-line max-len
import DonateForm from '../components/Donation/DonateForm';
import { Trans, useTranslation } from 'react-i18next';

import {
  showCertSelector,
  showCertFetchStateSelector,
  showCert,
  userFetchStateSelector,
  usernameSelector,
  isDonatingSelector,
  executeGA,
  userByNameSelector,
  fetchProfileForUser
} from '../redux';
import { certMap } from '../../src/resources/certAndProjectMap';
import { createFlashMessage } from '../components/Flash/redux';
import standardErrorMessage from '../utils/standardErrorMessage';
import reallyWeirdErrorMessage from '../utils/reallyWeirdErrorMessage';
import { langCodes } from '../../../config/i18n/all-langs';
import { clientLocale } from '../../../config/env.json';

import RedirectHome from '../components/RedirectHome';
import { Loader, Spacer } from '../components/helpers';
import { isEmpty } from 'lodash';

const localeCode = langCodes[clientLocale];

const propTypes = {
  cert: PropTypes.shape({
    username: PropTypes.string,
    name: PropTypes.string,
    certName: PropTypes.string,
    certTitle: PropTypes.string,
    completionTime: PropTypes.number,
    date: PropTypes.number
  }),
  certDashedName: PropTypes.string,
  certName: PropTypes.string,
  createFlashMessage: PropTypes.func.isRequired,
  executeGA: PropTypes.func,
  fetchProfileForUser: PropTypes.func,
  fetchState: PropTypes.shape({
    pending: PropTypes.bool,
    complete: PropTypes.bool,
    errored: PropTypes.bool
  }),
  isDonating: PropTypes.bool,
  location: PropTypes.shape({
    pathname: PropTypes.string
  }),
  showCert: PropTypes.func.isRequired,
  signedInUserName: PropTypes.string,
  user: PropTypes.shape({
    completedChallenges: PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.string,
        solution: PropTypes.string,
        githubLink: PropTypes.string,
        files: PropTypes.arrayOf(
          PropTypes.shape({
            contents: PropTypes.string,
            ext: PropTypes.string,
            key: PropTypes.string,
            name: PropTypes.string,
            path: PropTypes.string
          })
        )
      })
    ),
    profileUI: PropTypes.shape({
      showName: PropTypes.bool
    }),
    username: PropTypes.string
  }),
  userFetchState: PropTypes.shape({
    complete: PropTypes.bool
  }),
  userFullName: PropTypes.string,
  username: PropTypes.string,
  validCertName: PropTypes.bool
};

const requestedUserSelector = (state, { username = '' }) =>
  userByNameSelector(username.toLowerCase())(state);

const validCertNames = certMap.map(cert => cert.slug);

const mapStateToProps = (state, props) => {
  const validCertName = validCertNames.some(name => name === props.certName);
  return createSelector(
    showCertSelector,
    showCertFetchStateSelector,
    usernameSelector,
    userFetchStateSelector,
    isDonatingSelector,
    requestedUserSelector,
    (cert, fetchState, signedInUserName, userFetchState, isDonating, user) => ({
      cert,
      fetchState,
      validCertName,
      signedInUserName,
      userFetchState,
      isDonating,
      user
    })
  );
};

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    { createFlashMessage, showCert, fetchProfileForUser, executeGA },
    dispatch
  );

const ShowCertification = props => {
  const { t } = useTranslation();
  const [isDonationSubmitted, setIsDonationSubmitted] = useState(false);
  const [isDonationDisplayed, setIsDonationDisplayed] = useState(false);
  const [isDonationClosed, setIsDonationClosed] = useState(false);

  useEffect(() => {
    const { username, certName, validCertName, showCert } = props;
    if (validCertName) {
      showCert({ username, certName });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    const {
      userFetchState: { complete: userComplete },
      signedInUserName,
      isDonating,
      cert: { username = '' },
      fetchProfileForUser,
      user,
      executeGA
    } = props;

    if (!signedInUserName || signedInUserName !== username) {
      if (isEmpty(user) && username) {
        fetchProfileForUser(username);
      }
    }

    if (
      !isDonationDisplayed &&
      userComplete &&
      signedInUserName &&
      signedInUserName === username &&
      !isDonating
    ) {
      setIsDonationDisplayed(true);

      executeGA({
        type: 'event',
        data: {
          category: 'Donation View',
          action: 'Displayed Certificate Donation',
          nonInteraction: true
        }
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    isDonationDisplayed,
    props.userFetchState,
    props.signedInUserName,
    props.isDonating,
    props.cert,
    props.executeGA
  ]);

  const hideDonationSection = () => {
    setIsDonationDisplayed(false);
    setIsDonationClosed(true);
  };

  const handleProcessing = (
    duration,
    amount,
    action = 'stripe form submission'
  ) => {
    props.executeGA({
      type: 'event',
      data: {
        category: 'Donation',
        action: `certificate ${action}`,
        label: duration,
        value: amount
      }
    });
    setIsDonationSubmitted(true);
  };

  const {
    cert,
    fetchState,
    validCertName,
    createFlashMessage,
    signedInUserName,
    location: { pathname }
  } = props;

  if (!validCertName) {
    createFlashMessage(standardErrorMessage);
    return <RedirectHome />;
  }

  const { pending, complete, errored } = fetchState;

  if (pending) {
    return <Loader fullScreen={true} />;
  }

  if (!pending && errored) {
    createFlashMessage(standardErrorMessage);
    return <RedirectHome />;
  }

  if (!pending && !complete && !errored) {
    createFlashMessage(reallyWeirdErrorMessage);
    return <RedirectHome />;
  }

  const {
    date,
    name: userFullName = null,
    username,
    certTitle,
    completionTime
  } = cert;

  const { user } = props;

  const displayName = userFullName ?? username;

  const certDate = new Date(date);
  const certYear = certDate.getFullYear();
  const certMonth = certDate.getMonth();
  const certURL = `https://freecodecamp.org${pathname}`;

  const donationCloseBtn = (

      <Button
        block={true}
        bsSize='sm'
        bsStyle='primary'
        onClick={hideDonationSection}
      >
        {t('buttons.close')}
      </Button>

  );

  let donationSection = (
    <Grid className='donation-section'>
      {!isDonationSubmitted && (
        <Row>
          <Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>

{t('donate.only-you')}

          </Col>
        </Row>
      )}
      <DonateForm
        handleProcessing={handleProcessing}
        defaultTheme='light'
        isMinimalForm={true}
      />
      <Row>
        <Col sm={4} smOffset={4} xs={6} xsOffset={3}>
          {isDonationSubmitted && donationCloseBtn}
        </Col>
      </Row>
    </Grid>
  );

  const shareCertBtns = (
    <Row className='text-center'>
      <Spacer size={2} />
      <Button
        block={true}
        bsSize='lg'
        bsStyle='primary'
        target='_blank'
        href={`https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&name=${certTitle}&organizationId=4831032&issueYear=${certYear}&issueMonth=${certMonth +
          1}&certUrl=${certURL}`}
      >
        {t('profile.add-linkedin')}
      </Button>
      <Spacer />
      <Button
        block={true}
        bsSize='lg'
        bsStyle='primary'
        target='_blank'
        href={`https://twitter.com/intent/tweet?text=${t('profile.tweet', {
          certTitle: certTitle,
          certURL: certURL
        })}`}
      >
        {t('profile.add-twitter')}
      </Button>
    </Row>
  );

  return (

      {isDonationDisplayed && !isDonationClosed ? donationSection : ''}
      <Grid className='certificate-wrapper certification-namespace'>
        <Row>

            <Col md={5} sm={12}>

                <FreeCodeCampLogo />

            </Col>
            <Col md={7} sm={12}>

                {t('certification.issued')}

                  {certDate.toLocaleString([localeCode, 'en-US'], {
                    year: 'numeric',
                    month: 'long',
                    day: 'numeric'
                  })}

            </Col>

              <Trans
                user={displayName}
                title={certTitle}
                time={completionTime}
                i18nKey='certification.fulltext'
              >

placeholder

                  {{ user: displayName }}

placeholder

                  {{ title: certTitle }}

{{ time: completionTime }}

              </Trans>

              <Image
                alt="Quincy Larson's Signature"
                src={
                  'https://cdn.freecodecamp.org' +
                  '/platform/english/images/quincy-larson-signature.svg'
                }
              />

                Quincy Larson

{t('certification.executive')}

            <Row>

                {t('certification.verify', { certURL: certURL })}

            </Row>

        </Row>
      </Grid>
      {signedInUserName === username ? shareCertBtns : ''}
      <Spacer size={2} />
      <ShowProjectLinks user={user} name={displayName} certName={certTitle} />

  );
};

ShowCertification.displayName = 'ShowCertification';
ShowCertification.propTypes = propTypes;

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ShowCertification);
<commit_msg>fix: update certification page padding-bottom (#41158)<commit_after>/* eslint-disable react/jsx-sort-props */
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { Grid, Row, Col, Image, Button } from '@freecodecamp/react-bootstrap';

import ShowProjectLinks from './ShowProjectLinks';
import FreeCodeCampLogo from '../assets/icons/FreeCodeCampLogo';
// eslint-disable-next-line max-len
import DonateForm from '../components/Donation/DonateForm';
import { Trans, useTranslation } from 'react-i18next';

import {
  showCertSelector,
  showCertFetchStateSelector,
  showCert,
  userFetchStateSelector,
  usernameSelector,
  isDonatingSelector,
  executeGA,
  userByNameSelector,
  fetchProfileForUser
} from '../redux';
import { certMap } from '../../src/resources/certAndProjectMap';
import { createFlashMessage } from '../components/Flash/redux';
import standardErrorMessage from '../utils/standardErrorMessage';
import reallyWeirdErrorMessage from '../utils/reallyWeirdErrorMessage';
import { langCodes } from '../../../config/i18n/all-langs';
import { clientLocale } from '../../../config/env.json';

import RedirectHome from '../components/RedirectHome';
import { Loader, Spacer } from '../components/helpers';
import { isEmpty } from 'lodash';

const localeCode = langCodes[clientLocale];

const propTypes = {
  cert: PropTypes.shape({
    username: PropTypes.string,
    name: PropTypes.string,
    certName: PropTypes.string,
    certTitle: PropTypes.string,
    completionTime: PropTypes.number,
    date: PropTypes.number
  }),
  certDashedName: PropTypes.string,
  certName: PropTypes.string,
  createFlashMessage: PropTypes.func.isRequired,
  executeGA: PropTypes.func,
  fetchProfileForUser: PropTypes.func,
  fetchState: PropTypes.shape({
    pending: PropTypes.bool,
    complete: PropTypes.bool,
    errored: PropTypes.bool
  }),
  isDonating: PropTypes.bool,
  location: PropTypes.shape({
    pathname: PropTypes.string
  }),
  showCert: PropTypes.func.isRequired,
  signedInUserName: PropTypes.string,
  user: PropTypes.shape({
    completedChallenges: PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.string,
        solution: PropTypes.string,
        githubLink: PropTypes.string,
        files: PropTypes.arrayOf(
          PropTypes.shape({
            contents: PropTypes.string,
            ext: PropTypes.string,
            key: PropTypes.string,
            name: PropTypes.string,
            path: PropTypes.string
          })
        )
      })
    ),
    profileUI: PropTypes.shape({
      showName: PropTypes.bool
    }),
    username: PropTypes.string
  }),
  userFetchState: PropTypes.shape({
    complete: PropTypes.bool
  }),
  userFullName: PropTypes.string,
  username: PropTypes.string,
  validCertName: PropTypes.bool
};

const requestedUserSelector = (state, { username = '' }) =>
  userByNameSelector(username.toLowerCase())(state);

const validCertNames = certMap.map(cert => cert.slug);

const mapStateToProps = (state, props) => {
  const validCertName = validCertNames.some(name => name === props.certName);
  return createSelector(
    showCertSelector,
    showCertFetchStateSelector,
    usernameSelector,
    userFetchStateSelector,
    isDonatingSelector,
    requestedUserSelector,
    (cert, fetchState, signedInUserName, userFetchState, isDonating, user) => ({
      cert,
      fetchState,
      validCertName,
      signedInUserName,
      userFetchState,
      isDonating,
      user
    })
  );
};

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    { createFlashMessage, showCert, fetchProfileForUser, executeGA },
    dispatch
  );

const ShowCertification = props => {
  const { t } = useTranslation();
  const [isDonationSubmitted, setIsDonationSubmitted] = useState(false);
  const [isDonationDisplayed, setIsDonationDisplayed] = useState(false);
  const [isDonationClosed, setIsDonationClosed] = useState(false);

  useEffect(() => {
    const { username, certName, validCertName, showCert } = props;
    if (validCertName) {
      showCert({ username, certName });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    const {
      userFetchState: { complete: userComplete },
      signedInUserName,
      isDonating,
      cert: { username = '' },
      fetchProfileForUser,
      user,
      executeGA
    } = props;

    if (!signedInUserName || signedInUserName !== username) {
      if (isEmpty(user) && username) {
        fetchProfileForUser(username);
      }
    }

    if (
      !isDonationDisplayed &&
      userComplete &&
      signedInUserName &&
      signedInUserName === username &&
      !isDonating
    ) {
      setIsDonationDisplayed(true);

      executeGA({
        type: 'event',
        data: {
          category: 'Donation View',
          action: 'Displayed Certificate Donation',
          nonInteraction: true
        }
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    isDonationDisplayed,
    props.userFetchState,
    props.signedInUserName,
    props.isDonating,
    props.cert,
    props.executeGA
  ]);

  const hideDonationSection = () => {
    setIsDonationDisplayed(false);
    setIsDonationClosed(true);
  };

  const handleProcessing = (
    duration,
    amount,
    action = 'stripe form submission'
  ) => {
    props.executeGA({
      type: 'event',
      data: {
        category: 'Donation',
        action: `certificate ${action}`,
        label: duration,
        value: amount
      }
    });
    setIsDonationSubmitted(true);
  };

  const {
    cert,
    fetchState,
    validCertName,
    createFlashMessage,
    signedInUserName,
    location: { pathname }
  } = props;

  if (!validCertName) {
    createFlashMessage(standardErrorMessage);
    return <RedirectHome />;
  }

  const { pending, complete, errored } = fetchState;

  if (pending) {
    return <Loader fullScreen={true} />;
  }

  if (!pending && errored) {
    createFlashMessage(standardErrorMessage);
    return <RedirectHome />;
  }

  if (!pending && !complete && !errored) {
    createFlashMessage(reallyWeirdErrorMessage);
    return <RedirectHome />;
  }

  const {
    date,
    name: userFullName = null,
    username,
    certTitle,
    completionTime
  } = cert;

  const { user } = props;

  const displayName = userFullName ?? username;

  const certDate = new Date(date);
  const certYear = certDate.getFullYear();
  const certMonth = certDate.getMonth();
  const certURL = `https://freecodecamp.org${pathname}`;

  const donationCloseBtn = (

      <Button
        block={true}
        bsSize='sm'
        bsStyle='primary'
        onClick={hideDonationSection}
      >
        {t('buttons.close')}
      </Button>

  );

  let donationSection = (
    <Grid className='donation-section'>
      {!isDonationSubmitted && (
        <Row>
          <Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>

{t('donate.only-you')}

          </Col>
        </Row>
      )}
      <DonateForm
        handleProcessing={handleProcessing}
        defaultTheme='light'
        isMinimalForm={true}
      />
      <Row>
        <Col sm={4} smOffset={4} xs={6} xsOffset={3}>
          {isDonationSubmitted && donationCloseBtn}
        </Col>
      </Row>
    </Grid>
  );

  const shareCertBtns = (
    <Row className='text-center'>
      <Spacer size={2} />
      <Button
        block={true}
        bsSize='lg'
        bsStyle='primary'
        target='_blank'
        href={`https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&name=${certTitle}&organizationId=4831032&issueYear=${certYear}&issueMonth=${certMonth +
          1}&certUrl=${certURL}`}
      >
        {t('profile.add-linkedin')}
      </Button>
      <Spacer />
      <Button
        block={true}
        bsSize='lg'
        bsStyle='primary'
        target='_blank'
        href={`https://twitter.com/intent/tweet?text=${t('profile.tweet', {
          certTitle: certTitle,
          certURL: certURL
        })}`}
      >
        {t('profile.add-twitter')}
      </Button>
    </Row>
  );

  return (

      {isDonationDisplayed && !isDonationClosed ? donationSection : ''}
      <Grid className='certificate-wrapper certification-namespace'>
        <Row>

            <Col md={5} sm={12}>

                <FreeCodeCampLogo />

            </Col>
            <Col md={7} sm={12}>

                {t('certification.issued')}

                  {certDate.toLocaleString([localeCode, 'en-US'], {
                    year: 'numeric',
                    month: 'long',
                    day: 'numeric'
                  })}

            </Col>

              <Trans
                user={displayName}
                title={certTitle}
                time={completionTime}
                i18nKey='certification.fulltext'
              >

placeholder

                  {{ user: displayName }}

placeholder

                  {{ title: certTitle }}

{{ time: completionTime }}

              </Trans>

              <Image
                alt="Quincy Larson's Signature"
                src={
                  'https://cdn.freecodecamp.org' +
                  '/platform/english/images/quincy-larson-signature.svg'
                }
              />

                Quincy Larson

{t('certification.executive')}

            <Row>

                {t('certification.verify', { certURL: certURL })}

            </Row>

        </Row>
      </Grid>
      {signedInUserName === username ? shareCertBtns : ''}
      <Spacer size={2} />
      <ShowProjectLinks user={user} name={displayName} certName={certTitle} />
      <Spacer size={2} />

  );
};

ShowCertification.displayName = 'ShowCertification';
ShowCertification.propTypes = propTypes;

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ShowCertification);
<|endoftext|>


<commit_before>/**
 *  Copyright (C) 2009 Orbeon, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version
 *  2.1 of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Lesser General Public License for more details.
 *
 *  The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
(function() {
    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Lang = YAHOO.lang,
        Document = ORBEON.xforms.Document;

    /**
     * Singleton with information about about each map, indexed by ID of the component.
     */
    var maps = {};

    /**
     * Map object constructor
     */
    var Map = function(element) { this.init(element); }
    Map.prototype = {

        /**
         * Attributes
         */
        element: null,
        gmapDivID: null,
        gmap: null,
        geocoder: null,
        addressOutputID: null,
        longitudeInputID: null,
        latitudeInputID: null,
        marker: null,

        /**
         * Constructor
         */
        init: function(element) {

            // Init object attributes
            var gmapDiv = Dom.getElementsByClassName("fb-map-gmap-div", null, element)[0];
            this.element = element;
            this.gmapDivID = gmapDiv.id;
            this.addressOutputID = Dom.getElementsByClassName("fb-map-address", null, element)[0].id;
            this.longitudeInputID = Dom.getElementsByClassName("fb-map-longitude", null, element)[0].id;
            this.latitudeInputID = Dom.getElementsByClassName("fb-map-latitude", null, element)[0].id;
            this.geocoder = new GClientGeocoder();

            // Create map with its controls
            this.gmap = new GMap2(gmapDiv);
            this.gmap.addControl(new GSmallZoomControl3D());
            this.gmap.addControl(new GScaleControl());
            this.gmap.addControl(new GOverviewMapControl());

            // Set location
            this.updateMarkerFromAddress();
        },

        /**
         * Updates the address
         */
        updateMarkerFromAddress: function() {
            var address = Document.getValue(this.addressOutputID);
            var map = this;
            this.geocoder.getLatLng(address, function(longLat) {
                if (longLat != null) {
                    map._updateLongLat(longLat);
                    // Mark location
                    map.gmap.setCenter(longLat, 13);
                    if (map.marker == null) {
                        map.marker = new GMarker(longLat, {draggable: true});
                        map.gmap.addOverlay(map.marker);
                        GEvent.addListener(map.marker, "dragend", function(longLat) { map._updateLongLat(longLat); });
                    } else{
                        map.marker.setLatLng(longLat)
                    }
                }
            });
        },

        _updateLongLat: function(longLat) {
            Document.setValue(this.longitudeInputID, longLat.lng());
            Document.setValue(this.latitudeInputID, longLat.lat());
        }
    };

    ORBEON.widget.MapEvents = {

        /**
         * Called when the group containing the map becomes enabled.
         */
        mapContainerXFormsEnabled: function() {
            var mapContainer = this;
            var mapID = mapContainer.parentNode.id;
            if (!Lang.isObject(maps[mapID])) {
                maps[mapID] = new Map(mapContainer.parentNode);
            }
        },

        /**
         * Called when the address provided to the component changes.
         */
        addressXFormsValueChanged: function() {
            var mapID = this.parentNode.parentNode.id;
            maps[mapID].updateMarkerFromAddress();
        }
    };

})();

<commit_msg>Implement [ #313576 ] RFE: Map XBL: don't set lat/long based on address unless marker is moved<commit_after>/**
 *  Copyright (C) 2009 Orbeon, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version
 *  2.1 of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Lesser General Public License for more details.
 *
 *  The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
(function() {
    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Lang = YAHOO.lang,
        Document = ORBEON.xforms.Document;

    /**
     * Singleton with information about about each map, indexed by ID of the component.
     */
    var maps = {};

    /**
     * Map object constructor
     */
    var Map = function(element) { this.init(element); }
    Map.prototype = {

        /**
         * Attributes
         */
        element: null,
        gmapDivID: null,
        gmap: null,
        geocoder: null,
        addressOutputID: null,
        longitudeInputID: null,
        latitudeInputID: null,
        marker: null,

        /**
         * Constructor
         */
        init: function(element) {

            // Init object attributes
            var gmapDiv = Dom.getElementsByClassName("fb-map-gmap-div", null, element)[0];
            this.element = element;
            this.gmapDivID = gmapDiv.id;
            this.addressOutputID = Dom.getElementsByClassName("fb-map-address", null, element)[0].id;
            this.longitudeInputID = Dom.getElementsByClassName("fb-map-longitude", null, element)[0].id;
            this.latitudeInputID = Dom.getElementsByClassName("fb-map-latitude", null, element)[0].id;
            this.geocoder = new GClientGeocoder();

            // Create map with its controls
            this.gmap = new GMap2(gmapDiv);
            this.gmap.addControl(new GSmallZoomControl3D());
            this.gmap.addControl(new GScaleControl());
            this.gmap.addControl(new GOverviewMapControl());

            // Set location
            var initialLatitude = Document.getValue(this.latitudeInputID);
            var initialLongitude = Document.getValue(this.longitudeInputID);
            if (initialLatitude != "" && initialLongitude != "") {
                var latLng = new GLatLng(new Number(initialLatitude), new Number(initialLongitude));
                this.updateMarkerFromLatLng(latLng);
            } else {
                this.updateMarkerFromAddress();
            }
        },

        updateMarkerFromAddress: function() {
            var map = this;
            var address = Document.getValue(map.addressOutputID);
            this.geocoder.getLatLng(address, function(latLng) {
                if (latLng != null) {
                    map.updateMarkerFromLatLng(latLng);
                }
            });
        },

        updateMarkerFromLatLng: function(latLng) {
            var map = this;
            map.gmap.setCenter(latLng, 13);
            if (map.marker == null) {
                map.marker = new GMarker(latLng, {draggable: true});
                map.gmap.addOverlay(map.marker);
                GEvent.addListener(map.marker, "dragend", function(latLng) { map._updateLongLat(latLng); });
            } else{
                map.marker.setLatLng(latLng);
            }
        },

        _updateLongLat: function(longLat) {
            Document.setValue(this.longitudeInputID, longLat.lng());
            Document.setValue(this.latitudeInputID, longLat.lat());
        }
    };

    ORBEON.widget.MapEvents = {

        /**
         * Called when the group containing the map becomes enabled.
         */
        mapContainerXFormsEnabled: function() {
            var mapContainer = this;
            var mapID = mapContainer.parentNode.id;
            if (!Lang.isObject(maps[mapID])) {
                maps[mapID] = new Map(mapContainer.parentNode);
            }
        },

        /**
         * Called when the address provided to the component changes.
         */
        addressXFormsValueChanged: function() {
            var mapID = this.parentNode.parentNode.id;
            maps[mapID].updateMarkerFromAddress();
        }
    };

})();

<|endoftext|>


<commit_before>var TYPE = 1;
var TOPIC = "subscriber";
var PUBLISHER_TOPIC = "node-clicked";
var page = gadgetUtil.getCurrentPage();
var qs = gadgetUtil.getQueryString();
var timeFrom, timeTo, timeUnit = null;

var TOPDOWN = "TD";
var LEFT_TO_RIGHT = "LR";
var orientation = TOPDOWN;
var gadgetMaximized = gadgetUtil.getView() == 'maximized';

$(function() {

    if (qs[PARAM_ID] == null) {
        $("#canvas").html(gadgetUtil.getDefaultText());
        return;
    }
    timeFrom = gadgetUtil.timeFrom();
    timeTo = gadgetUtil.timeTo();
    console.log("MESSAGE_FLOW[" + page.name + "]: TimeFrom: " + timeFrom + " TimeTo: " + timeTo);

    gadgetUtil.fetchData(CONTEXT, {
        type: page.type,
        id: qs.id,
        timeFrom: timeFrom,
        timeTo: timeTo
    }, onData, onError);

    $("body").on("click", ".nodeLabel", function(e) {
        e.preventDefault();
        if ($(this).data("node-type") === "UNKNOWN") {
            return;
        }
        if (page.name != TYPE_MESSAGE) {
            var targetUrl = $(this).data("target-url");
            parent.window.location = targetUrl;
        } else {
            var componentId = $(this).data("component-id");
            var hashCode = $(this).data("hash-code");
            console.log("## componentId [ " + componentId + " ] hashCode [ " + hashCode + "]");
            message = {
                componentId: componentId,
                hashCode: hashCode
            };
            gadgets.Hub.publish(PUBLISHER_TOPIC, message);
        }
    });

});

gadgets.HubSettings.onConnect = function() {
    gadgets.Hub.subscribe(TOPIC, function(topic, data, subscriberData) {
        onTimeRangeChanged(data);
    });
};

function onTimeRangeChanged(data) {
    timeFrom = data.timeFrom;
    timeTo = data.timeTo;
    timeUnit = data.timeUnit;
    gadgetUtil.fetchData(CONTEXT, {
        type: page.type,
        id: qs.id,
        timeFrom: timeFrom,
        timeTo: timeTo
    }, onData, onError);
};

function onData(response) {
    var data = response.message;
    if (data.length == 0) {
        $("#canvas").html(gadgetUtil.getEmptyRecordsText());
        return;
    }
    var groups = [];
    $("#canvas").empty();
    var nodes = data;
    // Create the input graph

    orientation = (page.name === TYPE_MESSAGE) ? LEFT_TO_RIGHT : TOPDOWN;

    var g = new dagreD3.graphlib.Graph({ compound: true })
        .setGraph({ rankdir: orientation })
        .setDefaultEdgeLabel(function() {
            return {};
        });

    for (var i = 0; i < nodes.length; i++) {
        if (nodes[i].id != null) {
            //Set Nodes
            if (nodes[i].type == "group") {
                g.setNode(nodes[i].id, { label: "", clusterLabelPos: 'top' });

                //Add arbitary nodes for group
                g.setNode(nodes[i].id + "-s", { label: nodes[i].label, style: 'stroke-width: 0px;' });
                // g.setEdge(nodes[i].id + "-s", nodes[i].id + "-e",  { style: 'stroke-width: 0px; fill: #ffd47f'});
                g.setNode(nodes[i].id + "-e", { label: "", style: 'stroke-width: 0px;' });
                g.setParent(nodes[i].id + "-s", nodes[i].id);
                g.setParent(nodes[i].id + "-e", nodes[i].id);

                groups.push(nodes[i]);
            } else {
                var label = buildLabel(nodes[i]);
                g.setNode(nodes[i].id, { labelType: "html", label: label });
                // g.setNode(nodes[i].id, {label: nodes[i].label});
            }

            //Set Edges
            if (nodes[i].parents != null) {
                for (var x = 0; x < nodes[i].parents.length; x++) {
                    var isParentGroup = false;
                    for (var y = 0; y < groups.length; y++) {
                        if (groups[y].id == nodes[i].parents[x] && groups[y].type == "group") {
                            isParentGroup = true;
                        }
                    }

                    if (nodes[i].type == "group") {
                        if (isParentGroup) {
                            g.setEdge(nodes[i].parents[x] + "-e", nodes[i].id + "-s", { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        } else {
                            g.setEdge(nodes[i].parents[x], nodes[i].id + "-s", { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        }
                    } else {
                        if (isParentGroup) {
                            g.setEdge(nodes[i].parents[x] + "-e", nodes[i].id, { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        } else {
                            g.setEdge(nodes[i].parents[x], nodes[i].id, { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        }
                    }
                }
            }

            if (nodes[i].group != null) {
                g.setParent(nodes[i].id, nodes[i].group);
                if (nodes[i].type != "group" && nodes[i].parents.length == 0) {
                    g.setEdge(nodes[i].group + "-s", nodes[i].id, { style: 'stroke-width: 0px; ' });
                    g.setEdge(nodes[i].id, nodes[i].group + "-e", { style: 'stroke-width: 0px; ' });
                }

            }

        }

    }

    g.nodes().forEach(function(v) {
        var node = g.node(v);

        node.rx = node.ry = 7;
    });

    // Create the renderer
    var render = new dagreD3.render();

    var svg = d3.select("svg"),
        svgGroup = svg.append("g");
    inner = svg.select("g"),
        zoom = d3.behavior.zoom().on("zoom", function() {
            inner.attr("transform", "translate(" + d3.event.translate + ")" +
                "scale(" + d3.event.scale + ")");
        });

    //TODO hide zoom when the gadget is gadgetMaximized
    if (gadgetMaximized) {
        svg.call(zoom);
        var nanoScrollerSelector = $(".nano");
        nanoScrollerSelector.nanoScroller();
    } else {

    }
    inner.call(render, g);

    // Zoom and scale to fit
    var graphWidth = g.graph().width + 80;
    var graphHeight = g.graph().height + 40;
    var width = parseInt(svg.style("width").replace(/px/, ""));
    var height = parseInt(svg.style("height").replace(/px/, ""));
    var zoomScale = Math.min(width / graphWidth, height / graphHeight);
    var translate = [(width / 2) - ((graphWidth * zoomScale) / 2), (height / 2) - ((graphHeight * zoomScale) / 2)];

    zoom.translate(translate);
    zoom.scale(zoomScale);
    // zoom.event(isUpdate ? svg.transition().duration(500) : d3.select("svg"));
    zoom.event(svg);

};

function buildLabel(node) {
    var pageUrl = MEDIATOR_PAGE_URL;
    if (node.type === "Sequence") {
        pageUrl = SEQUENCE_PAGE_URL;
    } else if (node.type === "Endpoint") {
        pageUrl = ENDPOINT_PAGE_URL;
    }
    var hashCode;
    var hiddenParams = '';
    if (node.hiddenAttributes) {
        console.log(node.hiddenAttributes);
        node.hiddenAttributes.forEach(function(item, i) {
            hiddenParams += '&' + item.name + '=' + item.value;
            if (item.name === "hashCode") {
                hashCode = item.value;
            }
        });
    }
    var targetUrl = pageUrl + '?' + hiddenParams;
    var labelText = '

' + node.label + "
";

    if (node.dataAttributes && gadgetMaximized) {
        node.dataAttributes.forEach(function(item, i) {
            labelText += "
" + item.name + " : " + item.value + "
";
        });
    }
    labelText += "
";
    return labelText;
};

function onError(msg) {
    $("#canvas").html(gadgetUtil.getErrorText(msg));
};<commit_msg>Message flow sequence alignment fixed<commit_after>var TYPE = 1;
var TOPIC = "subscriber";
var PUBLISHER_TOPIC = "node-clicked";
var page = gadgetUtil.getCurrentPage();
var qs = gadgetUtil.getQueryString();
var timeFrom, timeTo, timeUnit = null;

var TOPDOWN = "TD";
var LEFT_TO_RIGHT = "LR";
var orientation = TOPDOWN;
var gadgetMaximized = gadgetUtil.getView() == 'maximized';

$(function() {

    if (qs[PARAM_ID] == null) {
        $("#canvas").html(gadgetUtil.getDefaultText());
        return;
    }
    timeFrom = gadgetUtil.timeFrom();
    timeTo = gadgetUtil.timeTo();
    console.log("MESSAGE_FLOW[" + page.name + "]: TimeFrom: " + timeFrom + " TimeTo: " + timeTo);

    gadgetUtil.fetchData(CONTEXT, {
        type: page.type,
        id: qs.id,
        timeFrom: timeFrom,
        timeTo: timeTo
    }, onData, onError);

    $("body").on("click", ".nodeLabel", function(e) {
        e.preventDefault();
        if ($(this).data("node-type") === "UNKNOWN") {
            return;
        }
        if (page.name != TYPE_MESSAGE) {
            var targetUrl = $(this).data("target-url");
            parent.window.location = targetUrl;
        } else {
            var componentId = $(this).data("component-id");
            var hashCode = $(this).data("hash-code");
            console.log("## componentId [ " + componentId + " ] hashCode [ " + hashCode + "]");
            message = {
                componentId: componentId,
                hashCode: hashCode
            };
            gadgets.Hub.publish(PUBLISHER_TOPIC, message);
        }
    });

});

gadgets.HubSettings.onConnect = function() {
    gadgets.Hub.subscribe(TOPIC, function(topic, data, subscriberData) {
        onTimeRangeChanged(data);
    });
};

function onTimeRangeChanged(data) {
    timeFrom = data.timeFrom;
    timeTo = data.timeTo;
    timeUnit = data.timeUnit;
    gadgetUtil.fetchData(CONTEXT, {
        type: page.type,
        id: qs.id,
        timeFrom: timeFrom,
        timeTo: timeTo
    }, onData, onError);
};

function onData(response) {
    var data = response.message;
    if (data.length == 0) {
        $("#canvas").html(gadgetUtil.getEmptyRecordsText());
        return;
    }
    var groups = [];
    $("#canvas").empty();
    var nodes = data;
    // Create the input graph

    orientation = (page.name === TYPE_MESSAGE) ? LEFT_TO_RIGHT : TOPDOWN;

    var g = new dagreD3.graphlib.Graph({ compound: true })
        .setGraph({ rankdir: orientation })
        .setDefaultEdgeLabel(function() {
            return {};
        });

    for (var i = 0; i < nodes.length; i++) {
        if (nodes[i].id != null) {
            //Set Nodes
            if (nodes[i].type == "group") {
                g.setNode(nodes[i].id, { label: "", clusterLabelPos: 'top' });

                //Add arbitary nodes for group
                g.setNode(nodes[i].id + "-s", { label: nodes[i].label, style: 'stroke-width: 0px;' });
                // g.setEdge(nodes[i].id + "-s", nodes[i].id + "-e",  { style: 'stroke-width: 0px; fill: #ffd47f'});
                g.setNode(nodes[i].id + "-e", { label: "", style: 'stroke-width: 0px;' });
                g.setParent(nodes[i].id + "-s", nodes[i].id);
                g.setParent(nodes[i].id + "-e", nodes[i].id);

                groups.push(nodes[i]);
            } else {
                var label = buildLabel(nodes[i]);
                g.setNode(nodes[i].id, { labelType: "html", label: label });
                // g.setNode(nodes[i].id, {label: nodes[i].label});
            }

            //Set Edges
            if (nodes[i].parents != null) {
                for (var x = 0; x < nodes[i].parents.length; x++) {
                    var isParentGroup = false;
                    for (var y = 0; y < groups.length; y++) {
                        if (groups[y].id == nodes[i].parents[x] && groups[y].type == "group") {
                            isParentGroup = true;
                        }
                    }

                    if (nodes[i].type == "group") {
                        if (isParentGroup) {
                            g.setEdge(nodes[i].parents[x] + "-e", nodes[i].id + "-s", { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        } else {
                            g.setEdge(nodes[i].parents[x], nodes[i].id + "-s", { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        }
                    } else {
                        if (isParentGroup) {
                            g.setEdge(nodes[i].parents[x] + "-e", nodes[i].id, { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        } else {
                            g.setEdge(nodes[i].parents[x], nodes[i].id, { lineInterpolate: 'basis', arrowheadClass: 'arrowhead' });
                        }
                    }
                }
            }

            if (nodes[i].group != null) {
                g.setParent(nodes[i].id, nodes[i].group);
                if (nodes[i].type != "group" && !isParent(nodes, nodes[i])) {
                    g.setEdge(nodes[i].group + "-s", nodes[i].id, { style: 'stroke-width: 0px; ' });
                    g.setEdge(nodes[i].id, nodes[i].group + "-e", { style: 'stroke-width: 0px; ' });
                }

            }

        }

    }

    g.nodes().forEach(function(v) {
        var node = g.node(v);

        node.rx = node.ry = 7;
    });

    // Create the renderer
    var render = new dagreD3.render();

    var svg = d3.select("svg"),
        svgGroup = svg.append("g");
    inner = svg.select("g"),
        zoom = d3.behavior.zoom().on("zoom", function() {
            inner.attr("transform", "translate(" + d3.event.translate + ")" +
                "scale(" + d3.event.scale + ")");
        });

    //TODO hide zoom when the gadget is gadgetMaximized
    if (gadgetMaximized) {
        svg.call(zoom);
        var nanoScrollerSelector = $(".nano");
        nanoScrollerSelector.nanoScroller();
    } else {

    }
    inner.call(render, g);

    // Zoom and scale to fit
    var graphWidth = g.graph().width + 80;
    var graphHeight = g.graph().height + 40;
    var width = parseInt(svg.style("width").replace(/px/, ""));
    var height = parseInt(svg.style("height").replace(/px/, ""));
    var zoomScale = Math.min(width / graphWidth, height / graphHeight);
    var translate = [(width / 2) - ((graphWidth * zoomScale) / 2), (height / 2) - ((graphHeight * zoomScale) / 2)];

    zoom.translate(translate);
    zoom.scale(zoomScale);
    // zoom.event(isUpdate ? svg.transition().duration(500) : d3.select("svg"));
    zoom.event(svg);

};

function isParent(searchNodes, id) {
   for (var x = 0; x < searchNodes.length; x++) {
        if (searchNodes[x].parent == id) {
            return true;
        }
   }
   return false;
}

function buildLabel(node) {
    var pageUrl = MEDIATOR_PAGE_URL;
    if (node.type === "Sequence") {
        pageUrl = SEQUENCE_PAGE_URL;
    } else if (node.type === "Endpoint") {
        pageUrl = ENDPOINT_PAGE_URL;
    }
    var hashCode;
    var hiddenParams = '';
    if (node.hiddenAttributes) {
        console.log(node.hiddenAttributes);
        node.hiddenAttributes.forEach(function(item, i) {
            hiddenParams += '&' + item.name + '=' + item.value;
            if (item.name === "hashCode") {
                hashCode = item.value;
            }
        });
    }
    var targetUrl = pageUrl + '?' + hiddenParams;
    var labelText = '

' + node.label + "
";

    if (node.dataAttributes && gadgetMaximized) {
        node.dataAttributes.forEach(function(item, i) {
            labelText += "
" + item.name + " : " + item.value + "
";
        });
    }
    labelText += "
";
    return labelText;
};

function onError(msg) {
    $("#canvas").html(gadgetUtil.getErrorText(msg));
};<|endoftext|>


<commit_before>/*
	* dsSizer 1.1
	*
	* Copyright 2016, Denis Stoliarchuk
	* Licensed under the MIT License (LICENSE.txt).
	*
	* Date: Fri Jul 15 21:34:00 2016
*/
(function($){

	$.fn.dsSizer = function (method, options){

		if(!this[method])
			throw '$.dsSizer => The jQuery method "' + method + '" you called does not exist';

		var settings = $.extend({
			absolute      : false,
			cloned        : false,
			includeMargin : false,
			display       : 'block'
		}, options || {});

		var self = this.eq(0);
		var fixIt, restore;

		if(settings.cloned === true){

			fixIt = function (){
				var style = 'position: absolute !important; top: -9999 !important; ';
				self = self.cloned().attr('style', style).appendTo('body');
			};

			restore = function (){ self.remove(); };

		}else{
			var tmp   = [],
				style = '',
				hidden;

			fixIt = function (){
				hidden = self.parents().addBack().filter(':hidden');
				style += 'visibility: hidden !important; display: ' + settings.display + ' !important;';

				if(settings.absolute === true) style += 'position: absolute !important;';

				hidden.each(function(){
					var self     = $(this),
						self_style = self.attr('style');

					tmp.push( self_style );
					self.attr({style: (self_style)? self_style+';'+style : style});
				});
			};

			restore = function (){
				hidden.each( function(i){
					var self  = $( this ),
						_tmp  = tmp[i];

					if(_tmp === undefined) self.removeAttr('style');
					else self.attr('style', _tmp);

				});
			};
		}

		fixIt();
		var size = /(outer)/.test(method) ? self[method](settings.includeMargin) : self[method]();
		restore();

		return size;
	}

/* --------------------------------------------------------------------------------------------------------------------------------- */

/*
	* jquery.dsVerticalizator.js 1.0
	*
	* Copyright 2016, Denis Stoliarchuk
	* Licensed under the MIT License (LICENSE.txt).
	*
	* Date: Fri Jul 15 21:34:00 2016
*/

	$.fn.dsVerticalizator = function(options) {
		var settings = $.extend({
			style:   'top',
			vertical_offset: 0,
			parent: null,
			refresher: 25,
			def_winload: false
		}, options || {});

		return this.each(function(){
			var self   = $(this);
			var timerRef;

			var resize = function () {
				var parentHeight = self.parent().dsSizer('height');
				if(settings.parent && self.parents(settings.parent).length)
					parentHeight = self.parents(settings.parent).first().dsSizer('height');

				var centered = (parentHeight / 2) - (self.dsSizer('height') / 2);
				var centered_with_opts = centered + parseInt(settings.vertical_offset)

				self.css(settings.style, centered_with_opts);

				if (settings.complete !== undefined)
					settings.complete();
			};

			$(window).resize(function () {
				clearTimeout(timerRef);
				timerRef = setTimeout(resize, settings.refresher);
			});

			if (!settings.def_winload) {
				resize();
			}

			$(window).load(function () {
				resize();
			});

		});

	};

})(jQuery);
<commit_msg>Update jquery.dsVerticalizator.js<commit_after>/*
	* dsSizer 1.1
	*
	* Copyright 2016, Denis Stoliarchuk
	* Licensed under the MIT License (LICENSE.txt).
	*
	* Date: Fri Jul 15 21:34:00 2016
*/
(function($){

	$.fn.dsSizer = function (method, options){

		if(!this[method])
			throw '$.dsSizer => The jQuery method "' + method + '" you called does not exist';

		var settings = $.extend({
			absolute      : false,
			cloned        : false,
			includeMargin : false,
			display       : 'block'
		}, options || {});

		var self = this.eq(0);
		var fixIt, restore;

		if(settings.cloned === true){

			fixIt = function (){
				var style = 'position: absolute !important; top: -9999 !important; ';
				self = self.cloned().attr('style', style).appendTo('body');
			};

			restore = function (){ self.remove(); };

		}else{
			var tmp   = [],
				style = '',
				hidden;

			fixIt = function (){
				hidden = self.parents().addBack().filter(':hidden');
				style += 'visibility: hidden !important; display: ' + settings.display + ' !important;';

				if(settings.absolute === true) style += 'position: absolute !important;';

				hidden.each(function(){
					var self     = $(this),
						self_style = self.attr('style');

					tmp.push( self_style );
					self.attr({style: (self_style)? self_style+';'+style : style});
				});
			};

			restore = function (){
				hidden.each( function(i){
					var self  = $( this ),
						_tmp  = tmp[i];

					if(_tmp === undefined) self.removeAttr('style');
					else self.attr('style', _tmp);

				});
			};
		}

		fixIt();
		var size = /(outer)/.test(method) ? self[method](settings.includeMargin) : self[method]();
		restore();

		return size;
	}

/* --------------------------------------------------------------------------------------------------------------------------------- */

/*
	* jquery.dsVerticalizator.js 1.0
	*
	* Copyright 2016, Denis Stoliarchuk
	* Licensed under the MIT License (LICENSE.txt).
	*
	* Date: Fri Jul 15 21:34:00 2016
*/

	$.fn.dsVerticalizator = function(options) {
		var settings = $.extend({
			style:   'top',
			vertical_offset: 0,
			parent: null,
			refresher: 25,
			def_winload: false
		}, options || {});

		return this.each(function(){
			var self   = $(this);
			var timerRef;

			var resize = function () {
				var parentHeight = self.parent().dsSizer('height');
				if(settings.parent && self.parents(settings.parent).length)
					parentHeight = self.parents(settings.parent).first().dsSizer('height');

				var centered = (parentHeight / 2) - (self.dsSizer('height') / 2);
				var centered_with_opts = centered + parseInt(settings.vertical_offset)

				self.css(settings.style, centered_with_opts);
				self.css('position', 'relative');

				if (settings.complete !== undefined)
					settings.complete();
			};

			$(window).resize(function () {
				clearTimeout(timerRef);
				timerRef = setTimeout(resize, settings.refresher);
			});

			if (!settings.def_winload) {
				resize();
			}

			$(window).load(function () {
				resize();
			});

		});

	};

})(jQuery);
<|endoftext|>


<commit_before>import path from 'path'
import Mocha from 'mocha'
import glob from 'glob'
import { TESTS, ROOT } from 'config/paths'

const mocha = new Mocha({
  reporter: 'nyan',
  ui: 'bdd',
})

const filesToRun = [
  ...[ `${TESTS}/index.js` ],
  ...glob.sync('**/*.test.js'),
]

filesToRun.forEach(file => {
  mocha.addFile(path.resolve(ROOT, file))
})

mocha.run(failures => {
  process.on('exit', () => {
    process.exit(failures)
  })
})

<commit_msg>fixed test run<commit_after>import path from 'path'
import Mocha from 'mocha'
import glob from 'glob'
import { TESTS, ROOT } from 'config/paths'

const mocha = new Mocha({
  reporter: 'nyan',
  ui: 'bdd',
})

const filesToRun = [
  ...[ `${TESTS}/index.js` ],
  ...glob.sync('./{src,test}/**/*.test.js'),
]

filesToRun.forEach(file => {
  mocha.addFile(path.resolve(ROOT, file))
})

mocha.run(failures => {
  process.on('exit', () => {
    process.exit(failures)
  })
})

<|endoftext|>


<commit_before>import { useEffect, useState } from 'react'
import get from 'lodash/get'

import { useClient } from 'cozy-client'
import logger from 'cozy-logger'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'

import {
  mkHomeMagicFolderConn,
  mkHomeCustomShorcutsConn,
  mkHomeCustomShorcutsDirConn
} from 'queries'
import { formatShortcuts } from './utils'

export const useCustomShortcuts = () => {
  const client = useClient()
  const { t } = useI18n()
  const [shortcutsDirectories, setDirectories] = useState()
  const abort = () => setDirectories(null)

  useEffect(() => {
    const load = async () => {
      try {
        const homeMagicFolderConn = mkHomeMagicFolderConn(t)
        const folder = await client.query(
          homeMagicFolderConn.query,
          homeMagicFolderConn
        )

        if (!folder) return abort()

        const homeShortcutsDirConn = mkHomeCustomShorcutsDirConn({
          currentFolderId: get(folder, 'data[0]._id')
        })
        const { data: folders } = await client.query(
          homeShortcutsDirConn.query,
          homeShortcutsDirConn
        )

        if (!folders || folders.length === 0) return abort()

        const homeShortcutsConn = mkHomeCustomShorcutsConn(
          folders.map(folder => folder._id)
        )
        const { data: shortcuts } = await client.query(
          homeShortcutsConn.query,
          homeShortcutsConn
        )

        if (!shortcuts || shortcuts.length === 0) return abort()

        setDirectories(formatShortcuts(folders, shortcuts))
      } catch (error) {
        logger.error(error)
        abort()
      }
    }

    load()
  }, [client, t])

  return { shortcutsDirectories }
}

export default useCustomShortcuts
<commit_msg>fix: Implement proper testing of magicFolder presence<commit_after>import { useEffect, useState } from 'react'

import { useClient } from 'cozy-client'
import logger from 'cozy-logger'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'

import {
  mkHomeMagicFolderConn,
  mkHomeCustomShorcutsConn,
  mkHomeCustomShorcutsDirConn
} from 'queries'
import { formatShortcuts } from './utils'

export const useCustomShortcuts = () => {
  const client = useClient()
  const { t } = useI18n()
  const [shortcutsDirectories, setDirectories] = useState()
  const abort = () => setDirectories(null)

  useEffect(() => {
    const load = async () => {
      try {
        // Get the magic dir
        const homeMagicFolderConn = mkHomeMagicFolderConn(t)
        const { data: magicFolder } = await client.query(
          homeMagicFolderConn.query,
          homeMagicFolderConn
        )

        if (!magicFolder || magicFolder.length === 0) return abort()

        // Get all shortcuts directories inside the magic dir
        const homeShortcutsDirConn = mkHomeCustomShorcutsDirConn({
          currentFolderId: magicFolder[0]._id
        })
        const { data: folders } = await client.query(
          homeShortcutsDirConn.query,
          homeShortcutsDirConn
        )

        if (!folders || folders.length === 0) return abort()

        // Get all shortcuts items inside those shortcuts directories
        const homeShortcutsConn = mkHomeCustomShorcutsConn(
          folders.map(folder => folder._id)
        )
        const { data: shortcuts } = await client.query(
          homeShortcutsConn.query,
          homeShortcutsConn
        )

        if (!shortcuts || shortcuts.length === 0) return abort()

        // Merge directories and shortcuts into an object that the view can process
        setDirectories(formatShortcuts(folders, shortcuts))
      } catch (error) {
        logger.error(error)
        abort()
      }
    }

    load()
  }, [client, t])

  return { shortcutsDirectories }
}

export default useCustomShortcuts
<|endoftext|>


<commit_before>/**
 * Nextcloud - passman
 *
 * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

(function () {
	'use strict';
	/**
	 * @ngdoc directive
	 * @name passmanApp.directive:passwordGen
	 * @description
	 * # passwordGen
	 */

	angular.module('passmanApp')
		.directive('credentialField', ['$timeout', '$translate', function ($timeout, $translate) {
			return {
				scope: {
					value: '=value',
					secret: '=secret'
				},
				restrict: 'A',
				replace: 'true',
				template: "" +
				'' +
				'
' +
				'*' +
				'{{value}}' +
				'
' +
				'
' +
				'

' +
				'

' +
				'

' +
				'
',
				link: function (scope) {
					var expression = /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/gi;
					var regex = new RegExp(expression);
					$translate(['toggle.visibility', 'copy', 'copied']).then(function (translations) {
						scope.tggltxt = translations['toggle.visibility'];
						scope.copy_msg = translations['copy.field'];
					});

					scope.$watch("value", function () {
						if (scope.value) {
							if (scope.secret) {
								scope.valueVisible = false;
							}
							if (scope.value.match(regex)) {
								scope.isLink = true;

							}
						}
					});
					if (!scope.toggle) {
						if (scope.secret) {
							scope.toggle = true;
						}
					}

					var timer;
					scope.onSuccess = function () {
						scope.copy_msg = $translate.instant('copied') ;
						$timeout.cancel(timer);
						timer = $timeout(function () {
							scope.copy_msg = $translate.instant('copy');
						}, 5000);
					};
					scope.valueVisible = true;
					scope.toggleVisibility = function () {
						scope.valueVisible = !scope.valueVisible;
					};
				}
			};
		}]);

}());<commit_msg>Add rel="nofollow noopener noreferrer" by EdOverflow<commit_after>/**
 * Nextcloud - passman
 *
 * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

(function () {
	'use strict';
	/**
	 * @ngdoc directive
	 * @name passmanApp.directive:passwordGen
	 * @description
	 * # passwordGen
	 */

	angular.module('passmanApp')
		.directive('credentialField', ['$timeout', '$translate', function ($timeout, $translate) {
			return {
				scope: {
					value: '=value',
					secret: '=secret'
				},
				restrict: 'A',
				replace: 'true',
				template: "" +
				'' +
				'
' +
				'*' +
				'{{value}}' +
				'
' +
				'
' +
				'

' +
				'

' +
				'

' +
				'
',
				link: function (scope) {
					var expression = /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/gi;
					var regex = new RegExp(expression);
					$translate(['toggle.visibility', 'copy', 'copied']).then(function (translations) {
						scope.tggltxt = translations['toggle.visibility'];
						scope.copy_msg = translations['copy.field'];
					});

					scope.$watch("value", function () {
						if (scope.value) {
							if (scope.secret) {
								scope.valueVisible = false;
							}
							if (scope.value.match(regex)) {
								scope.isLink = true;

							}
						}
					});
					if (!scope.toggle) {
						if (scope.secret) {
							scope.toggle = true;
						}
					}

					var timer;
					scope.onSuccess = function () {
						scope.copy_msg = $translate.instant('copied') ;
						$timeout.cancel(timer);
						timer = $timeout(function () {
							scope.copy_msg = $translate.instant('copy');
						}, 5000);
					};
					scope.valueVisible = true;
					scope.toggleVisibility = function () {
						scope.valueVisible = !scope.valueVisible;
					};
				}
			};
		}]);

}());
<|endoftext|>


<commit_before>// Description
//  watson
//
// Commands:
//  watson - returns answer of question

var url = require('url');
var https = require('https');

(function() {
  module.exports = function(robot) {
    var bmconf = require('./bmconf');

    return robot.respond(/.*/, function(msg) {
      var question = msg.message.text;

      var query = url.parse(bmconf.url + '/v1/question/travel');
      var options = {
        host: query.hostname,
        port: query.port,
        path: query.pathname,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
          'X-synctimeout': '30',
          'Authorization': bmconf.auth
        }
      };

      var watson_req = https.request(options, function(result) {
        result.setEncoding('utf-8');
        var response_string = '';
        result.on('data', function(chunk) {
          response_string += chunk;
        });
        result.on('end', function() {
          var watson_answer = JSON.parse(response_string)[0];
          var qa = watson_answer.question;
          if (watson_answer && qa &&
            qa.evidencelist &&
            qa.evidencelist.length > 0) {
            answer = qa.evidencelist[1].text;
          } else {
            answer = qa.errorNotifications[0].text +
              qa.questionText;
          }
          msg.send(answer.substring(0, 120) + '...');
        });
      });

      watson_req.on('error', function(err) {
        msg.send("Ooops, " + err);
      });

      var questionData = {
        'question': {
          'evidenceRequest': {
            'items': 1
          },
          'questionText': question
        }
      };

      watson_req.write(JSON.stringify(questionData));
      watson_req.end();
    });
  };
}).call(this);
<commit_msg>Reply the first evidence (not the second..)<commit_after>// Description
//  watson
//
// Commands:
//  watson - returns answer of question

var url = require('url');
var https = require('https');

(function() {
  module.exports = function(robot) {
    var bmconf = require('./bmconf');

    return robot.respond(/.*/, function(msg) {
      var question = msg.message.text;

      var query = url.parse(bmconf.url + '/v1/question/travel');
      var options = {
        host: query.hostname,
        port: query.port,
        path: query.pathname,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
          'X-synctimeout': '30',
          'Authorization': bmconf.auth
        }
      };

      var watson_req = https.request(options, function(result) {
        result.setEncoding('utf-8');
        var response_string = '';
        result.on('data', function(chunk) {
          response_string += chunk;
        });
        result.on('end', function() {
          var watson_answer = JSON.parse(response_string)[0];
          var qa = watson_answer.question;
          if (watson_answer && qa &&
            qa.evidencelist &&
            qa.evidencelist.length > 0) {
            answer = qa.evidencelist[0].text;
          } else {
            answer = qa.errorNotifications[0].text +
              qa.questionText;
          }
          msg.send(answer.substring(0, 120) + '...');
        });
      });

      watson_req.on('error', function(err) {
        msg.send("Ooops, " + err);
      });

      var questionData = {
        'question': {
          'evidenceRequest': {
            'items': 1
          },
          'questionText': question
        }
      };

      watson_req.write(JSON.stringify(questionData));
      watson_req.end();
    });
  };
}).call(this);
<|endoftext|>


<commit_before>var slugify = require('./slugify'),
plaintext = require('./plaintext');

module.exports = {
  slugify : slugify,
  plaintext : plaintext
};<commit_msg>Delete index.js<commit_after><|endoftext|>


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

const LEVELS = ['fatal', 'error', 'warn', 'info', 'debug', 'trace'];

/** eslint-disable no-console **/
console.log = function (...args) {
  logger.log(args, 'info');
};

LEVELS.forEach((level) => {
  console[level] = function (...args) {
    logger.log(args, level);
  };
});
/** eslint-enable no-console **/

exports.uiServer = require('./uiServer');
exports.server = require('./server');
<commit_msg>chore: Refine code<commit_after>const logger = require('./logger');

const LEVELS = ['fatal', 'error', 'warn', 'info', 'debug', 'trace'];

/* eslint-disable no-console */
console.log = function (...args) {
  logger.log(args, 'info');
};

LEVELS.forEach((level) => {
  console[level] = function (...args) {
    logger.log(args, level);
  };
});
/* eslint-enable no-console */

exports.uiServer = require('./uiServer');
exports.server = require('./server');
<|endoftext|>


<commit_before>var Command  = require('./command');
var Packets  = require('../packets/index.js');
var util    = require('util');

function Query(sql, callback)
{
  Command.call(this);
  this.query = sql;
  this.onResult = callback; // TODO check felixge multi-result api
  this.fieldCount = 0;
  this.insertId   = 0;
  this.fields     = [];
  this.rows       = [];
}
util.inherits(Query, Command);

Query.prototype.start = function(packet, connection) {
  var cmdPacket = new Packets.Query(this.query);
  connection.writePacket(cmdPacket.toPacket(1));
  return Query.prototype.resultsetHeader;
};

Query.prototype.resultsetHeader = function(packet) {
  var rs = new Packets.ResultSetHeader(packet);
  this.fieldCount = rs.fieldCount;
  this.insertId = rs.insertId;
  if (this.fieldCount === 0) {
    if (this.onResult)
      this.onResult(null, [], []);
    return null;
  }
  return Query.prototype.readField;
};

Query.prototype.readField = function(packet) {
  var field = new Packets.ColumnDefinition(packet);
  this.fields.push(field);
  if (this.fields.length == this.fieldCount)
    return Query.prototype.fieldsEOF;
  return Query.prototype.readField;
};

Query.prototype.fieldsEOF = function(packet) {
  // check EOF
  if (!packet.isEOF())
    throw "Expected EOF packet";
  // PROFILING
  this._fieldsEOFTime = process.hrtime();
  return Query.prototype.row;
};

function Row(columns) {
  this.id = columns[0];
  this.name = columns[1];
}

Query.prototype.row = function(packet)
{
  if (packet.isEOF()) {
    if (this.onResult)
      this.onResult(null, this.rows, this.fields);
    return null;
  }
  var row = Packets.TextRow.fromPacket(packet);
  // TODO: here we'll have dynamically pre-compiled and cached row parser
  if (true) // TODO: think of API to store raw copulns array (most probably connection options flags)
  {
    var r = {};
    for (var i = 0; i < row.columns.length; ++i)
    {
      var name = this.fields[i].name;
      r[name] = row.columns[i];
    }
    if (this.onResult)
      this.rows.push(r);
    else
      this.emit('result', r);
  } else {
    if (this.onResult)
      this.rows.push(row.columns);
    else
      this.emit('result', row.columns);
  }
  return Query.prototype.row;
};

module.exports = Query;
<commit_msg>cleanup<commit_after>var Command  = require('./command');
var Packets  = require('../packets/index.js');
var util    = require('util');

function Query(sql, callback)
{
  Command.call(this);
  this.query = sql;
  this.onResult = callback; // TODO check felixge multi-result api
  this.fieldCount = 0;
  this.insertId   = 0;
  this.fields     = [];
  this.rows       = [];
}
util.inherits(Query, Command);

Query.prototype.start = function(packet, connection) {
  var cmdPacket = new Packets.Query(this.query);
  connection.writePacket(cmdPacket.toPacket(1));
  return Query.prototype.resultsetHeader;
};

Query.prototype.resultsetHeader = function(packet) {
  var rs = new Packets.ResultSetHeader(packet);
  this.fieldCount = rs.fieldCount;
  this.insertId = rs.insertId;
  if (this.fieldCount === 0) {
    if (this.onResult)
      this.onResult(null, [], []);
    return null;
  }
  return Query.prototype.readField;
};

Query.prototype.readField = function(packet) {
  var field = new Packets.ColumnDefinition(packet);
  this.fields.push(field);
  if (this.fields.length == this.fieldCount)
    return Query.prototype.fieldsEOF;
  return Query.prototype.readField;
};

Query.prototype.fieldsEOF = function(packet) {
  // check EOF
  if (!packet.isEOF())
    throw "Expected EOF packet";
  // PROFILING
  this._fieldsEOFTime = process.hrtime();
  return Query.prototype.row;
};

Query.prototype.row = function(packet)
{
  if (packet.isEOF()) {
    if (this.onResult)
      this.onResult(null, this.rows, this.fields);
    return null;
  }
  var row = Packets.TextRow.fromPacket(packet);

  // TODO: here we'll have dynamically pre-compiled and cached row parser
  if (true) // TODO: think of API to store raw copulns array (most probably connection options flags)
  {
    var r = {};
    for (var i = 0; i < row.columns.length; ++i)
    {
      var name = this.fields[i].name;
      r[name] = row.columns[i];
    }
    if (this.onResult)
      this.rows.push(r);
    else
      this.emit('result', r);
  } else {
    if (this.onResult)
      this.rows.push(row.columns);
    else
      this.emit('result', row.columns);
  }
  return Query.prototype.row;
};

module.exports = Query;
<|endoftext|>