<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 * @author zz85 / http://joshuakoo.com/
 */

THREE.SVGLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.SVGLoader.prototype = {

	constructor: THREE.SVGLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var loader = new THREE.FileLoader( scope.manager );
		loader.load( url, function ( text ) {

			onLoad( scope.parse( text ) );

		}, onProgress, onError );

	},

	parse: function ( text ) {

		function parseNodes( nodes ) {

			for ( var i = 0; i < nodes.length; i ++ ) {

				parseNode( nodes[ i ] );

			}

		}

		function parseNode( node ) {

			if ( node.nodeType !== 1 ) return;

			switch ( node.nodeName ) {

				case 'svg':
					break;

				case 'g':
					break;

				case 'path':
					paths.push( parsePathNode( node ) );
					break;

				case 'rect':
					paths.push( parseRectNode( node ) );
					break;

				default:
					console.log( node );

			}

			parseNodes( node.childNodes );

		}

		function parsePathNode( node ) {

			var path = new THREE.ShapePath();
			var point = new THREE.Vector2();
			var control = new THREE.Vector2();

			var d = node.getAttribute( 'd' );

			// console.log( d );

			var commands = d.match( /[a-df-z][^a-df-z]*/ig );

			for ( var i = 0; i < commands.length; i ++ ) {

				var command = commands[ i ];

				var type = command.charAt( 0 );
				var data = command.substr( 1 );

				switch ( type ) {

					case 'M':
						var numbers = parseFloats( data );
						point.fromArray( numbers );
						control.x = point.x;
						control.y = point.y;
						path.moveTo( point.x, point.y );
						break;

					case 'H':
						var numbers = parseFloats( data );
						point.x = numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'V':
						var numbers = parseFloats( data );
						point.y = numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'L':
						var numbers = parseFloats( data );
						point.x = numbers[ 0 ];
						point.y = numbers[ 1 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'C':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							numbers[ 0 ],
							numbers[ 1 ],
							numbers[ 2 ],
							numbers[ 3 ],
							numbers[ 4 ],
							numbers[ 5 ],
						);
						control.x = numbers[ 2 ];
						control.y = numbers[ 3 ];
						point.x = numbers[ 4 ];
						point.y = numbers[ 5 ];
						break;

					case 'S':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							getReflection( point.x, control.x ),
							getReflection( point.y, control.y ),
							numbers[ 0 ],
							numbers[ 1 ],
							numbers[ 2 ],
							numbers[ 3 ]
						);
						control.x = numbers[ 0 ];
						control.y = numbers[ 1 ];
						point.x = numbers[ 2 ];
						point.y = numbers[ 3 ];
						break;

					case 'Q':
						var numbers = parseFloats( data );
						path.quadraticCurveTo(
							numbers[ 0 ],
							numbers[ 1 ],
							numbers[ 2 ],
							numbers[ 3 ]
						);
						control.x = numbers[ 0 ];
						control.y = numbers[ 1 ];
						point.x = numbers[ 2 ];
						point.y = numbers[ 3 ];
						break;

					case 'T':
						var numbers = parseFloats( data );
						var rx = getReflection( point.x, control.x );
						var ry = getReflection( point.y, control.y );
						path.quadraticCurveTo(
							rx,
							ry,
							numbers[ 0 ],
							numbers[ 1 ]
						);
						control.x = rx;
						control.y = ry;
						point.x = numbers[ 0 ];
						point.y = numbers[ 1 ];
						break;

					case 'A':
						// TODO:
						break;

					case 'm':
						var numbers = parseFloats( data );
						point.x += numbers[ 0 ];
						point.y += numbers[ 1 ];
						control.x = point.x;
						control.y = point.y;
						path.moveTo( point.x, point.y );
						break;

					case 'h':
						var numbers = parseFloats( data );
						point.x += numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'v':
						var numbers = parseFloats( data );
						point.y += numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'l':
						var numbers = parseFloats( data );
						point.x += numbers[ 0 ];
						point.y += numbers[ 1 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'c':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ],
							point.x + numbers[ 2 ],
							point.y + numbers[ 3 ],
							point.x + numbers[ 4 ],
							point.y + numbers[ 5 ],
						);
						point.x += numbers[ 4 ];
						point.y += numbers[ 5 ];
						break;

					case 's':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							// TODO: Not sure if point needs
							// to be added to reflection...
							getReflection( point.x, control.x ),
							getReflection( point.y, control.y ),
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ],
							point.x + numbers[ 2 ],
							point.y + numbers[ 3 ]
						);
						control.x = point.x + numbers[ 0 ];
						control.y = point.y + numbers[ 1 ];
						point.x += numbers[ 2 ];
						point.y += numbers[ 3 ];
						break;

					case 'q':
						var numbers = parseFloats( data );
						path.quadraticCurveTo(
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ],
							point.x + numbers[ 2 ],
							point.y + numbers[ 3 ]
						);
						control.x = point.x + numbers[ 0 ];
						control.y = point.y + numbers[ 1 ];
						point.x += numbers[ 2 ];
						point.y += numbers[ 3 ];
						break;

					case 't':
						var numbers = parseFloats( data );
						var rx = getReflection( point.x, control.x );
						var ry = getReflection( point.y, control.y );
						path.quadraticCurveTo(
							rx,
							ry,
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ]
						);
						control.x = rx;
						control.y = ry;
						point.x = point.x + numbers[ 0 ];
						point.y = point.y + numbers[ 1 ];
						break;

					case 'a':
						// TODO:
						break;

					case 'Z':
					case 'z':
						path.currentPath.autoClose = true;
						break;

					default:
						console.log( command );

				}

			}

			return path;

		}

		function parseRectNode( node ) {

			var x = parseFloat( node.getAttribute( 'x' ) );
			var y = parseFloat( node.getAttribute( 'y' ) );
			var w = parseFloat( node.getAttribute( 'width' ) );
			var h = parseFloat( node.getAttribute( 'height' ) );

			var path = new THREE.ShapePath();
			path.moveTo( x, y );
			path.lineTo( x + w, y );
			path.lineTo( x + w, y + h );
			path.lineTo( x, y + h );
			return path;

		}

		// http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes

		function getReflection( a, b ) {

			return 2 * a - ( b - a );

		}

		function parseFloats( string ) {

			var array = string.split( /[\s,]+|(?=\s?[+\-])/ );

			for ( var i = 0; i < array.length; i ++ ) {

				array[ i ] = parseFloat( array[ i ] );

			}

			return array;

		}

		//

		var xml = new DOMParser().parseFromString( text, 'image/svg+xml' ); // application/xml

		var svg = xml.documentElement;

		var paths = [];<commit_msg>added polygon and polyline nodes<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 * @author zz85 / http://joshuakoo.com/
 */

