<commit_before>/**
 * @module BgProcess
 * @submodule modules/RSSParser
 */
define(['md5'], function (CryptoJS) {

	/**
	 * RSS Parser
	 * @class RSSParser
	 * @constructor
	 * @extends Object
	 */
	function parseRSS(xml, sourceID) {
		var items = [];

		if (!xml || !(xml instanceof XMLDocument)) {
			return items;
		}

		var nodes = xml.querySelectorAll('item');
		if (!nodes.length) {
			nodes = xml.querySelectorAll('entry');
		}

		var title = getFeedTitle(xml);
		var source = sources.findWhere({
			id: sourceID
		});
		if (title && (source.get('title') == source.get('url') || !source.get('title'))) {
			source.save('title', title);
		}

		/**
		 * TTL check
		 */
		var ttl = xml.querySelector('channel > ttl, feed > ttl, rss > ttl');
		if (ttl && source.get('lastUpdate') == 0) {
			ttl = parseInt(ttl.textContent, 10);
			var vals = [300, 600, 1440, 10080];
			if (ttl > 10080) {
				source.save({ updateEvery: 10080 });
			} else if (ttl > 180) {
				for (var i=0; i<vals.length; i++) {
					if (ttl <= vals[i]) {
						ttl = vals[i];
						break;
					}
				}
				source.save({ updateEvery: ttl });
			}
		}
		/* END: ttl check */

		var mainEl = xml.querySelector('rss, rdf, feed');
		if (mainEl) {
			var baseStr = mainEl.getAttribute('xml:base') || mainEl.getAttribute('xmlns:base') || mainEl.getAttribute('base');
			if (baseStr) {
				source.save({ base: baseStr });
			}
		}

		[].forEach.call(nodes, function(node) {
			items.push({
				id: rssGetGuid(node),
				title: rssGetTitle(node),
				url: rssGetLink(node),
				date: rssGetDate(node),
				author: rssGetAuthor(node, title),
				content: rssGetContent(node),
				sourceID: sourceID,
				unread: true,
				deleted: false,
				trashed: false,
				visited: false,
				pinned: false,
				dateCreated: Date.now()
			});

			var last = items[items.length - 1];
			last.oldId = last.id;
			if (!last.id) {
				last.id = CryptoJS.MD5(last.sourceID + last.title + last.date).toString();
			} else {
				last.id = CryptoJS.MD5(last.sourceID + last.id).toString();
			}

			if (last.date == 0) last.date = Date.now();
		});

		return items;
	}

	function rssGetGuid(node) {
		if (!node) return false;
		var guid = node.querySelector('guid');
		return guid ? guid.textContent : '';
	}

	function rssGetLink(node) {
		if (!node) return false;

		var link = node.querySelector('link[rel="alternate"]');

		if (!link) {

			if (!link) link = node.querySelector('link[type="text/html"]');

			// prefer non atom links over atom links because of http://logbuch-netzpolitik.de/
			if (!link || link.prefix == 'atom') link = node.querySelector('link');

			if (!link) link = node.querySelector('link[type="text/html"]');
			if (!link) link = node.querySelector('link');

		}

		if (!link) {
			var guid = node.querySelector('guid');
			if (guid && guid.textContent.match(/:\/\//).length) {
				link = guid;
			}
		}

		if (link) {
			return link.textContent || link.getAttribute('href');
		}

		return false;
	}

	function getFeedTitle(xml) {
		var title = xml.querySelector('channel > title, feed > title, rss > title');
		if (!title || !(title.textContent).trim()) {
			title = xml.querySelector('channel > description, feed > description, rss > description');
		}

		if (!title || !(title.textContent).trim()) {
			title = xml.querySelector('channel > description, feed > description, rss > description');
		}

		if (!title || !(title.textContent).trim()) {
			title = xml.querySelector('channel > link, feed > link, rss > link');
		}

		return title && title.textContent ? title.textContent.trim() || 'rss' : 'rss';
	}

	function replaceUTCAbbr(str) {
		str = String(str);
		var rep = {
			'CET': '+0100', 'CEST': '+0200', 'EST': '', 'WET': '+0000', 'WEZ': '+0000', 'WEST': '+0100',
			'EEST': '+0300', 'BST': '+0100', 'EET': '+0200', 'IST': '+0100', 'KUYT': '+0400', 'MSD': '+0400',
			'MSK': '+0400', 'SAMT': '+0400'
		};
		var reg = new RegExp('(' + Object.keys(rep).join('|') + ')', 'gi');
		return str.replace(reg, function(all, abbr) {
			return rep[abbr];
		});
	}

	function rssGetDate(node) {
		var pubDate = node.querySelector('pubDate, published');
		if (pubDate) {
			return (new Date( replaceUTCAbbr(pubDate.textContent) )).getTime() || 0;
		}

		pubDate = node.querySelector('date');
		if (pubDate) {
			return (new Date( replaceUTCAbbr(pubDate.textContent) )).getTime() || 0;
		}

		pubDate = node.querySelector('lastBuildDate, updated, update');

		if (pubDate) {
			return (new Date( replaceUTCAbbr(pubDate.textContent) )).getTime() || 0;
		}
		return 0;
	}

	function rssGetAuthor(node, title) {
		var creator = node.querySelector('creator, author > name');
		if (creator) {
			creator = creator.textContent.trim();
		}

		if (!creator) {
			creator = node.querySelector('author');
			if (creator) {
				creator = creator.textContent.trim();
			}
		}

		if (!creator && title && title.length > 0) {
			creator = title;
		}

		if (creator) {
			if (/^\S+@\S+\.\S+\s+\(.+\)$/.test(creator)) {
				creator = creator.replace(/^\S+@\S+\.\S+\s+\((.+)\)$/, '$1');
			}
			creator = creator.replace(/\s*\(\)\s*$/, '');
			return creator;
		}

		return 'no author';
	}

	function rssGetTitle(node) {
		return node.querySelector('title') ? node.querySelector('title').textContent : '<no title>';
	}

	function rssGetContent(node) {
		var desc = node.querySelector('encoded');
		if (desc) return desc.textContent;

		desc = node.querySelector('description');
		if (desc) return desc.textContent;

		// content over summary because of "http://neregate.com/blog/feed/atom/"
		desc = node.querySelector('content');
		if (desc) return desc.textContent;

		desc = node.querySelector('summary');
		if (desc) return desc.textContent;

		return ' ';
	}

	return {
		parse: function() {
			return parseRSS.apply(null, arguments);
		}
	};
});<commit_msg>fix an error: String#match().length fails when match returns null<commit_after>/**
 * @module BgProcess
 * @submodule modules/RSSParser
 */
define(['md5'], function (CryptoJS) {

	/**
	 * RSS Parser
	 * @class RSSParser
	 * @constructor
	 * @extends Object
	 */
	function parseRSS(xml, sourceID) {
		var items = [];

		if (!xml || !(xml instanceof XMLDocument)) {
			return items;
		}

		var nodes = xml.querySelectorAll('item');
		if (!nodes.length) {
			nodes = xml.querySelectorAll('entry');
		}

		var title = getFeedTitle(xml);
		var source = sources.findWhere({
			id: sourceID
		});
		if (title && (source.get('title') == source.get('url') || !source.get('title'))) {
			source.save('title', title);
		}

		/**
		 * TTL check
		 */
		var ttl = xml.querySelector('channel > ttl, feed > ttl, rss > ttl');
		if (ttl && source.get('lastUpdate') == 0) {
			ttl = parseInt(ttl.textContent, 10);
			var vals = [300, 600, 1440, 10080];
			if (ttl > 10080) {
				source.save({ updateEvery: 10080 });
			} else if (ttl > 180) {
				for (var i=0; i<vals.length; i++) {
					if (ttl <= vals[i]) {
						ttl = vals[i];
						break;
					}
				}
				source.save({ updateEvery: ttl });
			}
		}
		/* END: ttl check */

		var mainEl = xml.querySelector('rss, rdf, feed');
		if (mainEl) {
			var baseStr = mainEl.getAttribute('xml:base') || mainEl.getAttribute('xmlns:base') || mainEl.getAttribute('base');
			if (baseStr) {
				source.save({ base: baseStr });
			}
		}

		[].forEach.call(nodes, function(node) {
			items.push({
				id: rssGetGuid(node),
				title: rssGetTitle(node),
				url: rssGetLink(node),
				date: rssGetDate(node),
				author: rssGetAuthor(node, title),
				content: rssGetContent(node),
				sourceID: sourceID,
				unread: true,
				deleted: false,
				trashed: false,
				visited: false,
				pinned: false,
				dateCreated: Date.now()
			});

			var last = items[items.length - 1];
			last.oldId = last.id;
			if (!last.id) {
				last.id = CryptoJS.MD5(last.sourceID + last.title + last.date).toString();
			} else {
				last.id = CryptoJS.MD5(last.sourceID + last.id).toString();
			}

			if (last.date == 0) last.date = Date.now();
		});

		return items;
	}

	function rssGetGuid(node) {
		if (!node) return false;
		var guid = node.querySelector('guid');
		return guid ? guid.textContent : '';
	}

	function rssGetLink(node) {
		if (!node) return false;

		var link = node.querySelector('link[rel="alternate"]');

		if (!link) {

			if (!link) link = node.querySelector('link[type="text/html"]');

			// prefer non atom links over atom links because of http://logbuch-netzpolitik.de/
			if (!link || link.prefix == 'atom') link = node.querySelector('link');

			if (!link) link = node.querySelector('link[type="text/html"]');
			if (!link) link = node.querySelector('link');

		}

		if (!link) {
			var guid = node.querySelector('guid');
			var tmp;
			if (guid && (tmp = guid.textContent.match(/:\/\//)) && tmp.length) {
				link = guid;
			}
		}

		if (link) {
			return link.textContent || link.getAttribute('href');
		}

		return false;
	}

	function getFeedTitle(xml) {
		var title = xml.querySelector('channel > title, feed > title, rss > title');
		if (!title || !(title.textContent).trim()) {
			title = xml.querySelector('channel > description, feed > description, rss > description');
		}

		if (!title || !(title.textContent).trim()) {
			title = xml.querySelector('channel > description, feed > description, rss > description');
		}

		if (!title || !(title.textContent).trim()) {
			title = xml.querySelector('channel > link, feed > link, rss > link');
		}

		return title && title.textContent ? title.textContent.trim() || 'rss' : 'rss';
	}

	function replaceUTCAbbr(str) {
		str = String(str);
		var rep = {
			'CET': '+0100', 'CEST': '+0200', 'EST': '', 'WET': '+0000', 'WEZ': '+0000', 'WEST': '+0100',
			'EEST': '+0300', 'BST': '+0100', 'EET': '+0200', 'IST': '+0100', 'KUYT': '+0400', 'MSD': '+0400',
			'MSK': '+0400', 'SAMT': '+0400'
		};
		var reg = new RegExp('(' + Object.keys(rep).join('|') + ')', 'gi');
		return str.replace(reg, function(all, abbr) {
			return rep[abbr];
		});
	}

	function rssGetDate(node) {
		var pubDate = node.querySelector('pubDate, published');
		if (pubDate) {
			return (new Date( replaceUTCAbbr(pubDate.textContent) )).getTime() || 0;
		}

		pubDate = node.querySelector('date');
		if (pubDate) {
			return (new Date( replaceUTCAbbr(pubDate.textContent) )).getTime() || 0;
		}

		pubDate = node.querySelector('lastBuildDate, updated, update');

		if (pubDate) {
			return (new Date( replaceUTCAbbr(pubDate.textContent) )).getTime() || 0;
		}
		return 0;
	}

	function rssGetAuthor(node, title) {
		var creator = node.querySelector('creator, author > name');
		if (creator) {
			creator = creator.textContent.trim();
		}

		if (!creator) {
			creator = node.querySelector('author');
			if (creator) {
				creator = creator.textContent.trim();
			}
		}

		if (!creator && title && title.length > 0) {
			creator = title;
		}

		if (creator) {
			if (/^\S+@\S+\.\S+\s+\(.+\)$/.test(creator)) {
				creator = creator.replace(/^\S+@\S+\.\S+\s+\((.+)\)$/, '$1');
			}
			creator = creator.replace(/\s*\(\)\s*$/, '');
			return creator;
		}

		return 'no author';
	}

	function rssGetTitle(node) {
		return node.querySelector('title') ? node.querySelector('title').textContent : '<no title>';
	}

	function rssGetContent(node) {
		var desc = node.querySelector('encoded');
		if (desc) return desc.textContent;

		desc = node.querySelector('description');
		if (desc) return desc.textContent;

		// content over summary because of "http://neregate.com/blog/feed/atom/"
		desc = node.querySelector('content');
		if (desc) return desc.textContent;

		desc = node.querySelector('summary');
		if (desc) return desc.textContent;

		return ' ';
	}

	return {
		parse: function() {
			return parseRSS.apply(null, arguments);
		}
	};
});<|endoftext|>


<commit_before>import React from "react";
import _ from "lodash";
// import {ReactSVGPanZoom} from 'react-svg-pan-zoom';
import * as globals from "./globals";
import graphUtil from "../util/graphUtil";

import Axes from "./graphAxes";
import Comments from "./graphComments";
import Participants from "./graphParticipants";
import Hulls from "./hull";
import BarChartForVotes from "./barChartsForGroupVotes";
import BarChart from "./barChart";

let ptptoiScaleFactor = 0.5;

class Graph extends React.Component {

  constructor(props) {
    super(props);
    this.Viewer = null;
    this.state = {
      selectedComment: null,
    };
  }

  componentWillMount() {
    console.log("graph mounted");
    document.getElementById("helpTextGroups").style.display = "none";
    document.getElementById("visualization_div").style.display = "none";
    document.getElementById("carouselPane").style.display = "none";
    document.getElementsByClassName("groupSelectionView")[0].style.display = "none";
  }

  handleCommentHover(selectedComment) {
    return () => {
      this.setState({selectedComment});
    }
  }

  handleCommentClick(selectedComment) {
    return () => {
      this.setState({selectedComment});
    }
  }

  render() {

    if (!this.props.math) {
      return null;
    }

    let tidsToShowSet = _.keyBy(this.props.tidsToShow);

    let {
      xx,
      yy,
      commentsPoints,
      xCenter,
      yCenter,
      baseClustersScaled,
      commentScaleupFactorX,
      commentScaleupFactorY,
      hulls,
      groupCornerAssignments,
    } = graphUtil(this.props.comments, this.props.math, this.props.badTids);

    console.log(groupCornerAssignments);

    let should_only_show_voted_on_comments = false;

    commentsPoints = commentsPoints.filter((c) => {
      return !should_only_show_voted_on_comments || !_.isUndefined(tidsToShowSet[c.tid]);
    });
    let commentsToShow = this.props.comments.filter((c) => {
      return !should_only_show_voted_on_comments || !_.isUndefined(tidsToShowSet[c.tid]);
    });

    let heading = (
 Opinion Graph

        This graph shows all people and all comments.

        Comments, identified by their number, are positioned more closely to comments that were voted on similarly (blue, in the correlation matrix above). Comments are positioned further away from comments that tended to be voted on differently (red, in the correlation matrix above).

People are positioned closer to the comments on which they agreed, and further from the comments on which they disagreed. Groups of participants that tended to vote similarly across many comments (elaborated in the previous section) are identified by their similar color.

);

    return (

        {this.props.renderHeading ? heading : ""}
        <svg width="100%" height={globals.side}>

          {/* Comment https://bl.ocks.org/mbostock/7555321 */}
          <g transform={`translate(${globals.side / 2}, ${15})`}>
            <text
              style={{
                fontFamily: "Georgia",
                fontSize: 14,
                fontStyle: "italic"
              }}
              textAnchor="middle">

            </text>
          </g>
          <Axes xCenter={xCenter} yCenter={yCenter} report={this.props.report}/>
          <Hulls hulls={hulls} showOnlyGroup={this.props.showOnlyGroup} />
          <Participants points={baseClustersScaled} ptptois={this.props.ptptois} ptptoiScaleFactor={ptptoiScaleFactor}/>
          <Comments
            commentsPoints={commentsPoints}
            selectedComment={this.state.selectedComment}
            handleCommentHover={this.handleCommentHover.bind(this)}
            points={commentsPoints}
            repfulAgreeTidsByGroup={this.props.repfulAgreeTidsByGroup}
            repfulDisageeTidsByGroup={this.props.repfulDisageeTidsByGroup}
            showOnlyGroup={this.props.showOnlyGroup}
            xx={xx}
            yy={yy}
            xCenter={xCenter}
            yCenter={yCenter}
            xScaleup={commentScaleupFactorX}
            yScaleup={commentScaleupFactorY}
            formatTid={this.props.formatTid}/>
          <BarChartForVotes
            selectedComment={this.state.selectedComment}
            allComments={this.props.comments}
            groups={window.preload.firstMath["group-votes"]}
            groupCornerAssignments={groupCornerAssignments}
            />
        </svg>

            {this.state.selectedComment ? "#" + this.state.selectedComment.tid : null}

            {this.state.selectedComment ? this.state.selectedComment.txt : null}

TOTAL:

            <svg width={260} height={100}>
              <BarChart
                selectedComment={this.state.selectedComment}
                allComments={this.props.comments}
                groups={window.preload.firstMath["group-votes"]}
                />
            </svg>

 Comments:

            {commentsToShow.map((c) => { return (

                {c.tid}

            )})}

    );
  }
}

export default Graph;

          // <defs>
          //   <marker
          //     className={'helpArrow'}
          //     id={'ArrowTip'}
          //     viewBox={'0 0 14 14'}
          //     refX={'1'
          //     refY={'5'}
          //     markerWidth={'5'}
          //     markerHeight={'5'}
          //     orient={'auto'}>
          //     // "<path d='M 0 0 L 10 5 L 0 10 z' />
          //     <circle cx = {'6'} cy = {'6'} r = {'5'} />
          //   </marker>
          //   <clipPath id={"clipCircleVis2"}>
          //     <circle r={ptptOiRadius * ptptoiScaleFactor} cx={0} cy={0}/>
          //   </clipPath>
          //   <filter id={'colorMeMatrix'}>
          //     <feColorMatrix
          //       in={'SourceGraphic'}
          //       type={'matrix'}
          //       values={'0.33 0.33 0.33 0 0
          //       0.33 0.33 0.33 0 0
          //       0.33 0.33 0.33 0 0
          //       0 0 0 1 0'} />
          //   </filter>

          //   <filter id={'colorMeMatrixRed'}
          //     <feColorMatrix
          //       in={'SourceGraphic'}
          //       type={'matrix'}
          //       values={'1.00 0.60 0.60 0 0.3
          //         0.10 0.20 0.10 0 0
          //         0.10 0.10 0.20 0 0
          //         0 0 0 1 0'} />
          //   </filter>

          //   <filter id={'colorMeMatrixGreen'}>
          //     <feColorMatrix
          //       in={'SourceGraphic'}
          //       type={'matrix'}
          //       values={'0.20 0.10 0.10 0 0
          //         0.60 1.00 0.60 0 0.3
          //         0.10 0.10 0.40 0 0
          //         0 0 0 1 0'} />
          //   </filter>
          // </defs>

// {/* this.props.math["group-clusters"].map((cluster, i) => {
//   return (<text x={300} y={300}> Renzi Supporters </text>)
// }) : null */}

// componentDidMount() {
//   this.Viewer.fitToViewer();
// }
//

//   <button onClick={event => this.Viewer.zoomOnViewerCenter(1.1)}>Zoom in</button>
//   <button onClick={event => this.Viewer.fitSelection(40, 40, 200, 200)}>Zoom area</button>
//   <button onClick={event => this.Viewer.fitToViewer()}>Fit</button>
//

// <ReactSVGPanZoom
//   style={{outline: "1px solid black", fill: "white"}}
//   width={500} height={500} ref={Viewer => this.Viewer = Viewer}
//   onClick={event => console.log('click', event.x, event.y, event.originalEvent)}
//   onMouseMove={event => console.log('move', event.x, event.y)} >
//
// </ReactSVGPanZoom>
<commit_msg>comment scrollpane<commit_after>import React from "react";
import _ from "lodash";
// import {ReactSVGPanZoom} from 'react-svg-pan-zoom';
import * as globals from "./globals";
import graphUtil from "../util/graphUtil";

import Axes from "./graphAxes";
import Comments from "./graphComments";
import Participants from "./graphParticipants";
import Hulls from "./hull";
import BarChartForVotes from "./barChartsForGroupVotes";
import BarChart from "./barChart";

let ptptoiScaleFactor = 0.5;

class Graph extends React.Component {

  constructor(props) {
    super(props);
    this.Viewer = null;
    this.state = {
      selectedComment: null,
    };
  }

  componentWillMount() {
    console.log("graph mounted");
    document.getElementById("helpTextGroups").style.display = "none";
    document.getElementById("visualization_div").style.display = "none";
    document.getElementById("carouselPane").style.display = "none";
    document.getElementsByClassName("groupSelectionView")[0].style.display = "none";
  }

  handleCommentHover(selectedComment) {
    return () => {
      this.setState({selectedComment});
    }
  }

  handleCommentClick(selectedComment) {
    return () => {
      this.setState({selectedComment});
    }
  }

  render() {

    if (!this.props.math) {
      return null;
    }

    let tidsToShowSet = _.keyBy(this.props.tidsToShow);

    let {
      xx,
      yy,
      commentsPoints,
      xCenter,
      yCenter,
      baseClustersScaled,
      commentScaleupFactorX,
      commentScaleupFactorY,
      hulls,
      groupCornerAssignments,
    } = graphUtil(this.props.comments, this.props.math, this.props.badTids);

    console.log(groupCornerAssignments);

    let should_only_show_voted_on_comments = false;

    commentsPoints = commentsPoints.filter((c) => {
      return !should_only_show_voted_on_comments || !_.isUndefined(tidsToShowSet[c.tid]);
    });
    let commentsToShow = this.props.comments.filter((c) => {
      return !should_only_show_voted_on_comments || !_.isUndefined(tidsToShowSet[c.tid]);
    });

    let heading = (
 Opinion Graph

        This graph shows all people and all comments.

        Comments, identified by their number, are positioned more closely to comments that were voted on similarly (blue, in the correlation matrix above). Comments are positioned further away from comments that tended to be voted on differently (red, in the correlation matrix above).

People are positioned closer to the comments on which they agreed, and further from the comments on which they disagreed. Groups of participants that tended to vote similarly across many comments (elaborated in the previous section) are identified by their similar color.

);

    return (

        {this.props.renderHeading ? heading : ""}
        <svg width="100%" height={globals.side}>

          {/* Comment https://bl.ocks.org/mbostock/7555321 */}
          <g transform={`translate(${globals.side / 2}, ${15})`}>
            <text
              style={{
                fontFamily: "Georgia",
                fontSize: 14,
                fontStyle: "italic"
              }}
              textAnchor="middle">

            </text>
          </g>
          <Axes xCenter={xCenter} yCenter={yCenter} report={this.props.report}/>
          <Hulls hulls={hulls} showOnlyGroup={this.props.showOnlyGroup} />
          <Participants points={baseClustersScaled} ptptois={this.props.ptptois} ptptoiScaleFactor={ptptoiScaleFactor}/>
          <Comments
            commentsPoints={commentsPoints}
            selectedComment={this.state.selectedComment}
            handleCommentHover={this.handleCommentHover.bind(this)}
            points={commentsPoints}
            repfulAgreeTidsByGroup={this.props.repfulAgreeTidsByGroup}
            repfulDisageeTidsByGroup={this.props.repfulDisageeTidsByGroup}
            showOnlyGroup={this.props.showOnlyGroup}
            xx={xx}
            yy={yy}
            xCenter={xCenter}
            yCenter={yCenter}
            xScaleup={commentScaleupFactorX}
            yScaleup={commentScaleupFactorY}
            formatTid={this.props.formatTid}/>
          <BarChartForVotes
            selectedComment={this.state.selectedComment}
            allComments={this.props.comments}
            groups={window.preload.firstMath["group-votes"]}
            groupCornerAssignments={groupCornerAssignments}
            />
        </svg>

            {this.state.selectedComment ? "#" + this.state.selectedComment.tid : null}

            {this.state.selectedComment ? this.state.selectedComment.txt : null}

TOTAL:

            <svg width={260} height={100}>
              <BarChart
                selectedComment={this.state.selectedComment}
                allComments={this.props.comments}
                groups={window.preload.firstMath["group-votes"]}
                />
            </svg>

 Comments:

              {commentsToShow.map((c) => { return (

                  {c.tid}

              )})}

    );
  }
}

export default Graph;

          // <defs>
          //   <marker
          //     className={'helpArrow'}
          //     id={'ArrowTip'}
          //     viewBox={'0 0 14 14'}
          //     refX={'1'
          //     refY={'5'}
          //     markerWidth={'5'}
          //     markerHeight={'5'}
          //     orient={'auto'}>
          //     // "<path d='M 0 0 L 10 5 L 0 10 z' />
          //     <circle cx = {'6'} cy = {'6'} r = {'5'} />
          //   </marker>
          //   <clipPath id={"clipCircleVis2"}>
          //     <circle r={ptptOiRadius * ptptoiScaleFactor} cx={0} cy={0}/>
          //   </clipPath>
          //   <filter id={'colorMeMatrix'}>
          //     <feColorMatrix
          //       in={'SourceGraphic'}
          //       type={'matrix'}
          //       values={'0.33 0.33 0.33 0 0
          //       0.33 0.33 0.33 0 0
          //       0.33 0.33 0.33 0 0
          //       0 0 0 1 0'} />
          //   </filter>

          //   <filter id={'colorMeMatrixRed'}
          //     <feColorMatrix
          //       in={'SourceGraphic'}
          //       type={'matrix'}
          //       values={'1.00 0.60 0.60 0 0.3
          //         0.10 0.20 0.10 0 0
          //         0.10 0.10 0.20 0 0
          //         0 0 0 1 0'} />
          //   </filter>

          //   <filter id={'colorMeMatrixGreen'}>
          //     <feColorMatrix
          //       in={'SourceGraphic'}
          //       type={'matrix'}
          //       values={'0.20 0.10 0.10 0 0
          //         0.60 1.00 0.60 0 0.3
          //         0.10 0.10 0.40 0 0
          //         0 0 0 1 0'} />
          //   </filter>
          // </defs>

// {/* this.props.math["group-clusters"].map((cluster, i) => {
//   return (<text x={300} y={300}> Renzi Supporters </text>)
// }) : null */}

// componentDidMount() {
//   this.Viewer.fitToViewer();
// }
//

//   <button onClick={event => this.Viewer.zoomOnViewerCenter(1.1)}>Zoom in</button>
//   <button onClick={event => this.Viewer.fitSelection(40, 40, 200, 200)}>Zoom area</button>
//   <button onClick={event => this.Viewer.fitToViewer()}>Fit</button>
//

// <ReactSVGPanZoom
//   style={{outline: "1px solid black", fill: "white"}}
//   width={500} height={500} ref={Viewer => this.Viewer = Viewer}
//   onClick={event => console.log('click', event.x, event.y, event.originalEvent)}
//   onMouseMove={event => console.log('move', event.x, event.y)} >
//
// </ReactSVGPanZoom>
<|endoftext|>


<commit_before>PolymerD3.dragElem = {
  initDragSettings: function(svg, settings, config) {

    /* == Helper Functions == */
    // function to access properties from settings
    let _getSettingsProp = function(prop) {
      return PolymerD3.utilities.searchArr(settings, function(elem) {
        return elem.input == prop;
      })
    };

    /* == Configuration Cooking == */
    if (!config) {
      config = {
        areaRect: {},
        innerRect: {}
      };
    }
    let scale = config.scale || .3;
    let width = _getSettingsProp('width').selectedValue * scale;
    let height = _getSettingsProp('height').selectedValue * scale;
    let rectFillOpacity = config.areaRect.opacity || .8;
    let marginLeft = _getSettingsProp('marginLeft').selectedValue * scale;
    let marginTop = _getSettingsProp('marginTop').selectedValue * scale;
    let marginRight = _getSettingsProp('marginRight').selectedValue * scale;
    let marginBottom = _getSettingsProp('marginBottom').selectedValue * scale;

    /* == Operation== */
    // clears SVG
    svg.html('');

    // creates area group
    let areaG = svg.append('g')
      .data([{
        x: width / 4,
        y: height / 4
      }]);

    // create area rectangle
    let areaRect = this._drawRect(areaG, {
      width: width,
      height: height,
      scalability: this.DRAG_CONSTANTS.BOTH,
      fillOpacity: rectFillOpacity
    });

    // make area rectangle scalable
    let areaRectSettings = this._makeScalable(areaRect, areaG, {
      scalability: this.DRAG_CONSTANTS.BOTH,
      scale: scale
    });

    // inner rectangle
    let innerG = areaG.append('g').data([{
      x: width / 4,
      y: height / 4
    }]);
    let innerRect = this._drawRect(innerG, {
      width: width - (marginLeft + marginRight),
      height: height - (marginTop + marginBottom),
      x: marginLeft,
      y: marginTop,
      scalability: this.DRAG_CONSTANTS.BOTH,
      fillOpacity: rectFillOpacity
    });
    let innerRectSettings = this._makeScalable(innerRect, innerG, {
      scalability: this.DRAG_CONSTANTS.BOTH,
      scale: scale
    });

    return {
      areaRect: areaRectSettings,
      innerRect: innerRectSettings,
      scale: scale
    }
  },

  // function to draw a rectangle with given config
  _drawRect: function(parent, config) {
    let x = config.x || 0;
    let y = config.y || 0;
    let dragrect = parent.append('rect')
      .attr('id', 'active')
      .attr('x', function(d) {
        return d.x + x;
      })
      .attr('y', function(d) {
        return d.y + y;
      })
      .attr('height', config.height)
      .attr('width', config.width)
      .attr('scalability', config.scalability)
      .attr('fill-opacity', config.fillOpacity);
    return dragrect;
  },

  // function to make a given rectangle inside a group scalable as per given config
  _makeScalable: function(rectangle, group, config) {
    let me = this;
    let dragbarw = config.dragbarw == null ? 20 : settings.dragbarw;
    let scale = config.scale || .3;
    let rectDiamensions = rectangle[0][0].getBBox();
    let height = rectDiamensions.height;
    let width = rectDiamensions.width;

    let parentDiamensions = this.boxDiamiensions();

    let isXChecked = (config.scalability == this.DRAG_CONSTANTS.BOTH || config.scalability == this.DRAG_CONSTANTS.VERTICAL) ? true : false;
    let isYChecked = (config.scalability == this.DRAG_CONSTANTS.BOTH || config.scalability == this.DRAG_CONSTANTS.HORIZONTAL) ? true : false;

    // scale behaviours
    let scaleright = d3.behavior.drag()
      .origin(Object)
      .on('drag', rScaleResize);

    let scaleleft = d3.behavior.drag()
      .origin(Object)
      .on('drag', lScaleResize);

    let scaletop = d3.behavior.drag()
      .origin(Object)
      .on('drag', tScaleResize);

    let scalebottom = d3.behavior.drag()
      .origin(Object)
      .on('drag', bScaleResize);

    // scale bars
    var scaleBarleft = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x - (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y + (dragbarw / 2);
      })
      .attr('height', height - dragbarw)
      .attr('id', 'scaleleft')
      .attr('width', dragbarw)
      .attr('fill', 'lightblue')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ew-resize')
      .call(scaleleft);

    var scaleBarright = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x + width - (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y + (dragbarw / 2);
      })
      .attr('id', 'scaleright')
      .attr('height', height - dragbarw)
      .attr('width', dragbarw)
      .attr('fill', 'lightblue')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ew-resize')
      .call(scaleright);

    var scaleBartop = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x + (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y - (dragbarw / 2);
      })
      .attr('height', dragbarw)
      .attr('id', 'scaleleft')
      .attr('width', width - dragbarw)
      .attr('fill', 'lightgreen')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ns-resize')
      .call(scaletop);

    var scaleBarbottom = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x + (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y + height - (dragbarw / 2);
      })
      .attr('id', 'scaleright')
      .attr('height', dragbarw)
      .attr('width', width - dragbarw)
      .attr('fill', 'lightgreen')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ns-resize')
      .call(scalebottom);

    function lScaleResize(d) {
      if (isXChecked) {
        var oldx = d.x;
        //Max x on the right is x + width - dragbarw
        //Max x on the left is 0 - (dragbarw/2)
        d.x = Math.max(0, Math.min(d.x + width - (dragbarw / 2), d3.event.x));
        width = width + (oldx - d.x);
        scaleBarleft
          .attr('x', function(d) {
            return d.x - (dragbarw / 2);
          });

        rectangle
          .attr('x', function(d) {
            return d.x;
          })
          .attr('width', width);

        scaleBartop
          .attr('x', function(d) {
            return d.x + (dragbarw / 2);
          })
          .attr('width', width - dragbarw)
        scaleBarbottom
          .attr('x', function(d) {
            return d.x + (dragbarw / 2);
          })
          .attr('width', width - dragbarw)
        reflectChange({
          x: d.x + (dragbarw / 2),
          y: d.y,
          height: height,
          width: width
        });
      }
    }

    function rScaleResize(d) {
      if (isXChecked) {
        //Max x on the left is x - width
        //Max x on the right is width of screen + (dragbarw/2)
        var dragx = Math.max(d.x + (dragbarw / 2), Math.min(parentDiamensions.width, d.x + width + d3.event.dx));

        //recalculate width
        width = dragx - d.x;

        //move the right drag handle
        scaleBarright
          .attr('x', function(d) {
            return dragx - (dragbarw / 2)
          });

        //resize the drag rectangle
        //as we are only resizing from the right, the x coordinate does not need to change
        rectangle
          .attr('width', width);
        scaleBartop
          .attr('width', width - dragbarw)
        scaleBarbottom
          .attr('width', width - dragbarw)
        reflectChange({
          x: d.x + (dragbarw / 2),
          y: d.y,
          height: height,
          width: width
        });
      }
    }

    function tScaleResize(d) {

      if (isYChecked) {
        var oldy = d.y;
        //Max x on the right is x + width - dragbarw
        //Max x on the left is 0 - (dragbarw/2)
        d.y = Math.max(0, Math.min(d.y + height - (dragbarw / 2), d3.event.y));
        height = height + (oldy - d.y);
        scaleBartop
          .attr('y', function(d) {
            return d.y - (dragbarw / 2);
          });

        rectangle
          .attr('y', function(d) {
            return d.y;
          })
          .attr('height', height);

        scaleBarleft
          .attr('y', function(d) {
            return d.y + (dragbarw / 2);
          })
          .attr('height', height - dragbarw);
        scaleBarright
          .attr('y', function(d) {
            return d.y + (dragbarw / 2);
          })
          .attr('height', height - dragbarw);
        reflectChange({
          x: d.x,
          y: d.y - (dragbarw / 2),
          height: height,
          width: width
        });
      }
    }

    function bScaleResize(d) {
      if (isYChecked) {
        //Max x on the left is x - width
        //Max x on the right is width of screen + (dragbarw/2)
        var dragy = Math.max(d.y + (dragbarw / 2), Math.min(parentDiamensions.height, d.y + height + d3.event.dy));

        //recalculate width
        height = dragy - d.y;

        //move the right drag handle
        scaleBarbottom
          .attr('y', function(d) {
            return dragy - (dragbarw / 2)
          });

        //resize the drag rectangle
        //as we are only resizing from the right, the x coordinate does not need to change
        rectangle
          .attr('height', height);
        scaleBarleft
          .attr('height', height - dragbarw);
        scaleBarright
          .attr('height', height - dragbarw);
        reflectChange({
          x: d.x,
          y: d.y,
          height: height,
          width: width
        });
      }
    }

    function reflectChange(d) {
      me.$['mouse-pointer'].innerHTML = 'x: ' + Math.round(d.x) +
        ',y: ' + Math.round(d.y) +
        ',h: ' + Math.round(d.height / scale) +
        ',w: ' + Math.round(d.width / scale);
    }

    return {
      rectangle,
      scaleBarleft,
      scaleBarright,
      scaleBartop,
      scaleBarbottom,
      getDiamensions: () => {
        return {
          height,
          width
        }
      }
    }
  },

  DRAG_CONSTANTS: {
    HORIZONTAL: 1,
    VERTICAL: 2,
    BOTH: 3
  },

  boxDiamiensions: function() {
    return {
      height: this.clientHeight,
      width: this.clientWidth
    }
  }
};
<commit_msg>Refactor '_getSettingsProp'<commit_after>PolymerD3.dragElem = {

  /* == Helper Functions == */
  // function to access properties from settings
  _getSettingsProp: function(prop, setting) {
    return PolymerD3.utilities.searchArr(setting, function(elem) {
      return elem.input == prop;
    });
  },

  initDragSettings: function(svg, settings, config) {
    /* == Configuration Cooking == */
    if (!config) {
      config = {
        areaRect: {},
        innerRect: {}
      };
    }
    let scale = config.scale || .3;
    let width = this._getSettingsProp('width', settings).selectedValue * scale;
    let height = this._getSettingsProp('height', settings).selectedValue * scale;
    let rectFillOpacity = config.areaRect.opacity || .8;
    let marginLeft = this._getSettingsProp('marginLeft', settings).selectedValue * scale;
    let marginTop = this._getSettingsProp('marginTop', settings).selectedValue * scale;
    let marginRight = this._getSettingsProp('marginRight', settings).selectedValue * scale;
    let marginBottom = this._getSettingsProp('marginBottom', settings).selectedValue * scale;

    /* == Operation== */
    // clears SVG
    svg.html('');

    // creates area group
    let areaG = svg.append('g')
      .data([{
        x: width / 4,
        y: height / 4
      }]);

    // create area rectangle
    let areaRect = this._drawRect(areaG, {
      width: width,
      height: height,
      scalability: this.DRAG_CONSTANTS.BOTH,
      fillOpacity: rectFillOpacity
    });

    // make area rectangle scalable
    let areaRectSettings = this._makeScalable(areaRect, areaG, {
      scalability: this.DRAG_CONSTANTS.BOTH,
      scale: scale
    });

    // inner rectangle
    let innerG = areaG.append('g').data([{
      x: width / 4,
      y: height / 4
    }]);
    let innerRect = this._drawRect(innerG, {
      width: width - (marginLeft + marginRight),
      height: height - (marginTop + marginBottom),
      x: marginLeft,
      y: marginTop,
      scalability: this.DRAG_CONSTANTS.BOTH,
      fillOpacity: rectFillOpacity
    });
    let innerRectSettings = this._makeScalable(innerRect, innerG, {
      scalability: this.DRAG_CONSTANTS.BOTH,
      scale: scale
    });

    return {
      areaRect: areaRectSettings,
      innerRect: innerRectSettings,
      scale: scale
    }
  },

  // creates a symmetrically scalable shape
  initSymmetric: function(svg, settings, config) {

  },

  // function to draw a rectangle with given config
  _drawRect: function(parent, config) {
    let x = config.x || 0;
    let y = config.y || 0;
    let dragrect = parent.append('rect')
      .attr('id', 'active')
      .attr('x', function(d) {
        return d.x + x;
      })
      .attr('y', function(d) {
        return d.y + y;
      })
      .attr('height', config.height)
      .attr('width', config.width)
      .attr('scalability', config.scalability)
      .attr('fill-opacity', config.fillOpacity);
    return dragrect;
  },

  // function to make a given rectangle inside a group scalable as per given config
  _makeScalable: function(rectangle, group, config) {
    let me = this;
    let dragbarw = config.dragbarw == null ? 20 : settings.dragbarw;
    let scale = config.scale || .3;
    let rectDiamensions = rectangle[0][0].getBBox();
    let height = rectDiamensions.height;
    let width = rectDiamensions.width;

    let parentDiamensions = this.boxDiamiensions();

    let isXChecked = (config.scalability == this.DRAG_CONSTANTS.BOTH || config.scalability == this.DRAG_CONSTANTS.VERTICAL) ? true : false;
    let isYChecked = (config.scalability == this.DRAG_CONSTANTS.BOTH || config.scalability == this.DRAG_CONSTANTS.HORIZONTAL) ? true : false;

    // scale behaviours
    let scaleright = d3.behavior.drag()
      .origin(Object)
      .on('drag', rScaleResize);

    let scaleleft = d3.behavior.drag()
      .origin(Object)
      .on('drag', lScaleResize);

    let scaletop = d3.behavior.drag()
      .origin(Object)
      .on('drag', tScaleResize);

    let scalebottom = d3.behavior.drag()
      .origin(Object)
      .on('drag', bScaleResize);

    // scale bars
    var scaleBarleft = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x - (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y + (dragbarw / 2);
      })
      .attr('height', height - dragbarw)
      .attr('id', 'scaleleft')
      .attr('width', dragbarw)
      .attr('fill', 'lightblue')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ew-resize')
      .call(scaleleft);

    var scaleBarright = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x + width - (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y + (dragbarw / 2);
      })
      .attr('id', 'scaleright')
      .attr('height', height - dragbarw)
      .attr('width', dragbarw)
      .attr('fill', 'lightblue')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ew-resize')
      .call(scaleright);

    var scaleBartop = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x + (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y - (dragbarw / 2);
      })
      .attr('height', dragbarw)
      .attr('id', 'scaleleft')
      .attr('width', width - dragbarw)
      .attr('fill', 'lightgreen')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ns-resize')
      .call(scaletop);

    var scaleBarbottom = group.append('rect')
      .attr('x', function(d) {
        return rectDiamensions.x + (dragbarw / 2);
      })
      .attr('y', function(d) {
        return rectDiamensions.y + height - (dragbarw / 2);
      })
      .attr('id', 'scaleright')
      .attr('height', dragbarw)
      .attr('width', width - dragbarw)
      .attr('fill', 'lightgreen')
      .attr('fill-opacity', 0)
      .attr('cursor', 'ns-resize')
      .call(scalebottom);

    function lScaleResize(d) {
      if (isXChecked) {
        var oldx = d.x;
        //Max x on the right is x + width - dragbarw
        //Max x on the left is 0 - (dragbarw/2)
        d.x = Math.max(0, Math.min(d.x + width - (dragbarw / 2), d3.event.x));
        width = width + (oldx - d.x);
        scaleBarleft
          .attr('x', function(d) {
            return d.x - (dragbarw / 2);
          });

        rectangle
          .attr('x', function(d) {
            return d.x;
          })
          .attr('width', width);

        scaleBartop
          .attr('x', function(d) {
            return d.x + (dragbarw / 2);
          })
          .attr('width', width - dragbarw)
        scaleBarbottom
          .attr('x', function(d) {
            return d.x + (dragbarw / 2);
          })
          .attr('width', width - dragbarw)
        reflectChange({
          x: d.x + (dragbarw / 2),
          y: d.y,
          height: height,
          width: width
        });
      }
    }

    function rScaleResize(d) {
      if (isXChecked) {
        //Max x on the left is x - width
        //Max x on the right is width of screen + (dragbarw/2)
        var dragx = Math.max(d.x + (dragbarw / 2), Math.min(parentDiamensions.width, d.x + width + d3.event.dx));

        //recalculate width
        width = dragx - d.x;

        //move the right drag handle
        scaleBarright
          .attr('x', function(d) {
            return dragx - (dragbarw / 2)
          });

        //resize the drag rectangle
        //as we are only resizing from the right, the x coordinate does not need to change
        rectangle
          .attr('width', width);
        scaleBartop
          .attr('width', width - dragbarw)
        scaleBarbottom
          .attr('width', width - dragbarw)
        reflectChange({
          x: d.x + (dragbarw / 2),
          y: d.y,
          height: height,
          width: width
        });
      }
    }

    function tScaleResize(d) {

      if (isYChecked) {
        var oldy = d.y;
        //Max x on the right is x + width - dragbarw
        //Max x on the left is 0 - (dragbarw/2)
        d.y = Math.max(0, Math.min(d.y + height - (dragbarw / 2), d3.event.y));
        height = height + (oldy - d.y);
        scaleBartop
          .attr('y', function(d) {
            return d.y - (dragbarw / 2);
          });

        rectangle
          .attr('y', function(d) {
            return d.y;
          })
          .attr('height', height);

        scaleBarleft
          .attr('y', function(d) {
            return d.y + (dragbarw / 2);
          })
          .attr('height', height - dragbarw);
        scaleBarright
          .attr('y', function(d) {
            return d.y + (dragbarw / 2);
          })
          .attr('height', height - dragbarw);
        reflectChange({
          x: d.x,
          y: d.y - (dragbarw / 2),
          height: height,
          width: width
        });
      }
    }

    function bScaleResize(d) {
      if (isYChecked) {
        //Max x on the left is x - width
        //Max x on the right is width of screen + (dragbarw/2)
        var dragy = Math.max(d.y + (dragbarw / 2), Math.min(parentDiamensions.height, d.y + height + d3.event.dy));

        //recalculate width
        height = dragy - d.y;

        //move the right drag handle
        scaleBarbottom
          .attr('y', function(d) {
            return dragy - (dragbarw / 2)
          });

        //resize the drag rectangle
        //as we are only resizing from the right, the x coordinate does not need to change
        rectangle
          .attr('height', height);
        scaleBarleft
          .attr('height', height - dragbarw);
        scaleBarright
          .attr('height', height - dragbarw);
        reflectChange({
          x: d.x,
          y: d.y,
          height: height,
          width: width
        });
      }
    }

    function reflectChange(d) {
      me.$['mouse-pointer'].innerHTML = 'x: ' + Math.round(d.x) +
        ',y: ' + Math.round(d.y) +
        ',h: ' + Math.round(d.height / scale) +
        ',w: ' + Math.round(d.width / scale);
    }

    return {
      rectangle,
      scaleBarleft,
      scaleBarright,
      scaleBartop,
      scaleBarbottom,
      getDiamensions: () => {
        return {
          height,
          width
        }
      }
    }
  },

  DRAG_CONSTANTS: {
    HORIZONTAL: 1,
    VERTICAL: 2,
    BOTH: 3
  },

  boxDiamiensions: function() {
    return {
      height: this.clientHeight,
      width: this.clientWidth
    }
  }
};
<|endoftext|>