THREE.SVGLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.SVGLoader.prototype = {

	constructor: THREE.SVGLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var loader = new THREE.FileLoader( scope.manager );
		loader.load( url, function ( text ) {

			onLoad( scope.parse( text ) );

		}, onProgress, onError );

	},

	parse: function ( text ) {

		function parseNodes( nodes ) {

			for ( var i = 0; i < nodes.length; i ++ ) {

				parseNode( nodes[ i ] );

			}

		}

		function parseNode( node ) {

			if ( node.nodeType !== 1 ) return;

			switch ( node.nodeName ) {

				case 'svg':
					break;

				case 'g':
					break;

				case 'path':
					paths.push( parsePathNode( node ) );
					break;

				case 'rect':
					paths.push( parseRectNode( node ) );
					break;

				case 'polygon':
					paths.push( parsePolygonNode( node ) );
					break;

				case 'polyline':
					paths.push( parsePolylineNode( node ) );
					break;

				default:
					console.log( node );

			}

			parseNodes( node.childNodes );

		}

		function parsePathNode( node ) {

			var path = new THREE.ShapePath();
			var point = new THREE.Vector2();
			var control = new THREE.Vector2();

			var d = node.getAttribute( 'd' );

			// console.log( d );

			var commands = d.match( /[a-df-z][^a-df-z]*/ig );

			for ( var i = 0; i < commands.length; i ++ ) {

				var command = commands[ i ];

				var type = command.charAt( 0 );
				var data = command.substr( 1 );

				switch ( type ) {

					case 'M':
						var numbers = parseFloats( data );
						point.fromArray( numbers );
						control.x = point.x;
						control.y = point.y;
						path.moveTo( point.x, point.y );
						break;

					case 'H':
						var numbers = parseFloats( data );
						point.x = numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'V':
						var numbers = parseFloats( data );
						point.y = numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'L':
						var numbers = parseFloats( data );
						point.x = numbers[ 0 ];
						point.y = numbers[ 1 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'C':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							numbers[ 0 ],
							numbers[ 1 ],
							numbers[ 2 ],
							numbers[ 3 ],
							numbers[ 4 ],
							numbers[ 5 ],
						);
						control.x = numbers[ 2 ];
						control.y = numbers[ 3 ];
						point.x = numbers[ 4 ];
						point.y = numbers[ 5 ];
						break;

					case 'S':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							getReflection( point.x, control.x ),
							getReflection( point.y, control.y ),
							numbers[ 0 ],
							numbers[ 1 ],
							numbers[ 2 ],
							numbers[ 3 ]
						);
						control.x = numbers[ 0 ];
						control.y = numbers[ 1 ];
						point.x = numbers[ 2 ];
						point.y = numbers[ 3 ];
						break;

					case 'Q':
						var numbers = parseFloats( data );
						path.quadraticCurveTo(
							numbers[ 0 ],
							numbers[ 1 ],
							numbers[ 2 ],
							numbers[ 3 ]
						);
						control.x = numbers[ 0 ];
						control.y = numbers[ 1 ];
						point.x = numbers[ 2 ];
						point.y = numbers[ 3 ];
						break;

					case 'T':
						var numbers = parseFloats( data );
						var rx = getReflection( point.x, control.x );
						var ry = getReflection( point.y, control.y );
						path.quadraticCurveTo(
							rx,
							ry,
							numbers[ 0 ],
							numbers[ 1 ]
						);
						control.x = rx;
						control.y = ry;
						point.x = numbers[ 0 ];
						point.y = numbers[ 1 ];
						break;

					case 'A':
						// TODO:
						break;

					case 'm':
						var numbers = parseFloats( data );
						point.x += numbers[ 0 ];
						point.y += numbers[ 1 ];
						control.x = point.x;
						control.y = point.y;
						path.moveTo( point.x, point.y );
						break;

					case 'h':
						var numbers = parseFloats( data );
						point.x += numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'v':
						var numbers = parseFloats( data );
						point.y += numbers[ 0 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'l':
						var numbers = parseFloats( data );
						point.x += numbers[ 0 ];
						point.y += numbers[ 1 ];
						control.x = point.x;
						control.y = point.y;
						path.lineTo( point.x, point.y );
						break;

					case 'c':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ],
							point.x + numbers[ 2 ],
							point.y + numbers[ 3 ],
							point.x + numbers[ 4 ],
							point.y + numbers[ 5 ],
						);
						point.x += numbers[ 4 ];
						point.y += numbers[ 5 ];
						break;

					case 's':
						var numbers = parseFloats( data );
						path.bezierCurveTo(
							// TODO: Not sure if point needs
							// to be added to reflection...
							getReflection( point.x, control.x ),
							getReflection( point.y, control.y ),
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ],
							point.x + numbers[ 2 ],
							point.y + numbers[ 3 ]
						);
						control.x = point.x + numbers[ 0 ];
						control.y = point.y + numbers[ 1 ];
						point.x += numbers[ 2 ];
						point.y += numbers[ 3 ];
						break;

					case 'q':
						var numbers = parseFloats( data );
						path.quadraticCurveTo(
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ],
							point.x + numbers[ 2 ],
							point.y + numbers[ 3 ]
						);
						control.x = point.x + numbers[ 0 ];
						control.y = point.y + numbers[ 1 ];
						point.x += numbers[ 2 ];
						point.y += numbers[ 3 ];
						break;

					case 't':
						var numbers = parseFloats( data );
						var rx = getReflection( point.x, control.x );
						var ry = getReflection( point.y, control.y );
						path.quadraticCurveTo(
							rx,
							ry,
							point.x + numbers[ 0 ],
							point.y + numbers[ 1 ]
						);
						control.x = rx;
						control.y = ry;
						point.x = point.x + numbers[ 0 ];
						point.y = point.y + numbers[ 1 ];
						break;

					case 'a':
						// TODO:
						break;

					case 'Z':
					case 'z':
						path.currentPath.autoClose = true;
						break;

					default:
						console.log( command );

				}

			}

			return path;

		}

		function parseRectNode( node ) {

			var x = parseFloat( node.getAttribute( 'x' ) );
			var y = parseFloat( node.getAttribute( 'y' ) );
			var w = parseFloat( node.getAttribute( 'width' ) );
			var h = parseFloat( node.getAttribute( 'height' ) );

			var path = new THREE.ShapePath();
			path.moveTo( x, y );
			path.lineTo( x + w, y );
			path.lineTo( x + w, y + h );
			path.lineTo( x, y + h );
			return path;

		}

		function parsePolygonNode( node ) {

			function iterator( match, a, b ) {

				var x = parseFloat( a );
				var y = parseFloat( b );

				if ( index === 0 ) {
					path.moveTo( x, y );
				} else {
					path.lineTo( x, y );
				}

				index++;

			}

			var regex = /(-?[\d\.?]+)[,|\s](-?[\d\.?]+)/g;
			var path = new THREE.ShapePath();
			var index = 0;

			node.getAttribute( 'points' ).replace(regex, iterator);

			path.currentPath.autoClose = true;

			return path;

		}

		function parsePolylineNode( node ) {

			function iterator( match, a, b ) {

				var x = parseFloat( a );
				var y = parseFloat( b );

				if ( index === 0 ) {
					path.moveTo( x, y );
				} else {
					path.lineTo( x, y );
				}

				index++;

			}

			var regex = /(-?[\d\.?]+)[,|\s](-?[\d\.?]+)/g;
			var path = new THREE.ShapePath();
			var index = 0;

			node.getAttribute( 'points' ).replace(regex, iterator);

			path.currentPath.autoClose = false;

			return path;

		}

		// http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes

		function getReflection( a, b ) {

			return 2 * a - ( b - a );

		}

		function parseFloats( string ) {

			var array = string.split( /[\s,]+|(?=\s?[+\-])/ );

			for ( var i = 0; i < array.length; i ++ ) {

				array[ i ] = parseFloat( array[ i ] );

			}

			return array;

		}

		//

		var xml = new DOMParser().parseFromString( text, 'image/svg+xml' ); // application/xml

		var svg = xml.documentElement;

		var paths = [];
{'fraction_non_alphanumeric': 0.15153955764822502, 'fraction_numerical': 0.010408277058422651, 'mean_word_length': 1.778791530383887, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '796813', 'n_tokens_mistral': 8091, 'n_tokens_neox': 5407, 'n_words': 1446}