<commit_before>$(document).ready(function() {

        var getInnerText = function (element) {
            var html = element.find("code")[0].outerHTML;
            var proxyItem = document.createElement("div");
            proxyItem.innerHTML = html;
            return proxyItem.textContent;
        };

        var createButton = function(className){
            var btn = document.createElement("div");
            btn.className = className;
            return btn;
        };

        var startScreenView = function(){
            var content = this.dataset !== undefined ? this.dataset.clipboardText : this.getAttribute("data-clipboard-text");
            window.sessionStorage.setItem("content", content);
            var title = $(this).parent().parent().parent().parent().find('h2')
                .clone(true)
                .find('a')
                .remove()
                .end()
                .html();

            var content = $(this).parent().parent()
                .clone(true)
                .find('.active-lang')
                .remove()
                .end()
                .find('.copy-btn')
                .addClass('copy-btn-fs')
                .removeClass('copy-btn')
                .end()
                .find('.screen-btn')
                .attr('data-original-title', 'Exit Full Screen')
                .end()
                .find('.tooltip')
                .remove()
                .end()
                .html();

            $(".fs-modal #modal-title").html(title);
            $(".fs-modal .modal-body").html(content);

            $(".fs-modal .modal-body").delegate(".reqres a", "click", function() {
                $(this).parent().children().removeClass("active");
                $(this).addClass("active");
                $(this).parents().closest(".modal-body").children().removeClass("active");
                $(this).parents().closest(".modal-body").children().eq($(this).index() + 1).addClass("active");
                var reqresNo = $(this).parent().parent().attr('class').substr(7);
                $(".left-wrapper .reqres." + reqresNo + " a").eq($(this).index()).click();
            });
        };

        var startRowView = function(){
            var content = this.dataset !== undefined ? this.dataset.contentText : this.getAttribute("data-content-text");
            window.sessionStorage.setItem("content", content);
            var win = window.open(window.location.protocol + "//" + window.location.host + "/products-and-docs/raw-view/", '_blank');
            win.focus();
        };

        var makeCopy = function () {
            this.classList.add("copied")
            window.setTimeout(function(){
                document.getElementsByClassName("copied")[0].classList.remove("copied");
            }, 2000);
        };

        $(".reqres").each(function(index) {

            $(this).addClass("n" + index);

            tab1 = $(this).next();
            tab2 = $(this).next().next();

            var screenbtn1 = createButton("screen-btn");
                if(screenbtn1.dataset !== undefined){
                    screenbtn1.dataset.clipboardText =  getInnerText(tab1);
                }
                else{
                    screenbtn1.setAttribute("data-clipboard-text", getInnerText(tab1));
                }
                screenbtn1.addEventListener("click",startScreenView);
                tab1.prepend(screenbtn1);
                screenbtn1.setAttribute("data-toggle", "modal");
                screenbtn1.setAttribute("data-target", ".modal-langs");
                screenbtn1.setAttribute("rel", "tooltip");
                screenbtn1.setAttribute("data-placement", "top");
                screenbtn1.setAttribute("data-original-title", "View Full Screen");

            var rawbtn1 = createButton("raw-btn");
                if(rawbtn1.dataset !== undefined){
                    rawbtn1.dataset.contentText =  getInnerText(tab1);
                }
                else{
                    rawbtn1.setAttribute("data-content-text", getInnerText(tab1));
                }
                rawbtn1.addEventListener("click",startRowView);
                tab1.prepend(rawbtn1);
                rawbtn1.setAttribute("rel", "tooltip");
                rawbtn1.setAttribute("data-placement", "top");
                rawbtn1.setAttribute("data-original-title", "View Raw");

            var btn1 = createButton("copy-btn");
                btn1.dataset.clipboardText =  getInnerText(tab1);
                btn1.addEventListener("click", makeCopy);
                tab1.prepend(btn1);
                btn1.setAttribute("rel", "tooltip");
                btn1.setAttribute("data-placement", "top");
                btn1.setAttribute("data-original-title", "Copy to Clipboard");

            var screenbtn2 = createButton("screen-btn");
            if(screenbtn2.dataset !== undefined){
                screenbtn2.dataset.clipboardText =  getInnerText(tab2);
            }
            else{
                screenbtn2.setAttribute("data-clipboard-text", getInnerText(tab2));
            }
            screenbtn2.addEventListener("click",startScreenView);
            tab2.prepend(screenbtn2);
            screenbtn2.setAttribute("data-toggle", "modal");
            screenbtn2.setAttribute("data-target", ".modal-langs");
            screenbtn2.setAttribute("rel", "tooltip");
            screenbtn2.setAttribute("data-placement", "top");
            screenbtn2.setAttribute("data-original-title", "View Full Screen");

            var rawbtn2 = createButton("raw-btn");
                if(rawbtn2.dataset !== undefined){
                    rawbtn2.dataset.contentText =  getInnerText(tab2);
                }
                else{
                    rawbtn2.setAttribute("data-content-text", getInnerText(tab2));
                }
                rawbtn2.addEventListener("click", startRowView);
                tab2.prepend(rawbtn2);
                rawbtn2.setAttribute("rel", "tooltip");
                rawbtn2.setAttribute("data-placement", "top");
                rawbtn2.setAttribute("data-original-title", "View Raw");

            var btn2 = createButton("copy-btn");
                btn2.dataset.clipboardText =  getInnerText(tab2);
                btn2.addEventListener("click", makeCopy);
            tab2.prepend(btn2);
            btn2.setAttribute("rel", "tooltip");
            btn2.setAttribute("data-placement", "top");
            btn2.setAttribute("data-original-title", "Copy to Clipboard");

            $('

').insertBefore($(this));
            $(this).prev().append($(this)).append(tab1).append(tab2);
            $(this).parent().find('a').eq(0).addClass("active");
            $(this).next().addClass("r-tab").next().addClass("r-tab");
            $(this).next().addClass("active");
        });

        $(".reqres a").click(function(event) {
            $(this).parent().find(".active").removeClass("active");
            $(this).parent().parent().parent().find(".r-tab.active").removeClass("active");
            $(this).parent().parent().parent().find(".r-tab").eq($(this).index()).addClass("active");
            $(this).addClass("active");
        });

        $(function () {
            $('body').tooltip({
                selector: '[rel="tooltip"]'
            });
            /* $('[rel="tooltip"]').tooltip({
                animation: true
            });
            */
        })

});<commit_msg>Changelog<commit_after>$(document).ready(function() {

        var getInnerText = function (element) {
            var html = element.find("code")[0].outerHTML;
            var proxyItem = document.createElement("div");
            proxyItem.innerHTML = html;
            return proxyItem.textContent;
        };

        var createButton = function(className){
            var btn = document.createElement("div");
            btn.className = className;
            return btn;
        };

        var startScreenView = function(){
            var content = this.dataset !== undefined ? this.dataset.clipboardText : this.getAttribute("data-clipboard-text");
            window.sessionStorage.setItem("content", content);
            var title = $(this).parent().parent().parent().parent().find('h2')
                .clone(true)
                .find('a')
                .remove()
                .end()
                .html();

            var content = $(this).parent().parent()
                .clone(true)
                .find('.active-lang')
                .remove()
                .end()
                .find('.copy-btn')
                .addClass('copy-btn-fs')
                .removeClass('copy-btn')
                .end()
                .find('.screen-btn')
                .attr('data-original-title', 'Exit Full Screen')
                .end()
                .find('.tooltip')
                .remove()
                .end()
                .html();

            $(".fs-modal #modal-title").html(title);
            $(".fs-modal .modal-body").html(content);

            $(".fs-modal .modal-body").delegate(".reqres a", "click", function(event) {
                event.preventDefault();
                $(this).parent().children().removeClass("active");
                $(this).addClass("active");
                $(this).parents().closest(".modal-body").children().removeClass("active");
                $(this).parents().closest(".modal-body").children().eq($(this).index() + 1).addClass("active");
                var reqresNo = $(this).parent().parent().attr('class').substr(7);
                $(".left-wrapper .reqres." + reqresNo + " a").eq($(this).index()).click();
            });
        };

        var startRowView = function(){
            var content = this.dataset !== undefined ? this.dataset.contentText : this.getAttribute("data-content-text");
            window.sessionStorage.setItem("content", content);
            var win = window.open(window.location.protocol + "//" + window.location.host + "/products-and-docs/raw-view/", '_blank');
            win.focus();
        };

        var makeCopy = function () {
            this.classList.add("copied")
            window.setTimeout(function(){
                document.getElementsByClassName("copied")[0].classList.remove("copied");
            }, 2000);
        };

        $(".reqres").each(function(index) {

            $(this).addClass("n" + index);

            tab1 = $(this).next();
            tab2 = $(this).next().next();

            var screenbtn1 = createButton("screen-btn");
                if(screenbtn1.dataset !== undefined){
                    screenbtn1.dataset.clipboardText =  getInnerText(tab1);
                }
                else{
                    screenbtn1.setAttribute("data-clipboard-text", getInnerText(tab1));
                }
                screenbtn1.addEventListener("click",startScreenView);
                tab1.prepend(screenbtn1);
                screenbtn1.setAttribute("data-toggle", "modal");
                screenbtn1.setAttribute("data-target", ".modal-langs");
                screenbtn1.setAttribute("rel", "tooltip");
                screenbtn1.setAttribute("data-placement", "top");
                screenbtn1.setAttribute("data-original-title", "View Full Screen");

            var rawbtn1 = createButton("raw-btn");
                if(rawbtn1.dataset !== undefined){
                    rawbtn1.dataset.contentText =  getInnerText(tab1);
                }
                else{
                    rawbtn1.setAttribute("data-content-text", getInnerText(tab1));
                }
                rawbtn1.addEventListener("click",startRowView);
                tab1.prepend(rawbtn1);
                rawbtn1.setAttribute("rel", "tooltip");
                rawbtn1.setAttribute("data-placement", "top");
                rawbtn1.setAttribute("data-original-title", "View Raw");

            var btn1 = createButton("copy-btn");
                btn1.dataset.clipboardText =  getInnerText(tab1);
                btn1.addEventListener("click", makeCopy);
                tab1.prepend(btn1);
                btn1.setAttribute("rel", "tooltip");
                btn1.setAttribute("data-placement", "top");
                btn1.setAttribute("data-original-title", "Copy to Clipboard");

            var screenbtn2 = createButton("screen-btn");
            if(screenbtn2.dataset !== undefined){
                screenbtn2.dataset.clipboardText =  getInnerText(tab2);
            }
            else{
                screenbtn2.setAttribute("data-clipboard-text", getInnerText(tab2));
            }
            screenbtn2.addEventListener("click",startScreenView);
            tab2.prepend(screenbtn2);
            screenbtn2.setAttribute("data-toggle", "modal");
            screenbtn2.setAttribute("data-target", ".modal-langs");
            screenbtn2.setAttribute("rel", "tooltip");
            screenbtn2.setAttribute("data-placement", "top");
            screenbtn2.setAttribute("data-original-title", "View Full Screen");

            var rawbtn2 = createButton("raw-btn");
                if(rawbtn2.dataset !== undefined){
                    rawbtn2.dataset.contentText =  getInnerText(tab2);
                }
                else{
                    rawbtn2.setAttribute("data-content-text", getInnerText(tab2));
                }
                rawbtn2.addEventListener("click", startRowView);
                tab2.prepend(rawbtn2);
                rawbtn2.setAttribute("rel", "tooltip");
                rawbtn2.setAttribute("data-placement", "top");
                rawbtn2.setAttribute("data-original-title", "View Raw");

            var btn2 = createButton("copy-btn");
                btn2.dataset.clipboardText =  getInnerText(tab2);
                btn2.addEventListener("click", makeCopy);
            tab2.prepend(btn2);
            btn2.setAttribute("rel", "tooltip");
            btn2.setAttribute("data-placement", "top");
            btn2.setAttribute("data-original-title", "Copy to Clipboard");

            $('

').insertBefore($(this));
            $(this).prev().append($(this)).append(tab1).append(tab2);
            $(this).parent().find('a').eq(0).addClass("active");
            $(this).next().addClass("r-tab").next().addClass("r-tab");
            $(this).next().addClass("active");
        });

        $(".reqres a").click(function(event) {
            event.preventDefault();
            $(this).parent().find(".active").removeClass("active");
            $(this).parent().parent().parent().find(".r-tab.active").removeClass("active");
            $(this).parent().parent().parent().find(".r-tab").eq($(this).index()).addClass("active");
            $(this).addClass("active");
        });

        $(function () {
            $('body').tooltip({
                selector: '[rel="tooltip"]'
            });
            /* $('[rel="tooltip"]').tooltip({
                animation: true
            });
            */
        })

});<|endoftext|>


<commit_before>function maquina(n){
     m=(n-1)%4 //número de piedas que quita la máquina
     if (m==0){
         m=(Math.floor(Math.random()*3)+1);
     }
     return m;
 }
 document.write('
'+"Este es el juego de"+'
');
 document.write('
'+"LA ÚLTIMA PIEDRA"+'
');
 document.write("Usted dispone de un conjunto de piedras iniciales."+'
');
 document.write("Juega contra la máquina"+'
');
 document.write("En cada tirada, tanto usted como la máquina,"+'
');
 document.write("pueden quirar una piedra, dos piedras o tres piedras."+'
');
 document.write("Es obligatorio quitar como mínimo 1 pieda y como máximo 3."+'
');
 document.write("Comienza jugando usted y el último que quita pierde."+'
');
 var n=Math.floor(Math.random()*12)+10 //número inicial de piedras
 document.write("Número inicial de piedras: "+n+'
');
 var x,m,juega=true;
 do {
     do {
         x = prompt ("Quedan "+n+"\nDime cuantas piedas quitas: 1, 2 o 3");
     }
     while (x<1 || x>3)
     n=n-x;
     document.write("Usted ha quitado "+x+" piedas. Quedan "+n+'
');
     if (n<=0){
         juega=false;
         document.write('
'+"La máquina gana."+'
');
     } else {
         m=maquina(n);
         n=n-m;
         document.write("La máquina ha quitado "+m+" piedas. Quedan "+n+'
');
         if (n<=0){
             juega=false;
             document.write('
'+"Usted gana."+'
');
         }
     }
 }
 while (juega);   <commit_msg>Delete piedras.js<commit_after><|endoftext|>


<commit_before>Future = Npm.require('fibers/future');

// At a minimum, set up LDAP_DEFAULTS.url and .dn according to
// your needs. url should appear as 'ldap://your.url.here'
// dn should appear in normal ldap format of comma separated attribute=value
// e.g. 'uid=someuser,cn=users,dc=somevalue'
LDAP_DEFAULTS = {
    url: false,
    port: '389',
    dn: false,
    searchDN: false,
    searchCredentials: false,
    createNewUser: true,
    defaultDomain: false,
    searchResultsProfileMap: false,
    base: null,
    search: '(objectclass=*)',
    ldapsCertificate: false
};

/**
 @class LDAP
 @constructor
 */
var LDAP = function (options) {
    // Set options
    this.options = _.defaults(options, LDAP_DEFAULTS);

    // Make sure options have been set
    try {
        check(this.options.url, String);
        //check(this.options.dn, String);
    } catch (e) {
        throw new Meteor.Error('Bad Defaults', 'Options not set. Make sure to set LDAP_DEFAULTS.url and LDAP_DEFAULTS.dn!');
    }

    // Because NPM ldapjs module has some binary builds,
    // We had to create a wraper package for it and build for
    // certain architectures. The package typ:ldap-js exports
    // 'MeteorWrapperLdapjs' which is a wrapper for the npm module
    this.ldapjs = MeteorWrapperLdapjs;
};

/**
 * Attempt to bind (authenticate) ldap
 * and perform a dn search if specified
 *
 * @method ldapCheck
 *
 * @param {Object} options  Object with username, ldapPass and overrides for LDAP_DEFAULTS object.
 * Additionally the searchBeforeBind parameter can be specified, which is used to search for the DN
 * if not provided.
 */
LDAP.prototype.ldapCheck = function (options) {

    var self = this;

    options = options || {};

    if (options.hasOwnProperty('username') && options.hasOwnProperty('ldapPass')) {

        var ldapAsyncFut = new Future();

        // Create ldap client
        var fullUrl = self.options.url + ':' + self.options.port;
        var client = null;

        if (self.options.url.indexOf('ldaps://') === 0) {
            client = self.ldapjs.createClient({
                url: fullUrl,
                tlsOptions: {
                    ca: [self.options.ldapsCertificate]
                }
            });
        }
        else {
            client = self.ldapjs.createClient({
                url: fullUrl
            });
        }

        // Slide @xyz.whatever from username if it was passed in
        // and replace it with the domain specified in defaults
        var emailSliceIndex = options.username.indexOf('@');
        var username;
        var domain = self.options.defaultDomain;

        // If user appended email domain, strip it out
        // And use the defaults.defaultDomain if set
        if (emailSliceIndex !== -1) {
            username = options.username.substring(0, emailSliceIndex);
            domain = domain || options.username.substring((emailSliceIndex + 1), options.username.length);
        } else {
            username = options.username;
        }

        // If DN is provided, use it to bind
        if (self.options.dn) {
            // Attempt to bind to ldap server with provided info
            client.bind(self.options.searchDN || self.options.dn, self.options.searchCredentials || options.ldapPass, function (err) {
                try {
                    if (err) {
                        // Bind failure, return error
                        throw new Meteor.Error(err.code, err.message);
                    }

                    var handleSearchProfile = function (retObject, bindAfterSearch) {
                        retObject.emptySearch = true;

                        // construct list of ldap attributes to fetch
                        var attributes = [];
                        if (self.options.searchResultsProfileMap) {
                            self.options.searchResultsProfileMap.map(function (item) {
                                attributes.push(item.resultKey);
                            });
                        }

                        // use base if given, else the dn for the ldap search
                        var searchBase = self.options.base || self.options.dn;
                        var searchOptions = {
                            scope: 'sub',
                            sizeLimit: 1,
                            attributes: attributes,
                            filter: self.options.search
                        };

                        client.search(searchBase, searchOptions, function (err, res) {
                            if (err) {
                                ldapAsyncFut.return({
                                    error: err
                                });
                            }

                            res.on('searchEntry', function (entry) {
                                retObject.emptySearch = false;
                                // Add entry results to return object
                                retObject.searchResults = entry.object;
                                if (bindAfterSearch) {
                                    client.bind(retObject.searchResults.dn, options.ldapPass, function (err) {
                                        try {
                                            if (err) {
                                                throw new Meteor.Error(err.code, err.message);
                                            }
                                            ldapAsyncFut.return(retObject);
                                        } catch (e) {
                                            ldapAsyncFut.return({
                                                error: e
                                            });
                                        }
                                    })
                                } else ldapAsyncFut.return(retObject);
                            });

                            res.on('end', function () {
                                if (retObject.dn === undefined) {
                                    ldapAsyncFut.return(retObject);
                                }
                            });

                        });
                    };

                    var retObject = {
                        username: username,
                        searchResults: null,
                        email: domain ? username + '@' + domain : false
                    };

                    if (self.options.searchDN) {
                        handleSearchProfile(retObject, true);
                    } else if (self.options.searchResultsProfileMap) {
                        handleSearchProfile(retObject, false);
                    } else {
                        ldapAsyncFut.return(retObject);
                    }

                } catch (e) {
                    ldapAsyncFut.return({
                        error: e
                    });
                }
            });
        }
        // DN not provided, search for DN and use result to bind
        else if (typeof self.options.searchBeforeBind !== undefined) {
            // initialize result
            var retObject = {
                username: username,
                email: domain ? username + '@' + domain : false,
                emptySearch: true,
                searchResults: {}
            };

            // compile attribute list to return
            var searchAttributes = ['dn'];
            self.options.searchResultsProfileMap.map(function (item) {
                searchAttributes.push(item.resultKey);
            });

            var filter = self.options.search;
            Object.keys(options.ldapOptions.searchBeforeBind).forEach(function (searchKey) {
                filter = '&' + filter + '(' + searchKey + '=' + options.ldapOptions.searchBeforeBind[searchKey] + ')';
            });
            var searchOptions = {
                scope: 'sub',
                sizeLimit: 1,
                filter: filter
            };

            // perform LDAP search to determine DN
            client.search(self.options.base, searchOptions, function (err, res) {
                retObject.emptySearch = true;
                res.on('searchEntry', function (entry) {
                    retObject.dn = entry.objectName;
                    retObject.username = retObject.dn;
                    retObject.emptySearch = false;

                    // Return search results if specified
                    if (self.options.searchResultsProfileMap) {
                        // construct list of ldap attributes to fetch
                        self.options.searchResultsProfileMap.map(function (item) {
                            retObject.searchResults[item.resultKey] = entry.object[item.resultKey];
                        });
                    }

                    // use the determined DN to bind
                    client.bind(entry.objectName, options.ldapPass, function (err) {
                        try {
                            if (err) {
                                throw new Meteor.Error(err.code, err.message);
                            }
                            else {
                                ldapAsyncFut.return(retObject);
                            }
                        }
                        catch (e) {
                            ldapAsyncFut.return({
                                error: e
                            });
                        }
                    });
                });
                // If no dn is found, return as is.
                res.on('end', function (result) {
                    if (retObject.dn === undefined) {
                        ldapAsyncFut.return(retObject);
                    }
                });
            });
        }

        return ldapAsyncFut.wait();

    } else {
        throw new Meteor.Error(403, 'Missing LDAP Auth Parameter');
    }

};

// Register login handler with Meteor
// Here we create a new LDAP instance with options passed from
// Meteor.loginWithLDAP on client side
// @param {Object} loginRequest will consist of username, ldapPass, ldap, and ldapOptions
Accounts.registerLoginHandler('ldap', function (loginRequest) {
    // If 'ldap' isn't set in loginRequest object,
    // then this isn't the proper handler (return undefined)
    if (!loginRequest.ldap) {
        return undefined;
    }

    // Instantiate LDAP with options
    var userOptions = loginRequest.ldapOptions || {};
    var ldapObj = new LDAP(userOptions);

    // Call ldapCheck and get response
    var ldapResponse = ldapObj.ldapCheck(loginRequest);

    if (ldapResponse.error) {
        return {
            userId: null,
            error: ldapResponse.error
        };
    }
    else if (ldapResponse.emptySearch) {
        return {
            userId: null,
            error: new Meteor.Error(403, 'User not found in LDAP')
        };
    }
    else {
        // Set initial userId and token vals
        var userId = null;
        var stampedToken = {
            token: null
        };

        // Look to see if user already exists
        var user = Meteor.users.findOne({
            username: ldapResponse.username
        });

        // Login user if they exist
        if (user) {
            userId = user._id;

            // Create hashed token so user stays logged in
            stampedToken = Accounts._generateStampedLoginToken();
            var hashStampedToken = Accounts._hashStampedToken(stampedToken);
            // Update the user's token in mongo
            Meteor.users.update(userId, {
                $push: {
                    'services.resume.loginTokens': hashStampedToken
                }
            });
        }
        // Otherwise create user if option is set
        else if (ldapObj.options.createNewUser) {
            var userObject = {
                username: ldapResponse.username
            };
            // Set email
            if (ldapResponse.email) userObject.email = ldapResponse.email;

            // Set profile values if specified in searchResultsProfileMap
            if (ldapResponse.searchResults && ldapObj.options.searchResultsProfileMap.length > 0) {

                var profileMap = ldapObj.options.searchResultsProfileMap;
                var profileObject = {};

                // Loop through profileMap and set values on profile object
                for (var i = 0; i < profileMap.length; i++) {
                    var resultKey = profileMap[i].resultKey;

                    // If our search results have the specified property, set the profile property to its value
                    if (ldapResponse.searchResults.hasOwnProperty(resultKey)) {
                        profileObject[profileMap[i].profileProperty] = ldapResponse.searchResults[resultKey];
                    }

                }
                // Set userObject profile
                userObject.profile = profileObject;
            }

            userId = Accounts.createUser(userObject);
        } else {
            // Ldap success, but no user created
            console.log('LDAP Authentication succeeded for ' + ldapResponse.username + ', but no user exists in Meteor. Either create the user manually or set LDAP_DEFAULTS.createNewUser to true');
            return {
                userId: null,
                error: new Meteor.Error(403, 'User found in LDAP but not in application')
            };
        }

        return {
            userId: userId,
            token: stampedToken.token
        };
    }

});
<commit_msg>Avoid another double future resolve in a bind after two step find<commit_after>Future = Npm.require('fibers/future');

// At a minimum, set up LDAP_DEFAULTS.url and .dn according to
// your needs. url should appear as 'ldap://your.url.here'
// dn should appear in normal ldap format of comma separated attribute=value
// e.g. 'uid=someuser,cn=users,dc=somevalue'
LDAP_DEFAULTS = {
    url: false,
    port: '389',
    dn: false,
    searchDN: false,
    searchCredentials: false,
    createNewUser: true,
    defaultDomain: false,
    searchResultsProfileMap: false,
    base: null,
    search: '(objectclass=*)',
    ldapsCertificate: false
};

/**
 @class LDAP
 @constructor
 */
var LDAP = function (options) {
    // Set options
    this.options = _.defaults(options, LDAP_DEFAULTS);

    // Make sure options have been set
    try {
        check(this.options.url, String);
        //check(this.options.dn, String);
    } catch (e) {
        throw new Meteor.Error('Bad Defaults', 'Options not set. Make sure to set LDAP_DEFAULTS.url and LDAP_DEFAULTS.dn!');
    }

    // Because NPM ldapjs module has some binary builds,
    // We had to create a wraper package for it and build for
    // certain architectures. The package typ:ldap-js exports
    // 'MeteorWrapperLdapjs' which is a wrapper for the npm module
    this.ldapjs = MeteorWrapperLdapjs;
};

/**
 * Attempt to bind (authenticate) ldap
 * and perform a dn search if specified
 *
 * @method ldapCheck
 *
 * @param {Object} options  Object with username, ldapPass and overrides for LDAP_DEFAULTS object.
 * Additionally the searchBeforeBind parameter can be specified, which is used to search for the DN
 * if not provided.
 */
LDAP.prototype.ldapCheck = function (options) {

    var self = this;

    options = options || {};

    if (options.hasOwnProperty('username') && options.hasOwnProperty('ldapPass')) {

        var ldapAsyncFut = new Future();

        // Create ldap client
        var fullUrl = self.options.url + ':' + self.options.port;
        var client = null;

        if (self.options.url.indexOf('ldaps://') === 0) {
            client = self.ldapjs.createClient({
                url: fullUrl,
                tlsOptions: {
                    ca: [self.options.ldapsCertificate]
                }
            });
        }
        else {
            client = self.ldapjs.createClient({
                url: fullUrl
            });
        }

        // Slide @xyz.whatever from username if it was passed in
        // and replace it with the domain specified in defaults
        var emailSliceIndex = options.username.indexOf('@');
        var username;
        var domain = self.options.defaultDomain;

        // If user appended email domain, strip it out
        // And use the defaults.defaultDomain if set
        if (emailSliceIndex !== -1) {
            username = options.username.substring(0, emailSliceIndex);
            domain = domain || options.username.substring((emailSliceIndex + 1), options.username.length);
        } else {
            username = options.username;
        }

        // If DN is provided, use it to bind
        if (self.options.dn) {
            // Attempt to bind to ldap server with provided info
            client.bind(self.options.searchDN || self.options.dn, self.options.searchCredentials || options.ldapPass, function (err) {
                try {
                    if (err) {
                        // Bind failure, return error
                        throw new Meteor.Error(err.code, err.message);
                    }

                    var handleSearchProfile = function (retObject, bindAfterSearch) {
                        retObject.emptySearch = true;

                        // construct list of ldap attributes to fetch
                        var attributes = [];
                        if (self.options.searchResultsProfileMap) {
                            self.options.searchResultsProfileMap.map(function (item) {
                                attributes.push(item.resultKey);
                            });
                        }

                        // use base if given, else the dn for the ldap search
                        var searchBase = self.options.base || self.options.dn;
                        var searchOptions = {
                            scope: 'sub',
                            sizeLimit: 1,
                            attributes: attributes,
                            filter: self.options.search
                        };

                        client.search(searchBase, searchOptions, function (err, res) {
                            if (err) {
                                ldapAsyncFut.return({
                                    error: err
                                });
                            }

                            res.on('searchEntry', function (entry) {
                                retObject.emptySearch = false;
                                // Add entry results to return object
                                retObject.searchResults = entry.object;
                                if (bindAfterSearch) {
                                    client.bind(retObject.searchResults.dn, options.ldapPass, function (err) {
                                        try {
                                            if (err) {
                                                throw new Meteor.Error(err.code, err.message);
                                            }
                                            ldapAsyncFut.return(retObject);
                                        } catch (e) {
                                            ldapAsyncFut.return({
                                                error: e
                                            });
                                        }
                                    })
                                } else ldapAsyncFut.return(retObject);
                            });

                            res.on('end', function () {
                                if (retObject.dn === undefined && !bindAfterSearch) {
                                    ldapAsyncFut.return(retObject);
                                }
                            });

                        });
                    };

                    var retObject = {
                        username: username,
                        searchResults: null,
                        email: domain ? username + '@' + domain : false
                    };

                    if (self.options.searchDN) {
                        handleSearchProfile(retObject, true);
                    } else if (self.options.searchResultsProfileMap) {
                        handleSearchProfile(retObject, false);
                    } else {
                        ldapAsyncFut.return(retObject);
                    }

                } catch (e) {
                    ldapAsyncFut.return({
                        error: e
                    });
                }
            });
        }
        // DN not provided, search for DN and use result to bind
        else if (typeof self.options.searchBeforeBind !== undefined) {
            // initialize result
            var retObject = {
                username: username,
                email: domain ? username + '@' + domain : false,
                emptySearch: true,
                searchResults: {}
            };

            // compile attribute list to return
            var searchAttributes = ['dn'];
            self.options.searchResultsProfileMap.map(function (item) {
                searchAttributes.push(item.resultKey);
            });

            var filter = self.options.search;
            Object.keys(options.ldapOptions.searchBeforeBind).forEach(function (searchKey) {
                filter = '&' + filter + '(' + searchKey + '=' + options.ldapOptions.searchBeforeBind[searchKey] + ')';
            });
            var searchOptions = {
                scope: 'sub',
                sizeLimit: 1,
                filter: filter
            };

            // perform LDAP search to determine DN
            client.search(self.options.base, searchOptions, function (err, res) {
                retObject.emptySearch = true;
                res.on('searchEntry', function (entry) {
                    retObject.dn = entry.objectName;
                    retObject.username = retObject.dn;
                    retObject.emptySearch = false;

                    // Return search results if specified
                    if (self.options.searchResultsProfileMap) {
                        // construct list of ldap attributes to fetch
                        self.options.searchResultsProfileMap.map(function (item) {
                            retObject.searchResults[item.resultKey] = entry.object[item.resultKey];
                        });
                    }

                    // use the determined DN to bind
                    client.bind(entry.objectName, options.ldapPass, function (err) {
                        try {
                            if (err) {
                                throw new Meteor.Error(err.code, err.message);
                            }
                            else {
                                ldapAsyncFut.return(retObject);
                            }
                        }
                        catch (e) {
                            ldapAsyncFut.return({
                                error: e
                            });
                        }
                    });
                });
                // If no dn is found, return as is.
                res.on('end', function (result) {
                    if (retObject.dn === undefined) {
                        ldapAsyncFut.return(retObject);
                    }
                });
            });
        }

        return ldapAsyncFut.wait();

    } else {
        throw new Meteor.Error(403, 'Missing LDAP Auth Parameter');
    }

};

// Register login handler with Meteor
// Here we create a new LDAP instance with options passed from
// Meteor.loginWithLDAP on client side
// @param {Object} loginRequest will consist of username, ldapPass, ldap, and ldapOptions
Accounts.registerLoginHandler('ldap', function (loginRequest) {
    // If 'ldap' isn't set in loginRequest object,
    // then this isn't the proper handler (return undefined)
    if (!loginRequest.ldap) {
        return undefined;
    }

    // Instantiate LDAP with options
    var userOptions = loginRequest.ldapOptions || {};
    var ldapObj = new LDAP(userOptions);

    // Call ldapCheck and get response
    var ldapResponse = ldapObj.ldapCheck(loginRequest);

    if (ldapResponse.error) {
        return {
            userId: null,
            error: ldapResponse.error
        };
    }
    else if (ldapResponse.emptySearch) {
        return {
            userId: null,
            error: new Meteor.Error(403, 'User not found in LDAP')
        };
    }
    else {
        // Set initial userId and token vals
        var userId = null;
        var stampedToken = {
            token: null
        };

        // Look to see if user already exists
        var user = Meteor.users.findOne({
            username: ldapResponse.username
        });

        // Login user if they exist
        if (user) {
            userId = user._id;

            // Create hashed token so user stays logged in
            stampedToken = Accounts._generateStampedLoginToken();
            var hashStampedToken = Accounts._hashStampedToken(stampedToken);
            // Update the user's token in mongo
            Meteor.users.update(userId, {
                $push: {
                    'services.resume.loginTokens': hashStampedToken
                }
            });
        }
        // Otherwise create user if option is set
        else if (ldapObj.options.createNewUser) {
            var userObject = {
                username: ldapResponse.username
            };
            // Set email
            if (ldapResponse.email) userObject.email = ldapResponse.email;

            // Set profile values if specified in searchResultsProfileMap
            if (ldapResponse.searchResults && ldapObj.options.searchResultsProfileMap.length > 0) {

                var profileMap = ldapObj.options.searchResultsProfileMap;
                var profileObject = {};

                // Loop through profileMap and set values on profile object
                for (var i = 0; i < profileMap.length; i++) {
                    var resultKey = profileMap[i].resultKey;

                    // If our search results have the specified property, set the profile property to its value
                    if (ldapResponse.searchResults.hasOwnProperty(resultKey)) {
                        profileObject[profileMap[i].profileProperty] = ldapResponse.searchResults[resultKey];
                    }

                }
                // Set userObject profile
                userObject.profile = profileObject;
            }

            userId = Accounts.createUser(userObject);
        } else {
            // Ldap success, but no user created
            console.log('LDAP Authentication succeeded for ' + ldapResponse.username + ', but no user exists in Meteor. Either create the user manually or set LDAP_DEFAULTS.createNewUser to true');
            return {
                userId: null,
                error: new Meteor.Error(403, 'User found in LDAP but not in application')
            };
        }

        return {
            userId: userId,
            token: stampedToken.token
        };
    }

});
<|endoftext|>