vendor: 4,491 bytes, lines 1-181
1/*! 2 * jQuery JavaScript Library v1.11.0 3 * http://jquery.com/ 4 * 5 * Includes Sizzle.js 6 * http://sizzlejs.com/ 7 * 8 * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors 9 * Released under the MIT license 10 * http://jquery.org/license 11 * 12 * Date: 2014-01-23T21:02Z 13 */ 14 15 16(function( global, factory ) { 17 18 if ( typeof module === "object" && typeof module.exports === "object" ) { 19 // For CommonJS and CommonJS-like environments where a proper window is present, 20 // execute the factory and get jQuery 21 // For environments that do not inherently posses a window with a document 22 // (such as Node.js), expose a jQuery-making factory as module.exports 23 // This accentuates the need for the creation of a real window 24 // e.g. var jQuery = require("jquery")(window); 25 // See ticket #14549 for more info 26 module.exports = global.document ? 27 factory( global, true ) : 28 function( w ) { 29 if ( !w.document ) { 30 throw new Error( "jQuery requires a window with a document" ); 31 } 32 return factory( w ); 33 }; 34 } else { 35 factory( global ); 36 } 37 38// Pass this if window is not defined yet 39}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 40 41// Can't do this because several apps including ASP.NET trace 42// the stack via arguments.caller.callee and Firefox dies if 43// you try to trace through "use strict" call chains. (#13335) 44// Support: Firefox 18+ 45// 46 47var deletedIds = []; 48 49var slice = deletedIds.slice; 50 51var concat = deletedIds.concat; 52 53var push = deletedIds.push; 54 55var indexOf = deletedIds.indexOf; 56 57var class2type = {}; 58 59var toString = class2type.toString; 60 61var hasOwn = class2type.hasOwnProperty; 62 63var trim = "".trim; 64 65var support = {}; 66 67 68 69var 70 version = "1.11.0", 71 72 // Define a local copy of jQuery 73 jQuery = function( selector, context ) { 74 // The jQuery object is actually just the init constructor 'enhanced' 75 // Need init if jQuery is called (just allow error to be thrown if not included) 76 return new jQuery.fn.init( selector, context ); 77 }, 78 79 // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) 80 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, 81 82 // Matches dashed string for camelizing 83 rmsPrefix = /^-ms-/, 84 rdashAlpha = /-([\da-z])/gi, 85 86 // Used by jQuery.camelCase as callback to replace() 87 fcamelCase = function( all, letter ) { 88 return letter.toUpperCase(); 89 }; 90 91jQuery.fn = jQuery.prototype = { 92 // The current version of jQuery being used 93 jquery: version, 94 95 constructor: jQuery, 96 97 // Start with an empty selector 98 selector: "", 99 100 // The default length of a jQuery object is 0 101 length: 0, 102 103 toArray: function() { 104 return slice.call( this ); 105 }, 106 107 // Get the Nth element in the matched element set OR 108 // Get the whole matched element set as a clean array 109 get: function( num ) { 110 return num != null ? 111 112 // Return a 'clean' array 113 ( num < 0 ? this[ num + this.length ] : this[ num ] ) : 114 115 // Return just the object 116 slice.call( this ); 117 }, 118 119 // Take an array of elements and push it onto the stack 120 // (returning the new matched element set) 121 pushStack: function( elems ) { 122 123 // Build a new jQuery matched element set 124 var ret = jQuery.merge( this.constructor(), elems ); 125 126 // Add the old object onto the stack (as a reference) 127 ret.prevObject = this; 128 ret.context = this.context; 129 130 // Return the newly-formed element set 131 return ret; 132 }, 133 134 // Execute a callback for every element in the matched set. 135 // (You can seed the arguments with an array of args, but this is 136 // only used internally.) 137 each: function( callback, args ) { 138 return jQuery.each( this, callback, args ); 139 }, 140 141 map: function( callback ) { 142 return this.pushStack( jQuery.map(this, function( elem, i ) { 143 return callback.call( elem, i, elem ); 144 })); 145 }, 146 147 slice: function() { 148 return this.pushStack( slice.apply( this, arguments ) ); 149 }, 150 151 first: function() { 152 return this.eq( 0 ); 153 }, 154 155 last: function() { 156 return this.eq( -1 ); 157 }, 158 159 eq: function( i ) { 160 var len = this.length, 161 j = +i + ( i < 0 ? len : 0 ); 162 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); 163 }, 164 165 end: function() { 166 return this.prevObject || this.constructor(null); 167 }, 168 169 // For internal use only. 170 // Behaves like an Array's method, not like a jQuery method. 171 push: push, 172 sort: deletedIds.sort, 173 splice: deletedIds.splice 174}; 175 176jQuery.extend = jQuery.fn.extend = function() { 177 var src, copyIsArray, copy, name, options, clone, 178 target = arguments[0] || {}, 179 i = 1, 180 length = arguments.length, 181 deep = false;
182 183 // Handle a deep copy situation 184 if ( typeof target === "boolean" ) { 185 deep = target; 186 187 // skip the boolean and the target 188 target = arguments[ i ] || {}; 189 i++; 190 } 191 192 // Handle case when target is a string or something (possible in deep copy) 193 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { 194 target = {}; 195 } 196 197 // extend jQuery itself if only one argument is passed 198 if ( i === length ) { 199 target = this; 200 i--; 201 } 202 203 for ( ; i < length; i++ ) { 204 // Only deal with non-null/undefined values 205 if ( (options = arguments[ i ]) != null ) { 206 // Extend the base object 207 for ( name in options ) { 208 src = target[ name ]; 209 copy = options[ name ]; 210 211 // Prevent never-ending loop 212 if ( target === copy ) { 213 continue; 214 } 215 216 // Recurse if we're merging plain objects or arrays 217 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { 218 if ( copyIsArray ) { 219 copyIsArray = false; 220 clone = src && jQuery.isArray(src) ? src : []; 221 222 } else { 223 clone = src && jQuery.isPlainObject(src) ? src : {}; 224 } 225 226 // Never move original objects, clone them 227 target[ name ] = jQuery.extend( deep, clone, copy ); 228 229 // Don't bring in undefined values 230 } else if ( copy !== undefined ) { 231 target[ name ] = copy; 232 } 233 } 234 } 235 } 236 237 // Return the modified object 238 return target; 239}; 240 241jQuery.extend({ 242 // Unique for each copy of jQuery on the page 243 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 244 245 // Assume jQuery is ready without the ready module 246 isReady: true, 247 248 error: function( msg ) { 249 throw new Error( msg ); 250 }, 251 252 noop: function() {}, 253 254 // See test/unit/core.js for details concerning isFunction. 255 // Since version 1.3, DOM methods and functions like alert 256 // aren't supported. They return false on IE (#2968). 257 isFunction: function( obj ) { 258 return jQuery.type(obj) === "function"; 259 }, 260 261 isArray: Array.isArray || function( obj ) { 262 return jQuery.type(obj) === "array"; 263 }, 264 265 isWindow: function( obj ) { 266 /* jshint eqeqeq: false */ 267 return obj != null && obj == obj.window; 268 }, 269 270 isNumeric: function( obj ) { 271 // parseFloat NaNs numeric-cast false positives (null|true|false|"") 272 // ...but misinterprets leading-number strings, particularly hex literals ("0x...") 273 // subtraction forces infinities to NaN 274 return obj - parseFloat( obj ) >= 0; 275 }, 276 277 isEmptyObject: function( obj ) { 278 var name; 279 for ( name in obj ) { 280 return false; 281 } 282 return true; 283 }, 284 285 isPlainObject: function( obj ) { 286 var key; 287 288 // Must be an Object. 289 // Because of IE, we also have to check the presence of the constructor property. 290 // Make sure that DOM nodes and window objects don't pass through, as well 291 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { 292 return false; 293 } 294 295 try { 296 // Not own constructor property must be Object 297 if ( obj.constructor && 298 !hasOwn.call(obj, "constructor") && 299 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { 300 return false; 301 } 302 } catch ( e ) { 303 // IE8,9 Will throw exceptions on certain host objects #9897 304 return false; 305 } 306 307 // Support: IE<9 308 // Handle iteration over inherited properties before own properties. 309 if ( support.ownLast ) { 310 for ( key in obj ) { 311 return hasOwn.call( obj, key ); 312 } 313 } 314 315 // Own properties are enumerated firstly, so to speed up, 316 // if last one is own, then all properties are own. 317 for ( key in obj ) {} 318 319 return key === undefined || hasOwn.call( obj, key ); 320 }, 321 322 type: function( obj ) { 323 if ( obj == null ) { 324 return obj + ""; 325 } 326 return typeof obj === "object" || typeof obj === "function" ? 327 class2type[ toString.call(obj) ] || "object" : 328 typeof obj; 329 }, 330 331 // Evaluates a script in a global context 332 // Workarounds based on findings by Jim Driscoll 333 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context 334 globalEval: function( data ) { 335 if ( data && jQuery.trim( data ) ) { 336 // We use execScript on Internet Explorer 337 // We use an anonymous function so that context is window 338 // rather than jQuery in Firefox 339 ( window.execScript || function( data ) { 340 window[ "eval" ].call( window, data ); 341 } )( data ); 342 } 343 }, 344 345 // Convert dashed to camelCase; used by the css and data modules 346 // Microsoft forgot to hump their vendor prefix (#9572) 347 camelCase: function( string ) { 348 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 349 }, 350
351 nodeName: function( elem, name ) { 352 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 353 }, 354 355 // args is for internal usage only 356 each: function( obj, callback, args ) { 357 var value, 358 i = 0, 359 length = obj.length, 360 isArray = isArraylike( obj ); 361 362 if ( args ) { 363 if ( isArray ) { 364 for ( ; i < length; i++ ) { 365 value = callback.apply( obj[ i ], args ); 366 367 if ( value === false ) { 368 break; 369 } 370 } 371 } else { 372 for ( i in obj ) { 373 value = callback.apply( obj[ i ], args ); 374 375 if ( value === false ) { 376 break; 377 } 378 } 379 } 380 381 // A special, fast, case for the most common use of each 382 } else { 383 if ( isArray ) { 384 for ( ; i < length; i++ ) { 385 value = callback.call( obj[ i ], i, obj[ i ] ); 386 387 if ( value === false ) { 388 break; 389 } 390 } 391 } else { 392 for ( i in obj ) { 393 value = callback.call( obj[ i ], i, obj[ i ] ); 394 395 if ( value === false ) { 396 break; 397 } 398 } 399 } 400 } 401 402 return obj; 403 }, 404 405 // Use native String.trim function wherever possible 406 trim: trim && !trim.call("\uFEFF\xA0") ? 407 function( text ) { 408 return text == null ? 409 "" : 410 trim.call( text ); 411 } : 412 413 // Otherwise use our own trimming functionality 414 function( text ) { 415 return text == null ? 416 "" : 417 ( text + "" ).replace( rtrim, "" ); 418 }, 419 420 // results is for internal usage only 421 makeArray: function( arr, results ) { 422 var ret = results || []; 423 424 if ( arr != null ) { 425 if ( isArraylike( Object(arr) ) ) { 426 jQuery.merge( ret, 427 typeof arr === "string" ? 428 [ arr ] : arr 429 ); 430 } else { 431 push.call( ret, arr ); 432 } 433 } 434 435 return ret; 436 }, 437 438 inArray: function( elem, arr, i ) { 439 var len; 440 441 if ( arr ) { 442 if ( indexOf ) { 443 return indexOf.call( arr, elem, i ); 444 } 445 446 len = arr.length; 447 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; 448 449 for ( ; i < len; i++ ) { 450 // Skip accessing in sparse arrays 451 if ( i in arr && arr[ i ] === elem ) { 452 return i; 453 } 454 } 455 } 456 457 return -1; 458 }, 459 460 merge: function( first, second ) { 461 var len = +second.length, 462 j = 0, 463 i = first.length; 464 465 while ( j < len ) { 466 first[ i++ ] = second[ j++ ]; 467 } 468 469 // Support: IE<9 470 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) 471 if ( len !== len ) { 472 while ( second[j] !== undefined ) { 473 first[ i++ ] = second[ j++ ]; 474 } 475 } 476 477 first.length = i; 478 479 return first; 480 }, 481 482 grep: function( elems, callback, invert ) { 483 var callbackInverse, 484 matches = [], 485 i = 0, 486 length = elems.length, 487 callbackExpect = !invert; 488 489 // Go through the array, only saving the items 490 // that pass the validator function 491 for ( ; i < length; i++ ) { 492 callbackInverse = !callback( elems[ i ], i ); 493 if ( callbackInverse !== callbackExpect ) { 494 matches.push( elems[ i ] ); 495 } 496 } 497 498 return matches; 499 }, 500 501 // arg is for internal usage only 502 map: function( elems, callback, arg ) { 503 var value, 504 i = 0, 505 length = elems.length, 506 isArray = isArraylike( elems ), 507 ret = []; 508 509 // Go through the array, translating each of the items to their new values 510 if ( isArray ) { 511 for ( ; i < length; i++ ) { 512 value = callback( elems[ i ], i, arg ); 513 514 if ( value != null ) { 515 ret.push( value ); 516 } 517 } 518 519 // Go through every key on the object, 520 } else { 521 for ( i in elems ) { 522 value = callback( elems[ i ], i, arg ); 523 524 if ( value != null ) { 525 ret.push( value ); 526 } 527 } 528 } 529 530 // Flatten any nested arrays 531 return concat.apply( [], ret ); 532 }, 533 534 // A global GUID counter for objects 535 guid: 1, 536 537 // Bind a function to a context, optionally partially applying any 538 // arguments. 539 proxy: function( fn, context ) { 540 var args, proxy, tmp; 541 542 if ( typeof context === "string" ) { 543 tmp = fn[ context ]; 544 context = fn; 545 fn = tmp; 546 } 547 548 // Quick check to determine if target is callable, in the spec 549 // this throws a TypeError, but we will just return undefined. 550 if ( !jQuery.isFunction( fn ) ) { 551 return undefined; 552 } 553 554 // Simulated bind 555 args = slice.call( arguments, 2 ); 556 proxy = function() { 557 return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); 558 }; 559 560 // Set the guid of unique handler to the same of original handler, so it can be removed 561 proxy.guid = fn.guid = fn.guid || jQuery.guid++; 562 563 return proxy; 564 }, 565 566 now: function() { 567 return +( new Date() ); 568 }, 569 570 // jQuery.support is not used in Core but other projects attach their 571 // properties to it so it needs to exist. 572 support: support 573}); 574 575// Populate the class2type map 576jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { 577 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 578}); 579 580function isArraylike( obj ) { 581 var length = obj.length, 582 type = jQuery.type( obj ); 583 584 if ( type === "function" || jQuery.isWindow( obj ) ) { 585 return false;
586 } 587 588 if ( obj.nodeType === 1 && length ) { 589 return true; 590 } 591 592 return type === "array" || length === 0 || 593 typeof length === "number" && length > 0 && ( length - 1 ) in obj; 594} 595var Sizzle = 596/*! 597 * Sizzle CSS Selector Engine v1.10.16 598 * http://sizzlejs.com/ 599 * 600 * Copyright 2013 jQuery Foundation, Inc. and other contributors 601 * Released under the MIT license 602 * http://jquery.org/license 603 * 604 * Date: 2014-01-13 605 */ 606(function( window ) { 607 608var i, 609 support, 610 Expr, 611 getText, 612 isXML, 613 compile, 614 outermostContext, 615 sortInput, 616 hasDuplicate, 617 618 // Local document vars 619 setDocument, 620 document, 621 docElem, 622 documentIsHTML, 623 rbuggyQSA, 624 rbuggyMatches, 625 matches, 626 contains, 627 628 // Instance-specific data 629 expando = "sizzle" + -(new Date()), 630 preferredDoc = window.document, 631 dirruns = 0, 632 done = 0, 633 classCache = createCache(), 634 tokenCache = createCache(), 635 compilerCache = createCache(), 636 sortOrder = function( a, b ) { 637 if ( a === b ) { 638 hasDuplicate = true; 639 } 640 return 0; 641 }, 642 643 // General-purpose constants 644 strundefined = typeof undefined, 645 MAX_NEGATIVE = 1 << 31, 646 647 // Instance methods 648 hasOwn = ({}).hasOwnProperty, 649 arr = [], 650 pop = arr.pop, 651 push_native = arr.push, 652 push = arr.push, 653 slice = arr.slice, 654 // Use a stripped-down indexOf if we can't use a native one 655 indexOf = arr.indexOf || function( elem ) { 656 var i = 0, 657 len = this.length; 658 for ( ; i < len; i++ ) { 659 if ( this[i] === elem ) { 660 return i; 661 } 662 } 663 return -1; 664 }, 665 666 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", 667 668 // Regular expressions 669 670 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace 671 whitespace = "[\\x20\\t\\r\\n\\f]", 672 // http://www.w3.org/TR/css3-syntax/#characters 673 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", 674 675 // Loosely modeled on CSS identifier characters 676 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors 677 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier 678 identifier = characterEncoding.replace( "w", "w#" ), 679 680 // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors 681 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + 682 "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", 683 684 // Prefer arguments quoted, 685 // then not containing pseudos/brackets, 686 // then attribute selectors/non-parenthetical expressions, 687 // then anything else 688 // These preferences are here to reduce the number of selectors 689 // needing tokenize in the PSEUDO preFilter 690 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", 691 692 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter 693 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), 694 695 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), 696 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), 697 698 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), 699 700 rpseudo = new RegExp( pseudos ), 701 ridentifier = new RegExp( "^" + identifier + "$" ), 702 703 matchExpr = { 704 "ID": new RegExp( "^#(" + characterEncoding + ")" ), 705 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), 706 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), 707 "ATTR": new RegExp( "^" + attributes ), 708 "PSEUDO": new RegExp( "^" + pseudos ), 709 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + 710 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + 711 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), 712 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), 713 // For use in libraries implementing .is() 714 // We use this for POS matching in `select` 715 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + 716 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) 717 }, 718
719 rinputs = /^(?:input|select|textarea|button)$/i, 720 rheader = /^h\d$/i, 721 722 rnative = /^[^{]+\{\s*\[native \w/, 723 724 // Easily-parseable/retrievable ID or TAG or CLASS selectors 725 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, 726 727 rsibling = /[+~]/, 728 rescape = /'|\\/g, 729 730 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters 731 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), 732 funescape = function( _, escaped, escapedWhitespace ) { 733 var high = "0x" + escaped - 0x10000; 734 // NaN means non-codepoint 735 // Support: Firefox 736 // Workaround erroneous numeric interpretation of +"0x" 737 return high !== high || escapedWhitespace ? 738 escaped : 739 high < 0 ? 740 // BMP codepoint 741 String.fromCharCode( high + 0x10000 ) : 742 // Supplemental Plane codepoint (surrogate pair) 743 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); 744 }; 745 746// Optimize for push.apply( _, NodeList ) 747try { 748 push.apply( 749 (arr = slice.call( preferredDoc.childNodes )), 750 preferredDoc.childNodes 751 ); 752 // Support: Android<4.0 753 // Detect silently failing push.apply 754 arr[ preferredDoc.childNodes.length ].nodeType; 755} catch ( e ) { 756 push = { apply: arr.length ? 757 758 // Leverage slice if possible 759 function( target, els ) { 760 push_native.apply( target, slice.call(els) ); 761 } : 762 763 // Support: IE<9 764 // Otherwise append directly 765 function( target, els ) { 766 var j = target.length, 767 i = 0; 768 // Can't trust NodeList.length 769 while ( (target[j++] = els[i++]) ) {} 770 target.length = j - 1; 771 } 772 }; 773} 774 775function Sizzle( selector, context, results, seed ) { 776 var match, elem, m, nodeType, 777 // QSA vars 778 i, groups, old, nid, newContext, newSelector; 779 780 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { 781 setDocument( context ); 782 } 783 784 context = context || document; 785 results = results || []; 786 787 if ( !selector || typeof selector !== "string" ) { 788 return results; 789 } 790 791 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { 792 return []; 793 } 794 795 if ( documentIsHTML && !seed ) { 796 797 // Shortcuts 798 if ( (match = rquickExpr.exec( selector )) ) { 799 // Speed-up: Sizzle("#ID") 800 if ( (m = match[1]) ) { 801 if ( nodeType === 9 ) { 802 elem = context.getElementById( m ); 803 // Check parentNode to catch when Blackberry 4.6 returns 804 // nodes that are no longer in the document (jQuery #6963) 805 if ( elem && elem.parentNode ) { 806 // Handle the case where IE, Opera, and Webkit return items 807 // by name instead of ID 808 if ( elem.id === m ) { 809 results.push( elem ); 810 return results; 811 } 812 } else { 813 return results; 814 } 815 } else { 816 // Context is not a document 817 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && 818 contains( context, elem ) && elem.id === m ) { 819 results.push( elem ); 820 return results; 821 } 822 } 823 824 // Speed-up: Sizzle("TAG") 825 } else if ( match[2] ) { 826 push.apply( results, context.getElementsByTagName( selector ) ); 827 return results; 828 829 // Speed-up: Sizzle(".CLASS") 830 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { 831 push.apply( results, context.getElementsByClassName( m ) ); 832 return results; 833 } 834 } 835 836 // QSA path 837 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { 838 nid = old = expando; 839 newContext = context; 840 newSelector = nodeType === 9 && selector; 841 842 // qSA works strangely on Element-rooted queries 843 // We can work around this by specifying an extra ID on the root 844 // and working up from there (Thanks to Andrew Dupont for the technique) 845 // IE 8 doesn't work on object elements 846 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { 847 groups = tokenize( selector ); 848 849 if ( (old = context.getAttribute("id")) ) { 850 nid = old.replace( rescape, "\\$&" ); 851 } else { 852 context.setAttribute( "id", nid ); 853 } 854 nid = "[id='" + nid + "'] "; 855 856 i = groups.length; 857 while ( i-- ) { 858 groups[i] = nid + toSelector( groups[i] ); 859 }
vendor: 4,490 bytes, lines 860-1042
860 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; 861 newSelector = groups.join(","); 862 } 863 864 if ( newSelector ) { 865 try { 866 push.apply( results, 867 newContext.querySelectorAll( newSelector ) 868 ); 869 return results; 870 } catch(qsaError) { 871 } finally { 872 if ( !old ) { 873 context.removeAttribute("id"); 874 } 875 } 876 } 877 } 878 } 879 880 // All others 881 return select( selector.replace( rtrim, "$1" ), context, results, seed ); 882} 883 884/** 885 * Create key-value caches of limited size 886 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with 887 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) 888 * deleting the oldest entry 889 */ 890function createCache() { 891 var keys = []; 892 893 function cache( key, value ) { 894 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) 895 if ( keys.push( key + " " ) > Expr.cacheLength ) { 896 // Only keep the most recent entries 897 delete cache[ keys.shift() ]; 898 } 899 return (cache[ key + " " ] = value); 900 } 901 return cache; 902} 903 904/** 905 * Mark a function for special use by Sizzle 906 * @param {Function} fn The function to mark 907 */ 908function markFunction( fn ) { 909 fn[ expando ] = true; 910 return fn; 911} 912 913/** 914 * Support testing using an element 915 * @param {Function} fn Passed the created div and expects a boolean result 916 */ 917function assert( fn ) { 918 var div = document.createElement("div"); 919 920 try { 921 return !!fn( div ); 922 } catch (e) { 923 return false; 924 } finally { 925 // Remove from its parent by default 926 if ( div.parentNode ) { 927 div.parentNode.removeChild( div ); 928 } 929 // release memory in IE 930 div = null; 931 } 932} 933 934/** 935 * Adds the same handler for all of the specified attrs 936 * @param {String} attrs Pipe-separated list of attributes 937 * @param {Function} handler The method that will be applied 938 */ 939function addHandle( attrs, handler ) { 940 var arr = attrs.split("|"), 941 i = attrs.length; 942 943 while ( i-- ) { 944 Expr.attrHandle[ arr[i] ] = handler; 945 } 946} 947 948/** 949 * Checks document order of two siblings 950 * @param {Element} a 951 * @param {Element} b 952 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b 953 */ 954function siblingCheck( a, b ) { 955 var cur = b && a, 956 diff = cur && a.nodeType === 1 && b.nodeType === 1 && 957 ( ~b.sourceIndex || MAX_NEGATIVE ) - 958 ( ~a.sourceIndex || MAX_NEGATIVE ); 959 960 // Use IE sourceIndex if available on both nodes 961 if ( diff ) { 962 return diff; 963 } 964 965 // Check if b follows a 966 if ( cur ) { 967 while ( (cur = cur.nextSibling) ) { 968 if ( cur === b ) { 969 return -1; 970 } 971 } 972 } 973 974 return a ? 1 : -1; 975} 976 977/** 978 * Returns a function to use in pseudos for input types 979 * @param {String} type 980 */ 981function createInputPseudo( type ) { 982 return function( elem ) { 983 var name = elem.nodeName.toLowerCase(); 984 return name === "input" && elem.type === type; 985 }; 986} 987 988/** 989 * Returns a function to use in pseudos for buttons 990 * @param {String} type 991 */ 992function createButtonPseudo( type ) { 993 return function( elem ) { 994 var name = elem.nodeName.toLowerCase(); 995 return (name === "input" || name === "button") && elem.type === type; 996 }; 997} 998 999/** 1000 * Returns a function to use in pseudos for positionals 1001 * @param {Function} fn 1002 */ 1003function createPositionalPseudo( fn ) { 1004 return markFunction(function( argument ) { 1005 argument = +argument; 1006 return markFunction(function( seed, matches ) { 1007 var j, 1008 matchIndexes = fn( [], seed.length, argument ), 1009 i = matchIndexes.length; 1010 1011 // Match elements found at the specified indexes 1012 while ( i-- ) { 1013 if ( seed[ (j = matchIndexes[i]) ] ) { 1014 seed[j] = !(matches[j] = seed[j]); 1015 } 1016 } 1017 }); 1018 }); 1019} 1020 1021/** 1022 * Checks a node for validity as a Sizzle context 1023 * @param {Element|Object=} context 1024 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value 1025 */ 1026function testContext( context ) { 1027 return context && typeof context.getElementsByTagName !== strundefined && context; 1028} 1029 1030// Expose support vars for convenience 1031support = Sizzle.support = {}; 1032 1033/** 1034 * Detects XML nodes 1035 * @param {Element|Object} elem An element or a document 1036 * @returns {Boolean} True iff elem is a non-HTML XML node 1037 */ 1038isXML = Sizzle.isXML = function( elem ) { 1039 // documentElement is verified for cases where it doesn't yet exist 1040 // (such as loading iframes in IE - #4833) 1041 var documentElement = elem && (elem.ownerDocument || elem).documentElement; 1042 return documentElement ? documentElement.nodeName !== "HTML" : false;
1043}; 1044 1045/** 1046 * Sets document-related variables once based on the current document 1047 * @param {Element|Object} [doc] An element or document object to use to set the document 1048 * @returns {Object} Returns the current document 1049 */ 1050setDocument = Sizzle.setDocument = function( node ) { 1051 var hasCompare, 1052 doc = node ? node.ownerDocument || node : preferredDoc, 1053 parent = doc.defaultView; 1054 1055 // If no document and documentElement is available, return 1056 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { 1057 return document; 1058 } 1059 1060 // Set our document 1061 document = doc; 1062 docElem = doc.documentElement; 1063 1064 // Support tests 1065 documentIsHTML = !isXML( doc ); 1066 1067 // Support: IE>8 1068 // If iframe document is assigned to "document" variable and if iframe has been reloaded, 1069 // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 1070 // IE6-8 do not support the defaultView property so parent will be undefined 1071 if ( parent && parent !== parent.top ) { 1072 // IE11 does not have attachEvent, so all must suffer 1073 if ( parent.addEventListener ) { 1074 parent.addEventListener( "unload", function() { 1075 setDocument(); 1076 }, false ); 1077 } else if ( parent.attachEvent ) { 1078 parent.attachEvent( "onunload", function() { 1079 setDocument(); 1080 }); 1081 } 1082 } 1083 1084 /* Attributes 1085 ---------------------------------------------------------------------- */ 1086 1087 // Support: IE<8 1088 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) 1089 support.attributes = assert(function( div ) { 1090 div.className = "i"; 1091 return !div.getAttribute("className"); 1092 }); 1093 1094 /* getElement(s)By* 1095 ---------------------------------------------------------------------- */ 1096 1097 // Check if getElementsByTagName("*") returns only elements 1098 support.getElementsByTagName = assert(function( div ) { 1099 div.appendChild( doc.createComment("") ); 1100 return !div.getElementsByTagName("*").length; 1101 }); 1102 1103 // Check if getElementsByClassName can be trusted 1104 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { 1105 div.innerHTML = "<div class='a'></div><div class='a i'></div>"; 1106 1107 // Support: Safari<4 1108 // Catch class over-caching 1109 div.firstChild.className = "i"; 1110 // Support: Opera<10 1111 // Catch gEBCN failure to find non-leading classes 1112 return div.getElementsByClassName("i").length === 2; 1113 }); 1114 1115 // Support: IE<10 1116 // Check if getElementById returns elements by name 1117 // The broken getElementById methods don't pick up programatically-set names, 1118 // so use a roundabout getElementsByName test 1119 support.getById = assert(function( div ) { 1120 docElem.appendChild( div ).id = expando; 1121 return !doc.getElementsByName || !doc.getElementsByName( expando ).length; 1122 }); 1123 1124 // ID find and filter 1125 if ( support.getById ) { 1126 Expr.find["ID"] = function( id, context ) { 1127 if ( typeof context.getElementById !== strundefined && documentIsHTML ) { 1128 var m = context.getElementById( id ); 1129 // Check parentNode to catch when Blackberry 4.6 returns 1130 // nodes that are no longer in the document #6963 1131 return m && m.parentNode ? [m] : []; 1132 } 1133 }; 1134 Expr.filter["ID"] = function( id ) { 1135 var attrId = id.replace( runescape, funescape ); 1136 return function( elem ) { 1137 return elem.getAttribute("id") === attrId; 1138 }; 1139 }; 1140 } else {
vendor: 42,934 bytes, lines 1141-2674
1141 // Support: IE6/7 1142 // getElementById is not reliable as a find shortcut 1143 delete Expr.find["ID"]; 1144 1145 Expr.filter["ID"] = function( id ) { 1146 var attrId = id.replace( runescape, funescape ); 1147 return function( elem ) { 1148 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); 1149 return node && node.value === attrId; 1150 }; 1151 }; 1152 } 1153 1154 // Tag 1155 Expr.find["TAG"] = support.getElementsByTagName ? 1156 function( tag, context ) { 1157 if ( typeof context.getElementsByTagName !== strundefined ) { 1158 return context.getElementsByTagName( tag ); 1159 } 1160 } : 1161 function( tag, context ) { 1162 var elem, 1163 tmp = [], 1164 i = 0, 1165 results = context.getElementsByTagName( tag ); 1166 1167 // Filter out possible comments 1168 if ( tag === "*" ) { 1169 while ( (elem = results[i++]) ) { 1170 if ( elem.nodeType === 1 ) { 1171 tmp.push( elem ); 1172 } 1173 } 1174 1175 return tmp; 1176 } 1177 return results; 1178 }; 1179 1180 // Class 1181 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { 1182 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { 1183 return context.getElementsByClassName( className ); 1184 } 1185 }; 1186 1187 /* QSA/matchesSelector 1188 ---------------------------------------------------------------------- */ 1189 1190 // QSA and matchesSelector support 1191 1192 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) 1193 rbuggyMatches = []; 1194 1195 // qSa(:focus) reports false when true (Chrome 21) 1196 // We allow this because of a bug in IE8/9 that throws an error 1197 // whenever `document.activeElement` is accessed on an iframe 1198 // So, we allow :focus to pass through QSA all the time to avoid the IE error 1199 // See http://bugs.jquery.com/ticket/13378 1200 rbuggyQSA = []; 1201 1202 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { 1203 // Build QSA regex 1204 // Regex strategy adopted from Diego Perini 1205 assert(function( div ) { 1206 // Select is set to empty string on purpose 1207 // This is to test IE's treatment of not explicitly 1208 // setting a boolean content attribute, 1209 // since its presence should be enough 1210 // http://bugs.jquery.com/ticket/12359 1211 div.innerHTML = "<select t=''><option selected=''></option></select>"; 1212 1213 // Support: IE8, Opera 10-12 1214 // Nothing should be selected when empty strings follow ^= or $= or *= 1215 if ( div.querySelectorAll("[t^='']").length ) { 1216 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); 1217 } 1218 1219 // Support: IE8 1220 // Boolean attributes and "value" are not treated correctly 1221 if ( !div.querySelectorAll("[selected]").length ) { 1222 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); 1223 } 1224 1225 // Webkit/Opera - :checked should return selected option elements 1226 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1227 // IE8 throws error here and will not see later tests 1228 if ( !div.querySelectorAll(":checked").length ) { 1229 rbuggyQSA.push(":checked"); 1230 } 1231 }); 1232 1233 assert(function( div ) { 1234 // Support: Windows 8 Native Apps 1235 // The type and name attributes are restricted during .innerHTML assignment 1236 var input = doc.createElement("input"); 1237 input.setAttribute( "type", "hidden" ); 1238 div.appendChild( input ).setAttribute( "name", "D" ); 1239 1240 // Support: IE8 1241 // Enforce case-sensitivity of name attribute 1242 if ( div.querySelectorAll("[name=d]").length ) { 1243 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); 1244 } 1245 1246 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) 1247 // IE8 throws error here and will not see later tests 1248 if ( !div.querySelectorAll(":enabled").length ) { 1249 rbuggyQSA.push( ":enabled", ":disabled" ); 1250 } 1251 1252 // Opera 10-11 does not throw on post-comma invalid pseudos 1253 div.querySelectorAll("*,:x"); 1254 rbuggyQSA.push(",.*:"); 1255 }); 1256 } 1257 1258 if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || 1259 docElem.mozMatchesSelector || 1260 docElem.oMatchesSelector || 1261 docElem.msMatchesSelector) )) ) { 1262 1263 assert(function( div ) { 1264 // Check to see if it's possible to do matchesSelector 1265 // on a disconnected node (IE 9) 1266 support.disconnectedMatch = matches.call( div, "div" ); 1267 1268 // This should fail with an exception 1269 // Gecko does not error, returns false instead 1270 matches.call( div, "[s!='']:x" ); 1271 rbuggyMatches.push( "!=", pseudos ); 1272 }); 1273 } 1274 1275 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); 1276 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); 1277 1278 /* Contains 1279 ---------------------------------------------------------------------- */ 1280 hasCompare = rnative.test( docElem.compareDocumentPosition ); 1281 1282 // Element contains another 1283 // Purposefully does not implement inclusive descendent 1284 // As in, an element does not contain itself 1285 contains = hasCompare || rnative.test( docElem.contains ) ? 1286 function( a, b ) { 1287 var adown = a.nodeType === 9 ? a.documentElement : a, 1288 bup = b && b.parentNode; 1289 return a === bup || !!( bup && bup.nodeType === 1 && ( 1290 adown.contains ? 1291 adown.contains( bup ) : 1292 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 1293 )); 1294 } : 1295 function( a, b ) { 1296 if ( b ) { 1297 while ( (b = b.parentNode) ) { 1298 if ( b === a ) { 1299 return true; 1300 } 1301 } 1302 } 1303 return false; 1304 }; 1305 1306 /* Sorting 1307 ---------------------------------------------------------------------- */ 1308 1309 // Document order sorting 1310 sortOrder = hasCompare ? 1311 function( a, b ) { 1312 1313 // Flag for duplicate removal 1314 if ( a === b ) { 1315 hasDuplicate = true; 1316 return 0; 1317 } 1318 1319 // Sort on method existence if only one input has compareDocumentPosition 1320 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; 1321 if ( compare ) { 1322 return compare; 1323 } 1324 1325 // Calculate position if both inputs belong to the same document 1326 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? 1327 a.compareDocumentPosition( b ) : 1328 1329 // Otherwise we know they are disconnected 1330 1; 1331 1332 // Disconnected nodes 1333 if ( compare & 1 || 1334 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { 1335 1336 // Choose the first element that is related to our preferred document 1337 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { 1338 return -1; 1339 } 1340 if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { 1341 return 1; 1342 } 1343 1344 // Maintain original order 1345 return sortInput ? 1346 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 1347 0; 1348 } 1349 1350 return compare & 4 ? -1 : 1; 1351 } : 1352 function( a, b ) { 1353 // Exit early if the nodes are identical 1354 if ( a === b ) { 1355 hasDuplicate = true; 1356 return 0; 1357 } 1358 1359 var cur, 1360 i = 0, 1361 aup = a.parentNode, 1362 bup = b.parentNode, 1363 ap = [ a ], 1364 bp = [ b ]; 1365 1366 // Parentless nodes are either documents or disconnected 1367 if ( !aup || !bup ) { 1368 return a === doc ? -1 : 1369 b === doc ? 1 : 1370 aup ? -1 : 1371 bup ? 1 : 1372 sortInput ? 1373 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : 1374 0; 1375 1376 // If the nodes are siblings, we can do a quick check 1377 } else if ( aup === bup ) { 1378 return siblingCheck( a, b ); 1379 } 1380 1381 // Otherwise we need full lists of their ancestors for comparison 1382 cur = a; 1383 while ( (cur = cur.parentNode) ) { 1384 ap.unshift( cur ); 1385 } 1386 cur = b; 1387 while ( (cur = cur.parentNode) ) { 1388 bp.unshift( cur ); 1389 } 1390 1391 // Walk down the tree looking for a discrepancy 1392 while ( ap[i] === bp[i] ) { 1393 i++; 1394 } 1395 1396 return i ? 1397 // Do a sibling check if the nodes have a common ancestor 1398 siblingCheck( ap[i], bp[i] ) : 1399 1400 // Otherwise nodes in our document sort first 1401 ap[i] === preferredDoc ? -1 : 1402 bp[i] === preferredDoc ? 1 : 1403 0; 1404 }; 1405 1406 return doc; 1407}; 1408 1409Sizzle.matches = function( expr, elements ) { 1410 return Sizzle( expr, null, null, elements ); 1411}; 1412 1413Sizzle.matchesSelector = function( elem, expr ) { 1414 // Set document vars if needed 1415 if ( ( elem.ownerDocument || elem ) !== document ) { 1416 setDocument( elem ); 1417 } 1418 1419 // Make sure that attribute selectors are quoted 1420 expr = expr.replace( rattributeQuotes, "='$1']" ); 1421 1422 if ( support.matchesSelector && documentIsHTML && 1423 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 1424 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 1425 1426 try { 1427 var ret = matches.call( elem, expr ); 1428 1429 // IE 9's matchesSelector returns false on disconnected nodes 1430 if ( ret || support.disconnectedMatch || 1431 // As well, disconnected nodes are said to be in a document 1432 // fragment in IE 9 1433 elem.document && elem.document.nodeType !== 11 ) { 1434 return ret; 1435 } 1436 } catch(e) {} 1437 } 1438 1439 return Sizzle( expr, document, null, [elem] ).length > 0; 1440}; 1441 1442Sizzle.contains = function( context, elem ) { 1443 // Set document vars if needed 1444 if ( ( context.ownerDocument || context ) !== document ) { 1445 setDocument( context ); 1446 } 1447 return contains( context, elem ); 1448}; 1449 1450Sizzle.attr = function( elem, name ) { 1451 // Set document vars if needed 1452 if ( ( elem.ownerDocument || elem ) !== document ) { 1453 setDocument( elem ); 1454 } 1455 1456 var fn = Expr.attrHandle[ name.toLowerCase() ], 1457 // Don't get fooled by Object.prototype properties (jQuery #13807) 1458 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 1459 fn( elem, name, !documentIsHTML ) : 1460 undefined; 1461 1462 return val !== undefined ? 1463 val : 1464 support.attributes || !documentIsHTML ? 1465 elem.getAttribute( name ) : 1466 (val = elem.getAttributeNode(name)) && val.specified ? 1467 val.value : 1468 null; 1469}; 1470 1471Sizzle.error = function( msg ) { 1472 throw new Error( "Syntax error, unrecognized expression: " + msg ); 1473}; 1474 1475/** 1476 * Document sorting and removing duplicates 1477 * @param {ArrayLike} results 1478 */ 1479Sizzle.uniqueSort = function( results ) { 1480 var elem, 1481 duplicates = [], 1482 j = 0, 1483 i = 0; 1484 1485 // Unless we *know* we can detect duplicates, assume their presence 1486 hasDuplicate = !support.detectDuplicates; 1487 sortInput = !support.sortStable && results.slice( 0 ); 1488 results.sort( sortOrder ); 1489 1490 if ( hasDuplicate ) { 1491 while ( (elem = results[i++]) ) { 1492 if ( elem === results[ i ] ) { 1493 j = duplicates.push( i ); 1494 } 1495 } 1496 while ( j-- ) { 1497 results.splice( duplicates[ j ], 1 ); 1498 } 1499 } 1500 1501 // Clear input after sorting to release objects 1502 // See https://github.com/jquery/sizzle/pull/225 1503 sortInput = null; 1504 1505 return results; 1506}; 1507 1508/** 1509 * Utility function for retrieving the text value of an array of DOM nodes 1510 * @param {Array|Element} elem 1511 */ 1512getText = Sizzle.getText = function( elem ) { 1513 var node, 1514 ret = "", 1515 i = 0, 1516 nodeType = elem.nodeType; 1517 1518 if ( !nodeType ) { 1519 // If no nodeType, this is expected to be an array 1520 while ( (node = elem[i++]) ) { 1521 // Do not traverse comment nodes 1522 ret += getText( node ); 1523 } 1524 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 1525 // Use textContent for elements 1526 // innerText usage removed for consistency of new lines (jQuery #11153) 1527 if ( typeof elem.textContent === "string" ) { 1528 return elem.textContent; 1529 } else { 1530 // Traverse its children 1531 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 1532 ret += getText( elem ); 1533 } 1534 } 1535 } else if ( nodeType === 3 || nodeType === 4 ) { 1536 return elem.nodeValue; 1537 } 1538 // Do not include comment or processing instruction nodes 1539 1540 return ret; 1541}; 1542 1543Expr = Sizzle.selectors = { 1544 1545 // Can be adjusted by the user 1546 cacheLength: 50, 1547 1548 createPseudo: markFunction, 1549 1550 match: matchExpr, 1551 1552 attrHandle: {}, 1553 1554 find: {}, 1555 1556 relative: { 1557 ">": { dir: "parentNode", first: true }, 1558 " ": { dir: "parentNode" }, 1559 "+": { dir: "previousSibling", first: true }, 1560 "~": { dir: "previousSibling" } 1561 }, 1562 1563 preFilter: { 1564 "ATTR": function( match ) { 1565 match[1] = match[1].replace( runescape, funescape ); 1566 1567 // Move the given value to match[3] whether quoted or unquoted 1568 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); 1569 1570 if ( match[2] === "~=" ) { 1571 match[3] = " " + match[3] + " "; 1572 } 1573 1574 return match.slice( 0, 4 ); 1575 }, 1576 1577 "CHILD": function( match ) { 1578 /* matches from matchExpr["CHILD"] 1579 1 type (only|nth|...) 1580 2 what (child|of-type) 1581 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 1582 4 xn-component of xn+y argument ([+-]?\d*n|) 1583 5 sign of xn-component 1584 6 x of xn-component 1585 7 sign of y-component 1586 8 y of y-component 1587 */ 1588 match[1] = match[1].toLowerCase(); 1589 1590 if ( match[1].slice( 0, 3 ) === "nth" ) { 1591 // nth-* requires argument 1592 if ( !match[3] ) { 1593 Sizzle.error( match[0] ); 1594 } 1595 1596 // numeric x and y parameters for Expr.filter.CHILD 1597 // remember that false/true cast respectively to 0/1 1598 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); 1599 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); 1600 1601 // other types prohibit arguments 1602 } else if ( match[3] ) { 1603 Sizzle.error( match[0] ); 1604 } 1605 1606 return match; 1607 }, 1608 1609 "PSEUDO": function( match ) { 1610 var excess, 1611 unquoted = !match[5] && match[2]; 1612 1613 if ( matchExpr["CHILD"].test( match[0] ) ) { 1614 return null; 1615 } 1616 1617 // Accept quoted arguments as-is 1618 if ( match[3] && match[4] !== undefined ) { 1619 match[2] = match[4]; 1620 1621 // Strip excess characters from unquoted arguments 1622 } else if ( unquoted && rpseudo.test( unquoted ) && 1623 // Get excess from tokenize (recursively) 1624 (excess = tokenize( unquoted, true )) && 1625 // advance to the next closing parenthesis 1626 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { 1627 1628 // excess is a negative index 1629 match[0] = match[0].slice( 0, excess ); 1630 match[2] = unquoted.slice( 0, excess ); 1631 } 1632 1633 // Return only captures needed by the pseudo filter method (type and argument) 1634 return match.slice( 0, 3 ); 1635 } 1636 }, 1637 1638 filter: { 1639 1640 "TAG": function( nodeNameSelector ) { 1641 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); 1642 return nodeNameSelector === "*" ? 1643 function() { return true; } : 1644 function( elem ) { 1645 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; 1646 }; 1647 }, 1648 1649 "CLASS": function( className ) { 1650 var pattern = classCache[ className + " " ]; 1651 1652 return pattern || 1653 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && 1654 classCache( className, function( elem ) { 1655 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); 1656 }); 1657 }, 1658 1659 "ATTR": function( name, operator, check ) { 1660 return function( elem ) { 1661 var result = Sizzle.attr( elem, name ); 1662 1663 if ( result == null ) { 1664 return operator === "!="; 1665 } 1666 if ( !operator ) { 1667 return true; 1668 } 1669 1670 result += ""; 1671 1672 return operator === "=" ? result === check : 1673 operator === "!=" ? result !== check : 1674 operator === "^=" ? check && result.indexOf( check ) === 0 : 1675 operator === "*=" ? check && result.indexOf( check ) > -1 : 1676 operator === "$=" ? check && result.slice( -check.length ) === check : 1677 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : 1678 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : 1679 false; 1680 }; 1681 }, 1682 1683 "CHILD": function( type, what, argument, first, last ) { 1684 var simple = type.slice( 0, 3 ) !== "nth", 1685 forward = type.slice( -4 ) !== "last", 1686 ofType = what === "of-type"; 1687 1688 return first === 1 && last === 0 ? 1689 1690 // Shortcut for :nth-*(n) 1691 function( elem ) { 1692 return !!elem.parentNode; 1693 } : 1694 1695 function( elem, context, xml ) { 1696 var cache, outerCache, node, diff, nodeIndex, start, 1697 dir = simple !== forward ? "nextSibling" : "previousSibling", 1698 parent = elem.parentNode, 1699 name = ofType && elem.nodeName.toLowerCase(), 1700 useCache = !xml && !ofType; 1701 1702 if ( parent ) { 1703 1704 // :(first|last|only)-(child|of-type) 1705 if ( simple ) { 1706 while ( dir ) { 1707 node = elem; 1708 while ( (node = node[ dir ]) ) { 1709 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { 1710 return false; 1711 } 1712 } 1713 // Reverse direction for :only-* (if we haven't yet done so) 1714 start = dir = type === "only" && !start && "nextSibling"; 1715 } 1716 return true; 1717 } 1718 1719 start = [ forward ? parent.firstChild : parent.lastChild ]; 1720 1721 // non-xml :nth-child(...) stores cache data on `parent` 1722 if ( forward && useCache ) { 1723 // Seek `elem` from a previously-cached index 1724 outerCache = parent[ expando ] || (parent[ expando ] = {}); 1725 cache = outerCache[ type ] || []; 1726 nodeIndex = cache[0] === dirruns && cache[1]; 1727 diff = cache[0] === dirruns && cache[2]; 1728 node = nodeIndex && parent.childNodes[ nodeIndex ]; 1729 1730 while ( (node = ++nodeIndex && node && node[ dir ] || 1731 1732 // Fallback to seeking `elem` from the start 1733 (diff = nodeIndex = 0) || start.pop()) ) { 1734 1735 // When found, cache indexes on `parent` and break 1736 if ( node.nodeType === 1 && ++diff && node === elem ) { 1737 outerCache[ type ] = [ dirruns, nodeIndex, diff ]; 1738 break; 1739 } 1740 } 1741 1742 // Use previously-cached element index if available 1743 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { 1744 diff = cache[1]; 1745 1746 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) 1747 } else { 1748 // Use the same loop as above to seek `elem` from the start 1749 while ( (node = ++nodeIndex && node && node[ dir ] || 1750 (diff = nodeIndex = 0) || start.pop()) ) { 1751 1752 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { 1753 // Cache the index of each encountered element 1754 if ( useCache ) { 1755 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; 1756 } 1757 1758 if ( node === elem ) { 1759 break; 1760 } 1761 } 1762 } 1763 } 1764 1765 // Incorporate the offset, then check against cycle size 1766 diff -= last; 1767 return diff === first || ( diff % first === 0 && diff / first >= 0 ); 1768 } 1769 }; 1770 }, 1771 1772 "PSEUDO": function( pseudo, argument ) { 1773 // pseudo-class names are case-insensitive 1774 // http://www.w3.org/TR/selectors/#pseudo-classes 1775 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters 1776 // Remember that setFilters inherits from pseudos 1777 var args, 1778 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || 1779 Sizzle.error( "unsupported pseudo: " + pseudo ); 1780 1781 // The user may use createPseudo to indicate that 1782 // arguments are needed to create the filter function 1783 // just as Sizzle does 1784 if ( fn[ expando ] ) { 1785 return fn( argument ); 1786 } 1787 1788 // But maintain support for old signatures 1789 if ( fn.length > 1 ) { 1790 args = [ pseudo, pseudo, "", argument ]; 1791 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? 1792 markFunction(function( seed, matches ) { 1793 var idx, 1794 matched = fn( seed, argument ), 1795 i = matched.length; 1796 while ( i-- ) { 1797 idx = indexOf.call( seed, matched[i] ); 1798 seed[ idx ] = !( matches[ idx ] = matched[i] ); 1799 } 1800 }) : 1801 function( elem ) { 1802 return fn( elem, 0, args ); 1803 }; 1804 } 1805 1806 return fn; 1807 } 1808 }, 1809 1810 pseudos: { 1811 // Potentially complex pseudos 1812 "not": markFunction(function( selector ) { 1813 // Trim the selector passed to compile 1814 // to avoid treating leading and trailing 1815 // spaces as combinators 1816 var input = [], 1817 results = [], 1818 matcher = compile( selector.replace( rtrim, "$1" ) ); 1819 1820 return matcher[ expando ] ? 1821 markFunction(function( seed, matches, context, xml ) { 1822 var elem, 1823 unmatched = matcher( seed, null, xml, [] ), 1824 i = seed.length; 1825 1826 // Match elements unmatched by `matcher` 1827 while ( i-- ) { 1828 if ( (elem = unmatched[i]) ) { 1829 seed[i] = !(matches[i] = elem); 1830 } 1831 } 1832 }) : 1833 function( elem, context, xml ) { 1834 input[0] = elem; 1835 matcher( input, null, xml, results ); 1836 return !results.pop(); 1837 }; 1838 }), 1839 1840 "has": markFunction(function( selector ) { 1841 return function( elem ) { 1842 return Sizzle( selector, elem ).length > 0; 1843 }; 1844 }), 1845 1846 "contains": markFunction(function( text ) { 1847 return function( elem ) { 1848 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; 1849 }; 1850 }), 1851 1852 // "Whether an element is represented by a :lang() selector 1853 // is based solely on the element's language value 1854 // being equal to the identifier C, 1855 // or beginning with the identifier C immediately followed by "-". 1856 // The matching of C against the element's language value is performed case-insensitively. 1857 // The identifier C does not have to be a valid language name." 1858 // http://www.w3.org/TR/selectors/#lang-pseudo 1859 "lang": markFunction( function( lang ) { 1860 // lang value must be a valid identifier 1861 if ( !ridentifier.test(lang || "") ) { 1862 Sizzle.error( "unsupported lang: " + lang ); 1863 } 1864 lang = lang.replace( runescape, funescape ).toLowerCase(); 1865 return function( elem ) { 1866 var elemLang; 1867 do { 1868 if ( (elemLang = documentIsHTML ? 1869 elem.lang : 1870 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { 1871 1872 elemLang = elemLang.toLowerCase(); 1873 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; 1874 } 1875 } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); 1876 return false; 1877 }; 1878 }), 1879 1880 // Miscellaneous 1881 "target": function( elem ) { 1882 var hash = window.location && window.location.hash; 1883 return hash && hash.slice( 1 ) === elem.id; 1884 }, 1885 1886 "root": function( elem ) { 1887 return elem === docElem; 1888 }, 1889 1890 "focus": function( elem ) { 1891 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); 1892 }, 1893 1894 // Boolean properties 1895 "enabled": function( elem ) { 1896 return elem.disabled === false; 1897 }, 1898 1899 "disabled": function( elem ) { 1900 return elem.disabled === true; 1901 }, 1902 1903 "checked": function( elem ) { 1904 // In CSS3, :checked should return both checked and selected elements 1905 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1906 var nodeName = elem.nodeName.toLowerCase(); 1907 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); 1908 }, 1909 1910 "selected": function( elem ) { 1911 // Accessing this property makes selected-by-default 1912 // options in Safari work properly 1913 if ( elem.parentNode ) { 1914 elem.parentNode.selectedIndex; 1915 } 1916 1917 return elem.selected === true; 1918 }, 1919 1920 // Contents 1921 "empty": function( elem ) { 1922 // http://www.w3.org/TR/selectors/#empty-pseudo 1923 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), 1924 // but not by others (comment: 8; processing instruction: 7; etc.) 1925 // nodeType < 6 works because attributes (2) do not appear as children 1926 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 1927 if ( elem.nodeType < 6 ) { 1928 return false; 1929 } 1930 } 1931 return true; 1932 }, 1933 1934 "parent": function( elem ) { 1935 return !Expr.pseudos["empty"]( elem ); 1936 }, 1937 1938 // Element/input types 1939 "header": function( elem ) { 1940 return rheader.test( elem.nodeName ); 1941 }, 1942 1943 "input": function( elem ) { 1944 return rinputs.test( elem.nodeName ); 1945 }, 1946 1947 "button": function( elem ) { 1948 var name = elem.nodeName.toLowerCase(); 1949 return name === "input" && elem.type === "button" || name === "button"; 1950 }, 1951 1952 "text": function( elem ) { 1953 var attr; 1954 return elem.nodeName.toLowerCase() === "input" && 1955 elem.type === "text" && 1956 1957 // Support: IE<8 1958 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" 1959 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); 1960 }, 1961 1962 // Position-in-collection 1963 "first": createPositionalPseudo(function() { 1964 return [ 0 ]; 1965 }), 1966 1967 "last": createPositionalPseudo(function( matchIndexes, length ) { 1968 return [ length - 1 ]; 1969 }), 1970 1971 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { 1972 return [ argument < 0 ? argument + length : argument ]; 1973 }), 1974 1975 "even": createPositionalPseudo(function( matchIndexes, length ) { 1976 var i = 0; 1977 for ( ; i < length; i += 2 ) { 1978 matchIndexes.push( i ); 1979 } 1980 return matchIndexes; 1981 }), 1982 1983 "odd": createPositionalPseudo(function( matchIndexes, length ) { 1984 var i = 1; 1985 for ( ; i < length; i += 2 ) { 1986 matchIndexes.push( i ); 1987 } 1988 return matchIndexes; 1989 }), 1990 1991 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { 1992 var i = argument < 0 ? argument + length : argument; 1993 for ( ; --i >= 0; ) { 1994 matchIndexes.push( i ); 1995 } 1996 return matchIndexes; 1997 }), 1998 1999 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2000 var i = argument < 0 ? argument + length : argument; 2001 for ( ; ++i < length; ) { 2002 matchIndexes.push( i ); 2003 } 2004 return matchIndexes; 2005 }) 2006 } 2007}; 2008 2009Expr.pseudos["nth"] = Expr.pseudos["eq"]; 2010 2011// Add button/input type pseudos 2012for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { 2013 Expr.pseudos[ i ] = createInputPseudo( i ); 2014} 2015for ( i in { submit: true, reset: true } ) { 2016 Expr.pseudos[ i ] = createButtonPseudo( i ); 2017} 2018 2019// Easy API for creating new setFilters 2020function setFilters() {} 2021setFilters.prototype = Expr.filters = Expr.pseudos; 2022Expr.setFilters = new setFilters(); 2023 2024function tokenize( selector, parseOnly ) { 2025 var matched, match, tokens, type, 2026 soFar, groups, preFilters, 2027 cached = tokenCache[ selector + " " ]; 2028 2029 if ( cached ) { 2030 return parseOnly ? 0 : cached.slice( 0 ); 2031 } 2032 2033 soFar = selector; 2034 groups = []; 2035 preFilters = Expr.preFilter; 2036 2037 while ( soFar ) { 2038 2039 // Comma and first run 2040 if ( !matched || (match = rcomma.exec( soFar )) ) { 2041 if ( match ) { 2042 // Don't consume trailing commas as valid 2043 soFar = soFar.slice( match[0].length ) || soFar; 2044 } 2045 groups.push( (tokens = []) ); 2046 } 2047 2048 matched = false; 2049 2050 // Combinators 2051 if ( (match = rcombinators.exec( soFar )) ) { 2052 matched = match.shift(); 2053 tokens.push({ 2054 value: matched, 2055 // Cast descendant combinators to space 2056 type: match[0].replace( rtrim, " " ) 2057 }); 2058 soFar = soFar.slice( matched.length ); 2059 } 2060 2061 // Filters 2062 for ( type in Expr.filter ) { 2063 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || 2064 (match = preFilters[ type ]( match ))) ) { 2065 matched = match.shift(); 2066 tokens.push({ 2067 value: matched, 2068 type: type, 2069 matches: match 2070 }); 2071 soFar = soFar.slice( matched.length ); 2072 } 2073 } 2074 2075 if ( !matched ) { 2076 break; 2077 } 2078 } 2079 2080 // Return the length of the invalid excess 2081 // if we're just parsing 2082 // Otherwise, throw an error or return tokens 2083 return parseOnly ? 2084 soFar.length : 2085 soFar ? 2086 Sizzle.error( selector ) : 2087 // Cache the tokens 2088 tokenCache( selector, groups ).slice( 0 ); 2089} 2090 2091function toSelector( tokens ) { 2092 var i = 0, 2093 len = tokens.length, 2094 selector = ""; 2095 for ( ; i < len; i++ ) { 2096 selector += tokens[i].value; 2097 } 2098 return selector; 2099} 2100 2101function addCombinator( matcher, combinator, base ) { 2102 var dir = combinator.dir, 2103 checkNonElements = base && dir === "parentNode", 2104 doneName = done++; 2105 2106 return combinator.first ? 2107 // Check against closest ancestor/preceding element 2108 function( elem, context, xml ) { 2109 while ( (elem = elem[ dir ]) ) { 2110 if ( elem.nodeType === 1 || checkNonElements ) { 2111 return matcher( elem, context, xml ); 2112 } 2113 } 2114 } : 2115 2116 // Check against all ancestor/preceding elements 2117 function( elem, context, xml ) { 2118 var oldCache, outerCache, 2119 newCache = [ dirruns, doneName ]; 2120 2121 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching 2122 if ( xml ) { 2123 while ( (elem = elem[ dir ]) ) { 2124 if ( elem.nodeType === 1 || checkNonElements ) { 2125 if ( matcher( elem, context, xml ) ) { 2126 return true; 2127 } 2128 } 2129 } 2130 } else { 2131 while ( (elem = elem[ dir ]) ) { 2132 if ( elem.nodeType === 1 || checkNonElements ) { 2133 outerCache = elem[ expando ] || (elem[ expando ] = {}); 2134 if ( (oldCache = outerCache[ dir ]) && 2135 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { 2136 2137 // Assign to newCache so results back-propagate to previous elements 2138 return (newCache[ 2 ] = oldCache[ 2 ]); 2139 } else { 2140 // Reuse newcache so results back-propagate to previous elements 2141 outerCache[ dir ] = newCache; 2142 2143 // A match means we're done; a fail means we have to keep checking 2144 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { 2145 return true; 2146 } 2147 } 2148 } 2149 } 2150 } 2151 }; 2152} 2153 2154function elementMatcher( matchers ) { 2155 return matchers.length > 1 ? 2156 function( elem, context, xml ) { 2157 var i = matchers.length; 2158 while ( i-- ) { 2159 if ( !matchers[i]( elem, context, xml ) ) { 2160 return false; 2161 } 2162 } 2163 return true; 2164 } : 2165 matchers[0]; 2166} 2167 2168function condense( unmatched, map, filter, context, xml ) { 2169 var elem, 2170 newUnmatched = [], 2171 i = 0, 2172 len = unmatched.length, 2173 mapped = map != null; 2174 2175 for ( ; i < len; i++ ) { 2176 if ( (elem = unmatched[i]) ) { 2177 if ( !filter || filter( elem, context, xml ) ) { 2178 newUnmatched.push( elem ); 2179 if ( mapped ) { 2180 map.push( i ); 2181 } 2182 } 2183 } 2184 } 2185 2186 return newUnmatched; 2187} 2188 2189function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { 2190 if ( postFilter && !postFilter[ expando ] ) { 2191 postFilter = setMatcher( postFilter ); 2192 } 2193 if ( postFinder && !postFinder[ expando ] ) { 2194 postFinder = setMatcher( postFinder, postSelector ); 2195 } 2196 return markFunction(function( seed, results, context, xml ) { 2197 var temp, i, elem, 2198 preMap = [], 2199 postMap = [], 2200 preexisting = results.length, 2201 2202 // Get initial elements from seed or context 2203 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), 2204 2205 // Prefilter to get matcher input, preserving a map for seed-results synchronization 2206 matcherIn = preFilter && ( seed || !selector ) ? 2207 condense( elems, preMap, preFilter, context, xml ) : 2208 elems, 2209 2210 matcherOut = matcher ? 2211 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, 2212 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? 2213 2214 // ...intermediate processing is necessary 2215 [] : 2216 2217 // ...otherwise use results directly 2218 results : 2219 matcherIn; 2220 2221 // Find primary matches 2222 if ( matcher ) { 2223 matcher( matcherIn, matcherOut, context, xml ); 2224 } 2225 2226 // Apply postFilter 2227 if ( postFilter ) { 2228 temp = condense( matcherOut, postMap ); 2229 postFilter( temp, [], context, xml ); 2230 2231 // Un-match failing elements by moving them back to matcherIn 2232 i = temp.length; 2233 while ( i-- ) { 2234 if ( (elem = temp[i]) ) { 2235 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); 2236 } 2237 } 2238 } 2239 2240 if ( seed ) { 2241 if ( postFinder || preFilter ) { 2242 if ( postFinder ) { 2243 // Get the final matcherOut by condensing this intermediate into postFinder contexts 2244 temp = []; 2245 i = matcherOut.length; 2246 while ( i-- ) { 2247 if ( (elem = matcherOut[i]) ) { 2248 // Restore matcherIn since elem is not yet a final match 2249 temp.push( (matcherIn[i] = elem) ); 2250 } 2251 } 2252 postFinder( null, (matcherOut = []), temp, xml ); 2253 } 2254 2255 // Move matched elements from seed to results to keep them synchronized 2256 i = matcherOut.length; 2257 while ( i-- ) { 2258 if ( (elem = matcherOut[i]) && 2259 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { 2260 2261 seed[temp] = !(results[temp] = elem); 2262 } 2263 } 2264 } 2265 2266 // Add elements to results, through postFinder if defined 2267 } else { 2268 matcherOut = condense( 2269 matcherOut === results ? 2270 matcherOut.splice( preexisting, matcherOut.length ) : 2271 matcherOut 2272 ); 2273 if ( postFinder ) { 2274 postFinder( null, results, matcherOut, xml ); 2275 } else { 2276 push.apply( results, matcherOut ); 2277 } 2278 } 2279 }); 2280} 2281 2282function matcherFromTokens( tokens ) { 2283 var checkContext, matcher, j, 2284 len = tokens.length, 2285 leadingRelative = Expr.relative[ tokens[0].type ], 2286 implicitRelative = leadingRelative || Expr.relative[" "], 2287 i = leadingRelative ? 1 : 0, 2288 2289 // The foundational matcher ensures that elements are reachable from top-level context(s) 2290 matchContext = addCombinator( function( elem ) { 2291 return elem === checkContext; 2292 }, implicitRelative, true ), 2293 matchAnyContext = addCombinator( function( elem ) { 2294 return indexOf.call( checkContext, elem ) > -1; 2295 }, implicitRelative, true ), 2296 matchers = [ function( elem, context, xml ) { 2297 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( 2298 (checkContext = context).nodeType ? 2299 matchContext( elem, context, xml ) : 2300 matchAnyContext( elem, context, xml ) ); 2301 } ]; 2302 2303 for ( ; i < len; i++ ) { 2304 if ( (matcher = Expr.relative[ tokens[i].type ]) ) { 2305 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; 2306 } else { 2307 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); 2308 2309 // Return special upon seeing a positional matcher 2310 if ( matcher[ expando ] ) { 2311 // Find the next relative operator (if any) for proper handling 2312 j = ++i; 2313 for ( ; j < len; j++ ) { 2314 if ( Expr.relative[ tokens[j].type ] ) { 2315 break; 2316 } 2317 } 2318 return setMatcher( 2319 i > 1 && elementMatcher( matchers ), 2320 i > 1 && toSelector( 2321 // If the preceding token was a descendant combinator, insert an implicit any-element `*` 2322 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) 2323 ).replace( rtrim, "$1" ), 2324 matcher, 2325 i < j && matcherFromTokens( tokens.slice( i, j ) ), 2326 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), 2327 j < len && toSelector( tokens ) 2328 ); 2329 } 2330 matchers.push( matcher ); 2331 } 2332 } 2333 2334 return elementMatcher( matchers ); 2335} 2336 2337function matcherFromGroupMatchers( elementMatchers, setMatchers ) { 2338 var bySet = setMatchers.length > 0, 2339 byElement = elementMatchers.length > 0, 2340 superMatcher = function( seed, context, xml, results, outermost ) { 2341 var elem, j, matcher, 2342 matchedCount = 0, 2343 i = "0", 2344 unmatched = seed && [], 2345 setMatched = [], 2346 contextBackup = outermostContext, 2347 // We must always have either seed elements or outermost context 2348 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), 2349 // Use integer dirruns iff this is the outermost matcher 2350 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), 2351 len = elems.length; 2352 2353 if ( outermost ) { 2354 outermostContext = context !== document && context; 2355 } 2356 2357 // Add elements passing elementMatchers directly to results 2358 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below 2359 // Support: IE<9, Safari 2360 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id 2361 for ( ; i !== len && (elem = elems[i]) != null; i++ ) { 2362 if ( byElement && elem ) { 2363 j = 0; 2364 while ( (matcher = elementMatchers[j++]) ) { 2365 if ( matcher( elem, context, xml ) ) { 2366 results.push( elem ); 2367 break; 2368 } 2369 } 2370 if ( outermost ) { 2371 dirruns = dirrunsUnique; 2372 } 2373 } 2374 2375 // Track unmatched elements for set filters 2376 if ( bySet ) { 2377 // They will have gone through all possible matchers 2378 if ( (elem = !matcher && elem) ) { 2379 matchedCount--; 2380 } 2381 2382 // Lengthen the array for every element, matched or not 2383 if ( seed ) { 2384 unmatched.push( elem ); 2385 } 2386 } 2387 } 2388 2389 // Apply set filters to unmatched elements 2390 matchedCount += i; 2391 if ( bySet && i !== matchedCount ) { 2392 j = 0; 2393 while ( (matcher = setMatchers[j++]) ) { 2394 matcher( unmatched, setMatched, context, xml ); 2395 } 2396 2397 if ( seed ) { 2398 // Reintegrate element matches to eliminate the need for sorting 2399 if ( matchedCount > 0 ) { 2400 while ( i-- ) { 2401 if ( !(unmatched[i] || setMatched[i]) ) { 2402 setMatched[i] = pop.call( results ); 2403 } 2404 } 2405 } 2406 2407 // Discard index placeholder values to get only actual matches 2408 setMatched = condense( setMatched ); 2409 } 2410 2411 // Add matches to results 2412 push.apply( results, setMatched ); 2413 2414 // Seedless set matches succeeding multiple successful matchers stipulate sorting 2415 if ( outermost && !seed && setMatched.length > 0 && 2416 ( matchedCount + setMatchers.length ) > 1 ) { 2417 2418 Sizzle.uniqueSort( results ); 2419 } 2420 } 2421 2422 // Override manipulation of globals by nested matchers 2423 if ( outermost ) { 2424 dirruns = dirrunsUnique; 2425 outermostContext = contextBackup; 2426 } 2427 2428 return unmatched; 2429 }; 2430 2431 return bySet ? 2432 markFunction( superMatcher ) : 2433 superMatcher; 2434} 2435 2436compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { 2437 var i, 2438 setMatchers = [], 2439 elementMatchers = [], 2440 cached = compilerCache[ selector + " " ]; 2441 2442 if ( !cached ) { 2443 // Generate a function of recursive functions that can be used to check each element 2444 if ( !group ) { 2445 group = tokenize( selector ); 2446 } 2447 i = group.length; 2448 while ( i-- ) { 2449 cached = matcherFromTokens( group[i] ); 2450 if ( cached[ expando ] ) { 2451 setMatchers.push( cached ); 2452 } else { 2453 elementMatchers.push( cached ); 2454 } 2455 } 2456 2457 // Cache the compiled function 2458 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); 2459 } 2460 return cached; 2461}; 2462 2463function multipleContexts( selector, contexts, results ) { 2464 var i = 0, 2465 len = contexts.length; 2466 for ( ; i < len; i++ ) { 2467 Sizzle( selector, contexts[i], results ); 2468 } 2469 return results; 2470} 2471 2472function select( selector, context, results, seed ) { 2473 var i, tokens, token, type, find, 2474 match = tokenize( selector ); 2475 2476 if ( !seed ) { 2477 // Try to minimize operations if there is only one group 2478 if ( match.length === 1 ) { 2479 2480 // Take a shortcut and set the context if the root selector is an ID 2481 tokens = match[0] = match[0].slice( 0 ); 2482 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && 2483 support.getById && context.nodeType === 9 && documentIsHTML && 2484 Expr.relative[ tokens[1].type ] ) { 2485 2486 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; 2487 if ( !context ) { 2488 return results; 2489 } 2490 selector = selector.slice( tokens.shift().value.length ); 2491 } 2492 2493 // Fetch a seed set for right-to-left matching 2494 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; 2495 while ( i-- ) { 2496 token = tokens[i]; 2497 2498 // Abort if we hit a combinator 2499 if ( Expr.relative[ (type = token.type) ] ) { 2500 break; 2501 } 2502 if ( (find = Expr.find[ type ]) ) { 2503 // Search, expanding context for leading sibling combinators 2504 if ( (seed = find( 2505 token.matches[0].replace( runescape, funescape ), 2506 rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context 2507 )) ) { 2508 2509 // If seed is empty or no tokens remain, we can return early 2510 tokens.splice( i, 1 ); 2511 selector = seed.length && toSelector( tokens ); 2512 if ( !selector ) { 2513 push.apply( results, seed ); 2514 return results; 2515 } 2516 2517 break; 2518 } 2519 } 2520 } 2521 } 2522 } 2523 2524 // Compile and execute a filtering function 2525 // Provide `match` to avoid retokenization if we modified the selector above 2526 compile( selector, match )( 2527 seed, 2528 context, 2529 !documentIsHTML, 2530 results, 2531 rsibling.test( selector ) && testContext( context.parentNode ) || context 2532 ); 2533 return results; 2534} 2535 2536// One-time assignments 2537 2538// Sort stability 2539support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; 2540 2541// Support: Chrome<14 2542// Always assume duplicates if they aren't passed to the comparison function 2543support.detectDuplicates = !!hasDuplicate; 2544 2545// Initialize against the default document 2546setDocument(); 2547 2548// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) 2549// Detached nodes confoundingly follow *each other* 2550support.sortDetached = assert(function( div1 ) { 2551 // Should return 1, but returns 4 (following) 2552 return div1.compareDocumentPosition( document.createElement("div") ) & 1; 2553}); 2554 2555// Support: IE<8 2556// Prevent attribute/property "interpolation" 2557// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 2558if ( !assert(function( div ) { 2559 div.innerHTML = "<a href='#'></a>"; 2560 return div.firstChild.getAttribute("href") === "#" ; 2561}) ) { 2562 addHandle( "type|href|height|width", function( elem, name, isXML ) { 2563 if ( !isXML ) { 2564 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); 2565 } 2566 }); 2567} 2568 2569// Support: IE<9 2570// Use defaultValue in place of getAttribute("value") 2571if ( !support.attributes || !assert(function( div ) { 2572 div.innerHTML = "<input/>"; 2573 div.firstChild.setAttribute( "value", "" ); 2574 return div.firstChild.getAttribute( "value" ) === ""; 2575}) ) { 2576 addHandle( "value", function( elem, name, isXML ) { 2577 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { 2578 return elem.defaultValue; 2579 } 2580 }); 2581} 2582 2583// Support: IE<9 2584// Use getAttributeNode to fetch booleans when getAttribute lies 2585if ( !assert(function( div ) { 2586 return div.getAttribute("disabled") == null; 2587}) ) { 2588 addHandle( booleans, function( elem, name, isXML ) { 2589 var val; 2590 if ( !isXML ) { 2591 return elem[ name ] === true ? name.toLowerCase() : 2592 (val = elem.getAttributeNode( name )) && val.specified ? 2593 val.value : 2594 null; 2595 } 2596 }); 2597} 2598 2599return Sizzle; 2600 2601})( window ); 2602 2603 2604 2605jQuery.find = Sizzle; 2606jQuery.expr = Sizzle.selectors; 2607jQuery.expr[":"] = jQuery.expr.pseudos; 2608jQuery.unique = Sizzle.uniqueSort; 2609jQuery.text = Sizzle.getText; 2610jQuery.isXMLDoc = Sizzle.isXML; 2611jQuery.contains = Sizzle.contains; 2612 2613 2614 2615var rneedsContext = jQuery.expr.match.needsContext; 2616 2617var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); 2618 2619 2620 2621var risSimple = /^.[^:#\[\.,]*$/; 2622 2623// Implement the identical functionality for filter and not 2624function winnow( elements, qualifier, not ) { 2625 if ( jQuery.isFunction( qualifier ) ) { 2626 return jQuery.grep( elements, function( elem, i ) { 2627 /* jshint -W018 */ 2628 return !!qualifier.call( elem, i, elem ) !== not; 2629 }); 2630 2631 } 2632 2633 if ( qualifier.nodeType ) { 2634 return jQuery.grep( elements, function( elem ) { 2635 return ( elem === qualifier ) !== not; 2636 }); 2637 2638 } 2639 2640 if ( typeof qualifier === "string" ) { 2641 if ( risSimple.test( qualifier ) ) { 2642 return jQuery.filter( qualifier, elements, not ); 2643 } 2644 2645 qualifier = jQuery.filter( qualifier, elements ); 2646 } 2647 2648 return jQuery.grep( elements, function( elem ) { 2649 return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; 2650 }); 2651} 2652 2653jQuery.filter = function( expr, elems, not ) { 2654 var elem = elems[ 0 ]; 2655 2656 if ( not ) { 2657 expr = ":not(" + expr + ")"; 2658 } 2659 2660 return elems.length === 1 && elem.nodeType === 1 ? 2661 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : 2662 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { 2663 return elem.nodeType === 1; 2664 })); 2665}; 2666 2667jQuery.fn.extend({ 2668 find: function( selector ) { 2669 var i, 2670 ret = [], 2671 self = this, 2672 len = self.length; 2673 2674 if ( typeof selector !== "string" ) {
2675 return this.pushStack( jQuery( selector ).filter(function() { 2676 for ( i = 0; i < len; i++ ) { 2677 if ( jQuery.contains( self[ i ], this ) ) { 2678 return true; 2679 } 2680 } 2681 }) ); 2682 } 2683 2684 for ( i = 0; i < len; i++ ) { 2685 jQuery.find( selector, self[ i ], ret ); 2686 } 2687 2688 // Needed because $( selector, context ) becomes $( context ).find( selector ) 2689 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); 2690 ret.selector = this.selector ? this.selector + " " + selector : selector; 2691 return ret; 2692 }, 2693 filter: function( selector ) { 2694 return this.pushStack( winnow(this, selector || [], false) ); 2695 }, 2696 not: function( selector ) { 2697 return this.pushStack( winnow(this, selector || [], true) ); 2698 }, 2699 is: function( selector ) { 2700 return !!winnow( 2701 this, 2702 2703 // If this is a positional/relative selector, check membership in the returned set 2704 // so $("p:first").is("p:last") won't return true for a doc with two "p". 2705 typeof selector === "string" && rneedsContext.test( selector ) ? 2706 jQuery( selector ) : 2707 selector || [], 2708 false 2709 ).length; 2710 } 2711}); 2712 2713 2714// Initialize a jQuery object 2715 2716 2717// A central reference to the root jQuery(document) 2718var rootjQuery, 2719 2720 // Use the correct document accordingly with window argument (sandbox) 2721 document = window.document, 2722 2723 // A simple way to check for HTML strings 2724 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) 2725 // Strict HTML recognition (#11290: must start with <) 2726 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, 2727 2728 init = jQuery.fn.init = function( selector, context ) { 2729 var match, elem; 2730 2731 // HANDLE: $(""), $(null), $(undefined), $(false) 2732 if ( !selector ) { 2733 return this; 2734 } 2735 2736 // Handle HTML strings 2737 if ( typeof selector === "string" ) { 2738 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { 2739 // Assume that strings that start and end with <> are HTML and skip the regex check 2740 match = [ null, selector, null ]; 2741 2742 } else { 2743 match = rquickExpr.exec( selector ); 2744 } 2745 2746 // Match html or make sure no context is specified for #id 2747 if ( match && (match[1] || !context) ) { 2748 2749 // HANDLE: $(html) -> $(array) 2750 if ( match[1] ) { 2751 context = context instanceof jQuery ? context[0] : context; 2752 2753 // scripts is true for back-compat 2754 // Intentionally let the error be thrown if parseHTML is not present 2755 jQuery.merge( this, jQuery.parseHTML( 2756 match[1], 2757 context && context.nodeType ? context.ownerDocument || context : document, 2758 true 2759 ) ); 2760 2761 // HANDLE: $(html, props) 2762 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { 2763 for ( match in context ) { 2764 // Properties of context are called as methods if possible 2765 if ( jQuery.isFunction( this[ match ] ) ) { 2766 this[ match ]( context[ match ] ); 2767 2768 // ...and otherwise set as attributes 2769 } else { 2770 this.attr( match, context[ match ] ); 2771 } 2772 } 2773 } 2774 2775 return this; 2776 2777 // HANDLE: $(#id) 2778 } else { 2779 elem = document.getElementById( match[2] ); 2780 2781 // Check parentNode to catch when Blackberry 4.6 returns 2782 // nodes that are no longer in the document #6963 2783 if ( elem && elem.parentNode ) { 2784 // Handle the case where IE and Opera return items 2785 // by name instead of ID 2786 if ( elem.id !== match[2] ) { 2787 return rootjQuery.find( selector ); 2788 } 2789 2790 // Otherwise, we inject the element directly into the jQuery object 2791 this.length = 1; 2792 this[0] = elem; 2793 } 2794 2795 this.context = document; 2796 this.selector = selector; 2797 return this; 2798 } 2799 2800 // HANDLE: $(expr, $(...)) 2801 } else if ( !context || context.jquery ) { 2802 return ( context || rootjQuery ).find( selector ); 2803 2804 // HANDLE: $(expr, context) 2805 // (which is just equivalent to: $(context).find(expr) 2806 } else { 2807 return this.constructor( context ).find( selector ); 2808 } 2809 2810 // HANDLE: $(DOMElement) 2811 } else if ( selector.nodeType ) { 2812 this.context = this[0] = selector; 2813 this.length = 1; 2814 return this; 2815 2816 // HANDLE: $(function) 2817 // Shortcut for document ready 2818 } else if ( jQuery.isFunction( selector ) ) { 2819 return typeof rootjQuery.ready !== "undefined" ? 2820 rootjQuery.ready( selector ) : 2821 // Execute immediately if ready is not present 2822 selector( jQuery ); 2823 } 2824 2825 if ( selector.selector !== undefined ) { 2826 this.selector = selector.selector; 2827 this.context = selector.context; 2828 } 2829 2830 return jQuery.makeArray( selector, this ); 2831 }; 2832 2833// Give the init function the jQuery prototype for later instantiation 2834init.prototype = jQuery.fn; 2835 2836// Initialize central reference 2837rootjQuery = jQuery( document ); 2838 2839 2840var rparentsprev = /^(?:parents|prev(?:Until|All))/, 2841 // methods guaranteed to produce a unique set when starting from a unique set 2842 guaranteedUnique = { 2843 children: true, 2844 contents: true, 2845 next: true, 2846 prev: true 2847 }; 2848 2849jQuery.extend({ 2850 dir: function( elem, dir, until ) { 2851 var matched = [], 2852 cur = elem[ dir ]; 2853 2854 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { 2855 if ( cur.nodeType === 1 ) { 2856 matched.push( cur ); 2857 } 2858 cur = cur[dir]; 2859 } 2860 return matched; 2861 }, 2862 2863 sibling: function( n, elem ) { 2864 var r = []; 2865 2866 for ( ; n; n = n.nextSibling ) { 2867 if ( n.nodeType === 1 && n !== elem ) { 2868 r.push( n ); 2869 } 2870 } 2871 2872 return r; 2873 } 2874}); 2875 2876jQuery.fn.extend({ 2877 has: function( target ) { 2878 var i, 2879 targets = jQuery( target, this ), 2880 len = targets.length; 2881 2882 return this.filter(function() { 2883 for ( i = 0; i < len; i++ ) { 2884 if ( jQuery.contains( this, targets[i] ) ) { 2885 return true; 2886 } 2887 } 2888 }); 2889 }, 2890 2891 closest: function( selectors, context ) { 2892 var cur, 2893 i = 0, 2894 l = this.length, 2895 matched = [], 2896 pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
2897 jQuery( selectors, context || this.context ) : 2898 0; 2899 2900 for ( ; i < l; i++ ) { 2901 for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { 2902 // Always skip document fragments 2903 if ( cur.nodeType < 11 && (pos ? 2904 pos.index(cur) > -1 : 2905 2906 // Don't pass non-elements to Sizzle 2907 cur.nodeType === 1 && 2908 jQuery.find.matchesSelector(cur, selectors)) ) { 2909 2910 matched.push( cur ); 2911 break; 2912 } 2913 } 2914 } 2915 2916 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); 2917 }, 2918 2919 // Determine the position of an element within 2920 // the matched set of elements 2921 index: function( elem ) { 2922 2923 // No argument, return index in parent 2924 if ( !elem ) { 2925 return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; 2926 } 2927 2928 // index in selector 2929 if ( typeof elem === "string" ) { 2930 return jQuery.inArray( this[0], jQuery( elem ) ); 2931 } 2932 2933 // Locate the position of the desired element 2934 return jQuery.inArray( 2935 // If it receives a jQuery object, the first element is used 2936 elem.jquery ? elem[0] : elem, this ); 2937 }, 2938 2939 add: function( selector, context ) { 2940 return this.pushStack( 2941 jQuery.unique( 2942 jQuery.merge( this.get(), jQuery( selector, context ) ) 2943 ) 2944 ); 2945 }, 2946 2947 addBack: function( selector ) { 2948 return this.add( selector == null ? 2949 this.prevObject : this.prevObject.filter(selector) 2950 ); 2951 } 2952}); 2953 2954function sibling( cur, dir ) { 2955 do { 2956 cur = cur[ dir ]; 2957 } while ( cur && cur.nodeType !== 1 ); 2958 2959 return cur; 2960} 2961 2962jQuery.each({ 2963 parent: function( elem ) { 2964 var parent = elem.parentNode; 2965 return parent && parent.nodeType !== 11 ? parent : null; 2966 }, 2967 parents: function( elem ) { 2968 return jQuery.dir( elem, "parentNode" ); 2969 }, 2970 parentsUntil: function( elem, i, until ) { 2971 return jQuery.dir( elem, "parentNode", until ); 2972 }, 2973 next: function( elem ) { 2974 return sibling( elem, "nextSibling" ); 2975 }, 2976 prev: function( elem ) { 2977 return sibling( elem, "previousSibling" ); 2978 }, 2979 nextAll: function( elem ) { 2980 return jQuery.dir( elem, "nextSibling" ); 2981 }, 2982 prevAll: function( elem ) { 2983 return jQuery.dir( elem, "previousSibling" ); 2984 }, 2985 nextUntil: function( elem, i, until ) { 2986 return jQuery.dir( elem, "nextSibling", until ); 2987 }, 2988 prevUntil: function( elem, i, until ) { 2989 return jQuery.dir( elem, "previousSibling", until ); 2990 }, 2991 siblings: function( elem ) { 2992 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); 2993 }, 2994 children: function( elem ) { 2995 return jQuery.sibling( elem.firstChild ); 2996 }, 2997 contents: function( elem ) { 2998 return jQuery.nodeName( elem, "iframe" ) ? 2999 elem.contentDocument || elem.contentWindow.document : 3000 jQuery.merge( [], elem.childNodes ); 3001 } 3002}, function( name, fn ) { 3003 jQuery.fn[ name ] = function( until, selector ) { 3004 var ret = jQuery.map( this, fn, until ); 3005 3006 if ( name.slice( -5 ) !== "Until" ) { 3007 selector = until; 3008 } 3009 3010 if ( selector && typeof selector === "string" ) { 3011 ret = jQuery.filter( selector, ret ); 3012 } 3013 3014 if ( this.length > 1 ) { 3015 // Remove duplicates 3016 if ( !guaranteedUnique[ name ] ) { 3017 ret = jQuery.unique( ret ); 3018 } 3019 3020 // Reverse order for parents* and prev-derivatives 3021 if ( rparentsprev.test( name ) ) { 3022 ret = ret.reverse(); 3023 } 3024 } 3025 3026 return this.pushStack( ret ); 3027 }; 3028}); 3029var rnotwhite = (/\S+/g); 3030 3031 3032 3033// String to Object options format cache 3034var optionsCache = {}; 3035 3036// Convert String-formatted options into Object-formatted ones and store in cache 3037function createOptions( options ) { 3038 var object = optionsCache[ options ] = {}; 3039 jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { 3040 object[ flag ] = true; 3041 }); 3042 return object; 3043} 3044 3045/* 3046 * Create a callback list using the following parameters: 3047 * 3048 * options: an optional list of space-separated options that will change how 3049 * the callback list behaves or a more traditional option object 3050 * 3051 * By default a callback list will act like an event callback list and can be 3052 * "fired" multiple times. 3053 * 3054 * Possible options: 3055 * 3056 * once: will ensure the callback list can only be fired once (like a Deferred) 3057 * 3058 * memory: will keep track of previous values and will call any callback added 3059 * after the list has been fired right away with the latest "memorized" 3060 * values (like a Deferred) 3061 * 3062 * unique: will ensure a callback can only be added once (no duplicate in the list) 3063 * 3064 * stopOnFalse: interrupt callings when a callback returns false 3065 * 3066 */ 3067jQuery.Callbacks = function( options ) { 3068 3069 // Convert options from String-formatted to Object-formatted if needed 3070 // (we check in cache first) 3071 options = typeof options === "string" ? 3072 ( optionsCache[ options ] || createOptions( options ) ) : 3073 jQuery.extend( {}, options ); 3074 3075 var // Flag to know if list is currently firing 3076 firing, 3077 // Last fire value (for non-forgettable lists) 3078 memory, 3079 // Flag to know if list was already fired 3080 fired, 3081 // End of the loop when firing 3082 firingLength, 3083 // Index of currently firing callback (modified by remove if needed) 3084 firingIndex, 3085 // First callback to fire (used internally by add and fireWith) 3086 firingStart, 3087 // Actual callback list 3088 list = [],
3089 // Stack of fire calls for repeatable lists 3090 stack = !options.once && [], 3091 // Fire callbacks 3092 fire = function( data ) { 3093 memory = options.memory && data; 3094 fired = true; 3095 firingIndex = firingStart || 0; 3096 firingStart = 0; 3097 firingLength = list.length; 3098 firing = true; 3099 for ( ; list && firingIndex < firingLength; firingIndex++ ) { 3100 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { 3101 memory = false; // To prevent further calls using add 3102 break; 3103 } 3104 } 3105 firing = false; 3106 if ( list ) { 3107 if ( stack ) { 3108 if ( stack.length ) { 3109 fire( stack.shift() ); 3110 } 3111 } else if ( memory ) { 3112 list = []; 3113 } else { 3114 self.disable(); 3115 } 3116 } 3117 }, 3118 // Actual Callbacks object 3119 self = { 3120 // Add a callback or a collection of callbacks to the list 3121 add: function() { 3122 if ( list ) { 3123 // First, we save the current length 3124 var start = list.length; 3125 (function add( args ) { 3126 jQuery.each( args, function( _, arg ) { 3127 var type = jQuery.type( arg ); 3128 if ( type === "function" ) { 3129 if ( !options.unique || !self.has( arg ) ) { 3130 list.push( arg ); 3131 } 3132 } else if ( arg && arg.length && type !== "string" ) { 3133 // Inspect recursively 3134 add( arg ); 3135 } 3136 }); 3137 })( arguments ); 3138 // Do we need to add the callbacks to the 3139 // current firing batch? 3140 if ( firing ) { 3141 firingLength = list.length; 3142 // With memory, if we're not firing then 3143 // we should call right away 3144 } else if ( memory ) { 3145 firingStart = start; 3146 fire( memory ); 3147 } 3148 } 3149 return this; 3150 }, 3151 // Remove a callback from the list 3152 remove: function() { 3153 if ( list ) { 3154 jQuery.each( arguments, function( _, arg ) { 3155 var index; 3156 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { 3157 list.splice( index, 1 ); 3158 // Handle firing indexes 3159 if ( firing ) { 3160 if ( index <= firingLength ) { 3161 firingLength--; 3162 } 3163 if ( index <= firingIndex ) { 3164 firingIndex--; 3165 } 3166 } 3167 } 3168 }); 3169 } 3170 return this; 3171 }, 3172 // Check if a given callback is in the list. 3173 // If no argument is given, return whether or not list has callbacks attached. 3174 has: function( fn ) { 3175 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); 3176 }, 3177 // Remove all callbacks from the list 3178 empty: function() { 3179 list = []; 3180 firingLength = 0; 3181 return this; 3182 }, 3183 // Have the list do nothing anymore 3184 disable: function() { 3185 list = stack = memory = undefined; 3186 return this; 3187 }, 3188 // Is it disabled? 3189 disabled: function() { 3190 return !list; 3191 }, 3192 // Lock the list in its current state 3193 lock: function() { 3194 stack = undefined; 3195 if ( !memory ) { 3196 self.disable(); 3197 } 3198 return this; 3199 }, 3200 // Is it locked? 3201 locked: function() { 3202 return !stack; 3203 }, 3204 // Call all callbacks with the given context and arguments 3205 fireWith: function( context, args ) { 3206 if ( list && ( !fired || stack ) ) { 3207 args = args || []; 3208 args = [ context, args.slice ? args.slice() : args ]; 3209 if ( firing ) { 3210 stack.push( args ); 3211 } else { 3212 fire( args ); 3213 } 3214 } 3215 return this; 3216 }, 3217 // Call all the callbacks with the given arguments 3218 fire: function() { 3219 self.fireWith( this, arguments ); 3220 return this; 3221 }, 3222 // To know if the callbacks have already been called at least once 3223 fired: function() { 3224 return !!fired; 3225 } 3226 }; 3227 3228 return self; 3229}; 3230 3231 3232jQuery.extend({ 3233 3234 Deferred: function( func ) { 3235 var tuples = [ 3236 // action, add listener, listener list, final state 3237 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], 3238 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], 3239 [ "notify", "progress", jQuery.Callbacks("memory") ] 3240 ], 3241 state = "pending", 3242 promise = { 3243 state: function() { 3244 return state; 3245 }, 3246 always: function() { 3247 deferred.done( arguments ).fail( arguments ); 3248 return this; 3249 }, 3250 then: function( /* fnDone, fnFail, fnProgress */ ) { 3251 var fns = arguments; 3252 return jQuery.Deferred(function( newDefer ) { 3253 jQuery.each( tuples, function( i, tuple ) { 3254 var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; 3255 // deferred[ done | fail | progress ] for forwarding actions to newDefer 3256 deferred[ tuple[1] ](function() { 3257 var returned = fn && fn.apply( this, arguments ); 3258 if ( returned && jQuery.isFunction( returned.promise ) ) { 3259 returned.promise() 3260 .done( newDefer.resolve ) 3261 .fail( newDefer.reject ) 3262 .progress( newDefer.notify ); 3263 } else { 3264 newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); 3265 } 3266 }); 3267 }); 3268 fns = null; 3269 }).promise(); 3270 }, 3271 // Get a promise for this deferred 3272 // If obj is provided, the promise aspect is added to the object 3273 promise: function( obj ) { 3274 return obj != null ? jQuery.extend( obj, promise ) : promise; 3275 } 3276 }, 3277 deferred = {}; 3278 3279 // Keep pipe for back-compat 3280 promise.pipe = promise.then; 3281 3282 // Add list-specific methods 3283 jQuery.each( tuples, function( i, tuple ) { 3284 var list = tuple[ 2 ], 3285 stateString = tuple[ 3 ]; 3286 3287 // promise[ done | fail | progress ] = list.add 3288 promise[ tuple[1] ] = list.add; 3289 3290 // Handle state 3291 if ( stateString ) { 3292 list.add(function() { 3293 // state = [ resolved | rejected ] 3294 state = stateString; 3295 3296 // [ reject_list | resolve_list ].disable; progress_list.lock 3297 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); 3298 } 3299 3300 // deferred[ resolve | reject | notify ] 3301 deferred[ tuple[0] ] = function() { 3302 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); 3303 return this; 3304 }; 3305 deferred[ tuple[0] + "With" ] = list.fireWith; 3306 }); 3307 3308 // Make the deferred a promise 3309 promise.promise( deferred ); 3310 3311 // Call given func if any 3312 if ( func ) { 3313 func.call( deferred, deferred ); 3314 } 3315 3316 // All done! 3317 return deferred; 3318 }, 3319 3320 // Deferred helper 3321 when: function( subordinate /* , ..., subordinateN */ ) { 3322 var i = 0, 3323 resolveValues = slice.call( arguments ), 3324 length = resolveValues.length, 3325 3326 // the count of uncompleted subordinates 3327 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, 3328 3329 // the master Deferred. If resolveValues consist of only a single Deferred, just use that. 3330 deferred = remaining === 1 ? subordinate : jQuery.Deferred(), 3331 3332 // Update function for both resolve and progress values 3333 updateFunc = function( i, contexts, values ) { 3334 return function( value ) { 3335 contexts[ i ] = this; 3336 values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; 3337 if ( values === progressValues ) { 3338 deferred.notifyWith( contexts, values ); 3339 3340 } else if ( !(--remaining) ) { 3341 deferred.resolveWith( contexts, values ); 3342 } 3343 }; 3344 }, 3345 3346 progressValues, progressContexts, resolveContexts; 3347 3348 // add listeners to Deferred subordinates; treat others as resolved 3349 if ( length > 1 ) { 3350 progressValues = new Array( length ); 3351 progressContexts = new Array( length ); 3352 resolveContexts = new Array( length ); 3353 for ( ; i < length; i++ ) { 3354 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { 3355 resolveValues[ i ].promise() 3356 .done( updateFunc( i, resolveContexts, resolveValues ) ) 3357 .fail( deferred.reject ) 3358 .progress( updateFunc( i, progressContexts, progressValues ) ); 3359 } else { 3360 --remaining; 3361 } 3362 } 3363 } 3364 3365 // if we're not waiting on anything, resolve the master 3366 if ( !remaining ) {
3367 deferred.resolveWith( resolveContexts, resolveValues ); 3368 } 3369 3370 return deferred.promise(); 3371 } 3372}); 3373 3374 3375// The deferred used on DOM ready 3376var readyList; 3377 3378jQuery.fn.ready = function( fn ) { 3379 // Add the callback 3380 jQuery.ready.promise().done( fn ); 3381 3382 return this; 3383}; 3384 3385jQuery.extend({ 3386 // Is the DOM ready to be used? Set to true once it occurs. 3387 isReady: false, 3388 3389 // A counter to track how many items to wait for before 3390 // the ready event fires. See #6781 3391 readyWait: 1, 3392 3393 // Hold (or release) the ready event 3394 holdReady: function( hold ) { 3395 if ( hold ) { 3396 jQuery.readyWait++; 3397 } else { 3398 jQuery.ready( true ); 3399 } 3400 }, 3401 3402 // Handle when the DOM is ready 3403 ready: function( wait ) { 3404 3405 // Abort if there are pending holds or we're already ready 3406 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { 3407 return; 3408 } 3409 3410 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 3411 if ( !document.body ) { 3412 return setTimeout( jQuery.ready ); 3413 } 3414 3415 // Remember that the DOM is ready 3416 jQuery.isReady = true; 3417 3418 // If a normal DOM Ready event fired, decrement, and wait if need be 3419 if ( wait !== true && --jQuery.readyWait > 0 ) { 3420 return; 3421 } 3422 3423 // If there are functions bound, to execute 3424 readyList.resolveWith( document, [ jQuery ] ); 3425 3426 // Trigger any bound ready events 3427 if ( jQuery.fn.trigger ) { 3428 jQuery( document ).trigger("ready").off("ready"); 3429 } 3430 } 3431}); 3432 3433/** 3434 * Clean-up method for dom ready events 3435 */ 3436function detach() { 3437 if ( document.addEventListener ) { 3438 document.removeEventListener( "DOMContentLoaded", completed, false ); 3439 window.removeEventListener( "load", completed, false ); 3440 3441 } else { 3442 document.detachEvent( "onreadystatechange", completed ); 3443 window.detachEvent( "onload", completed ); 3444 } 3445} 3446 3447/** 3448 * The ready event handler and self cleanup method 3449 */ 3450function completed() { 3451 // readyState === "complete" is good enough for us to call the dom ready in oldIE 3452 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { 3453 detach(); 3454 jQuery.ready(); 3455 } 3456} 3457 3458jQuery.ready.promise = function( obj ) { 3459 if ( !readyList ) { 3460 3461 readyList = jQuery.Deferred(); 3462 3463 // Catch cases where $(document).ready() is called after the browser event has already occurred. 3464 // we once tried to use readyState "interactive" here, but it caused issues like the one 3465 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 3466 if ( document.readyState === "complete" ) { 3467 // Handle it asynchronously to allow scripts the opportunity to delay ready 3468 setTimeout( jQuery.ready ); 3469 3470 // Standards-based browsers support DOMContentLoaded 3471 } else if ( document.addEventListener ) { 3472 // Use the handy event callback 3473 document.addEventListener( "DOMContentLoaded", completed, false ); 3474 3475 // A fallback to window.onload, that will always work 3476 window.addEventListener( "load", completed, false ); 3477 3478 // If IE event model is used 3479 } else { 3480 // Ensure firing before onload, maybe late but safe also for iframes 3481 document.attachEvent( "onreadystatechange", completed ); 3482 3483 // A fallback to window.onload, that will always work 3484 window.attachEvent( "onload", completed ); 3485 3486 // If IE and not a frame 3487 // continually check to see if the document is ready 3488 var top = false; 3489 3490 try { 3491 top = window.frameElement == null && document.documentElement; 3492 } catch(e) {} 3493 3494 if ( top && top.doScroll ) { 3495 (function doScrollCheck() { 3496 if ( !jQuery.isReady ) { 3497 3498 try { 3499 // Use the trick by Diego Perini 3500 // http://javascript.nwbox.com/IEContentLoaded/ 3501 top.doScroll("left"); 3502 } catch(e) { 3503 return setTimeout( doScrollCheck, 50 ); 3504 } 3505 3506 // detach all dom ready events 3507 detach(); 3508 3509 // and execute any waiting functions 3510 jQuery.ready(); 3511 } 3512 })(); 3513 } 3514 } 3515 } 3516 return readyList.promise( obj ); 3517}; 3518 3519 3520var strundefined = typeof undefined; 3521 3522 3523 3524// Support: IE<9 3525// Iteration over object's inherited properties before its own 3526var i; 3527for ( i in jQuery( support ) ) { 3528 break; 3529} 3530support.ownLast = i !== "0"; 3531 3532// Note: most support tests are defined in their respective modules. 3533// false until the test is run 3534support.inlineBlockNeedsLayout = false;
3535 3536jQuery(function() { 3537 // We need to execute this one support test ASAP because we need to know 3538 // if body.style.zoom needs to be set. 3539 3540 var container, div, 3541 body = document.getElementsByTagName("body")[0]; 3542 3543 if ( !body ) { 3544 // Return for frameset docs that don't have a body 3545 return; 3546 } 3547 3548 // Setup 3549 container = document.createElement( "div" ); 3550 container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; 3551 3552 div = document.createElement( "div" ); 3553 body.appendChild( container ).appendChild( div ); 3554 3555 if ( typeof div.style.zoom !== strundefined ) { 3556 // Support: IE<8 3557 // Check if natively block-level elements act like inline-block 3558 // elements when setting their display to 'inline' and giving 3559 // them layout 3560 div.style.cssText = "border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1"; 3561 3562 if ( (support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 )) ) { 3563 // Prevent IE 6 from affecting layout for positioned elements #11048 3564 // Prevent IE from shrinking the body in IE 7 mode #12869 3565 // Support: IE<8 3566 body.style.zoom = 1; 3567 } 3568 } 3569 3570 body.removeChild( container ); 3571 3572 // Null elements to avoid leaks in IE 3573 container = div = null; 3574}); 3575 3576 3577 3578 3579(function() { 3580 var div = document.createElement( "div" ); 3581 3582 // Execute the test only if not already executed in another module. 3583 if (support.deleteExpando == null) { 3584 // Support: IE<9 3585 support.deleteExpando = true; 3586 try { 3587 delete div.test; 3588 } catch( e ) { 3589 support.deleteExpando = false; 3590 } 3591 } 3592 3593 // Null elements to avoid leaks in IE. 3594 div = null; 3595})(); 3596 3597 3598/** 3599 * Determines whether an object can have data 3600 */ 3601jQuery.acceptData = function( elem ) { 3602 var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], 3603 nodeType = +elem.nodeType || 1; 3604 3605 // Do not set data on non-element DOM nodes because it will not be cleared (#8335). 3606 return nodeType !== 1 && nodeType !== 9 ? 3607 false : 3608 3609 // Nodes accept data unless otherwise specified; rejection can be conditional 3610 !noData || noData !== true && elem.getAttribute("classid") === noData; 3611}; 3612 3613 3614var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, 3615 rmultiDash = /([A-Z])/g; 3616 3617function dataAttr( elem, key, data ) { 3618 // If nothing was found internally, try to fetch any 3619 // data from the HTML5 data-* attribute 3620 if ( data === undefined && elem.nodeType === 1 ) { 3621 3622 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); 3623 3624 data = elem.getAttribute( name ); 3625 3626 if ( typeof data === "string" ) { 3627 try { 3628 data = data === "true" ? true : 3629 data === "false" ? false : 3630 data === "null" ? null : 3631 // Only convert to a number if it doesn't change the string 3632 +data + "" === data ? +data : 3633 rbrace.test( data ) ? jQuery.parseJSON( data ) : 3634 data; 3635 } catch( e ) {} 3636 3637 // Make sure we set the data so it isn't changed later 3638 jQuery.data( elem, key, data ); 3639 3640 } else { 3641 data = undefined; 3642 } 3643 } 3644 3645 return data; 3646} 3647 3648// checks a cache object for emptiness 3649function isEmptyDataObject( obj ) { 3650 var name; 3651 for ( name in obj ) { 3652 3653 // if the public data object is empty, the private is still empty 3654 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { 3655 continue; 3656 } 3657 if ( name !== "toJSON" ) { 3658 return false; 3659 } 3660 } 3661 3662 return true; 3663} 3664 3665function internalData( elem, name, data, pvt /* Internal Use Only */ ) { 3666 if ( !jQuery.acceptData( elem ) ) { 3667 return; 3668 } 3669 3670 var ret, thisCache, 3671 internalKey = jQuery.expando, 3672 3673 // We have to handle DOM nodes and JS objects differently because IE6-7 3674 // can't GC object references properly across the DOM-JS boundary 3675 isNode = elem.nodeType, 3676 3677 // Only DOM nodes need the global jQuery cache; JS object data is 3678 // attached directly to the object so GC can occur automatically 3679 cache = isNode ? jQuery.cache : elem, 3680 3681 // Only defining an ID for JS objects if its cache already exists allows 3682 // the code to shortcut on the same path as a DOM node with no cache 3683 id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; 3684 3685 // Avoid doing any more work than we need to when trying to get data on an 3686 // object that has no data at all 3687 if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { 3688 return; 3689 } 3690 3691 if ( !id ) { 3692 // Only DOM nodes need a new unique ID for each element since their data 3693 // ends up in the global cache 3694 if ( isNode ) { 3695 id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; 3696 } else { 3697 id = internalKey; 3698 } 3699 } 3700 3701 if ( !cache[ id ] ) { 3702 // Avoid exposing jQuery metadata on plain JS objects when the object 3703 // is serialized using JSON.stringify 3704 cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; 3705 } 3706
3707 // An object can be passed to jQuery.data instead of a key/value pair; this gets 3708 // shallow copied over onto the existing cache 3709 if ( typeof name === "object" || typeof name === "function" ) { 3710 if ( pvt ) { 3711 cache[ id ] = jQuery.extend( cache[ id ], name ); 3712 } else { 3713 cache[ id ].data = jQuery.extend( cache[ id ].data, name ); 3714 } 3715 } 3716 3717 thisCache = cache[ id ]; 3718 3719 // jQuery data() is stored in a separate object inside the object's internal data 3720 // cache in order to avoid key collisions between internal data and user-defined 3721 // data. 3722 if ( !pvt ) { 3723 if ( !thisCache.data ) { 3724 thisCache.data = {}; 3725 } 3726 3727 thisCache = thisCache.data; 3728 } 3729 3730 if ( data !== undefined ) { 3731 thisCache[ jQuery.camelCase( name ) ] = data; 3732 } 3733 3734 // Check for both converted-to-camel and non-converted data property names 3735 // If a data property was specified 3736 if ( typeof name === "string" ) { 3737 3738 // First Try to find as-is property data 3739 ret = thisCache[ name ]; 3740 3741 // Test for null|undefined property data 3742 if ( ret == null ) { 3743 3744 // Try to find the camelCased property 3745 ret = thisCache[ jQuery.camelCase( name ) ]; 3746 } 3747 } else { 3748 ret = thisCache; 3749 } 3750 3751 return ret; 3752} 3753 3754function internalRemoveData( elem, name, pvt ) { 3755 if ( !jQuery.acceptData( elem ) ) { 3756 return; 3757 } 3758 3759 var thisCache, i, 3760 isNode = elem.nodeType, 3761 3762 // See jQuery.data for more information 3763 cache = isNode ? jQuery.cache : elem, 3764 id = isNode ? elem[ jQuery.expando ] : jQuery.expando; 3765 3766 // If there is already no cache entry for this object, there is no 3767 // purpose in continuing 3768 if ( !cache[ id ] ) { 3769 return; 3770 } 3771 3772 if ( name ) { 3773 3774 thisCache = pvt ? cache[ id ] : cache[ id ].data; 3775 3776 if ( thisCache ) { 3777 3778 // Support array or space separated string names for data keys 3779 if ( !jQuery.isArray( name ) ) { 3780 3781 // try the string as a key before any manipulation 3782 if ( name in thisCache ) { 3783 name = [ name ]; 3784 } else { 3785 3786 // split the camel cased version by spaces unless a key with the spaces exists 3787 name = jQuery.camelCase( name ); 3788 if ( name in thisCache ) { 3789 name = [ name ]; 3790 } else { 3791 name = name.split(" "); 3792 } 3793 } 3794 } else { 3795 // If "name" is an array of keys... 3796 // When data is initially created, via ("key", "val") signature, 3797 // keys will be converted to camelCase. 3798 // Since there is no way to tell _how_ a key was added, remove 3799 // both plain key and camelCase key. #12786 3800 // This will only penalize the array argument path. 3801 name = name.concat( jQuery.map( name, jQuery.camelCase ) ); 3802 } 3803 3804 i = name.length; 3805 while ( i-- ) { 3806 delete thisCache[ name[i] ]; 3807 } 3808 3809 // If there is no data left in the cache, we want to continue 3810 // and let the cache object itself get destroyed 3811 if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { 3812 return; 3813 } 3814 } 3815 } 3816 3817 // See jQuery.data for more information 3818 if ( !pvt ) { 3819 delete cache[ id ].data; 3820 3821 // Don't destroy the parent cache unless the internal data object 3822 // had been the only thing left in it 3823 if ( !isEmptyDataObject( cache[ id ] ) ) { 3824 return; 3825 } 3826 } 3827 3828 // Destroy the cache 3829 if ( isNode ) { 3830 jQuery.cleanData( [ elem ], true ); 3831 3832 // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) 3833 /* jshint eqeqeq: false */ 3834 } else if ( support.deleteExpando || cache != cache.window ) { 3835 /* jshint eqeqeq: true */ 3836 delete cache[ id ]; 3837 3838 // When all else fails, null 3839 } else { 3840 cache[ id ] = null; 3841 } 3842} 3843 3844jQuery.extend({ 3845 cache: {}, 3846 3847 // The following elements (space-suffixed to avoid Object.prototype collisions) 3848 // throw uncatchable exceptions if you attempt to set expando properties 3849 noData: { 3850 "applet ": true, 3851 "embed ": true, 3852 // ...but Flash objects (which have this classid) *can* handle expandos 3853 "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 3854 }, 3855 3856 hasData: function( elem ) { 3857 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; 3858 return !!elem && !isEmptyDataObject( elem ); 3859 }, 3860 3861 data: function( elem, name, data ) { 3862 return internalData( elem, name, data ); 3863 }, 3864 3865 removeData: function( elem, name ) { 3866 return internalRemoveData( elem, name ); 3867 }, 3868 3869 // For internal use only. 3870 _data: function( elem, name, data ) { 3871 return internalData( elem, name, data, true ); 3872 }, 3873 3874 _removeData: function( elem, name ) { 3875 return internalRemoveData( elem, name, true ); 3876 } 3877}); 3878 3879jQuery.fn.extend({ 3880 data: function( key, value ) { 3881 var i, name, data, 3882 elem = this[0], 3883 attrs = elem && elem.attributes; 3884 3885 // Special expections of .data basically thwart jQuery.access, 3886 // so implement the relevant behavior ourselves 3887 3888 // Gets all values 3889 if ( key === undefined ) { 3890 if ( this.length ) { 3891 data = jQuery.data( elem ); 3892 3893 if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { 3894 i = attrs.length; 3895 while ( i-- ) { 3896 name = attrs[i].name; 3897
3898 if ( name.indexOf("data-") === 0 ) { 3899 name = jQuery.camelCase( name.slice(5) ); 3900 3901 dataAttr( elem, name, data[ name ] ); 3902 } 3903 } 3904 jQuery._data( elem, "parsedAttrs", true ); 3905 } 3906 } 3907 3908 return data; 3909 } 3910 3911 // Sets multiple values 3912 if ( typeof key === "object" ) { 3913 return this.each(function() { 3914 jQuery.data( this, key ); 3915 }); 3916 } 3917 3918 return arguments.length > 1 ? 3919 3920 // Sets one value 3921 this.each(function() { 3922 jQuery.data( this, key, value ); 3923 }) : 3924 3925 // Gets one value 3926 // Try to fetch any internally stored data first 3927 elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; 3928 }, 3929 3930 removeData: function( key ) { 3931 return this.each(function() { 3932 jQuery.removeData( this, key ); 3933 }); 3934 } 3935}); 3936 3937 3938jQuery.extend({ 3939 queue: function( elem, type, data ) { 3940 var queue; 3941 3942 if ( elem ) { 3943 type = ( type || "fx" ) + "queue"; 3944 queue = jQuery._data( elem, type ); 3945 3946 // Speed up dequeue by getting out quickly if this is just a lookup 3947 if ( data ) { 3948 if ( !queue || jQuery.isArray(data) ) { 3949 queue = jQuery._data( elem, type, jQuery.makeArray(data) ); 3950 } else { 3951 queue.push( data ); 3952 } 3953 } 3954 return queue || []; 3955 } 3956 }, 3957 3958 dequeue: function( elem, type ) { 3959 type = type || "fx"; 3960 3961 var queue = jQuery.queue( elem, type ), 3962 startLength = queue.length, 3963 fn = queue.shift(), 3964 hooks = jQuery._queueHooks( elem, type ), 3965 next = function() { 3966 jQuery.dequeue( elem, type ); 3967 }; 3968 3969 // If the fx queue is dequeued, always remove the progress sentinel 3970 if ( fn === "inprogress" ) { 3971 fn = queue.shift(); 3972 startLength--; 3973 } 3974 3975 if ( fn ) { 3976 3977 // Add a progress sentinel to prevent the fx queue from being 3978 // automatically dequeued 3979 if ( type === "fx" ) { 3980 queue.unshift( "inprogress" ); 3981 } 3982 3983 // clear up the last queue stop function 3984 delete hooks.stop; 3985 fn.call( elem, next, hooks ); 3986 } 3987 3988 if ( !startLength && hooks ) { 3989 hooks.empty.fire(); 3990 } 3991 }, 3992 3993 // not intended for public consumption - generates a queueHooks object, or returns the current one 3994 _queueHooks: function( elem, type ) { 3995 var key = type + "queueHooks"; 3996 return jQuery._data( elem, key ) || jQuery._data( elem, key, { 3997 empty: jQuery.Callbacks("once memory").add(function() { 3998 jQuery._removeData( elem, type + "queue" ); 3999 jQuery._removeData( elem, key ); 4000 }) 4001 }); 4002 } 4003}); 4004 4005jQuery.fn.extend({ 4006 queue: function( type, data ) { 4007 var setter = 2; 4008 4009 if ( typeof type !== "string" ) { 4010 data = type; 4011 type = "fx"; 4012 setter--; 4013 } 4014 4015 if ( arguments.length < setter ) { 4016 return jQuery.queue( this[0], type ); 4017 } 4018 4019 return data === undefined ? 4020 this : 4021 this.each(function() { 4022 var queue = jQuery.queue( this, type, data ); 4023 4024 // ensure a hooks for this queue 4025 jQuery._queueHooks( this, type ); 4026 4027 if ( type === "fx" && queue[0] !== "inprogress" ) { 4028 jQuery.dequeue( this, type ); 4029 } 4030 }); 4031 }, 4032 dequeue: function( type ) { 4033 return this.each(function() { 4034 jQuery.dequeue( this, type ); 4035 }); 4036 }, 4037 clearQueue: function( type ) { 4038 return this.queue( type || "fx", [] ); 4039 }, 4040 // Get a promise resolved when queues of a certain type 4041 // are emptied (fx is the type by default) 4042 promise: function( type, obj ) { 4043 var tmp, 4044 count = 1, 4045 defer = jQuery.Deferred(), 4046 elements = this, 4047 i = this.length, 4048 resolve = function() { 4049 if ( !( --count ) ) { 4050 defer.resolveWith( elements, [ elements ] ); 4051 } 4052 }; 4053 4054 if ( typeof type !== "string" ) { 4055 obj = type; 4056 type = undefined; 4057 } 4058 type = type || "fx"; 4059 4060 while ( i-- ) { 4061 tmp = jQuery._data( elements[ i ], type + "queueHooks" ); 4062 if ( tmp && tmp.empty ) { 4063 count++; 4064 tmp.empty.add( resolve ); 4065 } 4066 } 4067 resolve(); 4068 return defer.promise( obj ); 4069 } 4070}); 4071var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; 4072 4073var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; 4074 4075var isHidden = function( elem, el ) { 4076 // isHidden might be called from jQuery#filter function; 4077 // in that case, element will be second argument 4078 elem = el || elem; 4079 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); 4080 }; 4081 4082 4083 4084// Multifunctional method to get and set values of a collection 4085// The value/s can optionally be executed if it's a function 4086var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { 4087 var i = 0, 4088 length = elems.length, 4089 bulk = key == null; 4090 4091 // Sets many values 4092 if ( jQuery.type( key ) === "object" ) { 4093 chainable = true; 4094 for ( i in key ) { 4095 jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); 4096 } 4097 4098 // Sets one value 4099 } else if ( value !== undefined ) { 4100 chainable = true; 4101 4102 if ( !jQuery.isFunction( value ) ) {
4103 raw = true; 4104 } 4105 4106 if ( bulk ) { 4107 // Bulk operations run against the entire set 4108 if ( raw ) { 4109 fn.call( elems, value ); 4110 fn = null; 4111 4112 // ...except when executing function values 4113 } else { 4114 bulk = fn; 4115 fn = function( elem, key, value ) { 4116 return bulk.call( jQuery( elem ), value ); 4117 }; 4118 } 4119 } 4120 4121 if ( fn ) { 4122 for ( ; i < length; i++ ) { 4123 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); 4124 } 4125 } 4126 } 4127 4128 return chainable ? 4129 elems : 4130 4131 // Gets 4132 bulk ? 4133 fn.call( elems ) : 4134 length ? fn( elems[0], key ) : emptyGet; 4135}; 4136var rcheckableType = (/^(?:checkbox|radio)$/i); 4137 4138 4139 4140(function() { 4141 var fragment = document.createDocumentFragment(), 4142 div = document.createElement("div"), 4143 input = document.createElement("input"); 4144 4145 // Setup 4146 div.setAttribute( "className", "t" ); 4147 div.innerHTML = " <link/><table></table><a href='/a'>a</a>"; 4148 4149 // IE strips leading whitespace when .innerHTML is used 4150 support.leadingWhitespace = div.firstChild.nodeType === 3; 4151 4152 // Make sure that tbody elements aren't automatically inserted 4153 // IE will insert them into empty tables 4154 support.tbody = !div.getElementsByTagName( "tbody" ).length; 4155 4156 // Make sure that link elements get serialized correctly by innerHTML 4157 // This requires a wrapper element in IE 4158 support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; 4159 4160 // Makes sure cloning an html5 element does not cause problems 4161 // Where outerHTML is undefined, this still works 4162 support.html5Clone = 4163 document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>"; 4164 4165 // Check if a disconnected checkbox will retain its checked 4166 // value of true after appended to the DOM (IE6/7) 4167 input.type = "checkbox"; 4168 input.checked = true; 4169 fragment.appendChild( input ); 4170 support.appendChecked = input.checked; 4171 4172 // Make sure textarea (and checkbox) defaultValue is properly cloned 4173 // Support: IE6-IE11+ 4174 div.innerHTML = "<textarea>x</textarea>"; 4175 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 4176 4177 // #11217 - WebKit loses check when the name is after the checked attribute 4178 fragment.appendChild( div ); 4179 div.innerHTML = "<input type='radio' checked='checked' name='t'/>"; 4180 4181 // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 4182 // old WebKit doesn't clone checked state correctly in fragments 4183 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 4184 4185 // Support: IE<9 4186 // Opera does not clone events (and typeof div.attachEvent === undefined). 4187 // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() 4188 support.noCloneEvent = true; 4189 if ( div.attachEvent ) { 4190 div.attachEvent( "onclick", function() { 4191 support.noCloneEvent = false; 4192 }); 4193 4194 div.cloneNode( true ).click(); 4195 } 4196 4197 // Execute the test only if not already executed in another module. 4198 if (support.deleteExpando == null) { 4199 // Support: IE<9 4200 support.deleteExpando = true; 4201 try { 4202 delete div.test; 4203 } catch( e ) { 4204 support.deleteExpando = false; 4205 } 4206 } 4207 4208 // Null elements to avoid leaks in IE. 4209 fragment = div = input = null; 4210})(); 4211 4212 4213(function() { 4214 var i, eventName, 4215 div = document.createElement( "div" ); 4216 4217 // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) 4218 for ( i in { submit: true, change: true, focusin: true }) { 4219 eventName = "on" + i; 4220
4221 if ( !(support[ i + "Bubbles" ] = eventName in window) ) { 4222 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) 4223 div.setAttribute( eventName, "t" ); 4224 support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; 4225 } 4226 } 4227 4228 // Null elements to avoid leaks in IE. 4229 div = null; 4230})(); 4231 4232 4233var rformElems = /^(?:input|select|textarea)$/i, 4234 rkeyEvent = /^key/, 4235 rmouseEvent = /^(?:mouse|contextmenu)|click/, 4236 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, 4237 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; 4238 4239function returnTrue() { 4240 return true; 4241} 4242 4243function returnFalse() { 4244 return false; 4245} 4246 4247function safeActiveElement() { 4248 try { 4249 return document.activeElement; 4250 } catch ( err ) { } 4251} 4252 4253/* 4254 * Helper functions for managing events -- not part of the public interface. 4255 * Props to Dean Edwards' addEvent library for many of the ideas. 4256 */ 4257jQuery.event = { 4258 4259 global: {}, 4260 4261 add: function( elem, types, handler, data, selector ) { 4262 var tmp, events, t, handleObjIn, 4263 special, eventHandle, handleObj, 4264 handlers, type, namespaces, origType, 4265 elemData = jQuery._data( elem ); 4266 4267 // Don't attach events to noData or text/comment nodes (but allow plain objects) 4268 if ( !elemData ) { 4269 return; 4270 } 4271 4272 // Caller can pass in an object of custom data in lieu of the handler 4273 if ( handler.handler ) { 4274 handleObjIn = handler; 4275 handler = handleObjIn.handler; 4276 selector = handleObjIn.selector; 4277 } 4278 4279 // Make sure that the handler has a unique ID, used to find/remove it later 4280 if ( !handler.guid ) { 4281 handler.guid = jQuery.guid++; 4282 } 4283 4284 // Init the element's event structure and main handler, if this is the first 4285 if ( !(events = elemData.events) ) { 4286 events = elemData.events = {}; 4287 } 4288 if ( !(eventHandle = elemData.handle) ) { 4289 eventHandle = elemData.handle = function( e ) { 4290 // Discard the second event of a jQuery.event.trigger() and 4291 // when an event is called after a page has unloaded 4292 return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? 4293 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : 4294 undefined; 4295 }; 4296 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events 4297 eventHandle.elem = elem; 4298 } 4299 4300 // Handle multiple events separated by a space 4301 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4302 t = types.length; 4303 while ( t-- ) { 4304 tmp = rtypenamespace.exec( types[t] ) || []; 4305 type = origType = tmp[1]; 4306 namespaces = ( tmp[2] || "" ).split( "." ).sort(); 4307 4308 // There *must* be a type, no attaching namespace-only handlers 4309 if ( !type ) { 4310 continue; 4311 } 4312 4313 // If event changes its type, use the special event handlers for the changed type 4314 special = jQuery.event.special[ type ] || {}; 4315 4316 // If selector defined, determine special event api type, otherwise given type 4317 type = ( selector ? special.delegateType : special.bindType ) || type; 4318 4319 // Update special based on newly reset type 4320 special = jQuery.event.special[ type ] || {}; 4321 4322 // handleObj is passed to all event handlers 4323 handleObj = jQuery.extend({ 4324 type: type, 4325 origType: origType, 4326 data: data, 4327 handler: handler, 4328 guid: handler.guid, 4329 selector: selector, 4330 needsContext: selector && jQuery.expr.match.needsContext.test( selector ), 4331 namespace: namespaces.join(".") 4332 }, handleObjIn ); 4333 4334 // Init the event handler queue if we're the first 4335 if ( !(handlers = events[ type ]) ) { 4336 handlers = events[ type ] = []; 4337 handlers.delegateCount = 0; 4338 4339 // Only use addEventListener/attachEvent if the special events handler returns false 4340 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 4341 // Bind the global event handler to the element 4342 if ( elem.addEventListener ) { 4343 elem.addEventListener( type, eventHandle, false ); 4344 4345 } else if ( elem.attachEvent ) { 4346 elem.attachEvent( "on" + type, eventHandle ); 4347 } 4348 } 4349 } 4350 4351 if ( special.add ) { 4352 special.add.call( elem, handleObj ); 4353 4354 if ( !handleObj.handler.guid ) { 4355 handleObj.handler.guid = handler.guid; 4356 } 4357 } 4358 4359 // Add to the element's handler list, delegates in front 4360 if ( selector ) { 4361 handlers.splice( handlers.delegateCount++, 0, handleObj ); 4362 } else { 4363 handlers.push( handleObj ); 4364 } 4365 4366 // Keep track of which events have ever been used, for event optimization 4367 jQuery.event.global[ type ] = true; 4368 } 4369 4370 // Nullify elem to prevent memory leaks in IE 4371 elem = null; 4372 }, 4373 4374 // Detach an event or set of events from an element 4375 remove: function( elem, types, handler, selector, mappedTypes ) { 4376 var j, handleObj, tmp, 4377 origCount, t, events, 4378 special, handlers, type, 4379 namespaces, origType, 4380 elemData = jQuery.hasData( elem ) && jQuery._data( elem ); 4381 4382 if ( !elemData || !(events = elemData.events) ) { 4383 return; 4384 } 4385
vendor: 8,441 bytes, lines 4386-4652
4386 // Once for each type.namespace in types; type may be omitted 4387 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4388 t = types.length; 4389 while ( t-- ) { 4390 tmp = rtypenamespace.exec( types[t] ) || []; 4391 type = origType = tmp[1]; 4392 namespaces = ( tmp[2] || "" ).split( "." ).sort(); 4393 4394 // Unbind all events (on this namespace, if provided) for the element 4395 if ( !type ) { 4396 for ( type in events ) { 4397 jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); 4398 } 4399 continue; 4400 } 4401 4402 special = jQuery.event.special[ type ] || {}; 4403 type = ( selector ? special.delegateType : special.bindType ) || type; 4404 handlers = events[ type ] || []; 4405 tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); 4406 4407 // Remove matching events 4408 origCount = j = handlers.length; 4409 while ( j-- ) { 4410 handleObj = handlers[ j ]; 4411 4412 if ( ( mappedTypes || origType === handleObj.origType ) && 4413 ( !handler || handler.guid === handleObj.guid ) && 4414 ( !tmp || tmp.test( handleObj.namespace ) ) && 4415 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { 4416 handlers.splice( j, 1 ); 4417 4418 if ( handleObj.selector ) { 4419 handlers.delegateCount--; 4420 } 4421 if ( special.remove ) { 4422 special.remove.call( elem, handleObj ); 4423 } 4424 } 4425 } 4426 4427 // Remove generic event handler if we removed something and no more handlers exist 4428 // (avoids potential for endless recursion during removal of special event handlers) 4429 if ( origCount && !handlers.length ) { 4430 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { 4431 jQuery.removeEvent( elem, type, elemData.handle ); 4432 } 4433 4434 delete events[ type ]; 4435 } 4436 } 4437 4438 // Remove the expando if it's no longer used 4439 if ( jQuery.isEmptyObject( events ) ) { 4440 delete elemData.handle; 4441 4442 // removeData also checks for emptiness and clears the expando if empty 4443 // so use it instead of delete 4444 jQuery._removeData( elem, "events" ); 4445 } 4446 }, 4447 4448 trigger: function( event, data, elem, onlyHandlers ) { 4449 var handle, ontype, cur, 4450 bubbleType, special, tmp, i, 4451 eventPath = [ elem || document ], 4452 type = hasOwn.call( event, "type" ) ? event.type : event, 4453 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; 4454 4455 cur = tmp = elem = elem || document; 4456 4457 // Don't do events on text and comment nodes 4458 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 4459 return; 4460 } 4461 4462 // focus/blur morphs to focusin/out; ensure we're not firing them right now 4463 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 4464 return; 4465 } 4466 4467 if ( type.indexOf(".") >= 0 ) { 4468 // Namespaced trigger; create a regexp to match event type in handle() 4469 namespaces = type.split("."); 4470 type = namespaces.shift(); 4471 namespaces.sort(); 4472 } 4473 ontype = type.indexOf(":") < 0 && "on" + type; 4474 4475 // Caller can pass in a jQuery.Event object, Object, or just an event type string 4476 event = event[ jQuery.expando ] ? 4477 event : 4478 new jQuery.Event( type, typeof event === "object" && event ); 4479 4480 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 4481 event.isTrigger = onlyHandlers ? 2 : 3; 4482 event.namespace = namespaces.join("."); 4483 event.namespace_re = event.namespace ? 4484 new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : 4485 null; 4486 4487 // Clean up the event in case it is being reused 4488 event.result = undefined; 4489 if ( !event.target ) { 4490 event.target = elem; 4491 } 4492 4493 // Clone any incoming data and prepend the event, creating the handler arg list 4494 data = data == null ? 4495 [ event ] : 4496 jQuery.makeArray( data, [ event ] ); 4497 4498 // Allow special events to draw outside the lines 4499 special = jQuery.event.special[ type ] || {}; 4500 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 4501 return; 4502 } 4503 4504 // Determine event propagation path in advance, per W3C events spec (#9951) 4505 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) 4506 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { 4507 4508 bubbleType = special.delegateType || type; 4509 if ( !rfocusMorph.test( bubbleType + type ) ) { 4510 cur = cur.parentNode; 4511 } 4512 for ( ; cur; cur = cur.parentNode ) { 4513 eventPath.push( cur ); 4514 tmp = cur; 4515 } 4516 4517 // Only add window if we got to document (e.g., not plain obj or detached DOM) 4518 if ( tmp === (elem.ownerDocument || document) ) { 4519 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 4520 } 4521 } 4522 4523 // Fire handlers on the event path 4524 i = 0; 4525 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { 4526 4527 event.type = i > 1 ? 4528 bubbleType : 4529 special.bindType || type; 4530 4531 // jQuery handler 4532 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); 4533 if ( handle ) { 4534 handle.apply( cur, data ); 4535 } 4536 4537 // Native handler 4538 handle = ontype && cur[ ontype ]; 4539 if ( handle && handle.apply && jQuery.acceptData( cur ) ) { 4540 event.result = handle.apply( cur, data ); 4541 if ( event.result === false ) { 4542 event.preventDefault(); 4543 } 4544 } 4545 } 4546 event.type = type; 4547 4548 // If nobody prevented the default action, do it now 4549 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 4550 4551 if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && 4552 jQuery.acceptData( elem ) ) { 4553 4554 // Call a native DOM method on the target with the same name name as the event. 4555 // Can't use an .isFunction() check here because IE6/7 fails that test. 4556 // Don't do default actions on window, that's where global variables be (#6170) 4557 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { 4558 4559 // Don't re-trigger an onFOO event when we call its FOO() method 4560 tmp = elem[ ontype ]; 4561 4562 if ( tmp ) { 4563 elem[ ontype ] = null; 4564 } 4565 4566 // Prevent re-triggering of the same event, since we already bubbled it above 4567 jQuery.event.triggered = type; 4568 try { 4569 elem[ type ](); 4570 } catch ( e ) { 4571 // IE<9 dies on focus/blur to hidden element (#1486,#12518) 4572 // only reproducible on winXP IE8 native, not IE9 in IE8 mode 4573 } 4574 jQuery.event.triggered = undefined; 4575 4576 if ( tmp ) { 4577 elem[ ontype ] = tmp; 4578 } 4579 } 4580 } 4581 } 4582 4583 return event.result; 4584 }, 4585 4586 dispatch: function( event ) { 4587 4588 // Make a writable jQuery.Event from the native event object 4589 event = jQuery.event.fix( event ); 4590 4591 var i, ret, handleObj, matched, j, 4592 handlerQueue = [], 4593 args = slice.call( arguments ), 4594 handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], 4595 special = jQuery.event.special[ event.type ] || {}; 4596 4597 // Use the fix-ed jQuery.Event rather than the (read-only) native event 4598 args[0] = event; 4599 event.delegateTarget = this; 4600 4601 // Call the preDispatch hook for the mapped type, and let it bail if desired 4602 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { 4603 return; 4604 } 4605 4606 // Determine handlers 4607 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); 4608 4609 // Run delegates first; they may want to stop propagation beneath us 4610 i = 0; 4611 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { 4612 event.currentTarget = matched.elem; 4613 4614 j = 0; 4615 while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { 4616 4617 // Triggered event must either 1) have no namespace, or 4618 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). 4619 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { 4620 4621 event.handleObj = handleObj; 4622 event.data = handleObj.data; 4623 4624 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) 4625 .apply( matched.elem, args ); 4626 4627 if ( ret !== undefined ) { 4628 if ( (event.result = ret) === false ) { 4629 event.preventDefault(); 4630 event.stopPropagation(); 4631 } 4632 } 4633 } 4634 } 4635 } 4636 4637 // Call the postDispatch hook for the mapped type 4638 if ( special.postDispatch ) { 4639 special.postDispatch.call( this, event ); 4640 } 4641 4642 return event.result; 4643 }, 4644 4645 handlers: function( event, handlers ) { 4646 var sel, handleObj, matches, i, 4647 handlerQueue = [], 4648 delegateCount = handlers.delegateCount, 4649 cur = event.target; 4650 4651 // Find delegate handlers 4652 // Black-hole SVG <use> instance trees (#13180)
4653 // Avoid non-left-click bubbling in Firefox (#3861) 4654 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { 4655 4656 /* jshint eqeqeq: false */ 4657 for ( ; cur != this; cur = cur.parentNode || this ) { 4658 /* jshint eqeqeq: true */ 4659 4660 // Don't check non-elements (#13208) 4661 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) 4662 if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { 4663 matches = []; 4664 for ( i = 0; i < delegateCount; i++ ) { 4665 handleObj = handlers[ i ]; 4666 4667 // Don't conflict with Object.prototype properties (#13203) 4668 sel = handleObj.selector + " "; 4669 4670 if ( matches[ sel ] === undefined ) { 4671 matches[ sel ] = handleObj.needsContext ? 4672 jQuery( sel, this ).index( cur ) >= 0 : 4673 jQuery.find( sel, this, null, [ cur ] ).length; 4674 } 4675 if ( matches[ sel ] ) { 4676 matches.push( handleObj ); 4677 } 4678 } 4679 if ( matches.length ) { 4680 handlerQueue.push({ elem: cur, handlers: matches }); 4681 } 4682 } 4683 } 4684 } 4685 4686 // Add the remaining (directly-bound) handlers 4687 if ( delegateCount < handlers.length ) { 4688 handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); 4689 } 4690 4691 return handlerQueue; 4692 }, 4693 4694 fix: function( event ) { 4695 if ( event[ jQuery.expando ] ) { 4696 return event; 4697 } 4698 4699 // Create a writable copy of the event object and normalize some properties 4700 var i, prop, copy, 4701 type = event.type, 4702 originalEvent = event, 4703 fixHook = this.fixHooks[ type ]; 4704 4705 if ( !fixHook ) { 4706 this.fixHooks[ type ] = fixHook = 4707 rmouseEvent.test( type ) ? this.mouseHooks : 4708 rkeyEvent.test( type ) ? this.keyHooks : 4709 {}; 4710 } 4711 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; 4712 4713 event = new jQuery.Event( originalEvent ); 4714 4715 i = copy.length; 4716 while ( i-- ) { 4717 prop = copy[ i ]; 4718 event[ prop ] = originalEvent[ prop ]; 4719 } 4720 4721 // Support: IE<9 4722 // Fix target property (#1925) 4723 if ( !event.target ) { 4724 event.target = originalEvent.srcElement || document; 4725 } 4726 4727 // Support: Chrome 23+, Safari? 4728 // Target should not be a text node (#504, #13143) 4729 if ( event.target.nodeType === 3 ) { 4730 event.target = event.target.parentNode; 4731 } 4732 4733 // Support: IE<9 4734 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) 4735 event.metaKey = !!event.metaKey; 4736 4737 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; 4738 }, 4739 4740 // Includes some event props shared by KeyEvent and MouseEvent 4741 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), 4742 4743 fixHooks: {}, 4744 4745 keyHooks: { 4746 props: "char charCode key keyCode".split(" "), 4747 filter: function( event, original ) { 4748 4749 // Add which for key events 4750 if ( event.which == null ) { 4751 event.which = original.charCode != null ? original.charCode : original.keyCode; 4752 } 4753 4754 return event; 4755 } 4756 }, 4757 4758 mouseHooks: { 4759 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), 4760 filter: function( event, original ) { 4761 var body, eventDoc, doc, 4762 button = original.button, 4763 fromElement = original.fromElement; 4764 4765 // Calculate pageX/Y if missing and clientX/Y available 4766 if ( event.pageX == null && original.clientX != null ) { 4767 eventDoc = event.target.ownerDocument || document; 4768 doc = eventDoc.documentElement; 4769 body = eventDoc.body; 4770 4771 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); 4772 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); 4773 } 4774 4775 // Add relatedTarget, if necessary 4776 if ( !event.relatedTarget && fromElement ) { 4777 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; 4778 } 4779 4780 // Add which for click: 1 === left; 2 === middle; 3 === right 4781 // Note: button is not normalized, so don't use it 4782 if ( !event.which && button !== undefined ) { 4783 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); 4784 } 4785 4786 return event; 4787 } 4788 }, 4789 4790 special: { 4791 load: { 4792 // Prevent triggered image.load events from bubbling to window.load 4793 noBubble: true 4794 }, 4795 focus: { 4796 // Fire native event if possible so blur/focus sequence is correct 4797 trigger: function() { 4798 if ( this !== safeActiveElement() && this.focus ) { 4799 try { 4800 this.focus(); 4801 return false;
4802 } catch ( e ) { 4803 // Support: IE<9 4804 // If we error on focus to hidden element (#1486, #12518), 4805 // let .trigger() run the handlers 4806 } 4807 } 4808 }, 4809 delegateType: "focusin" 4810 }, 4811 blur: { 4812 trigger: function() { 4813 if ( this === safeActiveElement() && this.blur ) { 4814 this.blur(); 4815 return false; 4816 } 4817 }, 4818 delegateType: "focusout" 4819 }, 4820 click: { 4821 // For checkbox, fire native event so checked state will be right 4822 trigger: function() { 4823 if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { 4824 this.click(); 4825 return false; 4826 } 4827 }, 4828 4829 // For cross-browser consistency, don't fire native .click() on links 4830 _default: function( event ) { 4831 return jQuery.nodeName( event.target, "a" ); 4832 } 4833 }, 4834 4835 beforeunload: { 4836 postDispatch: function( event ) { 4837 4838 // Even when returnValue equals to undefined Firefox will still show alert 4839 if ( event.result !== undefined ) { 4840 event.originalEvent.returnValue = event.result; 4841 } 4842 } 4843 } 4844 }, 4845 4846 simulate: function( type, elem, event, bubble ) { 4847 // Piggyback on a donor event to simulate a different one. 4848 // Fake originalEvent to avoid donor's stopPropagation, but if the 4849 // simulated event prevents default then we do the same on the donor. 4850 var e = jQuery.extend( 4851 new jQuery.Event(), 4852 event, 4853 { 4854 type: type, 4855 isSimulated: true, 4856 originalEvent: {} 4857 } 4858 ); 4859 if ( bubble ) { 4860 jQuery.event.trigger( e, null, elem ); 4861 } else { 4862 jQuery.event.dispatch.call( elem, e ); 4863 } 4864 if ( e.isDefaultPrevented() ) { 4865 event.preventDefault(); 4866 } 4867 } 4868}; 4869 4870jQuery.removeEvent = document.removeEventListener ? 4871 function( elem, type, handle ) { 4872 if ( elem.removeEventListener ) { 4873 elem.removeEventListener( type, handle, false ); 4874 } 4875 } : 4876 function( elem, type, handle ) { 4877 var name = "on" + type; 4878 4879 if ( elem.detachEvent ) { 4880 4881 // #8545, #7054, preventing memory leaks for custom events in IE6-8 4882 // detachEvent needed property on element, by name of that event, to properly expose it to GC 4883 if ( typeof elem[ name ] === strundefined ) { 4884 elem[ name ] = null; 4885 } 4886 4887 elem.detachEvent( name, handle ); 4888 } 4889 }; 4890 4891jQuery.Event = function( src, props ) { 4892 // Allow instantiation without the 'new' keyword 4893 if ( !(this instanceof jQuery.Event) ) { 4894 return new jQuery.Event( src, props ); 4895 } 4896 4897 // Event object 4898 if ( src && src.type ) { 4899 this.originalEvent = src; 4900 this.type = src.type; 4901 4902 // Events bubbling up the document may have been marked as prevented 4903 // by a handler lower down the tree; reflect the correct value. 4904 this.isDefaultPrevented = src.defaultPrevented || 4905 src.defaultPrevented === undefined && ( 4906 // Support: IE < 9 4907 src.returnValue === false || 4908 // Support: Android < 4.0 4909 src.getPreventDefault && src.getPreventDefault() ) ? 4910 returnTrue : 4911 returnFalse; 4912 4913 // Event type 4914 } else { 4915 this.type = src; 4916 } 4917 4918 // Put explicitly provided properties onto the event object 4919 if ( props ) { 4920 jQuery.extend( this, props ); 4921 } 4922 4923 // Create a timestamp if incoming event doesn't have one 4924 this.timeStamp = src && src.timeStamp || jQuery.now(); 4925 4926 // Mark it as fixed 4927 this[ jQuery.expando ] = true; 4928}; 4929 4930// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 4931// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 4932jQuery.Event.prototype = { 4933 isDefaultPrevented: returnFalse, 4934 isPropagationStopped: returnFalse, 4935 isImmediatePropagationStopped: returnFalse, 4936 4937 preventDefault: function() { 4938 var e = this.originalEvent; 4939 4940 this.isDefaultPrevented = returnTrue; 4941 if ( !e ) { 4942 return; 4943 } 4944 4945 // If preventDefault exists, run it on the original event 4946 if ( e.preventDefault ) { 4947 e.preventDefault(); 4948 4949 // Support: IE 4950 // Otherwise set the returnValue property of the original event to false 4951 } else { 4952 e.returnValue = false; 4953 } 4954 }, 4955 stopPropagation: function() { 4956 var e = this.originalEvent; 4957 4958 this.isPropagationStopped = returnTrue; 4959 if ( !e ) { 4960 return; 4961 } 4962 // If stopPropagation exists, run it on the original event 4963 if ( e.stopPropagation ) { 4964 e.stopPropagation(); 4965 } 4966
4967 // Support: IE 4968 // Set the cancelBubble property of the original event to true 4969 e.cancelBubble = true; 4970 }, 4971 stopImmediatePropagation: function() { 4972 this.isImmediatePropagationStopped = returnTrue; 4973 this.stopPropagation(); 4974 } 4975}; 4976 4977// Create mouseenter/leave events using mouseover/out and event-time checks 4978jQuery.each({ 4979 mouseenter: "mouseover", 4980 mouseleave: "mouseout" 4981}, function( orig, fix ) { 4982 jQuery.event.special[ orig ] = { 4983 delegateType: fix, 4984 bindType: fix, 4985 4986 handle: function( event ) { 4987 var ret, 4988 target = this, 4989 related = event.relatedTarget, 4990 handleObj = event.handleObj; 4991 4992 // For mousenter/leave call the handler if related is outside the target. 4993 // NB: No relatedTarget if the mouse left/entered the browser window 4994 if ( !related || (related !== target && !jQuery.contains( target, related )) ) { 4995 event.type = handleObj.origType; 4996 ret = handleObj.handler.apply( this, arguments ); 4997 event.type = fix; 4998 } 4999 return ret; 5000 } 5001 }; 5002}); 5003 5004// IE submit delegation 5005if ( !support.submitBubbles ) { 5006 5007 jQuery.event.special.submit = { 5008 setup: function() { 5009 // Only need this for delegated form submit events 5010 if ( jQuery.nodeName( this, "form" ) ) { 5011 return false; 5012 } 5013 5014 // Lazy-add a submit handler when a descendant form may potentially be submitted 5015 jQuery.event.add( this, "click._submit keypress._submit", function( e ) { 5016 // Node name check avoids a VML-related crash in IE (#9807) 5017 var elem = e.target, 5018 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; 5019 if ( form && !jQuery._data( form, "submitBubbles" ) ) { 5020 jQuery.event.add( form, "submit._submit", function( event ) { 5021 event._submit_bubble = true; 5022 }); 5023 jQuery._data( form, "submitBubbles", true ); 5024 } 5025 }); 5026 // return undefined since we don't need an event listener 5027 }, 5028 5029 postDispatch: function( event ) { 5030 // If form was submitted by the user, bubble the event up the tree 5031 if ( event._submit_bubble ) { 5032 delete event._submit_bubble; 5033 if ( this.parentNode && !event.isTrigger ) { 5034 jQuery.event.simulate( "submit", this.parentNode, event, true ); 5035 } 5036 } 5037 }, 5038 5039 teardown: function() { 5040 // Only need this for delegated form submit events 5041 if ( jQuery.nodeName( this, "form" ) ) { 5042 return false; 5043 } 5044 5045 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above 5046 jQuery.event.remove( this, "._submit" ); 5047 } 5048 }; 5049} 5050 5051// IE change delegation and checkbox/radio fix 5052if ( !support.changeBubbles ) { 5053 5054 jQuery.event.special.change = { 5055 5056 setup: function() { 5057 5058 if ( rformElems.test( this.nodeName ) ) { 5059 // IE doesn't fire change on a check/radio until blur; trigger it on click 5060 // after a propertychange. Eat the blur-change in special.change.handle. 5061 // This still fires onchange a second time for check/radio after blur. 5062 if ( this.type === "checkbox" || this.type === "radio" ) { 5063 jQuery.event.add( this, "propertychange._change", function( event ) { 5064 if ( event.originalEvent.propertyName === "checked" ) { 5065 this._just_changed = true; 5066 } 5067 }); 5068 jQuery.event.add( this, "click._change", function( event ) { 5069 if ( this._just_changed && !event.isTrigger ) { 5070 this._just_changed = false; 5071 } 5072 // Allow triggered, simulated change events (#11500) 5073 jQuery.event.simulate( "change", this, event, true ); 5074 }); 5075 } 5076 return false; 5077 } 5078 // Delegated event; lazy-add a change handler on descendant inputs 5079 jQuery.event.add( this, "beforeactivate._change", function( e ) { 5080 var elem = e.target; 5081 5082 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { 5083 jQuery.event.add( elem, "change._change", function( event ) { 5084 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { 5085 jQuery.event.simulate( "change", this.parentNode, event, true ); 5086 } 5087 }); 5088 jQuery._data( elem, "changeBubbles", true ); 5089 } 5090 }); 5091 }, 5092 5093 handle: function( event ) { 5094 var elem = event.target; 5095 5096 // Swallow native change events from checkbox/radio, we already triggered them above 5097 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { 5098 return event.handleObj.handler.apply( this, arguments ); 5099 } 5100 }, 5101 5102 teardown: function() { 5103 jQuery.event.remove( this, "._change" ); 5104 5105 return !rformElems.test( this.nodeName ); 5106 } 5107 }; 5108} 5109 5110// Create "bubbling" focus and blur events 5111if ( !support.focusinBubbles ) { 5112 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { 5113 5114 // Attach a single capturing handler on the document while someone wants focusin/focusout 5115 var handler = function( event ) { 5116 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); 5117 }; 5118 5119 jQuery.event.special[ fix ] = { 5120 setup: function() { 5121 var doc = this.ownerDocument || this, 5122 attaches = jQuery._data( doc, fix ); 5123 5124 if ( !attaches ) { 5125 doc.addEventListener( orig, handler, true ); 5126 } 5127 jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); 5128 }, 5129 teardown: function() { 5130 var doc = this.ownerDocument || this, 5131 attaches = jQuery._data( doc, fix ) - 1; 5132 5133 if ( !attaches ) { 5134 doc.removeEventListener( orig, handler, true ); 5135 jQuery._removeData( doc, fix ); 5136 } else { 5137 jQuery._data( doc, fix, attaches ); 5138 } 5139 } 5140 }; 5141 }); 5142} 5143 5144jQuery.fn.extend({ 5145 5146 on: function( types, selector, data, fn, /*INTERNAL*/ one ) { 5147 var type, origFn; 5148 5149 // Types can be a map of types/handlers 5150 if ( typeof types === "object" ) { 5151 // ( types-Object, selector, data ) 5152 if ( typeof selector !== "string" ) { 5153 // ( types-Object, data ) 5154 data = data || selector; 5155 selector = undefined; 5156 } 5157 for ( type in types ) { 5158 this.on( type, selector, data, types[ type ], one ); 5159 } 5160 return this; 5161 } 5162 5163 if ( data == null && fn == null ) { 5164 // ( types, fn ) 5165 fn = selector; 5166 data = selector = undefined; 5167 } else if ( fn == null ) { 5168 if ( typeof selector === "string" ) { 5169 // ( types, selector, fn ) 5170 fn = data; 5171 data = undefined; 5172 } else { 5173 // ( types, data, fn ) 5174 fn = data; 5175 data = selector; 5176 selector = undefined; 5177 } 5178 } 5179 if ( fn === false ) { 5180 fn = returnFalse; 5181 } else if ( !fn ) { 5182 return this; 5183 } 5184 5185 if ( one === 1 ) { 5186 origFn = fn; 5187 fn = function( event ) { 5188 // Can use an empty set, since event contains the info 5189 jQuery().off( event ); 5190 return origFn.apply( this, arguments ); 5191 }; 5192 // Use same guid so caller can remove using origFn 5193 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 5194 } 5195 return this.each( function() { 5196 jQuery.event.add( this, types, fn, data, selector ); 5197 }); 5198 }, 5199 one: function( types, selector, data, fn ) { 5200 return this.on( types, selector, data, fn, 1 ); 5201 }, 5202 off: function( types, selector, fn ) { 5203 var handleObj, type; 5204 if ( types && types.preventDefault && types.handleObj ) { 5205 // ( event ) dispatched jQuery.Event 5206 handleObj = types.handleObj; 5207 jQuery( types.delegateTarget ).off( 5208 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, 5209 handleObj.selector, 5210 handleObj.handler 5211 ); 5212 return this; 5213 } 5214 if ( typeof types === "object" ) { 5215 // ( types-object [, selector] ) 5216 for ( type in types ) { 5217 this.off( type, selector, types[ type ] ); 5218 } 5219 return this; 5220 } 5221 if ( selector === false || typeof selector === "function" ) { 5222 // ( types [, fn] ) 5223 fn = selector; 5224 selector = undefined; 5225 } 5226 if ( fn === false ) { 5227 fn = returnFalse; 5228 } 5229 return this.each(function() { 5230 jQuery.event.remove( this, types, fn, selector ); 5231 }); 5232 }, 5233 5234 trigger: function( type, data ) { 5235 return this.each(function() { 5236 jQuery.event.trigger( type, data, this ); 5237 }); 5238 }, 5239 triggerHandler: function( type, data ) { 5240 var elem = this[0]; 5241 if ( elem ) { 5242 return jQuery.event.trigger( type, data, elem, true ); 5243 } 5244 } 5245}); 5246 5247 5248function createSafeFragment( document ) { 5249 var list = nodeNames.split( "|" ), 5250 safeFrag = document.createDocumentFragment(); 5251 5252 if ( safeFrag.createElement ) { 5253 while ( list.length ) { 5254 safeFrag.createElement( 5255 list.pop() 5256 ); 5257 } 5258 } 5259 return safeFrag; 5260} 5261 5262var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + 5263 "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", 5264 rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, 5265 rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), 5266 rleadingWhitespace = /^\s+/, 5267 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, 5268 rtagName = /<([\w:]+)/, 5269 rtbody = /<tbody/i,
5270 rhtml = /<|&#?\w+;/, 5271 rnoInnerhtml = /<(?:script|style|link)/i, 5272 // checked="checked" or checked 5273 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 5274 rscriptType = /^$|\/(?:java|ecma)script/i, 5275 rscriptTypeMasked = /^true\/(.*)/, 5276 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, 5277 5278 // We have to close these tags to support XHTML (#13200) 5279 wrapMap = { 5280 option: [ 1, "<select multiple='multiple'>", "</select>" ], 5281 legend: [ 1, "<fieldset>", "</fieldset>" ], 5282 area: [ 1, "<map>", "</map>" ], 5283 param: [ 1, "<object>", "</object>" ], 5284 thead: [ 1, "<table>", "</table>" ], 5285 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 5286 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], 5287 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 5288 5289 // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, 5290 // unless wrapped in a div with non-breaking characters in front of it. 5291 _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ] 5292 }, 5293 safeFragment = createSafeFragment( document ), 5294 fragmentDiv = safeFragment.appendChild( document.createElement("div") ); 5295 5296wrapMap.optgroup = wrapMap.option; 5297wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 5298wrapMap.th = wrapMap.td; 5299 5300function getAll( context, tag ) { 5301 var elems, elem, 5302 i = 0, 5303 found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : 5304 typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : 5305 undefined; 5306 5307 if ( !found ) { 5308 for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { 5309 if ( !tag || jQuery.nodeName( elem, tag ) ) { 5310 found.push( elem ); 5311 } else { 5312 jQuery.merge( found, getAll( elem, tag ) ); 5313 } 5314 } 5315 } 5316 5317 return tag === undefined || tag && jQuery.nodeName( context, tag ) ? 5318 jQuery.merge( [ context ], found ) : 5319 found; 5320} 5321 5322// Used in buildFragment, fixes the defaultChecked property 5323function fixDefaultChecked( elem ) { 5324 if ( rcheckableType.test( elem.type ) ) { 5325 elem.defaultChecked = elem.checked; 5326 } 5327} 5328 5329// Support: IE<8 5330// Manipulating tables requires a tbody 5331function manipulationTarget( elem, content ) { 5332 return jQuery.nodeName( elem, "table" ) && 5333 jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? 5334 5335 elem.getElementsByTagName("tbody")[0] || 5336 elem.appendChild( elem.ownerDocument.createElement("tbody") ) : 5337 elem; 5338} 5339 5340// Replace/restore the type attribute of script elements for safe DOM manipulation 5341function disableScript( elem ) { 5342 elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; 5343 return elem; 5344} 5345function restoreScript( elem ) { 5346 var match = rscriptTypeMasked.exec( elem.type ); 5347 if ( match ) { 5348 elem.type = match[1]; 5349 } else { 5350 elem.removeAttribute("type"); 5351 } 5352 return elem; 5353} 5354 5355// Mark scripts as having already been evaluated 5356function setGlobalEval( elems, refElements ) { 5357 var elem, 5358 i = 0; 5359 for ( ; (elem = elems[i]) != null; i++ ) { 5360 jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); 5361 } 5362} 5363 5364function cloneCopyEvent( src, dest ) { 5365 5366 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { 5367 return; 5368 } 5369 5370 var type, i, l, 5371 oldData = jQuery._data( src ), 5372 curData = jQuery._data( dest, oldData ), 5373 events = oldData.events; 5374 5375 if ( events ) { 5376 delete curData.handle; 5377 curData.events = {}; 5378 5379 for ( type in events ) { 5380 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 5381 jQuery.event.add( dest, type, events[ type ][ i ] ); 5382 } 5383 } 5384 } 5385 5386 // make the cloned public data object a copy from the original 5387 if ( curData.data ) { 5388 curData.data = jQuery.extend( {}, curData.data ); 5389 } 5390} 5391 5392function fixCloneNodeIssues( src, dest ) { 5393 var nodeName, e, data; 5394 5395 // We do not need to do anything for non-Elements 5396 if ( dest.nodeType !== 1 ) { 5397 return; 5398 } 5399 5400 nodeName = dest.nodeName.toLowerCase(); 5401 5402 // IE6-8 copies events bound via attachEvent when using cloneNode. 5403 if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { 5404 data = jQuery._data( dest ); 5405 5406 for ( e in data.events ) { 5407 jQuery.removeEvent( dest, e, data.handle ); 5408 } 5409 5410 // Event data gets referenced instead of copied if the expando gets copied too 5411 dest.removeAttribute( jQuery.expando ); 5412 } 5413 5414 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text 5415 if ( nodeName === "script" && dest.text !== src.text ) { 5416 disableScript( dest ).text = src.text; 5417 restoreScript( dest ); 5418 5419 // IE6-10 improperly clones children of object elements using classid. 5420 // IE10 throws NoModificationAllowedError if parent is null, #12132. 5421 } else if ( nodeName === "object" ) { 5422 if ( dest.parentNode ) { 5423 dest.outerHTML = src.outerHTML; 5424 } 5425 5426 // This path appears unavoidable for IE9. When cloning an object 5427 // element in IE9, the outerHTML strategy above is not sufficient. 5428 // If the src has innerHTML and the destination does not, 5429 // copy the src.innerHTML into the dest.innerHTML. #10324 5430 if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { 5431 dest.innerHTML = src.innerHTML; 5432 } 5433 5434 } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { 5435 // IE6-8 fails to persist the checked state of a cloned checkbox 5436 // or radio button. Worse, IE6-7 fail to give the cloned element 5437 // a checked appearance if the defaultChecked value isn't also set 5438 5439 dest.defaultChecked = dest.checked = src.checked; 5440 5441 // IE6-7 get confused and end up setting the value of a cloned 5442 // checkbox/radio button to an empty string instead of "on" 5443 if ( dest.value !== src.value ) { 5444 dest.value = src.value; 5445 } 5446 5447 // IE6-8 fails to return the selected option to the default selected 5448 // state when cloning options 5449 } else if ( nodeName === "option" ) { 5450 dest.defaultSelected = dest.selected = src.defaultSelected; 5451 5452 // IE6-8 fails to set the defaultValue to the correct value when 5453 // cloning other types of input fields 5454 } else if ( nodeName === "input" || nodeName === "textarea" ) { 5455 dest.defaultValue = src.defaultValue; 5456 } 5457} 5458 5459jQuery.extend({ 5460 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 5461 var destElements, node, clone, i, srcElements, 5462 inPage = jQuery.contains( elem.ownerDocument, elem ); 5463 5464 if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { 5465 clone = elem.cloneNode( true ); 5466 5467 // IE<=8 does not properly clone detached, unknown element nodes 5468 } else { 5469 fragmentDiv.innerHTML = elem.outerHTML; 5470 fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); 5471 } 5472 5473 if ( (!support.noCloneEvent || !support.noCloneChecked) && 5474 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { 5475 5476 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 5477 destElements = getAll( clone ); 5478 srcElements = getAll( elem ); 5479 5480 // Fix all IE cloning issues 5481 for ( i = 0; (node = srcElements[i]) != null; ++i ) { 5482 // Ensure that the destination node is not null; Fixes #9587 5483 if ( destElements[i] ) {
5484 fixCloneNodeIssues( node, destElements[i] ); 5485 } 5486 } 5487 } 5488 5489 // Copy the events from the original to the clone 5490 if ( dataAndEvents ) { 5491 if ( deepDataAndEvents ) { 5492 srcElements = srcElements || getAll( elem ); 5493 destElements = destElements || getAll( clone ); 5494 5495 for ( i = 0; (node = srcElements[i]) != null; i++ ) { 5496 cloneCopyEvent( node, destElements[i] ); 5497 } 5498 } else { 5499 cloneCopyEvent( elem, clone ); 5500 } 5501 } 5502 5503 // Preserve script evaluation history 5504 destElements = getAll( clone, "script" ); 5505 if ( destElements.length > 0 ) { 5506 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); 5507 } 5508 5509 destElements = srcElements = node = null; 5510 5511 // Return the cloned set 5512 return clone; 5513 }, 5514 5515 buildFragment: function( elems, context, scripts, selection ) { 5516 var j, elem, contains, 5517 tmp, tag, tbody, wrap, 5518 l = elems.length, 5519 5520 // Ensure a safe fragment 5521 safe = createSafeFragment( context ), 5522 5523 nodes = [], 5524 i = 0; 5525 5526 for ( ; i < l; i++ ) { 5527 elem = elems[ i ]; 5528 5529 if ( elem || elem === 0 ) { 5530 5531 // Add nodes directly 5532 if ( jQuery.type( elem ) === "object" ) { 5533 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); 5534 5535 // Convert non-html into a text node 5536 } else if ( !rhtml.test( elem ) ) { 5537 nodes.push( context.createTextNode( elem ) ); 5538 5539 // Convert html into DOM nodes 5540 } else { 5541 tmp = tmp || safe.appendChild( context.createElement("div") ); 5542 5543 // Deserialize a standard representation 5544 tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); 5545 wrap = wrapMap[ tag ] || wrapMap._default; 5546 5547 tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2]; 5548 5549 // Descend through wrappers to the right content 5550 j = wrap[0]; 5551 while ( j-- ) { 5552 tmp = tmp.lastChild; 5553 } 5554 5555 // Manually add leading whitespace removed by IE 5556 if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { 5557 nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); 5558 } 5559 5560 // Remove IE's autoinserted <tbody> from table fragments 5561 if ( !support.tbody ) { 5562 5563 // String was a <table>, *may* have spurious <tbody> 5564 elem = tag === "table" && !rtbody.test( elem ) ? 5565 tmp.firstChild : 5566 5567 // String was a bare <thead> or <tfoot> 5568 wrap[1] === "<table>" && !rtbody.test( elem ) ? 5569 tmp : 5570 0; 5571 5572 j = elem && elem.childNodes.length; 5573 while ( j-- ) { 5574 if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { 5575 elem.removeChild( tbody ); 5576 } 5577 } 5578 } 5579 5580 jQuery.merge( nodes, tmp.childNodes ); 5581 5582 // Fix #12392 for WebKit and IE > 9 5583 tmp.textContent = ""; 5584 5585 // Fix #12392 for oldIE 5586 while ( tmp.firstChild ) { 5587 tmp.removeChild( tmp.firstChild ); 5588 } 5589 5590 // Remember the top-level container for proper cleanup 5591 tmp = safe.lastChild; 5592 } 5593 } 5594 } 5595 5596 // Fix #11356: Clear elements from fragment 5597 if ( tmp ) { 5598 safe.removeChild( tmp ); 5599 } 5600 5601 // Reset defaultChecked for any radios and checkboxes 5602 // about to be appended to the DOM in IE 6/7 (#8060) 5603 if ( !support.appendChecked ) { 5604 jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); 5605 } 5606 5607 i = 0; 5608 while ( (elem = nodes[ i++ ]) ) { 5609 5610 // #4087 - If origin and destination elements are the same, and this is 5611 // that element, do not do anything 5612 if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { 5613 continue; 5614 } 5615 5616 contains = jQuery.contains( elem.ownerDocument, elem ); 5617 5618 // Append to fragment 5619 tmp = getAll( safe.appendChild( elem ), "script" ); 5620 5621 // Preserve script evaluation history 5622 if ( contains ) { 5623 setGlobalEval( tmp ); 5624 } 5625 5626 // Capture executables 5627 if ( scripts ) { 5628 j = 0; 5629 while ( (elem = tmp[ j++ ]) ) { 5630 if ( rscriptType.test( elem.type || "" ) ) { 5631 scripts.push( elem ); 5632 } 5633 } 5634 } 5635 } 5636 5637 tmp = null; 5638 5639 return safe; 5640 }, 5641 5642 cleanData: function( elems, /* internal */ acceptData ) { 5643 var elem, type, id, data, 5644 i = 0, 5645 internalKey = jQuery.expando, 5646 cache = jQuery.cache, 5647 deleteExpando = support.deleteExpando, 5648 special = jQuery.event.special; 5649 5650 for ( ; (elem = elems[i]) != null; i++ ) { 5651 if ( acceptData || jQuery.acceptData( elem ) ) { 5652 5653 id = elem[ internalKey ];
5654 data = id && cache[ id ]; 5655 5656 if ( data ) { 5657 if ( data.events ) { 5658 for ( type in data.events ) { 5659 if ( special[ type ] ) { 5660 jQuery.event.remove( elem, type ); 5661 5662 // This is a shortcut to avoid jQuery.event.remove's overhead 5663 } else { 5664 jQuery.removeEvent( elem, type, data.handle ); 5665 } 5666 } 5667 } 5668 5669 // Remove cache only if it was not already removed by jQuery.event.remove 5670 if ( cache[ id ] ) { 5671 5672 delete cache[ id ]; 5673 5674 // IE does not allow us to delete expando properties from nodes, 5675 // nor does it have a removeAttribute function on Document nodes; 5676 // we must handle all of these cases 5677 if ( deleteExpando ) { 5678 delete elem[ internalKey ]; 5679 5680 } else if ( typeof elem.removeAttribute !== strundefined ) { 5681 elem.removeAttribute( internalKey ); 5682 5683 } else { 5684 elem[ internalKey ] = null; 5685 } 5686 5687 deletedIds.push( id ); 5688 } 5689 } 5690 } 5691 } 5692 } 5693}); 5694 5695jQuery.fn.extend({ 5696 text: function( value ) { 5697 return access( this, function( value ) { 5698 return value === undefined ? 5699 jQuery.text( this ) : 5700 this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); 5701 }, null, value, arguments.length ); 5702 }, 5703 5704 append: function() { 5705 return this.domManip( arguments, function( elem ) { 5706 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 5707 var target = manipulationTarget( this, elem ); 5708 target.appendChild( elem ); 5709 } 5710 }); 5711 }, 5712
5713 prepend: function() { 5714 return this.domManip( arguments, function( elem ) { 5715 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 5716 var target = manipulationTarget( this, elem ); 5717 target.insertBefore( elem, target.firstChild ); 5718 } 5719 }); 5720 }, 5721 5722 before: function() { 5723 return this.domManip( arguments, function( elem ) { 5724 if ( this.parentNode ) { 5725 this.parentNode.insertBefore( elem, this ); 5726 } 5727 }); 5728 }, 5729 5730 after: function() { 5731 return this.domManip( arguments, function( elem ) { 5732 if ( this.parentNode ) { 5733 this.parentNode.insertBefore( elem, this.nextSibling ); 5734 } 5735 }); 5736 }, 5737 5738 remove: function( selector, keepData /* Internal Use Only */ ) { 5739 var elem, 5740 elems = selector ? jQuery.filter( selector, this ) : this, 5741 i = 0; 5742 5743 for ( ; (elem = elems[i]) != null; i++ ) { 5744 5745 if ( !keepData && elem.nodeType === 1 ) { 5746 jQuery.cleanData( getAll( elem ) ); 5747 } 5748 5749 if ( elem.parentNode ) { 5750 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { 5751 setGlobalEval( getAll( elem, "script" ) ); 5752 } 5753 elem.parentNode.removeChild( elem ); 5754 } 5755 } 5756 5757 return this; 5758 }, 5759 5760 empty: function() { 5761 var elem, 5762 i = 0; 5763 5764 for ( ; (elem = this[i]) != null; i++ ) { 5765 // Remove element nodes and prevent memory leaks 5766 if ( elem.nodeType === 1 ) { 5767 jQuery.cleanData( getAll( elem, false ) ); 5768 } 5769 5770 // Remove any remaining nodes 5771 while ( elem.firstChild ) { 5772 elem.removeChild( elem.firstChild ); 5773 } 5774 5775 // If this is a select, ensure that it displays empty (#12336) 5776 // Support: IE<9 5777 if ( elem.options && jQuery.nodeName( elem, "select" ) ) { 5778 elem.options.length = 0; 5779 } 5780 } 5781 5782 return this; 5783 }, 5784 5785 clone: function( dataAndEvents, deepDataAndEvents ) { 5786 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 5787 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 5788 5789 return this.map(function() { 5790 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 5791 }); 5792 }, 5793 5794 html: function( value ) { 5795 return access( this, function( value ) { 5796 var elem = this[ 0 ] || {}, 5797 i = 0, 5798 l = this.length; 5799 5800 if ( value === undefined ) { 5801 return elem.nodeType === 1 ? 5802 elem.innerHTML.replace( rinlinejQuery, "" ) : 5803 undefined; 5804 } 5805 5806 // See if we can take a shortcut and just use innerHTML 5807 if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 5808 ( support.htmlSerialize || !rnoshimcache.test( value ) ) && 5809 ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && 5810 !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { 5811 5812 value = value.replace( rxhtmlTag, "<$1></$2>" ); 5813 5814 try { 5815 for (; i < l; i++ ) { 5816 // Remove element nodes and prevent memory leaks 5817 elem = this[i] || {}; 5818 if ( elem.nodeType === 1 ) { 5819 jQuery.cleanData( getAll( elem, false ) ); 5820 elem.innerHTML = value; 5821 } 5822 } 5823 5824 elem = 0; 5825 5826 // If using innerHTML throws an exception, use the fallback method 5827 } catch(e) {} 5828 } 5829 5830 if ( elem ) { 5831 this.empty().append( value ); 5832 } 5833 }, null, value, arguments.length ); 5834 }, 5835 5836 replaceWith: function() { 5837 var arg = arguments[ 0 ]; 5838 5839 // Make the changes, replacing each context element with the new content 5840 this.domManip( arguments, function( elem ) { 5841 arg = this.parentNode; 5842 5843 jQuery.cleanData( getAll( this ) ); 5844 5845 if ( arg ) { 5846 arg.replaceChild( elem, this ); 5847 } 5848 }); 5849 5850 // Force removal if there was no new content (e.g., from empty arguments) 5851 return arg && (arg.length || arg.nodeType) ? this : this.remove(); 5852 }, 5853 5854 detach: function( selector ) { 5855 return this.remove( selector, true ); 5856 }, 5857 5858 domManip: function( args, callback ) { 5859 5860 // Flatten any nested arrays 5861 args = concat.apply( [], args ); 5862 5863 var first, node, hasScripts, 5864 scripts, doc, fragment, 5865 i = 0, 5866 l = this.length, 5867 set = this, 5868 iNoClone = l - 1, 5869 value = args[0], 5870 isFunction = jQuery.isFunction( value ); 5871 5872 // We can't cloneNode fragments that contain checked, in WebKit 5873 if ( isFunction || 5874 ( l > 1 && typeof value === "string" && 5875 !support.checkClone && rchecked.test( value ) ) ) { 5876 return this.each(function( index ) { 5877 var self = set.eq( index ); 5878 if ( isFunction ) { 5879 args[0] = value.call( this, index, self.html() ); 5880 } 5881 self.domManip( args, callback ); 5882 }); 5883 } 5884 5885 if ( l ) { 5886 fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); 5887 first = fragment.firstChild; 5888 5889 if ( fragment.childNodes.length === 1 ) { 5890 fragment = first; 5891 } 5892 5893 if ( first ) { 5894 scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); 5895 hasScripts = scripts.length; 5896 5897 // Use the original fragment for the last item instead of the first because it can end up 5898 // being emptied incorrectly in certain situations (#8070). 5899 for ( ; i < l; i++ ) { 5900 node = fragment; 5901 5902 if ( i !== iNoClone ) { 5903 node = jQuery.clone( node, true, true ); 5904 5905 // Keep references to cloned scripts for later restoration 5906 if ( hasScripts ) { 5907 jQuery.merge( scripts, getAll( node, "script" ) ); 5908 } 5909 } 5910 5911 callback.call( this[i], node, i ); 5912 } 5913 5914 if ( hasScripts ) { 5915 doc = scripts[ scripts.length - 1 ].ownerDocument; 5916 5917 // Reenable scripts 5918 jQuery.map( scripts, restoreScript ); 5919 5920 // Evaluate executable scripts on first document insertion 5921 for ( i = 0; i < hasScripts; i++ ) { 5922 node = scripts[ i ]; 5923 if ( rscriptType.test( node.type || "" ) && 5924 !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { 5925 5926 if ( node.src ) {
5927 // Optional AJAX dependency, but won't run scripts if not present 5928 if ( jQuery._evalUrl ) { 5929 jQuery._evalUrl( node.src ); 5930 } 5931 } else { 5932 jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); 5933 } 5934 } 5935 } 5936 } 5937 5938 // Fix #11809: Avoid leaking memory 5939 fragment = first = null; 5940 } 5941 } 5942 5943 return this; 5944 } 5945}); 5946 5947jQuery.each({ 5948 appendTo: "append", 5949 prependTo: "prepend", 5950 insertBefore: "before", 5951 insertAfter: "after", 5952 replaceAll: "replaceWith" 5953}, function( name, original ) { 5954 jQuery.fn[ name ] = function( selector ) { 5955 var elems, 5956 i = 0, 5957 ret = [], 5958 insert = jQuery( selector ), 5959 last = insert.length - 1; 5960 5961 for ( ; i <= last; i++ ) { 5962 elems = i === last ? this : this.clone(true); 5963 jQuery( insert[i] )[ original ]( elems ); 5964 5965 // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() 5966 push.apply( ret, elems.get() ); 5967 } 5968 5969 return this.pushStack( ret ); 5970 }; 5971}); 5972 5973 5974var iframe, 5975 elemdisplay = {}; 5976 5977/** 5978 * Retrieve the actual display of a element 5979 * @param {String} name nodeName of the element 5980 * @param {Object} doc Document object 5981 */ 5982// Called only from within defaultDisplay 5983function actualDisplay( name, doc ) { 5984 var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), 5985 5986 // getDefaultComputedStyle might be reliably used only on attached element 5987 display = window.getDefaultComputedStyle ? 5988 5989 // Use of this method is a temporary fix (more like optmization) until something better comes along, 5990 // since it was removed from specification and supported only in FF 5991 window.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], "display" ); 5992 5993 // We don't have any data stored on the element, 5994 // so use "detach" method as fast way to get rid of the element 5995 elem.detach(); 5996 5997 return display; 5998} 5999 6000/** 6001 * Try to determine the default display value of an element 6002 * @param {String} nodeName 6003 */ 6004function defaultDisplay( nodeName ) { 6005 var doc = document, 6006 display = elemdisplay[ nodeName ]; 6007 6008 if ( !display ) { 6009 display = actualDisplay( nodeName, doc ); 6010 6011 // If the simple way fails, read from inside an iframe 6012 if ( display === "none" || !display ) { 6013 6014 // Use the already-created iframe if possible 6015 iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement ); 6016 6017 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse 6018 doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document; 6019 6020 // Support: IE 6021 doc.write(); 6022 doc.close(); 6023 6024 display = actualDisplay( nodeName, doc ); 6025 iframe.detach(); 6026 } 6027 6028 // Store the correct default display 6029 elemdisplay[ nodeName ] = display; 6030 } 6031 6032 return display; 6033} 6034 6035 6036(function() { 6037 var a, shrinkWrapBlocksVal, 6038 div = document.createElement( "div" ), 6039 divReset = 6040 "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;" + 6041 "display:block;padding:0;margin:0;border:0"; 6042 6043 // Setup 6044 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 6045 a = div.getElementsByTagName( "a" )[ 0 ]; 6046 6047 a.style.cssText = "float:left;opacity:.5"; 6048 6049 // Make sure that element opacity exists 6050 // (IE uses filter instead) 6051 // Use a regex to work around a WebKit issue. See #5145 6052 support.opacity = /^0.5/.test( a.style.opacity ); 6053 6054 // Verify style float existence 6055 // (IE uses styleFloat instead of cssFloat) 6056 support.cssFloat = !!a.style.cssFloat; 6057 6058 div.style.backgroundClip = "content-box"; 6059 div.cloneNode( true ).style.backgroundClip = ""; 6060 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 6061 6062 // Null elements to avoid leaks in IE. 6063 a = div = null; 6064 6065 support.shrinkWrapBlocks = function() { 6066 var body, container, div, containerStyles; 6067 6068 if ( shrinkWrapBlocksVal == null ) { 6069 body = document.getElementsByTagName( "body" )[ 0 ]; 6070 if ( !body ) { 6071 // Test fired too early or in an unsupported environment, exit. 6072 return; 6073 } 6074 6075 containerStyles = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px"; 6076 container = document.createElement( "div" ); 6077 div = document.createElement( "div" ); 6078 6079 body.appendChild( container ).appendChild( div ); 6080 6081 // Will be changed later if needed. 6082 shrinkWrapBlocksVal = false;
6083 6084 if ( typeof div.style.zoom !== strundefined ) { 6085 // Support: IE6 6086 // Check if elements with layout shrink-wrap their children 6087 div.style.cssText = divReset + ";width:1px;padding:1px;zoom:1"; 6088 div.innerHTML = "<div></div>"; 6089 div.firstChild.style.width = "5px"; 6090 shrinkWrapBlocksVal = div.offsetWidth !== 3; 6091 } 6092 6093 body.removeChild( container ); 6094 6095 // Null elements to avoid leaks in IE. 6096 body = container = div = null; 6097 } 6098 6099 return shrinkWrapBlocksVal; 6100 }; 6101 6102})(); 6103var rmargin = (/^margin/); 6104 6105var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 6106 6107 6108 6109var getStyles, curCSS, 6110 rposition = /^(top|right|bottom|left)$/; 6111 6112if ( window.getComputedStyle ) { 6113 getStyles = function( elem ) { 6114 return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); 6115 }; 6116 6117 curCSS = function( elem, name, computed ) { 6118 var width, minWidth, maxWidth, ret, 6119 style = elem.style; 6120 6121 computed = computed || getStyles( elem ); 6122 6123 // getPropertyValue is only needed for .css('filter') in IE9, see #12537 6124 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined; 6125 6126 if ( computed ) { 6127 6128 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { 6129 ret = jQuery.style( elem, name ); 6130 } 6131 6132 // A tribute to the "awesome hack by Dean Edwards" 6133 // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right 6134 // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels 6135 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values 6136 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { 6137 6138 // Remember the original values 6139 width = style.width; 6140 minWidth = style.minWidth; 6141 maxWidth = style.maxWidth; 6142 6143 // Put in the new values to get a computed value out 6144 style.minWidth = style.maxWidth = style.width = ret; 6145 ret = computed.width; 6146 6147 // Revert the changed values 6148 style.width = width; 6149 style.minWidth = minWidth; 6150 style.maxWidth = maxWidth; 6151 } 6152 } 6153 6154 // Support: IE 6155 // IE returns zIndex value as an integer. 6156 return ret === undefined ? 6157 ret : 6158 ret + ""; 6159 }; 6160} else if ( document.documentElement.currentStyle ) { 6161 getStyles = function( elem ) { 6162 return elem.currentStyle; 6163 }; 6164 6165 curCSS = function( elem, name, computed ) { 6166 var left, rs, rsLeft, ret, 6167 style = elem.style; 6168 6169 computed = computed || getStyles( elem ); 6170 ret = computed ? computed[ name ] : undefined; 6171 6172 // Avoid setting ret to empty string here 6173 // so we don't default to auto 6174 if ( ret == null && style && style[ name ] ) { 6175 ret = style[ name ]; 6176 } 6177 6178 // From the awesome hack by Dean Edwards 6179 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 6180 6181 // If we're not dealing with a regular pixel number 6182 // but a number that has a weird ending, we need to convert it to pixels 6183 // but not position css attributes, as those are proportional to the parent element instead 6184 // and we can't measure the parent instead because it might trigger a "stacking dolls" problem 6185 if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { 6186 6187 // Remember the original values 6188 left = style.left; 6189 rs = elem.runtimeStyle; 6190 rsLeft = rs && rs.left; 6191 6192 // Put in the new values to get a computed value out 6193 if ( rsLeft ) { 6194 rs.left = elem.currentStyle.left; 6195 } 6196 style.left = name === "fontSize" ? "1em" : ret; 6197 ret = style.pixelLeft + "px"; 6198 6199 // Revert the changed values 6200 style.left = left; 6201 if ( rsLeft ) { 6202 rs.left = rsLeft; 6203 } 6204 } 6205 6206 // Support: IE 6207 // IE returns zIndex value as an integer. 6208 return ret === undefined ? 6209 ret : 6210 ret + "" || "auto"; 6211 }; 6212} 6213 6214 6215 6216 6217function addGetHookIf( conditionFn, hookFn ) { 6218 // Define the hook, we'll check on the first run if it's really needed. 6219 return { 6220 get: function() { 6221 var condition = conditionFn(); 6222 6223 if ( condition == null ) { 6224 // The test was not ready at this point; screw the hook this time 6225 // but check again when needed next time. 6226 return; 6227 } 6228 6229 if ( condition ) { 6230 // Hook not needed (or it's not possible to use it due to missing dependency), 6231 // remove it. 6232 // Since there are no other hooks for marginRight, remove the whole object. 6233 delete this.get; 6234 return; 6235 } 6236 6237 // Hook needed; redefine it so that the support test is not executed again. 6238 6239 return (this.get = hookFn).apply( this, arguments ); 6240 } 6241 }; 6242} 6243 6244 6245(function() { 6246 var a, reliableHiddenOffsetsVal, boxSizingVal, boxSizingReliableVal, 6247 pixelPositionVal, reliableMarginRightVal, 6248 div = document.createElement( "div" ), 6249 containerStyles = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px",
6250 divReset = 6251 "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;" + 6252 "display:block;padding:0;margin:0;border:0"; 6253 6254 // Setup 6255 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 6256 a = div.getElementsByTagName( "a" )[ 0 ]; 6257 6258 a.style.cssText = "float:left;opacity:.5"; 6259 6260 // Make sure that element opacity exists 6261 // (IE uses filter instead) 6262 // Use a regex to work around a WebKit issue. See #5145 6263 support.opacity = /^0.5/.test( a.style.opacity ); 6264 6265 // Verify style float existence 6266 // (IE uses styleFloat instead of cssFloat) 6267 support.cssFloat = !!a.style.cssFloat; 6268 6269 div.style.backgroundClip = "content-box"; 6270 div.cloneNode( true ).style.backgroundClip = ""; 6271 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 6272 6273 // Null elements to avoid leaks in IE. 6274 a = div = null; 6275 6276 jQuery.extend(support, { 6277 reliableHiddenOffsets: function() { 6278 if ( reliableHiddenOffsetsVal != null ) { 6279 return reliableHiddenOffsetsVal; 6280 } 6281 6282 var container, tds, isSupported, 6283 div = document.createElement( "div" ), 6284 body = document.getElementsByTagName( "body" )[ 0 ]; 6285 6286 if ( !body ) { 6287 // Return for frameset docs that don't have a body 6288 return; 6289 } 6290 6291 // Setup 6292 div.setAttribute( "className", "t" ); 6293 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 6294 6295 container = document.createElement( "div" ); 6296 container.style.cssText = containerStyles; 6297 6298 body.appendChild( container ).appendChild( div ); 6299 6300 // Support: IE8 6301 // Check if table cells still have offsetWidth/Height when they are set 6302 // to display:none and there are still other visible table cells in a 6303 // table row; if so, offsetWidth/Height are not reliable for use when 6304 // determining if an element has been hidden directly using 6305 // display:none (it is still safe to use offsets if a parent element is 6306 // hidden; don safety goggles and see bug #4512 for more information). 6307 div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>"; 6308 tds = div.getElementsByTagName( "td" ); 6309 tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; 6310 isSupported = ( tds[ 0 ].offsetHeight === 0 ); 6311 6312 tds[ 0 ].style.display = ""; 6313 tds[ 1 ].style.display = "none"; 6314 6315 // Support: IE8 6316 // Check if empty table cells still have offsetWidth/Height 6317 reliableHiddenOffsetsVal = isSupported && ( tds[ 0 ].offsetHeight === 0 ); 6318 6319 body.removeChild( container ); 6320 6321 // Null elements to avoid leaks in IE. 6322 div = body = null; 6323 6324 return reliableHiddenOffsetsVal; 6325 }, 6326 6327 boxSizing: function() { 6328 if ( boxSizingVal == null ) { 6329 computeStyleTests(); 6330 } 6331 return boxSizingVal; 6332 }, 6333 6334 boxSizingReliable: function() { 6335 if ( boxSizingReliableVal == null ) { 6336 computeStyleTests(); 6337 } 6338 return boxSizingReliableVal; 6339 }, 6340 6341 pixelPosition: function() { 6342 if ( pixelPositionVal == null ) { 6343 computeStyleTests(); 6344 } 6345 return pixelPositionVal; 6346 }, 6347 6348 reliableMarginRight: function() { 6349 var body, container, div, marginDiv; 6350 6351 // Use window.getComputedStyle because jsdom on node.js will break without it. 6352 if ( reliableMarginRightVal == null && window.getComputedStyle ) { 6353 body = document.getElementsByTagName( "body" )[ 0 ]; 6354 if ( !body ) { 6355 // Test fired too early or in an unsupported environment, exit. 6356 return; 6357 } 6358 6359 container = document.createElement( "div" ); 6360 div = document.createElement( "div" ); 6361 container.style.cssText = containerStyles; 6362 6363 body.appendChild( container ).appendChild( div ); 6364 6365 // Check if div with explicit width and no margin-right incorrectly 6366 // gets computed margin-right based on width of container. (#3333) 6367 // Fails in WebKit before Feb 2011 nightlies 6368 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 6369 marginDiv = div.appendChild( document.createElement( "div" ) ); 6370 marginDiv.style.cssText = div.style.cssText = divReset; 6371 marginDiv.style.marginRight = marginDiv.style.width = "0"; 6372 div.style.width = "1px"; 6373 6374 reliableMarginRightVal = 6375 !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); 6376 6377 body.removeChild( container ); 6378 } 6379 6380 return reliableMarginRightVal; 6381 } 6382 }); 6383 6384 function computeStyleTests() { 6385 var container, div, 6386 body = document.getElementsByTagName( "body" )[ 0 ]; 6387 6388 if ( !body ) { 6389 // Test fired too early or in an unsupported environment, exit. 6390 return; 6391 } 6392 6393 container = document.createElement( "div" ); 6394 div = document.createElement( "div" ); 6395 container.style.cssText = containerStyles; 6396 6397 body.appendChild( container ).appendChild( div ); 6398 6399 div.style.cssText = 6400 "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" + 6401 "position:absolute;display:block;padding:1px;border:1px;width:4px;" + 6402 "margin-top:1%;top:1%"; 6403 6404 // Workaround failing boxSizing test due to offsetWidth returning wrong value 6405 // with some non-1 values of body zoom, ticket #13543 6406 jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() { 6407 boxSizingVal = div.offsetWidth === 4; 6408 }); 6409 6410 // Will be changed later if needed. 6411 boxSizingReliableVal = true; 6412 pixelPositionVal = false;
6413 reliableMarginRightVal = true; 6414 6415 // Use window.getComputedStyle because jsdom on node.js will break without it. 6416 if ( window.getComputedStyle ) { 6417 pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; 6418 boxSizingReliableVal = 6419 ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; 6420 } 6421 6422 body.removeChild( container ); 6423 6424 // Null elements to avoid leaks in IE. 6425 div = body = null; 6426 } 6427 6428})(); 6429 6430 6431// A method for quickly swapping in/out CSS properties to get correct calculations. 6432jQuery.swap = function( elem, options, callback, args ) { 6433 var ret, name, 6434 old = {}; 6435 6436 // Remember the old values, and insert the new ones 6437 for ( name in options ) { 6438 old[ name ] = elem.style[ name ]; 6439 elem.style[ name ] = options[ name ]; 6440 } 6441 6442 ret = callback.apply( elem, args || [] ); 6443 6444 // Revert the old values 6445 for ( name in options ) { 6446 elem.style[ name ] = old[ name ]; 6447 } 6448 6449 return ret; 6450}; 6451 6452 6453var 6454 ralpha = /alpha\([^)]*\)/i, 6455 ropacity = /opacity\s*=\s*([^)]*)/, 6456 6457 // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" 6458 // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display 6459 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 6460 rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ), 6461 rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ), 6462 6463 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 6464 cssNormalTransform = { 6465 letterSpacing: 0, 6466 fontWeight: 400 6467 }, 6468 6469 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; 6470 6471 6472// return a css property mapped to a potentially vendor prefixed property 6473function vendorPropName( style, name ) { 6474 6475 // shortcut for names that are not vendor prefixed 6476 if ( name in style ) { 6477 return name; 6478 } 6479 6480 // check for vendor prefixed names 6481 var capName = name.charAt(0).toUpperCase() + name.slice(1), 6482 origName = name, 6483 i = cssPrefixes.length; 6484 6485 while ( i-- ) { 6486 name = cssPrefixes[ i ] + capName; 6487 if ( name in style ) { 6488 return name; 6489 } 6490 } 6491 6492 return origName; 6493} 6494 6495function showHide( elements, show ) { 6496 var display, elem, hidden, 6497 values = [], 6498 index = 0, 6499 length = elements.length; 6500 6501 for ( ; index < length; index++ ) { 6502 elem = elements[ index ]; 6503 if ( !elem.style ) { 6504 continue; 6505 } 6506 6507 values[ index ] = jQuery._data( elem, "olddisplay" ); 6508 display = elem.style.display; 6509 if ( show ) { 6510 // Reset the inline display of this element to learn if it is 6511 // being hidden by cascaded rules or not 6512 if ( !values[ index ] && display === "none" ) { 6513 elem.style.display = ""; 6514 } 6515 6516 // Set elements which have been overridden with display: none 6517 // in a stylesheet to whatever the default browser style is 6518 // for such an element 6519 if ( elem.style.display === "" && isHidden( elem ) ) { 6520 values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); 6521 } 6522 } else { 6523 6524 if ( !values[ index ] ) { 6525 hidden = isHidden( elem ); 6526 6527 if ( display && display !== "none" || !hidden ) { 6528 jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); 6529 } 6530 } 6531 } 6532 } 6533 6534 // Set the display of most of the elements in a second loop 6535 // to avoid the constant reflow 6536 for ( index = 0; index < length; index++ ) { 6537 elem = elements[ index ]; 6538 if ( !elem.style ) { 6539 continue; 6540 } 6541 if ( !show || elem.style.display === "none" || elem.style.display === "" ) { 6542 elem.style.display = show ? values[ index ] || "" : "none"; 6543 } 6544 } 6545 6546 return elements; 6547} 6548 6549function setPositiveNumber( elem, value, subtract ) { 6550 var matches = rnumsplit.exec( value ); 6551 return matches ? 6552 // Guard against undefined "subtract", e.g., when used as in cssHooks 6553 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : 6554 value; 6555} 6556 6557function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { 6558 var i = extra === ( isBorderBox ? "border" : "content" ) ? 6559 // If we already have the right measurement, avoid augmentation 6560 4 : 6561 // Otherwise initialize for horizontal or vertical properties 6562 name === "width" ? 1 : 0, 6563 6564 val = 0; 6565 6566 for ( ; i < 4; i += 2 ) { 6567 // both box models exclude margin, so add it if we want it 6568 if ( extra === "margin" ) { 6569 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); 6570 } 6571 6572 if ( isBorderBox ) { 6573 // border-box includes padding, so remove it if we want content 6574 if ( extra === "content" ) { 6575 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6576 } 6577 6578 // at this point, extra isn't border nor margin, so remove border 6579 if ( extra !== "margin" ) { 6580 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6581 } 6582 } else { 6583 // at this point, extra isn't content, so add padding 6584 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6585 6586 // at this point, extra isn't content nor padding, so add border 6587 if ( extra !== "padding" ) { 6588 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6589 } 6590 } 6591 } 6592 6593 return val; 6594} 6595 6596function getWidthOrHeight( elem, name, extra ) { 6597 6598 // Start with offset property, which is equivalent to the border-box value 6599 var valueIsBorderBox = true, 6600 val = name === "width" ? elem.offsetWidth : elem.offsetHeight, 6601 styles = getStyles( elem ), 6602 isBorderBox = support.boxSizing() && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 6603 6604 // some non-html elements return undefined for offsetWidth, so check for null/undefined 6605 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 6606 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 6607 if ( val <= 0 || val == null ) { 6608 // Fall back to computed then uncomputed css if necessary 6609 val = curCSS( elem, name, styles ); 6610 if ( val < 0 || val == null ) { 6611 val = elem.style[ name ]; 6612 } 6613 6614 // Computed unit is not pixels. Stop here and return. 6615 if ( rnumnonpx.test(val) ) { 6616 return val; 6617 } 6618 6619 // we need the check for style in case a browser which returns unreliable values 6620 // for getComputedStyle silently falls back to the reliable elem.style 6621 valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] ); 6622 6623 // Normalize "", auto, and prepare for extra 6624 val = parseFloat( val ) || 0; 6625 } 6626 6627 // use the active box-sizing model to add/subtract irrelevant styles 6628 return ( val + 6629 augmentWidthOrHeight( 6630 elem, 6631 name, 6632 extra || ( isBorderBox ? "border" : "content" ), 6633 valueIsBorderBox, 6634 styles 6635 ) 6636 ) + "px"; 6637} 6638 6639jQuery.extend({ 6640 // Add in style property hooks for overriding the default 6641 // behavior of getting and setting a style property 6642 cssHooks: { 6643 opacity: { 6644 get: function( elem, computed ) { 6645 if ( computed ) { 6646 // We should always get a number back from opacity 6647 var ret = curCSS( elem, "opacity" ); 6648 return ret === "" ? "1" : ret; 6649 } 6650 } 6651 } 6652 }, 6653 6654 // Don't automatically add "px" to these possibly-unitless properties 6655 cssNumber: { 6656 "columnCount": true, 6657 "fillOpacity": true, 6658 "fontWeight": true, 6659 "lineHeight": true, 6660 "opacity": true, 6661 "order": true, 6662 "orphans": true, 6663 "widows": true, 6664 "zIndex": true, 6665 "zoom": true 6666 }, 6667 6668 // Add in properties whose names you wish to fix before 6669 // setting or getting the value 6670 cssProps: { 6671 // normalize float css property 6672 "float": support.cssFloat ? "cssFloat" : "styleFloat" 6673 }, 6674 6675 // Get and set the style property on a DOM Node 6676 style: function( elem, name, value, extra ) { 6677 // Don't set styles on text and comment nodes 6678 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 6679 return; 6680 } 6681 6682 // Make sure that we're working with the right name 6683 var ret, type, hooks, 6684 origName = jQuery.camelCase( name ), 6685 style = elem.style; 6686 6687 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); 6688 6689 // gets hook for the prefixed version 6690 // followed by the unprefixed version 6691 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 6692 6693 // Check if we're setting a value 6694 if ( value !== undefined ) { 6695 type = typeof value; 6696 6697 // convert relative number strings (+= or -=) to relative numbers. #7345 6698 if ( type === "string" && (ret = rrelNum.exec( value )) ) { 6699 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); 6700 // Fixes bug #9237 6701 type = "number"; 6702 } 6703 6704 // Make sure that null and NaN values aren't set. See: #7116 6705 if ( value == null || value !== value ) { 6706 return; 6707 } 6708 6709 // If a number was passed in, add 'px' to the (except for certain CSS properties) 6710 if ( type === "number" && !jQuery.cssNumber[ origName ] ) { 6711 value += "px"; 6712 } 6713 6714 // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, 6715 // but it would mean to define eight (for every problematic property) identical functions 6716 if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { 6717 style[ name ] = "inherit"; 6718 } 6719 6720 // If a hook was provided, use that value, otherwise just set the specified value 6721 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { 6722
6723 // Support: IE 6724 // Swallow errors from 'invalid' CSS values (#5509) 6725 try { 6726 // Support: Chrome, Safari 6727 // Setting style to blank string required to delete "style: x !important;" 6728 style[ name ] = ""; 6729 style[ name ] = value; 6730 } catch(e) {} 6731 } 6732 6733 } else { 6734 // If a hook was provided get the non-computed value from there 6735 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { 6736 return ret; 6737 } 6738 6739 // Otherwise just get the value from the style object 6740 return style[ name ]; 6741 } 6742 }, 6743 6744 css: function( elem, name, extra, styles ) { 6745 var num, val, hooks, 6746 origName = jQuery.camelCase( name ); 6747 6748 // Make sure that we're working with the right name 6749 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); 6750 6751 // gets hook for the prefixed version 6752 // followed by the unprefixed version 6753 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 6754 6755 // If a hook was provided get the computed value from there 6756 if ( hooks && "get" in hooks ) { 6757 val = hooks.get( elem, true, extra ); 6758 } 6759 6760 // Otherwise, if a way to get the computed value exists, use that 6761 if ( val === undefined ) { 6762 val = curCSS( elem, name, styles ); 6763 } 6764 6765 //convert "normal" to computed value 6766 if ( val === "normal" && name in cssNormalTransform ) { 6767 val = cssNormalTransform[ name ]; 6768 } 6769 6770 // Return, converting to number if forced or a qualifier was provided and val looks numeric 6771 if ( extra === "" || extra ) { 6772 num = parseFloat( val ); 6773 return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; 6774 } 6775 return val; 6776 } 6777}); 6778 6779jQuery.each([ "height", "width" ], function( i, name ) { 6780 jQuery.cssHooks[ name ] = { 6781 get: function( elem, computed, extra ) { 6782 if ( computed ) { 6783 // certain elements can have dimension info if we invisibly show them 6784 // however, it must have a current display style that would benefit from this 6785 return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ? 6786 jQuery.swap( elem, cssShow, function() { 6787 return getWidthOrHeight( elem, name, extra ); 6788 }) : 6789 getWidthOrHeight( elem, name, extra ); 6790 } 6791 }, 6792 6793 set: function( elem, value, extra ) { 6794 var styles = extra && getStyles( elem ); 6795 return setPositiveNumber( elem, value, extra ? 6796 augmentWidthOrHeight( 6797 elem, 6798 name, 6799 extra, 6800 support.boxSizing() && jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 6801 styles 6802 ) : 0 6803 ); 6804 } 6805 }; 6806}); 6807 6808if ( !support.opacity ) { 6809 jQuery.cssHooks.opacity = { 6810 get: function( elem, computed ) { 6811 // IE uses filters for opacity 6812 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? 6813 ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : 6814 computed ? "1" : ""; 6815 }, 6816 6817 set: function( elem, value ) { 6818 var style = elem.style, 6819 currentStyle = elem.currentStyle, 6820 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", 6821 filter = currentStyle && currentStyle.filter || style.filter || ""; 6822 6823 // IE has trouble with opacity if it does not have layout 6824 // Force it by setting the zoom level 6825 style.zoom = 1; 6826 6827 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 6828 // if value === "", then remove inline opacity #12685 6829 if ( ( value >= 1 || value === "" ) && 6830 jQuery.trim( filter.replace( ralpha, "" ) ) === "" && 6831 style.removeAttribute ) { 6832 6833 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText 6834 // if "filter:" is present at all, clearType is disabled, we want to avoid this 6835 // style.removeAttribute is IE Only, but so apparently is this code path... 6836 style.removeAttribute( "filter" ); 6837 6838 // if there is no filter style applied in a css rule or unset inline opacity, we are done 6839 if ( value === "" || currentStyle && !currentStyle.filter ) { 6840 return; 6841 } 6842 } 6843 6844 // otherwise, set new filter values 6845 style.filter = ralpha.test( filter ) ? 6846 filter.replace( ralpha, opacity ) : 6847 filter + " " + opacity; 6848 } 6849 }; 6850} 6851 6852jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight, 6853 function( elem, computed ) { 6854 if ( computed ) { 6855 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 6856 // Work around by temporarily setting element display to inline-block 6857 return jQuery.swap( elem, { "display": "inline-block" }, 6858 curCSS, [ elem, "marginRight" ] ); 6859 } 6860 } 6861); 6862 6863// These hooks are used by animate to expand properties 6864jQuery.each({ 6865 margin: "", 6866 padding: "", 6867 border: "Width" 6868}, function( prefix, suffix ) { 6869 jQuery.cssHooks[ prefix + suffix ] = { 6870 expand: function( value ) { 6871 var i = 0, 6872 expanded = {}, 6873 6874 // assumes a single number if not a string 6875 parts = typeof value === "string" ? value.split(" ") : [ value ]; 6876 6877 for ( ; i < 4; i++ ) { 6878 expanded[ prefix + cssExpand[ i ] + suffix ] = 6879 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 6880 } 6881 6882 return expanded; 6883 } 6884 }; 6885 6886 if ( !rmargin.test( prefix ) ) { 6887 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 6888 } 6889}); 6890 6891jQuery.fn.extend({ 6892 css: function( name, value ) { 6893 return access( this, function( elem, name, value ) { 6894 var styles, len, 6895 map = {}, 6896 i = 0; 6897 6898 if ( jQuery.isArray( name ) ) { 6899 styles = getStyles( elem ); 6900 len = name.length; 6901 6902 for ( ; i < len; i++ ) { 6903 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 6904 } 6905 6906 return map; 6907 } 6908 6909 return value !== undefined ? 6910 jQuery.style( elem, name, value ) : 6911 jQuery.css( elem, name ); 6912 }, name, value, arguments.length > 1 ); 6913 }, 6914 show: function() { 6915 return showHide( this, true ); 6916 }, 6917 hide: function() { 6918 return showHide( this ); 6919 }, 6920 toggle: function( state ) { 6921 if ( typeof state === "boolean" ) { 6922 return state ? this.show() : this.hide(); 6923 } 6924 6925 return this.each(function() { 6926 if ( isHidden( this ) ) { 6927 jQuery( this ).show(); 6928 } else { 6929 jQuery( this ).hide(); 6930 } 6931 }); 6932 } 6933}); 6934 6935 6936function Tween( elem, options, prop, end, easing ) { 6937 return new Tween.prototype.init( elem, options, prop, end, easing ); 6938} 6939jQuery.Tween = Tween; 6940
6941Tween.prototype = { 6942 constructor: Tween, 6943 init: function( elem, options, prop, end, easing, unit ) { 6944 this.elem = elem; 6945 this.prop = prop; 6946 this.easing = easing || "swing"; 6947 this.options = options; 6948 this.start = this.now = this.cur(); 6949 this.end = end; 6950 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); 6951 }, 6952 cur: function() { 6953 var hooks = Tween.propHooks[ this.prop ]; 6954 6955 return hooks && hooks.get ? 6956 hooks.get( this ) : 6957 Tween.propHooks._default.get( this ); 6958 }, 6959 run: function( percent ) { 6960 var eased, 6961 hooks = Tween.propHooks[ this.prop ]; 6962 6963 if ( this.options.duration ) { 6964 this.pos = eased = jQuery.easing[ this.easing ]( 6965 percent, this.options.duration * percent, 0, 1, this.options.duration 6966 ); 6967 } else { 6968 this.pos = eased = percent; 6969 } 6970 this.now = ( this.end - this.start ) * eased + this.start; 6971 6972 if ( this.options.step ) { 6973 this.options.step.call( this.elem, this.now, this ); 6974 } 6975 6976 if ( hooks && hooks.set ) { 6977 hooks.set( this ); 6978 } else { 6979 Tween.propHooks._default.set( this ); 6980 } 6981 return this; 6982 } 6983}; 6984 6985Tween.prototype.init.prototype = Tween.prototype; 6986 6987Tween.propHooks = { 6988 _default: { 6989 get: function( tween ) { 6990 var result; 6991 6992 if ( tween.elem[ tween.prop ] != null && 6993 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { 6994 return tween.elem[ tween.prop ]; 6995 } 6996 6997 // passing an empty string as a 3rd parameter to .css will automatically 6998 // attempt a parseFloat and fallback to a string if the parse fails 6999 // so, simple values such as "10px" are parsed to Float. 7000 // complex values such as "rotate(1rad)" are returned as is. 7001 result = jQuery.css( tween.elem, tween.prop, "" ); 7002 // Empty strings, null, undefined and "auto" are converted to 0. 7003 return !result || result === "auto" ? 0 : result; 7004 }, 7005 set: function( tween ) { 7006 // use step hook for back compat - use cssHook if its there - use .style if its 7007 // available and use plain properties where available 7008 if ( jQuery.fx.step[ tween.prop ] ) { 7009 jQuery.fx.step[ tween.prop ]( tween ); 7010 } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { 7011 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); 7012 } else { 7013 tween.elem[ tween.prop ] = tween.now; 7014 } 7015 } 7016 } 7017}; 7018 7019// Support: IE <=9 7020// Panic based approach to setting things on disconnected nodes 7021 7022Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { 7023 set: function( tween ) { 7024 if ( tween.elem.nodeType && tween.elem.parentNode ) { 7025 tween.elem[ tween.prop ] = tween.now; 7026 } 7027 } 7028}; 7029 7030jQuery.easing = { 7031 linear: function( p ) { 7032 return p; 7033 }, 7034 swing: function( p ) { 7035 return 0.5 - Math.cos( p * Math.PI ) / 2; 7036 } 7037}; 7038 7039jQuery.fx = Tween.prototype.init; 7040 7041// Back Compat <1.8 extension point 7042jQuery.fx.step = {}; 7043 7044 7045 7046 7047var 7048 fxNow, timerId, 7049 rfxtypes = /^(?:toggle|show|hide)$/, 7050 rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ), 7051 rrun = /queueHooks$/, 7052 animationPrefilters = [ defaultPrefilter ], 7053 tweeners = { 7054 "*": [ function( prop, value ) { 7055 var tween = this.createTween( prop, value ), 7056 target = tween.cur(), 7057 parts = rfxnum.exec( value ), 7058 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), 7059 7060 // Starting value computation is required for potential unit mismatches 7061 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) && 7062 rfxnum.exec( jQuery.css( tween.elem, prop ) ), 7063 scale = 1, 7064 maxIterations = 20; 7065 7066 if ( start && start[ 3 ] !== unit ) { 7067 // Trust units reported by jQuery.css 7068 unit = unit || start[ 3 ]; 7069 7070 // Make sure we update the tween properties later on 7071 parts = parts || []; 7072 7073 // Iteratively approximate from a nonzero starting point 7074 start = +target || 1; 7075 7076 do { 7077 // If previous iteration zeroed out, double until we get *something* 7078 // Use a string for doubling factor so we don't accidentally see scale as unchanged below 7079 scale = scale || ".5"; 7080 7081 // Adjust and apply 7082 start = start / scale; 7083 jQuery.style( tween.elem, prop, start + unit ); 7084 7085 // Update scale, tolerating zero or NaN from tween.cur() 7086 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough 7087 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); 7088 } 7089 7090 // Update tween properties 7091 if ( parts ) { 7092 start = tween.start = +start || +target || 0; 7093 tween.unit = unit; 7094 // If a +=/-= token was provided, we're doing a relative animation 7095 tween.end = parts[ 1 ] ? 7096 start + ( parts[ 1 ] + 1 ) * parts[ 2 ] : 7097 +parts[ 2 ]; 7098 } 7099 7100 return tween; 7101 } ] 7102 }; 7103 7104// Animations created synchronously will run synchronously 7105function createFxNow() { 7106 setTimeout(function() { 7107 fxNow = undefined; 7108 }); 7109 return ( fxNow = jQuery.now() ); 7110} 7111 7112// Generate parameters to create a standard animation 7113function genFx( type, includeWidth ) { 7114 var which, 7115 attrs = { height: type }, 7116 i = 0; 7117 7118 // if we include width, step value is 1 to do all cssExpand values, 7119 // if we don't include width, step value is 2 to skip over Left and Right 7120 includeWidth = includeWidth ? 1 : 0; 7121 for ( ; i < 4 ; i += 2 - includeWidth ) { 7122 which = cssExpand[ i ]; 7123 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; 7124 } 7125 7126 if ( includeWidth ) { 7127 attrs.opacity = attrs.width = type; 7128 } 7129 7130 return attrs; 7131} 7132 7133function createTween( value, prop, animation ) { 7134 var tween, 7135 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), 7136 index = 0, 7137 length = collection.length; 7138 for ( ; index < length; index++ ) { 7139 if ( (tween = collection[ index ].call( animation, prop, value )) ) { 7140 7141 // we're done with this property 7142 return tween; 7143 } 7144 } 7145} 7146 7147function defaultPrefilter( elem, props, opts ) { 7148 /* jshint validthis: true */ 7149 var prop, value, toggle, tween, hooks, oldfire, display, dDisplay, 7150 anim = this, 7151 orig = {}, 7152 style = elem.style, 7153 hidden = elem.nodeType && isHidden( elem ), 7154 dataShow = jQuery._data( elem, "fxshow" ); 7155 7156 // handle queue: false promises 7157 if ( !opts.queue ) { 7158 hooks = jQuery._queueHooks( elem, "fx" ); 7159 if ( hooks.unqueued == null ) { 7160 hooks.unqueued = 0; 7161 oldfire = hooks.empty.fire; 7162 hooks.empty.fire = function() { 7163 if ( !hooks.unqueued ) { 7164 oldfire(); 7165 } 7166 }; 7167 } 7168 hooks.unqueued++; 7169 7170 anim.always(function() { 7171 // doing this makes sure that the complete handler will be called 7172 // before this completes 7173 anim.always(function() { 7174 hooks.unqueued--; 7175 if ( !jQuery.queue( elem, "fx" ).length ) { 7176 hooks.empty.fire(); 7177 } 7178 }); 7179 }); 7180 } 7181 7182 // height/width overflow pass 7183 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { 7184 // Make sure that nothing sneaks out 7185 // Record all 3 overflow attributes because IE does not 7186 // change the overflow attribute when overflowX and 7187 // overflowY are set to the same value 7188 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; 7189 7190 // Set display property to inline-block for height/width 7191 // animations on inline elements that are having width/height animated
7192 display = jQuery.css( elem, "display" ); 7193 dDisplay = defaultDisplay( elem.nodeName ); 7194 if ( display === "none" ) { 7195 display = dDisplay; 7196 } 7197 if ( display === "inline" && 7198 jQuery.css( elem, "float" ) === "none" ) { 7199 7200 // inline-level elements accept inline-block; 7201 // block-level elements need to be inline with layout 7202 if ( !support.inlineBlockNeedsLayout || dDisplay === "inline" ) { 7203 style.display = "inline-block"; 7204 } else { 7205 style.zoom = 1; 7206 } 7207 } 7208 } 7209 7210 if ( opts.overflow ) { 7211 style.overflow = "hidden"; 7212 if ( !support.shrinkWrapBlocks() ) { 7213 anim.always(function() { 7214 style.overflow = opts.overflow[ 0 ]; 7215 style.overflowX = opts.overflow[ 1 ]; 7216 style.overflowY = opts.overflow[ 2 ]; 7217 }); 7218 } 7219 } 7220 7221 // show/hide pass 7222 for ( prop in props ) { 7223 value = props[ prop ]; 7224 if ( rfxtypes.exec( value ) ) { 7225 delete props[ prop ]; 7226 toggle = toggle || value === "toggle"; 7227 if ( value === ( hidden ? "hide" : "show" ) ) { 7228 7229 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden 7230 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { 7231 hidden = true; 7232 } else { 7233 continue; 7234 } 7235 } 7236 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); 7237 } 7238 } 7239 7240 if ( !jQuery.isEmptyObject( orig ) ) { 7241 if ( dataShow ) { 7242 if ( "hidden" in dataShow ) { 7243 hidden = dataShow.hidden; 7244 } 7245 } else { 7246 dataShow = jQuery._data( elem, "fxshow", {} ); 7247 } 7248 7249 // store state if its toggle - enables .stop().toggle() to "reverse" 7250 if ( toggle ) { 7251 dataShow.hidden = !hidden; 7252 } 7253 if ( hidden ) { 7254 jQuery( elem ).show(); 7255 } else { 7256 anim.done(function() { 7257 jQuery( elem ).hide(); 7258 }); 7259 } 7260 anim.done(function() { 7261 var prop; 7262 jQuery._removeData( elem, "fxshow" ); 7263 for ( prop in orig ) { 7264 jQuery.style( elem, prop, orig[ prop ] ); 7265 } 7266 }); 7267 for ( prop in orig ) { 7268 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); 7269 7270 if ( !( prop in dataShow ) ) { 7271 dataShow[ prop ] = tween.start; 7272 if ( hidden ) { 7273 tween.end = tween.start; 7274 tween.start = prop === "width" || prop === "height" ? 1 : 0; 7275 } 7276 } 7277 } 7278 } 7279} 7280 7281function propFilter( props, specialEasing ) { 7282 var index, name, easing, value, hooks; 7283 7284 // camelCase, specialEasing and expand cssHook pass 7285 for ( index in props ) { 7286 name = jQuery.camelCase( index ); 7287 easing = specialEasing[ name ]; 7288 value = props[ index ]; 7289 if ( jQuery.isArray( value ) ) { 7290 easing = value[ 1 ]; 7291 value = props[ index ] = value[ 0 ]; 7292 } 7293 7294 if ( index !== name ) { 7295 props[ name ] = value; 7296 delete props[ index ]; 7297 } 7298 7299 hooks = jQuery.cssHooks[ name ]; 7300 if ( hooks && "expand" in hooks ) { 7301 value = hooks.expand( value ); 7302 delete props[ name ]; 7303 7304 // not quite $.extend, this wont overwrite keys already present. 7305 // also - reusing 'index' from above because we have the correct "name" 7306 for ( index in value ) { 7307 if ( !( index in props ) ) { 7308 props[ index ] = value[ index ]; 7309 specialEasing[ index ] = easing; 7310 } 7311 } 7312 } else { 7313 specialEasing[ name ] = easing; 7314 } 7315 } 7316} 7317 7318function Animation( elem, properties, options ) { 7319 var result, 7320 stopped, 7321 index = 0, 7322 length = animationPrefilters.length, 7323 deferred = jQuery.Deferred().always( function() { 7324 // don't match elem in the :animated selector 7325 delete tick.elem; 7326 }), 7327 tick = function() { 7328 if ( stopped ) { 7329 return false; 7330 } 7331 var currentTime = fxNow || createFxNow(), 7332 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), 7333 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) 7334 temp = remaining / animation.duration || 0, 7335 percent = 1 - temp, 7336 index = 0, 7337 length = animation.tweens.length; 7338 7339 for ( ; index < length ; index++ ) { 7340 animation.tweens[ index ].run( percent ); 7341 } 7342 7343 deferred.notifyWith( elem, [ animation, percent, remaining ]); 7344 7345 if ( percent < 1 && length ) { 7346 return remaining; 7347 } else { 7348 deferred.resolveWith( elem, [ animation ] ); 7349 return false; 7350 } 7351 }, 7352 animation = deferred.promise({ 7353 elem: elem, 7354 props: jQuery.extend( {}, properties ), 7355 opts: jQuery.extend( true, { specialEasing: {} }, options ), 7356 originalProperties: properties, 7357 originalOptions: options, 7358 startTime: fxNow || createFxNow(), 7359 duration: options.duration, 7360 tweens: [], 7361 createTween: function( prop, end ) { 7362 var tween = jQuery.Tween( elem, animation.opts, prop, end, 7363 animation.opts.specialEasing[ prop ] || animation.opts.easing ); 7364 animation.tweens.push( tween ); 7365 return tween; 7366 }, 7367 stop: function( gotoEnd ) { 7368 var index = 0, 7369 // if we are going to the end, we want to run all the tweens 7370 // otherwise we skip this part 7371 length = gotoEnd ? animation.tweens.length : 0; 7372 if ( stopped ) { 7373 return this; 7374 } 7375 stopped = true; 7376 for ( ; index < length ; index++ ) { 7377 animation.tweens[ index ].run( 1 ); 7378 } 7379 7380 // resolve when we played the last frame 7381 // otherwise, reject 7382 if ( gotoEnd ) { 7383 deferred.resolveWith( elem, [ animation, gotoEnd ] ); 7384 } else { 7385 deferred.rejectWith( elem, [ animation, gotoEnd ] ); 7386 } 7387 return this; 7388 } 7389 }), 7390 props = animation.props; 7391 7392 propFilter( props, animation.opts.specialEasing ); 7393 7394 for ( ; index < length ; index++ ) { 7395 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); 7396 if ( result ) { 7397 return result; 7398 } 7399 } 7400 7401 jQuery.map( props, createTween, animation ); 7402 7403 if ( jQuery.isFunction( animation.opts.start ) ) { 7404 animation.opts.start.call( elem, animation ); 7405 } 7406 7407 jQuery.fx.timer( 7408 jQuery.extend( tick, { 7409 elem: elem, 7410 anim: animation, 7411 queue: animation.opts.queue 7412 }) 7413 ); 7414 7415 // attach callbacks from options 7416 return animation.progress( animation.opts.progress ) 7417 .done( animation.opts.done, animation.opts.complete ) 7418 .fail( animation.opts.fail ) 7419 .always( animation.opts.always ); 7420} 7421 7422jQuery.Animation = jQuery.extend( Animation, { 7423 tweener: function( props, callback ) { 7424 if ( jQuery.isFunction( props ) ) { 7425 callback = props; 7426 props = [ "*" ]; 7427 } else { 7428 props = props.split(" "); 7429 } 7430 7431 var prop, 7432 index = 0, 7433 length = props.length; 7434 7435 for ( ; index < length ; index++ ) { 7436 prop = props[ index ]; 7437 tweeners[ prop ] = tweeners[ prop ] || []; 7438 tweeners[ prop ].unshift( callback ); 7439 } 7440 }, 7441 7442 prefilter: function( callback, prepend ) { 7443 if ( prepend ) { 7444 animationPrefilters.unshift( callback ); 7445 } else { 7446 animationPrefilters.push( callback ); 7447 } 7448 } 7449}); 7450 7451jQuery.speed = function( speed, easing, fn ) { 7452 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 7453 complete: fn || !fn && easing || 7454 jQuery.isFunction( speed ) && speed, 7455 duration: speed, 7456 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing 7457 }; 7458 7459 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : 7460 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; 7461 7462 // normalize opt.queue - true/undefined/null -> "fx" 7463 if ( opt.queue == null || opt.queue === true ) { 7464 opt.queue = "fx"; 7465 } 7466 7467 // Queueing 7468 opt.old = opt.complete; 7469 7470 opt.complete = function() { 7471 if ( jQuery.isFunction( opt.old ) ) { 7472 opt.old.call( this ); 7473 } 7474 7475 if ( opt.queue ) { 7476 jQuery.dequeue( this, opt.queue ); 7477 } 7478 }; 7479 7480 return opt; 7481}; 7482 7483jQuery.fn.extend({ 7484 fadeTo: function( speed, to, easing, callback ) { 7485 7486 // show any hidden elements after setting opacity to 0 7487 return this.filter( isHidden ).css( "opacity", 0 ).show() 7488 7489 // animate to the value specified 7490 .end().animate({ opacity: to }, speed, easing, callback ); 7491 }, 7492 animate: function( prop, speed, easing, callback ) { 7493 var empty = jQuery.isEmptyObject( prop ), 7494 optall = jQuery.speed( speed, easing, callback ), 7495 doAnimation = function() { 7496 // Operate on a copy of prop so per-property easing won't be lost 7497 var anim = Animation( this, jQuery.extend( {}, prop ), optall ); 7498 7499 // Empty animations, or finishing resolves immediately 7500 if ( empty || jQuery._data( this, "finish" ) ) { 7501 anim.stop( true ); 7502 } 7503 }; 7504 doAnimation.finish = doAnimation; 7505 7506 return empty || optall.queue === false ? 7507 this.each( doAnimation ) : 7508 this.queue( optall.queue, doAnimation ); 7509 }, 7510 stop: function( type, clearQueue, gotoEnd ) { 7511 var stopQueue = function( hooks ) { 7512 var stop = hooks.stop; 7513 delete hooks.stop; 7514 stop( gotoEnd ); 7515 }; 7516 7517 if ( typeof type !== "string" ) { 7518 gotoEnd = clearQueue; 7519 clearQueue = type; 7520 type = undefined; 7521 } 7522 if ( clearQueue && type !== false ) { 7523 this.queue( type || "fx", [] ); 7524 } 7525 7526 return this.each(function() { 7527 var dequeue = true, 7528 index = type != null && type + "queueHooks", 7529 timers = jQuery.timers, 7530 data = jQuery._data( this ); 7531 7532 if ( index ) { 7533 if ( data[ index ] && data[ index ].stop ) { 7534 stopQueue( data[ index ] ); 7535 } 7536 } else { 7537 for ( index in data ) { 7538 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { 7539 stopQueue( data[ index ] ); 7540 } 7541 } 7542 } 7543 7544 for ( index = timers.length; index--; ) { 7545 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { 7546 timers[ index ].anim.stop( gotoEnd ); 7547 dequeue = false;
7548 timers.splice( index, 1 ); 7549 } 7550 } 7551 7552 // start the next in the queue if the last step wasn't forced 7553 // timers currently will call their complete callbacks, which will dequeue 7554 // but only if they were gotoEnd 7555 if ( dequeue || !gotoEnd ) { 7556 jQuery.dequeue( this, type ); 7557 } 7558 }); 7559 }, 7560 finish: function( type ) { 7561 if ( type !== false ) { 7562 type = type || "fx"; 7563 } 7564 return this.each(function() { 7565 var index, 7566 data = jQuery._data( this ), 7567 queue = data[ type + "queue" ], 7568 hooks = data[ type + "queueHooks" ], 7569 timers = jQuery.timers, 7570 length = queue ? queue.length : 0; 7571 7572 // enable finishing flag on private data 7573 data.finish = true; 7574 7575 // empty the queue first 7576 jQuery.queue( this, type, [] ); 7577 7578 if ( hooks && hooks.stop ) { 7579 hooks.stop.call( this, true ); 7580 } 7581 7582 // look for any active animations, and finish them 7583 for ( index = timers.length; index--; ) { 7584 if ( timers[ index ].elem === this && timers[ index ].queue === type ) { 7585 timers[ index ].anim.stop( true ); 7586 timers.splice( index, 1 ); 7587 } 7588 } 7589 7590 // look for any animations in the old queue and finish them 7591 for ( index = 0; index < length; index++ ) { 7592 if ( queue[ index ] && queue[ index ].finish ) { 7593 queue[ index ].finish.call( this ); 7594 } 7595 } 7596 7597 // turn off finishing flag 7598 delete data.finish; 7599 }); 7600 } 7601}); 7602 7603jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { 7604 var cssFn = jQuery.fn[ name ]; 7605 jQuery.fn[ name ] = function( speed, easing, callback ) { 7606 return speed == null || typeof speed === "boolean" ? 7607 cssFn.apply( this, arguments ) : 7608 this.animate( genFx( name, true ), speed, easing, callback ); 7609 }; 7610}); 7611 7612// Generate shortcuts for custom animations 7613jQuery.each({ 7614 slideDown: genFx("show"), 7615 slideUp: genFx("hide"), 7616 slideToggle: genFx("toggle"), 7617 fadeIn: { opacity: "show" }, 7618 fadeOut: { opacity: "hide" }, 7619 fadeToggle: { opacity: "toggle" } 7620}, function( name, props ) { 7621 jQuery.fn[ name ] = function( speed, easing, callback ) { 7622 return this.animate( props, speed, easing, callback ); 7623 }; 7624}); 7625 7626jQuery.timers = []; 7627jQuery.fx.tick = function() { 7628 var timer, 7629 timers = jQuery.timers, 7630 i = 0; 7631 7632 fxNow = jQuery.now(); 7633 7634 for ( ; i < timers.length; i++ ) { 7635 timer = timers[ i ]; 7636 // Checks the timer has not already been removed 7637 if ( !timer() && timers[ i ] === timer ) { 7638 timers.splice( i--, 1 ); 7639 } 7640 } 7641 7642 if ( !timers.length ) { 7643 jQuery.fx.stop(); 7644 } 7645 fxNow = undefined; 7646}; 7647 7648jQuery.fx.timer = function( timer ) { 7649 jQuery.timers.push( timer ); 7650 if ( timer() ) { 7651 jQuery.fx.start(); 7652 } else { 7653 jQuery.timers.pop(); 7654 } 7655}; 7656 7657jQuery.fx.interval = 13; 7658 7659jQuery.fx.start = function() { 7660 if ( !timerId ) { 7661 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); 7662 } 7663}; 7664 7665jQuery.fx.stop = function() { 7666 clearInterval( timerId ); 7667 timerId = null; 7668}; 7669 7670jQuery.fx.speeds = { 7671 slow: 600, 7672 fast: 200, 7673 // Default speed 7674 _default: 400 7675}; 7676 7677 7678// Based off of the plugin by Clint Helfers, with permission. 7679// http://blindsignals.com/index.php/2009/07/jquery-delay/
7680jQuery.fn.delay = function( time, type ) { 7681 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 7682 type = type || "fx"; 7683 7684 return this.queue( type, function( next, hooks ) { 7685 var timeout = setTimeout( next, time ); 7686 hooks.stop = function() { 7687 clearTimeout( timeout ); 7688 }; 7689 }); 7690}; 7691 7692 7693(function() { 7694 var a, input, select, opt, 7695 div = document.createElement("div" ); 7696 7697 // Setup 7698 div.setAttribute( "className", "t" ); 7699 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 7700 a = div.getElementsByTagName("a")[ 0 ]; 7701 7702 // First batch of tests. 7703 select = document.createElement("select"); 7704 opt = select.appendChild( document.createElement("option") ); 7705 input = div.getElementsByTagName("input")[ 0 ]; 7706 7707 a.style.cssText = "top:1px"; 7708 7709 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) 7710 support.getSetAttribute = div.className !== "t"; 7711 7712 // Get the style information from getAttribute 7713 // (IE uses .cssText instead) 7714 support.style = /top/.test( a.getAttribute("style") ); 7715 7716 // Make sure that URLs aren't manipulated 7717 // (IE normalizes it by default) 7718 support.hrefNormalized = a.getAttribute("href") === "/a"; 7719 7720 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) 7721 support.checkOn = !!input.value; 7722 7723 // Make sure that a selected-by-default option has a working selected property. 7724 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) 7725 support.optSelected = opt.selected; 7726 7727 // Tests for enctype support on a form (#6743) 7728 support.enctype = !!document.createElement("form").enctype; 7729 7730 // Make sure that the options inside disabled selects aren't marked as disabled 7731 // (WebKit marks them as disabled) 7732 select.disabled = true; 7733 support.optDisabled = !opt.disabled; 7734 7735 // Support: IE8 only 7736 // Check if we can trust getAttribute("value") 7737 input = document.createElement( "input" ); 7738 input.setAttribute( "value", "" ); 7739 support.input = input.getAttribute( "value" ) === ""; 7740 7741 // Check if an input maintains its value after becoming a radio 7742 input.value = "t"; 7743 input.setAttribute( "type", "radio" ); 7744 support.radioValue = input.value === "t"; 7745 7746 // Null elements to avoid leaks in IE. 7747 a = input = select = opt = div = null; 7748})(); 7749 7750 7751var rreturn = /\r/g; 7752 7753jQuery.fn.extend({ 7754 val: function( value ) { 7755 var hooks, ret, isFunction, 7756 elem = this[0]; 7757 7758 if ( !arguments.length ) { 7759 if ( elem ) { 7760 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; 7761 7762 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { 7763 return ret; 7764 } 7765 7766 ret = elem.value; 7767 7768 return typeof ret === "string" ? 7769 // handle most common string cases 7770 ret.replace(rreturn, "") : 7771 // handle cases where value is null/undef or number 7772 ret == null ? "" : ret; 7773 } 7774 7775 return; 7776 } 7777 7778 isFunction = jQuery.isFunction( value ); 7779 7780 return this.each(function( i ) { 7781 var val; 7782 7783 if ( this.nodeType !== 1 ) { 7784 return; 7785 } 7786 7787 if ( isFunction ) { 7788 val = value.call( this, i, jQuery( this ).val() ); 7789 } else { 7790 val = value; 7791 } 7792 7793 // Treat null/undefined as ""; convert numbers to string 7794 if ( val == null ) { 7795 val = ""; 7796 } else if ( typeof val === "number" ) { 7797 val += ""; 7798 } else if ( jQuery.isArray( val ) ) { 7799 val = jQuery.map( val, function( value ) { 7800 return value == null ? "" : value + ""; 7801 }); 7802 } 7803 7804 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; 7805 7806 // If set returns undefined, fall back to normal setting 7807 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { 7808 this.value = val; 7809 } 7810 }); 7811 } 7812}); 7813 7814jQuery.extend({ 7815 valHooks: { 7816 option: { 7817 get: function( elem ) { 7818 var val = jQuery.find.attr( elem, "value" ); 7819 return val != null ? 7820 val : 7821 jQuery.text( elem ); 7822 } 7823 }, 7824 select: { 7825 get: function( elem ) { 7826 var value, option, 7827 options = elem.options, 7828 index = elem.selectedIndex, 7829 one = elem.type === "select-one" || index < 0, 7830 values = one ? null : [], 7831 max = one ? index + 1 : options.length, 7832 i = index < 0 ? 7833 max : 7834 one ? index : 0; 7835 7836 // Loop through all the selected options 7837 for ( ; i < max; i++ ) { 7838 option = options[ i ]; 7839 7840 // oldIE doesn't update selected after form reset (#2551) 7841 if ( ( option.selected || i === index ) && 7842 // Don't return options that are disabled or in a disabled optgroup 7843 ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && 7844 ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { 7845 7846 // Get the specific value for the option 7847 value = jQuery( option ).val(); 7848 7849 // We don't need an array for one selects 7850 if ( one ) { 7851 return value; 7852 } 7853 7854 // Multi-Selects return an array 7855 values.push( value ); 7856 } 7857 } 7858 7859 return values; 7860 }, 7861 7862 set: function( elem, value ) { 7863 var optionSet, option, 7864 options = elem.options, 7865 values = jQuery.makeArray( value ), 7866 i = options.length; 7867 7868 while ( i-- ) { 7869 option = options[ i ]; 7870 7871 if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) { 7872
7873 // Support: IE6 7874 // When new option element is added to select box we need to 7875 // force reflow of newly added node in order to workaround delay 7876 // of initialization properties 7877 try { 7878 option.selected = optionSet = true; 7879 7880 } catch ( _ ) { 7881 7882 // Will be executed only in IE6 7883 option.scrollHeight; 7884 } 7885 7886 } else { 7887 option.selected = false; 7888 } 7889 } 7890 7891 // Force browsers to behave consistently when non-matching value is set 7892 if ( !optionSet ) { 7893 elem.selectedIndex = -1; 7894 } 7895 7896 return options; 7897 } 7898 } 7899 } 7900}); 7901 7902// Radios and checkboxes getter/setter 7903jQuery.each([ "radio", "checkbox" ], function() { 7904 jQuery.valHooks[ this ] = { 7905 set: function( elem, value ) { 7906 if ( jQuery.isArray( value ) ) { 7907 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); 7908 } 7909 } 7910 }; 7911 if ( !support.checkOn ) { 7912 jQuery.valHooks[ this ].get = function( elem ) { 7913 // Support: Webkit 7914 // "" is returned instead of "on" if a value isn't specified 7915 return elem.getAttribute("value") === null ? "on" : elem.value; 7916 }; 7917 } 7918}); 7919 7920 7921 7922 7923var nodeHook, boolHook, 7924 attrHandle = jQuery.expr.attrHandle, 7925 ruseDefault = /^(?:checked|selected)$/i, 7926 getSetAttribute = support.getSetAttribute, 7927 getSetInput = support.input; 7928 7929jQuery.fn.extend({ 7930 attr: function( name, value ) { 7931 return access( this, jQuery.attr, name, value, arguments.length > 1 ); 7932 }, 7933 7934 removeAttr: function( name ) { 7935 return this.each(function() { 7936 jQuery.removeAttr( this, name ); 7937 }); 7938 } 7939}); 7940 7941jQuery.extend({ 7942 attr: function( elem, name, value ) { 7943 var hooks, ret, 7944 nType = elem.nodeType; 7945 7946 // don't get/set attributes on text, comment and attribute nodes 7947 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { 7948 return; 7949 } 7950 7951 // Fallback to prop when attributes are not supported 7952 if ( typeof elem.getAttribute === strundefined ) { 7953 return jQuery.prop( elem, name, value ); 7954 } 7955 7956 // All attributes are lowercase 7957 // Grab necessary hook if one is defined 7958 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 7959 name = name.toLowerCase(); 7960 hooks = jQuery.attrHooks[ name ] || 7961 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); 7962 } 7963 7964 if ( value !== undefined ) { 7965 7966 if ( value === null ) { 7967 jQuery.removeAttr( elem, name ); 7968 7969 } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { 7970 return ret; 7971 7972 } else { 7973 elem.setAttribute( name, value + "" ); 7974 return value; 7975 } 7976 7977 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { 7978 return ret; 7979 7980 } else { 7981 ret = jQuery.find.attr( elem, name ); 7982 7983 // Non-existent attributes return null, we normalize to undefined 7984 return ret == null ? 7985 undefined : 7986 ret; 7987 } 7988 }, 7989 7990 removeAttr: function( elem, value ) { 7991 var name, propName, 7992 i = 0, 7993 attrNames = value && value.match( rnotwhite ); 7994 7995 if ( attrNames && elem.nodeType === 1 ) { 7996 while ( (name = attrNames[i++]) ) { 7997 propName = jQuery.propFix[ name ] || name; 7998 7999 // Boolean attributes get special treatment (#10870) 8000 if ( jQuery.expr.match.bool.test( name ) ) { 8001 // Set corresponding property to false 8002 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { 8003 elem[ propName ] = false; 8004 // Support: IE<9 8005 // Also clear defaultChecked/defaultSelected (if appropriate) 8006 } else { 8007 elem[ jQuery.camelCase( "default-" + name ) ] = 8008 elem[ propName ] = false; 8009 } 8010 8011 // See #9699 for explanation of this approach (setting first, then removal) 8012 } else { 8013 jQuery.attr( elem, name, "" ); 8014 } 8015 8016 elem.removeAttribute( getSetAttribute ? name : propName ); 8017 } 8018 } 8019 }, 8020 8021 attrHooks: { 8022 type: { 8023 set: function( elem, value ) { 8024 if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { 8025 // Setting the type on a radio button after the value resets the value in IE6-9 8026 // Reset value to default in case type is set after value during creation 8027 var val = elem.value; 8028 elem.setAttribute( "type", value ); 8029 if ( val ) { 8030 elem.value = val; 8031 } 8032 return value; 8033 } 8034 } 8035 } 8036 } 8037}); 8038 8039// Hook for boolean attributes 8040boolHook = { 8041 set: function( elem, value, name ) { 8042 if ( value === false ) { 8043 // Remove boolean attributes when set to false 8044 jQuery.removeAttr( elem, name ); 8045 } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
8046 // IE<8 needs the *property* name 8047 elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); 8048 8049 // Use defaultChecked and defaultSelected for oldIE 8050 } else { 8051 elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; 8052 } 8053 8054 return name; 8055 } 8056}; 8057 8058// Retrieve booleans specially 8059jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { 8060 8061 var getter = attrHandle[ name ] || jQuery.find.attr; 8062 8063 attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ? 8064 function( elem, name, isXML ) { 8065 var ret, handle; 8066 if ( !isXML ) { 8067 // Avoid an infinite loop by temporarily removing this function from the getter 8068 handle = attrHandle[ name ]; 8069 attrHandle[ name ] = ret; 8070 ret = getter( elem, name, isXML ) != null ? 8071 name.toLowerCase() : 8072 null; 8073 attrHandle[ name ] = handle; 8074 } 8075 return ret; 8076 } : 8077 function( elem, name, isXML ) { 8078 if ( !isXML ) { 8079 return elem[ jQuery.camelCase( "default-" + name ) ] ? 8080 name.toLowerCase() : 8081 null; 8082 } 8083 }; 8084}); 8085 8086// fix oldIE attroperties 8087if ( !getSetInput || !getSetAttribute ) { 8088 jQuery.attrHooks.value = { 8089 set: function( elem, value, name ) { 8090 if ( jQuery.nodeName( elem, "input" ) ) { 8091 // Does not return so that setAttribute is also used 8092 elem.defaultValue = value; 8093 } else { 8094 // Use nodeHook if defined (#1954); otherwise setAttribute is fine 8095 return nodeHook && nodeHook.set( elem, value, name ); 8096 } 8097 } 8098 }; 8099} 8100 8101// IE6/7 do not support getting/setting some attributes with get/setAttribute 8102if ( !getSetAttribute ) { 8103 8104 // Use this for any attribute in IE6/7 8105 // This fixes almost every IE6/7 issue 8106 nodeHook = { 8107 set: function( elem, value, name ) { 8108 // Set the existing or create a new attribute node 8109 var ret = elem.getAttributeNode( name ); 8110 if ( !ret ) { 8111 elem.setAttributeNode( 8112 (ret = elem.ownerDocument.createAttribute( name )) 8113 ); 8114 } 8115 8116 ret.value = value += ""; 8117 8118 // Break association with cloned elements by also using setAttribute (#9646) 8119 if ( name === "value" || value === elem.getAttribute( name ) ) { 8120 return value; 8121 } 8122 } 8123 }; 8124 8125 // Some attributes are constructed with empty-string values when not defined 8126 attrHandle.id = attrHandle.name = attrHandle.coords = 8127 function( elem, name, isXML ) { 8128 var ret; 8129 if ( !isXML ) { 8130 return (ret = elem.getAttributeNode( name )) && ret.value !== "" ? 8131 ret.value : 8132 null; 8133 } 8134 }; 8135 8136 // Fixing value retrieval on a button requires this module 8137 jQuery.valHooks.button = { 8138 get: function( elem, name ) { 8139 var ret = elem.getAttributeNode( name ); 8140 if ( ret && ret.specified ) { 8141 return ret.value; 8142 } 8143 }, 8144 set: nodeHook.set 8145 }; 8146 8147 // Set contenteditable to false on removals(#10429) 8148 // Setting to empty string throws an error as an invalid value 8149 jQuery.attrHooks.contenteditable = { 8150 set: function( elem, value, name ) { 8151 nodeHook.set( elem, value === "" ? false : value, name ); 8152 } 8153 }; 8154 8155 // Set width and height to auto instead of 0 on empty string( Bug #8150 ) 8156 // This is for removals 8157 jQuery.each([ "width", "height" ], function( i, name ) { 8158 jQuery.attrHooks[ name ] = { 8159 set: function( elem, value ) { 8160 if ( value === "" ) { 8161 elem.setAttribute( name, "auto" ); 8162 return value; 8163 } 8164 } 8165 }; 8166 }); 8167} 8168 8169if ( !support.style ) { 8170 jQuery.attrHooks.style = { 8171 get: function( elem ) { 8172 // Return undefined in the case of empty string 8173 // Note: IE uppercases css property names, but if we were to .toLowerCase() 8174 // .cssText, that would destroy case senstitivity in URL's, like in "background" 8175 return elem.style.cssText || undefined; 8176 }, 8177 set: function( elem, value ) { 8178 return ( elem.style.cssText = value + "" ); 8179 } 8180 }; 8181} 8182 8183 8184 8185 8186var rfocusable = /^(?:input|select|textarea|button|object)$/i, 8187 rclickable = /^(?:a|area)$/i; 8188 8189jQuery.fn.extend({ 8190 prop: function( name, value ) { 8191 return access( this, jQuery.prop, name, value, arguments.length > 1 ); 8192 }, 8193 8194 removeProp: function( name ) { 8195 name = jQuery.propFix[ name ] || name; 8196 return this.each(function() { 8197 // try/catch handles cases where IE balks (such as removing a property on window) 8198 try { 8199 this[ name ] = undefined; 8200 delete this[ name ]; 8201 } catch( e ) {} 8202 }); 8203 } 8204}); 8205 8206jQuery.extend({ 8207 propFix: { 8208 "for": "htmlFor", 8209 "class": "className" 8210 }, 8211 8212 prop: function( elem, name, value ) { 8213 var ret, hooks, notxml, 8214 nType = elem.nodeType; 8215 8216 // don't get/set properties on text, comment and attribute nodes 8217 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { 8218 return; 8219 } 8220 8221 notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); 8222 8223 if ( notxml ) { 8224 // Fix name and attach hooks 8225 name = jQuery.propFix[ name ] || name; 8226 hooks = jQuery.propHooks[ name ]; 8227 } 8228 8229 if ( value !== undefined ) { 8230 return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? 8231 ret : 8232 ( elem[ name ] = value ); 8233 8234 } else { 8235 return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? 8236 ret : 8237 elem[ name ]; 8238 } 8239 }, 8240 8241 propHooks: { 8242 tabIndex: { 8243 get: function( elem ) { 8244 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set 8245 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 8246 // Use proper attribute retrieval(#12072) 8247 var tabindex = jQuery.find.attr( elem, "tabindex" ); 8248 8249 return tabindex ? 8250 parseInt( tabindex, 10 ) : 8251 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 8252 0 : 8253 -1; 8254 } 8255 } 8256 } 8257}); 8258 8259// Some attributes require a special call on IE
8260// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 8261if ( !support.hrefNormalized ) { 8262 // href/src property should get the full normalized URL (#10299/#12915) 8263 jQuery.each([ "href", "src" ], function( i, name ) { 8264 jQuery.propHooks[ name ] = { 8265 get: function( elem ) { 8266 return elem.getAttribute( name, 4 ); 8267 } 8268 }; 8269 }); 8270} 8271 8272// Support: Safari, IE9+ 8273// mis-reports the default selected property of an option 8274// Accessing the parent's selectedIndex property fixes it 8275if ( !support.optSelected ) { 8276 jQuery.propHooks.selected = { 8277 get: function( elem ) { 8278 var parent = elem.parentNode; 8279 8280 if ( parent ) { 8281 parent.selectedIndex; 8282 8283 // Make sure that it also works with optgroups, see #5701 8284 if ( parent.parentNode ) { 8285 parent.parentNode.selectedIndex; 8286 } 8287 } 8288 return null; 8289 } 8290 }; 8291} 8292 8293jQuery.each([ 8294 "tabIndex", 8295 "readOnly", 8296 "maxLength", 8297 "cellSpacing", 8298 "cellPadding", 8299 "rowSpan", 8300 "colSpan", 8301 "useMap", 8302 "frameBorder", 8303 "contentEditable" 8304], function() { 8305 jQuery.propFix[ this.toLowerCase() ] = this; 8306}); 8307 8308// IE6/7 call enctype encoding 8309if ( !support.enctype ) { 8310 jQuery.propFix.enctype = "encoding"; 8311} 8312 8313 8314 8315 8316var rclass = /[\t\r\n\f]/g; 8317 8318jQuery.fn.extend({ 8319 addClass: function( value ) { 8320 var classes, elem, cur, clazz, j, finalValue, 8321 i = 0, 8322 len = this.length, 8323 proceed = typeof value === "string" && value; 8324 8325 if ( jQuery.isFunction( value ) ) { 8326 return this.each(function( j ) { 8327 jQuery( this ).addClass( value.call( this, j, this.className ) ); 8328 }); 8329 } 8330 8331 if ( proceed ) { 8332 // The disjunction here is for better compressibility (see removeClass) 8333 classes = ( value || "" ).match( rnotwhite ) || []; 8334 8335 for ( ; i < len; i++ ) { 8336 elem = this[ i ]; 8337 cur = elem.nodeType === 1 && ( elem.className ? 8338 ( " " + elem.className + " " ).replace( rclass, " " ) : 8339 " " 8340 ); 8341 8342 if ( cur ) { 8343 j = 0; 8344 while ( (clazz = classes[j++]) ) { 8345 if ( cur.indexOf( " " + clazz + " " ) < 0 ) { 8346 cur += clazz + " "; 8347 } 8348 } 8349 8350 // only assign if different to avoid unneeded rendering. 8351 finalValue = jQuery.trim( cur ); 8352 if ( elem.className !== finalValue ) { 8353 elem.className = finalValue; 8354 } 8355 } 8356 } 8357 } 8358 8359 return this; 8360 }, 8361 8362 removeClass: function( value ) { 8363 var classes, elem, cur, clazz, j, finalValue, 8364 i = 0, 8365 len = this.length, 8366 proceed = arguments.length === 0 || typeof value === "string" && value; 8367 8368 if ( jQuery.isFunction( value ) ) { 8369 return this.each(function( j ) { 8370 jQuery( this ).removeClass( value.call( this, j, this.className ) ); 8371 }); 8372 } 8373 if ( proceed ) { 8374 classes = ( value || "" ).match( rnotwhite ) || []; 8375 8376 for ( ; i < len; i++ ) { 8377 elem = this[ i ]; 8378 // This expression is here for better compressibility (see addClass) 8379 cur = elem.nodeType === 1 && ( elem.className ? 8380 ( " " + elem.className + " " ).replace( rclass, " " ) : 8381 "" 8382 ); 8383 8384 if ( cur ) { 8385 j = 0; 8386 while ( (clazz = classes[j++]) ) { 8387 // Remove *all* instances 8388 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { 8389 cur = cur.replace( " " + clazz + " ", " " ); 8390 } 8391 } 8392 8393 // only assign if different to avoid unneeded rendering. 8394 finalValue = value ? jQuery.trim( cur ) : ""; 8395 if ( elem.className !== finalValue ) { 8396 elem.className = finalValue; 8397 } 8398 } 8399 } 8400 } 8401 8402 return this; 8403 }, 8404 8405 toggleClass: function( value, stateVal ) { 8406 var type = typeof value; 8407 8408 if ( typeof stateVal === "boolean" && type === "string" ) { 8409 return stateVal ? this.addClass( value ) : this.removeClass( value ); 8410 } 8411 8412 if ( jQuery.isFunction( value ) ) { 8413 return this.each(function( i ) { 8414 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); 8415 }); 8416 } 8417 8418 return this.each(function() { 8419 if ( type === "string" ) { 8420 // toggle individual class names 8421 var className, 8422 i = 0, 8423 self = jQuery( this ), 8424 classNames = value.match( rnotwhite ) || []; 8425 8426 while ( (className = classNames[ i++ ]) ) { 8427 // check each className given, space separated list 8428 if ( self.hasClass( className ) ) { 8429 self.removeClass( className ); 8430 } else { 8431 self.addClass( className ); 8432 } 8433 } 8434 8435 // Toggle whole class name 8436 } else if ( type === strundefined || type === "boolean" ) { 8437 if ( this.className ) { 8438 // store className if set 8439 jQuery._data( this, "__className__", this.className ); 8440 } 8441 8442 // If the element has a class name or if we're passed "false", 8443 // then remove the whole classname (if there was one, the above saved it). 8444 // Otherwise bring back whatever was previously saved (if anything), 8445 // falling back to the empty string if nothing was stored. 8446 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; 8447 } 8448 }); 8449 }, 8450 8451 hasClass: function( selector ) { 8452 var className = " " + selector + " ", 8453 i = 0, 8454 l = this.length; 8455 for ( ; i < l; i++ ) { 8456 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { 8457 return true; 8458 } 8459 } 8460 8461 return false;
8462 } 8463}); 8464 8465 8466 8467 8468// Return jQuery for attributes-only inclusion 8469 8470 8471jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + 8472 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 8473 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { 8474 8475 // Handle event binding 8476 jQuery.fn[ name ] = function( data, fn ) { 8477 return arguments.length > 0 ? 8478 this.on( name, null, data, fn ) : 8479 this.trigger( name ); 8480 }; 8481}); 8482 8483jQuery.fn.extend({ 8484 hover: function( fnOver, fnOut ) { 8485 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 8486 }, 8487 8488 bind: function( types, data, fn ) { 8489 return this.on( types, null, data, fn ); 8490 }, 8491 unbind: function( types, fn ) { 8492 return this.off( types, null, fn ); 8493 }, 8494 8495 delegate: function( selector, types, data, fn ) { 8496 return this.on( types, selector, data, fn ); 8497 }, 8498 undelegate: function( selector, types, fn ) { 8499 // ( namespace ) or ( selector, types [, fn] ) 8500 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); 8501 } 8502}); 8503 8504 8505var nonce = jQuery.now(); 8506 8507var rquery = (/\?/); 8508 8509 8510 8511var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g; 8512 8513jQuery.parseJSON = function( data ) { 8514 // Attempt to parse using the native JSON parser first 8515 if ( window.JSON && window.JSON.parse ) { 8516 // Support: Android 2.3 8517 // Workaround failure to string-cast null input 8518 return window.JSON.parse( data + "" ); 8519 } 8520 8521 var requireNonComma, 8522 depth = null, 8523 str = jQuery.trim( data + "" ); 8524 8525 // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains 8526 // after removing valid tokens 8527 return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) { 8528 8529 // Force termination if we see a misplaced comma 8530 if ( requireNonComma && comma ) { 8531 depth = 0; 8532 } 8533 8534 // Perform no more replacements after returning to outermost depth 8535 if ( depth === 0 ) { 8536 return token; 8537 } 8538 8539 // Commas must not follow "[", "{", or "," 8540 requireNonComma = open || comma; 8541 8542 // Determine new depth 8543 // array/object open ("[" or "{"): depth += true - false (increment) 8544 // array/object close ("]" or "}"): depth += false - true (decrement) 8545 // other cases ("," or primitive): depth += true - true (numeric cast) 8546 depth += !close - !open; 8547 8548 // Remove this token 8549 return ""; 8550 }) ) ? 8551 ( Function( "return " + str ) )() : 8552 jQuery.error( "Invalid JSON: " + data ); 8553}; 8554 8555 8556// Cross-browser xml parsing 8557jQuery.parseXML = function( data ) { 8558 var xml, tmp; 8559 if ( !data || typeof data !== "string" ) { 8560 return null; 8561 } 8562 try { 8563 if ( window.DOMParser ) { // Standard 8564 tmp = new DOMParser(); 8565 xml = tmp.parseFromString( data, "text/xml" ); 8566 } else { // IE 8567 xml = new ActiveXObject( "Microsoft.XMLDOM" ); 8568 xml.async = "false"; 8569 xml.loadXML( data ); 8570 } 8571 } catch( e ) { 8572 xml = undefined; 8573 } 8574 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { 8575 jQuery.error( "Invalid XML: " + data ); 8576 } 8577 return xml; 8578}; 8579 8580 8581var 8582 // Document location 8583 ajaxLocParts, 8584 ajaxLocation, 8585 8586 rhash = /#.*$/, 8587 rts = /([?&])_=[^&]*/, 8588 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL 8589 // #7653, #8125, #8152: local protocol detection 8590 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, 8591 rnoContent = /^(?:GET|HEAD)$/, 8592 rprotocol = /^\/\//, 8593 rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/, 8594 8595 /* Prefilters 8596 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 8597 * 2) These are called: 8598 * - BEFORE asking for a transport 8599 * - AFTER param serialization (s.data is a string if s.processData is true) 8600 * 3) key is the dataType 8601 * 4) the catchall symbol "*" can be used 8602 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 8603 */ 8604 prefilters = {}, 8605 8606 /* Transports bindings 8607 * 1) key is the dataType 8608 * 2) the catchall symbol "*" can be used 8609 * 3) selection will start with transport dataType and THEN go to "*" if needed 8610 */ 8611 transports = {}, 8612 8613 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression 8614 allTypes = "*/".concat("*"); 8615 8616// #8138, IE may throw an exception when accessing 8617// a field from window.location if document.domain has been set 8618try { 8619 ajaxLocation = location.href; 8620} catch( e ) { 8621 // Use the href attribute of an A element 8622 // since IE will modify it given document.location 8623 ajaxLocation = document.createElement( "a" ); 8624 ajaxLocation.href = ""; 8625 ajaxLocation = ajaxLocation.href; 8626} 8627 8628// Segment location into parts 8629ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; 8630 8631// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 8632function addToPrefiltersOrTransports( structure ) { 8633 8634 // dataTypeExpression is optional and defaults to "*" 8635 return function( dataTypeExpression, func ) { 8636 8637 if ( typeof dataTypeExpression !== "string" ) { 8638 func = dataTypeExpression; 8639 dataTypeExpression = "*"; 8640 } 8641 8642 var dataType, 8643 i = 0, 8644 dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || []; 8645 8646 if ( jQuery.isFunction( func ) ) { 8647 // For each dataType in the dataTypeExpression
vendor: 4,101 bytes, lines 8648-8797
8648 while ( (dataType = dataTypes[i++]) ) { 8649 // Prepend if requested 8650 if ( dataType.charAt( 0 ) === "+" ) { 8651 dataType = dataType.slice( 1 ) || "*"; 8652 (structure[ dataType ] = structure[ dataType ] || []).unshift( func ); 8653 8654 // Otherwise append 8655 } else { 8656 (structure[ dataType ] = structure[ dataType ] || []).push( func ); 8657 } 8658 } 8659 } 8660 }; 8661} 8662 8663// Base inspection function for prefilters and transports 8664function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { 8665 8666 var inspected = {}, 8667 seekingTransport = ( structure === transports ); 8668 8669 function inspect( dataType ) { 8670 var selected; 8671 inspected[ dataType ] = true; 8672 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { 8673 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); 8674 if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) { 8675 options.dataTypes.unshift( dataTypeOrTransport ); 8676 inspect( dataTypeOrTransport ); 8677 return false; 8678 } else if ( seekingTransport ) { 8679 return !( selected = dataTypeOrTransport ); 8680 } 8681 }); 8682 return selected; 8683 } 8684 8685 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); 8686} 8687 8688// A special extend for ajax options 8689// that takes "flat" options (not to be deep extended) 8690// Fixes #9887 8691function ajaxExtend( target, src ) { 8692 var deep, key, 8693 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 8694 8695 for ( key in src ) { 8696 if ( src[ key ] !== undefined ) { 8697 ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ]; 8698 } 8699 } 8700 if ( deep ) { 8701 jQuery.extend( true, target, deep ); 8702 } 8703 8704 return target; 8705} 8706 8707/* Handles responses to an ajax request: 8708 * - finds the right dataType (mediates between content-type and expected dataType) 8709 * - returns the corresponding response 8710 */ 8711function ajaxHandleResponses( s, jqXHR, responses ) { 8712 var firstDataType, ct, finalDataType, type, 8713 contents = s.contents, 8714 dataTypes = s.dataTypes; 8715 8716 // Remove auto dataType and get content-type in the process 8717 while ( dataTypes[ 0 ] === "*" ) { 8718 dataTypes.shift(); 8719 if ( ct === undefined ) { 8720 ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); 8721 } 8722 } 8723 8724 // Check if we're dealing with a known content-type 8725 if ( ct ) { 8726 for ( type in contents ) { 8727 if ( contents[ type ] && contents[ type ].test( ct ) ) { 8728 dataTypes.unshift( type ); 8729 break; 8730 } 8731 } 8732 } 8733 8734 // Check to see if we have a response for the expected dataType 8735 if ( dataTypes[ 0 ] in responses ) { 8736 finalDataType = dataTypes[ 0 ]; 8737 } else { 8738 // Try convertible dataTypes 8739 for ( type in responses ) { 8740 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { 8741 finalDataType = type; 8742 break; 8743 } 8744 if ( !firstDataType ) { 8745 firstDataType = type; 8746 } 8747 } 8748 // Or just use first one 8749 finalDataType = finalDataType || firstDataType; 8750 } 8751 8752 // If we found a dataType 8753 // We add the dataType to the list if needed 8754 // and return the corresponding response 8755 if ( finalDataType ) { 8756 if ( finalDataType !== dataTypes[ 0 ] ) { 8757 dataTypes.unshift( finalDataType ); 8758 } 8759 return responses[ finalDataType ]; 8760 } 8761} 8762 8763/* Chain conversions given the request and the original response 8764 * Also sets the responseXXX fields on the jqXHR instance 8765 */ 8766function ajaxConvert( s, response, jqXHR, isSuccess ) { 8767 var conv2, current, conv, tmp, prev, 8768 converters = {}, 8769 // Work with a copy of dataTypes in case we need to modify it for conversion 8770 dataTypes = s.dataTypes.slice(); 8771 8772 // Create converters map with lowercased keys 8773 if ( dataTypes[ 1 ] ) { 8774 for ( conv in s.converters ) { 8775 converters[ conv.toLowerCase() ] = s.converters[ conv ]; 8776 } 8777 } 8778 8779 current = dataTypes.shift(); 8780 8781 // Convert to each sequential dataType 8782 while ( current ) { 8783 8784 if ( s.responseFields[ current ] ) { 8785 jqXHR[ s.responseFields[ current ] ] = response; 8786 } 8787 8788 // Apply the dataFilter if provided 8789 if ( !prev && isSuccess && s.dataFilter ) { 8790 response = s.dataFilter( response, s.dataType ); 8791 } 8792 8793 prev = current; 8794 current = dataTypes.shift(); 8795 8796 if ( current ) { 8797
8798 // There's only work to do if current dataType is non-auto 8799 if ( current === "*" ) { 8800 8801 current = prev; 8802 8803 // Convert response if prev dataType is non-auto and differs from current 8804 } else if ( prev !== "*" && prev !== current ) { 8805 8806 // Seek a direct converter 8807 conv = converters[ prev + " " + current ] || converters[ "* " + current ]; 8808 8809 // If none found, seek a pair 8810 if ( !conv ) { 8811 for ( conv2 in converters ) { 8812 8813 // If conv2 outputs current 8814 tmp = conv2.split( " " ); 8815 if ( tmp[ 1 ] === current ) { 8816 8817 // If prev can be converted to accepted input 8818 conv = converters[ prev + " " + tmp[ 0 ] ] || 8819 converters[ "* " + tmp[ 0 ] ]; 8820 if ( conv ) { 8821 // Condense equivalence converters 8822 if ( conv === true ) { 8823 conv = converters[ conv2 ]; 8824 8825 // Otherwise, insert the intermediate dataType 8826 } else if ( converters[ conv2 ] !== true ) { 8827 current = tmp[ 0 ]; 8828 dataTypes.unshift( tmp[ 1 ] ); 8829 } 8830 break; 8831 } 8832 } 8833 } 8834 } 8835 8836 // Apply converter (if not an equivalence) 8837 if ( conv !== true ) { 8838 8839 // Unless errors are allowed to bubble, catch and return them 8840 if ( conv && s[ "throws" ] ) { 8841 response = conv( response ); 8842 } else { 8843 try { 8844 response = conv( response ); 8845 } catch ( e ) { 8846 return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; 8847 } 8848 } 8849 } 8850 } 8851 } 8852 } 8853 8854 return { state: "success", data: response }; 8855} 8856 8857jQuery.extend({ 8858 8859 // Counter for holding the number of active queries 8860 active: 0, 8861 8862 // Last-Modified header cache for next request 8863 lastModified: {}, 8864 etag: {}, 8865 8866 ajaxSettings: { 8867 url: ajaxLocation, 8868 type: "GET", 8869 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), 8870 global: true, 8871 processData: true, 8872 async: true, 8873 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 8874 /* 8875 timeout: 0, 8876 data: null, 8877 dataType: null, 8878 username: null, 8879 password: null, 8880 cache: null, 8881 throws: false, 8882 traditional: false, 8883 headers: {}, 8884 */ 8885 8886 accepts: { 8887 "*": allTypes, 8888 text: "text/plain", 8889 html: "text/html", 8890 xml: "application/xml, text/xml", 8891 json: "application/json, text/javascript" 8892 }, 8893 8894 contents: { 8895 xml: /xml/, 8896 html: /html/, 8897 json: /json/ 8898 }, 8899 8900 responseFields: { 8901 xml: "responseXML", 8902 text: "responseText", 8903 json: "responseJSON" 8904 }, 8905 8906 // Data converters 8907 // Keys separate source (or catchall "*") and destination types with a single space 8908 converters: { 8909 8910 // Convert anything to text 8911 "* text": String, 8912 8913 // Text to html (true = no transformation) 8914 "text html": true, 8915 8916 // Evaluate text as a json expression 8917 "text json": jQuery.parseJSON, 8918 8919 // Parse text as xml 8920 "text xml": jQuery.parseXML 8921 }, 8922 8923 // For options that shouldn't be deep extended: 8924 // you can add your own custom options here if 8925 // and when you create one that shouldn't be 8926 // deep extended (see ajaxExtend) 8927 flatOptions: { 8928 url: true, 8929 context: true 8930 } 8931 }, 8932 8933 // Creates a full fledged settings object into target 8934 // with both ajaxSettings and settings fields. 8935 // If target is omitted, writes into ajaxSettings. 8936 ajaxSetup: function( target, settings ) { 8937 return settings ? 8938 8939 // Building a settings object 8940 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : 8941 8942 // Extending ajaxSettings 8943 ajaxExtend( jQuery.ajaxSettings, target ); 8944 }, 8945 8946 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 8947 ajaxTransport: addToPrefiltersOrTransports( transports ), 8948 8949 // Main method 8950 ajax: function( url, options ) { 8951 8952 // If url is an object, simulate pre-1.5 signature 8953 if ( typeof url === "object" ) { 8954 options = url; 8955 url = undefined; 8956 } 8957 8958 // Force options to be an object 8959 options = options || {}; 8960 8961 var // Cross-domain detection vars 8962 parts, 8963 // Loop variable 8964 i, 8965 // URL without anti-cache param 8966 cacheURL, 8967 // Response headers as string 8968 responseHeadersString, 8969 // timeout handle 8970 timeoutTimer, 8971 8972 // To know if global events are to be dispatched 8973 fireGlobals, 8974 8975 transport, 8976 // Response headers 8977 responseHeaders, 8978 // Create the final options object 8979 s = jQuery.ajaxSetup( {}, options ), 8980 // Callbacks context 8981 callbackContext = s.context || s, 8982 // Context for global events is callbackContext if it is a DOM node or jQuery collection 8983 globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? 8984 jQuery( callbackContext ) : 8985 jQuery.event, 8986 // Deferreds 8987 deferred = jQuery.Deferred(), 8988 completeDeferred = jQuery.Callbacks("once memory"), 8989 // Status-dependent callbacks 8990 statusCode = s.statusCode || {}, 8991 // Headers (they are sent all at once) 8992 requestHeaders = {}, 8993 requestHeadersNames = {}, 8994 // The jqXHR state 8995 state = 0, 8996 // Default abort message 8997 strAbort = "canceled", 8998 // Fake xhr 8999 jqXHR = { 9000 readyState: 0, 9001 9002 // Builds headers hashtable if needed 9003 getResponseHeader: function( key ) { 9004 var match; 9005 if ( state === 2 ) { 9006 if ( !responseHeaders ) { 9007 responseHeaders = {}; 9008 while ( (match = rheaders.exec( responseHeadersString )) ) { 9009 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; 9010 } 9011 } 9012 match = responseHeaders[ key.toLowerCase() ]; 9013 } 9014 return match == null ? null : match; 9015 }, 9016 9017 // Raw string 9018 getAllResponseHeaders: function() { 9019 return state === 2 ? responseHeadersString : null; 9020 }, 9021 9022 // Caches the header 9023 setRequestHeader: function( name, value ) { 9024 var lname = name.toLowerCase(); 9025 if ( !state ) { 9026 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; 9027 requestHeaders[ name ] = value; 9028 } 9029 return this; 9030 }, 9031 9032 // Overrides response content-type header 9033 overrideMimeType: function( type ) { 9034 if ( !state ) { 9035 s.mimeType = type; 9036 } 9037 return this; 9038 }, 9039 9040 // Status-dependent callbacks 9041 statusCode: function( map ) { 9042 var code; 9043 if ( map ) { 9044 if ( state < 2 ) { 9045 for ( code in map ) { 9046 // Lazy-add the new callback in a way that preserves old ones 9047 statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; 9048 } 9049 } else { 9050 // Execute the appropriate callbacks 9051 jqXHR.always( map[ jqXHR.status ] ); 9052 } 9053 } 9054 return this; 9055 }, 9056 9057 // Cancel the request 9058 abort: function( statusText ) { 9059 var finalText = statusText || strAbort; 9060 if ( transport ) { 9061 transport.abort( finalText ); 9062 } 9063 done( 0, finalText ); 9064 return this; 9065 } 9066 }; 9067 9068 // Attach deferreds 9069 deferred.promise( jqXHR ).complete = completeDeferred.add; 9070 jqXHR.success = jqXHR.done; 9071 jqXHR.error = jqXHR.fail; 9072 9073 // Remove hash character (#7531: and string promotion) 9074 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) 9075 // Handle falsy url in the settings object (#10093: consistency with old signature) 9076 // We also use the url parameter if available 9077 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); 9078 9079 // Alias method option to type as per ticket #12004 9080 s.type = options.method || options.type || s.method || s.type; 9081 9082 // Extract dataTypes list 9083 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; 9084 9085 // A cross-domain request is in order when we have a protocol:host:port mismatch 9086 if ( s.crossDomain == null ) { 9087 parts = rurl.exec( s.url.toLowerCase() ); 9088 s.crossDomain = !!( parts && 9089 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || 9090 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !== 9091 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) ) 9092 ); 9093 } 9094 9095 // Convert data if not already a string 9096 if ( s.data && s.processData && typeof s.data !== "string" ) { 9097 s.data = jQuery.param( s.data, s.traditional ); 9098 } 9099 9100 // Apply prefilters 9101 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 9102 9103 // If request was aborted inside a prefilter, stop there 9104 if ( state === 2 ) { 9105 return jqXHR; 9106 } 9107 9108 // We can fire global events as of now if asked to 9109 fireGlobals = s.global; 9110 9111 // Watch for a new set of requests 9112 if ( fireGlobals && jQuery.active++ === 0 ) { 9113 jQuery.event.trigger("ajaxStart"); 9114 } 9115 9116 // Uppercase the type 9117 s.type = s.type.toUpperCase(); 9118 9119 // Determine if request has content 9120 s.hasContent = !rnoContent.test( s.type ); 9121 9122 // Save the URL in case we're toying with the If-Modified-Since 9123 // and/or If-None-Match header later on 9124 cacheURL = s.url; 9125 9126 // More options handling for requests with no content 9127 if ( !s.hasContent ) { 9128 9129 // If data is available, append data to url 9130 if ( s.data ) {
9131 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); 9132 // #9682: remove data so that it's not used in an eventual retry 9133 delete s.data; 9134 } 9135 9136 // Add anti-cache in url if needed 9137 if ( s.cache === false ) { 9138 s.url = rts.test( cacheURL ) ? 9139 9140 // If there is already a '_' parameter, set its value 9141 cacheURL.replace( rts, "$1_=" + nonce++ ) : 9142 9143 // Otherwise add one to the end 9144 cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; 9145 } 9146 } 9147 9148 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9149 if ( s.ifModified ) { 9150 if ( jQuery.lastModified[ cacheURL ] ) { 9151 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); 9152 } 9153 if ( jQuery.etag[ cacheURL ] ) { 9154 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); 9155 } 9156 } 9157 9158 // Set the correct header, if data is being sent 9159 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 9160 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 9161 } 9162 9163 // Set the Accepts header for the server, depending on the dataType 9164 jqXHR.setRequestHeader( 9165 "Accept", 9166 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? 9167 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 9168 s.accepts[ "*" ] 9169 ); 9170 9171 // Check for headers option 9172 for ( i in s.headers ) { 9173 jqXHR.setRequestHeader( i, s.headers[ i ] ); 9174 } 9175 9176 // Allow custom headers/mimetypes and early abort 9177 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { 9178 // Abort if not done already and return 9179 return jqXHR.abort(); 9180 } 9181 9182 // aborting is no longer a cancellation 9183 strAbort = "abort"; 9184 9185 // Install callbacks on deferreds 9186 for ( i in { success: 1, error: 1, complete: 1 } ) { 9187 jqXHR[ i ]( s[ i ] ); 9188 } 9189 9190 // Get transport 9191 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 9192 9193 // If no transport, we auto-abort 9194 if ( !transport ) { 9195 done( -1, "No Transport" ); 9196 } else { 9197 jqXHR.readyState = 1; 9198 9199 // Send global event 9200 if ( fireGlobals ) { 9201 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 9202 } 9203 // Timeout 9204 if ( s.async && s.timeout > 0 ) { 9205 timeoutTimer = setTimeout(function() { 9206 jqXHR.abort("timeout"); 9207 }, s.timeout ); 9208 } 9209 9210 try { 9211 state = 1; 9212 transport.send( requestHeaders, done ); 9213 } catch ( e ) { 9214 // Propagate exception as error if not done 9215 if ( state < 2 ) { 9216 done( -1, e ); 9217 // Simply rethrow otherwise 9218 } else { 9219 throw e; 9220 } 9221 } 9222 } 9223 9224 // Callback for when everything is done 9225 function done( status, nativeStatusText, responses, headers ) { 9226 var isSuccess, success, error, response, modified, 9227 statusText = nativeStatusText; 9228 9229 // Called once 9230 if ( state === 2 ) { 9231 return; 9232 } 9233 9234 // State is "done" now 9235 state = 2; 9236 9237 // Clear timeout if it exists 9238 if ( timeoutTimer ) { 9239 clearTimeout( timeoutTimer ); 9240 } 9241 9242 // Dereference transport for early garbage collection 9243 // (no matter how long the jqXHR object will be used) 9244 transport = undefined; 9245 9246 // Cache response headers 9247 responseHeadersString = headers || ""; 9248 9249 // Set readyState 9250 jqXHR.readyState = status > 0 ? 4 : 0; 9251 9252 // Determine if successful 9253 isSuccess = status >= 200 && status < 300 || status === 304; 9254 9255 // Get response data 9256 if ( responses ) { 9257 response = ajaxHandleResponses( s, jqXHR, responses ); 9258 } 9259 9260 // Convert no matter what (that way responseXXX fields are always set) 9261 response = ajaxConvert( s, response, jqXHR, isSuccess ); 9262 9263 // If successful, handle type chaining 9264 if ( isSuccess ) { 9265 9266 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9267 if ( s.ifModified ) { 9268 modified = jqXHR.getResponseHeader("Last-Modified"); 9269 if ( modified ) { 9270 jQuery.lastModified[ cacheURL ] = modified; 9271 } 9272 modified = jqXHR.getResponseHeader("etag"); 9273 if ( modified ) { 9274 jQuery.etag[ cacheURL ] = modified; 9275 } 9276 } 9277 9278 // if no content 9279 if ( status === 204 || s.type === "HEAD" ) { 9280 statusText = "nocontent"; 9281 9282 // if not modified 9283 } else if ( status === 304 ) { 9284 statusText = "notmodified"; 9285 9286 // If we have data, let's convert it 9287 } else { 9288 statusText = response.state; 9289 success = response.data; 9290 error = response.error; 9291 isSuccess = !error; 9292 } 9293 } else { 9294 // We extract error from statusText 9295 // then normalize statusText and status for non-aborts 9296 error = statusText; 9297 if ( status || !statusText ) { 9298 statusText = "error"; 9299 if ( status < 0 ) { 9300 status = 0; 9301 } 9302 } 9303 } 9304 9305 // Set data for the fake xhr object 9306 jqXHR.status = status; 9307 jqXHR.statusText = ( nativeStatusText || statusText ) + ""; 9308 9309 // Success/Error 9310 if ( isSuccess ) { 9311 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 9312 } else { 9313 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 9314 } 9315 9316 // Status-dependent callbacks 9317 jqXHR.statusCode( statusCode ); 9318 statusCode = undefined; 9319 9320 if ( fireGlobals ) { 9321 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", 9322 [ jqXHR, s, isSuccess ? success : error ] ); 9323 } 9324 9325 // Complete 9326 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 9327 9328 if ( fireGlobals ) { 9329 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 9330 // Handle the global AJAX counter 9331 if ( !( --jQuery.active ) ) { 9332 jQuery.event.trigger("ajaxStop"); 9333 } 9334 } 9335 } 9336 9337 return jqXHR; 9338 }, 9339 9340 getJSON: function( url, data, callback ) { 9341 return jQuery.get( url, data, callback, "json" ); 9342 }, 9343 9344 getScript: function( url, callback ) { 9345 return jQuery.get( url, undefined, callback, "script" ); 9346 } 9347}); 9348 9349jQuery.each( [ "get", "post" ], function( i, method ) { 9350 jQuery[ method ] = function( url, data, callback, type ) { 9351 // shift arguments if data argument was omitted 9352 if ( jQuery.isFunction( data ) ) { 9353 type = type || callback; 9354 callback = data; 9355 data = undefined; 9356 } 9357 9358 return jQuery.ajax({ 9359 url: url, 9360 type: method, 9361 dataType: type, 9362 data: data, 9363 success: callback 9364 }); 9365 }; 9366}); 9367 9368// Attach a bunch of functions for handling common AJAX events 9369jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) { 9370 jQuery.fn[ type ] = function( fn ) { 9371 return this.on( type, fn ); 9372 }; 9373}); 9374 9375 9376jQuery._evalUrl = function( url ) { 9377 return jQuery.ajax({ 9378 url: url, 9379 type: "GET", 9380 dataType: "script", 9381 async: false, 9382 global: false, 9383 "throws": true 9384 }); 9385}; 9386 9387 9388jQuery.fn.extend({ 9389 wrapAll: function( html ) { 9390 if ( jQuery.isFunction( html ) ) { 9391 return this.each(function(i) { 9392 jQuery(this).wrapAll( html.call(this, i) ); 9393 }); 9394 } 9395 9396 if ( this[0] ) { 9397 // The elements to wrap the target around 9398 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); 9399 9400 if ( this[0].parentNode ) { 9401 wrap.insertBefore( this[0] ); 9402 } 9403 9404 wrap.map(function() { 9405 var elem = this; 9406 9407 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { 9408 elem = elem.firstChild; 9409 } 9410 9411 return elem; 9412 }).append( this ); 9413 } 9414 9415 return this; 9416 }, 9417 9418 wrapInner: function( html ) { 9419 if ( jQuery.isFunction( html ) ) { 9420 return this.each(function(i) { 9421 jQuery(this).wrapInner( html.call(this, i) ); 9422 }); 9423 } 9424 9425 return this.each(function() { 9426 var self = jQuery( this ), 9427 contents = self.contents(); 9428 9429 if ( contents.length ) { 9430 contents.wrapAll( html ); 9431 9432 } else { 9433 self.append( html ); 9434 } 9435 }); 9436 }, 9437 9438 wrap: function( html ) { 9439 var isFunction = jQuery.isFunction( html ); 9440 9441 return this.each(function(i) { 9442 jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); 9443 }); 9444 }, 9445 9446 unwrap: function() { 9447 return this.parent().each(function() { 9448 if ( !jQuery.nodeName( this, "body" ) ) { 9449 jQuery( this ).replaceWith( this.childNodes ); 9450 } 9451 }).end(); 9452 } 9453}); 9454 9455 9456jQuery.expr.filters.hidden = function( elem ) { 9457 // Support: Opera <= 12.12 9458 // Opera reports offsetWidths and offsetHeights less than zero on some elements 9459 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 || 9460 (!support.reliableHiddenOffsets() && 9461 ((elem.style && elem.style.display) || jQuery.css( elem, "dis
9461play" )) === "none"); 9462}; 9463 9464jQuery.expr.filters.visible = function( elem ) { 9465 return !jQuery.expr.filters.hidden( elem ); 9466}; 9467 9468 9469 9470 9471var r20 = /%20/g, 9472 rbracket = /\[\]$/, 9473 rCRLF = /\r?\n/g, 9474 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 9475 rsubmittable = /^(?:input|select|textarea|keygen)/i; 9476 9477function buildParams( prefix, obj, traditional, add ) { 9478 var name; 9479 9480 if ( jQuery.isArray( obj ) ) { 9481 // Serialize array item. 9482 jQuery.each( obj, function( i, v ) { 9483 if ( traditional || rbracket.test( prefix ) ) { 9484 // Treat each array item as a scalar. 9485 add( prefix, v ); 9486 9487 } else { 9488 // Item is non-scalar (array or object), encode its numeric index. 9489 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); 9490 } 9491 }); 9492 9493 } else if ( !traditional && jQuery.type( obj ) === "object" ) { 9494 // Serialize object item. 9495 for ( name in obj ) { 9496 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 9497 } 9498 9499 } else { 9500 // Serialize scalar item. 9501 add( prefix, obj ); 9502 } 9503} 9504 9505// Serialize an array of form elements or a set of 9506// key/values into a query string 9507jQuery.param = function( a, traditional ) { 9508 var prefix, 9509 s = [], 9510 add = function( key, value ) { 9511 // If value is a function, invoke it and return its value 9512 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); 9513 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); 9514 }; 9515 9516 // Set traditional to true for jQuery <= 1.3.2 behavior. 9517 if ( traditional === undefined ) { 9518 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; 9519 } 9520 9521 // If an array was passed in, assume that it is an array of form elements. 9522 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 9523 // Serialize the form elements 9524 jQuery.each( a, function() { 9525 add( this.name, this.value ); 9526 }); 9527 9528 } else { 9529 // If traditional, encode the "old" way (the way 1.3.2 or older 9530 // did it), otherwise encode params recursively. 9531 for ( prefix in a ) { 9532 buildParams( prefix, a[ prefix ], traditional, add ); 9533 } 9534 } 9535 9536 // Return the resulting serialization 9537 return s.join( "&" ).replace( r20, "+" ); 9538}; 9539 9540jQuery.fn.extend({ 9541 serialize: function() { 9542 return jQuery.param( this.serializeArray() ); 9543 }, 9544 serializeArray: function() { 9545 return this.map(function() { 9546 // Can add propHook for "elements" to filter or add form elements 9547 var elements = jQuery.prop( this, "elements" ); 9548 return elements ? jQuery.makeArray( elements ) : this; 9549 }) 9550 .filter(function() { 9551 var type = this.type; 9552 // Use .is(":disabled") so that fieldset[disabled] works 9553 return this.name && !jQuery( this ).is( ":disabled" ) && 9554 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 9555 ( this.checked || !rcheckableType.test( type ) ); 9556 }) 9557 .map(function( i, elem ) { 9558 var val = jQuery( this ).val(); 9559 9560 return val == null ? 9561 null : 9562 jQuery.isArray( val ) ? 9563 jQuery.map( val, function( val ) { 9564 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9565 }) : 9566 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9567 }).get(); 9568 } 9569}); 9570 9571 9572// Create the request object 9573// (This is still attached to ajaxSettings for backward compatibility) 9574jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ? 9575 // Support: IE6+ 9576 function() { 9577 9578 // XHR cannot access local files, always use ActiveX for that case 9579 return !this.isLocal && 9580 9581 // Support: IE7-8 9582 // oldIE XHR does not support non-RFC2616 methods (#13240) 9583 // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx 9584 // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9 9585 // Although this check for six methods instead of eight 9586 // since IE also does not support "trace" and "connect" 9587 /^(get|post|head|put|delete|options)$/i.test( this.type ) && 9588 9589 createStandardXHR() || createActiveXHR(); 9590 } : 9591 // For all other browsers, use the standard XMLHttpRequest object 9592 createStandardXHR; 9593 9594var xhrId = 0, 9595 xhrCallbacks = {}, 9596 xhrSupported = jQuery.ajaxSettings.xhr(); 9597 9598// Support: IE<10 9599// Open requests must be manually aborted on unload (#5280) 9600if ( window.ActiveXObject ) { 9601 jQuery( window ).on( "unload", function() {
9602 for ( var key in xhrCallbacks ) { 9603 xhrCallbacks[ key ]( undefined, true ); 9604 } 9605 }); 9606} 9607 9608// Determine support properties 9609support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 9610xhrSupported = support.ajax = !!xhrSupported; 9611 9612// Create transport if the browser can provide an xhr 9613if ( xhrSupported ) { 9614 9615 jQuery.ajaxTransport(function( options ) { 9616 // Cross domain only allowed if supported through XMLHttpRequest 9617 if ( !options.crossDomain || support.cors ) { 9618 9619 var callback; 9620 9621 return { 9622 send: function( headers, complete ) { 9623 var i, 9624 xhr = options.xhr(), 9625 id = ++xhrId; 9626 9627 // Open the socket 9628 xhr.open( options.type, options.url, options.async, options.username, options.password ); 9629 9630 // Apply custom fields if provided 9631 if ( options.xhrFields ) { 9632 for ( i in options.xhrFields ) { 9633 xhr[ i ] = options.xhrFields[ i ]; 9634 } 9635 } 9636 9637 // Override mime type if needed 9638 if ( options.mimeType && xhr.overrideMimeType ) { 9639 xhr.overrideMimeType( options.mimeType ); 9640 } 9641 9642 // X-Requested-With header 9643 // For cross-domain requests, seeing as conditions for a preflight are 9644 // akin to a jigsaw puzzle, we simply never set it to be sure. 9645 // (it can always be set on a per-request basis or even using ajaxSetup)
9646 // For same-domain requests, won't change header if already provided. 9647 if ( !options.crossDomain && !headers["X-Requested-With"] ) { 9648 headers["X-Requested-With"] = "XMLHttpRequest"; 9649 } 9650 9651 // Set headers 9652 for ( i in headers ) { 9653 // Support: IE<9 9654 // IE's ActiveXObject throws a 'Type Mismatch' exception when setting 9655 // request header to a null-value. 9656 // 9657 // To keep consistent with other XHR implementations, cast the value 9658 // to string and ignore `undefined`. 9659 if ( headers[ i ] !== undefined ) { 9660 xhr.setRequestHeader( i, headers[ i ] + "" ); 9661 } 9662 } 9663 9664 // Do send the request 9665 // This may raise an exception which is actually 9666 // handled in jQuery.ajax (so no try/catch here) 9667 xhr.send( ( options.hasContent && options.data ) || null ); 9668 9669 // Listener 9670 callback = function( _, isAbort ) { 9671 var status, statusText, responses; 9672 9673 // Was never called and is aborted or complete 9674 if ( callback && ( isAbort || xhr.readyState === 4 ) ) { 9675 // Clean up 9676 delete xhrCallbacks[ id ]; 9677 callback = undefined; 9678 xhr.onreadystatechange = jQuery.noop; 9679 9680 // Abort manually if needed 9681 if ( isAbort ) { 9682 if ( xhr.readyState !== 4 ) { 9683 xhr.abort(); 9684 } 9685 } else { 9686 responses = {}; 9687 status = xhr.status; 9688 9689 // Support: IE<10 9690 // Accessing binary-data responseText throws an exception 9691 // (#11426) 9692 if ( typeof xhr.responseText === "string" ) { 9693 responses.text = xhr.responseText; 9694 } 9695 9696 // Firefox throws an exception when accessing 9697 // statusText for faulty cross-domain requests 9698 try { 9699 statusText = xhr.statusText; 9700 } catch( e ) { 9701 // We normalize with Webkit giving an empty statusText 9702 statusText = ""; 9703 } 9704 9705 // Filter status for non standard behaviors 9706 9707 // If the request is local and we have data: assume a success 9708 // (success with no data won't get notified, that's the best we 9709 // can do given current implementations) 9710 if ( !status && options.isLocal && !options.crossDomain ) { 9711 status = responses.text ? 200 : 404; 9712 // IE - #1450: sometimes returns 1223 when it should be 204 9713 } else if ( status === 1223 ) { 9714 status = 204; 9715 } 9716 } 9717 } 9718 9719 // Call complete if needed 9720 if ( responses ) { 9721 complete( status, statusText, responses, xhr.getAllResponseHeaders() ); 9722 } 9723 }; 9724 9725 if ( !options.async ) { 9726 // if we're in sync mode we fire the callback 9727 callback(); 9728 } else if ( xhr.readyState === 4 ) { 9729 // (IE6 & IE7) if it's in cache and has been 9730 // retrieved directly we need to fire the callback 9731 setTimeout( callback ); 9732 } else { 9733 // Add to the list of active xhr callbacks 9734 xhr.onreadystatechange = xhrCallbacks[ id ] = callback; 9735 } 9736 }, 9737 9738 abort: function() { 9739 if ( callback ) { 9740 callback( undefined, true ); 9741 } 9742 } 9743 }; 9744 } 9745 }); 9746} 9747 9748// Functions to create xhrs 9749function createStandardXHR() { 9750 try { 9751 return new window.XMLHttpRequest(); 9752 } catch( e ) {} 9753} 9754 9755function createActiveXHR() { 9756 try { 9757 return new window.ActiveXObject( "Microsoft.XMLHTTP" ); 9758 } catch( e ) {} 9759} 9760 9761 9762 9763 9764// Install script dataType 9765jQuery.ajaxSetup({ 9766 accepts: { 9767 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" 9768 }, 9769 contents: { 9770 script: /(?:java|ecma)script/ 9771 }, 9772 converters: { 9773 "text script": function( text ) { 9774 jQuery.globalEval( text ); 9775 return text; 9776 } 9777 } 9778}); 9779 9780// Handle cache's special case and global 9781jQuery.ajaxPrefilter( "script", function( s ) { 9782 if ( s.cache === undefined ) { 9783 s.cache = false; 9784 } 9785 if ( s.crossDomain ) { 9786 s.type = "GET"; 9787 s.global = false; 9788 } 9789}); 9790 9791// Bind script tag hack transport 9792jQuery.ajaxTransport( "script", function(s) { 9793 9794 // This transport only deals with cross domain requests 9795 if ( s.crossDomain ) { 9796 9797 var script, 9798 head = document.head || jQuery("head")[0] || document.documentElement; 9799 9800 return { 9801 9802 send: function( _, callback ) { 9803 9804 script = document.createElement("script"); 9805 9806 script.async = true; 9807 9808 if ( s.scriptCharset ) { 9809 script.charset = s.scriptCharset; 9810 } 9811 9812 script.src = s.url; 9813 9814 // Attach handlers for all browsers 9815 script.onload = script.onreadystatechange = function( _, isAbort ) { 9816 9817 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { 9818 9819 // Handle memory leak in IE 9820 script.onload = script.onreadystatechange = null; 9821 9822 // Remove the script 9823 if ( script.parentNode ) { 9824 script.parentNode.removeChild( script ); 9825 } 9826 9827 // Dereference the script 9828 script = null; 9829 9830 // Callback if not abort 9831 if ( !isAbort ) { 9832 callback( 200, "success" ); 9833 } 9834 } 9835 }; 9836 9837 // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending 9838 // Use native DOM manipulation to avoid our domManip AJAX trickery 9839 head.insertBefore( script, head.firstChild ); 9840 }, 9841 9842 abort: function() { 9843 if ( script ) { 9844 script.onload( undefined, true ); 9845 } 9846 } 9847 }; 9848 } 9849}); 9850 9851 9852 9853 9854var oldCallbacks = [], 9855 rjsonp = /(=)\?(?=&|$)|\?\?/; 9856 9857// Default jsonp settings 9858jQuery.ajaxSetup({ 9859 jsonp: "callback", 9860 jsonpCallback: function() { 9861 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); 9862 this[ callback ] = true; 9863 return callback; 9864 } 9865}); 9866 9867// Detect, normalize options and install callbacks for jsonp requests 9868jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 9869 9870 var callbackName, overwritten, responseContainer, 9871 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 9872 "url" : 9873 typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data" 9874 ); 9875 9876 // Handle iff the expected data type is "jsonp" or we have a parameter to set 9877 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 9878 9879 // Get callback name, remembering preexisting value associated with it 9880 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? 9881 s.jsonpCallback() : 9882 s.jsonpCallback; 9883 9884 // Insert callback into url or form data 9885 if ( jsonProp ) { 9886 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 9887 } else if ( s.jsonp !== false ) { 9888 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 9889 } 9890 9891 // Use data converter to retrieve json after script execution 9892 s.converters["script json"] = function() { 9893 if ( !responseContainer ) { 9894 jQuery.error( callbackName + " was not called" ); 9895 } 9896 return responseContainer[ 0 ]; 9897 }; 9898 9899 // force json dataType 9900 s.dataTypes[ 0 ] = "json"; 9901 9902 // Install callback 9903 overwritten = window[ callbackName ]; 9904 window[ callbackName ] = function() { 9905 responseContainer = arguments; 9906 }; 9907 9908 // Clean-up function (fires after converters) 9909 jqXHR.always(function() { 9910 // Restore preexisting value 9911 window[ callbackName ] = overwritten; 9912 9913 // Save back as free 9914 if ( s[ callbackName ] ) { 9915 // make sure that re-using the options doesn't screw things around 9916 s.jsonpCallback = originalSettings.jsonpCallback; 9917 9918 // save the callback name for future use 9919 oldCallbacks.push( callbackName ); 9920 } 9921 9922 // Call if it was a function and we have a response 9923 if ( responseContainer && jQuery.isFunction( overwritten ) ) { 9924 overwritten( responseContainer[ 0 ] ); 9925 } 9926 9927 responseContainer = overwritten = undefined; 9928 }); 9929 9930 // Delegate to script 9931 return "script"; 9932 } 9933}); 9934 9935 9936 9937 9938// data: string of html 9939// context (optional): If specified, the fragment will be created in this context, defaults to document 9940// keepScripts (optional): If true, will include scripts passed in the html string 9941jQuery.parseHTML = function( data, context, keepScripts ) { 9942 if ( !data || typeof data !== "string" ) { 9943 return null; 9944 } 9945 if ( typeof context === "boolean" ) { 9946 keepScripts = context; 9947 context = false;
9948 } 9949 context = context || document; 9950 9951 var parsed = rsingleTag.exec( data ), 9952 scripts = !keepScripts && []; 9953 9954 // Single tag 9955 if ( parsed ) { 9956 return [ context.createElement( parsed[1] ) ]; 9957 } 9958 9959 parsed = jQuery.buildFragment( [ data ], context, scripts ); 9960 9961 if ( scripts && scripts.length ) { 9962 jQuery( scripts ).remove(); 9963 } 9964 9965 return jQuery.merge( [], parsed.childNodes ); 9966}; 9967 9968 9969// Keep a copy of the old load method 9970var _load = jQuery.fn.load; 9971 9972/** 9973 * Load a url into a page 9974 */ 9975jQuery.fn.load = function( url, params, callback ) { 9976 if ( typeof url !== "string" && _load ) { 9977 return _load.apply( this, arguments ); 9978 } 9979 9980 var selector, response, type, 9981 self = this, 9982 off = url.indexOf(" "); 9983 9984 if ( off >= 0 ) { 9985 selector = url.slice( off, url.length ); 9986 url = url.slice( 0, off ); 9987 } 9988 9989 // If it's a function 9990 if ( jQuery.isFunction( params ) ) { 9991 9992 // We assume that it's the callback 9993 callback = params; 9994 params = undefined; 9995 9996 // Otherwise, build a param string 9997 } else if ( params && typeof params === "object" ) { 9998 type = "POST"; 9999 } 10000 10001 // If we have elements to modify, make the request 10002 if ( self.length > 0 ) { 10003 jQuery.ajax({ 10004 url: url, 10005 10006 // if "type" variable is undefined, then "GET" method will be used 10007 type: type, 10008 dataType: "html", 10009 data: params 10010 }).done(function( responseText ) { 10011 10012 // Save response for use in complete callback 10013 response = arguments; 10014 10015 self.html( selector ? 10016 10017 // If a selector was specified, locate the right elements in a dummy div 10018 // Exclude scripts to avoid IE 'Permission Denied' errors 10019 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) : 10020 10021 // Otherwise use the full result 10022 responseText ); 10023 10024 }).complete( callback && function( jqXHR, status ) { 10025 self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); 10026 }); 10027 } 10028 10029 return this; 10030}; 10031 10032 10033 10034 10035jQuery.expr.filters.animated = function( elem ) { 10036 return jQuery.grep(jQuery.timers, function( fn ) { 10037 return elem === fn.elem; 10038 }).length; 10039}; 10040 10041 10042 10043 10044 10045var docElem = window.document.documentElement; 10046 10047/** 10048 * Gets a window from an element 10049 */ 10050function getWindow( elem ) { 10051 return jQuery.isWindow( elem ) ? 10052 elem : 10053 elem.nodeType === 9 ? 10054 elem.defaultView || elem.parentWindow : 10055 false; 10056} 10057 10058jQuery.offset = { 10059 setOffset: function( elem, options, i ) { 10060 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, 10061 position = jQuery.css( elem, "position" ), 10062 curElem = jQuery( elem ), 10063 props = {}; 10064 10065 // set position first, in-case top/left are set even on static elem 10066 if ( position === "static" ) { 10067 elem.style.position = "relative"; 10068 } 10069 10070 curOffset = curElem.offset(); 10071 curCSSTop = jQuery.css( elem, "top" ); 10072 curCSSLeft = jQuery.css( elem, "left" ); 10073 calculatePosition = ( position === "absolute" || position === "fixed" ) && 10074 jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1; 10075 10076 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed 10077 if ( calculatePosition ) { 10078 curPosition = curElem.position(); 10079 curTop = curPosition.top; 10080 curLeft = curPosition.left; 10081 } else { 10082 curTop = parseFloat( curCSSTop ) || 0; 10083 curLeft = parseFloat( curCSSLeft ) || 0; 10084 } 10085 10086 if ( jQuery.isFunction( options ) ) { 10087 options = options.call( elem, i, curOffset ); 10088 } 10089 10090 if ( options.top != null ) { 10091 props.top = ( options.top - curOffset.top ) + curTop; 10092 } 10093 if ( options.left != null ) { 10094 props.left = ( options.left - curOffset.left ) + curLeft; 10095 } 10096 10097 if ( "using" in options ) { 10098 options.using.call( elem, props ); 10099 } else { 10100 curElem.css( props ); 10101 } 10102 } 10103}; 10104 10105jQuery.fn.extend({ 10106 offset: function( options ) { 10107 if ( arguments.length ) { 10108 return options === undefined ? 10109 this : 10110 this.each(function( i ) { 10111 jQuery.offset.setOffset( this, options, i ); 10112 }); 10113 } 10114 10115 var docElem, win, 10116 box = { top: 0, left: 0 }, 10117 elem = this[ 0 ], 10118 doc = elem && elem.ownerDocument; 10119 10120 if ( !doc ) { 10121 return; 10122 } 10123 10124 docElem = doc.documentElement; 10125 10126 // Make sure it's not a disconnected DOM node 10127 if ( !jQuery.contains( docElem, elem ) ) { 10128 return box; 10129 } 10130 10131 // If we don't have gBCR, just use 0,0 rather than error 10132 // BlackBerry 5, iOS 3 (original iPhone) 10133 if ( typeof elem.getBoundingClientRect !== strundefined ) { 10134 box = elem.getBoundingClientRect(); 10135 } 10136 win = getWindow( doc ); 10137 return { 10138 top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ), 10139 left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 ) 10140 }; 10141 }, 10142 10143 position: function() { 10144 if ( !this[ 0 ] ) { 10145 return; 10146 } 10147 10148 var offsetParent, offset, 10149 parentOffset = { top: 0, left: 0 }, 10150 elem = this[ 0 ]; 10151 10152 // fixed elements are offset from window (parentOffset = {top:0, left
10152: 0}, because it is its only offset parent 10153 if ( jQuery.css( elem, "position" ) === "fixed" ) { 10154 // we assume that getBoundingClientRect is available when computed position is fixed 10155 offset = elem.getBoundingClientRect(); 10156 } else { 10157 // Get *real* offsetParent 10158 offsetParent = this.offsetParent(); 10159 10160 // Get correct offsets 10161 offset = this.offset(); 10162 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { 10163 parentOffset = offsetParent.offset(); 10164 } 10165 10166 // Add offsetParent borders 10167 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ); 10168 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ); 10169 } 10170 10171 // Subtract parent offsets and element margins 10172 // note: when an element has margin: auto the offsetLeft and marginLeft 10173 // are the same in Safari causing offset.left to incorrectly be 0 10174 return { 10175 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), 10176 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true) 10177 }; 10178 }, 10179 10180 offsetParent: function() { 10181 return this.map(function() { 10182 var offsetParent = this.offsetParent || docElem; 10183 10184 while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) { 10185 offsetParent = offsetParent.offsetParent; 10186 } 10187 return offsetParent || docElem; 10188 }); 10189 } 10190}); 10191 10192// Create scrollLeft and scrollTop methods 10193jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { 10194 var top = /Y/.test( prop ); 10195 10196 jQuery.fn[ method ] = function( val ) { 10197 return access( this, function( elem, method, val ) { 10198 var win = getWindow( elem ); 10199 10200 if ( val === undefined ) { 10201 return win ? (prop in win) ? win[ prop ] : 10202 win.document.documentElement[ method ] : 10203 elem[ method ]; 10204 } 10205 10206 if ( win ) { 10207 win.scrollTo( 10208 !top ? val : jQuery( win ).scrollLeft(), 10209 top ? val : jQuery( win ).scrollTop() 10210 ); 10211 10212 } else { 10213 elem[ method ] = val; 10214 } 10215 }, method, val, arguments.length, null ); 10216 }; 10217}); 10218 10219// Add the top/left cssHooks using jQuery.fn.position 10220// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 10221// getComputedStyle returns percent when specified for top/left/bottom/right 10222// rather than make the css module depend on the offset module, we just check for it here 10223jQuery.each( [ "top", "left" ], function( i, prop ) { 10224 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, 10225 function( elem, computed ) { 10226 if ( computed ) { 10227 computed = curCSS( elem, prop ); 10228 // if curCSS returns percentage, fallback to offset 10229 return rnumnonpx.test( computed ) ? 10230 jQuery( elem ).position()[ prop ] + "px" : 10231 computed; 10232 } 10233 } 10234 ); 10235}); 10236 10237 10238// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 10239jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 10240 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { 10241 // margin is only for outerHeight, outerWidth 10242 jQuery.fn[ funcName ] = function( margin, value ) { 10243 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 10244 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 10245 10246 return access( this, function( elem, type, value ) { 10247 var doc; 10248 10249 if ( jQuery.isWindow( elem ) ) { 10250 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there 10251 // isn't a whole lot we can do. See pull request at this URL for discussion: 10252 // https://github.com/jquery/jquery/pull/764 10253 return elem.document.documentElement[ "client" + name ]; 10254 } 10255 10256 // Get document width or height 10257 if ( elem.nodeType === 9 ) { 10258 doc = elem.documentElement; 10259 10260 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest 10261 // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. 10262 return Math.max( 10263 elem.body[ "scroll" + name ], doc[ "scroll" + name ], 10264 elem.body[ "offset" + name ], doc[ "offset" + name ], 10265 doc[ "client" + name ] 10266 ); 10267 } 10268 10269 return value === undefined ? 10270 // Get width or height on the element, requesting but not forcing parseFloat 10271 jQuery.css( elem, type, extra ) : 10272 10273 // Set width or height on the element 10274 jQuery.style( elem, type, value, extra ); 10275 }, type, chainable ? margin : undefined, chainable, null ); 10276 }; 10277 }); 10278}); 10279 10280 10281// The number of elements contained in the matched element set 10282jQuery.fn.size = function() { 10283 return this.length; 10284}; 10285 10286jQuery.fn.andSelf = jQuery.fn.addBack; 10287 10288 10289 10290 10291// Register as a named AMD module, since jQuery can be concatenated with other 10292// files that may use define, but not via a proper concatenation script that 10293// understands anonymous AMD modules. A named AMD is safest and most robust 10294// way to register. Lowercase jquery is used because AMD module names are 10295// derived from file names, and jQuery is normally delivered in a lowercase 10296// file name. Do this after creating the global so that if an AMD module wants 10297// to call noConflict to hide this version of jQuery, it will work. 10298if ( typeof define === "function" && define.amd ) { 10299 define( "jquery", [], function() { 10300 return jQuery; 10301 }); 10302} 10303 10304 10305 10306 10307var 10308 // Map over jQuery in case of overwrite 10309 _jQuery = window.jQuery, 10310 10311 // Map over the $ in case of overwrite 10312 _$ = window.$; 10313 10314jQuery.noConflict = function( deep ) { 10315 if ( window.$ === jQuery ) { 10316 window.$ = _$; 10317 } 10318 10319 if ( deep && window.jQuery === jQuery ) { 10320 window.jQuery = _jQuery; 10321 } 10322 10323 return jQuery; 10324}; 10325 10326// Expose jQuery and $ identifiers, even in 10327// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 10328// and CommonJS for browser emulators (#13566) 10329if ( typeof noGlobal === strundefined ) { 10330 window.jQuery = window.$ = jQuery; 10331} 10332 10333 10334 10335 10336return jQuery; 10337 10338})); 10339/* jshint node: true */ 10340 10341/** 10342 * Unobtrusive scripting adapter for jQuery 10343 * https://github.com/rails/jquery-ujs 10344 * 10345 * Requires jQuery 1.8.0 or later. 10346 * 10347 * Released under the MIT license 10348 * 10349 */ 10350 10351 10352(function() { 10353 'use strict'; 10354 10355 var jqueryUjsInit = function($, undefined) { 10356 10357 // Cut down on the number of issues from people inadvertently including jquery_ujs twice 10358 // by detecting and raising an error when it happens. 10359 if ( $.rails !== undefined ) { 10360 $.error('jquery-ujs has already been loaded!'); 10361 } 10362 10363 // Shorthand to make it a little easier to call public rails functions from within rails.js 10364 var rails; 10365 var $document = $(document); 10366 10367 $.rails = rails = { 10368 // Link elements bound by jquery-ujs 10369 linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]', 10370 10371 // Button elements bound by jquery-ujs 10372 buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)', 10373 10374 // Select elements bound by jquery-ujs 10375 inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]', 10376 10377 // Form elements bound by jquery-ujs 10378 formSubmitSelector: 'form:not([data-turbo=true])', 10379 10380 // Form input elements bound by jquery-ujs 10381 formInputClickSelector: 'form:not([data-turbo=true]) input[type=submit], form:not([data-turbo=true]) input[type=image], form:not([data-turbo=true]) button[type=submit], form:not([data-turbo=true]) button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])', 10382 10383 // Form input elements disabled during form submission 10384 disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled', 10385 10386 // Form input elements re-enabled after form submission 10387 enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled', 10388 10389 // Form required input elements 10390 requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])', 10391 10392 // Form file input elements 10393 fileInputSelector: 'input[name][type=file]:not([disabled])', 10394 10395 // Link onClick disable selector with possible reenable after remote submission 10396 linkDisableSelector: 'a[data-disable-with], a[data-disable]', 10397 10398 // Button onClick disable selector with possible reenable after remote submission 10399 buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]', 10400 10401 // Up-to-date Cross-Site Request Forgery token 10402 csrfToken: function() { 10403 return $('meta[name=csrf-token]').attr('content'); 10404 }, 10405 10406 // URL param that must contain the CSRF token
10407 csrfParam: function() { 10408 return $('meta[name=csrf-param]').attr('content'); 10409 }, 10410 10411 // Make sure that every Ajax request sends the CSRF token 10412 CSRFProtection: function(xhr) { 10413 var token = rails.csrfToken(); 10414 if (token) xhr.setRequestHeader('X-CSRF-Token', token); 10415 }, 10416 10417 // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones) 10418 refreshCSRFTokens: function(){ 10419 $('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken()); 10420 }, 10421 10422 // Triggers an event on an element and returns false if the event result is false 10423 fire: function(obj, name, data) { 10424 var event = $.Event(name); 10425 obj.trigger(event, data); 10426 return event.result !== false; 10427 }, 10428 10429 // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm 10430 confirm: function(message) { 10431 return confirm(message); 10432 }, 10433 10434 // Default ajax function, may be overridden with custom function in $.rails.ajax 10435 ajax: function(options) { 10436 return $.ajax(options); 10437 }, 10438 10439 // Default way to get an element's href. May be overridden at $.rails.href. 10440 href: function(element) { 10441 return element[0].href; 10442 }, 10443 10444 // Checks "data-remote" if true to handle the request through a XHR request. 10445 isRemote: function(element) { 10446 return element.data('remote') !== undefined && element.data('remote') !== false; 10447 }, 10448 10449 // Submits "remote" forms and links with ajax 10450 handleRemote: function(element) { 10451 var method, url, data, withCredentials, dataType, options; 10452 10453 if (rails.fire(element, 'ajax:before')) { 10454 withCredentials = element.data('with-credentials') || null; 10455 dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); 10456 10457 if (element.is('form')) { 10458 method = element.data('ujs:submit-button-formmethod') || element.attr('method'); 10459 url = element.data('ujs:submit-button-formaction') || element.attr('action'); 10460 data = $(element[0]).serializeArray(); 10461 // memoized value from clicked submit button 10462 var button = element.data('ujs:submit-button'); 10463 if (button) { 10464 data.push(button); 10465 element.data('ujs:submit-button', null); 10466 } 10467 element.data('ujs:submit-button-formmethod', null); 10468 element.data('ujs:submit-button-formaction', null); 10469 } else if (element.is(rails.inputChangeSelector)) { 10470 method = element.data('method'); 10471 url = element.data('url'); 10472 data = element.serialize(); 10473 if (element.data('params')) data = data + '&' + element.data('params'); 10474 } else if (element.is(rails.buttonClickSelector)) { 10475 method = element.data('method') || 'get'; 10476 url = element.data('url'); 10477 data = element.serialize(); 10478 if (element.data('params')) data = data + '&' + element.data('params'); 10479 } else { 10480 method = element.data('method'); 10481 url = rails.href(element); 10482 data = element.data('params') || null; 10483 } 10484 10485 options = { 10486 type: method || 'GET', data: data, dataType: dataType, 10487 // stopping the "ajax:beforeSend" event will cancel the ajax request 10488 beforeSend: function(xhr, settings) { 10489 if (settings.dataType === undefined) { 10490 xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script); 10491 } 10492 if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) { 10493 element.trigger('ajax:send', xhr); 10494 } else { 10495 return false; 10496 } 10497 }, 10498 success: function(data, status, xhr) { 10499 element.trigger('ajax:success', [data, status, xhr]); 10500 }, 10501 complete: function(xhr, status) { 10502 element.trigger('ajax:complete', [xhr, status]); 10503 }, 10504 error: function(xhr, status, error) { 10505 element.trigger('ajax:error', [xhr, status, error]); 10506 }, 10507 crossDomain: rails.isCrossDomain(url) 10508 }; 10509 10510 // There is no withCredentials for IE6-8 when 10511 // "Enable native XMLHTTP support" is disabled 10512 if (withCredentials) { 10513 options.xhrFields = { 10514 withCredentials: withCredentials 10515 }; 10516 } 10517 10518 // Only pass url to `ajax` options if not blank 10519 if (url) { options.url = url; } 10520 10521 return rails.ajax(options); 10522 } else { 10523 return false;
10524 } 10525 }, 10526 10527 // Determines if the request is a cross domain request. 10528 isCrossDomain: function(url) { 10529 var originAnchor = document.createElement('a'); 10530 originAnchor.href = location.href; 10531 var urlAnchor = document.createElement('a'); 10532 10533 try { 10534 urlAnchor.href = url; 10535 // This is a workaround to a IE bug. 10536 urlAnchor.href = urlAnchor.href; 10537 10538 // If URL protocol is false or is a string containing a single colon 10539 // *and* host are false, assume it is not a cross-domain request 10540 // (should only be the case for IE7 and IE compatibility mode). 10541 // Otherwise, evaluate protocol and host of the URL against the origin 10542 // protocol and host. 10543 return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) || 10544 (originAnchor.protocol + '//' + originAnchor.host === 10545 urlAnchor.protocol + '//' + urlAnchor.host)); 10546 } catch (e) { 10547 // If there is an error parsing the URL, assume it is crossDomain. 10548 return true; 10549 } 10550 }, 10551 10552 // Handles "data-method" on links such as: 10553 // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a> 10554 handleMethod: function(link) { 10555 var href = rails.href(link), 10556 method = link.data('method'), 10557 target = link.attr('target'), 10558 csrfToken = rails.csrfToken(), 10559 csrfParam = rails.csrfParam(), 10560 form = $('<form method="post" action="' + href + '"></form>'), 10561 metadataInput = '<input name="_method" value="' + method + '" type="hidden" />'; 10562 10563 if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) { 10564 metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />'; 10565 } 10566 10567 if (target) { form.attr('target', target); } 10568 10569 form.hide().append(metadataInput).appendTo('body'); 10570 form.submit(); 10571 }, 10572 10573 // Helper function that returns form elements that match the specified CSS selector 10574 // If form is actually a "form" element this will return associated elements outside the from that have 10575 // the html form attribute set 10576 formElements: function(form, selector) { 10577 return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector); 10578 }, 10579 10580 /* Disables form elements: 10581 - Caches element value in 'ujs:enable-with' data store 10582 - Replaces element text with value of 'data-disable-with' attribute 10583 - Sets disabled property to true 10584 */ 10585 disableFormElements: function(form) { 10586 rails.formElements(form, rails.disableSelector).each(function() { 10587 rails.disableFormElement($(this)); 10588 }); 10589 }, 10590 10591 disableFormElement: function(element) { 10592 var method, replacement; 10593 10594 method = element.is('button') ? 'html' : 'val'; 10595 replacement = element.data('disable-with'); 10596 10597 if (replacement !== undefined) { 10598 element.data('ujs:enable-with', element[method]()); 10599 element[method](replacement); 10600 } 10601 10602 element.prop('disabled', true); 10603 element.data('ujs:disabled', true); 10604 }, 10605 10606 /* Re-enables disabled form elements: 10607 - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`) 10608 - Sets disabled property to false 10609 */ 10610 enableFormElements: function(form) { 10611 rails.formElements(form, rails.enableSelector).each(function() { 10612 rails.enableFormElement($(this)); 10613 }); 10614 }, 10615 10616 enableFormElement: function(element) { 10617 var method = element.is('button') ? 'html' : 'val'; 10618 if (element.data('ujs:enable-with') !== undefined) { 10619 element[method](element.data('ujs:enable-with')); 10620 element.removeData('ujs:enable-with'); // clean up cache 10621 } 10622 element.prop('disabled', false); 10623 element.removeData('ujs:disabled'); 10624 }, 10625 10626 /* For 'data-confirm' attribute: 10627 - Fires `confirm` event 10628 - Shows the confirmation dialog 10629 - Fires the `confirm:complete` event 10630 10631 Returns `true` if no function stops the chain and user chose yes; `false` otherwise. 10632 Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog. 10633 Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
10634 return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog. 10635 */ 10636 allowAction: function(element) { 10637 var message = element.data('confirm'), 10638 answer = false, callback; 10639 if (!message) { return true; } 10640 10641 if (rails.fire(element, 'confirm')) { 10642 try { 10643 answer = rails.confirm(message); 10644 } catch (e) { 10645 (console.error || console.log).call(console, e.stack || e); 10646 } 10647 callback = rails.fire(element, 'confirm:complete', [answer]); 10648 } 10649 return answer && callback; 10650 }, 10651 10652 // Helper function which checks for blank inputs in a form that match the specified CSS selector 10653 blankInputs: function(form, specifiedSelector, nonBlank) { 10654 var foundInputs = $(), 10655 input, 10656 valueToCheck, 10657 radiosForNameWithNoneSelected, 10658 radioName, 10659 selector = specifiedSelector || 'input,textarea', 10660 requiredInputs = form.find(selector), 10661 checkedRadioButtonNames = {}; 10662 10663 requiredInputs.each(function() { 10664 input = $(this); 10665 if (input.is('input[type=radio]')) { 10666 10667 // Don't count unchecked required radio as blank if other radio with same name is checked, 10668 // regardless of whether same-name radio input has required attribute or not. The spec 10669 // states https://www.w3.org/TR/html5/forms.html#the-required-attribute 10670 radioName = input.attr('name'); 10671 10672 // Skip if we've already seen the radio with this name. 10673 if (!checkedRadioButtonNames[radioName]) { 10674 10675 // If none checked 10676 if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) { 10677 radiosForNameWithNoneSelected = form.find( 10678 'input[type=radio][name="' + radioName + '"]'); 10679 foundInputs = foundInputs.add(radiosForNameWithNoneSelected); 10680 } 10681 10682 // We only need to check each name once. 10683 checkedRadioButtonNames[radioName] = radioName; 10684 } 10685 } else { 10686 valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val(); 10687 if (valueToCheck === nonBlank) { 10688 foundInputs = foundInputs.add(input); 10689 } 10690 } 10691 }); 10692 return foundInputs.length ? foundInputs : false; 10693 }, 10694 10695 // Helper function which checks for non-blank inputs in a form that match the specified CSS selector 10696 nonBlankInputs: function(form, specifiedSelector) { 10697 return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank 10698 }, 10699 10700 // Helper function, needed to provide consistent behavior in IE 10701 stopEverything: function(e) { 10702 $(e.target).trigger('ujs:everythingStopped'); 10703 e.stopImmediatePropagation(); 10704 return false; 10705 }, 10706 10707 // Replace element's html with the 'data-disable-with' after storing original html 10708 // and prevent clicking on it 10709 disableElement: function(element) { 10710 var replacement = element.data('disable-with'); 10711 10712 if (replacement !== undefined) { 10713 element.data('ujs:enable-with', element.html()); // store enabled state 10714 element.html(replacement); 10715 } 10716 10717 element.on('click.railsDisable', function(e) { // prevent further clicking 10718 return rails.stopEverything(e); 10719 }); 10720 element.data('ujs:disabled', true); 10721 }, 10722 10723 // Restore element to its original state which was disabled by 'disableElement' above 10724 enableElement: function(element) { 10725 if (element.data('ujs:enable-with') !== undefined) { 10726 element.html(element.data('ujs:enable-with')); // set to old enabled state 10727 element.removeData('ujs:enable-with'); // clean up cache 10728 } 10729 element.off('click.railsDisable'); // enable element 10730 element.removeData('ujs:disabled'); 10731 } 10732 }; 10733 10734 if (rails.fire($document, 'rails:attachBindings')) { 10735 10736 $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); 10737 10738 // This event works the same as the load event, except that it fires every 10739 // time the page is loaded. 10740 // 10741 // See https://github.com/rails/jquery-ujs/issues/357 10742 // See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching 10743 $(window).on('pageshow.rails', function () { 10744 $($.rails.enableSelector).each(function () { 10745 var element = $(this); 10746 10747 if (element.data('ujs:disabled')) { 10748 $.rails.enableFormElement(element); 10749 } 10750 }); 10751 10752 $($.rails.linkDisableSelector).each(function () { 10753 var element = $(this); 10754 10755 if (element.data('ujs:disabled')) { 10756 $.rails.enableElement(element); 10757 } 10758 }); 10759 }); 10760 10761 $document.on('ajax:complete', rails.linkDisableSelector, function() { 10762 rails.enableElement($(this)); 10763 }); 10764 10765 $document.on('ajax:complete', rails.buttonDisableSelector, function() { 10766 rails.enableFormElement($(this)); 10767 }); 10768 10769 $document.on('click.rails', rails.linkClickSelector, function(e) { 10770 var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey; 10771 if (!rails.allowAction(link)) return rails.stopEverything(e); 10772 10773 if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link); 10774 10775 if (rails.isRemote(link)) { 10776 if (metaClick && (!method || method === 'GET') && !data) { return true; } 10777 10778 var handleRemote = rails.handleRemote(link); 10779 // Response from rails.handleRemote() will either be false or a deferred object promise. 10780 if (handleRemote === false) { 10781 rails.enableElement(link); 10782 } else { 10783 handleRemote.fail( function() { rails.enableElement(link); } ); 10784 } 10785 return false;
10786 10787 } else if (method) { 10788 rails.handleMethod(link); 10789 return false; 10790 } 10791 }); 10792 10793 $document.on('click.rails', rails.buttonClickSelector, function(e) { 10794 var button = $(this); 10795 10796 if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e); 10797 10798 if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button); 10799 10800 var handleRemote = rails.handleRemote(button); 10801 // Response from rails.handleRemote() will either be false or a deferred object promise. 10802 if (handleRemote === false) { 10803 rails.enableFormElement(button); 10804 } else { 10805 handleRemote.fail( function() { rails.enableFormElement(button); } ); 10806 } 10807 return false; 10808 }); 10809 10810 $document.on('change.rails', rails.inputChangeSelector, function(e) { 10811 var link = $(this); 10812 if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e); 10813 10814 rails.handleRemote(link); 10815 return false; 10816 }); 10817 10818 $document.on('submit.rails', rails.formSubmitSelector, function(e) { 10819 var form = $(this), 10820 remote = rails.isRemote(form), 10821 blankRequiredInputs, 10822 nonBlankFileInputs; 10823 10824 if (!rails.allowAction(form)) return rails.stopEverything(e); 10825 10826 // Skip other logic when required values are missing or file upload is present 10827 if (form.attr('novalidate') === undefined) { 10828 if (form.data('ujs:formnovalidate-button') === undefined) { 10829 blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false); 10830 if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { 10831 return rails.stopEverything(e); 10832 } 10833 } else { 10834 // Clear the formnovalidate in case the next button click is not on a formnovalidate button 10835 // Not strictly necessary to do here, since it is also reset on each button click, but just to be certain 10836 form.data('ujs:formnovalidate-button', undefined); 10837 } 10838 } 10839 10840 if (remote) { 10841 nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); 10842 if (nonBlankFileInputs) { 10843 // Slight timeout so that the submit button gets properly serialized 10844 // (make it easy for event handler to serialize form without disabled values) 10845 setTimeout(function(){ rails.disableFormElements(form); }, 13); 10846 var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]); 10847 10848 // Re-enable form elements if event bindings return false (canceling normal form submission) 10849 if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); } 10850 10851 return aborted; 10852 } 10853 10854 rails.handleRemote(form); 10855 return false; 10856 10857 } else { 10858 // Slight timeout so that the submit button gets properly serialized 10859 setTimeout(function(){ rails.disableFormElements(form); }, 13); 10860 } 10861 }); 10862 10863 $document.on('click.rails', rails.formInputClickSelector, function(event) { 10864 var button = $(this); 10865 10866 if (!rails.allowAction(button)) return rails.stopEverything(event); 10867 10868 // Register the pressed submit button 10869 var name = button.attr('name'), 10870 data = name ? {name:name, value:button.val()} : null; 10871 10872 var form = button.closest('form'); 10873 if (form.length === 0) { 10874 form = $('#' + button.attr('form')); 10875 } 10876 form.data('ujs:submit-button', data); 10877 10878 // Save attributes from button 10879 form.data('ujs:formnovalidate-button', button.attr('formnovalidate')); 10880 form.data('ujs:submit-button-formaction', button.attr('formaction')); 10881 form.data('ujs:submit-button-formmethod', button.attr('formmethod')); 10882 }); 10883 10884 $document.on('ajax:send.rails', rails.formSubmitSelector, function(event) { 10885 if (this === event.target) rails.disableFormElements($(this)); 10886 }); 10887 10888 $document.on('ajax:complete.rails', rails.formSubmitSelector, function(event) { 10889 if (this === event.target) rails.enableFormElements($(this)); 10890 }); 10891 10892 $(function(){ 10893 rails.refreshCSRFTokens(); 10894 }); 10895 } 10896 10897 }; 10898 10899 if (window.jQuery) { 10900 jqueryUjsInit(jQuery); 10901 } else if (typeof exports === 'object' && typeof module === 'object') { 10902 module.exports = jqueryUjsInit; 10903 } 10904})(); 10905/*! 10906 * JavaScript Cookie v2.2.0 10907 * https://github.com/js-cookie/js-cookie 10908 * 10909 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack 10910 * Released under the MIT license 10911 */ 10912 10913;(function (factory) { 10914 var registeredInModuleLoader = false;
10915 if (typeof define === 'function' && define.amd) { 10916 define(factory); 10917 registeredInModuleLoader = true; 10918 } 10919 if (typeof exports === 'object') { 10920 module.exports = factory(); 10921 registeredInModuleLoader = true; 10922 } 10923 if (!registeredInModuleLoader) { 10924 var OldCookies = window.Cookies; 10925 var api = window.Cookies = factory(); 10926 api.noConflict = function () { 10927 window.Cookies = OldCookies; 10928 return api; 10929 }; 10930 } 10931}(function () { 10932 function extend () { 10933 var i = 0; 10934 var result = {}; 10935 for (; i < arguments.length; i++) { 10936 var attributes = arguments[ i ]; 10937 for (var key in attributes) { 10938 result[key] = attributes[key]; 10939 } 10940 } 10941 return result; 10942 } 10943 10944 function init (converter) { 10945 function api (key, value, attributes) { 10946 var result; 10947 if (typeof document === 'undefined') { 10948 return; 10949 } 10950 10951 // Write 10952 10953 if (arguments.length > 1) { 10954 attributes = extend({ 10955 path: '/' 10956 }, api.defaults, attributes); 10957 10958 if (typeof attributes.expires === 'number') { 10959 var expires = new Date(); 10960 expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5); 10961 attributes.expires = expires; 10962 } 10963 10964 // We're using "expires" because "max-age" is not supported by IE 10965 attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; 10966 10967 try { 10968 result = JSON.stringify(value); 10969 if (/^[\{\[]/.test(result)) { 10970 value = result; 10971 } 10972 } catch (e) {} 10973 10974 if (!converter.write) { 10975 value = encodeURIComponent(String(value)) 10976 .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); 10977 } else { 10978 value = converter.write(value, key); 10979 } 10980 10981 key = encodeURIComponent(String(key)); 10982 key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent); 10983 key = key.replace(/[\(\)]/g, escape); 10984 10985 var stringifiedAttributes = ''; 10986 10987 for (var attributeName in attributes) { 10988 if (!attributes[attributeName]) { 10989 continue; 10990 } 10991 stringifiedAttributes += '; ' + attributeName; 10992 if (attributes[attributeName] === true) { 10993 continue; 10994 } 10995 stringifiedAttributes += '=' + attributes[attributeName]; 10996 } 10997 return (document.cookie = key + '=' + value + stringifiedAttributes); 10998 } 10999 11000 // Read 11001 11002 if (!key) { 11003 result = {}; 11004 } 11005 11006 // To prevent the for loop in the first place assign an empty array 11007 // in case there are no cookies at all. Also prevents odd result when 11008 // calling "get()" 11009 var cookies = document.cookie ? document.cookie.split('; ') : []; 11010 var rdecode = /(%[0-9A-Z]{2})+/g; 11011 var i = 0; 11012 11013 for (; i < cookies.length; i++) { 11014 var parts = cookies[i].split('='); 11015 var cookie = parts.slice(1).join('='); 11016 11017 if (!this.json && cookie.charAt(0) === '"') { 11018 cookie = cookie.slice(1, -1); 11019 } 11020 11021 try { 11022 var name = parts[0].replace(rdecode, decodeURIComponent); 11023 cookie = converter.read ? 11024 converter.read(cookie, name) : converter(cookie, name) || 11025 cookie.replace(rdecode, decodeURIComponent); 11026 11027 if (this.json) { 11028 try { 11029 cookie = JSON.parse(cookie); 11030 } catch (e) {} 11031 } 11032 11033 if (key === name) { 11034 result = cookie; 11035 break; 11036 } 11037 11038 if (!key) { 11039 result[name] = cookie; 11040 } 11041 } catch (e) {} 11042 } 11043 11044 return result; 11045 } 11046 11047 api.set = api; 11048 api.get = function (key) { 11049 return api.call(api, key); 11050 }; 11051 api.getJSON = function () { 11052 return api.apply({ 11053 json: true 11054 }, [].slice.call(arguments)); 11055 }; 11056 api.defaults = {}; 11057 11058 api.remove = function (key, attributes) { 11059 api(key, '', extend(attributes, { 11060 expires: -1 11061 })); 11062 }; 11063 11064 api.withConverter = init; 11065 11066 return api; 11067 } 11068 11069 return init(function () {}); 11070})); 11071/* 11072 jQuery deparam is an extraction of the deparam method from Ben Alman's jQuery BBQ 11073 http://benalman.com/projects/jquery-bbq-plugin/ 11074*/ 11075 11076(function ($) { 11077 $.deparam = function (params, coerce) { 11078 var obj = {}, 11079 coerce_types = { 'true': !0, 'false': !1, 'null': null }; 11080 11081 // Iterate over all name=value pairs. 11082 $.each(params.replace(/\+/g, ' ').split('&'), function (j,v) { 11083 var param = v.split('='), 11084 key, 11085 val, 11086 cur = obj, 11087 i = 0; 11088 11089 // Try to decode the key parameter safely
11090 try { 11091 key = decodeURIComponent(param[0]) 11092 } catch (e) { 11093 if (typeof window !== 'undefined' 11094 && window.Sentry 11095 && window.Sentry.captureException 11096 ) { 11097 window.Sentry.captureException(new Error('URL parameter key decoding failed'), { 11098 tags: { 11099 error_type: 'url_decode_failure', 11100 library: 'jquery_deparam', 11101 param_type: 'key', 11102 }, 11103 extra: { 11104 original_key: param[0], 11105 full_param: v, 11106 params_string: params, 11107 error_message: e.message, 11108 stack_trace: e.stack, 11109 timestamp: new Date().toISOString(), 11110 page_url: typeof window !== 'undefined' ? window.location.href : 'unknown', 11111 }, 11112 level: 'warning', 11113 }) 11114 } 11115 key = param[0] 11116 } 11117 11118 // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it 11119 // into its component parts. 11120 var keys = key.split(']['), 11121 keys_last = keys.length - 1; 11122 11123 // If the first keys part contains [ and the last ends with ], then [] 11124 // are correctly balanced. 11125 if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) { 11126 // Remove the trailing ] from the last keys part. 11127 keys[keys_last] = keys[keys_last].replace(/\]$/, ''); 11128 11129 // Split first keys part into two parts on the [ and add them back onto 11130 // the beginning of the keys array. 11131 keys = keys.shift().split('[').concat(keys); 11132 11133 keys_last = keys.length - 1; 11134 } else { 11135 // Basic 'foo' style key. 11136 keys_last = 0; 11137 } 11138 11139 // Are we dealing with a name=value pair, or just a name? 11140 if (param.length === 2) { 11141 try { 11142 val = decodeURIComponent(param[1]) 11143 } catch (e) { 11144 if (typeof window !== 'undefined' 11145 && window.Sentry 11146 && window.Sentry.captureException 11147 ) { 11148 window.Sentry.captureException(new Error('URL parameter value decoding failed'), { 11149 tags: { 11150 error_type: 'url_decode_failure', 11151 library: 'jquery_deparam', 11152 param_type: 'value', 11153 }, 11154 extra: { 11155 original_value: param[1], 11156 decoded_key: key, 11157 full_param: v, 11158 params_string: params, 11159 error_message: e.message, 11160 stack_trace: e.stack, 11161 timestamp: new Date().toISOString(), 11162 page_url: typeof window !== 'undefined' ? window.location.href : 'unknown', 11163 }, 11164 level: 'warning', 11165 }) 11166 } 11167 val = param[1] 11168 } 11169 11170 // Coerce values. 11171 if (coerce) { 11172 val = val && !isNaN(val) ? +val // number 11173 : val === 'undefined' ? undefined // undefined 11174 : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null 11175 : val; // string 11176 } 11177 11178 if ( keys_last ) { 11179 // Complex key, build deep object structure based on a few rules: 11180 // * The 'cur' pointer starts at the object top-level. 11181 // * [] = array push (n is set to array length), [n] = array if n is 11182 // numeric, otherwise object. 11183 // * If at the last keys part, set the value. 11184 // * For each keys part, if the current level is undefined create an 11185 // object or array based on the type of the next keys part. 11186 // * Move the 'cur' pointer to the next level. 11187 // * Rinse & repeat. 11188 for (; i <= keys_last; i++) { 11189 key = keys[i] === '' ? cur.length : keys[i]; 11190 cur = cur[key] = i < keys_last 11191 ? cur[key] || (keys[i+1] && isNaN(keys[i+1]) ? {} : []) 11192 : val; 11193 } 11194 11195 } else { 11196 // Simple key, even simpler rules, since only scalars and shallow 11197 // arrays are allowed. 11198 11199 if ($.isArray(obj[key])) { 11200 // val is already an array, so push on the next value. 11201 obj[key].push( val ); 11202 11203 } else if (obj[key] !== undefined) { 11204 // val isn't an array, but since a second value has been specified, 11205 // convert val into an array.
vendor: 16,190 bytes, lines 11206-11779
11206 obj[key] = [obj[key], val]; 11207 11208 } else { 11209 // val is a scalar. 11210 obj[key] = val; 11211 } 11212 } 11213 11214 } else if (key) { 11215 // No value was defined, so set something meaningful. 11216 obj[key] = coerce 11217 ? undefined 11218 : ''; 11219 } 11220 }); 11221 11222 return obj; 11223 }; 11224})(jQuery); 11225/*! jQuery UI - v1.11.4+CommonJS - 2015-08-28 11226* http://jqueryui.com 11227* Includes: widget.js 11228* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ 11229 11230 11231(function( factory ) { 11232 if ( typeof define === "function" && define.amd ) { 11233 11234 // AMD. Register as an anonymous module. 11235 define([ "jquery" ], factory ); 11236 11237 } else if ( typeof exports === "object" ) { 11238 11239 // Node/CommonJS 11240 factory( require( "jquery" ) ); 11241 11242 } else { 11243 11244 // Browser globals 11245 factory( jQuery ); 11246 } 11247}(function( $ ) { 11248/*! 11249 * jQuery UI Widget 1.11.4 11250 * http://jqueryui.com 11251 * 11252 * Copyright jQuery Foundation and other contributors 11253 * Released under the MIT license. 11254 * http://jquery.org/license 11255 * 11256 * http://api.jqueryui.com/jQuery.widget/ 11257 */ 11258 11259 11260var widget_uuid = 0, 11261 widget_slice = Array.prototype.slice; 11262 11263$.cleanData = (function( orig ) { 11264 return function( elems ) { 11265 var events, elem, i; 11266 for ( i = 0; (elem = elems[i]) != null; i++ ) { 11267 try { 11268 11269 // Only trigger remove when necessary to save time 11270 events = $._data( elem, "events" ); 11271 if ( events && events.remove ) { 11272 $( elem ).triggerHandler( "remove" ); 11273 } 11274 11275 // http://bugs.jquery.com/ticket/8235 11276 } catch ( e ) {} 11277 } 11278 orig( elems ); 11279 }; 11280})( $.cleanData ); 11281 11282$.widget = function( name, base, prototype ) { 11283 var fullName, existingConstructor, constructor, basePrototype, 11284 // proxiedPrototype allows the provided prototype to remain unmodified 11285 // so that it can be used as a mixin for multiple widgets (#8876) 11286 proxiedPrototype = {}, 11287 namespace = name.split( "." )[ 0 ]; 11288 11289 name = name.split( "." )[ 1 ]; 11290 fullName = namespace + "-" + name; 11291 11292 if ( !prototype ) { 11293 prototype = base; 11294 base = $.Widget; 11295 } 11296 11297 // create selector for plugin 11298 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 11299 return !!$.data( elem, fullName ); 11300 }; 11301 11302 $[ namespace ] = $[ namespace ] || {}; 11303 existingConstructor = $[ namespace ][ name ]; 11304 constructor = $[ namespace ][ name ] = function( options, element ) { 11305 // allow instantiation without "new" keyword 11306 if ( !this._createWidget ) { 11307 return new constructor( options, element ); 11308 } 11309 11310 // allow instantiation without initializing for simple inheritance 11311 // must use "new" keyword (the code above always passes args) 11312 if ( arguments.length ) { 11313 this._createWidget( options, element ); 11314 } 11315 }; 11316 // extend with the existing constructor to carry over any static properties 11317 $.extend( constructor, existingConstructor, { 11318 version: prototype.version, 11319 // copy the object used to create the prototype in case we need to 11320 // redefine the widget later 11321 _proto: $.extend( {}, prototype ), 11322 // track widgets that inherit from this widget in case this widget is 11323 // redefined after a widget inherits from it 11324 _childConstructors: [] 11325 }); 11326 11327 basePrototype = new base(); 11328 // we need to make the options hash a property directly on the new instance 11329 // otherwise we'll modify the options hash on the prototype that we're 11330 // inheriting from 11331 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 11332 $.each( prototype, function( prop, value ) { 11333 if ( !$.isFunction( value ) ) { 11334 proxiedPrototype[ prop ] = value; 11335 return; 11336 } 11337 proxiedPrototype[ prop ] = (function() { 11338 var _super = function() { 11339 return base.prototype[ prop ].apply( this, arguments ); 11340 }, 11341 _superApply = function( args ) { 11342 return base.prototype[ prop ].apply( this, args ); 11343 }; 11344 return function() { 11345 var __super = this._super, 11346 __superApply = this._superApply, 11347 returnValue; 11348 11349 this._super = _super; 11350 this._superApply = _superApply; 11351 11352 returnValue = value.apply( this, arguments ); 11353 11354 this._super = __super; 11355 this._superApply = __superApply; 11356 11357 return returnValue; 11358 }; 11359 })(); 11360 }); 11361 constructor.prototype = $.widget.extend( basePrototype, { 11362 // TODO: remove support for widgetEventPrefix 11363 // always use the name + a colon as the prefix, e.g., draggable:start 11364 // don't prefix for widgets that aren't DOM-based 11365 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name 11366 }, proxiedPrototype, { 11367 constructor: constructor, 11368 namespace: namespace, 11369 widgetName: name, 11370 widgetFullName: fullName 11371 }); 11372 11373 // If this widget is being redefined then we need to find all widgets that 11374 // are inheriting from it and redefine all of them so that they inherit from 11375 // the new version of this widget. We're essentially trying to replace one 11376 // level in the prototype chain. 11377 if ( existingConstructor ) { 11378 $.each( existingConstructor._childConstructors, function( i, child ) { 11379 var childPrototype = child.prototype; 11380 11381 // redefine the child widget using the same prototype that was 11382 // originally used, but inherit from the new version of the base 11383 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); 11384 }); 11385 // remove the list of existing child constructors from the old constructor 11386 // so the old child constructors can be garbage collected 11387 delete existingConstructor._childConstructors; 11388 } else { 11389 base._childConstructors.push( constructor ); 11390 } 11391 11392 $.widget.bridge( name, constructor ); 11393 11394 return constructor; 11395}; 11396 11397$.widget.extend = function( target ) { 11398 var input = widget_slice.call( arguments, 1 ), 11399 inputIndex = 0, 11400 inputLength = input.length, 11401 key, 11402 value; 11403 for ( ; inputIndex < inputLength; inputIndex++ ) { 11404 for ( key in input[ inputIndex ] ) { 11405 value = input[ inputIndex ][ key ]; 11406 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 11407 // Clone objects 11408 if ( $.isPlainObject( value ) ) { 11409 target[ key ] = $.isPlainObject( target[ key ] ) ? 11410 $.widget.extend( {}, target[ key ], value ) : 11411 // Don't extend strings, arrays, etc. with objects 11412 $.widget.extend( {}, value ); 11413 // Copy everything else by reference 11414 } else { 11415 target[ key ] = value; 11416 } 11417 } 11418 } 11419 } 11420 return target; 11421}; 11422 11423$.widget.bridge = function( name, object ) { 11424 var fullName = object.prototype.widgetFullName || name; 11425 $.fn[ name ] = function( options ) { 11426 var isMethodCall = typeof options === "string", 11427 args = widget_slice.call( arguments, 1 ), 11428 returnValue = this; 11429 11430 if ( isMethodCall ) { 11431 this.each(function() { 11432 var methodValue, 11433 instance = $.data( this, fullName ); 11434 if ( options === "instance" ) { 11435 returnValue = instance; 11436 return false; 11437 } 11438 if ( !instance ) { 11439 return $.error( "cannot call methods on " + name + " prior to initialization; " + 11440 "attempted to call method '" + options + "'" ); 11441 } 11442 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { 11443 return $.error( "no such method '" + options + "' for " + name + " widget instance" ); 11444 } 11445 methodValue = instance[ options ].apply( instance, args ); 11446 if ( methodValue !== instance && methodValue !== undefined ) { 11447 returnValue = methodValue && methodValue.jquery ? 11448 returnValue.pushStack( methodValue.get() ) : 11449 methodValue; 11450 return false; 11451 } 11452 }); 11453 } else { 11454 11455 // Allow multiple hashes to be passed on init 11456 if ( args.length ) { 11457 options = $.widget.extend.apply( null, [ options ].concat(args) ); 11458 } 11459 11460 this.each(function() { 11461 var instance = $.data( this, fullName ); 11462 if ( instance ) { 11463 instance.option( options || {} ); 11464 if ( instance._init ) { 11465 instance._init(); 11466 } 11467 } else { 11468 $.data( this, fullName, new object( options, this ) ); 11469 } 11470 }); 11471 } 11472 11473 return returnValue; 11474 }; 11475}; 11476 11477$.Widget = function( /* options, element */ ) {}; 11478$.Widget._childConstructors = []; 11479 11480$.Widget.prototype = { 11481 widgetName: "widget", 11482 widgetEventPrefix: "", 11483 defaultElement: "<div>", 11484 options: { 11485 disabled: false, 11486 11487 // callbacks 11488 create: null 11489 }, 11490 _createWidget: function( options, element ) { 11491 element = $( element || this.defaultElement || this )[ 0 ]; 11492 this.element = $( element ); 11493 this.uuid = widget_uuid++; 11494 this.eventNamespace = "." + this.widgetName + this.uuid; 11495 11496 this.bindings = $(); 11497 this.hoverable = $(); 11498 this.focusable = $(); 11499 11500 if ( element !== this ) { 11501 $.data( element, this.widgetFullName, this ); 11502 this._on( true, this.element, { 11503 remove: function( event ) { 11504 if ( event.target === element ) { 11505 this.destroy(); 11506 } 11507 } 11508 }); 11509 this.document = $( element.style ? 11510 // element within the document 11511 element.ownerDocument : 11512 // element is window or document 11513 element.document || element ); 11514 this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); 11515 } 11516 11517 this.options = $.widget.extend( {}, 11518 this.options, 11519 this._getCreateOptions(), 11520 options ); 11521 11522 this._create(); 11523 this._trigger( "create", null, this._getCreateEventData() ); 11524 this._init(); 11525 }, 11526 _getCreateOptions: $.noop, 11527 _getCreateEventData: $.noop, 11528 _create: $.noop, 11529 _init: $.noop, 11530 11531 destroy: function() { 11532 this._destroy(); 11533 // we can probably remove the unbind calls in 2.0 11534 // all event bindings should go through this._on() 11535 this.element 11536 .unbind( this.eventNamespace ) 11537 .removeData( this.widgetFullName ) 11538 // support: jquery <1.6.3 11539 // http://bugs.jquery.com/ticket/9413 11540 .removeData( $.camelCase( this.widgetFullName ) ); 11541 this.widget() 11542 .unbind( this.eventNamespace ) 11543 .removeAttr( "aria-disabled" ) 11544 .removeClass( 11545 this.widgetFullName + "-disabled " + 11546 "ui-state-disabled" ); 11547 11548 // clean up events and states 11549 this.bindings.unbind( this.eventNamespace ); 11550 this.hoverable.removeClass( "ui-state-hover" ); 11551 this.focusable.removeClass( "ui-state-focus" ); 11552 }, 11553 _destroy: $.noop, 11554 11555 widget: function() { 11556 return this.element; 11557 }, 11558 11559 option: function( key, value ) { 11560 var options = key, 11561 parts, 11562 curOption, 11563 i; 11564 11565 if ( arguments.length === 0 ) { 11566 // don't return a reference to the internal hash 11567 return $.widget.extend( {}, this.options ); 11568 } 11569 11570 if ( typeof key === "string" ) { 11571 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 11572 options = {}; 11573 parts = key.split( "." ); 11574 key = parts.shift(); 11575 if ( parts.length ) { 11576 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 11577 for ( i = 0; i < parts.length - 1; i++ ) { 11578 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 11579 curOption = curOption[ parts[ i ] ]; 11580 } 11581 key = parts.pop(); 11582 if ( arguments.length === 1 ) { 11583 return curOption[ key ] === undefined ? null : curOption[ key ]; 11584 } 11585 curOption[ key ] = value; 11586 } else { 11587 if ( arguments.length === 1 ) { 11588 return this.options[ key ] === undefined ? null : this.options[ key ]; 11589 } 11590 options[ key ] = value; 11591 } 11592 } 11593 11594 this._setOptions( options ); 11595 11596 return this; 11597 }, 11598 _setOptions: function( options ) { 11599 var key; 11600 11601 for ( key in options ) { 11602 this._setOption( key, options[ key ] ); 11603 } 11604 11605 return this; 11606 }, 11607 _setOption: function( key, value ) { 11608 this.options[ key ] = value; 11609 11610 if ( key === "disabled" ) { 11611 this.widget() 11612 .toggleClass( this.widgetFullName + "-disabled", !!value ); 11613 11614 // If the widget is becoming disabled, then nothing is interactive 11615 if ( value ) { 11616 this.hoverable.removeClass( "ui-state-hover" ); 11617 this.focusable.removeClass( "ui-state-focus" ); 11618 } 11619 } 11620 11621 return this; 11622 }, 11623 11624 enable: function() { 11625 return this._setOptions({ disabled: false }); 11626 }, 11627 disable: function() { 11628 return this._setOptions({ disabled: true }); 11629 }, 11630 11631 _on: function( suppressDisabledCheck, element, handlers ) { 11632 var delegateElement, 11633 instance = this; 11634 11635 // no suppressDisabledCheck flag, shuffle arguments 11636 if ( typeof suppressDisabledCheck !== "boolean" ) { 11637 handlers = element; 11638 element = suppressDisabledCheck; 11639 suppressDisabledCheck = false; 11640 } 11641 11642 // no element argument, shuffle and use this.element 11643 if ( !handlers ) { 11644 handlers = element; 11645 element = this.element; 11646 delegateElement = this.widget(); 11647 } else { 11648 element = delegateElement = $( element ); 11649 this.bindings = this.bindings.add( element ); 11650 } 11651 11652 $.each( handlers, function( event, handler ) { 11653 function handlerProxy() { 11654 // allow widgets to customize the disabled handling 11655 // - disabled as an array instead of boolean 11656 // - disabled class as method for disabling individual parts 11657 if ( !suppressDisabledCheck && 11658 ( instance.options.disabled === true || 11659 $( this ).hasClass( "ui-state-disabled" ) ) ) { 11660 return; 11661 } 11662 return ( typeof handler === "string" ? instance[ handler ] : handler ) 11663 .apply( instance, arguments ); 11664 } 11665 11666 // copy the guid so direct unbinding works 11667 if ( typeof handler !== "string" ) { 11668 handlerProxy.guid = handler.guid = 11669 handler.guid || handlerProxy.guid || $.guid++; 11670 } 11671 11672 var match = event.match( /^([\w:-]*)\s*(.*)$/ ), 11673 eventName = match[1] + instance.eventNamespace, 11674 selector = match[2]; 11675 if ( selector ) { 11676 delegateElement.delegate( selector, eventName, handlerProxy ); 11677 } else { 11678 element.bind( eventName, handlerProxy ); 11679 } 11680 }); 11681 }, 11682 11683 _off: function( element, eventName ) { 11684 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + 11685 this.eventNamespace; 11686 element.unbind( eventName ).undelegate( eventName ); 11687 11688 // Clear the stack to avoid memory leaks (#10056) 11689 this.bindings = $( this.bindings.not( element ).get() ); 11690 this.focusable = $( this.focusable.not( element ).get() ); 11691 this.hoverable = $( this.hoverable.not( element ).get() ); 11692 }, 11693 11694 _delay: function( handler, delay ) { 11695 function handlerProxy() { 11696 return ( typeof handler === "string" ? instance[ handler ] : handler ) 11697 .apply( instance, arguments ); 11698 } 11699 var instance = this; 11700 return setTimeout( handlerProxy, delay || 0 ); 11701 }, 11702 11703 _hoverable: function( element ) { 11704 this.hoverable = this.hoverable.add( element ); 11705 this._on( element, { 11706 mouseenter: function( event ) { 11707 $( event.currentTarget ).addClass( "ui-state-hover" ); 11708 }, 11709 mouseleave: function( event ) { 11710 $( event.currentTarget ).removeClass( "ui-state-hover" ); 11711 } 11712 }); 11713 }, 11714 11715 _focusable: function( element ) { 11716 this.focusable = this.focusable.add( element ); 11717 this._on( element, { 11718 focusin: function( event ) { 11719 $( event.currentTarget ).addClass( "ui-state-focus" ); 11720 }, 11721 focusout: function( event ) { 11722 $( event.currentTarget ).removeClass( "ui-state-focus" ); 11723 } 11724 }); 11725 }, 11726 11727 _trigger: function( type, event, data ) { 11728 var prop, orig, 11729 callback = this.options[ type ]; 11730 11731 data = data || {}; 11732 event = $.Event( event ); 11733 event.type = ( type === this.widgetEventPrefix ? 11734 type : 11735 this.widgetEventPrefix + type ).toLowerCase(); 11736 // the original event may come from any element 11737 // so we need to reset the target on the new event 11738 event.target = this.element[ 0 ]; 11739 11740 // copy original event properties over to the new event 11741 orig = event.originalEvent; 11742 if ( orig ) { 11743 for ( prop in orig ) { 11744 if ( !( prop in event ) ) { 11745 event[ prop ] = orig[ prop ]; 11746 } 11747 } 11748 } 11749 11750 this.element.trigger( event, data ); 11751 return !( $.isFunction( callback ) && 11752 callback.apply( this.element[0], [ event ].concat( data ) ) === false || 11753 event.isDefaultPrevented() ); 11754 } 11755}; 11756 11757$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 11758 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 11759 if ( typeof options === "string" ) { 11760 options = { effect: options }; 11761 } 11762 var hasOptions, 11763 effectName = !options ? 11764 method : 11765 options === true || typeof options === "number" ? 11766 defaultEffect : 11767 options.effect || defaultEffect; 11768 options = options || {}; 11769 if ( typeof options === "number" ) { 11770 options = { duration: options }; 11771 } 11772 hasOptions = !$.isEmptyObject( options ); 11773 options.complete = callback; 11774 if ( options.delay ) { 11775 element.delay( options.delay ); 11776 } 11777 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 11778 element[ method ]( options ); 11779 } else if ( effectName !== method && element[ effectName ] ) {
11780 element[ effectName ]( options.duration, options.easing, callback ); 11781 } else { 11782 element.queue(function( next ) { 11783 $( this )[ method ](); 11784 if ( callback ) { 11785 callback.call( element[ 0 ] ); 11786 } 11787 next(); 11788 }); 11789 } 11790 }; 11791}); 11792 11793var widget = $.widget; 11794 11795 11796 11797})); 11798/* 11799 * jQuery Iframe Transport Plugin 11800 * https://github.com/blueimp/jQuery-File-Upload 11801 * 11802 * Copyright 2011, Sebastian Tschan 11803 * https://blueimp.net 11804 * 11805 * Licensed under the MIT license: 11806 * http://www.opensource.org/licenses/MIT 11807 */ 11808 11809/* global define, require, window, document */ 11810 11811 11812;(function (factory) { 11813 'use strict'; 11814 if (typeof define === 'function' && define.amd) { 11815 // Register as an anonymous AMD module: 11816 define(['jquery'], factory); 11817 } else if (typeof exports === 'object') { 11818 // Node/CommonJS: 11819 factory(require('jquery')); 11820 } else { 11821 // Browser globals: 11822 factory(window.jQuery); 11823 } 11824}(function ($) { 11825 'use strict'; 11826 11827 // Helper variable to create unique names for the transport iframes: 11828 var counter = 0; 11829 11830 // The iframe transport accepts four additional options: 11831 // options.fileInput: a jQuery collection of file input fields 11832 // options.paramName: the parameter name for the file form data, 11833 // overrides the name property of the file input field(s), 11834 // can be a string or an array of strings. 11835 // options.formData: an array of objects with name and value properties, 11836 // equivalent to the return data of .serializeArray(), e.g.: 11837 // [{name: 'a', value: 1}, {name: 'b', value: 2}] 11838 // options.initialIframeSrc: the URL of the initial iframe src, 11839 // by default set to "javascript:false;" 11840 $.ajaxTransport('iframe', function (options) { 11841 if (options.async) { 11842 // javascript:false as initial iframe src 11843 // prevents warning popups on HTTPS in IE6: 11844 /*jshint scripturl: true */ 11845 var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', 11846 /*jshint scripturl: false */ 11847 form, 11848 iframe, 11849 addParamChar; 11850 return { 11851 send: function (_, completeCallback) { 11852 form = $('<form style="display:none;"></form>'); 11853 form.attr('accept-charset', options.formAcceptCharset); 11854 addParamChar = /\?/.test(options.url) ? '&' : '?'; 11855 // XDomainRequest only supports GET and POST: 11856 if (options.type === 'DELETE') { 11857 options.url = options.url + addParamChar + '_method=DELETE'; 11858 options.type = 'POST'; 11859 } else if (options.type === 'PUT') { 11860 options.url = options.url + addParamChar + '_method=PUT'; 11861 options.type = 'POST'; 11862 } else if (options.type === 'PATCH') { 11863 options.url = options.url + addParamChar + '_method=PATCH'; 11864 options.type = 'POST'; 11865 } 11866 // IE versions below IE8 cannot set the name property of 11867 // elements that have already been added to the DOM, 11868 // so we set the name along with the iframe HTML markup: 11869 counter += 1; 11870 iframe = $( 11871 '<iframe src="' + initialIframeSrc + 11872 '" name="iframe-transport-' + counter + '"></iframe>' 11873 ).bind('load', function () { 11874 var fileInputClones, 11875 paramNames = $.isArray(options.paramName) ? 11876 options.paramName : [options.paramName]; 11877 iframe 11878 .unbind('load') 11879 .bind('load', function () { 11880 var response; 11881 // Wrap in a try/catch block to catch exceptions thrown 11882 // when trying to access cross-domain iframe contents: 11883 try { 11884 response = iframe.contents(); 11885 // Google Chrome and Firefox do not throw an 11886 // exception when calling iframe.contents() on 11887 // cross-domain requests, so we unify the response: 11888 if (!response.length || !response[0].firstChild) { 11889 throw new Error(); 11890 } 11891 } catch (e) { 11892 response = undefined; 11893 } 11894 // The complete callback returns the 11895 // iframe content document as response object: 11896 completeCallback( 11897 200, 11898 'success', 11899 {'iframe': response} 11900 ); 11901 // Fix for IE endless progress bar activity bug 11902 // (happens on form submits to iframe targets): 11903 $('<iframe src="' + initialIframeSrc + '"></iframe>') 11904 .appendTo(form); 11905 window.setTimeout(function () { 11906 // Removing the form in a setTimeout call 11907 // allows Chrome's developer tools to display 11908 // the response result 11909 form.remove(); 11910 }, 0); 11911 }); 11912 form 11913 .prop('target', iframe.prop('name')) 11914 .prop('action', options.url) 11915 .prop('method', options.type); 11916 if (options.formData) { 11917 $.each(options.formData, function (index, field) { 11918 $('<input type="hidden"/>') 11919 .prop('name', field.name) 11920 .val(field.value) 11921 .appendTo(form); 11922 }); 11923 } 11924 if (options.fileInput && options.fileInput.length && 11925 options.type === 'POST') { 11926 fileInputClones = options.fileInput.clone(); 11927 // Insert a clone for each file input field: 11928 options.fileInput.after(function (index) { 11929 return fileInputClones[index]; 11930 }); 11931 if (options.paramName) { 11932 options.fileInput.each(function (index) { 11933 $(this).prop( 11934 'name', 11935 paramNames[index] || options.paramName 11936 ); 11937 }); 11938 } 11939 // Appending the file input fields to the hidden form 11940 // removes them from their original location: 11941 form 11942 .append(options.fileInput) 11943 .prop('enctype', 'multipart/form-data') 11944 // enctype must be set as encoding for IE: 11945 .prop('encoding', 'multipart/form-data'); 11946 // Remove the HTML5 form attribute from the input(s): 11947 options.fileInput.removeAttr('form'); 11948 } 11949 form.submit(); 11950 // Insert the file input fields at their original location 11951 // by replacing the clones with the originals: 11952 if (fileInputClones && fileInputClones.length) { 11953 options.fileInput.each(function (index, input) { 11954 var clone = $(fileInputClones[index]); 11955 // Restore the original name and form properties: 11956 $(input) 11957 .prop('name', clone.prop('name')) 11958 .attr('form', clone.attr('form')); 11959 clone.replaceWith(input); 11960 }); 11961 } 11962 }); 11963 form.append(iframe).appendTo(document.body); 11964 }, 11965 abort: function () { 11966 if (iframe) { 11967 // javascript:false as iframe src aborts the request 11968 // and prevents warning popups on HTTPS in IE6. 11969 // concat is used to avoid the "Script URL" JSLint error: 11970 iframe 11971 .unbind('load') 11972 .prop('src', initialIframeSrc); 11973 } 11974 if (form) { 11975 form.remove(); 11976 } 11977 } 11978 }; 11979 } 11980 }); 11981 11982 // The iframe transport returns the iframe content document as response. 11983 // The following adds converters from iframe to text, json, html, xml 11984 // and script. 11985 // Please note that the Content-Type for JSON responses has to be text/plain 11986 // or text/html, if the browser doesn't include application/json in the 11987 // Accept header, else IE will show a download dialog. 11988 // The Content-Type for XML responses on the other hand has to be al
11988ways 11989 // application/xml or text/xml, so IE properly parses the XML response. 11990 // See also 11991 // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation 11992 $.ajaxSetup({ 11993 converters: { 11994 'iframe text': function (iframe) { 11995 return iframe && $(iframe[0].body).text(); 11996 }, 11997 'iframe json': function (iframe) { 11998 return iframe && $.parseJSON($(iframe[0].body).text()); 11999 }, 12000 'iframe html': function (iframe) { 12001 return iframe && $(iframe[0].body).html(); 12002 }, 12003 'iframe xml': function (iframe) { 12004 var xmlDoc = iframe && iframe[0]; 12005 return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : 12006 $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) || 12007 $(xmlDoc.body).html()); 12008 }, 12009 'iframe script': function (iframe) { 12010 return iframe && $.globalEval($(iframe[0].body).text()); 12011 } 12012 } 12013 }); 12014 12015})); 12016/* 12017 * jQuery File Upload Plugin 12018 * https://github.com/blueimp/jQuery-File-Upload 12019 * 12020 * Copyright 2010, Sebastian Tschan 12021 * https://blueimp.net 12022 * 12023 * Licensed under the MIT license: 12024 * http://www.opensource.org/licenses/MIT 12025 */ 12026 12027/* jshint nomen:false */ 12028/* global define, require, window, document, location, Blob, FormData */ 12029 12030 12031;(function (factory) { 12032 'use strict'; 12033 if (typeof define === 'function' && define.amd) { 12034 // Register as an anonymous AMD module: 12035 define([ 12036 'jquery', 12037 'jquery.ui.widget' 12038 ], factory); 12039 } else if (typeof exports === 'object') { 12040 // Node/CommonJS: 12041 factory( 12042 require('jquery'), 12043 require('./vendor/jquery.ui.widget') 12044 ); 12045 } else { 12046 // Browser globals: 12047 factory(window.jQuery); 12048 } 12049}(function ($) { 12050 'use strict'; 12051 12052 // Detect file input support, based on 12053 // http://viljamis.com/blog/2012/file-upload-support-on-mobile/ 12054 $.support.fileInput = !(new RegExp( 12055 // Handle devices which give false positives for the feature detection: 12056 '(Android (1\\.[0156]|2\\.[01]))' + 12057 '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' + 12058 '|(w(eb)?OSBrowser)|(webOS)' + 12059 '|(Kindle/(1\\.0|2\\.[05]|3\\.0))' 12060 ).test(window.navigator.userAgent) || 12061 // Feature detection for all other devices: 12062 $('<input type="file">').prop('disabled')); 12063 12064 // The FileReader API is not actually used, but works as feature detection, 12065 // as some Safari versions (5?) support XHR file uploads via the FormData API, 12066 // but not non-multipart XHR file uploads. 12067 // window.XMLHttpRequestUpload is not available on IE10, so we check for 12068 // window.ProgressEvent instead to detect XHR2 file upload capability: 12069 $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader); 12070 $.support.xhrFormDataFileUpload = !!window.FormData; 12071 12072 // Detect support for Blob slicing (required for chunked uploads): 12073 $.support.blobSlice = window.Blob && (Blob.prototype.slice || 12074 Blob.prototype.webkitSlice || Blob.prototype.mozSlice); 12075 12076 // Helper function to create drag handlers for dragover/dragenter/dragleave: 12077 function getDragHandler(type) { 12078 var isDragOver = type === 'dragover'; 12079 return function (e) { 12080 e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; 12081 var dataTransfer = e.dataTransfer; 12082 if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 && 12083 this._trigger( 12084 type, 12085 $.Event(type, {delegatedEvent: e}) 12086 ) !== false) { 12087 e.preventDefault(); 12088 if (isDragOver) { 12089 dataTransfer.dropEffect = 'copy'; 12090 } 12091 } 12092 }; 12093 } 12094 12095 // The fileupload widget listens for change events on file input fields defined 12096 // via fileInput setting and paste or drop events of the given dropZone. 12097 // In addition to the default jQuery Widget methods, the fileupload widget 12098 // exposes the "add" and "send" methods, to add or directly send files using 12099 // the fileupload API. 12100 // By default, files added via file input selection, paste, drag & drop or 12101 // "add" method are uploaded immediately, but it is possible to override 12102 // the "add" callback option to queue file uploads. 12103 $.widget('blueimp.fileupload', { 12104 12105 options: {
12106 // The drop target element(s), by the default the complete document. 12107 // Set to null to disable drag & drop support: 12108 dropZone: $(document), 12109 // The paste target element(s), by the default undefined. 12110 // Set to a DOM node or jQuery object to enable file pasting: 12111 pasteZone: undefined, 12112 // The file input field(s), that are listened to for change events. 12113 // If undefined, it is set to the file input fields inside 12114 // of the widget element on plugin initialization. 12115 // Set to null to disable the change listener. 12116 fileInput: undefined, 12117 // By default, the file input field is replaced with a clone after 12118 // each input field change event. This is required for iframe transport 12119 // queues and allows change events to be fired for the same file 12120 // selection, but can be disabled by setting the following option to false: 12121 replaceFileInput: true, 12122 // The parameter name for the file form data (the request argument name). 12123 // If undefined or empty, the name property of the file input field is 12124 // used, or "files[]" if the file input name property is also empty, 12125 // can be a string or an array of strings: 12126 paramName: undefined, 12127 // By default, each file of a selection is uploaded using an individual 12128 // request for XHR type uploads. Set to false to upload file 12129 // selections in one request each: 12130 singleFileUploads: true, 12131 // To limit the number of files uploaded with one XHR request, 12132 // set the following option to an integer greater than 0: 12133 limitMultiFileUploads: undefined, 12134 // The following option limits the number of files uploaded with one 12135 // XHR request to keep the request size under or equal to the defined 12136 // limit in bytes: 12137 limitMultiFileUploadSize: undefined, 12138 // Multipart file uploads add a number of bytes to each uploaded file, 12139 // therefore the following option adds an overhead for each file used 12140 // in the limitMultiFileUploadSize configuration: 12141 limitMultiFileUploadSizeOverhead: 512, 12142 // Set the following option to true to issue all file upload requests 12143 // in a sequential order: 12144 sequentialUploads: false, 12145 // To limit the number of concurrent uploads, 12146 // set the following option to an integer greater than 0: 12147 limitConcurrentUploads: undefined, 12148 // Set the following option to true to force iframe transport uploads: 12149 forceIframeTransport: false, 12150 // Set the following option to the location of a redirect url on the 12151 // origin server, for cross-domain iframe transport uploads: 12152 redirect: undefined, 12153 // The parameter name for the redirect url, sent as part of the form 12154 // data and set to 'redirect' if this option is empty: 12155 redirectParamName: undefined, 12156 // Set the following option to the location of a postMessage window, 12157 // to enable postMessage transport uploads: 12158 postMessage: undefined, 12159 // By default, XHR file uploads are sent as multipart/form-data. 12160 // The iframe transport is always using multipart/form-data. 12161 // Set to false to enable non-multipart XHR uploads: 12162 multipart: true, 12163 // To upload large files in smaller chunks, set the following option 12164 // to a preferred maximum chunk size. If set to 0, null or undefined, 12165 // or the browser does not support the required Blob API, files will 12166 // be uploaded as a whole. 12167 maxChunkSize: undefined, 12168 // When a non-multipart upload or a chunked multipart upload has been 12169 // aborted, this option can be used to resume the upload by setting 12170 // it to the size of the already uploaded bytes. This option is most 12171 // useful when modifying the options object inside of the "add" or 12172 // "send" callbacks, as the options are cloned for each file upload. 12173 uploadedBytes: undefined, 12174 // By default, failed (abort or error) file uploads are removed from the 12175 // global progress calculation. Set the following option to fal
12175se to 12176 // prevent recalculating the global progress data: 12177 recalculateProgress: true, 12178 // Interval in milliseconds to calculate and trigger progress events: 12179 progressInterval: 100, 12180 // Interval in milliseconds to calculate progress bitrate: 12181 bitrateInterval: 500, 12182 // By default, uploads are started automatically when adding files: 12183 autoUpload: true, 12184 12185 // Error and info messages: 12186 messages: { 12187 uploadedBytes: 'Uploaded bytes exceed file size' 12188 }, 12189 12190 // Translation function, gets the message key to be translated 12191 // and an object with context specific data as arguments: 12192 i18n: function (message, context) { 12193 message = this.messages[message] || message.toString(); 12194 if (context) { 12195 $.each(context, function (key, value) { 12196 message = message.replace('{' + key + '}', value); 12197 }); 12198 } 12199 return message; 12200 }, 12201 12202 // Additional form data to be sent along with the file uploads can be set 12203 // using this option, which accepts an array of objects with name and 12204 // value properties, a function returning such an array, a FormData 12205 // object (for XHR file uploads), or a simple object. 12206 // The form of the first fileInput is given as parameter to the function: 12207 formData: function (form) { 12208 return form.serializeArray(); 12209 }, 12210 12211 // The add callback is invoked as soon as files are added to the fileupload 12212 // widget (via file input selection, drag & drop, paste or add API call). 12213 // If the singleFileUploads option is enabled, this callback will be 12214 // called once for each file in the selection for XHR file uploads, else 12215 // once for each file selection. 12216 // 12217 // The upload starts when the submit method is invoked on the data parameter. 12218 // The data object contains a files property holding the added files 12219 // and allows you to override plugin options as well as define ajax settings. 12220 // 12221 // Listeners for this callback can also be bound the following way: 12222 // .bind('fileuploadadd', func); 12223 // 12224 // data.submit() returns a Promise object and allows to attach additional 12225 // handlers using jQuery's Deferred callbacks: 12226 // data.submit().done(func).fail(func).always(func); 12227 add: function (e, data) { 12228 if (e.isDefaultPrevented()) { 12229 return false; 12230 } 12231 if (data.autoUpload || (data.autoUpload !== false && 12232 $(this).fileupload('option', 'autoUpload'))) { 12233 data.process().done(function () { 12234 data.submit(); 12235 }); 12236 } 12237 }, 12238 12239 // Other callbacks: 12240 12241 // Callback for the submit event of each file upload: 12242 // submit: function (e, data) {}, // .bind('fileuploadsubmit', func); 12243 12244 // Callback for the start of each file upload request: 12245 // send: function (e, data) {}, // .bind('fileuploadsend', func); 12246 12247 // Callback for successful uploads: 12248 // done: function (e, data) {}, // .bind('fileuploaddone', func); 12249 12250 // Callback for failed (abort or error) uploads: 12251 // fail: function (e, data) {}, // .bind('fileuploadfail', func); 12252 12253 // Callback for completed (success, abort or error) requests: 12254 // always: function (e, data) {}, // .bind('fileuploadalways', func); 12255 12256 // Callback for upload progress events: 12257 // progress: function (e, data) {}, // .bind('fileuploadprogress', func); 12258 12259 // Callback for global upload progress events: 12260 // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); 12261 12262 // Callback for uploads start, equivalent to the global ajaxStart event: 12263 // start: function (e) {}, // .bind('fileuploadstart', func); 12264 12265 // Callback for uploads stop, equivalent to the global ajaxStop event: 12266 // stop: function (e) {}, // .bind('fileuploadstop', func); 12267 12268 // Callback for change events of the fileInput(s): 12269 // change: function (e, data) {}, // .bind('fileuploadchange', func); 12270 12271 // Callback for paste events to the pasteZone(s): 12272 // paste: function (e, data) {}, // .bind('fileuploadpaste', func); 12273 12274 // Callback for drop events of the dropZone(s): 12275 // drop: function (e, data) {}, // .bind('fileuploaddrop', func); 12276 12277 // Callback for dragover events of the dropZone(s): 12278 // dragover: function (e) {}, // .bind('fileuploaddragover', func); 12279 12280 // Callback for the start of each chunk upload request: 12281 // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func); 12282 12283 // Callback for successful chunk uploads: 12284 // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func); 12285 12286 // Callback for failed (abort or error) chunk uploads: 12287 // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func); 12288 12289 // Callback for completed (success, abort or error) chunk upload requests: 12290 // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func); 12291 12292 // The plugin options are used as settings object for the ajax calls. 12293 // The following are jQuery ajax settings required for the file uploads: 12294 processData: false, 12295 contentType: false, 12296 cache: false, 12297 timeout: 0 12298 }, 12299 12300 // A list of options that require reinitializing event listeners and/or 12301 // special initialization code: 12302 _specialOptions: [ 12303 'fileInput', 12304 'dropZone', 12305 'pasteZone', 12306 'multipart', 12307 'forceIframeTransport' 12308 ], 12309 12310 _blobSlice: $.support.blobSlice && function () { 12311 var slice = this.slice || this.webkitSlice || this.mozSlice; 12312 return slice.apply(this, arguments); 12313 }, 12314 12315 _BitrateTimer: function () { 12316 this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime()); 12317 this.loaded = 0; 12318 this.bitrate = 0; 12319 this.getBitrate = function (now, loaded, interval) { 12320 var timeDiff = now - this.timestamp; 12321 if (!this.bitrate || !interval || timeDiff > interval) { 12322 this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; 12323 this.loaded = loaded; 12324 this.timestamp = now; 12325 } 12326 return this.bitrate; 12327 }; 12328 }, 12329 12330 _isXHRUpload: function (options) { 12331 return !options.forceIframeTransport && 12332 ((!options.multipart && $.support.xhrFileUpload) || 12333 $.support.xhrFormDataFileUpload); 12334 }, 12335 12336 _getFormData: function (options) { 12337 var formData; 12338 if ($.type(options.formData) === 'function') { 12339 return options.formData(options.form); 12340 } 12341 if ($.isArray(options.formData)) { 12342 return options.formData; 12343 } 12344 if ($.type(options.formData) === 'object') { 12345 formData = []; 12346 $.each(options.formData, function (name, value) { 12347 formData.push({name: name, value: value}); 12348 }); 12349 return formData; 12350 } 12351 return []; 12352 }, 12353 12354 _getTotal: function (files) { 12355 var total = 0; 12356 $.each(files, function (index, file) { 12357 total += file.size || 1; 12358 }); 12359 return total; 12360 }, 12361 12362 _initProgressObject: function (obj) { 12363 var progress = { 12364 loaded: 0, 12365 total: 0, 12366 bitrate: 0 12367 }; 12368 if (obj._progress) { 12369 $.extend(obj._progress, progress); 12370 } else { 12371 obj._progress = progress; 12372 } 12373 }, 12374 12375 _initResponseObject: function (obj) { 12376 var prop; 12377 if (obj._response) { 12378 for (prop in obj._response) { 12379 if (obj._response.hasOwnProperty(prop)) { 12380 delete obj._response[prop]; 12381 } 12382 } 12383 } else { 12384 obj._response = {}; 12385 } 12386 }, 12387 12388 _onProgress: function (e, data) { 12389 if (e.lengthComputable) { 12390 var now = ((Date.now) ? Date.now() : (new Date()).getTime()), 12391 loaded; 12392 if (data._time && data.progressInterval && 12393 (now - data._time < data.progressInterval) && 12394 e.loaded !== e.total) { 12395 return; 12396 } 12397 data._time = now; 12398 loaded = Math.floor( 12399 e.loaded / e.total * (data.chunkSize || data._progress.total) 12400 ) + (data.uploadedBytes || 0); 12401 // Add the difference from the previously loaded state 12402 // to the global loaded counter: 12403 this._progress.loaded += (loaded - data._progress.loaded); 12404 this._progress.bitrate = this._bitrateTimer.getBitrate( 12405 now, 12406 this._progress.loaded, 12407 data.bitrateInterval 12408 ); 12409 data._progress.loaded = data.loaded = loaded; 12410 data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate( 12411 now, 12412 loaded, 12413 data.bitrateInterval 12414 ); 12415 // Trigger a custom progress event with a total data property set 12416 // to the file size(s) of the current upload and a loaded data 12417 // property calculated accordingly: 12418 this._trigger( 12419 'progress', 12420 $.Event('progress', {delegatedEvent: e}), 12421 data 12422 ); 12423 // Trigger a global progress event for all current file uploads, 12424 // including ajax calls queued for sequential file uploads: 12425 this._trigger( 12426 'progressall', 12427 $.Event('progressall', {delegatedEvent: e}), 12428 this._progress 12429 ); 12430 } 12431 }, 12432 12433 _initProgressListener: function (options) { 12434 var that = this, 12435 xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); 12436 // Accesss to the native XHR object is required to add event listeners 12437 // for the upload progress event: 12438 if (xhr.upload) { 12439 $(xhr.upload).bind('progress', function (e) { 12440 var oe = e.originalEvent; 12441 // Make sure the progress event properties get copied over: 12442 e.lengthComputable = oe.lengthComputable; 12443 e.loaded = oe.loaded; 12444 e.total = oe.total; 12445 that._onProgress(e, options); 12446 }); 12447 options.xhr = function () { 12448 return xhr; 12449 }; 12450 } 12451 }, 12452 12453 _isInstanceOf: function (type, obj) { 12454 // Cross-frame instanceof check 12455 return Object.prototype.toString.call(obj) === '[object ' + type + ']'; 12456 }, 12457 12458 _initXHRData: function (options) { 12459 var that = this, 12460 formData, 12461 file = options.files[0], 12462 // Ignore non-multipart setting if not supported:
12463 multipart = options.multipart || !$.support.xhrFileUpload, 12464 paramName = $.type(options.paramName) === 'array' ? 12465 options.paramName[0] : options.paramName; 12466 options.headers = $.extend({}, options.headers); 12467 if (options.contentRange) { 12468 options.headers['Content-Range'] = options.contentRange; 12469 } 12470 if (!multipart || options.blob || !this._isInstanceOf('File', file)) { 12471 options.headers['Content-Disposition'] = 'attachment; filename="' + 12472 encodeURI(file.name) + '"'; 12473 } 12474 if (!multipart) { 12475 options.contentType = file.type || 'application/octet-stream'; 12476 options.data = options.blob || file; 12477 } else if ($.support.xhrFormDataFileUpload) { 12478 if (options.postMessage) { 12479 // window.postMessage does not allow sending FormData 12480 // objects, so we just add the File/Blob objects to 12481 // the formData array and let the postMessage window 12482 // create the FormData object out of this array: 12483 formData = this._getFormData(options); 12484 if (options.blob) { 12485 formData.push({ 12486 name: paramName, 12487 value: options.blob 12488 }); 12489 } else { 12490 $.each(options.files, function (index, file) { 12491 formData.push({ 12492 name: ($.type(options.paramName) === 'array' && 12493 options.paramName[index]) || paramName, 12494 value: file 12495 }); 12496 }); 12497 } 12498 } else { 12499 if (that._isInstanceOf('FormData', options.formData)) { 12500 formData = options.formData; 12501 } else { 12502 formData = new FormData(); 12503 $.each(this._getFormData(options), function (index, field) { 12504 formData.append(field.name, field.value); 12505 }); 12506 } 12507 if (options.blob) { 12508 formData.append(paramName, options.blob, file.name); 12509 } else { 12510 $.each(options.files, function (index, file) { 12511 // This check allows the tests to run with 12512 // dummy objects: 12513 if (that._isInstanceOf('File', file) || 12514 that._isInstanceOf('Blob', file)) { 12515 formData.append( 12516 ($.type(options.paramName) === 'array' && 12517 options.paramName[index]) || paramName, 12518 file, 12519 file.uploadName || file.name 12520 ); 12521 } 12522 }); 12523 } 12524 } 12525 options.data = formData; 12526 } 12527 // Blob reference is not needed anymore, free memory: 12528 options.blob = null; 12529 }, 12530 12531 _initIframeSettings: function (options) { 12532 var targetHost = $('<a></a>').prop('href', options.url).prop('host'); 12533 // Setting the dataType to iframe enables the iframe transport: 12534 options.dataType = 'iframe ' + (options.dataType || ''); 12535 // The iframe transport accepts a serialized array as form data: 12536 options.formData = this._getFormData(options); 12537 // Add redirect url to form data on cross-domain uploads: 12538 if (options.redirect && targetHost && targetHost !== location.host) { 12539 options.formData.push({ 12540 name: options.redirectParamName || 'redirect', 12541 value: options.redirect 12542 }); 12543 } 12544 }, 12545 12546 _initDataSettings: function (options) { 12547 if (this._isXHRUpload(options)) { 12548 if (!this._chunkedUpload(options, true)) { 12549 if (!options.data) { 12550 this._initXHRData(options); 12551 } 12552 this._initProgressListener(options); 12553 } 12554 if (options.postMessage) { 12555 // Setting the dataType to postmessage enables the 12556 // postMessage transport: 12557 options.dataType = 'postmessage ' + (options.dataType || ''); 12558 } 12559 } else { 12560 this._initIframeSettings(options); 12561 } 12562 }, 12563 12564 _getParamName: function (options) { 12565 var fileInput = $(options.fileInput), 12566 paramName = options.paramName; 12567 if (!paramName) { 12568 paramName = []; 12569 fileInput.each(function () { 12570 var input = $(this), 12571 name = input.prop('name') || 'files[]', 12572 i = (input.prop('files') || [1]).length; 12573 while (i) { 12574 paramName.push(name); 12575 i -= 1; 12576 } 12577 }); 12578 if (!paramName.length) { 12579 paramName = [fileInput.prop('name') || 'files[]']; 12580 } 12581 } else if (!$.isArray(paramName)) { 12582 paramName = [paramName]; 12583 } 12584 return paramName; 12585 }, 12586 12587 _initFormSettings: function (options) { 12588 // Retrieve missing options from the input field and the 12589 // associated form, if available: 12590 if (!options.form || !options.form.length) { 12591 options.form = $(options.fileInput.prop('form')); 12592 // If the given file input doesn't have an associated form, 12593 // use the default widget file input's form: 12594 if (!options.form.length) { 12595 options.form = $(this.options.fileInput.prop('form')); 12596 } 12597 } 12598 options.paramName = this._getParamName(options); 12599 if (!options.url) { 12600 options.url = options.form.prop('action') || location.href; 12601 } 12602 // The HTTP request method must be "POST" or "PUT": 12603 options.type = (options.type || 12604 ($.type(options.form.prop('method')) === 'string' && 12605 options.form.prop('method')) || '' 12606 ).toUpperCase(); 12607 if (options.type !== 'POST' && options.type !== 'PUT' && 12608 options.type !== 'PATCH') { 12609 options.type = 'POST'; 12610 } 12611 if (!options.formAcceptCharset) { 12612 options.formAcceptCharset = options.form.attr('accept-charset'); 12613 } 12614 }, 12615 12616 _getAJAXSettings: function (data) { 12617 var options = $.extend({}, this.options, data); 12618 this._initFormSettings(options); 12619 this._initDataSettings(options); 12620 return options; 12621 }, 12622 12623 // jQuery 1.6 doesn't provide .state(), 12624 // while jQuery 1.8+ removed .isRejected() and .isResolved(): 12625 _getDeferredState: function (deferred) { 12626 if (deferred.state) { 12627 return deferred.state(); 12628 } 12629 if (deferred.isResolved()) { 12630 return 'resolved'; 12631 } 12632 if (deferred.isRejected()) { 12633 return 'rejected'; 12634 } 12635 return 'pending'; 12636 }, 12637 12638 // Maps jqXHR callbacks to the equivalent 12639 // methods of the given Promise object: 12640 _enhancePromise: function (promise) { 12641 promise.success = promise.done; 12642 promise.error = promise.fail; 12643 promise.complete = promise.always; 12644 return promise; 12645 }, 12646 12647 // Creates and returns a Promise object enhanced with 12648 // the jqXHR methods abort, success, error and complete: 12649 _getXHRPromise: function (resolveOrReject, context, args
12649) { 12650 var dfd = $.Deferred(), 12651 promise = dfd.promise(); 12652 context = context || this.options.context || promise; 12653 if (resolveOrReject === true) { 12654 dfd.resolveWith(context, args); 12655 } else if (resolveOrReject === false) { 12656 dfd.rejectWith(context, args); 12657 } 12658 promise.abort = dfd.promise; 12659 return this._enhancePromise(promise); 12660 }, 12661 12662 // Adds convenience methods to the data callback argument: 12663 _addConvenienceMethods: function (e, data) { 12664 var that = this, 12665 getPromise = function (args) { 12666 return $.Deferred().resolveWith(that, args).promise(); 12667 }; 12668 data.process = function (resolveFunc, rejectFunc) { 12669 if (resolveFunc || rejectFunc) { 12670 data._processQueue = this._processQueue = 12671 (this._processQueue || getPromise([this])).then( 12672 function () { 12673 if (data.errorThrown) { 12674 return $.Deferred() 12675 .rejectWith(that, [data]).promise(); 12676 } 12677 return getPromise(arguments); 12678 } 12679 ).then(resolveFunc, rejectFunc); 12680 } 12681 return this._processQueue || getPromise([this]); 12682 }; 12683 data.submit = function () { 12684 if (this.state() !== 'pending') { 12685 data.jqXHR = this.jqXHR = 12686 (that._trigger( 12687 'submit', 12688 $.Event('submit', {delegatedEvent: e}), 12689 this 12690 ) !== false) && that._onSend(e, this); 12691 } 12692 return this.jqXHR || that._getXHRPromise(); 12693 }; 12694 data.abort = function () { 12695 if (this.jqXHR) { 12696 return this.jqXHR.abort(); 12697 } 12698 this.errorThrown = 'abort'; 12699 that._trigger('fail', null, this); 12700 return that._getXHRPromise(false); 12701 }; 12702 data.state = function () { 12703 if (this.jqXHR) { 12704 return that._getDeferredState(this.jqXHR); 12705 } 12706 if (this._processQueue) { 12707 return that._getDeferredState(this._processQueue); 12708 } 12709 }; 12710 data.processing = function () { 12711 return !this.jqXHR && this._processQueue && that 12712 ._getDeferredState(this._processQueue) === 'pending'; 12713 }; 12714 data.progress = function () { 12715 return this._progress; 12716 }; 12717 data.response = function () { 12718 return this._response; 12719 }; 12720 }, 12721 12722 // Parses the Range header from the server response 12723 // and returns the uploaded bytes: 12724 _getUploadedBytes: function (jqXHR) { 12725 var range = jqXHR.getResponseHeader('Range'), 12726 parts = range && range.split('-'), 12727 upperBytesPos = parts && parts.length > 1 && 12728 parseInt(parts[1], 10); 12729 return upperBytesPos && upperBytesPos + 1; 12730 }, 12731 12732 // Uploads a file in multiple, sequential requests 12733 // by splitting the file up in multiple blob chunks. 12734 // If the second parameter is true, only tests if the file 12735 // should be uploaded in chunks, but does not invoke any 12736 // upload requests: 12737 _chunkedUpload: function (options, testOnly) { 12738 options.uploadedBytes = options.uploadedBytes || 0; 12739 var that = this, 12740 file = options.files[0], 12741 fs = file.size, 12742 ub = options.uploadedBytes, 12743 mcs = options.maxChunkSize || fs, 12744 slice = this._blobSlice, 12745 dfd = $.Deferred(), 12746 promise = dfd.promise(), 12747 jqXHR, 12748 upload; 12749 if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || 12750 options.data) { 12751 return false;
12752 } 12753 if (testOnly) { 12754 return true; 12755 } 12756 if (ub >= fs) { 12757 file.error = options.i18n('uploadedBytes'); 12758 return this._getXHRPromise( 12759 false, 12760 options.context, 12761 [null, 'error', file.error] 12762 ); 12763 } 12764 // The chunk upload method: 12765 upload = function () { 12766 // Clone the options object for each chunk upload: 12767 var o = $.extend({}, options), 12768 currentLoaded = o._progress.loaded; 12769 o.blob = slice.call( 12770 file, 12771 ub, 12772 ub + mcs, 12773 file.type 12774 ); 12775 // Store the current chunk size, as the blob itself 12776 // will be dereferenced after data processing: 12777 o.chunkSize = o.blob.size; 12778 // Expose the chunk bytes position range: 12779 o.contentRange = 'bytes ' + ub + '-' + 12780 (ub + o.chunkSize - 1) + '/' + fs; 12781 // Process the upload data (the blob and potential form data): 12782 that._initXHRData(o); 12783 // Add progress listeners for this chunk upload: 12784 that._initProgressListener(o); 12785 jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) || 12786 that._getXHRPromise(false, o.context)) 12787 .done(function (result, textStatus, jqXHR) { 12788 ub = that._getUploadedBytes(jqXHR) || 12789 (ub + o.chunkSize); 12790 // Create a progress event if no final progress event 12791 // with loaded equaling total has been triggered 12792 // for this chunk: 12793 if (currentLoaded + o.chunkSize - o._progress.loaded) { 12794 that._onProgress($.Event('progress', { 12795 lengthComputable: true, 12796 loaded: ub - o.uploadedBytes, 12797 total: ub - o.uploadedBytes 12798 }), o); 12799 } 12800 options.uploadedBytes = o.uploadedBytes = ub; 12801 o.result = result; 12802 o.textStatus = textStatus; 12803 o.jqXHR = jqXHR; 12804 that._trigger('chunkdone', null, o); 12805 that._trigger('chunkalways', null, o); 12806 if (ub < fs) { 12807 // File upload not yet complete, 12808 // continue with the next chunk: 12809 upload(); 12810 } else { 12811 dfd.resolveWith( 12812 o.context, 12813 [result, textStatus, jqXHR] 12814 ); 12815 } 12816 }) 12817 .fail(function (jqXHR, textStatus, errorThrown) { 12818 o.jqXHR = jqXHR; 12819 o.textStatus = textStatus; 12820 o.errorThrown = errorThrown; 12821 that._trigger('chunkfail', null, o); 12822 that._trigger('chunkalways', null, o); 12823 dfd.rejectWith( 12824 o.context, 12825 [jqXHR, textStatus, errorThrown] 12826 ); 12827 }); 12828 }; 12829 this._enhancePromise(promise); 12830 promise.abort = function () { 12831 return jqXHR.abort(); 12832 }; 12833 upload(); 12834 return promise; 12835 }, 12836 12837 _beforeSend: function (e, data) { 12838 if (this._active === 0) { 12839 // the start callback is triggered when an upload starts 12840 // and no other uploads are currently running, 12841 // equivalent to the global ajaxStart event: 12842 this._trigger('start'); 12843 // Set timer for global bitrate progress calculation: 12844 this._bitrateTimer = new this._BitrateTimer(); 12845 // Reset the global progress values: 12846 this._progress.loaded = this._progress.total = 0; 12847 this._progress.bitrate = 0; 12848 } 12849 // Make sure the container objects for the .response() and 12850 // .progress() methods on the data object are available 12851 // and reset to their initial state: 12852 this._initResponseObject(data); 12853 this._initProgressObject(data); 12854 data._progress.loaded = data.loaded = data.uploadedBytes || 0; 12855 data._progress.total = data.total = this._getTotal(data.files) || 1; 12856 data._progress.bitrate = data.bitrate = 0; 12857 this._active += 1; 12858 // Initialize the global progress values: 12859 this._progress.loaded += data.loaded; 12860 this._progress.total += data.total; 12861 }, 12862 12863 _onDone: function (result, textStatus, jqXHR, options) { 12864 var total = options._progress.total, 12865 response = options._response; 12866 if (options._progress.loaded < total) { 12867 // Create a progress event if no final progress event 12868 // with loaded equaling total has been triggered: 12869 this._onProgress($.Event('progress', { 12870 lengthComputable: true, 12871 loaded: total, 12872 total: total 12873 }), options); 12874 } 12875 response.result = options.result = result; 12876 response.textStatus = options.textStatus = textStatus; 12877 response.jqXHR = options.jqXHR = jqXHR; 12878 this._trigger('done', null, options); 12879 }, 12880 12881 _onFail: function (jqXHR, textStatus, errorThrown, options) { 12882 var response = options._response; 12883 if (options.recalculateProgress) { 12884 // Remove the failed (error or abort) file upload from 12885 // the global progress calculation: 12886 this._progress.loaded -= options._progress.loaded;
12887 this._progress.total -= options._progress.total; 12888 } 12889 response.jqXHR = options.jqXHR = jqXHR; 12890 response.textStatus = options.textStatus = textStatus; 12891 response.errorThrown = options.errorThrown = errorThrown; 12892 this._trigger('fail', null, options); 12893 }, 12894 12895 _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { 12896 // jqXHRorResult, textStatus and jqXHRorError are added to the 12897 // options object via done and fail callbacks 12898 this._trigger('always', null, options); 12899 }, 12900 12901 _onSend: function (e, data) { 12902 if (!data.submit) { 12903 this._addConvenienceMethods(e, data); 12904 } 12905 var that = this, 12906 jqXHR, 12907 aborted, 12908 slot, 12909 pipe, 12910 options = that._getAJAXSettings(data), 12911 send = function () { 12912 that._sending += 1; 12913 // Set timer for bitrate progress calculation: 12914 options._bitrateTimer = new that._BitrateTimer(); 12915 jqXHR = jqXHR || ( 12916 ((aborted || that._trigger( 12917 'send', 12918 $.Event('send', {delegatedEvent: e}), 12919 options 12920 ) === false) && 12921 that._getXHRPromise(false, options.context, aborted)) || 12922 that._chunkedUpload(options) || $.ajax(options) 12923 ).done(function (result, textStatus, jqXHR) { 12924 that._onDone(result, textStatus, jqXHR, options); 12925 }).fail(function (jqXHR, textStatus, errorThrown) { 12926 that._onFail(jqXHR, textStatus, errorThrown, options); 12927 }).always(function (jqXHRorResult, textStatus, jqXHRorError) { 12928 that._onAlways( 12929 jqXHRorResult, 12930 textStatus, 12931 jqXHRorError, 12932 options 12933 ); 12934 that._sending -= 1; 12935 that._active -= 1; 12936 if (options.limitConcurrentUploads && 12937 options.limitConcurrentUploads > that._sending) { 12938 // Start the next queued upload, 12939 // that has not been aborted: 12940 var nextSlot = that._slots.shift(); 12941 while (nextSlot) { 12942 if (that._getDeferredState(nextSlot) === 'pending') { 12943 nextSlot.resolve(); 12944 break; 12945 } 12946 nextSlot = that._slots.shift(); 12947 } 12948 } 12949 if (that._active === 0) { 12950 // The stop callback is triggered when all uploads have 12951 // been completed, equivalent to the global ajaxStop event: 12952 that._trigger('stop'); 12953 } 12954 }); 12955 return jqXHR; 12956 }; 12957 this._beforeSend(e, options); 12958 if (this.options.sequentialUploads || 12959 (this.options.limitConcurrentUploads && 12960 this.options.limitConcurrentUploads <= this._sending)) { 12961 if (this.options.limitConcurrentUploads > 1) { 12962 slot = $.Deferred(); 12963 this._slots.push(slot); 12964 pipe = slot.then(send); 12965 } else { 12966 this._sequence = this._sequence.then(send, send); 12967 pipe = this._sequence; 12968 } 12969 // Return the piped Promise object, enhanced with an abort method, 12970 // which is delegated to the jqXHR object of the current upload, 12971 // and jqXHR callbacks mapped to the equivalent Promise methods: 12972 pipe.abort = function () { 12973 aborted = [undefined, 'abort', 'abort']; 12974 if (!jqXHR) { 12975 if (slot) { 12976 slot.rejectWith(options.context, aborted); 12977 } 12978 return send(); 12979 } 12980 return jqXHR.abort(); 12981 }; 12982 return this._enhancePromise(pipe); 12983 } 12984 return send(); 12985 }, 12986 12987 _onAdd: function (e, data) { 12988 var that = this, 12989 result = true, 12990 options = $.extend({}, this.options, data), 12991 files = data.files, 12992 filesLength = files.length, 12993 limit = options.limitMultiFileUploads, 12994 limitSize = options.limitMultiFileUploadSize, 12995 overhead = options.limitMultiFileUploadSizeOverhead, 12996 batchSize = 0, 12997 paramName = this._getParamName(options), 12998 paramNameSet, 12999 paramNameSlice, 13000 fileSet, 13001 i, 13002 j = 0; 13003 if (!filesLength) { 13004 return false;
13005 } 13006 if (limitSize && files[0].size === undefined) { 13007 limitSize = undefined; 13008 } 13009 if (!(options.singleFileUploads || limit || limitSize) || 13010 !this._isXHRUpload(options)) { 13011 fileSet = [files]; 13012 paramNameSet = [paramName]; 13013 } else if (!(options.singleFileUploads || limitSize) && limit) { 13014 fileSet = []; 13015 paramNameSet = []; 13016 for (i = 0; i < filesLength; i += limit) { 13017 fileSet.push(files.slice(i, i + limit)); 13018 paramNameSlice = paramName.slice(i, i + limit); 13019 if (!paramNameSlice.length) { 13020 paramNameSlice = paramName; 13021 } 13022 paramNameSet.push(paramNameSlice); 13023 } 13024 } else if (!options.singleFileUploads && limitSize) { 13025 fileSet = []; 13026 paramNameSet = []; 13027 for (i = 0; i < filesLength; i = i + 1) { 13028 batchSize += files[i].size + overhead; 13029 if (i + 1 === filesLength || 13030 ((batchSize + files[i + 1].size + overhead) > limitSize) || 13031 (limit && i + 1 - j >= limit)) { 13032 fileSet.push(files.slice(j, i + 1)); 13033 paramNameSlice = paramName.slice(j, i + 1); 13034 if (!paramNameSlice.length) { 13035 paramNameSlice = paramName; 13036 } 13037 paramNameSet.push(paramNameSlice); 13038 j = i + 1; 13039 batchSize = 0; 13040 } 13041 } 13042 } else { 13043 paramNameSet = paramName; 13044 } 13045 data.originalFiles = files; 13046 $.each(fileSet || files, function (index, element) { 13047 var newData = $.extend({}, data); 13048 newData.files = fileSet ? element : [element]; 13049 newData.paramName = paramNameSet[index]; 13050 that._initResponseObject(newData); 13051 that._initProgressObject(newData); 13052 that._addConvenienceMethods(e, newData); 13053 result = that._trigger( 13054 'add', 13055 $.Event('add', {delegatedEvent: e}), 13056 newData 13057 ); 13058 return result; 13059 }); 13060 return result; 13061 }, 13062 13063 _replaceFileInput: function (data) { 13064 var input = data.fileInput, 13065 inputClone = input.clone(true), 13066 restoreFocus = input.is(document.activeElement); 13067 // Add a reference for the new cloned file input to the data argument: 13068 data.fileInputClone = inputClone; 13069 $('<form></form>').append(inputClone)[0].reset(); 13070 // Detaching allows to insert the fileInput on another form 13071 // without loosing the file input value: 13072 input.after(inputClone).detach(); 13073 // If the fileInput had focus before it was detached, 13074 // restore focus to the inputClone. 13075 if (restoreFocus) { 13076 inputClone.focus(); 13077 } 13078 // Avoid memory leaks with the detached file input: 13079 $.cleanData(input.unbind('remove')); 13080 // Replace the original file input element in the fileInput 13081 // elements set with the clone, which has been copied including 13082 // event handlers: 13083 this.options.fileInput = this.options.fileInput.map(function (i, el) { 13084 if (el === input[0]) { 13085 return inputClone[0]; 13086 } 13087 return el; 13088 }); 13089 // If the widget has been initialized on the file input itself, 13090 // override this.element with the file input clone: 13091 if (input[0] === this.element[0]) { 13092 this.element = inputClone; 13093 } 13094 }, 13095 13096 _handleFileTreeEntry: function (entry, path) { 13097 var that = this, 13098 dfd = $.Deferred(), 13099 errorHandler = function (e) { 13100 if (e && !e.entry) { 13101 e.entry = entry; 13102 } 13103 // Since $.when returns immediately if one 13104 // Deferred is rejected, we use resolve instead. 13105 // This allows valid files and invalid items 13106 // to be returned together in one set: 13107 dfd.resolve([e]); 13108 }, 13109 successHandler = function (entries) { 13110 that._handleFileTreeEntries(
13111 entries, 13112 path + entry.name + '/' 13113 ).done(function (files) { 13114 dfd.resolve(files); 13115 }).fail(errorHandler); 13116 }, 13117 readEntries = function () { 13118 dirReader.readEntries(function (results) { 13119 if (!results.length) { 13120 successHandler(entries); 13121 } else { 13122 entries = entries.concat(results); 13123 readEntries(); 13124 } 13125 }, errorHandler); 13126 }, 13127 dirReader, entries = []; 13128 path = path || ''; 13129 if (entry.isFile) { 13130 if (entry._file) { 13131 // Workaround for Chrome bug #149735 13132 entry._file.relativePath = path; 13133 dfd.resolve(entry._file); 13134 } else { 13135 entry.file(function (file) { 13136 file.relativePath = path; 13137 dfd.resolve(file); 13138 }, errorHandler); 13139 } 13140 } else if (entry.isDirectory) { 13141 dirReader = entry.createReader(); 13142 readEntries(); 13143 } else { 13144 // Return an empy list for file system items 13145 // other than files or directories: 13146 dfd.resolve([]); 13147 } 13148 return dfd.promise(); 13149 }, 13150 13151 _handleFileTreeEntries: function (entries, path) { 13152 var that = this; 13153 return $.when.apply( 13154 $, 13155 $.map(entries, function (entry) { 13156 return that._handleFileTreeEntry(entry, path); 13157 }) 13158 ).then(function () { 13159 return Array.prototype.concat.apply( 13160 [], 13161 arguments 13162 ); 13163 }); 13164 }, 13165 13166 _getDroppedFiles: function (dataTransfer) { 13167 dataTransfer = dataTransfer || {}; 13168 var items = dataTransfer.items; 13169 if (items && items.length && (items[0].webkitGetAsEntry || 13170 items[0].getAsEntry)) { 13171 return this._handleFileTreeEntries( 13172 $.map(items, function (item) { 13173 var entry; 13174 if (item.webkitGetAsEntry) { 13175 entry = item.webkitGetAsEntry(); 13176 if (entry) { 13177 // Workaround for Chrome bug #149735: 13178 entry._file = item.getAsFile(); 13179 } 13180 return entry; 13181 } 13182 return item.getAsEntry(); 13183 }) 13184 ); 13185 } 13186 return $.Deferred().resolve( 13187 $.makeArray(dataTransfer.files) 13188 ).promise(); 13189 }, 13190 13191 _getSingleFileInputFiles: function (fileInput) { 13192 fileInput = $(fileInput); 13193 var entries = fileInput.prop('webkitEntries') || 13194 fileInput.prop('entries'), 13195 files, 13196 value; 13197 if (entries && entries.length) { 13198 return this._handleFileTreeEntries(entries); 13199 } 13200 files = $.makeArray(fileInput.prop('files')); 13201 if (!files.length) { 13202 value = fileInput.prop('value'); 13203 if (!value) { 13204 return $.Deferred().resolve([]).promise(); 13205 } 13206 // If the files property is not available, the browser does not 13207 // support the File API and we add a pseudo File object with 13208 // the input value as name with path information removed: 13209 files = [{name: value.replace(/^.*\\/, '')}]; 13210 } else if (files[0].name === undefined && files[0].fileName) { 13211 // File normalization for Safari 4 and Firefox 3: 13212 $.each(files, function (index, file) { 13213 file.name = file.fileName; 13214 file.size = file.fileSize; 13215 }); 13216 } 13217 return $.Deferred().resolve(files).promise(); 13218 }, 13219 13220 _getFileInputFiles: function (fileInput) { 13221 if (!(fileInput instanceof $) || fileInput.length === 1) { 13222 return this._getSingleFileInputFiles(fileInput); 13223 } 13224 return $.when.apply( 13225 $, 13226 $.map(fileInput, this._getSingleFileInputFiles) 13227 ).then(function () { 13228 return Array.prototype.concat.apply( 13229 [], 13230 arguments 13231 ); 13232 }); 13233 }, 13234 13235 _onChange: function (e) { 13236 var that = this, 13237 data = { 13238 fileInput: $(e.target), 13239 form: $(e.target.form) 13240 }; 13241 this._getFileInputFiles(data.fileInput).always(function (files) { 13242 data.files = files; 13243 if (that.options.replaceFileInput) { 13244 that._replaceFileInput(data); 13245 } 13246 if (that._trigger( 13247 'change', 13248 $.Event('change', {delegatedEvent: e}), 13249 data 13250 ) !== false) { 13251 that._onAdd(e, data); 13252 } 13253 }); 13254 }, 13255 13256 _onPaste: function (e) { 13257 var items = e.originalEvent && e.originalEvent.clipboardData && 13258 e.originalEvent.clipboardData.items, 13259 data = {files: []}; 13260 if (items && items.length) { 13261 $.each(items, function (index, item) { 13262 var file = item.getAsFile && item.getAsFile(); 13263 if (file) { 13264 data.files.push(file); 13265 } 13266 }); 13267 if (this._trigger( 13268 'paste', 13269 $.Event('paste', {delegatedEvent: e}), 13270 data 13271 ) !== false) { 13272 this._onAdd(e, data); 13273 } 13274 } 13275 }, 13276 13277 _onDrop: function (e) { 13278 e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; 13279 var that = this, 13280 dataTransfer = e.dataTransfer, 13281 data = {}; 13282 if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { 13283 e.preventDefault(); 13284 this._getDroppedFiles(dataTransfer).always(function (files) { 13285 data.files = files; 13286 if (that._trigger( 13287 'drop', 13288 $.Event('drop', {delegatedEvent: e}), 13289 data 13290 ) !== false) { 13291 that._onAdd(e, data); 13292 } 13293 }); 13294 } 13295 }, 13296 13297 _onDragOver: getDragHandler('dragover'), 13298 13299 _onDragEnter: getDragHandler('dragenter'), 13300 13301 _onDragLeave: getDragHandler('dragleave'), 13302 13303 _initEventHandlers: function () { 13304 if (this._isXHRUpload(this.options)) { 13305 this._on(this.options.dropZone, { 13306 dragover: this._onDragOver, 13307 drop: this._onDrop, 13308 // event.preventDefault() on dragenter is required for IE10+: 13309 dragenter: this._onDragEnter, 13310 // dragleave is not required, but added for c
13310ompleteness: 13311 dragleave: this._onDragLeave 13312 }); 13313 this._on(this.options.pasteZone, { 13314 paste: this._onPaste 13315 }); 13316 } 13317 if ($.support.fileInput) { 13318 this._on(this.options.fileInput, { 13319 change: this._onChange 13320 }); 13321 } 13322 }, 13323 13324 _destroyEventHandlers: function () { 13325 this._off(this.options.dropZone, 'dragenter dragleave dragover drop'); 13326 this._off(this.options.pasteZone, 'paste'); 13327 this._off(this.options.fileInput, 'change'); 13328 }, 13329 13330 _setOption: function (key, value) { 13331 var reinit = $.inArray(key, this._specialOptions) !== -1; 13332 if (reinit) { 13333 this._destroyEventHandlers(); 13334 } 13335 this._super(key, value); 13336 if (reinit) { 13337 this._initSpecialOptions(); 13338 this._initEventHandlers(); 13339 } 13340 }, 13341 13342 _initSpecialOptions: function () { 13343 var options = this.options; 13344 if (options.fileInput === undefined) { 13345 options.fileInput = this.element.is('input[type="file"]') ? 13346 this.element : this.element.find('input[type="file"]'); 13347 } else if (!(options.fileInput instanceof $)) { 13348 options.fileInput = $(options.fileInput); 13349 } 13350 if (!(options.dropZone instanceof $)) { 13351 options.dropZone = $(options.dropZone); 13352 } 13353 if (!(options.pasteZone instanceof $)) { 13354 options.pasteZone = $(options.pasteZone); 13355 } 13356 }, 13357 13358 _getRegExp: function (str) { 13359 var parts = str.split('/'), 13360 modifiers = parts.pop(); 13361 parts.shift(); 13362 return new RegExp(parts.join('/'), modifiers); 13363 }, 13364 13365 _isRegExpOption: function (key, value) { 13366 return key !== 'url' && $.type(value) === 'string' && 13367 /^\/.*\/[igm]{0,3}$/.test(value); 13368 }, 13369 13370 _initDataAttributes: function () { 13371 var that = this, 13372 options = this.options, 13373 data = this.element.data(); 13374 // Initialize options set via HTML5 data-attributes: 13375 $.each( 13376 this.element[0].attributes, 13377 function (index, attr) { 13378 var key = attr.name.toLowerCase(), 13379 value; 13380 if (/^data-/.test(key)) { 13381 // Convert hyphen-ated key to camelCase: 13382 key = key.slice(5).replace(/-[a-z]/g, function (str) { 13383 return str.charAt(1).toUpperCase(); 13384 }); 13385 value = data[key]; 13386 if (that._isRegExpOption(key, value)) { 13387 value = that._getRegExp(value); 13388 } 13389 options[key] = value; 13390 } 13391 } 13392 ); 13393 }, 13394 13395 _create: function () { 13396 this._initDataAttributes(); 13397 this._initSpecialOptions(); 13398 this._slots = []; 13399 this._sequence = this._getXHRPromise(true); 13400 this._sending = this._active = 0; 13401 this._initProgressObject(this); 13402 this._initEventHandlers(); 13403 }, 13404 13405 // This method is exposed to the widget API and allows to query 13406 // the number of active uploads: 13407 active: function () { 13408 return this._active; 13409 }, 13410 13411 // This method is exposed to the widget API and allows to query 13412 // the widget upload progress. 13413 // It returns an object with loaded, total and bitrate properties 13414 // for the running uploads: 13415 progress: function () { 13416 return this._progress; 13417 }, 13418 13419 // This method is exposed to the widget API and allows adding files 13420 // using the fileupload API. The data parameter accepts an object which 13421 // must have a files property and can contain additional options: 13422 // .fileupload('add', {files: filesList}); 13423 add: function (data) { 13424 var that = this; 13425 if (!data || this.options.disabled) { 13426 return; 13427 } 13428 if (data.fileInput && !data.files) { 13429 this._getFileInputFiles(data.fileInput).always(function (files) { 13430 data.files = files; 13431 that._onAdd(null, data); 13432 }); 13433 } else { 13434 data.files = $.makeArray(data.files); 13435 this._onAdd(null, data); 13436 } 13437 }, 13438 13439 // This method is exposed to the widget API and allows sending files 13440 // using the fileupload API. The data parameter accepts an object which 13441 // must have a files or fileInput property and can contain additional options: 13442 // .fileupload('send', {files: filesList}); 13443 // The method returns a Promise object for the file upload call. 13444 send: function (data) { 13445 if (data && !this.options.disabled) { 13446 if (data.fileInput && !data.files) { 13447 var that = this, 13448 dfd = $.Deferred(), 13449 promise = dfd.promise(), 13450 jqXHR, 13451 aborted; 13452 promise.abort = function () { 13453 aborted = true; 13454 if (jqXHR) { 13455 return jqXHR.abort(); 13456 } 13457 dfd.reject(null, 'abort', 'abort'); 13458 return promise; 13459 }; 13460 this._getFileInputFiles(data.fileInput).always( 13461 function (files) { 13462 if (aborted) { 13463 return; 13464 } 13465 if (!files.length) { 13466 dfd.reject(); 13467 return; 13468 } 13469 data.files = files; 13470 jqXHR = that._onSend(null, data); 13471 jqXHR.then( 13472 function (result, textStatus, jqXHR) { 13473 dfd.resolve(result, textStatus, jqXHR); 13474 }, 13475 function (jqXHR, textStatus, errorThrown) { 13476 dfd.reject(jqXHR, textStatus, errorThrown); 13477 } 13478 ); 13479 } 13480 ); 13481 return this._enhancePromise(promise); 13482 } 13483 data.files = $.makeArray(data.files); 13484 if (data.files.length) { 13485 return this._onSend(null, data); 13486 } 13487 } 13488 return this._getXHRPromise(false, data && data.context); 13489 } 13490 13491 }); 13492 13493})); 13494 13495 13496
13497/*! jQuery Validation Plugin - v1.11.0 - 2/4/2013 13498* https://github.com/jzaefferer/jquery-validation 13499* Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */ 13500 13501 13502(function($) { 13503 13504$.extend($.fn, { 13505 // http://docs.jquery.com/Plugins/Validation/validate 13506 validate: function( options ) { 13507 13508 // if nothing is selected, return nothing; can't chain anyway 13509 if ( !this.length ) { 13510 if ( options && options.debug && window.console ) { 13511 console.warn( "Nothing selected, can't validate, returning nothing." ); 13512 } 13513 return; 13514 } 13515 13516 // check if a validator for this form was already created 13517 var validator = $.data( this[0], "validator" ); 13518 if ( validator ) { 13519 return validator; 13520 } 13521 13522 // Add novalidate tag if HTML5. 13523 this.attr( "novalidate", "novalidate" ); 13524 13525 validator = new $.validator( options, this[0] ); 13526 $.data( this[0], "validator", validator ); 13527 13528 if ( validator.settings.onsubmit ) { 13529 13530 this.validateDelegate( ":submit", "click", function( event ) { 13531 if ( validator.settings.submitHandler ) { 13532 validator.submitButton = event.target; 13533 } 13534 // allow suppressing validation by adding a cancel class to the submit button 13535 if ( $(event.target).hasClass("cancel") ) { 13536 validator.cancelSubmit = true; 13537 } 13538 }); 13539 13540 // validate the form on submit 13541 this.submit( function( event ) { 13542 if ( validator.settings.debug ) { 13543 // prevent form submit to be able to see console output 13544 event.preventDefault(); 13545 } 13546 function handle() { 13547 var hidden; 13548 if ( validator.settings.submitHandler ) { 13549 if ( validator.submitButton ) { 13550 // insert a hidden input as a replacement for the missing submit button 13551 hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); 13552 } 13553 validator.settings.submitHandler.call( validator, validator.currentForm, event ); 13554 if ( validator.submitButton ) { 13555 // and clean up afterwards; thanks to no-block-scope, hidden can be referenced 13556 hidden.remove(); 13557 } 13558 return false; 13559 } 13560 return true; 13561 } 13562 13563 // prevent submit for invalid forms or custom submit handlers 13564 if ( validator.cancelSubmit ) { 13565 validator.cancelSubmit = false; 13566 return handle(); 13567 } 13568 if ( validator.form() ) { 13569 if ( validator.pendingRequest ) { 13570 validator.formSubmitted = true; 13571 return false; 13572 } 13573 return handle(); 13574 } else { 13575 validator.focusInvalid(); 13576 return false; 13577 } 13578 }); 13579 } 13580 13581 return validator; 13582 }, 13583 // http://docs.jquery.com/Plugins/Validation/valid 13584 valid: function() { 13585 if ( $(this[0]).is("form")) { 13586 return this.validate().form(); 13587 } else { 13588 var valid = true; 13589 var validator = $(this[0].form).validate(); 13590 this.each(function() { 13591 valid &= validator.element(this); 13592 }); 13593 return valid; 13594 } 13595 }, 13596 // attributes: space seperated list of attributes to retrieve and remove 13597 removeAttrs: function( attributes ) { 13598 var result = {}, 13599 $element = this; 13600 $.each(attributes.split(/\s/), function( index, value ) { 13601 result[value] = $element.attr(value); 13602 $element.removeAttr(value); 13603 }); 13604 return result; 13605 }, 13606 // http://docs.jquery.com/Plugins/Validation/rules 13607 rules: function( command, argument ) { 13608 var element = this[0]; 13609 13610 if ( command ) { 13611 var settings = $.data(element.form, "validator").settings; 13612 var staticRules = settings.rules; 13613 var existingRules = $.validator.staticRules(element); 13614 switch(command) { 13615 case "add": 13616 $.extend(existingRules, $.validator.normalizeRule(argument)); 13617 staticRules[element.name] = existingRules; 13618 if ( argument.messages ) { 13619 settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); 13620 } 13621 break; 13622 case "remove": 13623 if ( !argument ) { 13624 delete staticRules[element.name]; 13625 return existingRules; 13626 } 13627 var filtered = {}; 13628 $.each(argument.split(/\s/), function( index, method ) { 13629 filtered[method] = existingRules[method]; 13630 delete existingRules[method]; 13631 }); 13632 return filtered; 13633 } 13634 } 13635 13636 var data = $.validator.normalizeRules( 13637 $.extend( 13638 {}, 13639 $.validator.classRules(element), 13640 $.validator.attributeRules(element), 13641 $.validator.dataRules(element), 13642 $.validator.staticRules(element) 13643 ), element); 13644 13645 // make sure required is at front 13646 if ( data.required ) { 13647 var param = data.required; 13648 delete data.required; 13649 data = $.extend({required: param}, data); 13650 } 13651 13652 return data; 13653 } 13654}); 13655 13656// Custom selectors 13657$.extend($.expr[":"], {
13658 // http://docs.jquery.com/Plugins/Validation/blank 13659 blank: function( a ) { return !$.trim("" + a.value); }, 13660 // http://docs.jquery.com/Plugins/Validation/filled 13661 filled: function( a ) { return !!$.trim("" + a.value); }, 13662 // http://docs.jquery.com/Plugins/Validation/unchecked 13663 unchecked: function( a ) { return !a.checked; } 13664}); 13665 13666// constructor for validator 13667$.validator = function( options, form ) { 13668 this.settings = $.extend( true, {}, $.validator.defaults, options ); 13669 this.currentForm = form; 13670 this.init(); 13671}; 13672 13673$.validator.format = function( source, params ) { 13674 if ( arguments.length === 1 ) { 13675 return function() { 13676 var args = $.makeArray(arguments); 13677 args.unshift(source); 13678 return $.validator.format.apply( this, args ); 13679 }; 13680 } 13681 if ( arguments.length > 2 && params.constructor !== Array ) { 13682 params = $.makeArray(arguments).slice(1); 13683 } 13684 if ( params.constructor !== Array ) { 13685 params = [ params ]; 13686 } 13687 $.each(params, function( i, n ) { 13688 source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() { 13689 return n; 13690 }); 13691 }); 13692 return source; 13693}; 13694 13695$.extend($.validator, { 13696 13697 defaults: { 13698 messages: {}, 13699 groups: {}, 13700 rules: {}, 13701 errorClass: "error", 13702 validClass: "valid", 13703 errorElement: "label", 13704 focusInvalid: true, 13705 errorContainer: $([]), 13706 errorLabelContainer: $([]), 13707 onsubmit: true, 13708 ignore: ":hidden", 13709 ignoreTitle: false, 13710 onfocusin: function( element, event ) { 13711 this.lastActive = element; 13712 13713 // hide error label and remove error class on focus if enabled 13714 if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { 13715 if ( this.settings.unhighlight ) { 13716 this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); 13717 } 13718 this.addWrapper(this.errorsFor(element)).hide(); 13719 } 13720 }, 13721 onfocusout: function( element, event ) { 13722 if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { 13723 this.element(element); 13724 } 13725 }, 13726 onkeyup: function( element, event ) { 13727 if ( event.which === 9 && this.elementValue(element) === "" ) { 13728 return; 13729 } else if ( element.name in this.submitted || element === this.lastElement ) { 13730 this.element(element); 13731 } 13732 }, 13733 onclick: function( element, event ) { 13734 // click on selects, radiobuttons and checkboxes 13735 if ( element.name in this.submitted ) { 13736 this.element(element); 13737 } 13738 // or option elements, check parent select in that case 13739 else if ( element.parentNode.name in this.submitted ) { 13740 this.element(element.parentNode); 13741 } 13742 }, 13743 highlight: function( element, errorClass, validClass ) { 13744 if ( element.type === "radio" ) { 13745 this.findByName(element.name).addClass(errorClass).removeClass(validClass); 13746 } else { 13747 $(element).addClass(errorClass).removeClass(validClass); 13748 } 13749 }, 13750 unhighlight: function( element, errorClass, validClass ) { 13751 if ( element.type === "radio" ) { 13752 this.findByName(element.name).removeClass(errorClass).addClass(validClass); 13753 } else { 13754 $(element).removeClass(errorClass).addClass(validClass); 13755 } 13756 } 13757 }, 13758 13759 // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults 13760 setDefaults: function( settings ) { 13761 $.extend( $.validator.defaults, settings ); 13762 }, 13763 13764 messages: { 13765 required: "This field is required.", 13766 remote: "Please fix this field.", 13767 email: "Please enter a valid email address.", 13768 url: "Please enter a valid URL.", 13769 date: "Please enter a valid date.", 13770 dateISO: "Please enter a valid date (ISO).", 13771 number: "Please enter a valid number.", 13772 digits: "Please enter only digits.", 13773 creditcard: "Please enter a valid credit card number.", 13774 equalTo: "Please enter the same value again.", 13775 maxlength: $.validator.format("Please enter no more than {0} characters."), 13776 minlength: $.validator.format("Please enter at least {0} characters."), 13777 rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), 13778 range: $.validator.format("Please enter a value between {0} and {1}."), 13779 max: $.validator.format("Please enter a value less than or equal to {0}."), 13780 min: $.validator.format("Please enter a value greater than or equal to {0}.") 13781 }, 13782 13783 autoCreateRanges: false, 13784 13785 prototype: { 13786 13787 init: function() { 13788 this.labelContainer = $(this.settings.errorLabelContainer); 13789 this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); 13790 this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); 13791 this.submitted = {}; 13792 this.valueCache = {}; 13793 this.pendingRequest = 0; 13794 this.pending = {}; 13795 this.invalid = {}; 13796 this.reset(); 13797 13798 var groups = (this.groups = {}); 13799 $.each(this.settings.groups, function( key, value ) { 13800 if ( typeof value === "string" ) { 13801 value = value.split(/\s/); 13802 } 13803 $.each(value, function( index, name ) { 13804 groups[name] = key; 13805 }); 13806 }); 13807 var rules = this.settings.rules; 13808 $.each(rules, function( key, value ) { 13809 rules[key] = $.validator.normalizeRule(value); 13810 }); 13811 13812 function delegate(event) {
13813 var validator = $.data(this[0].form, "validator"), 13814 eventType = "on" + event.type.replace(/^validate/, ""); 13815 if ( validator.settings[eventType] ) { 13816 validator.settings[eventType].call(validator, this[0], event); 13817 } 13818 } 13819 $(this.currentForm) 13820 .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " + 13821 "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + 13822 "[type='email'], [type='datetime'], [type='date'], [type='month'], " + 13823 "[type='week'], [type='time'], [type='datetime-local'], " + 13824 "[type='range'], [type='color'] ", 13825 "focusin focusout keyup", delegate) 13826 .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate); 13827 13828 if ( this.settings.invalidHandler ) { 13829 $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); 13830 } 13831 }, 13832 13833 // http://docs.jquery.com/Plugins/Validation/Validator/form 13834 form: function() { 13835 this.checkForm(); 13836 $.extend(this.submitted, this.errorMap); 13837 this.invalid = $.extend({}, this.errorMap); 13838 if ( !this.valid() ) { 13839 $(this.currentForm).triggerHandler("invalid-form", [this]); 13840 } 13841 this.showErrors(); 13842 return this.valid(); 13843 }, 13844 13845 checkForm: function() { 13846 this.prepareForm(); 13847 for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { 13848 this.check( elements[i] ); 13849 } 13850 return this.valid(); 13851 }, 13852 13853 // http://docs.jquery.com/Plugins/Validation/Validator/element 13854 element: function( element ) { 13855 element = this.validationTargetFor( this.clean( element ) ); 13856 this.lastElement = element; 13857 this.prepareElement( element ); 13858 this.currentElements = $(element); 13859 var result = this.check( element ) !== false; 13860 if ( result ) { 13861 delete this.invalid[element.name]; 13862 } else { 13863 this.invalid[element.name] = true; 13864 } 13865 if ( !this.numberOfInvalids() ) { 13866 // Hide error containers on last error 13867 this.toHide = this.toHide.add( this.containers ); 13868 } 13869 this.showErrors(); 13870 return result; 13871 }, 13872 13873 // http://docs.jquery.com/Plugins/Validation/Validator/showErrors 13874 showErrors: function( errors ) { 13875 if ( errors ) { 13876 // add items to error list and map 13877 $.extend( this.errorMap, errors ); 13878 this.errorList = []; 13879 for ( var name in errors ) { 13880 this.errorList.push({ 13881 message: errors[name], 13882 element: this.findByName(name)[0] 13883 }); 13884 } 13885 // remove items from success list 13886 this.successList = $.grep( this.successList, function( element ) { 13887 return !(element.name in errors); 13888 }); 13889 } 13890 if ( this.settings.showErrors ) { 13891 this.settings.showErrors.call( this, this.errorMap, this.errorList ); 13892 } else { 13893 this.defaultShowErrors(); 13894 } 13895 }, 13896 13897 // http://docs.jquery.com/Plugins/Validation/Validator/resetForm 13898 resetForm: function() { 13899 if ( $.fn.resetForm ) { 13900 $(this.currentForm).resetForm(); 13901 } 13902 this.submitted = {}; 13903 this.lastElement = null; 13904 this.prepareForm(); 13905 this.hideErrors(); 13906 this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" ); 13907 }, 13908 13909 numberOfInvalids: function() { 13910 return this.objectLength(this.invalid); 13911 }, 13912 13913 objectLength: function( obj ) { 13914 var count = 0; 13915 for ( var i in obj ) { 13916 count++; 13917 } 13918 return count; 13919 }, 13920 13921 hideErrors: function() { 13922 this.addWrapper( this.toHide ).hide(); 13923 }, 13924 13925 valid: function() { 13926 return this.size() === 0; 13927 }, 13928 13929 size: function() { 13930 return this.errorList.length; 13931 }, 13932 13933 focusInvalid: function() { 13934 if ( this.settings.focusInvalid ) { 13935 try { 13936 $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) 13937 .filter(":visible") 13938 .focus() 13939 // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find 13940 .trigger("focusin"); 13941 } catch(e) { 13942 // ignore IE throwing errors when focusing hidden elements 13943 } 13944 } 13945 }, 13946 13947 findLastActive: function() { 13948 var lastActive = this.lastActive; 13949 return lastActive && $.grep(this.errorList, function( n ) { 13950 return n.element.name === lastActive.name; 13951 }).length === 1 && lastActive; 13952 }, 13953 13954 elements: function() {
13955 var validator = this, 13956 rulesCache = {}; 13957 13958 // select all valid inputs inside the form (no submit or reset buttons) 13959 return $(this.currentForm) 13960 .find("input, select, textarea") 13961 .not(":submit, :reset, :image, [disabled]") 13962 .not( this.settings.ignore ) 13963 .filter(function() { 13964 if ( !this.name && validator.settings.debug && window.console ) { 13965 console.error( "%o has no name assigned", this); 13966 } 13967 13968 // select only the first element for each name, and only those with rules specified 13969 if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) { 13970 return false; 13971 } 13972 13973 rulesCache[this.name] = true; 13974 return true; 13975 }); 13976 }, 13977 13978 clean: function( selector ) { 13979 return $(selector)[0]; 13980 }, 13981 13982 errors: function() { 13983 var errorClass = this.settings.errorClass.replace(" ", "."); 13984 return $(this.settings.errorElement + "." + errorClass, this.errorContext); 13985 }, 13986 13987 reset: function() { 13988 this.successList = []; 13989 this.errorList = []; 13990 this.errorMap = {}; 13991 this.toShow = $([]); 13992 this.toHide = $([]); 13993 this.currentElements = $([]); 13994 }, 13995 13996 prepareForm: function() { 13997 this.reset(); 13998 this.toHide = this.errors().add( this.containers ); 13999 }, 14000 14001 prepareElement: function( element ) { 14002 this.reset(); 14003 this.toHide = this.errorsFor(element); 14004 }, 14005 14006 elementValue: function( element ) { 14007 var type = $(element).attr("type"), 14008 val = $(element).val(); 14009 14010 if ( type === "radio" || type === "checkbox" ) { 14011 return $("input[name='" + $(element).attr("name") + "']:checked").val(); 14012 } 14013 14014 if ( typeof val === "string" ) { 14015 return val.replace(/\r/g, ""); 14016 } 14017 return val; 14018 }, 14019 14020 check: function( element ) { 14021 element = this.validationTargetFor( this.clean( element ) ); 14022 14023 var rules = $(element).rules(); 14024 var dependencyMismatch = false; 14025 var val = this.elementValue(element); 14026 var result; 14027 14028 for (var method in rules ) { 14029 var rule = { method: method, parameters: rules[method] }; 14030 try { 14031 14032 result = $.validator.methods[method].call( this, val, element, rule.parameters ); 14033 14034 // if a method indicates that the field is optional and therefore valid, 14035 // don't mark it as valid when there are no other rules 14036 if ( result === "dependency-mismatch" ) { 14037 dependencyMismatch = true; 14038 continue; 14039 } 14040 dependencyMismatch = false; 14041 14042 if ( result === "pending" ) { 14043 this.toHide = this.toHide.not( this.errorsFor(element) ); 14044 return; 14045 } 14046 14047 if ( !result ) { 14048 this.formatAndAdd( element, rule ); 14049 return false; 14050 } 14051 } catch(e) { 14052 if ( this.settings.debug && window.console ) { 14053 console.log( "Exception occured when checking element " + element.id + ", check the '" + rule.method + "' method.", e ); 14054 } 14055 throw e; 14056 } 14057 } 14058 if ( dependencyMismatch ) { 14059 return; 14060 } 14061 if ( this.objectLength(rules) ) { 14062 this.successList.push(element); 14063 } 14064 return true; 14065 }, 14066 14067 // return the custom message for the given element and validation method 14068 // specified in the element's HTML5 data attribute 14069 customDataMessage: function( element, method ) { 14070 return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase())); 14071 }, 14072 14073 // return the custom message for the given element name and validation method 14074 customMessage: function( name, method ) { 14075 var m = this.settings.messages[name]; 14076 return m && (m.constructor === String ? m : m[method]); 14077 }, 14078 14079 // return the first defined argument, allowing empty strings 14080 findDefined: function() { 14081 for(var i = 0; i < arguments.length; i++) { 14082 if ( arguments[i] !== undefined ) { 14083 return arguments[i]; 14084 } 14085 } 14086 return undefined; 14087 }, 14088 14089 defaultMessage: function( element, method ) { 14090 return this.findDefined( 14091 this.customMessage( element.name, method ), 14092 this.customDataMessage( element, method ), 14093 // title is never undefined, so handle empty string as undefined 14094 !this.settings.ignoreTitle && element.title || undefined, 14095 $.validator.messages[method], 14096 "<strong>Warning: No message defined for " + element.name + "</strong>" 14097 ); 14098 }, 14099 14100 formatAndAdd: function( element, rule ) { 14101 var message = this.defaultMessage( element, rule.method ), 14102 theregex = /\$?\{(\d+)\}/g; 14103 if ( typeof message === "function" ) { 14104 message = message.call(this, rule.parameters, element); 14105 } else if (theregex.test(message)) { 14106 message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters); 14107 } 14108 this.errorList.push({ 14109 message: message, 14110 element: element 14111 }); 14112 14113 this.errorMap[element.name] = message; 14114 this.submitted[element.name] = message; 14115 }, 14116 14117 addWrapper: function( toToggle ) { 14118 if ( this.settings.wrapper ) { 14119 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); 14120 } 14121 return toToggle; 14122 }, 14123 14124 defaultShowErrors: function() { 14125 var i, elements; 14126 for ( i = 0; this.errorList[i]; i++ ) { 14127 var error = this.errorList[i]; 14128 if ( this.settings.highlight ) { 14129 this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.val
14129idClass ); 14130 } 14131 this.showLabel( error.element, error.message ); 14132 } 14133 if ( this.errorList.length ) { 14134 this.toShow = this.toShow.add( this.containers ); 14135 } 14136 if ( this.settings.success ) { 14137 for ( i = 0; this.successList[i]; i++ ) { 14138 this.showLabel( this.successList[i] ); 14139 } 14140 } 14141 if ( this.settings.unhighlight ) { 14142 for ( i = 0, elements = this.validElements(); elements[i]; i++ ) { 14143 this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); 14144 } 14145 } 14146 this.toHide = this.toHide.not( this.toShow ); 14147 this.hideErrors(); 14148 this.addWrapper( this.toShow ).show(); 14149 }, 14150 14151 validElements: function() { 14152 return this.currentElements.not(this.invalidElements()); 14153 }, 14154 14155 invalidElements: function() { 14156 return $(this.errorList).map(function() { 14157 return this.element; 14158 }); 14159 }, 14160 14161 showLabel: function( element, message ) { 14162 var label = this.errorsFor( element ); 14163 if ( label.length ) { 14164 // refresh error/success class 14165 label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); 14166 // replace message on existing label 14167 label.html(message); 14168 } else { 14169 // create label 14170 label = $("<" + this.settings.errorElement + ">") 14171 .attr("for", this.idOrName(element)) 14172 .addClass(this.settings.errorClass) 14173 .html(message || ""); 14174 if ( this.settings.wrapper ) { 14175 // make sure the element is visible, even in IE 14176 // actually showing the wrapped element is handled elsewhere 14177 label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); 14178 } 14179 if ( !this.labelContainer.append(label).length ) { 14180 if ( this.settings.errorPlacement ) { 14181 this.settings.errorPlacement(label, $(element) ); 14182 } else { 14183 label.insertAfter(element); 14184 } 14185 } 14186 } 14187 if ( !message && this.settings.success ) { 14188 label.text(""); 14189 if ( typeof this.settings.success === "string" ) { 14190 label.addClass( this.settings.success ); 14191 } else { 14192 this.settings.success( label, element ); 14193 } 14194 } 14195 this.toShow = this.toShow.add(label); 14196 }, 14197 14198 errorsFor: function( element ) { 14199 var name = this.idOrName(element); 14200 return this.errors().filter(function() { 14201 return $(this).attr("for") === name; 14202 }); 14203 }, 14204 14205 idOrName: function( element ) { 14206 return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); 14207 }, 14208 14209 validationTargetFor: function( element ) { 14210 // if radio/checkbox, validate first element in group instead 14211 if ( this.checkable(element) ) { 14212 element = this.findByName( element.name ).not(this.settings.ignore)[0]; 14213 } 14214 return element; 14215 }, 14216 14217 checkable: function( element ) { 14218 return (/radio|checkbox/i).test(element.type); 14219 }, 14220 14221 findByName: function( name ) { 14222 return $(this.currentForm).find("[name='" + name + "']"); 14223 }, 14224 14225 getLength: function( value, element ) { 14226 switch( element.nodeName.toLowerCase() ) { 14227 case "select": 14228 return $("option:selected", element).length; 14229 case "input": 14230 if ( this.checkable( element) ) { 14231 return this.findByName(element.name).filter(":checked").length; 14232 } 14233 } 14234 return value.length; 14235 }, 14236 14237 depend: function( param, element ) { 14238 return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true; 14239 }, 14240 14241 dependTypes: { 14242 "boolean": function( param, element ) { 14243 return param; 14244 }, 14245 "string": function( param, element ) { 14246 return !!$(param, element.form).length; 14247 }, 14248 "function": function( param, element ) { 14249 return param(element); 14250 } 14251 }, 14252 14253 optional: function( element ) { 14254 var val = this.elementValue(element); 14255 return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch"; 14256 }, 14257 14258 startRequest: function( element ) { 14259 if ( !this.pending[element.name] ) { 14260 this.pendingRequest++; 14261 this.pending[element.name] = true; 14262 } 14263 }, 14264 14265 stopRequest: function( element, valid ) { 14266 this.pendingRequest--; 14267 // sometimes synchronization fails, make sure pendingRequest is never < 0 14268 if ( this.pendingRequest < 0 ) { 14269 this.pendingRequest = 0; 14270 } 14271 delete this.pending[element.name]; 14272 if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { 14273 $(this.currentForm).submit(); 14274 this.formSubmitted = false;
14275 } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) { 14276 $(this.currentForm).triggerHandler("invalid-form", [this]); 14277 this.formSubmitted = false; 14278 } 14279 }, 14280 14281 previousValue: function( element ) { 14282 return $.data(element, "previousValue") || $.data(element, "previousValue", { 14283 old: null, 14284 valid: true, 14285 message: this.defaultMessage( element, "remote" ) 14286 }); 14287 } 14288 14289 }, 14290 14291 classRuleSettings: { 14292 required: {required: true}, 14293 email: {email: true}, 14294 url: {url: true}, 14295 date: {date: true}, 14296 dateISO: {dateISO: true}, 14297 number: {number: true}, 14298 digits: {digits: true}, 14299 creditcard: {creditcard: true} 14300 }, 14301 14302 addClassRules: function( className, rules ) { 14303 if ( className.constructor === String ) { 14304 this.classRuleSettings[className] = rules; 14305 } else { 14306 $.extend(this.classRuleSettings, className); 14307 } 14308 }, 14309 14310 classRules: function( element ) { 14311 var rules = {}; 14312 var classes = $(element).attr("class"); 14313 if ( classes ) { 14314 $.each(classes.split(" "), function() { 14315 if ( this in $.validator.classRuleSettings ) { 14316 $.extend(rules, $.validator.classRuleSettings[this]); 14317 } 14318 }); 14319 } 14320 return rules; 14321 }, 14322 14323 attributeRules: function( element ) { 14324 var rules = {}; 14325 var $element = $(element); 14326 14327 for (var method in $.validator.methods) { 14328 var value; 14329 14330 // support for <input required> in both html5 and older browsers 14331 if ( method === "required" ) { 14332 value = $element.get(0).getAttribute(method); 14333 // Some browsers return an empty string for the required attribute 14334 // and non-HTML5 browsers might have required="" markup 14335 if ( value === "" ) { 14336 value = true; 14337 } 14338 // force non-HTML5 browsers to return bool 14339 value = !!value; 14340 } else { 14341 value = $element.attr(method); 14342 } 14343 14344 if ( value ) { 14345 rules[method] = value; 14346 } else if ( $element[0].getAttribute("type") === method ) { 14347 rules[method] = true; 14348 } 14349 } 14350 14351 // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs 14352 if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) { 14353 delete rules.maxlength; 14354 } 14355 14356 return rules; 14357 }, 14358 14359 dataRules: function( element ) { 14360 var method, value, 14361 rules = {}, $element = $(element); 14362 for (method in $.validator.methods) { 14363 value = $element.data("rule-" + method.toLowerCase()); 14364 if ( value !== undefined ) { 14365 rules[method] = value; 14366 } 14367 } 14368 return rules; 14369 }, 14370 14371 staticRules: function( element ) { 14372 var rules = {}; 14373 var validator = $.data(element.form, "validator"); 14374 if ( validator.settings.rules ) { 14375 rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; 14376 } 14377 return rules; 14378 }, 14379 14380 normalizeRules: function( rules, element ) { 14381 // handle dependency check 14382 $.each(rules, function( prop, val ) { 14383 // ignore rule when param is explicitly false, eg. required:false 14384 if ( val === false ) { 14385 delete rules[prop]; 14386 return; 14387 } 14388 if ( val.param || val.depends ) { 14389 var keepRule = true; 14390 switch (typeof val.depends) { 14391 case "string": 14392 keepRule = !!$(val.depends, element.form).length; 14393 break; 14394 case "function": 14395 keepRule = val.depends.call(element, element); 14396 break; 14397 } 14398 if ( keepRule ) { 14399 rules[prop] = val.param !== undefined ? val.param : true; 14400 } else { 14401 delete rules[prop]; 14402 } 14403 } 14404 }); 14405 14406 // evaluate parameters 14407 $.each(rules, function( rule, parameter ) { 14408 rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; 14409 }); 14410 14411 // clean number parameters 14412 $.each(['minlength', 'maxlength'], function() { 14413 if ( rules[this] ) { 14414 rules[this] = Number(rules[this]); 14415 } 14416 }); 14417 $.each(['rangelength'], function() { 14418 var parts; 14419 if ( rules[this] ) { 14420 if ( $.isArray(rules[this]) ) { 14421 rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; 14422 } else if ( typeof rules[this] === "string" ) { 14423 parts = rules[this].split(/[\s,]+/); 14424 rules[this] = [Number(parts[0]), Number(parts[1])]; 14425 } 14426 } 14427 }); 14428 14429 if ( $.validator.autoCreateRanges ) { 14430 // auto-create ranges 14431 if ( rules.min && rules.max ) { 14432 rules.range = [rules.min, rules.max]; 14433 delete rules.min; 14434 delete rules.max; 14435 } 14436 if ( rules.minlength && rules.maxlength ) { 14437 rules.rangelength = [rules.minlength, rules.maxlength]; 14438 delete rules.minlength; 14439 delete rules.maxlength; 14440 } 14441 } 14442 14443 return rules; 14444 }, 14445
14446 // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} 14447 normalizeRule: function( data ) { 14448 if ( typeof data === "string" ) { 14449 var transformed = {}; 14450 $.each(data.split(/\s/), function() { 14451 transformed[this] = true; 14452 }); 14453 data = transformed; 14454 } 14455 return data; 14456 }, 14457 14458 // http://docs.jquery.com/Plugins/Validation/Validator/addMethod 14459 addMethod: function( name, method, message ) { 14460 $.validator.methods[name] = method; 14461 $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; 14462 if ( method.length < 3 ) { 14463 $.validator.addClassRules(name, $.validator.normalizeRule(name)); 14464 } 14465 }, 14466 14467 methods: { 14468 14469 // http://docs.jquery.com/Plugins/Validation/Methods/required 14470 required: function( value, element, param ) { 14471 // check if dependency is met 14472 if ( !this.depend(param, element) ) { 14473 return "dependency-mismatch"; 14474 } 14475 if ( element.nodeName.toLowerCase() === "select" ) { 14476 // could be an array for select-multiple or a string, both are fine this way 14477 var val = $(element).val(); 14478 return val && val.length > 0; 14479 } 14480 if ( this.checkable(element) ) { 14481 return this.getLength(value, element) > 0; 14482 } 14483 return $.trim(value).length > 0; 14484 }, 14485 14486 // http://docs.jquery.com/Plugins/Validation/Methods/remote 14487 remote: function( value, element, param ) { 14488 if ( this.optional(element) ) { 14489 return "dependency-mismatch"; 14490 } 14491 14492 var previous = this.previousValue(element); 14493 if (!this.settings.messages[element.name] ) { 14494 this.settings.messages[element.name] = {}; 14495 } 14496 previous.originalMessage = this.settings.messages[element.name].remote; 14497 this.settings.messages[element.name].remote = previous.message; 14498 14499 param = typeof param === "string" && {url:param} || param; 14500 14501 if ( previous.old === value ) { 14502 return previous.valid; 14503 } 14504 14505 previous.old = value; 14506 var validator = this; 14507 this.startRequest(element); 14508 var data = {}; 14509 data[element.name] = value; 14510 $.ajax($.extend(true, { 14511 url: param, 14512 mode: "abort", 14513 port: "validate" + element.name, 14514 dataType: "json", 14515 data: data, 14516 success: function( response ) { 14517 validator.settings.messages[element.name].remote = previous.originalMessage; 14518 var valid = response === true || response === "true"; 14519 if ( valid ) { 14520 var submitted = validator.formSubmitted; 14521 validator.prepareElement(element); 14522 validator.formSubmitted = submitted; 14523 validator.successList.push(element); 14524 delete validator.invalid[element.name]; 14525 validator.showErrors(); 14526 } else { 14527 var errors = {}; 14528 var message = response || validator.defaultMessage( element, "remote" ); 14529 errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; 14530 validator.invalid[element.name] = true; 14531 validator.showErrors(errors); 14532 } 14533 previous.valid = valid; 14534 validator.stopRequest(element, valid); 14535 } 14536 }, param)); 14537 return "pending"; 14538 }, 14539 14540 // http://docs.jquery.com/Plugins/Validation/Methods/minlength 14541 minlength: function( value, element, param ) { 14542 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 14543 return this.optional(element) || length >= param; 14544 }, 14545 14546 // http://docs.jquery.com/Plugins/Validation/Methods/maxlength 14547 maxlength: function( value, element, param ) { 14548 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 14549 return this.optional(element) || length <= param; 14550 }, 14551 14552 // http://docs.jquery.com/Plugins/Validation/Methods/rangelength 14553 rangelength: function( value, element, param ) { 14554 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 14555 return this.optional(element) || ( length >= param[0] && length <= param[1] ); 14556 }, 14557 14558 // http://docs.jquery.com/Plugins/Validation/Methods/min 14559 min: function( value, element, param ) { 14560 return this.optional(element) || value >= param; 14561 }, 14562 14563 // http://docs.jquery.com/Plugins/Validation/Methods/max 14564 max: function( value, element, param ) { 14565 return this.optional(element) || value <= param; 14566 }, 14567 14568 // http://docs.jquery.com/Plugins/Validation/Methods/range 14569 range: function( value, element, param ) { 14570 return this.optional(element) || ( value >= param[0] && value <= param[1] ); 14571 }, 14572 14573 // http://docs.jquery.com/Plugins/Validation/Methods/email 14574 email: function( value, element ) { 14575 return this.optional(element) || /^[^@]+@[^\.]+\..+$/.test(value); 14576 }, 14577 14578 // http://docs.jquery.com/Plugins/Validation/Methods/url 14579 url: function( value, element ) { 14580 // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ 14581 return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); 14582 }, 14583 14584 // http://docs.jquery.com/Plugins/Validation/Methods/date 14585 date: function( value, element ) { 14586 return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString()); 14587 }, 14588 14589 // http://docs.jquery.com/Plugins/Validation/Methods/dateISO 14590 dateISO: function( value, element ) { 14591 return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value); 14592 }, 14593 14594 // http://docs.jquery.com/Plugins/Validation/Methods/number 14595 number: function( value, element ) { 14596 return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value); 14597 }, 14598 14599 // http://docs.jquery.com/Plugins/Validation/Methods/digits 14600 digits: function( value, element ) { 14601 return this.optional(element) || /^\d+$/.test(value); 14602 }, 14603 14604 // http://docs.jquery.com/Plugins/Validation/Methods/creditcard 14605 // based on http://en.wikipedia.org/wiki/Luhn 14606 creditcard: function( value, element ) { 14607 if ( this.optional(element) ) { 14608 return "dependency-mismatch"; 14609 } 14610 // accept only spaces, digits and dashes 14611 if ( /[^0-9 \-]+/.test(value) ) { 14612 return false;
14613 } 14614 var nCheck = 0, 14615 nDigit = 0, 14616 bEven = false; 14617 14618 value = value.replace(/\D/g, ""); 14619 14620 for (var n = value.length - 1; n >= 0; n--) { 14621 var cDigit = value.charAt(n); 14622 nDigit = parseInt(cDigit, 10); 14623 if ( bEven ) { 14624 if ( (nDigit *= 2) > 9 ) { 14625 nDigit -= 9; 14626 } 14627 } 14628 nCheck += nDigit; 14629 bEven = !bEven; 14630 } 14631 14632 return (nCheck % 10) === 0; 14633 }, 14634 14635 // http://docs.jquery.com/Plugins/Validation/Methods/equalTo 14636 equalTo: function( value, element, param ) { 14637 // bind to the blur event of the target in order to revalidate whenever the target field is updated 14638 // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead 14639 var target = $(param); 14640 if ( this.settings.onfocusout ) { 14641 target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { 14642 $(element).valid(); 14643 }); 14644 } 14645 return value === target.val(); 14646 } 14647 14648 } 14649 14650}); 14651 14652// deprecated, use $.validator.format instead 14653$.format = $.validator.format; 14654 14655}(jQuery)); 14656 14657// ajax mode: abort 14658// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 14659// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 14660(function($) { 14661 var pendingRequests = {}; 14662 // Use a prefilter if available (1.5+) 14663 if ( $.ajaxPrefilter ) { 14664 $.ajaxPrefilter(function( settings, _, xhr ) { 14665 var port = settings.port; 14666 if ( settings.mode === "abort" ) { 14667 if ( pendingRequests[port] ) { 14668 pendingRequests[port].abort(); 14669 } 14670 pendingRequests[port] = xhr; 14671 } 14672 }); 14673 } else { 14674 // Proxy ajax 14675 var ajax = $.ajax; 14676 $.ajax = function( settings ) { 14677 var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, 14678 port = ( "port" in settings ? settings : $.ajaxSettings ).port; 14679 if ( mode === "abort" ) { 14680 if ( pendingRequests[port] ) { 14681 pendingRequests[port].abort(); 14682 } 14683 return (pendingRequests[port] = ajax.apply(this, arguments)); 14684 } 14685 return ajax.apply(this, arguments); 14686 }; 14687 } 14688}(jQuery)); 14689 14690// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation 14691// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 14692(function($) { 14693 $.extend($.fn, { 14694 validateDelegate: function( delegate, type, handler ) { 14695 return this.bind(type, function( event ) { 14696 var target = $(event.target); 14697 if ( target.is(delegate) ) { 14698 return handler.apply(target, arguments); 14699 } 14700 }); 14701 } 14702 }); 14703}(jQuery)); 14704/*! 14705* jQuery File Download Plugin v1.4.3 14706* 14707* http://www.johnculviner.com 14708* 14709* Copyright (c) 2013 - John Culviner 14710* 14711* Licensed under the MIT license: 14712* http://www.opensource.org/licenses/mit-license.php 14713* 14714* !!!!NOTE!!!! 14715* You must also write a cookie in conjunction with using this plugin as mentioned in the orignal post: 14716* http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/ 14717* !!!!NOTE!!!! 14718*/ 14719 14720 14721(function($, window){ 14722 // i'll just put them here to get evaluated on script load 14723 var htmlSpecialCharsRegEx = /[<>&\r\n"']/gm; 14724 var htmlSpecialCharsPlaceHolders = { 14725 '<': 'lt;', 14726 '>': 'gt;', 14727 '&': 'amp;', 14728 '\r': "#13;", 14729 '\n': "#10;", 14730 '"': 'quot;', 14731 "'": '#39;' /*single quotes just to be safe, IE8 doesn't support ', so use ' instead */ 14732 }; 14733 14734$.extend({ 14735 // 14736 //$.fileDownload('/path/to/url/', options) 14737 // see directly below for possible 'options' 14738 fileDownload: function (fileUrl, options) { 14739 14740 //provide some reasonable defaults to any unspecified options below 14741 var settings = $.extend({ 14742 14743 // 14744 //Requires jQuery UI: provide a message to display to the user when the file download is being prepared before the browser's dialog appears 14745 // 14746 preparingMessageHtml: null, 14747 14748 // 14749 //Requires jQuery UI: provide a message to display to the user when a file download fails 14750 // 14751 failMessageHtml: null, 14752 14753 // 14754 //the stock android browser straight up doesn't support file downloads initiated by a non GET: http://code.google.com/p/android/issues/detail?id=1780 14755 //specify a message here to display if a user tries with an android browser 14756 //if jQuery UI is installed this will be a dialog, otherwise it will be an alert 14757 //Set to null to disable the message and attempt to download anyway 14758 // 14759 androidPostUnsupportedMessageHtml: "Unfortunately your Android browser doesn't support this type of file download. Please try again with a different browser.", 14760 14761 // 14762 //Requires jQuery UI: options to pass into jQuery UI Dialog 14763 // 14764 dialogOptions: { modal: true }, 14765 14766 // 14767 //a function to call while the dowload is being prepared before the browser's dialog appears 14768 //Args: 14769 // url - the original url attempted 14770 // 14771 prepareCallback: function (url) { }, 14772 14773 // 14774 //a function to call after a file download dialog/ribbon has appeared 14775 //Args: 14776 // url - the original url attempted 14777 // 14778 successCallback: function (url) { }, 14779 14780 // 14781 //a function to call after a file download dialog/ribbon has appeared 14782 //Args: 14783 // responseHtml - the html that came back in response to the file download. this won't necessarily come back depending on the browser. 14784 // in less than IE9 a cross domain error occurs because 500+ errors cause a cross domain issue due to IE subbing out the 14785 // server's error message with a "helpful" IE built in message 14786 // url - the original url attempted 14787 // 14788 failCallback: function (responseHtml, url) { }, 14789 14790 // 14791 // the HTTP method to use. Defaults to "GET". 14792 // 14793 httpMethod: "GET", 14794 14795 // 14796 // if specified will perform a "httpMethod" request to the specified 'fileUrl' using the specified data. 14797 // data must be an object (which will be $.param seri
14797alized) or already a key=value param string 14798 // 14799 data: null, 14800 14801 // 14802 //a period in milliseconds to poll to determine if a successful file download has occured or not 14803 // 14804 checkInterval: 100, 14805 14806 // 14807 //the cookie name to indicate if a file download has occured 14808 // 14809 cookieName: "fileDownload", 14810 14811 // 14812 //the cookie value for the above name to indicate that a file download has occured 14813 // 14814 cookieValue: "true", 14815 14816 // 14817 //the cookie path for above name value pair 14818 // 14819 cookiePath: "/", 14820 14821 // 14822 //if specified it will be used when attempting to clear the above name value pair 14823 //useful for when downloads are being served on a subdomain (e.g. downloads.example.com) 14824 // 14825 cookieDomain: null, 14826 14827 // 14828 //the title for the popup second window as a download is processing in the case of a mobile browser 14829 // 14830 popupWindowTitle: "Initiating file download...", 14831 14832 // 14833 //Functionality to encode HTML entities for a POST, need this if data is an object with properties whose values contains strings with quotation marks. 14834 //HTML entity encoding is done by replacing all &,<,>,',",\r,\n characters. 14835 //Note that some browsers will POST the string htmlentity-encoded whilst others will decode it before POSTing. 14836 //It is recommended that on the server, htmlentity decoding is done irrespective. 14837 // 14838 encodeHTMLEntities: true 14839 14840 }, options); 14841 14842 var deferred = new $.Deferred(); 14843 14844 //Setup mobile browser detection: Partial credit: http://detectmobilebrowser.com/ 14845 var userAgent = (navigator.userAgent || navigator.vendor || window.opera).toLowerCase(); 14846 14847 var isIos; //has full support of features in iOS 4.0+, uses a new window to accomplish this. 14848 var isAndroid; //has full support of GET features in 4.0+ by using a new window. Non-GET is completely unsupported by the browser. See above for specifying a message. 14849 var isOtherMobileBrowser; //there is no way to reliably guess here so all other mobile devices will GET and POST to the current window. 14850 14851 if (/ip(ad|hone|od)/.test(userAgent)) { 14852 14853 isIos = true; 14854 14855 } else if (userAgent.indexOf('android') !== -1) { 14856 14857 isAndroid = true; 14858 14859 } else { 14860 14861 isOtherMobileBrowser = /avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|playbook|silk|iemobile|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
14861sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)); 14862 14863 } 14864 14865 var httpMethodUpper = settings.httpMethod.toUpperCase(); 14866 14867 if (isAndroid && httpMethodUpper !== "GET" && settings.androidPostUnsupportedMessageHtml) { 14868 //the stock android browser straight up doesn't support file downloads initiated by non GET requests: http://code.google.com/p/android/issues/detail?id=1780 14869 14870 if ($().dialog) { 14871 $("<div>").html(settings.androidPostUnsupportedMessageHtml).dialog(settings.dialogOptions); 14872 } else { 14873 alert(settings.androidPostUnsupportedMessageHtml); 14874 } 14875 14876 return deferred.reject(); 14877 } 14878 14879 var $preparingDialog = null; 14880 14881 var internalCallbacks = { 14882 14883 onPrepare: function (url) { 14884 14885 //wire up a jquery dialog to display the preparing message if specified 14886 if (settings.preparingMessageHtml) { 14887 14888 $preparingDialog = $("<div>").html(settings.preparingMessageHtml).dialog(settings.dialogOptions); 14889 14890 } else if (settings.prepareCallback) { 14891 14892 settings.prepareCallback(url); 14893 14894 } 14895 14896 }, 14897 14898 onSuccess: function (url) { 14899 14900 //remove the perparing message if it was specified 14901 if ($preparingDialog) { 14902 $preparingDialog.dialog('close'); 14903 }; 14904 14905 settings.successCallback(url); 14906 14907 deferred.resolve(url); 14908 }, 14909 14910 onFail: function (responseHtml, url) { 14911 14912 //remove the perparing message if it was specified 14913 if ($preparingDialog) { 14914 $preparingDialog.dialog('close'); 14915 }; 14916 14917 //wire up a jquery dialog to display the fail message if specified 14918 if (settings.failMessageHtml) { 14919 $("<div>").html(settings.failMessageHtml).dialog(settings.dialogOptions); 14920 } 14921 14922 settings.failCallback(responseHtml, url); 14923 14924 deferred.reject(responseHtml, url); 14925 } 14926 }; 14927 14928 internalCallbacks.onPrepare(fileUrl); 14929 14930 //make settings.data a param string if it exists and isn't already 14931 if (settings.data !== null && typeof settings.data !== "string") { 14932 settings.data = $.param(settings.data); 14933 } 14934 14935 14936 var $iframe, 14937 downloadWindow, 14938 formDoc, 14939 $form; 14940 14941 if (httpMethodUpper === "GET") { 14942 14943 if (settings.data !== null) { 14944 //need to merge any fileUrl params with the data object 14945 14946 var qsStart = fileUrl.indexOf('?'); 14947 14948 if (qsStart !== -1) { 14949 //we have a querystring in the url 14950 14951 if (fileUrl.substring(fileUrl.length - 1) !== "&") { 14952 fileUrl = fileUrl + "&"; 14953 } 14954 } else { 14955 14956 fileUrl = fileUrl + "?"; 14957 } 14958 14959 fileUrl = fileUrl + settings.data; 14960 } 14961 14962 if (isIos || isAndroid) { 14963 14964 downloadWindow = window.open(fileUrl); 14965 downloadWindow.document.title = settings.popupWindowTitle; 14966 window.focus(); 14967 14968 } else if (isOtherMobileBrowser) { 14969 14970 window.location(fileUrl); 14971 14972 } else { 14973 14974 //create a temporary iframe that is used to request the fileUrl as a GET request 14975 $iframe = $("<iframe>") 14976 .hide() 14977 .prop("src", fileUrl) 14978 .appendTo("body"); 14979 } 14980 14981 } else { 14982 14983 var formInnerHtml = ""; 14984 14985 if (settings.data !== null) { 14986 14987 $.each(settings.data.replace(/\+/g, ' ').split("&"), function () { 14988 14989 var kvp = this.split("="); 14990 14991 var key = settings.encodeHTMLEntities ? htmlSpecialCharsEntityEncode(decodeURIComponent(kvp[0])) : decodeURIComponent(kvp[0]); 14992 if (key) { 14993 var value = settings.encodeHTMLEntities ? htmlSpecialCharsEntityEncode(decodeURIComponent(kvp[1])) : decodeURIComponent(kvp[1]); 14994 formInnerHtml += '<input type="hidden" name="' + key + '" value="' + value + '" />'; 14995 } 14996 }); 14997 } 14998 14999 if (isOtherMobileBrowser) { 15000 15001 $form = $("<form>").appendTo("body"); 15002 $form.hide() 15003 .prop('method', settings.httpMethod) 15004 .prop('action', fileUrl) 15005 .html(formInnerHtml); 15006 15007 } else { 15008 15009 if (isIos) { 15010 15011 downloadWindow = window.open("about:blank"); 15012 downloadWindow.document.title = settings.popupWindowTitle; 15013 formDoc = downloadWindow.document; 15014 window.focus(); 15015 15016 } else { 15017 15018 $iframe = $("<iframe style='display: none' src='about:blank'></iframe>").appendTo("body"); 15019 formDoc = getiframeDocument($iframe); 15020 } 15021 15022 formDoc.write("<html><head></head><body><form method='" + settings.httpMethod + "' action='" + fileUrl + "'>" + formInnerHtml + "</form>" + settings.popupWindowTitle + "</body></html>"); 15023 $form = $(formDoc).find('form'); 15024 } 15025 15026 $form.submit(); 15027 } 15028 15029 15030 //check if the file download has completed every checkInterval ms 15031 setTimeout(checkFileDownloadComplete, settings.checkInterval); 15032 15033 15034 function checkFileDownloadComplete() { 15035 //has the cookie been written due to a file download occuring? 15036 if (document.cookie.indexOf(settings.cookieName + "=" + settings.cookieValue) != -1) { 15037 15038 //execute specified callback 15039 internalCallbacks.onSuccess(fileUrl); 15040 15041 //remove cookie 15042 var cookieData = settings.cookieName + "=; path=" + settings.cookiePath + "; expires=" + new Date(0).toUTCString() + ";"; 15043 if (settings.cookieDomain) cookieData += " domain=" + settings.cookieDomain + ";"; 15044 document.cookie = cookieData; 15045 15046 //remove iframe 15047 cleanUp(false); 15048 15049 return; 15050 } 15051 15052 //has an error occured? 15053 //if neither containers exist below then the file download is occuring on the current window 15054 if (downloadWindow || $iframe) { 15055 15056 //has an error occured? 15057 try { 15058 15059 var formDoc = downloadWindow ? downloadWindow.document : getiframeDocument($iframe); 15060 15061 if (formDoc && formDoc.body != null && formDoc.body.innerHTML.length) { 15062 15063 var isFailure = true; 15064 15065 if ($form && $form.length) { 15066 var $contents = $(formDoc.body).contents().first(); 15067 15068 try { 15069 if ($contents.length && $contents[0] === $form[0]) { 15070 isFailure = false;
15071 } 15072 } catch (e) { 15073 if (e && e.number == -2146828218) { 15074 // IE 8-10 throw a permission denied after the form reloads on the "$contents[0] === $form[0]" comparison 15075 isFailure = true; 15076 } else { 15077 throw e; 15078 } 15079 } 15080 } 15081 15082 if (isFailure) { 15083 // IE 8-10 don't always have the full content available right away, they need a litle bit to finish 15084 setTimeout(function () { 15085 internalCallbacks.onFail(formDoc.body.innerHTML, fileUrl); 15086 cleanUp(true); 15087 }, 100); 15088 15089 return; 15090 } 15091 } 15092 } 15093 catch (err) { 15094 15095 //500 error less than IE9 15096 internalCallbacks.onFail('', fileUrl); 15097 15098 cleanUp(true); 15099 15100 return; 15101 } 15102 } 15103 15104 15105 //keep checking... 15106 setTimeout(checkFileDownloadComplete, settings.checkInterval); 15107 } 15108 15109 //gets an iframes document in a cross browser compatible manner 15110 function getiframeDocument($iframe) { 15111 var iframeDoc = $iframe[0].contentWindow || $iframe[0].contentDocument; 15112 if (iframeDoc.document) { 15113 iframeDoc = iframeDoc.document; 15114 } 15115 return iframeDoc; 15116 } 15117 15118 function cleanUp(isFailure) { 15119 15120 setTimeout(function() { 15121 15122 if (downloadWindow) { 15123 15124 if (isAndroid) { 15125 downloadWindow.close(); 15126 } 15127 15128 if (isIos) { 15129 if (downloadWindow.focus) { 15130 downloadWindow.focus(); //ios safari bug doesn't allow a window to be closed unless it is focused 15131 if (isFailure) { 15132 downloadWindow.close(); 15133 } 15134 } 15135 } 15136 } 15137 15138 //iframe cleanup appears to randomly cause the download to fail 15139 //not doing it seems better than failure... 15140 //if ($iframe) { 15141 // $iframe.remove(); 15142 //} 15143 15144 }, 0); 15145 } 15146 15147 15148 function htmlSpecialCharsEntityEncode(str) { 15149 return str.replace(htmlSpecialCharsRegEx, function(match) { 15150 return '&' + htmlSpecialCharsPlaceHolders[match]; 15151 }); 15152 } 15153 var promise = deferred.promise(); 15154 promise.abort = function() { 15155 cleanUp(); 15156 $iframe.remove(); 15157 }; 15158 return promise; 15159 } 15160}); 15161 15162})(jQuery, this); 15163// I18n.js 15164// ======= 15165// 15166// This small library provides the Rails I18n API on the Javascript. 15167// You don't actually have to use Rails (or even Ruby) to use I18n.js. 15168// Just make sure you export all translations in an object like this: 15169// 15170// I18n.translations.en = { 15171// hello: "Hello World" 15172// }; 15173// 15174// See tests for specific formatting like numbers and dates. 15175// 15176 15177// Using UMD pattern from 15178// https://github.com/umdjs/umd#regular-module 15179// `returnExports.js` version 15180;(function (root, factory) { 15181 if (typeof define === 'function' && define.amd) { 15182 // AMD. Register as an anonymous module. 15183 define("i18n", function(){ return factory(root);}); 15184 } else if (typeof module === 'object' && module.exports) { 15185 // Node. Does not work with strict CommonJS, but 15186 // only CommonJS-like environments that support module.exports, 15187 // like Node. 15188 module.exports = factory(root); 15189 } else { 15190 // Browser globals (root is window) 15191 root.I18n = factory(root); 15192 } 15193}(this, function(global) { 15194 "use strict"; 15195 15196 // Use previously defined object if exists in current scope 15197 var I18n = global && global.I18n || {}; 15198 15199 // Just cache the Array#slice function. 15200 var slice = Array.prototype.slice; 15201 15202 // Apply number padding. 15203 var padding = function(number) { 15204 return ("0" + number.toString()).substr(-2); 15205 }; 15206 15207 // Improved toFixed number rounding function with support for unprecise floating points 15208 // JavaScript's standard toFixed function does not round certain
15208numbers correctly (for example 0.105 with precision 2). 15209 var toFixed = function(number, precision) { 15210 return decimalAdjust('round', number, -precision).toFixed(precision); 15211 }; 15212 15213 // Is a given variable an object? 15214 // Borrowed from Underscore.js 15215 var isObject = function(obj) { 15216 var type = typeof obj; 15217 return type === 'function' || type === 'object' 15218 }; 15219 15220 var isFunction = function(func) { 15221 var type = typeof func; 15222 return type === 'function' 15223 }; 15224 15225 // Check if value is different than undefined and null; 15226 var isSet = function(value) { 15227 return typeof(value) !== 'undefined' && value !== null; 15228 }; 15229 15230 // Is a given value an array? 15231 // Borrowed from Underscore.js 15232 var isArray = function(val) { 15233 if (Array.isArray) { 15234 return Array.isArray(val); 15235 } 15236 return Object.prototype.toString.call(val) === '[object Array]'; 15237 }; 15238 15239 var isString = function(val) { 15240 return typeof val === 'string' || Object.prototype.toString.call(val) === '[object String]'; 15241 }; 15242 15243 var isNumber = function(val) { 15244 return typeof val === 'number' || Object.prototype.toString.call(val) === '[object Number]'; 15245 }; 15246 15247 var isBoolean = function(val) { 15248 return val === true || val === false; 15249 }; 15250 15251 var isNull = function(val) { 15252 return val === null; 15253 }; 15254 15255 var decimalAdjust = function(type, value, exp) { 15256 // If the exp is undefined or zero... 15257 if (typeof exp === 'undefined' || +exp === 0) { 15258 return Math[type](value); 15259 } 15260 value = +value; 15261 exp = +exp; 15262 // If the value is not a number or the exp is not an integer... 15263 if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) { 15264 return NaN; 15265 } 15266 // Shift 15267 value = value.toString().split('e'); 15268 value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp))); 15269 // Shift back 15270 value = value.toString().split('e'); 15271 return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)); 15272 }; 15273 15274 var lazyEvaluate = function(message, scope) { 15275 if (isFunction(message)) { 15276 return message(scope); 15277 } else { 15278 return message; 15279 } 15280 }; 15281 15282 var merge = function (dest, obj) { 15283 var key, value; 15284 for (key in obj) if (obj.hasOwnProperty(key)) { 15285 value = obj[key]; 15286 if (isString(value) || isNumber(value) || isBoolean(value) || isArray(value) || isNull(value)) { 15287 dest[key] = value; 15288 } else { 15289 if (dest[key] == null) dest[key] = {}; 15290 merge(dest[key], value); 15291 } 15292 } 15293 return dest; 15294 }; 15295 15296 // Set default days/months translations. 15297 var DATE = { 15298 day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] 15299 , abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] 15300 , month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
15300November", "December"] 15301 , abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 15302 , meridian: ["AM", "PM"] 15303 }; 15304 15305 // Set default number format. 15306 var NUMBER_FORMAT = { 15307 precision: 3 15308 , separator: "." 15309 , delimiter: "," 15310 , strip_insignificant_zeros: false 15311 }; 15312 15313 // Set default currency format. 15314 var CURRENCY_FORMAT = { 15315 unit: "$" 15316 , precision: 2 15317 , format: "%u%n" 15318 , sign_first: true 15319 , delimiter: "," 15320 , separator: "." 15321 }; 15322 15323 // Set default percentage format. 15324 var PERCENTAGE_FORMAT = { 15325 unit: "%" 15326 , precision: 3 15327 , format: "%n%u" 15328 , separator: "." 15329 , delimiter: "" 15330 }; 15331 15332 // Set default size units. 15333 var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"]; 15334 15335 // Other default options 15336 var DEFAULT_OPTIONS = { 15337 // Set default locale. This locale will be used when fallback is enabled and 15338 // the translation doesn't exist in a particular locale. 15339 defaultLocale: "en" 15340 // Set the current locale to `en`. 15341 , locale: "en" 15342 // Set the translation key separator. 15343 , defaultSeparator: "." 15344 // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`. 15345 , placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm 15346 // Set if engine should fallback to the default locale when a translation 15347 // is missing. 15348 , fallbacks: false 15349 // Set the default translation object. 15350 , translations: {} 15351 // Set missing translation behavior. 'message' will display a message 15352 // that the translation is missing, 'guess' will try to guess the string 15353 , missingBehaviour: 'message' 15354 // if you use missingBehaviour with 'message', but want to know that the 15355 // string is actually missing for testing purposes, you can prefix the 15356 // guessed string by setting the value here. By default, no prefix! 15357 , missingTranslationPrefix: '' 15358 }; 15359 15360 // Set default locale. This locale will be used when fallback is enabled and 15361 // the translation doesn't exist in a particular locale. 15362 I18n.reset = function() { 15363 var key; 15364 for (key in DEFAULT_OPTIONS) { 15365 this[key] = DEFAULT_OPTIONS[key]; 15366 } 15367 }; 15368 15369 // Much like `reset`, but only assign options if not already assigned 15370 I18n.initializeOptions = function() { 15371 var key; 15372 for (key in DEFAULT_OPTIONS) if (!isSet(this[key])) { 15373 this[key] = DEFAULT_OPTIONS[key]; 15374 } 15375 }; 15376 I18n.initializeOptions(); 15377 15378 // Return a list of all locales that must be tried before returning the 15379 // missing translation message. By default, this will consider the inline option, 15380 // current locale and fallback locale. 15381 // 15382 // I18n.locales.get("de-DE"); 15383 // // ["de-DE", "de", "en"] 15384 // 15385 // You can define custom rules for any locale. Just make sure you return a array 15386 // containing all locales. 15387 // 15388 // // Default the Wookie locale to English. 15389 // I18n.locales["wk"] = function(locale) { 15390 // return ["en"]; 15391 // }; 15392 // 15393 I18n.locales = {}; 15394 15395 // Retrieve locales based on inline locale, current locale or default to 15396 // I18n's detection. 15397 I18n.locales.get = function(locale) { 15398 var result = this[locale] || this[I18n.locale] || this["default"]; 15399 15400 if (isFunction(result)) { 15401 result = result(locale); 15402 } 15403 15404 if (isArray(result) === false) { 15405 result = [result]; 15406 } 15407 15408 return result; 15409 }; 15410 15411 // The default locale list. 15412 I18n.locales["default"] = function(locale) { 15413 var locales = [] 15414 , list = [] 15415 ; 15416 15417 // Handle the inline locale option that can be provided to 15418 // the `I18n.t` options. 15419 if (locale) { 15420 locales.push(locale); 15421 } 15422 15423 // Add the current locale to the list. 15424 if (!locale && I18n.locale) { 15425 locales.push(I18n.locale); 15426 } 15427 15428 // Add the default locale if fallback strategy is enabled. 15429 if (I18n.fallbacks && I18n.defaultLocale) { 15430 locales.push(I18n.defaultLocale); 15431 } 15432 15433 // Locale code format 1: 15434 // According to RFC4646 (https://www.ietf.org/rfc/rfc4646.txt) 15435 // language codes for Traditional Chinese should be `zh-Hant` 15436 // 15437 // But due to backward compatibility 15438 // We use older version of IETF language tag 15439 // @see https://www.w3.org/TR/html401/struct/dirlang.html 15440 // @see https://en.wikipedia.org/wiki/IETF_language_tag 15441 // 15442 // Format: `language-code = primary-code ( "-" subcode )*` 15443 // 15444 // primary-code uses ISO639-1 15445 // @see https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 15446 // @see https://www.iso.org/iso/home/standards/language_codes.htm 15447 // 15448 // subcode uses ISO 3166-1 alpha-2 15449 // @see https://en.wikipedia.org/wiki/ISO_3166 15450 // @see https://www.iso.org/iso/country_codes.htm 15451 // 15452 // @note 15453 // subcode can be in upper case or lower case 15454 // defining it in upper case is a convention only 15455 15456 15457 // Locale code format 2: 15458 // Format: `code = primary-code ( "-" region-code )*` 15459 // primary-code uses ISO 639-1 15460 // script-code uses ISO 15924 15461 // region-code uses ISO 3166-1 alpha-2 15462 // Example: zh-Hant-TW, en-HK, zh-Hant-CN 15463 // 15464 // It is similar to RFC4646 (or actually the same), 15465 // but seems to be limited to language, script, region 15466 15467 // Compute each locale with its country code. 15468 // So this will return an array containing 15469 // `de-DE` and `de` 15470 // or 15471 // `zh-hans-tw`, `zh-hans`, `zh` 15472 // locales.
15473 locales.forEach(function(locale) { 15474 var localeParts = locale.split("-"); 15475 var firstFallback = null; 15476 var secondFallback = null; 15477 if (localeParts.length === 3) { 15478 firstFallback = [ 15479 localeParts[0], 15480 localeParts[1] 15481 ].join("-"); 15482 secondFallback = localeParts[0]; 15483 } 15484 else if (localeParts.length === 2) { 15485 firstFallback = localeParts[0]; 15486 } 15487 15488 if (list.indexOf(locale) === -1) { 15489 list.push(locale); 15490 } 15491 15492 if (! I18n.fallbacks) { 15493 return; 15494 } 15495 15496 [ 15497 firstFallback, 15498 secondFallback 15499 ].forEach(function(nullableFallbackLocale) { 15500 // We don't want null values 15501 if (typeof nullableFallbackLocale === "undefined") { return; } 15502 if (nullableFallbackLocale === null) { return; } 15503 // We don't want duplicate values 15504 // 15505 // Comparing with `locale` first is faster than 15506 // checking whether value's presence in the list 15507 if (nullableFallbackLocale === locale) { return; } 15508 if (list.indexOf(nullableFallbackLocale) !== -1) { return; } 15509 15510 list.push(nullableFallbackLocale); 15511 }); 15512 }); 15513 15514 // No locales set? English it is. 15515 if (!locales.length) { 15516 locales.push("en"); 15517 } 15518 15519 return list; 15520 }; 15521 15522 // Hold pluralization rules. 15523 I18n.pluralization = {}; 15524 15525 // Return the pluralizer for a specific locale. 15526 // If no specify locale is found, then I18n's default will be used. 15527 I18n.pluralization.get = function(locale) { 15528 return this[locale] || this[I18n.locale] || this["default"]; 15529 }; 15530 15531 // The default pluralizer rule. 15532 // It detects the `zero`, `one`, and `other` scopes. 15533 I18n.pluralization["default"] = function(count) { 15534 switch (count) { 15535 case 0: return ["zero", "other"]; 15536 case 1: return ["one"]; 15537 default: return ["other"]; 15538 } 15539 }; 15540 15541 // Return current locale. If no locale has been set, then 15542 // the current locale will be the default locale. 15543 I18n.currentLocale = function() { 15544 return this.locale || this.defaultLocale; 15545 }; 15546 15547 // Check if value is different than undefined and null; 15548 I18n.isSet = isSet; 15549 15550 // Find and process the translation using the provided scope and options. 15551 // This is used internally by some functions and should not be used as an 15552 // public API. 15553 I18n.lookup = function(scope, options) { 15554 options = options || {}; 15555 15556 var locales = this.locales.get(options.locale).slice() 15557 , locale 15558 , scopes 15559 , fullScope 15560 , translations 15561 ; 15562 15563 fullScope = this.getFullScope(scope, options); 15564 15565 while (locales.length) { 15566 locale = locales.shift(); 15567 scopes = fullScope.split(options.separator || this.defaultSeparator); 15568 translations = this.translations[locale]; 15569 15570 if (!translations) { 15571 continue; 15572 } 15573 while (scopes.length) { 15574 translations = translations[scopes.shift()]; 15575 15576 if (translations === undefined || translations === null) { 15577 break; 15578 } 15579 } 15580 15581 if (translations !== undefined && translations !== null) { 15582 return translations; 15583 } 15584 } 15585 15586 if (isSet(options.defaultValue)) { 15587 return lazyEvaluate(options.defaultValue, scope); 15588 } 15589 }; 15590 15591 // lookup pluralization rule key into translations 15592 I18n.pluralizationLookupWithoutFallback = function(count, locale, translations) { 15593 var pluralizer = this.pluralization.get(locale) 15594 , pluralizerKeys = pluralizer(count) 15595 , pluralizerKey 15596 , message; 15597 15598 if (translations && isObject(translations)) { 15599 while (pluralizerKeys.length) { 15600 pluralizerKey = pluralizerKeys.shift(); 15601 if (isSet(translations[pluralizerKey])) { 15602 message = translations[pluralizerKey]; 15603 break; 15604 } 15605 } 15606 } 15607 15608 return message; 15609 }; 15610 15611 // Lookup dedicated to pluralization 15612 I18n.pluralizationLookup = function(count, scope, options) { 15613 options = options || {}; 15614 var locales = this.locales.get(options.locale).slice() 15615 , locale 15616 , scopes 15617 , translations 15618 , message 15619 ; 15620 scope = this.getFullScope(scope, options); 15621 15622 while (locales.length) { 15623 locale = locales.shift(); 15624 scopes = scope.split(options.separator || this.defaultSeparator); 15625 translations = this.translations[locale]; 15626 15627 if (!translations) { 15628 continue; 15629 } 15630 15631 while (scopes.length) { 15632 translations = translations[scopes.shift()]; 15633 if (!isObject(translations)) { 15634 break; 15635 } 15636 if (scopes.length === 0) { 15637 message = this.pluralizationLookupWithoutFallback(count, locale, translations); 15638 } 15639 } 15640 if (typeof message !== "undefined" && message !== null) { 15641 break; 15642 } 15643 } 15644 15645 if (typeof message === "undefined" || message === null) { 15646 if (isSet(options.defaultValue)) { 15647 if (isObject(options.defaultValue)) { 15648 message = this.pluralizationLookupWithoutFallback(count, options.locale, options.defaultValue); 15649 } else { 15650 message = options.defaultValue; 15651 } 15652 translations = options.defaultValue; 15653 } 15654 } 15655 15656 return { message: message, translations: translations }; 15657 }; 15658 15659 // Rails changed the way the meridian is stored. 15660 // It started with `date.meridian` returning an array, 15661 // then it switched to `time.am` and `time.pm`. 15662 // This function abstracts this difference and returns 15663 // the correct meridian or the default value when none is provided. 15664 I18n.meridian = function() { 15665 var time = this.lookup("time"); 15666 var date = this.lookup("date"); 15667 15668 if (time && time.am && time.pm) { 15669 return [time.am, time.pm]; 15670 } else if (date && date.meridian) { 15671 return date.meridian; 15672 } else { 15673 return DATE.meridian; 15674 } 15675 }; 15676 15677 // Merge serveral hash options, checking if value is set before 15678 // overwriting any value. The precedence is from left to right. 15679 //
15680 // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"}); 15681 // #=> {name: "John Doe", role: "user"} 15682 // 15683 I18n.prepareOptions = function() { 15684 var args = slice.call(arguments) 15685 , options = {} 15686 , subject 15687 ; 15688 15689 while (args.length) { 15690 subject = args.shift(); 15691 15692 if (typeof(subject) != "object") { 15693 continue; 15694 } 15695 15696 for (var attr in subject) { 15697 if (!subject.hasOwnProperty(attr)) { 15698 continue; 15699 } 15700 15701 if (isSet(options[attr])) { 15702 continue; 15703 } 15704 15705 options[attr] = subject[attr]; 15706 } 15707 } 15708 15709 return options; 15710 }; 15711 15712 // Generate a list of translation options for default fallbacks. 15713 // `defaultValue` is also deleted from options as it is returned as part of 15714 // the translationOptions array. 15715 I18n.createTranslationOptions = function(scope, options) { 15716 var translationOptions = [{scope: scope}]; 15717 15718 // Defaults should be an array of hashes containing either 15719 // fallback scopes or messages 15720 if (isSet(options.defaults)) { 15721 translationOptions = translationOptions.concat(options.defaults); 15722 } 15723 15724 // Maintain support for defaultValue. Since it is always a message 15725 // insert it in to the translation options as such. 15726 if (isSet(options.defaultValue)) { 15727 translationOptions.push({ message: options.defaultValue }); 15728 } 15729 15730 return translationOptions; 15731 }; 15732 15733 // Translate the given scope with the provided options. 15734 I18n.translate = function(scope, options) { 15735 options = options || {}; 15736 15737 var translationOptions = this.createTranslationOptions(scope, options); 15738 15739 var translation; 15740 var usedScope = scope; 15741 15742 var optionsWithoutDefault = this.prepareOptions(options) 15743 delete optionsWithoutDefault.defaultValue 15744 15745 // Iterate through the translation options until a translation 15746 // or message is found. 15747 var translationFound = 15748 translationOptions.some(function(translationOption) { 15749 if (isSet(translationOption.scope)) { 15750 usedScope = translationOption.scope; 15751 translation = this.lookup(usedScope, optionsWithoutDefault); 15752 } else if (isSet(translationOption.message)) { 15753 translation = lazyEvaluate(translationOption.message, scope); 15754 } 15755 15756 if (translation !== undefined && translation !== null) { 15757 return true; 15758 } 15759 }, this); 15760 15761 if (!translationFound) { 15762 return this.missingTranslation(scope, options); 15763 } 15764 15765 if (typeof(translation) === "string") { 15766 translation = this.interpolate(translation, options); 15767 } else if (isArray(translation)) { 15768 translation = translation.map(function(t) { 15769 return (typeof(t) === "string" ? this.interpolate(t, options) : t); 15770 }, this); 15771 } else if (isObject(translation) && isSet(options.count)) { 15772 translation = this.pluralize(options.count, usedScope, options); 15773 } 15774 15775 return translation; 15776 }; 15777 15778 // This function interpolates the all variables in the given message. 15779 I18n.interpolate = function(message, options) { 15780 if (message == null) { 15781 return message; 15782 } 15783 15784 options = options || {}; 15785 var matches = message.match(this.placeholder) 15786 , placeholder 15787 , value 15788 , name 15789 , regex 15790 ; 15791 15792 if (!matches) { 15793 return message; 15794 } 15795 15796 while (matches.length) { 15797 placeholder = matches.shift(); 15798 name = placeholder.replace(this.placeholder, "$1"); 15799 15800 if (isSet(options[name])) { 15801 value = options[name].toString().replace(/\$/gm, "_#$#_"); 15802 } else if (name in options) { 15803 value = this.nullPlaceholder(placeholder, message, options); 15804 } else { 15805 value = this.missingPlaceholder(placeholder, message, options); 15806 } 15807 15808 regex = new RegExp(placeholder.replace(/{/gm, "\\{").replace(/}/gm, "\\}")); 15809 message = message.replace(regex, value); 15810 } 15811 15812 return message.replace(/_#\$#_/g, "$"); 15813 }; 15814 15815 // Pluralize the given scope using the `count` value. 15816 // The pluralized translation may have other placeholders, 15817 // which will be retrieved from `options`. 15818 I18n.pluralize = function(count, scope, options) { 15819 options = this.prepareOptions({count: String(count)}, options) 15820 var pluralizer, result; 15821 15822 result = this.pluralizationLookup(count, scope, options); 15823 if (typeof result.translations === "undefined" || result.translations == null) { 15824 return this.missingTranslation(scope, options); 15825 } 15826 15827 if (typeof result.message !== "undefined" && result.message != null) { 15828 return this.interpolate(result.message, options); 15829 } 15830 else { 15831 pluralizer = this.pluralization.get(options.locale); 15832 return this.missingTranslation(scope + '.' + pluralizer(count)[0], options); 15833 } 15834 }; 15835 15836 // Return a missing translation message for the given parameters. 15837 I18n.missingTranslation = function(scope, options) { 15838 //guess intended string 15839 if(this.missingBehaviour === 'guess'){ 15840 //get only the last portion of the scope 15841 var s = scope.split('.').slice(-1)[0]; 15842 //replace underscore with space && camelcase with space and lowercase letter 15843 return (this.missingTranslationPrefix.length > 0 ? this.missingTranslationPrefix : '') + 15844 s.replace(/_/g,' ').replace(/([a-z])([A-Z])/g, 15845 function(match, p1, p2) {return p1 + ' ' + p2.toLowerCase()} ); 15846 } 15847 15848 var localeForTranslation = (options != null && options.locale != null) ? options.locale : this.currentLocale(); 15849 var fullScope = this.getFullScope(scope, options); 15850 var fullScopeWithLocale = [localeForTranslation, fullScope].join(options.separator || this.defaultSeparator); 15851 15852 return '[missing "' + fullScopeWithLocale + '" translation]'; 15853 }; 15854 15855 // Return a missing placeholder message for given parameters 15856 I18n.missingPlaceholder = function(placeholder, message, options) { 15857 return "[missing " + placeholder + " value]"; 15858 }; 15859 15860 I18n.nullPlaceholder = function() { 15861 return I18n.missingPlaceholder.apply(I18n, arguments); 15862 }; 15863 15864 // Format number using localization rules. 15865 // The options will be retrieved from the `number.format` scope. 15866 // If this isn't present, then the following options will be used: 15867 // 15868 // - `precision`: `3` 15869 // - `separator`: `"."` 15870 // - `delimiter`: `","` 15871 // - `strip_insignificant_zeros`: `false` 15872 // 15873 // You can also override these options by providing the `options` argument. 15874 // 15875 I18n.toNumber = function(number, options) { 15876 options = this.prepareOptions( 15877 options 15878 , this.lookup("number.format") 15879 , NUMBER_FORMAT 15880 ); 15881 15882 var negative = number < 0 15883 , string = toFixed(Math.abs(number), options.precision).toString() 15884 , parts = string.split(".") 15885 , precision 15886 , buffer = [] 15887 , formattedNumber 15888 , format = options.format || "%n" 15889 , sign = negative ? "-" : "" 15890 ; 15891 15892 number = parts[0]; 15893 precision = parts[1]; 15894 15895 while (number.length > 0) { 15896 buffer.unshift(number.substr(Math.max(0, number.length - 3), 3)); 15897 number = number.substr(0, number.length -3); 15898 } 15899 15900 formattedNumber = buffer.join(options.delimiter); 15901 15902 if (options.strip_insignificant_zeros && precision) { 15903 precision = precision.replace(/0+$/, ""); 15904 } 15905 15906 if (options.precision > 0 && precision) { 15907 formattedNumber += options.separator + precision; 15908 } 15909 15910 if (options.sign_first) { 15911 format = "%s" + format; 15912 } 15913 else { 15914 format = format.replace("%n", "%s%n"); 15915 } 15916 15917 formattedNumber = format 15918 .replace("%u", options.unit) 15919 .replace("%n", formattedNumber) 15920 .replace("%s", sign) 15921 ; 15922 15923 return formattedNumber; 15924 }; 15925 15926 // Format currency with localization rules. 15927 // The options will be retrieved from the `number.currency.format` and 15928 // `number.format` scopes, in that order. 15929 // 15930 // Any missing option will be retrieved from the `I18n.toNumber` defaults and 15931 // the following options: 15932 // 15933 // - `unit`: `"$"` 15934 // - `precision`: `2` 15935 // - `format`: `"%u%n"` 15936 // - `delimiter`: `","` 15937 // - `separator`: `"."` 15938 // 15939 // You can also override these options by providing the `options` argument. 15940 // 15941 I18n.toCurrency = function(number, options) { 15942 options = this.prepareOptions( 15943 options 15944 , this.lookup("number.currency.format", options) 15945 , this.lookup("number.format", options) 15946 , CURRENCY_FORMAT 15947 ); 15948 15949 return this.toNumber(number, options); 15950 }; 15951 15952 // Localize several values. 15953 // You can provide the following scopes: `currency`, `number`, or `percentage`.
15954 // If you provide a scope that matches the `/^(date|time)/` regular expression 15955 // then the `value` will be converted by using the `I18n.toTime` function. 15956 // 15957 // It will default to the value's `toString` function. 15958 // 15959 I18n.localize = function(scope, value, options) { 15960 options || (options = {}); 15961 15962 switch (scope) { 15963 case "currency": 15964 return this.toCurrency(value, options); 15965 case "number": 15966 scope = this.lookup("number.format", options); 15967 return this.toNumber(value, scope); 15968 case "percentage": 15969 return this.toPercentage(value, options); 15970 default: 15971 var localizedValue; 15972 15973 if (scope.match(/^(date|time)/)) { 15974 localizedValue = this.toTime(scope, value, options); 15975 } else { 15976 localizedValue = value.toString(); 15977 } 15978 15979 return this.interpolate(localizedValue, options); 15980 } 15981 }; 15982 15983 // Parse a given `date` string into a JavaScript Date object. 15984 // This function is time zone aware. 15985 // 15986 // The following string formats are recognized: 15987 // 15988 // yyyy-mm-dd 15989 // yyyy-mm-dd[ T]hh:mm::ss 15990 // yyyy-mm-dd[ T]hh:mm::ss 15991 // yyyy-mm-dd[ T]hh:mm::ssZ 15992 // yyyy-mm-dd[ T]hh:mm::ss+0000 15993 // yyyy-mm-dd[ T]hh:mm::ss+00:00 15994 // yyyy-mm-dd[ T]hh:mm::ss.123Z 15995 // 15996 I18n.parseDate = function(date) { 15997 var matches, convertedDate, fraction; 15998 // A date input of `null` or `undefined` will be returned as-is 15999 if (date == null) { 16000 return date; 16001 } 16002 // we have a date, so just return it. 16003 if (typeof(date) === "object") { 16004 return date; 16005 } 16006 16007 matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/); 16008 16009 if (matches) { 16010 for (var i = 1; i <= 6; i++) { 16011 matches[i] = parseInt(matches[i], 10) || 0; 16012 } 16013 16014 // month starts on 0 16015 matches[2] -= 1; 16016 16017 fraction = matches[7] ? 1000 * ("0" + matches[7]) : null; 16018 16019 if (matches[8]) { 16020 convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction)); 16021 } else { 16022 convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction); 16023 } 16024 } else if (typeof(date) == "number") { 16025 // UNIX timestamp 16026 convertedDate = new Date(); 16027 convertedDate.setTime(date); 16028 } else if (date.match(/([A-Z][a-z]{2}) ([A-Z][a-z]{2}) (\d+) (\d+:\d+:\d+) ([+-]\d+) (\d+)/)) { 16029 // This format `Wed Jul 20 13:03:39 +0000 2011` is parsed by 16030 // webkit/firefox, but not by IE, so we must parse it manually. 16031 convertedDate = new Date(); 16032 convertedDate.setTime(Date.parse([ 16033 RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$6, RegExp.$4, RegExp.$5 16034 ].join(" "))); 16035 } else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) { 16036 // a valid javascript format with timezone info 16037 convertedDate = new Date(); 16038 convertedDate.setTime(Date.parse(date)); 16039 } else { 16040 // an arbitrary javascript string 16041 convertedDate = new Date(); 16042 convertedDate.setTime(Date.parse(date)); 16043 } 16044 16045 return convertedDate; 16046 }; 16047 16048 // Formats time according to the directives in the given format string. 16049 // The directives begins with a percent (%) character. Any text not listed as a 16050 // directive will be passed through to the output string. 16051 // 16052 // The accepted formats are: 16053 // 16054 // %a - The abbreviated weekday name (Sun) 16055 // %A - The full weekday name (Sunday) 16056 // %b - The abbreviated month name (Jan) 16057 // %B - The full month name (January) 16058 // %c - The preferred local date and time representation 16059 // %d - Day of the month (01..31) 16060 // %-d - Day of the month (1..31) 16061 // %H - Hour of the day, 24-hour clock (00..23) 16062 // %-H/%k - Hour of the day, 24-hour clock (0..23) 16063 // %I - Hour of the day, 12-hour clock (01..12) 16064 // %-I/%l - Hour of the day, 12-hour clock (1..12) 16065 // %m - Month of the year (01..12) 16066 // %-m - Month of the year (1..12) 16067 // %M - Minute of the hour (00..59) 16068 // %-M - Minute of the hour (0..59) 16069 // %p - Meridian indicator (AM or PM) 16070 // %P - Meridian indicator (am or pm) 16071 // %S - Second of the minute (00..60) 16072 // %-S - Second of the minute (0..60) 16073 // %w - Day of the week (Sunday is 0, 0..6) 16074 // %y - Year without a century (00..99) 16075 // %-y - Year without a century (0..99) 16076 // %Y - Year with century 16077 // %z/%Z - Timezone offset (+0545) 16078 // 16079 I18n.strftime = function(date, format, options) { 16080 var options = this.lookup("date", options) 16081 , meridianOptions = I18n.meridian() 16082 ; 16083 16084 if (!options) { 16085 options = {}; 16086 } 16087 16088 options = this.prepareOptions(options, DATE); 16089 16090 if (isNaN(date.getTime())) { 16091 throw new Error('I18n.strftime() requires a valid date object, but received an invali
16091d date.'); 16092 } 16093 16094 var weekDay = date.getDay() 16095 , day = date.getDate() 16096 , year = date.getFullYear() 16097 , month = date.getMonth() + 1 16098 , hour = date.getHours() 16099 , hour12 = hour 16100 , meridian = hour > 11 ? 1 : 0 16101 , secs = date.getSeconds() 16102 , mins = date.getMinutes() 16103 , offset = date.getTimezoneOffset() 16104 , absOffsetHours = Math.floor(Math.abs(offset / 60)) 16105 , absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60) 16106 , timezoneoffset = (offset > 0 ? "-" : "+") + 16107 (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) + 16108 (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes) 16109 ; 16110 16111 if (hour12 > 12) { 16112 hour12 = hour12 - 12; 16113 } else if (hour12 === 0) { 16114 hour12 = 12; 16115 } 16116 16117 format = format.replace("%a", options.abbr_day_names[weekDay]); 16118 format = format.replace("%A", options.day_names[weekDay]); 16119 format = format.replace("%b", options.abbr_month_names[month]); 16120 format = format.replace("%B", options.month_names[month]); 16121 format = format.replace("%d", padding(day)); 16122 format = format.replace("%e", day); 16123 format = format.replace("%-d", day); 16124 format = format.replace("%H", padding(hour)); 16125 format = format.replace("%-H", hour); 16126 format = format.replace("%k", hour); 16127 format = format.replace("%I", padding(hour12)); 16128 format = format.replace("%-I", hour12); 16129 format = format.replace("%l", hour12); 16130 format = format.replace("%m", padding(month)); 16131 format = format.replace("%-m", month); 16132 format = format.replace("%M", padding(mins)); 16133 format = format.replace("%-M", mins); 16134 format = format.replace("%p", meridianOptions[meridian]); 16135 format = format.replace("%P", meridianOptions[meridian].toLowerCase()); 16136 format = format.replace("%S", padding(secs)); 16137 format = format.replace("%-S", secs); 16138 format = format.replace("%w", weekDay); 16139 format = format.replace("%y", padding(year)); 16140 format = format.replace("%-y", padding(year).replace(/^0+/, "")); 16141 format = format.replace("%Y", year); 16142 format = format.replace("%z", timezoneoffset); 16143 format = format.replace("%Z", timezoneoffset); 16144 16145 return format; 16146 }; 16147 16148 // Convert the given dateString into a formatted date. 16149 I18n.toTime = function(scope, dateString, options) { 16150 var date = this.parseDate(dateString) 16151 , format = this.lookup(scope, options) 16152 ; 16153 16154 // A date input of `null` or `undefined` will be returned as-is 16155 if (date == null) { 16156 return date; 16157 } 16158 16159 var date_string = date.toString() 16160 if (date_string.match(/invalid/i)) { 16161 return date_string; 16162 } 16163 16164 if (!format) { 16165 return date_string; 16166 } 16167 16168 return this.strftime(date, format, options); 16169 }; 16170 16171 // Convert a number into a formatted percentage value. 16172 I18n.toPercentage = function(number, options) { 16173 options = this.prepareOptions( 16174 options 16175 , this.lookup("number.percentage.format", options) 16176 , this.lookup("number.format", options) 16177 , PERCENTAGE_FORMAT 16178 ); 16179 16180 return this.toNumber(number, options); 16181 }; 16182 16183 // Convert a number into a readable size representation. 16184 I18n.toHumanSize = function(number, options) { 16185 var kb = 1024 16186 , size = number 16187 , iterations = 0 16188 , unit 16189 , precision 16190 , fullScope 16191 ; 16192 16193 while (size >= kb && iterations < 4) { 16194 size = size / kb; 16195 iterations += 1; 16196 } 16197 16198 if (iterations === 0) { 16199 fullScope = this.getFullScope("number.human.storage_units.units.byte", options); 16200 unit = this.t(fullScope, {count: size}); 16201 precision = 0; 16202 } else { 16203 fullScope = this.getFullScope("number.human.storage_units.units." + SIZE_UNITS[iterations], options); 16204 unit = this.t(fullScope); 16205 precision = (size - Math.floor(size) === 0) ? 0 : 1; 16206 } 16207 16208 options = this.prepareOptions( 16209 options 16210 , {unit: unit, precision: precision, format: "%n%u", delimiter: ""} 16211 ); 16212 16213 return this.toNumber(size, options); 16214 }; 16215 16216 I18n.getFullScope = function(scope, options) { 16217 options = options || {}; 16218 16219 // Deal with the scope as an array.
16220 if (isArray(scope)) { 16221 scope = scope.join(options.separator || this.defaultSeparator); 16222 } 16223 16224 // Deal with the scope option provided through the second argument. 16225 // 16226 // I18n.t('hello', {scope: 'greetings'}); 16227 // 16228 if (options.scope) { 16229 scope = [options.scope, scope].join(options.separator || this.defaultSeparator); 16230 } 16231 16232 return scope; 16233 }; 16234 /** 16235 * Merge obj1 with obj2 (shallow merge), without modifying inputs 16236 * @param {Object} obj1 16237 * @param {Object} obj2 16238 * @returns {Object} Merged values of obj1 and obj2 16239 * 16240 * In order to support ES3, `Object.prototype.hasOwnProperty.call` is used 16241 * Idea is from: 16242 * https://stackoverflow.com/questions/8157700/object-has-no-hasownproperty-method-i-e-its-undefined-ie8 16243 */ 16244 I18n.extend = function ( obj1, obj2 ) { 16245 if (typeof(obj1) === "undefined" && typeof(obj2) === "undefined") { 16246 return {}; 16247 } 16248 return merge(obj1, obj2); 16249 }; 16250 16251 // Set aliases, so we can save some typing. 16252 I18n.t = I18n.translate.bind(I18n); 16253 I18n.l = I18n.localize.bind(I18n); 16254 I18n.p = I18n.pluralize.bind(I18n); 16255 16256 return I18n; 16257})); 16258// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf 16259if (!Array.prototype.indexOf) { 16260 Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { 16261 "use strict"; 16262 if (this == null) { 16263 throw new TypeError(); 16264 } 16265 var t = Object(this); 16266 var len = t.length >>> 0; 16267 if (len === 0) { 16268 return -1; 16269 } 16270 var n = 0; 16271 if (arguments.length > 1) { 16272 n = Number(arguments[1]); 16273 if (n != n) { // shortcut for verifying if it's NaN 16274 n = 0; 16275 } else if (n != 0 && n != Infinity && n != -Infinity) { 16276 n = (n > 0 || -1) * Math.floor(Math.abs(n)); 16277 } 16278 } 16279 if (n >= len) { 16280 return -1; 16281 } 16282 var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); 16283 for (; k < len; k++) { 16284 if (k in t && t[k] === searchElement) { 16285 return k; 16286 } 16287 } 16288 return -1; 16289 } 16290} 16291 16292// Production steps of ECMA-262, Edition 5, 15.4.4.18 16293// Reference: https://es5.github.com/#x15.4.4.18 16294// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach 16295if ( !Array.prototype.forEach ) { 16296 16297 Array.prototype.forEach = function forEach( callback, thisArg ) { 16298 16299 var T, k; 16300 16301 if ( this == null ) { 16302 throw new TypeError( "this is null or not defined" ); 16303 } 16304 16305 // 1. Let O be the result of calling ToObject passing the |this| value as the argument. 16306 var O = Object(this); 16307 16308 // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". 16309 // 3. Let len be ToUint32(lenValue). 16310 var len = O.length >>> 0; // Hack to convert O.length to a UInt32 16311 16312 // 4. If IsCallable(callback) is false, throw a TypeError exception. 16313 // See: https://es5.github.com/#x9.11 16314 if ( {}.toString.call(callback) !== "[object Function]" ) { 16315 throw new TypeError( callback + " is not a function" ); 16316 } 16317 16318 // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. 16319 if ( thisArg ) { 16320 T = thisArg; 16321 } 16322 16323 // 6. Let k be 0 16324 k = 0; 16325 16326 // 7. Repeat, while k < len 16327 while( k < len ) { 16328 16329 var kValue; 16330 16331 // a. Let Pk be ToString(k). 16332 // This is implicit for LHS operands of the in operator 16333 // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. 16334 // This step can be combined with c 16335 // c. If kPresent is true, then 16336 if ( Object.prototype.hasOwnProperty.call(O, k) ) { 16337 16338 // i. Let kValue be the result of calling the Get internal method of O with argument Pk. 16339 kValue = O[ k ]; 16340 16341 // ii. Call the Call internal method of callback with T as the this value and 16342 // argument list containing kValue, k, and O. 16343 callback.call( T, kValue, k, O ); 16344 } 16345 // d. Increase k by 1. 16346 k++; 16347 } 16348 // 8. return undefined 16349 }; 16350} 16351 16352// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some 16353if (!Array.prototype.some) 16354{ 16355 Array.prototype.some = function(fun /*, thisArg */) 16356 { 16357 'use strict'; 16358 16359 if (this === void 0 || this === null) 16360 throw new TypeError(); 16361 16362 var t = Object(this); 16363 var len = t.length >>> 0; 16364 if (typeof fun !== 'function') 16365 throw new TypeError(); 16366 16367 var thisArg = arguments.length >= 2 ? arguments[1] : void 0; 16368 for (var i = 0; i < len; i++) 16369 { 16370 if (i in t && fun.call(thisArg, t[i], i, t)) 16371 return true; 16372 } 16373 16374 return false;
16375 }; 16376} 16377 16378// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map 16379if (!Array.prototype.map) { 16380 16381 Array.prototype.map = function(callback/*, thisArg*/) { 16382 16383 var T, A, k; 16384 16385 if (this == null) { 16386 throw new TypeError('this is null or not defined'); 16387 } 16388 16389 // 1. Let O be the result of calling ToObject passing the |this| 16390 // value as the argument. 16391 var O = Object(this); 16392 16393 // 2. Let lenValue be the result of calling the Get internal 16394 // method of O with the argument "length". 16395 // 3. Let len be ToUint32(lenValue). 16396 var len = O.length >>> 0; 16397 16398 // 4. If IsCallable(callback) is false, throw a TypeError exception. 16399 // See: https://es5.github.com/#x9.11 16400 if (typeof callback !== 'function') { 16401 throw new TypeError(callback + ' is not a function'); 16402 } 16403 16404 // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. 16405 if (arguments.length > 1) { 16406 T = arguments[1]; 16407 } 16408 16409 // 6. Let A be a new array created as if by the expression new Array(len) 16410 // where Array is the standard built-in constructor with that name and 16411 // len is the value of len. 16412 A = new Array(len); 16413 16414 // 7. Let k be 0 16415 k = 0; 16416 16417 // 8. Repeat, while k < len 16418 while (k < len) { 16419 16420 var kValue, mappedValue; 16421 16422 // a. Let Pk be ToString(k). 16423 // This is implicit for LHS operands of the in operator 16424 // b. Let kPresent be the result of calling the HasProperty internal 16425 // method of O with argument Pk. 16426 // This step can be combined with c 16427 // c. If kPresent is true, then 16428 if (k in O) { 16429 16430 // i. Let kValue be the result of calling the Get internal 16431 // method of O with argument Pk. 16432 kValue = O[k]; 16433 16434 // ii. Let mappedValue be the result of calling the Call internal 16435 // method of callback with T as the this value and argument 16436 // list containing kValue, k, and O. 16437 mappedValue = callback.call(T, kValue, k, O); 16438 16439 // iii. Call the DefineOwnProperty internal method of A with arguments 16440 // Pk, Property Descriptor 16441 // { Value: mappedValue, 16442 // Writable: true, 16443 // Enumerable: true, 16444 // Configurable: true }, 16445 // and false. 16446 16447 // In browsers that support Object.defineProperty, use the following: 16448 // Object.defineProperty(A, k, { 16449 // value: mappedValue, 16450 // writable: true, 16451 // enumerable: true, 16452 // configurable: true 16453 // }); 16454 16455 // For best browser support, use the following: 16456 A[k] = mappedValue; 16457 } 16458 // d. Increase k by 1. 16459 k++; 16460 } 16461 16462 // 9. return A 16463 return A; 16464 }; 16465} 16466 16467// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind 16468if (!Function.prototype.bind) (function(){ 16469 var ArrayPrototypeSlice = Array.prototype.slice; 16470 Function.prototype.bind = function(otherThis) { 16471 if (typeof this !== 'function') { 16472 // closest thing possible to the ECMAScript 5 16473 // internal IsCallable function 16474 throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); 16475 } 16476 16477 var baseArgs= ArrayPrototypeSlice .call(arguments, 1), 16478 baseArgsLength = baseArgs.length, 16479 fToBind = this, 16480 fNOP = function() {}, 16481 fBound = function() { 16482 baseArgs.length = baseArgsLength; // reset to default base arguments 16483 baseArgs.push.apply(baseArgs, arguments); 16484 return fToBind.apply( 16485 fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs 16486 ); 16487 }; 16488 16489 if (this.prototype) { 16490 // Function.prototype doesn't have a prototype property 16491 fNOP.prototype = this.prototype; 16492 } 16493 fBound.prototype = new fNOP(); 16494 16495 return fBound; 16496 }; 16497})(); 16498 16499// Using UMD pattern from 16500// https://github.com/umdjs/umd#regular-module 16501// `returnExports.js` version 16502;(function (root, factory) { 16503 if (typeof define === 'function' && define.amd) { 16504 // AMD. Register as an anonymous module. 16505 define(["i18n"], factory); 16506 } else if (typeof module === 'object' && module.exports) { 16507 // Node. Does not work with strict CommonJS, but 16508 // only CommonJS-like environments that support module.exports, 16509 // like Node. 16510 factory(require("i18n")); 16511 } else { 16512 // Browser globals (root is window) 16513 factory(root.I18n); 16514 } 16515}(this, function(I18n) { 16516 "use strict"; 16517 16518 I18n.translations = {"de":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"Erwachsene oder gewalttätige Inhalte","ai_generated":"KI-generierte Inhalte","copyright":"Copyright-Verletzung"}}},"errors":{"messages":{"embedded_script":"Diese Datei wird nicht unterstützt und kann nicht hochgeladen werden. Bitte versuche eine andere Datei."}}},"api":{"profile":{"actions":{"contact":"Kontakt","follow":"Folgen","follow_tooltip":"Folgen Sie diesem Designer, um über seine Inhalte informiert zu werden und Lieblingsdesigner leichter in den Suchergebnissen zu filtern.","hide":"Ausblenden","hire_me":"Stellen Sie mich ein","invite_client":"Projekt starten","mute_tooltip":"Blenden Sie die Modelle dieses Designers in de
16518n Suchergebnissen aus.","take_over":"Ãbernehmen","unfollow":"Entfolgen","unhide":"Einblenden","view_all_models":"Alle Modelle des Designers ansehen"},"private_project_review":"Privates Projekt"}},"browser":{"3d_models":"3D Modelle","3d_print":"3D Druck","active_filters":{"polygons":"%{range} Polygonen"},"adult_content":"Anzeigen Alter +","animated":"animierte","breadcrumb":{"browse_by_type":"Nach Typ durchsuchen","collection":"3D-Pakete","free":"frei","free_models":"Kostenlose 3D Modelle","free_print_models":"Kostenlose 3D-Drucken Modelle","low_poly":"Low-poly","low_poly_models":"VR / AR / Low-Poly 3D Modelle","low_poly_print_models":"Low-Poly 3D-Druckdateien","model_3d":"3D-Modell","model_3dp":"3D Druck modell","models":"3D Modelle","models_3d":"3D Modelle","models_3dp":"3D Druck modelle","models_variant_0":"3D-Modelle","models_variant_1":"3D-Assets","models_variant_2":"VR-Modelle","models_variant_3":"CG-Modelle","models_variant_4":"3D-Modellshop","models_variant_5":"3D-Objekte","print_models":"3D-Druckdateien","print_models_variant_0":"3D-Druckmodelle","print_models_variant_1":"3D-Druckermodell","print_models_variant_10":"3D-Modelle zum Drucken","print_models_variant_11":"3D-Modelle zum Ausdrucken","print_models_variant_12":"3D-Dateien für den Druck","print_models_variant_13":"Modelle für 3D-Drucker","print_models_variant_14":"Modelle für den 3D-Druck","print_models_variant_15":"3D-Druckmodelle","print_models_variant_16":"Druckbare 3D-Dateien","print_models_variant_2":"3D-Modelle zum Drucken","print_models_variant_3":"3D-Druckmodelle","print_models_variant_4":"3D-Druckdateien","print_models_variant_5":"3D-Druckdateien","print_models_variant_6":"3D-Druckerdateien","print_models_variant_7":"Druckbare 3D-Modelle","print_models_variant_8":"Druckbare 3D-Modelle","print_models_variant_9":"Gedruckte 3D-Modelle"},"buyer_engagement_program":"Rabatte","categories":"Kategorien","category":{"meta":{"3d_models":"%{count} %{category} 3D Modelle zum Download zur Verfügung in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download %{count} %{category} 3D Druck Modelle, zum Herunterladen in STL, OBJ und anderen Dateiformaten für das Drucken mit FDM, SLS und anderem 3D Drucker .%{page}","animated_3d_models":"%{count} %{category} 3D Modelle zum Download in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page} verfügbar animiert","free_3d_models":"Herunterladen %{count} %{category} kostenlose 3D Modelle, erhältlich in MAX, OBJ, FBX, 3DS, C4D Dateiformate, bereit für VR / AR, Animation, Spiele und andere 3D-Projekte.%{page}","free_3d_print_models":"Herunterladen %{count} %{category} kostenlos 3D Druck-Modelle bereit für FDM, SLA, SLS und anderen 3D Drucker , verfügbare Formate STL, OBJ, 3DM und vieles mehr.%{page}","lowpoly_3d_models":"Download %{count} VR / AR / Low-Poly-%{category} 3D Modelle bereit für die Virtual Reality, Spiele und andere Echtzeit-Anwendungen, in FBX, OBJ, MAX, 3DS, C4D-Dateiformaten.%{page}","rigged_3d_models":"%{count} %{category} 3D Modelle zum Download in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page} verfügbar in Ordnung gebracht"}},"collection":"3D-Paket","discounts":"Rabatte","ext":{"meta":{"3d_models":"%{rounded_count} 3D-Modelle im %{format_upper}-Format herunterladen. Kostenlose und Premium-%{format_lower}-Dateien.","3d_print_models":"Herunterladen %{count} %{ext} Dateien - %{software_name} 3D Druck Modelle bereit für VR / AR, 3D-Design, Animation, Spiele und Echtzeit-Anwendungen %{page}."}},"filter":"Filter","filter_button":"Filter anwenden","filters":{"adult_content_only":"Nur Inhalte für Erwachsene","cgt_standard_only":"CGT-Standard","collections_only":"Nur Pakete","content_filters":"Inhaltsfilter","designer":"Designer","exclude_3d_print":"3D-Druck ausschlieÃen","exclude_adult_content":"Inhalte für Erwachsene ausschlieÃen","exclude_ai_generated":"KI-generierte Inhalte ausschlieÃen","exclude_editorial_license":"Redaktionelle Lizenz ausschlieÃen","exclude_free":"Kostenlose ausschlieÃen","file_format":"Dateiformate","following":"Gefolgt","free":"Kostenlos","has_marmoset":"Mit 3D-Viewer","has_video":"Mit Video","include_ai_generated":"KI-generierte Inhalte einbeziehen","label":"Filter","poly_count":"Polygonanzahl","print_ready":"3D-Druck","stl_files":"STL-Dateien","subscription":"Abonnement","type":"Typ"},"formats":"Formate","free":"Frei","free_models":"Gratis-Models Nur","free_to_premium":{"main":"%{category} 3D-Modelle","postfix":"in der Premium-Liste.","prefix":"Benötigen Sie etwas Besonderes? Sie können bessere Qualität finden"},"gallery":{"preview":"Vorschau"},"game_ready":"Spiel bereit","high_poly":"High-Poly","items_page_title":"3D Modelle","license":{"exclude_branded":"AusschlieÃen Marken","exclude_editorial":"Editorial ausschlieÃen","prompt":"Lizenz","tooltip_more":"Weiterlesen","tooltip_text":" nicht zeigen Modelle, die nur in nicht-kommerziellen, pädagogische Zwecke genutzt werden können.","tooltip_title":"Editorial ausschlieÃen:"},"low-poly":"Low-Poly","low_poly":"Low-poly","meta":{"3d_models":"Ãber %{rounded_count} professionelle 3D-Modelle herunterladen oder kaufen. Kostenlose und Premium-3D-Assets für Games, Film, VFX und 3D-Druck. FBX, OBJ, BLEND, GLB u.v.m.","3d_print_models":"Ãber %{rounded_count} 3D-Druck-Vorlagen herunterladen. Kostenlose und Premium-STL-Dateien für den 3D-Drucker: Figuren, Miniaturen, Deko, Werkzeug und mehr.","animated_3d_models":"%{rounded_count} animierte 3D-Modelle mit Animationen herunterladen. Game-ready Charaktere, Tiere und Objekte in FBX, BLEND, GLB.","free_3d_models":"%{rounded_count} kostenlose 3D-Modelle zum Herunterladen. Lizenzfreie 3D-Objekte und Assets in FBX, OBJ, BLEND, GLB â für Games, Film und AR/VR.","free_3d_print_models":"%{rounded_count}
16518 kostenlose 3D-Drucker-Vorlagen. Gratis STL-Dateien und 3D-Druck-Modelle zum Downloaden.","lowpoly_3d_models":"%{rounded_count} Low-Poly-3D-Modelle für Games, AR/VR und Echtzeit-Rendering herunterladen. Kostenlos und Premium, game-ready.","metaverse":"Geben Sie die Metaverse mit unserer Sammlung von 3D-Modellen mit hohem und niedrigem Poly ein, animiert und verfügbare Dateiformat.","omniverse":"Bauen Sie Ihre virtuelle Welt mit unseren Omniverse-fähigen 3D-Modellen auf. Wählen Sie aus animierten, manipulierten und PBR -Modellen mit hoher und niedriger Polygonzahl.","page_prefix":"Page %{page_number} mit","pbr_3d_models":"%{rounded_count} PBR-3D-Modelle mit physikalisch basierten Texturen. Game-ready Assets für Unity, Unreal und Echtzeit-Engines.","rigged_3d_models":"%{rounded_count} geriggte 3D-Modelle mit Skelett/Bones, bereit zur Animation. Für Blender, Maya, 3ds Max, Unity und Unreal.","snap-ar":"Mit unseren 3D -Modellen können Sie Millionen von Snapchatters verwenden, um Snap AR zu erstellen, um unterhaltsame Augmented Reality -Erlebnisse zu schaffen.","spark-ar":"Erhellen Sie Ihr Facebook und Ihr Instagram mit einer Vielzahl von Funken -AR -3D -Modellen, die manipuliert, animiert und verwendet werden können.","stream_3d_print_models":"Blättern Sie durch eine Vielzahl von Strom Kategorien 3D Druck modell einige der auÃergewöhnlichsten 3D druckbare Motive von professionellen 3D-Schöpfer zu entdecken.","textures":"%{count} Textures 3D-Assets und Materialien zum Download in verschiedenen Formaten, einschlieÃlich .tga .sbsar .jpeg .png tiff und andere. %{page}","tiktok":"Machen Sie Ihre Videoeffekte mit Tiktok 3D -Modellen beeindruckender. Unsere Bibliothek kann alle Ihre kreativen Bedürfnisse erfüllen und wird ständig aktualisiert.","unity":"Finden Sie 3D -Modelle für Ihr Unity -Projekt in jedem Dateiformat und jeder Poly -Anzahl. Alles, was Sie brauchen, um eine einzigartige virtuelle Umgebung zu schaffen.","unreal":"Erstellen Sie beeindruckende Visualisierungen mit unwirklichen Engine -kompatiblen 3D -Modellen in jedem Dateiformat. Unsere Bibliothek verfügt über niedrig- und hochpoly-Modelle aus jeder Kategorie."},"optimized":"Low-Poly / PBR","page_title":{"animated_3d_models":"Animierte 3D-Modelle â Kostenlos \u0026 Premium","format_page":"%{format_upper} 3D-Modelle â %{format_lower}-Dateien kostenlos \u0026 Premium","free_3d_models":"Kostenlose 3D-Modelle herunterladen â %{rounded_count} Modelle","free_3d_print_models":"Kostenlose 3D-Druck Vorlagen â Gratis STL-Dateien","lowpoly_3d_models":"Low Poly 3D-Modelle â Kostenlos \u0026 Premium","pbr_3d_models":"PBR 3D-Modelle â Kostenlos \u0026 Premium","rigged_3d_models":"Rigged 3D-Modelle â Kostenlos \u0026 Premium herunterladen","software_page":"%{software} 3D-Modelle â %{ext_file}-Dateien herunterladen","tag":{"3d_merged_premium":"%{tag_cap} 3D-Modelle â Kostenlose \u0026 Premium-Downloads","3d_merged_premium_print":"%{tag_cap} STL-Dateien â 3D-Druck Vorlagen","3d_models":"%{tag_cap} 3D-Modelle â Kostenlose \u0026 Premium-Downloads","3d_print_models":"%{tag_cap} STL-Dateien â 3D-Druck Vorlagen"}},"pbr":"PBR","per_page":"Pro Seite","polygons_options":{"custom":"Benutzerdefinierten Bereich","gt_250k":"250k +","lt_5k":"Bis zu 5k","more_than_250000":"250K+","prompt":"Poly Graf","range_0_5000":"Bis zu 5K","range_100000_250000":"100 - 250K","range_10000_50000":"10 - 50K","range_100k_250k":"100k bis 250k","range_10k_50k":"10k auf 50k","range_50000_100000":"50 - 100K","range_5000_10000":"5 - 10K","range_50k_100k":"50k auf 100k","range_5k_10k":"5k bis 10k"},"price":"Preis: $%{from}-%{to}","price_range":"Preis","print_ready":"3D Druck bereit","reset_button":"Filter zurücksetzen","rigged":"Manipulierten","rounded_count":{"delimiter":".","exact":"%{n}","million":"%{n} Mio.","separator":",","thousand":"%{n}+"},"sale_off":"Im Angebot","search_placeholder":"Suche Schlüsselwörter","show_all_formats":"Alle Formate","simulation_ready":"Simulationsbereit","software":{"meta":{"3d_models":"%{rounded_count} 3D-Modelle für %{software} herunterladen. Kostenlose und Premium-%{ext_file}-Dateien, direkt importierbar."}},"sort_by":"Sortiere nach","sort_by_options":{"best_match":"Bester Treffer","highest_price":"Höherer Preis","lowest_price":"Niedrigerer Preis","newest":"Neueste","oldest":"Ãlteste","sales":"Meistverkauft","trending":"Trending"},"subcategory":{"meta":{"3d_models":"%{count} %{category} 3D Modelle zum Download zur Verfügung in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download %{count} %{category} 3D Druck Modelle, zum Herunterladen in STL, OBJ und anderen Dateiformaten für das Drucken mit FDM, SLS und anderem 3D Drucker .%{page}","animated_3d_models":"%{count} %{category} 3D Modelle zum Download in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page} verfügbar animiert","free_3d_models":"Herunterladen %{count} %{category} kostenlose 3D Modelle, erhältlich in MAX, OBJ, FBX, 3DS, C4D Dateiformate, bereit für VR / AR, Animation, Spiele und andere 3D-Projekte.%{page}","free_3d_print_models":"Herunterladen %{count} %{category} kostenlos 3D Druck-Modelle bereit für FDM, SLA, SLS und anderen 3D Drucker , verfügbare Formate STL, OBJ, 3DM und vieles mehr.%{page}","lowpoly_3d_models":"Laden Sie VR / AR / Low Poly %{tag} 3D Modelle bereit für die Virtual Reality, Spiele und andere Echtzeit-Anwendungen, in FBX, OBJ, MAX, 3DS, C4D-Dateiformaten.%{page}","rigged_3d_models":"%{count} %{category} 3D Modelle zum Download in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page} verfügbar in Ordnung gebracht"}}
16518,"subtitle":{"aircraft":"%{count} Flugzeuge 3D Modelle stehen zum Download auf unserem Marktplatz zur Verfügung. CG %{airplanes_link} passt in Simulationen, Visualisierungen, Anzeigen und Videos. %{drone_link} Körper und Teile werden die Fans von kleinen fliegenden Fahrzeuge erfreuen. Und das %{rigged_link} Modelle sind bereit, in der Game-Engines importiert werden und für die Animation oder VR / AR-Projekte verwendet werden. Fliegen Spiele, Simulatoren und Videos sowohl regelmäÃiger CG und Low-Poly-Typen können mit 3D Modellen in den meisten gängigen Formaten wie FBX, OBJ, MAX, 3DS, C4D gefüllt werden.","animals":"%{count} von CG 3D-Tiere - %{cats_link} %{horses_link} %{bears_link} %{rhinos_link} %{eagles_link} %{lions_link}, fiktiv %{dragons_link} und mehr - sind hier verfügbar zum Download bereit. Die Sammlung von 3D-Fauna wird auf die Bedürfnisse von Werbeanzeigen oder statischer Szenen befriedigen. Wir haben auch %{rigged_link} Modelle für Spiele, Animation, Videoproduktion und VR / AR-Projekte. Verwenden Sie Filter in den meisten Industrie akzeptierten Dateiformate in Ordnung gebracht, animiert, Low-Poly oder freie 3D Modelle zu finden, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D und andere.","animated":"Laden Sie %{rounded_count} animierte 3D-Modelle mit fertigen Bewegungsabläufen herunter â Charaktere, Tiere und Objekte für Games, Film und Echtzeit-Projekte.","architectural":"%{count} von architektonischen 3D Modelle zum Download zur Verfügung enthält Elemente und Details der Architektur, Konstruktion und Engineering-Design. Zum Kauf oder ein kostenloses 3D-Modell herunterladen, durchsuchen Sie die Kategorien oben. Sie können Modelle für Animationen oder Spiele verwenden - einige von ihnen sind in Ordnung gebracht und Low-Poly-VR / AR Projektanforderungen zu dienen. 3D Modelle sind in Dateiformate wie FBX, OBJ, MAX, 3DS, C4D verfügbar.","car":"%{count} Auto 3D Modelle zum Download zur Verfügung. Low-Poly-Versionen von denen zu Game-Designer oder VR / AR-Anwendungen Entwickler, andere attraktiv sein - zu Filmemachern, Animateure oder Werbetreibende. Von klassischen und antiken Autos auf das Rennen und Konzept diejenigen in Filmen zu sehen, gibt es eine groÃe Auswahl an 3D-Auto-Modelle im Wesentlichen jedes Format (FBX, OBJ, MAX, 3DS, C4D, etc.) Sie benötigen. Verwenden Sie animierte und kostenlose 3D Modelle Prototyp und shorten Entwicklungszeit.","character":"%{count} Zeichen 3D Modelle zum Download zur Verfügung, so dass diese Kategorie Surfen Sie 3D Modelle von %{human_link} finden, Menschen, mythische Figuren, Science-Fiction %{robots_link}, Kleidung und andere zu Zeichen bezogene Dinge. Von %{heart_link} und %{hand_link}, um detaillierte realistisches %{male_link} oder %{female_link} Modellen. Einige der Modelle sind in Ordnung gebracht und leicht zu Ihrem Spiel, VR / AR-Projekt, Video oder Animation hinzugefügt werden könnten. Sowohl hohe und niedrige Poly Poly Modelle können in einer Reihe von Formaten, einschlieÃlich FBX, OBJ, MAX, 3DS, C4d finden.","custom":"Hier können Sie kostenlos %{tag} 3D Modelle kaufen oder herunterladen. %{tag_heading_subtitle}","electronics":"%{count} Elektronik 3D Modelle zum Download zur Verfügung. Dies ist eine Kategorie für Architekten, Innenarchitekten, Level-Designer, Szene Entscheidungsträgern und anderen Kreativen. 3D Modelle von%{smartphones_link}, %{laptops_link}, %{cameras_link}, %{tvs_link} und wird dazu beitragen, genau das moderne Leben Besessenheit mit Geräten und Technologie zu erfassen. Es gibt 3D Modelle in Dateiformate wie FBX, OBJ, MAX, 3DS, C4D. Laden Sie kostenlos oder kaufen Premium-Modelle und die Nutzung für Animation, Spiele und VR / AR-Projekte.","exterior":"%{count} von architektonischen AuÃen 3D Modelle zum Download zur Verfügung Bereich von Fassaden, städtische Gebäude, Landschaftsobjekte, Wohnhäuser zu Industriebauten, Infrastrukturbauten und Skalenendwertkontrolle %{city_link} Modelle. Zum Kauf oder ein kostenloses 3D-Modell herunterladen, durchsuchen Sie die Kategorien oben. Verwenden Sie Filter in Ordnung gebracht zu finden, animiert, Low-Poly, freie 3D Modelle oder sortieren nach Format benötigt, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D. Einige der Vermögenswerte sind Low-Poly und könnten Sie die Umwelt in Ihrem Spiel oder VR / AR-Anwendung helfen abzuschlieÃen.","food":"%{count} Lebensmittel 3D Modelle sind für download..Food dient auch realistische Szenen des häuslichen Lebens zu schaffen. 3D-Obst, Gemüse, Getränke und Speisen sind alle hier, um die komplette Werbung für Restaurants, AR-Anwendungen für gesündere Ernährung und Visualisierungen Architekten und Innenarchitekten arbeiten. Ob Sie sich für 3D suchen %{pizza_link} und %{ketchup_link} Modelle oder ein 3D-Modell einer Hochzeit %{cake_link}, sind sie hier. Eine Reihe von Low-Poly-Versionen sind für die im Spiel, VR / AR-Entwicklung zur Verfügung. 3D Modelle können in FBX, OBJ, MAX, 3DS, C4D Formaten zu finden.","formats":"Laden Sie %{rounded_count} 3D-Modelle im %{format_upper}
16518-Format herunter â kostenlos und Premium. Jede Datei auf dieser Seite ist nativ als %{format_upper} verfügbar, ohne Konvertierung nutzbar.","free_general":"Laden Sie %{rounded_count} kostenlose 3D-Modelle herunter â 3D-Modelle kostenlos für private und kommerzielle Projekte. Gratis 3D-Objekte in FBX, OBJ, BLEND und GLB, ohne versteckte Kosten.","free_no_tag":"%{model_count} kostenlose 3D %{tag} Modelle bereit für 3D Druck. Download %{tag} freie 3D Druck modelle, Dateiformate zur Verfügung, einschlieÃlich STL, OBJ, 3DM, 3DS, MAX. 3D Modelle sind bereit, mit FDM, SLA, SLS und anderen Arten von 3D-Druckern verwendet werden.","free_printable":"Ãber %{rounded_count} kostenlose 3D-Druck-Vorlagen zum Herunterladen: gratis STL-Dateien und 3D-Druckvorlagen für Ihren 3D-Drucker â von der Community getestet, von Deko bis Werkstatt-Helfern.","free_tag":"Free 3D %{tag} Modelle zum Download zur Verfügung. Erhältlich in vielen Dateiformaten wie MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB. Finden Sie professionelles %{tag_link} für alle 3D-Design-Projekte wie Virtual Reality (VR), Augmented Reality (AR), Spiele, 3D-Visualisierung oder Animation.","furniture":"%{count} Möbel 3D Modelle zum Download zur Verfügung gehören Tische, Stühle, Sofas, Betten und andere Möbel in einer Vielzahl von Texturen (Holz, Metall, etc.) und Arten (%{retro_link}, %{modern_link} usw. ). Diese Kategorie ist für jedermann mit Architektur und Innenarchitektur sowie Werbetreibende und Animateure beteiligt gemeint. Echtzeit-Assets können Spiel und VR / AR-Anwendungsentwickler zu kompletten Projekten helfen. Verwenden Sie Filter in Ordnung gebracht, animiert, Low-Poly oder freie 3D Modelle zu finden. Erhältlich in jedem Dateiformat einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.","general":"Entdecken Sie über %{rounded_count} professionelle 3D-Modelle für Games, Film, VFX, AR/VR und 3D-Druck. 3D-Objekte und 3D-Dateien kostenlos herunterladen oder als Premium-Modelle kaufen â in FBX, OBJ, BLEND, GLB und über 100 weiteren Formaten.","high_poly":"Kaufen oder herunterladen Animated Professionelle 3D Modelle bereit, in CG-Projekten verwendet werden, Film- und Videoproduktion, Animation, Visualisierung und andere. Vermögenswerte sind zum Download in vielen branchenüblichen Formaten, einschlieÃlich MAX, OBJ, FBX, 3DS, UE4 und andere zur Verfügung. Wenn Sie auf der Suche nach High-Poly-Qualität 3D-Assets sind, dann haben wir eine führende digitale Kunstbibliothek für alle Ihre Bedürfnisse.\n","household":"%{count} Haushalt 3D Modelle zum Download zur Verfügung können verwendet werden, um Details zu den Zimmern zu geben. Vielleicht haben Sie ein Abendessen auf dem Tisch setzen wollen, Pfeffer und Salz Container komplette Küche Interieur haben oder etwas setzen {lights_link} und %{flowers_link} neben dem Bett luxuriöse Atmosphäre zu schaffen. Wenn Sie ein Innenarchitekt, Animator, VR / AR-Anwendung oder Spiel Schöpfer sind, ist diese Kategorie für Sie. Verwenden Sie Filter in Ordnung gebracht, animiert, Low-Poly oder freie 3D Modelle zu finden. Erhältlich in jedem Dateiformat einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.","industrial":"%{count} industrielle 3D Modelle zum Download zur Verfügung - Baumaterialien, %{engineering_link} Werkzeuge, Maschinen und %{containers_link} - wird beiden Details liefern und interaktive, manipulierten Elemente lebendigere Umgebungen zu schaffen. Dies ist eine perfekte Kategorie für Simulationen / VR / AR oder Entwickler des Aufbau %{construction_link} Site-Ebene im Spiel. Die 3D Modelle werden Baufachleute präzise Visualisierung arbeiten mit unterschiedlicher Software dienen als Modelle in Formaten wie FBX, OBJ, MAX, 3DS, C4D verfügbar sind.","interior":"%{count} Interieur 3D Modelle zum Download zur Verfügung und beinhalten Elemente und in der Architektur, Konstruktion und Engineering, Innenarchitektur verwendeten Details. Zum Kauf Prämie oder ein kostenloses 3D-Modell herunterladen, durchsuchen Sie die oben genannten Kategorien. Sie Modelle für Animationen oder Spiele nutzen können - einige von ihnen sind in Ordnung gebracht, animiert und Low-Poly. Erhältlich in einer Vielzahl von Dateiformaten, darunter FBX, OBJ, MAX, 3DS, C4D.","low_poly":"Laden Sie %{rounded_count} Low-Poly-3D-Modelle herunter â leichtgewichtige, game-ready Assets für Games, AR/VR und mobile Projekte.","military":"%{count} militärische 3D Modelle von Waffen, Waffen, %{swords_link}
16518 und Artillerie sowohl moderner als auch historischen durch Streitkräfte und Selbstverteidigung verwendet werden, sind zum Download zur Verfügung. Sie können Modelle für Spiele oder VR / AR Inhalte verwenden - einige von ihnen sind Polygone optimiert und bereit zu einem Spiel-Engine hinzugefügt werden. In Ordnung gebracht und animierte Modelle können Ihre Arbeit weiter erleichtern. Sie werden sicherlich relevanten Vermögenswerte finden, da es viele 3D Modelle in jedem Dateiformat sind, könnten Sie (FBX, OBJ, MAX, 3DS, C4D, etc.) benötigen.","not_custom":"Laden Sie %{rounded_count} %{tag_cap}-3D-Modelle herunter. Ob 3D-Modell %{tag_cap} für Games oder hochauflösend fürs Rendering â kostenlos und Premium, in FBX, OBJ, BLEND und GLB.","optimized":"Modelle, die weniger Polygone haben, sind am besten in Echtzeit-Anwendungen verwendet, die eine schnelle Verarbeitung erfordern, wie Virtual Reality (VR), Augmented Reality (AR), Mixed Reality (MR), Quer Realität (XR) und Spiele, vor allem mobile Spiele. Wähle aus einer Sammlung von in Ordnung gebracht und animierten Modelle, um sie leicht in Ihrer Echtzeit-Anwendungen verwenden. Erhalten Sie 3D Assets für Umgebungen, Pick Requisiten, Objekte oder kaufen komplette 3D-Modellsammlungen, Bundles und Packungen mit allem was das Spiel benötigen. Sparen Entwicklungszeit und -kosten, make Prototyp Erfahrungen oder die Verwendung von 3D Modellen als Platzhalter in Ihrem Projekt. Physikalisch basierten Rendering oder PBR bezeichnet Modelle, die genau und konsistent in allen Lichtverhältnissen infolge der Texturierung gerendert werden Arbeitsabläufe in der Erstellungsprozess verwendet.\n","pbr":"Laden Sie %{rounded_count} PBR-3D-Modelle mit physikalisch basierten Texturen (PBR-Texturen) herunter â konsistente, realistische Materialien für Unity, Unreal und andere Echtzeit-Engines.","plant":"%{count} Pflanze 3D Modelle zum Download zur Verfügung enthalten Flora Organismen, die als Hauspflanzen und in der Natur, wie Blumen, %{trees_link}, Gras, Kletterpflanzen, Pflanzen, Kräuter, Stauden, Keimlinge, Sprossen, Sträucher, rutschen wachsen, Sprossen, Reben, Unkraut. Zum Kauf Prämie oder ein kostenloses 3D-Modell herunterladen Durchsuchen Sie die Kategorien oben, um die beste Lösung unter den Modellen zu finden. Verwenden Sie Filter in Ordnung gebracht zu finden, animiert, Low-Poly (für den Einsatz in Spielen und VR / AR-Anwendungen) Modelle oder benötigten Formate, um herauszufiltern (Modelle in FBX, OBJ, MAX, 3DS, C4D und mehr stehen zur Verfügung).","printable":"Laden Sie über %{rounded_count}
16518 3D-Druck-Vorlagen herunter â geprüfte 3D-Drucker-Vorlagen und 3D-Druck-Dateien für FDM- und Resin-Drucker. Von Figuren und Miniaturen bis zu Deko, Werkzeug und Ersatzteilen.","printable_merged_tag":"Laden Sie %{rounded_count} %{tag_cap}-STL-Dateien für den 3D-Druck herunter. Kostenlose und Premium-3D-Druck-Vorlagen für FDM- und Resin-Drucker.","printable_tag":"Laden Sie %{rounded_count} %{tag_cap}-STL-Dateien für den 3D-Druck herunter. Kostenlose und Premium-3D-Druck-Vorlagen für FDM- und Resin-Drucker.","rigged":"Laden Sie %{rounded_count} Rigged-3D-Modelle (geriggte Modelle mit Skelett) herunter â animationsbereite Charaktere, Tiere und Kreaturen für Blender, Maya, 3ds Max, Unity und Unreal.","scanned":"%{count} gescannten 3D Modelle verfügbar sind für den Kauf oder kostenlosen Download. 3D-gescannter Modelle sind bereit, für die Animation, Spiele und VR / AR-Projekte. Sie können wie Felsen und natürliche Oberflächen, Menschen und andere reale Objekte hier gefunden 3D Modelle von Objekten in der Natur finden ... und es kann nicht mehr realistisch als diese. Verwenden Sie Filter in Ordnung gebracht, animiert, Low-Poly oder freie 3D Modelle zu finden. Erhältlich in jedem Dateiformat einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.","science":"Laborgeräte, mikroskopische Körper und subatomaren Welt:%{count} Wissenschaft 3D Modelle zum Download zur Verfügung in dieser Kategorie reicht von Medizin, Biologie, Physik, Chemie Feldern und anderen Objekten der realen Welt der Wissenschaft und Technologie. Suchen Sie nicht weiter, %{cell_link}, %{skull_link} und %{skeleton_link} 3D Modelle finden Sie hier! Kaufen oder kostenlos 3D-Assets herunterladen, durchsuchen Sie die Kategorien oben. Sie können in Ordnung gebracht Modelle für Animationen oder Low-Poly diejenigen, für Spiele und VR / AR-Projekte verwenden. Beide kostenlos und Premium-3D Modelle können in einer Reihe von Dateiformaten einschlieÃlich FBX, OBJ, MAX, 3DS, C4D finden.","scripts_plugins":"%{count} 3D-Skripte / Plugins zum Download zur Verfügung. 3D-Skripte / Plugins können auf verschiedene Software hinzugefügt werden, und verwendet, um Ihre Arbeit Pipeline effizienter zu machen. Filtern nach Formaten Werkzeuge passend Beliebten Software zu finden.\n","software_page":"Laden Sie %{rounded_count} 3D-Modelle für %{software} herunter â kostenlos und Premium. Native %{ext_file}-Dateien lassen sich direkt öffnen, weitere Formate einfach importieren.","space":"%{count} Raum 3D Modelle stehen zum Download auf CGTrader zur Verfügung. Der Raum ist eine Kategorie voller Low-Poly, Spiel-ready Modelle von Science-Fiction- %{spaceships_link}. Es gibt auch %{asteroids_link}, Planeten (einschlieÃlich Mond und Mars zu simulieren Kolonisation) und realistische Raum %{shuttles_link} für den wissenschaftlich geneigt. Die Modelle können auf jeden Fall im VR-Raum Simulator-Spielen, AR-Anwendungen und Animationen verwendet werden, um die Welt auÃerhalb des Planeten %{earth_link} zu demonstrieren. Filter sind hier, um Ihnen helfen, in Ordnung gebracht finden, animiert, Low-Poly-Vermögenswerte oder Modelle in bestimmten Formaten, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.","sports":"%{count} Sport 3D Modelle zur Verfügung Nest zusammen Ausrüstung, die für Freizeitaktivitäten, Unterhaltung, Sport, Freizeit, angenehmen Zeitvertreib, Spaà sowie Spiele, Kinderspielzeug und die vollständige Palette von Musikinstrumenten verwendet wird. Zum Kauf oder ein kostenloses 3D-Modell in jedem Dateiformat herunterladen benötigt, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D, durchsuchen Sie die Kategorien oben. Sie können Modelle für die Animation, Spiele, VR / AR-Projekte verwenden - viele von ihnen sind in Ordnung gebracht, Low-Poly oder bereits animiert.","test":{"airplane":"Luftfahrt-Enthusiasten, aufhorchen, es ist noch nie so einfach das perfekte 3D Druck Flugzeugmodell für Ihr Brettspiel oder Modellsammlung zu erhalten. Suchen Sie in %{model_count} 3D druckbare Flugzeugmodelle und finden ein Modell, das Sie gerade benötigen, um auf diesem Regal. Entdecken Sie echte Flugzeugmodelle oder aufbereitetem diejenigen. Suchen Sie nach neuesten Designs oder etwas, das zählt ab dem Zeitpunkt der Gebrüder Wright zurück. Es ist auch ein perfektes Geschenk für jedes Kind, das ein Pilot sein träumt, wenn er aufwächst. Download und Kauf eines 3D Druck modell, drucken Sie es selbst oder das Modell zu einem unserer 3D-Druckdienstleister einreichen, um es gedruckt und in kürzester Zeit zu Ihnen versendet!\n","anatomy":"%{model_count} 3D-Anatomie-Modelle zum Download auf unserem Marktplatz. Entdecken Sie die Anatomie des Menschen mit hoher - Poly Knochen, Muskeln, Organmodelle. Perfekt für jede pädagogische oder wisse
16518nschaftliche Projekt. Verwenden Sie druckbare 3D Modelle für eine verbesserte Ausbildung Erfahrung. Erstellen Sie beeindruckende Animationen und Videospiele mit unseren\n umfangreiche Bibliothek von manipulierten Modellen. Nutzen Sie unsere erweiterte Filtersystem leicht Low-Poly zu finden, animiert, PBR,\n manipulierten Modelle oder alles, was passt am besten Ihren Bedürfnissen. Wählen Sie aus einer groÃen Menge Dateiformate, einschlieÃlich der\n die meisten populären wie FBX, OBJ, MAX, 3DS, C4D.\n","castle":"Ihre eigene erstaunliche 3D Druck Schloss ist ein Klick entfernt! Suchen Sie verschiedene 3D-Schloss-Modelle für 3D Druck bereit. Erstellen Sie eine einzigartige Fantasy-Festung für D \u0026 D-Sitzung oder ein anderes mittelalterlichen rpg Tabletop-Spiel. Diese mittelalterlichen Festungen sind ein erstaunliches Geschenk für jedes Brettspiel-Enthusiasten oder eine groÃartige Ergänzung zu Ihrer eigenen Sammlung. Finden Sie das perfekte 3D-Modell für Bastler oder einen von einer Art Spielzeug für Kinder zu malen. Download und Kauf von Ihnen gewählten 3D-Schloss-Design, drucken Sie es mit Ihrem eigenen Drucker oder senden Sie das Modell zu einem unserer 3D Druck-Service-Provider haben es gedruckt und versendet zu Ihnen.\n","dice":"Das Glück wird nicht abgelaufen ist mit 3D-Würfel gedruckt! Wenn Sie für Ihre Brettspiel Nacht authentisches Spiel Würfel wollen, schauen Sie nicht mehr. Hier können Sie zwischen %{model_count} kostenlose 3D Würfel Modelle bereit für den 3D Druck wählen. Wenn das Spiel vorbei ist, diese schönen Modelle als Zubehör verwenden. Download der kostenlosen 3D-Druckvorschau Würfel Modelle, Dateiformate, einschlieÃlich STL, verfügbar OBJ, 3DM, 3DS, MAX. Unser 3D Modelle sind bereit, mit FDM, SLA, SLS und anderen Arten von 3D-Druckern verwendet werden. Machen Sie Ihr Spiel ein wenig interessanter und erhalten Sie Ihre 3D Druck Würfel!\n","drone":"3D Druck und Ihre eigene Drohne bauen oder Teile für den Ersatz finden. 3D Druck-Drohnen sind leicht nach einer Bruchlandung zu montieren und zu reparieren. Entdecken Sie ein Modell mit der perfekten Kamera Einbaulage oder Anfrage für minimale Ãnderungen. Perfekt für Spaà Freizeitaktivitäten, Luftaufnahmen, Videografie oder Mapping. Finden und kaufen Sie eine einzigartige 3D-Drohne Modell konzipiert, dass passt auf alle Ihre Bedürfnisse. Drucken Sie es selbst oder das Modell zu einem unserer 3D-Druckdienstleister vorlegen, um es gedruckt und versendet zu Ihnen in kürzester Zeit! Holen Sie Ihre eigene 3D-gedruckten Drohne und durchstreift den weiten blauen Himmel!\n","pokemon":"Pikachu, ich wählen Sie! Wählen Sie aus Lasten der Tasche Monster bereit für die 3D Druck. GroÃe 3D gedruckt pokemon Sammlung zu erweitern. Suchen und stolpern das beste, ausführlichsten pokemon Design für Ihr nächstes Tabletop-Spiel mit Freunden. Kauf und laden Sie Ihre 3D-pokemon, drucken Sie es mit Ihrem eigenen 3D Drucker laden oder das Modell zu einem unserer 3D Druck-Service-Provider haben es gedruckt und versendet zu Ihnen. Immerhin ist dies eine der coolsten Sachen 3D Druck!\n","ring":"3D Druck-Schmuck ist das neue Schwarz in der Branche, sind als gedruckte 3D-Ringe! Suchen Sie eine enorme Menge an %{model_count} freier 3D-bedruckbare Ringmodelle. Stöbern Sie in einzigartigen Designs und für Sie nur etwas gemacht finden. Ich kann nichts für sich selbst im Laden finden? Oder vielleicht möchten Sie ein Zubehörteil genau wie die, Ihren Lieblingsfilm Charakter hat? Wählen Sie aus einer groÃen Menge Dateiformate wie STL, OBJ, 3DM, 3DS, MAX. 3D Modelle sind bereit, mit FDM, SLA, SLS und anderen Arten von 3D-Druckern verwendet werden, um durch unsere Auswahl durchsuchen und auf Ihrem neuen Lieblings-Ring versuchen.\n","shoes":"GroÃe Marken sind an Bord mit 3D-Schuhe gedruckt und jetzt können Sie die Erfahrung als auch teilen. Durchsuchen und frei bedruckbare Schuh-Design - von den Turnschuhen zu modischen Fersen gibt es eine Menge von ready-to-Print-Modellen warten auf Sie sie auf versuchen. Machen Sie das Ergebnis perfekt durch Auswahl der Materialien, die Anpassung Weichheit und GröÃe. Wählen Sie aus 146 3D freie Schuhmodelle und laden Sie sie in verfügbaren Dateiformate wie STL, OBJ, 3DM, 3DS, MAX. Designs sind bereit, mit FDM, SLA, SLS und anderen Arten von 3D-Druckern verwendet werden. Holen Sie sich Ihre 3D Druck-Schuhe heute!\n","textures":"Suchen Sie in einer groÃen Menge von %{model_count} CG Texturen für Downloads zur Verfügung, einschlieÃlich schön hergestellten Materialien. Blättern Sie durch die Kategorie und findet nahtlosen Stoff, Holz, Metall, Kunststoff, Ziegel Texturen zu helfen, Ihr Projekt schneller Finish auf. Nutzen Sie unsere erweiterte Suche, um manipulierte und animierte Texturen für Spiele oder Video-Erstellung zu finden. Unsere Materialien stehen zum Download in verschiedenen Formaten einschlieÃlich TGA, SBSAR, JPG, PNG, TIFF und anderen, so verschwenden Sie keine Zeit und ready-to-use CG Texturen für fast jedes Projekt vorstellbar zu finden.\n"},"various":"%{count} verschiedene 3D Modelle, die ihren Platz in anderen Kategorien nicht leicht zum Download zur Verfügung finden. %{rocks_link}, %{clouds_link}, %{logos_link}, %{cigarette_link} und andere nicht kategorisiert 3D Modelle, dass Sie Ihr Spiel, Animation oder VR / AR-Projekt sind hier zu vervollständigen benötigen. Verwenden Sie Filter, durch den verfügbaren Formaten wie FBX, OBJ, MAX, 3DS, C4D in Ordnung gebracht, animiert, Low-Poly oder freie 3D Modelle oder aussortieren zu finden.","vehicle":"%{count} Fahrzeug 3D Modelle zum Download bereit sind LKW, %{ambulances_link}, Busse, %{bikes_link} und moto - Diese Kategorie ist für die Menschen, die ihre StraÃen der Stadt wollen mit Fahrzeugen, ob realistisch oder Sci-Fi gefüllt werden. Diejenigen, Simulationsspiele oder VR / AR-Anwendungen, Kreativen in der Videoproduktion oder sogar entwerfen Plakate werden höchstwahrscheinlich die meisten gängigen Dateiformaten finden wie FBX, OBJ, MAX, 3DS, C4D verwendbar. Andere Landtransportfahrzeuge wie Zug oder %{tractor_link} 3D Modelle können auch in dieser riesigen Sammlung zu finden. Verwenden Sie Filter in Ordnung gebracht zu finden, animierte, Low-Poly oder schnellen 3D Modelle frei.","
16518watercraft":"%{count} Wasserfahrzeuge 3D Modelle zum Download verfügbar sind %{boats_link}, %{yachts_link}, %{ships_link} und andere Wasser gehen Fahrzeuge aller Art. Die manipulierten Low-Poly 3D Modelle werden gut daran tun in Videospielen, VR / AR-Projekten sowie Animationen, während CG-Modelle hier für Ihre Szenen und andere Anwendungen, wo visuelle Treue ist wichtiger als polycount. Alle Modelle sind in jedem Dateiformat zur Verfügung, einschlieÃlich, aber nicht beschränkt auf FBX, OBJ, MAX, 3DS, C4D."},"tag":{"meta":{"3d_merged_premium":"%{rounded_count} %{tag_cap}-3D-Modelle herunterladen, kostenlos und Premium. In FBX, OBJ, BLEND, GLB und mehr â für Games, Film, AR/VR und 3D-Druck.","3d_merged_premium_print":"%{rounded_count} %{tag_cap}-STL-Dateien und 3D-Druck-Vorlagen herunterladen, kostenlos und Premium â getestet für FDM- und Resin-Drucker.","3d_models":"%{rounded_count} %{tag_cap}-3D-Modelle herunterladen, kostenlos und Premium. In FBX, OBJ, BLEND, GLB und mehr â für Games, Film, AR/VR und 3D-Druck.","3d_print_models":"%{rounded_count} %{tag_cap}-STL-Dateien und 3D-Druck-Vorlagen herunterladen, kostenlos und Premium â getestet für FDM- und Resin-Drucker.","animated_3d_models":"%{count} %{tag} 3D Modelle zum Download in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page} verfügbar animiert","free_3d_models":"Herunterladen %{count} %{tag} freie 3D Modelle, erhältlich in MAX, OBJ, FBX, 3DS, C4D Dateiformaten, bereit für VR / AR, Animation, Spiele und andere 3D-Projekte.%{page}","free_3d_print_models":"Herunterladen %{count} %{tag} freie 3D Druck Modelle bereit für FDM, SLA, SLS und anderen 3D Drucker , verfügbare Formate STL, OBJ, 3DM und vieles mehr.%{page}","lowpoly_3d_models":"Download %{count} VR / AR / Low-Poly-%{tag} 3D Modelle bereit für die Virtual Reality, Spiele und andere Echtzeit-Anwendungen, in FBX, OBJ, MAX, 3DS, C4D-Dateiformaten.%{page}","rigged_3d_models":"%{count} %{tag} 3D Modelle zum Download in jedem Dateiformat, einschlieÃlich FBX, OBJ, MAX, 3DS, C4D.%{page} verfügbar in Ordnung gebracht"}},"title":{"download":"| herunterladen","files":"3D-Dateien","formats":"%{format_upper} 3D-Modelle","free":"Kostenlose 3D-Modelle","free_printing":"Kostenlose 3D-Druck Vorlagen","free_tag":"Freies %{selected_tag} 3D Modelle","general":"Professionelle 3D-Modelle","high_poly":"%{selected_filter}3D Modelle","landing":{"animated_3d_models":"Animierte 3D-Modelle","lowpoly_3d_models":"Low Poly 3D-Modelle","pbr_3d_models":"PBR 3D-Modelle","rigged_3d_models":"Rigged 3D-Modelle"},"low_poly":"%{selected_filter}3D Modelle","newest_cg":"Neueste 3D Modelle","newest_print":"Neueste 3D Druck Modelle","page_prefix":"Page %{page_number} von ","pbr":"PBR 3D Modelle","printing":"3D-Druck Vorlagen \u0026 STL-Dateien","sales_cg":"Bestseller 3D Modelle","sales_print":"Bestseller 3D Druck modelle","software_page":"%{software} 3D-Modelle","tag_heading":{"cg":"Freies %{tag} 3D Printing Modelle","filter":"%{selected_filter} %{tag} 3D Modelle","general":"%{tag_cap} 3D-Modelle","merged_premium_print_tag":"%{tag_cap} STL-Dateien \u0026 3D-Druck Vorlagen","merged_premium_tag":"%{tag_cap} 3D-Modelle","printable":"%{tag_cap} STL-Dateien \u0026 3D-Druck Vorlagen"},"trending_cg":"Trendige 3D Modelle","trending_print":"Trendige 3D Druck modelle"}},"cart":{"request_invoice_failed":"Ups. Etwas ist schiefgelaufen.","request_invoice_successful":"Rechnungsanforderung erfolgreich gesendet.","shareable_cart_created":"Warenkorb erfolgreich geteilt.","shareable_cart_failed":"Ups. Etwas ist schiefgelaufen.","subscription_covered_items_removed":"Aus Ihrem Warenkorb entfernt: %{titles}. Bereits in Ihrem Abonnement enthalten.","subscription_covered_order_refused":"Ihr Abonnement enthält jetzt %{titles}, daher haben wir Ihnen nichts berechnet. Laden Sie die Modelle stattdessen über Ihr Abonnement herunter."},"categories":{"cg":{"header_title_html":"Professionelle 3D-Modelle","text":"Finden Sie genau die richtigen 3D-Inhalte für Ihre Bedürfnisse, einschlieÃlich AR/VR, Gaming, Werbung, Unterhaltung und mehr"},"head-title":{"cg":"3D-Modelle â %{rounded_count} Modelle kostenlos \u0026 Premium","cg-models":{"sort_by":{"newest":"Neueste 3D-Modelle","top_selling":"Meistverkaufte 3D-Modelle","trending":"Trendige 3D-Modelle"}},"print":"3D-Druck Vorlagen â STL-Dateien kostenlos \u0026 Premium","print-models":{"sort_by":{"newest":"Neueste 3D-Druckdateien","top_selling":"Meistverkaufte 3D-Druckdateien","trending":"Trendige 3D-Druckdateien"}}
16518,"product-type":{"plural":{"capital":{"cg":"3D Modelle","cg-merge-premium":"3D-Modelle â Kostenlose und Premium-Downloads","print":"3D-Druckdateien und Modelle","print-merge-premium":"%{tag} 3D-Druckdateien â kostenlose und Premium-STL-Modelle"},"lower":{"cg":"3D Modelle","print":"3D-Druckdateien und Modelle"}},"singular":{"capital":{"cg":"3D Modell","print":"3D-Druckmodell"},"lower":{"cg":"3D Modell","print":"3D Druckmodell"}}}},"index":{"browse_all":"Alle Modelle durchsuchen","info-section__description_1_html":"Kaufen oder kostenlos herunterladen: professionelle 3D-Modelle, die sofort in CG-Projekten, Film- und Videoproduktion, Animation, Visualisierungen, Spielen, VR/AR und mehr verwendet werden können. Assets sind in vielen \u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003ebranchenüblichen Formaten\u003c/a\u003e verfügbar, darunter MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB und andere. Wenn Sie nach High-Poly- oder Echtzeit-3D-Assets suchen, haben wir eine führende digitale Kunstbibliothek für alle Ihre Bedürfnisse.\n","info-section__description_1_printable_html":"Professionelle 3D-Dateien, Drucke und Modelle, die zu Hause mit Desktop-FDM- oder industriellen SLS-3D-Druckern gedruckt werden können, verfügbar in vielen Industrieformaten, darunter OBJ, \u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003e, WRL. Wenn Sie ein 3D-Druck-Hobbyist, Maker, Pädagoge oder ein Unternehmen sind, das Prototypen durch 3D-Druck erstellt, werden unsere Wohnaccessoires, trendigen Gadget-Zubehörteile, auffälligen Modeartikel, einzigartigen Schmuckstücke, mechanischen Teile und eine Vielzahl von Miniaturen Ihnen sicherlich einen Inspirationsschub geben.","info-section__heading_1_html":"3D-Modell \u003cstrong\u003eKategorien\u003c/strong\u003e erkunden","info-section__heading_1_printable_html":"Entdecken Sie 3D Druck modell \u003cstrong\u003e Kategorien \u003c/strong\u003e","info-section__heading_2_html":"3D-Modelle-\u003cstrong\u003eMarktplatz\u003c/strong\u003e","info-section__heading_2_printable_html":"Was \u003cstrong\u003enoch?\u003c/strong\u003e"},"marketplace":{"3d-printing":{"link_text":"3D-Druckmodelle durchsuchen","text":"Finden Sie 3D-Druckmodelle für Ihren 3D-Drucker.","title":"3D-Druckmodelle"},"blender_text":"Entdecken Sie Tausende von Blender-3D-Modellen im BLEND-Format.","browse":"Durchsuche","cinema-4d_text":"Entdecken Sie Tausende hochwertiger Cinema-4D-Modelle, die im C4D-Dateiformat verfügbar sind.","discounted":{"link_text":"Durchsuchen ErmäÃigte 3D Modelle","text":"Kaufen Sie professionelle 3D Modelle mit einem Abschlag.","title":"ErmäÃigte 3D Modelle"},"low-poly":{"link_text":"Low-Poly-3D-Modelle durchsuchen","text":"Low-Poly-3D-Modelle, bereit für Videospiele, VR- \u0026 AR-Echtzeitanwendungen.","title":"Low-Poly-3D-Modelle"},"pbr":{"link_text":"PBR-3D-Modelle durchsuchen","text":"Physically Based Rendering 3D-Modelle.","title":"PBR-3D-Modell"},"scripts_apps":{"link_text":"Alle durchsuchen","text":"3D-Skripte und Plugins, um Ihre 3D-Modellierungs-Pipeline effizienter zu gestalten.","title":"Skripte \u0026 Apps"},"sketchup_text":"Durchsuchen Sie die groÃe Auswahl an Sketchup-3D-Modellen für Architektur-, Innen- und Videospieldesigns.","textures":{"link_text":"Texturen durchsuchen","text":"Einsatzbereite Texturen, um Zeit bei der Vorbereitung Ihrer 3D-Modelle zu sparen.","title":"Texturen"},"zbrush_text":"Finden Sie 3D-Assets im ZTL-Dateiformat für Ihre digitalen Sculpting-, 3D-Modellierungs-, Texturierungs- und Malprojekte."},"meta-description":{"cg":"Ãber %{rounded_count} professionelle 3D-Modelle herunterladen oder kaufen. Kostenlose und Premium-3D-Assets für Games, Film, VFX und 3D-Druck. FBX, OBJ, BLEND, GLB u.v.m.","print":"Ãber %{rounded_count} 3D-Druck-Vorlagen herunterladen. Kostenlose und Premium-STL-Dateien für den 3D-Drucker: Figuren, Miniaturen, Deko, Werkzeug und mehr."},"more":{"designers":{"link_text":"3D-Designer-Liste durchsuchen","text":"Durchsuchen Sie Tausende von 3D-Designer-Portfolios und finden Sie genau das, was Sie für Ihre Anwendung benötigen.","title":"Beste 3D-Designer finden"},"projects":{"link_text":"Mehr über 3D-Projekte erfahren","text":"Qualifizierte freiberufliche 3D-Künstler beauftragen und alle Ihre individuellen Modellierungsherausforderungen lösen.","t
16518itle":"CGTrader-3D-Projekte"},"visualization":{"link_text":"Mehr erfahren","text":"Verwandeln Sie Ihre Produkte in fotorealistische 3D-Modelle für E-Commerce und andere Geschäftsanwendungen.","title":"3D-Visualisierung für E-Commerce"}},"navbar":{"aircraft":"Flugzeug","animal":"Tiere","animals":"Tiere","architectural":"Architektonisch","art":"Kunst","car":"Auto","character":"Charakter","exterior":"AuÃen","fashion":"Mode","food":"Essen","furniture":"Möbel","gadgets":"Gadgets","games-toys":"Spiele und Spielzeug","hobby-diy":"Hobby \u0026 Basteln","house":"Haus","household":"Haushalt","industrial":"Industriell","interior":"Innenraum","jewelry":"Schmuck","military":"Militär","miniatures":"Miniaturen","plant":"Pflanze","science":"Wissenschaft","space":"Platz","vehicle":"Fahrzeug","watercraft":"Wasserfahrzeug"},"print_models":{"hero_title_html":"3D-Druck Vorlagen \u0026 STL-Dateien","subtitle":"Finden Sie genau die richtigen 3D-Druckinhalte für Ihre Bedürfnisse","title_html":"Professionelle \u003cstrong\u003e3D-Modelle für den Druck\u003c/strong\u003e kaufen"},"profile":{"collection":"3D-Pakete","free":"Kostenlose 3D-Modelle","high_poly":"High-Poly 3D Modelle","optimized":"Low-Poly / Pbr 3D Modelle","printable":"3D Druck modelle"},"seo":{"cg":{"aircraft":"Diese Kategorie umfasst 3D-Flugzeuge. CG-Flugzeuge eignen sich für Simulationen,\nVisualisierungen, Werbung und Videos. Drohnenkörper und -teile erfreuen\nFans kleiner Fluggeräte. Und die geriggten Modelle sind bereit, in Spiel-Engines\nimportiert zu werden.\n","animals":"Die Sammlung von 3D-Fauna â Katzen, Pferde, Bären, Nashörner, Adler, Löwen\nund mehr â ist hier zu finden. Die CG-Tiere erfüllen die Anforderungen\nvon Werbung oder statischen Szenen. Wir haben auch geriggte Tiermodelle\nfür Spiele.\n","architectural":"Treppen, Kamine, 3D-Modelle sowie Dekorationen wie Rahmen, Kissen oder\nLampen finden Sie in der umfangreichen Bibliothek architektonischer Detailmodelle.\nInnen- und AuÃenbereiche können genutzt werden, um digitale Küchen, Schlafzimmer,\nSchlossräume oder Dungeons zu bauen â egal ob Architekt, Ingenieur oder\nIndie-Entwickler.\n","car":"Die Kategorie Auto enthält Automobil-3D-Modelle, deren Low-Poly-Versionen\nfür Spieledesigner attraktiv sind, andere für Filmemacher oder Werbetreibende.\nVon klassischen Autos über Renn- und Sportwagen bis hin zu Konzeptfahrzeugen\ngibt es eine groÃe Vielfalt an 3D-Automodellen.\n","character":"In dieser Kategorie finden Sie 3D-Modelle von Menschen, Personen, Sci-Fi,\nKleidung und mehr. Vom Herz und von der Hand bis hin zu detaillierten realistischen\nmännlichen oder weiblichen Modellen. Zahlreiche Modelle sind geriggt und\nkönnen leicht in Ihr Spiel oder Ihre Animation integriert werden.\n","electronics":"Elektronik ist eine Kategorie für Architekten, Innenarchitekten, Level-Designer, Szene Entscheidungsträgern und anderen Kreativen. 3D Modelle von {\"slug\": \"Smartphone\",\"title\": \"Smartphones\"}, {\"slug\": \"Laptop\",\"title\": \"Laptops\"}, {\"slug\": \"Kamera\", \"title\":âKamerasâ}, {\"slug\":âtvâ,âtitleâ:âTVâ} und wird dazu beitragen, genau die moderne Leben Besessenheit mit Geräten und Technologie zu erfassen.\n","engineering-parts":"Fenster, Pipelines, Schiebetürmechanismen und andere Bits, die für CAD-Projekte notwendig sind und auch DIY Pläne fallen unter diese Kategorie. Hier können Sie 3D Modelle von den globalen Herstellern wie ANVER, Dynatec und FCi finden.\n","exterior":"Durchsuchen Sie architektonische AuÃenbereiche von Fassaden, städtischen\nGebäuden bis hin zu Landschaftsobjekten, Wohnhäusern, Industrieanlagen\nund vollständigen 3D-Stadtmodellen. Einige Assets sind Low Poly und können\nIhnen helfen, Ihr Spiel oder Ihre VR/AR-Anwendung zu vervollständigen.\n","food":"Lebensmittel helfen, realistische Szenen des häuslichen Lebens zu erschaffen.\n3D-Früchte, Gemüse, Getränke und Mahlzeiten sind alle hier. Werbung für\nRestaurants, AR-Anwendungen für gesünderes Essen. Ob Sie ein 3D-Pizza- oder\nHochzeitstortenmodell gesucht haben â hier finden Sie es.\n","furniture":"3D-Tische, Stühle, Sofas, Betten in verschiedenen Texturen (Holz, Metall\nusw.) und Stilen (Retro, Modern usw.) sind verfügbar. Diese Kategorie richtet\nsich an alle, die mit Architektur und Inneneinrichtung sowie Werbung zu\ntun haben.\
16518n","furniture-set":"Wenn Sie gleich brauchen antiken Stuhl und Sofa schauen, oder vollständigen Satz von Geschirr, ist dies ein Ort wie diese Kategorie collect Sätze von 3D-Möbelmodellen aus Küche und Wohnzimmer zu Büro und Speisesaal Möbel-Sets zu sein. Dies hilft, die innere oder Level-Design-Spezialist Build Zimmer mit Anpasselemente.\n","household":"Haushaltsgegenstände in 3D werden verwendet, um Räumen Details zu verleihen.\nSie können ein 3D-Geschirrset auf den Tisch stellen oder Pfeffer- und Salzstreuer\nverwenden, um die Kücheneinrichtung zu vervollständigen, vielleicht Lichter\nund Blumen neben das Bett stellen, um ein luxuriöses Ambiente zu schaffen.\n","industrial":"Baumaterialien, Ingenieurwerkzeuge, Maschinen und Container, die sowohl\nUmgebungsdetails als auch interaktive, geriggte Elemente bieten. Perfekt\nfür Entwickler von Simulationsspielen oder Personen, die Baustellen-Level\nerstellen.\n","interior":"Diese Kategorie enthält realistische 3D-Elemente und Details der Architektur,\
16518ndes Bauwesens und des Innenraumdesigns. Sie können diese 3D-Modelle für\nAnimationen oder Spiele verwenden â einige sind geriggt und Low Poly.\n","military":"In dieser Kategorie können Sie 3D-Modelle von Waffen, Rüstungen, Schwertern\nund Artillerie â sowohl modern als auch historisch â kaufen, die von Militärkräften\noder zur Selbstverteidigung genutzt werden. Sie können die Modelle für Spiele\nverwenden â einige sind polygonoptimiert und für Spiel-Engines bereit.\n","plant":"Diese Kategorie enthält 3D-Modelle von Flora-Organismen wie Blumen, Bäumen,\nGras, Kletterpflanzen, Grünpflanzen, Kräutern, Stauden, Setzlingen, Trieben,\nSträuchern, Stecklingen, Sprossen, Reben und Unkraut. Um ein 3D-Modell zu\nkaufen oder kostenlos herunterzuladen, durchsuchen Sie die Kategorien unten.\n","scanned":"Modellierer erstellen, um diese Modelle von 3D-Scan-Technologien wie RealSense verwenden. Baumstümpfe, Statuen, auch Männer und Frauen sind hier sehr beliebt. Das Produkt ist bereit, in Szenen und Animationen verwendet wird, beispiellosen Realismus bieten.\n","science":"Diese Kategorie enthält 3D Modelle im Zusammenhang mit Medizin, Biologie, Physik, Chemie und Technik, wie Laborgeräte, mikroskopische Körper und subatomaren Welt. Suchen Sie nicht weiter, {\"slug\": \"Zelle\"}, {\"slug\": \"skull\"} und {\"slug\": \"Skelett\"} 3D Modelle finden Sie hier.\n","scripts-plugins":"Scripts und Plug-Ins bieten Ihnen Software-Verknüpfungen. Modellierung, Rendering, Texturieren - all dies einfacher gemacht werden kann Plug-In verwenden, die für alle Arten von Software wie Maya und V-Ray kommt.\n","space":"Weltraum ist eine Kategorie voller Low-Poly-, spielbereiter Modelle von\nSci-Fi-Raumschiffen, Asteroiden, Planeten (einschlieÃlich Erde und realistischer\nSpace Shuttles für wissenschaftlich Interessierte). 3D-Weltraummodelle sind\nnützlich für VR-Weltraumsimulatorspiele.\n","sport-hobby":"Diese Kategorie encompases alles, was bezieht {\"slug\": \"Feld\"} Veranstaltungen, Sport und Hobbys im Allgemeinen. Von {\"slug\": \"FuÃball\"} und Skipisten zu {\"slug\": \"Gitarre\"} und {\"slug\": \"Piano\"}, sind diese nützlichen 3D Modelle für Anzeigen, Szenen und Animationen. Low-Poly-Versionen gibt es für Sportvideospiele.\n","textures":"Durchsuchen Sie eine Bibliothek wunderschön erstellter 3D-Materialien und\nfinden Sie die am besten geeigneten, einsatzbereiten Texturen, um spielbereite\noder fotorealistische Modelle vorzubereiten, Ihre Asset-Bibliothek zu erweitern\nund Ihre 3D-Arbeiten zu verbessern.\n","various":"Dies sind die 3D Modelle, die nicht leicht in andere Kategorien gepasst haben, so dass wir eine erstellt, die sie alle akzeptieren würde. {\"title\": \"Rock\", \"slug\": \"Felsen\"}, {\"slug\": \"Wolken\"}, {\"title\": \"Logo\", \"slug\": \"Logo\"}, {\"title\" : \"Regenschirme\", \"slug\": \"Regenschirm\"} und andere nicht kategorisiert 3D Modelle sind hier.\n","vehicle":"Lkw, Krankenwagen, Busse, Züge, Traktoren, Fahrräder und Motorräder â diese\nKategorie ist für Menschen gedacht, die ihre StadtstraÃen mit realistischen\nund Sci-Fi-Fahrzeugen füllen wollen, und für diejenigen, die Simulationsspiele\nmachen oder Poster gestalten.\n","watercraft":"Wasserfahrzeuge umfassen Boote, Yachten, Schiffe und andere Wasserfahrzeuge.\nDie geriggten 3D-Modelle eignen sich gut für Videospiele und Animationen,\nwährend CG-Modelle für Szenen oder andere Anwendungen gedacht sind, bei\ndenen visuelle Treue wichtiger ist als Polygonanzahl.\n"},"forwarded":{"cg":{"aircraft":"Diese Kategorie umfasst 3D-Flugzeuge. CG {\"slug\": \"aircraft\",\"title\": \"Flugzeuge\"} paÃt in Simulationen, Visualisierungen, Anzeigen und Videos. {\"slug\": \"drone\",\"title\": \"Drone\"} Körper und Teile werden die Fans von kleinen fliegenden Fahrzeuge erfreuen. Und die {\"slug\": \"aircraft\",\"title\": \"in Ordnung gebracht Modelle\", \"active_filter\": \"rigged\"} sind bereit, in der Game-Engines importiert werden.\n","animals":"Die Sammlung von 3D-Fauna - {\"slug\": \"cat\",\"title\": \"Katzen\"}, {\"slug\": \"horse\",\"title\": \"Pferde\"}, {\"slug\": \"bear\",\"title\": \"Trägt\"}, {\"slug\": \"rhino\", \"Titel\": \"rhinos\"}, {\"slug\": \"eagle\", \"Titel\": \"Eagles\"}, {\"slug\": \"lion\",\"title\": \"Löwen\"} und mehr - ist hier zu finden. Die CG 3D Tiere werden auf die Bedürfnisse von Werbeanzeigen oder statischer Szenen befriedigen. Wir haben auch {\"slug\": \"animal\",\"title\": \"in Ordnung gebracht Tieres\", \"active_filter\": \"rigged\"} Modelle für Spiele.\n","architectural":"{\"slug\": \"stairs\",\"title\": \"Treppe\"}, {\"slug\": \"fireplace\",\"title\": \"Kamin\"}, 3D Modelle sowie Dekorationen wie {\"slug\": \"frame\",\"title\": \"Frame\"}
16518, {\"slug\": \"pillow\",\"title\": \"Kissen\"} oder {\"slug\": \"lamp\",\"title\":\"Lampe\"} können in dem umfangreichen architektonischen Details Car enthält Automobil 3D Modelle gefunden werden, {\"slug\": \"car\",\"title\": \"niedrige poly\", \"active_filter\": \"low_poly\"} Modellbibliothek. Innen- und AuÃenbereich können sowohl digitale als Küchen und Schlafzimmer sowie Schlossräume und Dungeons zu bauen verwendet werden, ob Sie ein Architekt, Ingenieur oder Indie-Spiele-Entwickler sind.\n","car":"Auto enthält Automobil 3D Modelle, \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e Low-Poly \u003c/a\u003e Versionen davon zu Game-Designern attraktiv sein werden, andere - zu Filmemachern oder Werbekunden. Von Oldtimern zu Renn- und Draisinen auf das Konzept diejenigen, gibt es eine groÃe Auswahl an 3D-Auto-Modelle.\n","character":"Menschen, Science-Fiction, Kleidung und andere: In dieser Kategorie finden Sie 3D Modelle von { \"slug\": \"human\",\"title\": \"mensch\" } finden. Von {\"slug\": \"heart\",\"title\": \"Herz\"} und {\"slug\": \"hand\",\"title\": \"Hand\"}, um detaillierte realistische {\"slug\": \"male\",\"title\": \"Männlich\"} oder {\"slug\": \"female\",\"title\": \"Weiblich\"} Modelle. Einige der Modelle sind in Ordnung gebracht und könnten leicht zu Ihrem Spiel oder eine Animation hinzugefügt werden.\n","electronics":"Elektronik ist eine Kategorie für Architekten, Innenarchitekten, Level-Designer, Szene Entscheidungsträgern und anderen Kreativen. 3D Modelle von {\"slug\": \"smartphone\",\"title\": \"Smartphones\"}, {\"slug\": \"laptop\",\"title\": \"Laptops\"}, {\"slug\": \"camera\", \"title\":\"Kameras\"}, {\"slug\":\"tv\",\"title\":\"TV\"} und wird dazu beitragen, genau die moderne Leben Besessenheit mit Geräten und Technologie zu erfassen.\n","engineering-parts":"Fenster, Pipelines, Schiebetürmechanismen und andere Bits, die für CAD-Projekte notwendig sind und auch DIY Pläne fallen unter diese Kategorie. Hier können Sie 3D Modelle von den globalen Herstellern wie ANVER, Dynatec und FCi finden.\n","exterior":"Durchsuchen Architektur AuÃen von Fassaden, städtischen Gebäuden zu Landschaftsobjekte, Wohnhäuser, Industriebauten und Skalenendwert 3D {\"slug\": \"city\",\"title\": \"Stadt\"} Modelle. Einige der Vermögenswerte sind Low-Poly und könnten Sie Ihr Spiel oder VR / AR-Anwendung vervollständigen helfen.\n","food":"Essen hilft realistische Szenen des häuslichen Lebens zu schaffen. 3D-Obst, Gemüse, Getränke und Speisen sind alle hier. Werbung für Restaurants, AR-Anwendungen für gesündere Ernährung. Egal, ob Sie waren auf der Suche nach 3D {\"slug\": \"pizza\",\"title\": \"Pizza\"} oder einer Hochzeit {\"slug\": \"cake\",\"title\": \"Kuchen\"} Modell, sind sie hier.\n","furniture":"3D-Tische, Stühle, Sofas, Betten in einer Vielzahl von Texturen (Holz, Metall, etc.) und Stilen ({\"slug\": \"retro\",\"title\": \"Retro\"}, {\"slug\": \"modern\",\"title\": \"Modern\"}, etc.) sind on- Hand. Diese Kategorie ist für jedermann mit Architektur und Innenarchitektur sowie Werbetreibende beteiligten gemeint.\n","furniture-set":"Wenn Sie gleich brauchen antiken Stuhl und Sofa schauen, oder vollständigen Satz von Geschirr, ist dies ein Ort wie diese Kategorie collect Sätze von 3D-Möbelmodellen aus Küche und Wohnzimmer zu Büro und Speisesaal Möbel-Sets zu sein. Dies hilft, die innere oder Level-Design-Spezialist Build Zimmer mit Anpasselemente.\n","household":"Haushalt Artikel 3D Modelle werden verwendet, Details zu den Zimmern zu geben. Sie können einen 3D-Besteckset auf dem Tisch legen, oder Pfeffer und Salz Container komplette Küche Interieur haben, vielleicht etwas setzen {\"slug\": \"light\",\"title\": \"Lichter\"} und {\"slug\": \"flowers\",\"title\": \"Blumen\"} in der Nähe des Bettes luxuriöse Atmosphäre zu schaffen.\n","industrial":"Baustoffe, {\"slug\": \"engineering\",\"title\": \"Ingenieurwesen\"} Werkzeuge, Maschinen und {\"slug\": \"container\",\"title\": \"Container\"}, die sowohl Umweltdaten und interaktive liefern, manipulierten Elemente. Dies ist ideal für Simulationsspiel-Entwickler oder Menschen bauen {\"slug\": \"construction\",\"title\": \"Bau\"} Hofebene.\n","interior":"Diese Kategorie enthält realistische 3D-Elemente und Details der Architektur, Bau- und Ingenieurinnenarchitektur. Sie können diese 3D Modelle für Animationen oder Spiele verwenden - einige von ihnen sind in Ordnung gebracht und Low-Poly.\n","military":"Durch Streitkräfte und Selbstverteidigung und Artillerie sowohl moderne als auch historische In dieser Kategorie können Sie 3D Modelle von Waffen, Waffen, { \"Schwert\": \"Schwerter\", \"slug\": \"sword\"} kaufen. Sie können Modelle für Spiele verwenden - einige von ihnen Polygone sind optimiert und bereit für Game-Engines.\n","plant":"Diese Kategorie enthält 3D Modelle von Flora Organismen wie Blumen, {\"slug\": \"tree\",\"title\": \"Bäume\"}, Gras, Kletterpflanzen, Pflanzen, Kräuter, Stauden, Keimlinge, Sprossen, Sträucher, rutscht, Sprossen, Reben, Unkraut. Zum Kauf oder ein kostenloses 3D-Modell herunterladen, durchsuchen Sie die Kategorien unten.\n","scanned":"Modellierer erstellen, um diese Modelle von 3D-Scan-Technologien wie RealSense verwenden. Baumstümpfe, Statuen, auch Männer und Frauen sind hier sehr beliebt. Das Produkt ist bereit, in Szenen und Animationen verwendet wird, beispiellosen Realismus bieten.\n","scie
16518nce":"Diese Kategorie enthält 3D Modelle im Zusammenhang mit Medizin, Biologie, Physik, Chemie und Technik, wie Laborgeräte, mikroskopische Körper und subatomaren Welt. Suchen Sie nicht weiter, {\"slug\": \"cell\",\"title\": \"Zelle\"}, {\"slug\": \"skull\", \"title\":\"schädel\"} und {\"slug\": \"skeleton\",\"title\": \"Skelett\"} 3D Modelle finden Sie hier.\n","scripts-plugins":"Scripts und Plug-Ins bieten Ihnen Software-Verknüpfungen. Modellierung, Rendering, Texturieren - all dies einfacher gemacht werden kann Plug-In verwenden, die für alle Arten von Software wie Maya und V-Ray kommt.\n","space":"Der Raum ist eine Kategorie voller Low-Poly, Spiel-ready Modelle von Science-Fiction-{\"slug\": \"spaceship\",\"title\": \"Raumschiffe\"}, {\"slug\": \"asteroid\",\"title\": \"Asteroiden \"}, Planeten (einschlieÃlich {\"slug\": \"earth\",\"title\": \"Erde\"} und realistischen Raum {\"slug\": \"shuttle\",\"title\": \"Shuttles\"} für die wissenschaftlich geneigt 3D Raummodelle sind für VR Weltraum-Simulator-Spiele geeignet.\n","sport-hobby":"Diese Kategorie encompases alles, was bezieht {\"slug\": \"field\",\"title\": \"Feld\"} Veranstaltungen, Sport und Hobbys im Allgemeinen. Von {\"slug\": \"football\",\"title\": \"FuÃball\"} und Skipisten zu {\"slug\": \"guitar\",\"title\": \"Gitarre\"} und {\"slug\": \"piano\",\"title\": \"Piano\"}, sind diese nützlichen 3D Modelle für Anzeigen, Szenen und Animationen. Low-Poly-Versionen gibt es für Sportvideospiele.\n","textures":"Durchsuchen einer Bibliothek von schön gemacht 3D-Materialien und finden Sie die am besten geeignet, ready-to-use-Texturen \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e Spiel-ready \u003c/a\u003e oder fotorealistische Modelle, aktualisieren Sie Ihre Asset-Bibliothek herzustellen und 3D-Arbeiten verbessern.\n","various":"Dies sind die 3D Modelle, die nicht leicht in andere Kategorien gepasst haben, so dass wir eine erstellt, die sie alle akzeptieren würde. {\"title\": \"Rock\", \"slug\": \"rocks\"}, {\"slug\": \"clouds\",\"title\": \"Wolken\"}, {\"title\": \"Logo\", \"slug\": \"logo\"}, {\"title\" : \"Regenschirme\", \"slug\": \"umbrella\"} und andere nicht kategorisiert 3D Modelle sind hier.\n","vehicle":"Trucks, {\"title\": \"Krankenwagen\", \"slug\": \"ambulance\"}, Busse, Züge, Traktoren, {\"title\": \"Fahrräder\", \"slug\": \"bike\"} und Motorräder - Diese Kategorie ist für die Menschen, die ihre StraÃen der Stadt wollen mit realistischen und sci-fi-Fahrzeuge, und für diejenigen, die Simulationsspiele oder Formating Poster gefüllt werden.\n","watercraft":"Wasserfahrzeug Abdeckungen {\"title\": \"Boote\", \"slug\": \"boat\"}, {\"title\": \"Yachten\", \"slug\": \"yacht\"}, {\"title\": \"Schiffe\", \"slug\": \"ship\"} und andere Wasserfahrzeuge. Die manipulierten 3D Modelle werden gut daran tun in Videospiele, Animation während CG-Modelle gibt es für Ihre Szenen oder andere Anwendungen, bei denen visuelle Treue ist wichtiger als polycount.\n"},"printable":{"art":"Dies ist, wo der künstlerische 3D Druck gehen. Suche nach Phantasie Skulptur Design klassische Werke und Statuen historischer Persönlichkeiten neu zu erstellen, oder Figuren inspiriert, vielleicht sogar 3D-druckbare Logos? Das ist die Kategorie.\n","fashion":"Schöne und stilvolle Dinge, die Sie tragen können, sind in dieser Kategorie. Sehen Sie, wenn Sie eine Anwendung für Phantasie Raum Alter finden {\"slug\": \"footwear\",\"title\": \"Schuhe\"}, Neuheit Gläser und Cosplay {\"slug\": \"accessories\",\"title\": \"Zubehör\"} hier gefunden.\n","gadgets":"Alle {\"title\": \"iPhone\", \"slug\": \"iphone\"}, {\"title\": \"iPad\", \"slug\": \"ipad\"} (und andere intelligente Geräte) Fälle können in Gadget-Kategorie gefunden werden. Von der einfachen 3D-Add-ons, um komplexe Teile und \"Hacks\" für Ihre Artikel, dies ist die Kategorie für die Kreativen, und Liebhaber der Technik.\n","games-toys":"Spiele und Spielzeug sind die Kategorie druckbare 3D Alien oder Monster Miniaturen bedeckt, winzige {\"title\": \"Panzer\", \"slug\": \"tank\"}, flippig {\"slug\": \"chess\",\"title\": \"Schach\"} Stücke, Filmfigur Helme, Hobby Utensilien und Zubehör. Dies ist die To-Go Kategorie für alle Dinge geeky.\n","hobby-diy":"Wenn Sie unsere nächsten groÃen Erfinder und wollen Ihr DIY-Projekt erstellen oder einige Ersatzteile für Ihren {\"slug\": \"drone\",\"title\": \"Drohne\"} bekommen, ist dies der Ort zu sein. Darüber hinaus bietet es eine Menge Dinge für die Menschen, die ihre eigenen Figuren oder Plastikpistole Repliken machen wollen.\
16518n","house":"Allerlei Krimskrams sind hier zu finden. {\"title\": \"Lampen\", \"slug\": \"lamp\"}, künstlerisch {\"title\": \"Schalen\", \"slug\": \"bowl\"}, und alle Arten von {\"title\": \"Inhaber\", \"slug\": \"holder\"}, ob Sie nicht eine richtige Stelle für Ihr Telefon finden können, halten, um von Zahnstochern, Stapeln von Stiften oder Schmuck auf Ihrem Schreibtisch.\n","jewelry":"Schmuck ist, wo Sie gehen Armbänder und Anhänger oder Ringe mit Diamanten zu bekommen. Während 3D Drucker nicht gut genug ist Diamanten zu machen - noch - man kann immer noch einen Metallring als Basis für Ihre IT-Geek ring ausdrucken.\n","miniatures":"3D druckbare {\"title\": \"Zeichen\", \"slug\": \"character\"}, berühmt Leute, {\"title\": \"Sehenswürdigkeiten\", \"slug\": \"landmark\"}, Tiere, {\"title\": \"Männlich\", \"slug\": \"male\"}, {\"slug\": \"female\"}, {\"title\": \"Monster\", \"slug\": \"monster\"}, {\"title\": \"Aliens\",\"slug\": \"alien\"} - es ist alles hier. Egal, ob Sie Utility Vehicles sind Druck auf den Tisch legen oder Miniaturen für Tabletop-Spiele zu schaffen, ist es Ihre Kategorie.\n","science":"Was kann die Wissenschaft eingestuft werden? Nun, Modelle von Skelett {\"slug\": \"bones\",\"title\": \"Knochen\"}, Ãrzte {\"slug\": \"tools\",\"title\": \"Werkzeuge\"} und Astrophysik bezogene 3D druckbare Modelle, die in vielen Studienprozesse verwendet werden können.\n"}},"printable":{"art":"Dies ist, wo der künstlerische 3D Druck gehen. Suche nach Phantasie Skulptur Design klassische Werke und Statuen historischer Persönlichkeiten neu zu erstellen, oder Figuren inspiriert, vielleicht sogar 3D-druckbare Logos? Das ist die Kategorie.\n","fashion":"Schöne und stilvolle Dinge, die Sie tragen können, sind in dieser Kategorie. Sehen Sie, wenn Sie eine Anwendung für Phantasie Raum Alter finden {\"slug\": \"Schuhe\"}, Neuheit Gläser und Cosplay {\"slug\": \"Zubehör\"} hier gefunden.\n","gadgets":"Alle {\"title\": \"iPhone\", \"slug\": \"iphone\"}, {\"title\": \"iPad\", \"slug\": \"ipad\"} (und andere intelligente Geräte) Fälle können in Gadget-Kategorie gefunden werden. Von der einfachen 3D-Add-ons, um komplexe Teile und \"Hacks\" für Ihre Artikel, dies ist die Kategorie für die Kreativen, und Liebhaber der Technik.\n","games-toys":"Spiele und Spielzeug sind die Kategorie druckbare 3D Alien oder Monster Miniaturen bedeckt, winzige {\"title\": \"Panzer\", \"slug\": \"Tank\"}, flippig {\"slug\": \"Schach\"} Stücke, Filmfigur Helme, Hobby Utensilien und Zubehör. Dies ist die To-Go Kategorie für alle Dinge geeky.\n","hobby-diy":"Wenn Sie unsere nächsten groÃen Erfinder und wollen Ihr DIY-Projekt erstellen oder einige Ersatzteile für Ihren {\"slug\": \"Drohne\"} bekommen, ist dies der Ort zu sein. Darüber hinaus bietet es eine Menge Dinge für die Menschen, die ihre eigenen Figuren oder Plastikpistole Repliken machen wollen.\n","house":"Allerlei Krimskrams sind hier zu finden. {\"title\": \"Lampen\", \"slug\": \"Lampe\"}, künstlerisch {\"title\": \"Schalen\", \"slug\": \"Schüssel\"}, und alle Arten von {\"title\": \"Inhaber\", \"slug\": \"Inhaber\"}, ob Sie nicht eine richtige Stelle für Ihr Telefon finden können, halten, um von Zahnstochern, Stapeln von Stiften oder Schmuck auf Ihrem Schreibtisch.\n","jewelry":"Schmuck ist, wo Sie gehen Armbänder und Anhänger oder Ringe mit Diamanten zu bekommen. Während 3D Drucker nicht gut genug ist Diamanten zu machen - noch - man kann immer noch einen Metallring als Basis für Ihre IT-Geek ring ausdrucken.\n","miniatures":"3D druckbare {\"title\": \"Zeichen\", \"slug\": \"Zeichen\"}, berühmt Leute, {\"title\": \"Sehenswürdigkeiten\", \"slug\": \"Wahrzeichen\"}, Tiere, {\"title\": \"Male \", \"slug\": \"männlich\"}, {\"slug\": \"weiblich\"}, {\"title\": \"Monster\", \"slug\": \"Monster\"}, {\"title\": \"Aliens\",\"slug\": \"alien\"} - es ist alles hier. Egal, ob Sie Utility Vehicles sind Druck auf den Tisch legen oder Miniaturen für Tabletop-Spiele zu schaffen, ist es Ihre Kategorie.\n","science":"Was kann die Wissenschaft eingestuft werden? Nun, Modelle von Skelett {\"slug\": \"Knochen\"}, Ãrzte {\"slug\": \"Tools\"} und Astrophysik bezogene 3D druckbare Modelle, die in vielen Studienprozesse verwendet werden können.\n"},"titles":{"aircraft":"Flugzeug-3D-Modelle","animals":"Tier-3D-Modelle","architectural":"Architektur-3D-Modelle","car":"Auto-3D-Modelle","character":"Charakter-3D-Modelle","exterior":"AuÃen-3D-Modelle","food":"Lebensmittel-3D-Modelle","furniture":"Möbel-3D-Modelle","household":"Haushalts-3D-Modelle","industrial":"Industrielle 3D-Modelle","interior":"Innenraum-3D-Modelle","military":"Militär-3D-Modelle","plant":"Pflanzen-3D-Modelle","space":"Weltraum-3D-Modelle","textures":"CG-Texturen-3D-Modelle","vehicle":"Fahrzeug-3D-Modelle","watercraft":"Wasserfahrzeug-3D-Modelle"}},"title":{"cg":" 3D Modelle","print":" 3D-Druckdateien"}}
16518,"competition":{"digital-art-competition":{"categories":{"page_description":"in dem durch die Ãbermittlung Ihrer Werke Charakter Illustration, Character Konzept Design, Umwelt Illustration, Umwelt Konzept Design, Objektgestaltung und Objekt Konzept Design Kategorien CGTrader Digitalen Kunst-Wettbewerb teilnehmen. Wenn Sie mehrere groÃe Werke haben, die verschiedenen Kategorien passen, können Sie sie in die entsprechenden Kategorien einzureichen. Wählen Sie eine Kategorie, die Preise für diese Kategorie zu sehen."}}},"conversations":{"action_button_confirmation":"Möchten Sie diese Anfrage wirklich erneut öffnen?","reply_posted":"Antwort wurde veröffentlicht.","with_yourself":"darf nicht mit dem Absender identisch sein."},"date":{"month_names":[null,"Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"]},"devise":{"failure":{"too_many_requests":"Sie haben bereits eine E-Mail zum Zurücksetzen des Passworts angefordert. Bitte warten Sie einige Minuten, bevor Sie es erneut versuchen."}},"disabled_cookies_modal":{"button":"Stornieren","text_1":"Sie werden Millionen von groÃen 3D-Modelle zu erforschen, fügen Sie sie in den Warenkorb gelegt oder kaufen nicht in der Lage sein.","text_2":"Wenn Sie völlig CGTrader erleben wollen, empfehlen wir
16518Cookies auf dieser Website ermöglicht.","title":"Es scheint, dass Sie Cookies in Ihrem Browser deaktiviert haben"},"emails":{"error_notification":"Abonnement nicht gefunden.","success_subscribed_notification":"Sie haben sich erfolgreich angemeldet.","success_unsubscribed_notification":"Sie haben sich erfolgreich abgemeldet."},"errors":{"messages":{"invalid_vat":"ist keine gültige %{country_adjective} USt-IdNr.","vies_down":"Die USt-IdNr. kann nicht überprüft werden: der VIES-Webservice ist nicht verfügbar. Bitte später noch einmal versuchen."}},"file_size_validator":{"errors":{"invalid_carrierwave":"Es wurde ein CarrierWave::Uploader::Base-Objekt erwartet","invalid_key":":%{key} muss eine nicht negative ganze Zahl sein","range_format":":in und :within müssen ein Bereich (Range) sein","range_unspecified":"Bereich nicht angegeben. Geben Sie die Option :within, :maximum, :minimum oder :is an."}},"file_type":{"default_error":"Kein Dateipfad angegeben."},"footer":{"bottom-row":{"privacy":"Datenschutz","terms-link":"Allgemeine Geschäftsbedingungen"},"links":{"buyLinks":[{"text":"3D-Modelle kaufen","link":"/de/3d-modelle"},{"text":"Für Unternehmen","link":"/discover/business-account"},{"text":"Kostenlose 3D-Datensätze","link":"/discover/datasets"},{"text":"3D-Designer beauftragen","link":"/3d-modeling-jobs"},{"text":"Kostenlose 3D-Modelle","link":"/de/frei-3d-modelle"},{"text":"Kostenlose 3D-Druckmodelle","link":"/de/frei-3d-druck-modelle"}],"communityLinks":[{"text":"Community","link":""},{"text":"Top-Designer","link":"/designers"},{"text":"Challenges","link":"/challenges"},{"text":"Forum","link":"/forum"}],"companyLinks":[{"text":"Unternehmen","link":"/discover/about-us"},{"text":"Blog","link":"/blog"},{"text":"Karriere","link":"/pages/careers"},{"text":"Hilfecenter","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"3D-Modelle verkaufen","link":"/discover/sell-3d-models"},{"text":"Steigern Sie Ihre Verkäufe","link":"discover/sell-more"},{"text":"3D-Markteinblicke","link":"/discover/3d-market-trends"},{"text":"Top 3D-Modellsuchen","link":"/discover/3d-models-top-searches"},{"text":"Top 3D-Drucksuchen","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"Abonnieren","button-disabled":"Gezeichnet","header":"Abonnieren Sie unsere Nachrichten:","placeholder":"Geben sie ihre E-Mail Adresse ein","terms-link":"Nutzungsbedingungen","text":"Mit der Anmeldung bestätigen Sie, dass Sie gelesen haben und akzeptieren Sie unsere"}},"general":{"description":"CGTrader ist ein Online-Marktplatz, auf dem 3D-Künstler und Designer können, verkaufen oder teilen Sie 3D Modelle kaufen. Es wurde gegründet und wird von einem Team von 3D-Designern und Ingenieuren entwickelt. Unser Ziel ist es 3D-Aktienmarkt demokratisieren und die Art und Weise ändern, wie wir 3D Modelle online zu verkaufen. Indem Autoren maximale Lizenzgebühren verdienen, sind wir bestrebt, ihre Motivation und erhöhen die Qualität der 3D Modelle zu erhöhen.","navigation":{"buy_3d_models":"Kaufen 3D Modelle","sell_3d_models":"Verkaufen Sie 3D Modelle"},"search_placeholder":"Suche in mehr als 2 Millionen Modellen","site-search__field":"%{model_count} 3D-Modelle durchsuchen","site_title":"3D-Modell-Speicher","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"Lassen Sie KI Ihre Träume verwirklichen","subtitle":"Verwandeln Sie einen Prompt oder ein Referenzbild in ein produktionsfertiges 3D-Modell â verfeinern, retexturieren und exportieren Sie es in dem Format, das Sie benötigen."},"faq":{"heading":"Häufig gestellte Fragen","items":{"commercial":{"answer":"Die kommerzielle Nutzung Ihres 3D-%{object}-Modells ist mit einem kostenpflichtigen CGTrader AI-Plan möglich. Bitte lesen Sie die CGTrader Allgemeinen Geschäftsbedingungen für die geltenden Lizenzbedingungen für KI-generierte Modelle.","question":"Kann ich das generierte %{object}-Modell für kommerzielle Zwecke nutzen?"},"formats":{"answer":"Die 3D-Modelle von %{object} sind in den Formaten GLB, FBX, OBJ, STL oder USDZ verfügbar.","question":"In welchem Dateiformat erhalte ich mein %{object}-Modell?"},"no_skills":{"answer":"Keine Kenntnisse in der 3D-Modellierung erforderlich. Die gesamte Modellierung erfolgt über den %{object}-Modell-Generator. Das System verwaltet Geometrie, Proportionen und Struktur basierend auf Ihrem Prompt oder hochgeladenen Bild. Auch Anfänger können in wenigen Minuten ein umfassendes 3D-%{object}-Modell erstellen.","question":"Sind Kenntnisse in der 3D-Modellierung für einen %{object}-Modell-Generator erforderlich?"},"what_is":{"answer":"Der CGTrader 3D-%{object}-Modell-Generator, ein KI-basiertes Tool, erstellt ein dreidimensionales %{object}-Modell aus schriftlichen Anweisungen oder Referenzbildern. Er analysiert Ihre Idee und erstellt ein herunterladbares Modell für Design, Prototypen und Visualisierung. Unsere kostenpflichtigen Abonnements bieten höhere monatliche Limits.","question":"Was ist ein 3D-%{object}-Modell-Generator?"},"why_cgtrader":{"answer":"CGTrader bietet eine reibungslose Erfahrung, schnelle Verarbeitungszeiten und qualitativ hochwertige 3D-Ausgaben. Dieses Tool eignet sich für Profis und Anfänger, die eine zuverlässige Lösung für die Erstellung von 3D-%{object}-Modellen suchen.","question":"Warum den KI-%{object}-Generator von CGTrader nutzen?"}}},"h1":"KI-%{object}-3D-Modell-Generator","hero_alt":"KI-%{object}-3D-Modell-Generator","hero_height":617,"hero_width":1080,"how_to":{"heading":"%{object} aus Bild- oder Textprompts generieren","paragraphs":["Es ist sehr einfach, ein dreidimensionales %{object}-Modell zu gestalten. Klicken Sie in der linken Seitenleiste oben links auf die Schaltfläche, um Ihr %{object}-Bild hochzuladen und ein 3D-Modell zu erstellen. Sie können auch einen Prompt im Feld âBesc
16518hreiben Sie, was Sie erstellen möchten\" unten eingeben. CGTrader AI verfeinert Ihren Prompt automatisch, sodass eine kurze Beschreibung ausreicht.","Die rechte Seitenleiste bietet Ihnen umfangreiche Kontrolle über Ihr 3D-%{object}-Modell. Wählen Sie Einstellungen wie Mesh-Typ, Material, Prompt-Führung und Dateiformat. Sie können Ihr %{object}-Modell auch texturieren. Klicken Sie nach Eingabe Ihrer Text- oder Bildinstruktionen auf âGenerieren\". Das Tool verarbeitet Ihre Eingabe in wenigen Minuten, abhängig von Systemlast, Material, Mesh-Typ, Formen, Seed-Werten und Qualität."],"steps":["Geben Sie Ihre Textbeschreibung ein und/oder fügen Sie ein Referenzbild hinzu, um die Genauigkeit Ihres 3D-%{object}-Modells zu verbessern.","Wählen Sie eines unserer Voreinstellungen oder eine KI-Engine, geben Sie eine benutzerdefinierte Polygonanzahl an und wählen Sie den Materialtyp für Ihr 3D-%{object}-Modell.","Klicken Sie auf âGenerieren\", um ein 3D-%{object}-Modell aus Ihrem Prompt und/oder Referenzbild zu erstellen.","Laden Sie Ihr erstelltes 3D-%{object}-Modell in verschiedenen Formaten herunter (GLB, FBX, OBJ, STL oder USDZ)."]},"intro":"Suchen Sie nach einer einfachen und schnellen Möglichkeit, in wenigen Minuten ein hochwertiges 3D-%{object}-Modell zu erstellen? Unser fortschrittlicher 3D-%{object}-Modell-Generator, CGTrader AI, kann schriftliche Befehle oder Referenzbilder in vollständig funktionierende Modelle umwandeln. Er basiert auf führenden 3D-Generierungs-Engines, darunter Meshy, Hunyuan und Tripo3D. Damit können sowohl Anfänger als auch Experten schnell 3D-Modelle für Visualisierung, Experimente und Prototypen erstellen. Er unterstützt Text-zu-3D und Bild-zu-3D und ist mit 3D-Druckern kompatibel. Sie können ein Bild im JPG- oder PNG-Format hochladen oder eine Beschreibung als Text eingeben. CGTrader AI übernimmt alle weiteren Schritte für Sie.","meta_description":"KI-%{object}-3D-Modell-Generator von CGTrader âï¸ Erstellen Sie detaillierte 3D-%{object}-Modelle aus Text oder Bildern. Jetzt kostenlos starten.","primary_cta":"Jetzt kostenlos generieren","title":"KI-%{object}-3D-Modell-Generator (kostenlos) | CGTrader"}}},"rules":{"errors":{"front_view_required":"Ein Bild der Vorderansicht ist erforderlich."}}},"home":{"index":{"3D-projects":{"info-section__cta":"Erfahren Sie mehr","info-section__description":"Wo Menschen mit spannenden 3D Projekten erfüllen talentierte 3D Designer","info-section__heading_html":"\u003cStrong\u003e 3D Projekte \u003c/strong\u003e Freier Hub"},"categories-conatainer":{"browse_all":"Alle Modelle durchsuchen","browse_all_tooltip":"Durchsuchen Sie alle 3D Modelle","discounts":"Rabatte"},"cgdream":{"cta":"Fangen Sie kostenlos an!","heading_html":"\u003cstrong\u003eEntdecke CGDream,\u003c/strong\u003e\u003c/br\u003e wo KI auf 3D-Modelle trifft.","text_html":"\u003cstrong\u003e CGDream \u003c/strong\u003e ist eine modernste Anwendung, die die Leistung generativer KI- und 3D-Modelle nutzt, um atemberaubende 2D-Bilder zu erzeugen. \u003cstrong\u003e Ihre kreative Reise beginnt jetzt. \u003c/strong\u003e"},"community":{"info-section__cta":"Trete der Community bei","info-section__heading_html":"Registriert CGTrader \u003cstrong\u003e Community \u003c/strong\u003e","info-section__icon-list_1":{"description":"Präsentieren Sie Ihre besten macht, erhalten Feedback und Anerkennung","heading":"Galerien"},"info-section__icon-list_2":{"description":"Lernen Sie neue Fähigkeiten und andere lehren,","heading":"Tutorials"},"info-section__icon-list_3":{"description":"Finden Tutorials und diskutieren andere 3D Fragen","heading":"Forum"}},"covid":{"timer-strip__item":"Kostenlose 3D Druck-Ressourcen für COVID-19 Schutz","timer-strip__item--button":"Durchsuchen 3D Modelle"},"enterprise":{"info-section__cta":"Erfahren Sie mehr","info-section__heading_html":"3D Dienste für die \u003cstrong\u003e Unternehmen \u003c/strong\u003e","info-section__icon-list_1":"Wir können für Sie die AR-Implementierung tun","info-section__icon-list_2":"Mehr Conversions Umsatz weniger Produktrück","info-section__icon-list_3":"Qualität gewährleistet mit strengem QA"},"header":"3D Modelle für VR / AR, 3D Druck und Computergrafik","marketplace":{"info-section__description":"Wählen Sie aus %{models_count} 3D Modelle für Anwendungen wie Spiele, AR / VR, Werbung, Animation, Kino und 3D Druck","info-section__heading_html":"3D-Modelle-\u003cstrong\u003eMarktplatz\u003c/strong\u003e","info-section__image-list_1":{"de
16518scription":"Kaufen Sie professionelle 3D Modelle für Ihr Projekt","heading":"3D Modelle"},"info-section__image-list_2":{"description":"Low-Poly-PBR 3D Modelle bereit für die Videospiele, VR \u0026 AR Echtzeitanwendungen","heading":"Low-Poly-PBR 3D Modelle"},"info-section__image-list_3":{"description":"Finden 3D Druck-Design für Ihren 3D Drucker","heading":"3D Druck modelle"},"view_all":"Alle"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"Verwandeln Sie ein Bild in ein 3D-Modell","title":"Bild zu 3D"},"text_to_3d":{"description":"Beschreiben Sie Ihre Idee, um ein 3D-Modell zu erstellen","title":"Text zu 3D"}},"ai_section_title":"Mit KI erstellen","aria_label":"Suchvorschläge","columns":{"cg":{"search_label":"In 3D-Modellen suchen","title":"3D-Modelle"},"print":{"search_label":"In 3D-Druck suchen","title":"3D-Druckmodelle"}}},"sell":{"info-section__heading_html":"\u003cStrong\u003e Verkauf \u003c/strong\u003e Ihre 3D Modelle und Finden freie Projekte","info-section__icon-list_1":{"description":"Verkaufen Sie Ihre 3D Modelle und verdienen bis zu 80% Lizenzgebühren","link":"Verkaufen Sie 3D Modelle"},"info-section__icon-list_2":{"description":"Arbeiten mit Unternehmenskunden","link":"Holen Qualified"},"info-section__icon-list_3":{"description":"Lagern Sie Ihre Fähigkeiten und erhalten Sie bis zu 95% Lizenzgebühren","link":"Durchsuchen 3D Modellierung Jobs"},"info-section__icon-list_4":{"description":"Bauen Sie Ihr Portfolio und sichtbar","link":"Durchsuchen 3D Designer"}},"seo":{"description":"Entdecken Sie über 2 Millionen 3D-Modelle online für Druck-, Spiel-, VR/AR- und Designprojekte. Laden Sie herunter, passen Sie an oder beauftragen Sie 3D-Experten - alles auf CGTrader.","title":"CGTrader - 3D-Modelle und 3D-Druck-Marktplatz"}}},"homepage":{"budget_counter":{"range_0_10":"Unter 10 $","range_10_20":"10 $ - 20 $","range_20_15000":"Mehr als 20 $"},"quotes":{"quote_0":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Senken Sie Provisionen von den Verkäufern Mittel bessere Preise für die Käufer gemacht. Schauen Sie sich und vergleichen Sie die Preise bei CGTrader und die anderen Geschäfte."},"quote_1":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Der auffälligste Vorteil CGTrader ist Flat-Fee-Aktivierungssystem, das uns hohe Erträge liefert. Sie sind nicht eine Provision Prozentsatz unseres Umsatzes nehmen. Nach dem Verkauf erhalten wir das 100% des Preises. Nur wenn wir dieses Produkt verkaufen fortsetzen wollen, können wir es wieder zu aktivieren wieder um $ 5 bezahlen. Elegante Lösung."},"quote_10":{"author":{"name":"Threed Ken","username":"3dken"},"text":"Das Pauschalgebühr-Aktivierungssystem ist ausgeklügelte. Ich frage mich, warum niemand von diesem vorher gedacht hatte. Nach dem Verkauf zahlt eine geringe Gebühr für ein Produkt und das ist es zu aktivieren. Der Verkäufer ist in der vollen Kontrolle."},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Es gibt zwei Dinge, die ich am meisten über CGTrader mögen. Erstens gibt es keine versteckten hier etwas bedeutet. Sie müssen nicht mit CGTrader vorsichtig sein. Zweitens ist dieser Speicher durch die Künstler und für die Künstler. Sie verstehen Sie besser. Etwas stört Sie hier ... sie wissen lassen, und sie sorgen dafür, dass Sie sich hier wohlfühlen."},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Flat-Fee-Aktivierungssystem ist die beste! (Zumindest habe ich nicht über alles kommen besser als diese). Es ist sehr realistisch und fair gegenüber den Verkäufern. Sie kümmern sich nicht, wie viel Gewinn Sie machen, nur die feste Miete zahlen. Aber wenn Sie keinen Umsatz, Sie müssen auch nicht die Miete zahlen. Messe CG Handel ist hier!"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"CGTrader zieht Kunden selbst aus Entwicklungsländern, weil die Preise sind günstiger als auf anderen Geschäften. Zur gleichen Zeit können Autoren mehr verdienen, weil es nicht so etwas wie hohe Provisionssätze ist. Es ist ein richtiger Weg, um die Arbeit von 3D-Künstler zu schätzen."},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"Intuitive Schnittstelle des Verlegers und innovative Tools wie Tag-Empfehlung und flexible Beschreibungsformen macht den Publishing-Prozess einfach und schnell."},"quote_15":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTrader Ansatz von 3D-Verkauf ist anders und hat nichts gemein mit anderen Geschäften ich zu verkaufen verwendet. Zahlt eine geringe Gebühr von $ 5 nach dem Verkauf ist eine groÃartige Idee und lassen Sie mich zum besten Preis hier bieten. Kunde und Künstler sind mit dieser Arbeitsweise profitieren."},"quote_16":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"Das Upload-System ist einfach und klar. Es ist gut zu wissen, dass hinter dem Projekt sind die Menschen mit langjähriger Erfahrung in der Computer-Grafik-Angelegenheiten. Immer hatte ich ein Problem, festen CGTrader Team es schnell."},"quote_17":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTrader erlaubt es mir, mein Profil mit meiner persönlichen Webseite zu verknüpfen. Kunden können mit mir Kontakt auf, wenn sie sich nicht sicher über ein Merkmal eines Postens sie kaufen möchten oder einfach nur eine Modifikation davon wollen. Es ist wie ein persönlichen 3D-Speicher in einem groÃen Mar
16518kt zu besitzen!"},"quote_2":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Wir haben eine groÃe und reaktionsschnelle Unterstützung von CGTrader Team genossen. Das Personal freundlich bot die Veröffentlichung aller Modelle für uns zu tun, was eine groÃe Hilfe für den professionellen Verkäufer ist."},"quote_3":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Auf dieser Plattform können wir viel bessere Preise für unsere Kunden bieten. Zum Beispiel sind alle unsere Produkte 20% niedriger als anderswo günstig und wir noch mehr Gewinn bekommen im Vergleich zu anderen Geschäften!"},"quote_4":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"Dies ist das beste System auf dem neuesten Stand. Alle anderen 3D-Online-Shops nehmen% unserer Gewinne. Dies war das Merkmal, dass unser Interesse an CGTrader von Anfang an gefangen. Kunden, den Kauf auf CGTrader, wissen, dass der gröÃte Teil ihres Geldes gehen an den Autor, der am Ende wird mehr und bessere Modelle, wenn ihre Gewinne verbessern machen."},"quote_5":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"CGTrader ist der 3D-Online-Shop, die den am schnellsten wachsenden Umsatz und Gewinn für uns. Das Flat-Fee-Aktivierungssystem ist das Beste, was Sie finden können, wie es Content-Ersteller statt Mittelsmann belohnt."},"quote_6":{"author":{"name":"RiÄardas Marozas","username":"Pumper"},"text":"Als ich $ 160 auf mein Paypal-Konto empfing, wusste nicht, was los ist, wie es noch nie passiert, aber dann dachte ich, dass es ein CGTrader Verkauf sein könnte und ich habe recht. Verkaufte die gleiche Packung auf Turbosquid im letzten Monat für $ 189, aber nach 40% Lizenzgebühr und 30% MwSt, alles, was ich bekam, war $ 52,92 - ein paar Cent auf $ 160 von CGTrader verglichen. Plus der Kunde bezahlt $ 29 weniger - nun, das ist ein richtiges Geschäft."},"quote_7":{"author":{"name":"Threed Ken","username":"3dken"},"text":"Am Anfang war ich skeptisch, was so ein gutes Geschäft für Verkäufer, die nicht die Norm für die groÃen 3D-Online-Shops ist. Wenn ich über die Flat-Fee-Aktivierungssystem gelernt, wurde ich von einem solchen kreativen Art und Weise beeindruckt digitale Assets zu verkaufen. Verkauf, aktiviert dann durch eine $ 5 Gebühr zahlen. Das alles macht Sinn für mich. Ich lud ein paar ausprobieren und wirklich, als ich meinen ersten Verkauf bekam, war es 100% Lizenzgebühren!"},"quote_8":{"author":{"name":"Threed Ken","username":"3dken"},"text":"Ich war so verwendet, um viele andere Websites, die Ladung zwischen 30% - 60% Provision, bis ich CGTrader entdeckt. Als Verkäufer, ich auf jeden Fall wie der hohe Anteil an Lizenzzurückkehrt."},"quote_9":{"author":{"name":"Threed Ken","username":"3dken"},"text":"Der Verkäufer Erfahrung ist fantastisch. Produkt-Vorlage ist ein Kinderspiel. Und ja, das System erlaubte mir jede Stufe der Art und Weise einen Entwurf meiner Produkt-Vorlage zu speichern."}}},"hyperwallet":{"failed_payment_agreement":"Etwas Unerwartetes ist passiert","success_notification":"Die Zahlungsvereinbarung wurde erfolgreich aktualisiert.","success_payment_agreement":"Die Zahlungsvereinbarung wurde erfolgreich übermittelt."},"item-search-filters":{"3d-models-url":"3d-modelle","3d-print-models-url":"3d-druck-modelle","dedicated-search-page-url":{"animated":"/animierte-","free":"/frei-","low_poly":"/low-poly-","pbr":"/pbr-","rigged":"/manipulierten-"}},"item_use_case":{"not_valid":"Ungültige Datei","pundit":{"not_authorized":"Sie sind nicht berechtigt, diese Aktion auszuführen."},"title":"Anwendungsfall für %{item_name}"},"items":{"already_purchased":"Sie haben diesen Artikel bereits gekauft.","filters":{"attributes":"Attribute","free":"Frei","max_value":"$ 500 +","min_value":"$ 2","reset":"Filter zurücksetzen"},"footer":{"next":"Nächster","per_page":"Pro Seite:","previous":"Bisherige"},"geometry_type_forbidden":"Geometrietyp verboten!","last_card":{"button_text":"Fordern Sie ein individuelles 3D-Modell","text":"Kann nicht das finden, was Sie suchen?"}
16518,"migrations":{"errors":{"invalid_owner":"Der neue Besitzer kann keine Artikel übernehmen.","unpublished_items":"Alle Artikel müssen veröffentlicht sein."}},"new_price_applied":"Neue Preise wurden erfolgreich auf alle Artikel angewendet.","new_price_applied_to_selected_items":"Neue Preise wurden erfolgreich auf die ausgewählten Artikel angewendet.","new_prices_to_filtered_models":"Neue Preise wurden erfolgreich auf alle gefilterten Artikel angewendet.","order_processed":"Bestellung bearbeitet.","order_processing":"Bestellung wird bearbeitet.","something_went_wrong":"Etwas ist schiefgelaufen","title_error":"Der Titel darf keine nicht-lateinischen Zeichen enthalten","uniq_user":"hat bereits einen Anwendungsfall für diesen Artikel eingereicht","upload_error":"Upload-Fehler.","validate_license_for_zero_price":"ist für kostenlosen Artikel ungültig","validate_minimum_price":"Preisangebote dürfen nicht unter dem Minimum von 50 % des ursprünglichen Preises liegen","verify_printable_formats_error":"Bitte laden Sie mindestens eine .stl-, .obj- oder .wrl-Datei hoch.","you_can_not_delete_models":"Sie können keine Modelle löschen"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projects macht es einfach, hochwertige freiberufliche 3D-Künstler zu engagieren und all Ihre Modellierungsherausforderungen zu lösen.","heading_html":"Lernen Sie die beste Freelancer-Plattform für Ihre \u003cstrong\u003e3D-Modellierungsaufträge\u003c/strong\u003e kennen"},"sections":{"call_to_action":{"description":"Veröffentlichen Sie Ihr Projekt kostenlos und sehen Sie, wie einfach es ist, Ihre nächste Modellierungsherausforderung mit 3D-Projekten zu lösen.","title":"Stellen Sie heute die besten 3D-Talente ein!"},"freelancer_selection":{"title":"Machen Sie Ihr nächstes 3D-Projekt zum Erfolg","widest_selection":{"description":"Geben Sie sich nicht mit weniger zufrieden. Mit 40.000 freiberuflichen 3D-Designern ist CGTrader die gröÃte Plattform, um Sie mit qualifizierten Spezialisten zu verbinden: Modellierer, Animateure, Rigger, 3D-Druck-Experten und viele mehr.","title":"GröÃte Auswahl an 3D-Freelancern"}},"how_it_works":{"steps":{"describe":{"description":"Sagen Sie uns, was Sie brauchen. Verwenden Sie unser einfaches Formular, fügen Sie Bilder hinzu und veröffentlichen Sie Ihr Freelance-Angebot in wenigen Minuten.","title":"Beschreiben Sie Ihr Projekt"},"pay":{"description":"Zahlen Sie das Budget sicher im Voraus an CGTrader und lassen Sie Ihren Freelancer wissen, dass Sie startbereit sind. Chatten Sie, teilen Sie Anhänge und verfolgen Sie den Projektfortschritt bequem in Ihrem Arbeitsbereich. Geben Sie die Zahlung frei, wenn Sie mit dem Endergebnis zufrieden sind.","title":"Zahlen Sie für das Ergebnis"},"select":{"bullets":["Erhalten Sie Angebote von qualifizierten Designern direkt in Ihrem Posteingang","Chatten Sie in Echtzeit mit Designern","Durchsuchen Sie deren frühere Projekte","Sie können auch nach 3D-Fähigkeiten, Bewertungen und Software- oder Formatpräferenzen suchen, filtern und Freelancer einladen"],"title":"Wählen Sie den besten Freelancer aus"}},"title":"Erledigen Sie Ihren Job in 3 einfachen Schritten"},"payment_quality":{"description":"CGTrader stellt sicher, dass die freiberuflichen Dienstleistungen Ihre Anforderungen erfüllen und rechtzeitig geliefert werden. Unser QA-Team steht Ihnen jederzeit zur Verfügung.","title":"Qualität garantiert"},"secure_payments":{"description":"Unser Treuhandservice bedeutet, dass Ihr Geld geschützt ist und Sie nur zahlen, wenn Sie mit dem Endergebnis zufrieden sind.","title":"Sichere Zahlungen"},"workspace_convenience":{"description":"Vergessen Sie die Frustration, zwischen Tabs und verschiedenen Tools wechseln zu müssen. Mit dem dedizierten Arbeitsbereich können Sie alles an einem Ort verwalten: mehrere Projekte, Rechnungen, Unterhaltungen, Dateifreigabe und mehr.","title":"Bequemlichkeit auf einem einzigen Bildschirm"}},"shared":{"post_project_cta":"Projekt veröffentlichen"}},"navigation":{"find_jobs_cta":"3D-Jobs finden","hire_freelancers_cta":"3D-Freelancer einstellen","how_
16518it_works":"Wie es funktioniert","why_projects":"Warum 3D-Projekte"}},"agreed_to_terms_of_use":"Sie müssen den Geschäftsbedingungen von 3D Projects zustimmen, um fortzufahren.","budget_error_message":"ist zu hoch","check_designer_uniqueness_error":"Designer können nur einmal eingeladen werden","check_ownership_error":"Der Einladende ist nicht der Eigentümer des Projekts","check_status_error":"Designer können nur zu genehmigten Projekten eingeladen werden.","deadline_error_message":"Die Frist muss in der Zukunft liegen","discount_code_error":"Entschuldigung, der Rabattcode existiert nicht oder ist abgelaufen.","email_subject":"3D-Projektchance: %{subject}","error_check_application_uniqueness":"Sie können sich nur einmal bewerben","error_check_applier":"Sie können sich nicht auf Ihr eigenes 3D-Projekt bewerben","error_check_job_availability":"Benutzer ist nicht berechtigt, sich zu bewerben","error_check_job_status":"Projektbewerbungen sind ausgesetzt, bis unser neuer Moderationsprozess abgeschlossen ist, in der Regel innerhalb von 3 Werktagen. Vielen Dank für Ihr Verständnis!","modeling_request_failed":"Modellierungsanfrage fehlgeschlagen!","offer_has_been_sent":"Danke, Ihr Angebot wurde gesendet!","offer_is_closed":"Das Angebot ist geschlossen.","payment_successful":"Zahlung erfolgreich abgeschlossen.","payment_under_review":"Die Zahlung wird überprüft.","share_with_yourself_error":"Das Teilen von âHire Meâ-Vorlagen mit sich selbst ist nicht erlaubt","system_messages":{"buyer_cancels_job":"Das Projekt wurde storniert und in den Reiter %{archive_url} verschoben.","buyer_edits_hire_me_template":"Projektdetails wurden vom Kunden aktualisiert.","buyer_edits_job_details":"Projektdetails wurden aktualisiert.","buyer_marks_job_as_finished":"Projekt wurde als abgeschlossen markiert und in den Reiter %{archive_url} verschoben.","buyer_marks_job_as_finished_with_resell":"Kunde hat das Projekt als abgeschlossen markiert und erlaubt Ihnen, die Ergebnisse auf CGTrader zu verkaufen. Stellen Sie sicher, dass Sie das erstellte Modell \u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003ehochladen\u003c/a\u003e\u003c/b\u003e!","buyer_negotiates":"Kunde hat Ihr Preisangebot verhandelt.","buyer_pays_for_the_job":"Projekt wurde vorausbezahlt und in den Reiter %{in_progress_url} verschoben.","designer_accepts_changes":"Designer hat die aktualisierten Details überprüft.","designer_accepts_offer":"Designer hat Ihr Angebot angenommen.","designer_edits_offer":"Designer hat sein Angebot bearbeitet.","designer_negotiates":"Designer hat Ihr Angebot verhandelt.","designer_withdraws_offer":"Designer hat sein Angebot zurückgezogen.","job_expires":"Projekt ist abgelaufen und wurde in den Reiter %{archive_url} verschoben."},"template_error":"Es wurden keine Projekte erstellt!","user_not_exists":"Benutzer mit diesem Benutzernamen existiert nicht.","want_that_job":"Ich will diesen Job!"},"kodama":{"invalid_request":"Ungültige Anfrage!"},"landing":{"consent_not_saved":"Die Zustimmung wurde nicht gespeichert","failure_notification":"Alle erforderlichen Felder des API-Zugriffsantrags müssen gültig sein.","success_notification":"Vielen Dank für Ihre Anfrage. Wir werden Sie in Kürze kontaktieren."},"layout":{"chunk_load_notice":"Beim Laden dieser Seite ist ein Fehler aufgetreten. Bitte lade die Seite neu.","cookies_policy":{"accept":"Akzeptieren","learn_more":"Mehr erfahren","text":"Unsere Website verwendet Cookies statistische Besucherdaten und Track Interaktion mit Direktmarketing-Kommunikation / Verbesserung unserer Website zu sammeln und Ihren Browser-Erfahrung verbessern. Bitte beachten Sie unsere Cookie-Hinweis für weitere Informationen über Cookies, Daten, die sie sammeln, die sie zugreifen können, und Ihre Rechte."},"translations_notice":{"cta":"Wechseln zu English","text":"Hallo! Wir übersetzen CGTrader. Ãbersetzungen sind im Gange und einige Abschnitte sind möglicherweise nicht auf Deutsch verfügbar."}},"model":{"already_purchased":"Sie haben dieses Produkt bereits gekauft. Sie können es von Ihrem \u003ca href='/profile/cart/purchased'\u003eWarenkorb\u003c/a\u003e herunterladen. Falls gewünscht, können Sie es erneut kaufen.","animated":"Animiert","artist_profile":"Künstlerprofil","author":"Autor","author_get_your_payment":"Der Autor erhält 100% Ihrer Zahlung. CGTrader ermöglicht Künstlern, maximale Einnahmen zu erzielen und motiviert sie, hochwertige Inhalte zu verkaufen.","author_products":"Weitere Produkte von \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e","authorised_seller":"Autorisierter Verkäufer bei CGTrader","authority":"Autorität","breadcrumb":{"3d_models":"3D-Modelle","home":"Startseite"},"bulk_download":{"download_all":"Alle Dateien herunterladen","files_included":{"one":"%{count} Datei enthalten","other":"%{count} Dateien enthalten"},"too_large":"Dieses Modell ist zu groÃ, um es als ein Archiv herunterzuladen (über %{limit}). Bitte laden Sie die Dateien einzeln herunter."},"buy":"Kaufen","cannot_download":"Nur Nutzer mit %{experience_needed} Rufpunkten können mehr als %{models} kostenlose Modelle herunterladen. Erfahren Sie mehr über Level und Reputation, indem Sie \u003ca href='%{reputation_url}' target='_blank'\u003ehier klicken\u003c/a\u003e.","collection":"3D-Paket","contact_author":"Autor kontaktieren","description":"Beschreibung","download":"Herunterladen","download_limit_exceeded":"Sie haben Ihr tägliches Download-Limit
16518überschritten. Bitte versuchen Sie es morgen erneut. Dieses Limit gilt nicht für Nutzer, die in den letzten 12 Monaten einen Kauf getätigt haben.","download_modal":{"chat_with_us":"Chat mit uns","contact_support":"Bitte kontaktieren Sie uns über den Chat.","download_file":"%{name} herunterladen","empty":"Es wurden keine Dateien gefunden","generic_error":"Etwas ist schiefgelaufen, bitte versuchen Sie es erneut","link_error":"Es tut uns leid, aber mit Ihrem Download-Link scheint es ein kleines Problem zu geben.","pbr_ready":"PBR-fähig","preparing":"Ihr Download wird vorbereitet...","title":"Dateien herunterladen"},"format_downloads":"3D-Software-Format-Downloads","game_ready":"Spielbereit (Low-Poly)","geometry":"Geometrie","license":"Lizenz","make_offer":"Angebot machen","materials":"Materialien","messages":{"no_files":"Keine hochgeladenen Dateien","no_rating":"Für dieses Modell ist noch keine Bewertung verfügbar"},"model_details":"3D-Modell-Details","pbr_textures":"PBR-Texturen","plugin_used":"Verwendetes Plugin","polygons":"Polygone","price":"Preis","print_ready":"3D-Druckbereit","product_id":"Produkt-ID","product_support":"Produktsupport","product_type":"Produkttyp","published":"Veröffentlicht am","rated":{"error":"Sie haben dieses Modell bereits bewertet","success":"Danke für Ihre Bewertung dieses Modells"},"rating":"3D-Modell-Bewertung","ratings":{"desc":{"negative":"Nutzer, die dieses 3D-Modell gekauft haben, halten es für minderwertig","positive":"Nutzer, die dieses 3D-Modell gekauft haben, halten es für hochwertig"},"negative":"Negativ","positive":"Positiv"},"recently_viewed_models":"Kürzlich angesehene Modelle","renderer":"Renderer","report":"Melden","rigged":"Geriggt","scripts-plugins":"Skripte und Plugins","similar_models":"Ãhnliche Modelle","statistics":"Statistiken","subscription":{"limit_reached":"Sie haben das Download-Limit für diesen Abrechnungszeitraum erreicht.","limit_reached_detailed":"Sie haben Ihr Download-Limit von %{limit} für diesen Monat erreicht. Ihr Limit wird am %{reset_date} zurückgesetzt. Um jetzt weitere Modelle herunterzuladen, können Sie diese einzeln kaufen.","limit_reached_detailed_no_date":"Sie haben Ihr Download-Limit von %{limit} für diesen Monat erreicht. Um jetzt weitere Modelle herunterzuladen, können Sie diese einzeln kaufen."},"tags":"Tags","textures":"Texturen","title":"%{item_title} 3D-Modell","unwrapped_uvs":"Entpackte UVs","uv_mapping":"UV-Mapping","vat_notice":"Alle Preise sind exklusive Mehrwertsteuer","version":"Version","vertices":"Scheitelpunkte","vr":"VR-Modelle"},"models":{"error":{"cannot_be_blank":" darf nicht leer sein."}},"navigation":{"3d-models":{"3d-printing":"3D Druckdateien","discounts":"Rabatte","find_designers":"Finden Sie Die Besten Designer","free":"Kostenlose 3D Modelle","pbr":"PBR","scanned_3d-models":"Gescannte 3D Modelle","scripts_apps":"Skripte \u0026 Apps","show-all":"Zeige alles","textures":"Texturen","title":"3D Modelle","vr_low-poly":"VR / Low-Poly"},"already_added_message":"hat bereits in den Warenkorb gelegt worden","already_purchased_message":"Sie haben diesen Artikel bereits gekauft.","aria":{"account":"Konto","cart":"Einkaufswagen","close_menu":"Menü schlieÃen","logo":"CGTrader - 3D-Modelle / 3D-Designer","messages":"Nachrichten","notifications":"Benachrichtigungen","open_menu":"Menü öffnen","search":"Suchen","search_by_image":"Bildsuche"},"budgets":{"below_10":"Unter $10","collections":"Pakete","free":"Kostenlos","more_than_20":"Mehr als $20","more_than_50":"Mehr als $50","sale":"Im Verkauf","subscription":"Abonnement"},"cart_limit_reached":"Sie haben das Limit von 500 Artikeln in Ihrem Warenkorb erreicht. Um weiter einzukaufen, schlieÃen Sie bitte Ihre aktuelle Bestellung ab und beginnen Sie eine neue für zusätzliche Artikel.","cart_widget":{"continue_shopping":"Weiter einkaufen","discount":"Rabatt mit Enterprise-Gutschein: ","discount_applied":"Angewendete Rabatte:","final":"Endgültiger Preis: ","have":"Du hast ","items":" Artikel im Warenkorb.","left_to_unlock_discounts":"Noch {{leftToUnlock}} bis zum Freischalten von Rabatten","potential_discount":"Möglicher Rabatt:","proceed":"Zur Kasse","recently_viewed_empty_text":"Beginnen Sie zu stöbern und Ihre kürzlich angesehenen Art
16518ikel erscheinen hier.","recently_viewed_empty_title":"Noch nichts hier","recently_viewed_tab":"Kürzlich angesehen","remainer":"Um CGTrader-Punkte zu aktivieren, fügen Sie hinzu: ","sale_discounts":"Rabatte angewendet: ","sale_time_left":"Verkauf endet in","sale_tooltip":"Rabatte aus unseren Sale-Kampagnen werden nur angewendet, wenn Ihr Warenkorb ${{threshold}} oder mehr erreicht.","sale_tooltip_text":"Dieser Artikel ist im Angebot, aber der Rabatt wird erst angewendet, wenn die Zwischensumme Ihres Warenkorbs ${{threshold}} oder mehr erreicht.","text":"Dein Einkaufswagen ist leer.","title":"Einkaufswagen","total":"Gesamt: ","used":"Credits verwendet: ","view":" Warenkorb ansehen","wishlist_empty_text":"Beginnen Sie zu stöbern und speichern Sie Ihre Favoriten für später â sie erscheinen hier.","wishlist_empty_title":"Ihre Wunschliste ist leer","wishlist_tab":"Wunschliste"},"community":{"awards":"Designer-Auszeichnungen ð","blog":"Blog","challenges":"Herausforderungen","community_ratings":"Kundenbewertung","designers":"3D-Designer","digital_art":"Digitaler Kunst-Wettbewerb","forum":"Forum","galleries":"Galerien","invite":"Einen Freund einladen","printlist":"3D drucke","sell_3d-models":"Verkaufen Sie 3D Modelle","title":"Gemeinschaft","tutorials":"Tutorials"},"conversations_widget":{"conversations":"Gespräche","messages":{"loading":"Laden Posteingang"},"types":{"cgtrader_support":"CGTrader Unterstützung","file_conversion_request":"Die Dateikonvertierung Anfrage","job_application":"3D-Projekt","model_feedback":"Product Feedback","model_support":"Model-Support","offer":"Angebotspreis","personal":"Persönliche Mitteilung","promotions":"Promotions"}},"create_ai":{"community_gallery":"Community-Galerie","free_trial":"Kostenlos testen","generate_3d_model":"3D-Modell generieren","generation":{"dismiss":"Benachrichtigung schlieÃen","error_title":"Generierungsproblem","generating_title":"Ihr 3D-Modell wird generiert","open_model":"Modell öffnen","ready_title":"Ihr 3D-Modell ist fertig!"}},"create_with_ai":"Mit KI erstellen","credits_guest_widget":{"create":"Erstellen Sie jetzt ein Konto!","discount":" Rabatt","for":" für dein ","get":" und bis zu ","learn_more":"Erfahren Sie mehr über CGTrader Treue Credits ","link":"Hier","purchase":"erster Kauf!","sign-up":"Anmelden","text_below_1":"Credits können verwendet werden, beim Kauf \"","text_below_2":"\"Gekennzeichnete Modelle unterzeichnen und decken bis zu 30% ErmäÃigung des Preises."},"credits_user_widget":{"condition_1":"CGTrader-Punkte können für den Kauf von Modellen verwendet werden, die mit dem \u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e Symbol gekennzeichnet sind, und bieten bis zu 30% Rabatt auf ihren Preis.","condition_2":"Punkte können nur verwendet werden, wenn der Gesamtwert Ihres Warenkorbs \u003cstrong\u003e$%{minimum}\u003c/strong\u003e oder mehr beträgt.","condition_3":"Während aktiver Verkäufe oder Werbeaktionen können Punkte nicht verwendet werden.","condition_4":"Beachten Sie, dass Punkte ein Ablaufdatum haben - Ihre Punkte verfallen in \u003cstrong\u003e%{days}\u003c/strong\u003e Tagen.","earn_rate":"Kredit verdient Rate ","first_text_1":"Betrachten Sie es als ein Geschenk für Ihren ersten Einkauf - Sie können Kredite verwenden, wenn Einkauf \" ","first_text_2":" \" modelle gekennzeichnet und erhalten Sie bis zu 30% Rabatt von seinem Preis. Credits nur verwendet werden, wenn der Gesamtwert des Korbes ist gleich oder gröÃer als","important":"WICHTIG:","learn_more":"Mehr erfahren","lifetime_spending":"Lebensdauer Ausgaben: ","list_item":"Durch die Erhöhung Ihrer Lebenszeit Ausgaben für CGTrader, Ihr Kredit verdient Rate steigt auch.","message":" Credits können nicht während des Verkaufs Kampagnen verwendet werden, aber man kann immer noch Ihre Lizenzstufe erhöhen und mehr Kredite für Ihren nächsten Einkauf sammeln.","more_credits":"Wie kann ich mehr Kredite bekommen?","next_level":"Nächste Stufe: ","notice":"HINWEIS: CGTrader-Punkte können während des laufenden Verkaufs nicht verwendet werden, stehen jedoch nach Ende des Verkaufs wieder zur Verfügung. In der Zwischenzeit können Sie sich tolle Angebote für 3D-Modelle \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003ehier\u003c/a\u003e ansehen.","par_1":"Du hast ","par_2":" CGTrader Credits.","par_2_variation":" in Punkte, die Sie einlösen können, wenn kein Ausverkauf verfügbar ist.","regular_text_1":"Credits können verwendet werden, beim Kauf \" ","regular_text_2":" \" Gekennzeichnete Modelle unterzeichnen und decken bis zu 30% Rabatt von seinem Preis.","title":"CGTrader Treuerabatt"},"enterprise":{"management":"3D Asset Management","title":"Produktion von 3D-Inhalten"},"hire_a_freelancer":"Freelancer beauftragen","item_add_message":"erfolgreich in de
16518n Warenkorb gelegt worden","item_restricted_message":"Dieser Artikel kann aufgrund von Sanktionen gegen das Land des Designers (RU/BY) nicht gekauft werden.","navbar":{"actions":{"new":"Neu","top_selling":"Bestseller","trending":"Im Trend"},"budgets":{"below_10":"Unter $10","free":"Kostenlos","more_than_20":"Mehr als $20","more_than_50":"Mehr als $50","sale":"Im Verkauf","up_to_10":"Bis zu $10"}},"projects":{"3d_customs":"Individuelles 3D","3d_printing":"3D-Druck","about":"Ãber 3D-Projekte","browse":"Durchsuchen Projekte","buyer_perspective":"Vermittlung eines 3D-Designers","for_designers":"Für Designer","my_projects":"Meine Projekte","seller_perspective":"Freiberuflicher 3D Projekte","start":"Starten Sie Ein Projekt","work":"Arbeit Mit Cgtrader"},"sell_3d-models":"3D-Modelle verkaufen","sellers_hub":"Verkäufer-Hub","subscription_includes_item_message":"Dieser Artikel ist bereits in Ihrem Abonnement enthalten.","tooltips":{"cart":"Einkaufswagen","conversations":"Meine Gespräche","discounts":"CGTrader Treuerabatt","notifications":"Benachrichtigungen","publisher":"Verleger"},"user":{"ban_notification":"Dieses Benutzerkonto ist gesperrt. Bitte kontaktieren Sie unseren Support für weitere Informationen.","cannot_refer_yourself":"Sie können sich nicht selbst empfehlen","email_confirmation":"Ihre E-Mail-Adresse wurde bestätigt.","email_reconfirmation":"wurde bereits bestätigt, bitte versuchen Sie sich anzumelden","ends_at":"Endet am: %{date}","handle_error_tfa_code_missmatch":"Der eingegebene Sicherheitscode ist falsch. Bitte versuchen Sie es erneut.","handle_error_tfa_code_missmatch_last":"Ihr Sicherheitscode ist abgelaufen. Wenn Sie fortfahren möchten, klicken Sie auf âE-Mail erneut sendenâ und geben Sie den neuen Code ein.","handle_error_tfa_default":"Etwas ist schiefgelaufen, bitte versuchen Sie es später erneut.","handle_error_tfa_expired":"Ihr Sicherheitscode ist abgelaufen.","hundred_percent_royalties_popover":"Sie nehmen an einer temporären 100 %-Kampagne teil: Alle Verkaufserlöse aus neuen Modellen gehen bis zum Ende der Kampagne an Sie","invalid_email_message":"Bitte geben Sie eine gültige E-Mail-Adresse ein, um fortzufahren.","login":"Anmeldung","meta_description":"Sehen Sie sich das 3D-Designerprofil von %{username} auf CGTrader an, sein Portfolio und verfügbare 3D-Modelle. Entdecken Sie die besten 3D-Modelle von Top-Künstlern der Branche.","meta_title_suffix":"3D-Designer","not_valid_birthday":"Geburtstag ist ungültig.","offline":"Offline","online":"Online","page_title":"Designerprofil","rate_models_limit":"Sie können heute keine weiteren Modelle bewerten.","semantic_description":"3D-Modelle, Kunstwerke und Portfolio des Designers. Sehen Sie sich seine Kreationen auf CGTrader an","semantic_title":"Designerprofil","session_failure":"Falscher Benutzername/E-Mail oder falsches Passwort angegeben","session_password_expired":"Ihr Passwort ist aufgrund von Inaktivität abgelaufen. Bitte setzen Sie Ihr Passwort über den Link in der zugesandten E-Mail zurück.","session_two_fa_failure":"Codeüberprüfung fehlgeschlagen","session_unconfirmed":"Ihre E-Mail-Adresse wurde noch nicht bestätigt.","token_not_recognized":"Token wurde nicht erkannt","twitter_shareable_text":"Ein #3dartist, dem man folgen sollte","username_error":"darf keine Leerzeichen oder nicht-lateinische Zeichen enthalten"},"user_menu":{"buyer":{"freelancers":"finden Sie Freelancer","purchases":"Meine Einkäufe","sell":"Verkaufen Sie 3D Modelle","wishlist":"3D-Modell Wunschliste"},"dashboard":"Admin-Dashboard","logout":"Abmelden","public_profile":"Ãffentlicher Profil","seller":{"analytics":"Analytics","find_new_projects":"Neue 3D-Projekte finden","freelance":"Freiberuflicher 3D Projekte","freelance_cgtrader":"Freiberuflicher mit CGTrader","models":"Meine Modelle","publish_project":"Projekt veröffentlichen","publishing":"Verlagswesen","sales":"Meine Verkäufe","subscription":"Abonnement","wishlist":"3D-Modell Wunschliste"},"settings":"die Einstellungen"}},"owly":{"failed_set_pending":"Fehler beim Setzen auf âausstehendâ.","failed_to_approve":"Fehler bei der Genehmigung.","failed_to_suspend":"Fehler beim Aussetzen.","failed_to_update_license":"Fehler beim Aktualisieren der Lizenz.","failed_to_update_status":"Fehler beim Aktualisieren des Genehmigungsstatus."},"print_models":{"browse_all_makes":"Alle 3D-Drucke durchsuchen","browse_all_models":"Alle Modelle durchsuchen","description":"Entdecken Sie trendige, druckfertige 3D-Modelle, druckbare Assets und STL-Dateien für Spiele, Kunst, Heimprojekte und mehr.","makes_description":"Entdecken Sie die neuesten 3D-Drucke, die von der Community hochgeladen wurden â reale Beispiele, die zeigen, wie 3D-Modelle in der physischen Welt aussehen.","makes_title":"Neue 3D-Drucke","new_description":"Entdecken Sie die neuesten 3D-Drucke in unserer Sammlung â frische Designs, die Sie für Ihr nächstes Projekt herunterladen und drucken können.","new_title":"Neue 3D-Druckmodelle","title":"Trendige 3D-Druckmodelle"},"profile":{"account_settings":{"account":{"email":"E-Mail","submit":"Speichern","title":"Profil","update":{"updated":"Profil aktualisiert"},"username":"Benutzername"},"email_settings":{"descriptions":{"ai_studio_notifications":"Benachrichtigungen über Ihre CGTrader AI Generierungen, einschlieÃlich wenn ein noch nicht geöffnetes Modell fertig ist","communication":"Informationen über Ihre Kommunikation mit anderen CGTrader-Nutzern, einschlieÃlich persönlicher Nachrichten, neuer Preis- und benutzerdefinierter Jobangebote, Feedback und Produktunterstützungsanfragen","news":"Informationen über CGTrader-Produkte, neue Feature-Ankündigungen und Community-News","onboarding_and_edu":"Informationen über Ihren Onboarding-Prozess und Tipps, um das Beste aus CGTrader herauszuholen","sales_and_offers":"Informationen über Sonderangebote, 3D-Modellverkäufe und CGTrader-Bonusguthaben","seller_sold_item":"Informationen über Ihre verkauften 3D-Modelle und erhaltenen Zahlungen"},"privacy_policy_html":"Bitte lesen Sie unsere \u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003eDatenschutzrichtlinie\u003c/a\u003e für weitere Informationen. ","t
16518itles":{"ai_studio_notifications":"CGTrader AI Benachrichtigungen","communication":"Kommunikation (Persönliche Nachrichten, 3D-Modell-Feedback, Community-Aktivitäten, Angebote)","news":"3D-News / CGTrader-Updates","onboarding_and_edu":"Onboarding \u0026 Bildung","sales_and_offers":"Verkäufe \u0026 Sonderangebote","seller_sold_item":"Verkaufs- \u0026 Zahlungsinformationen"},"tracking_attributes":{"ai_studio_notifications":"CGTrader AI Benachrichtigungen","communication":"Kommunikation","news":"3D-News / CGTrader-Updates","onboarding_and_edu":"Onboarding \u0026 Bildung","sales_and_offers":"Verkäufe \u0026 Sonderangebote","seller_sold_item":"Verkaufs- \u0026 Zahlungsinformationen"},"update":{"updated":"Ihre E-Mail wurde erfolgreich aktualisiert."}},"gdpr_success_notification":{"opt_in":"Danke! Sie haben sich erfolgreich wieder für unsere E-Mails angemeldet.","opt_out":"Sie haben sich erfolgreich von unseren Newslettern abgemeldet. Sie können diese Einstellung jederzeit in Ihren Profileinstellungen ändern.\n"},"location_tooltip_text":"\u003cdiv\u003eDieses Kontrollkästchen ermöglicht das Anzeigen des Standorts auf der Profilseite.\u003c/div\u003e \u003cdiv\u003eBeachten Sie, dass Ihr Standort aus Compliance-Gründen in jedem Fall Ihren Käufern (wenn Sie Verkäufer sind) und den Verkäufern, bei denen Sie gekauft haben, angezeigt wird.\u003c/div\u003e","moneybookers":{"account":"Skrill-Konto"},"password":{"current_password":"Aktuelles Passwort","new_password":"Neues Passwort","submit":"Passwort ändern","title":"Passwort","updated":"Ihr Passwort wurde erfolgreich aktualisiert. Sie können sich jetzt mit Ihrem neuen Passwort anmelden.","verify_password":"Passwort bestätigen"},"paypal":{"account":"PayPal-Konto","submit":"Speichern","title":"PayPal-Einstellungen","update":{"updated":"Ihre PayPal-Einstellungen wurden aktualisiert"}},"personal_info":{"areas_of_expertise":"Fachgebiete","country":"Land","description":"Ein paar Sätze über sich selbst","full_name":"Vollständiger Name","languages":"Sprachen","preffered_tools":"Bevorzugte Werkzeuge","submit":"Speichern","title":"Persönliche und berufliche Informationen","update":{"updated":"Ihre Informationen wurden erfolgreich aktualisiert"},"website":"Webseite"},"personalization":{"no_muted_title":"Keine stummgeschalteten Designer","title":"Stummgeschaltete Designer","tooltip":"3D-Modelle der aufgeführten Designer werden aus Ihren Suchergebnissen ausgeschlossen.","unmute_designer":{"confirm":"Sind Sie sicher?"}},"professional_info":{"allow_private_job_requests":"Käufer können Ihnen benutzerdefinierte 3D-Jobanfragen senden.","buyer_engagement_program_html":"Gewinnen Sie mehr Kunden, indem Sie ihnen ermöglichen, Ihre Modelle mit CGTrader CGTrader-Punkten zu kaufen. \u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003eWeitere Informationen\u003c/a\u003e\n","pbr_program":"Der niedrigere Verdienstsatz wird nur angewendet, wenn die konvertierte Datei heruntergeladen wird","pbr_program_agreement":"Sie haben zugestimmt, am PBR-Programm für 24 Monate ab %{date} teilzunehmen. Weitere Details finden Sie in den Allgemeinen Geschäftsbedingungen. Bitte kontaktieren Sie unseren Support, wenn Sie Fragen haben.","product_analytics_participation_html":"Ich nehme an \u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eAnalytics\u003c/a\u003e teil und stimme deren Allgemeinen Geschäftsbedingungen zu\n","product_analytics_participation_tooltip_html":"Sie haben zugestimmt, an Analytics teilzunehmen und den Analytics-Nutzungsbedingungen (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003eLink\u003c/a\u003e) am %{accepted_at} zugestimmt. Wenn Sie Ihre Teilnahme beenden möchten, kontaktieren Sie bitte den CGTrader-Support\n"},"security":{"allow_mfa":"Aktivieren Sie die 2-Schritt-Verifizierung, um Ihr Konto zu schützen","use_authenticator_app":"Verwenden Sie eine Authentifikator-App für die 2-Schritt-Verifizierung","use_authenticator_app_tooltip":"Scannen Sie den QR-Code mit Ihrer Authentifikator-App (Google Authenticator / Authy), um Verifizierungscodes zu generieren.","use_email":"Verwenden Sie E-Mail für die 2-Schritt-Verifizierung"},"sidebar":{"general_settigns":"Allgemeine Einstellungen","member_since":"Mitglied seit","paypal":"PayPal","title":"Kontoinformationen"},"title":"Mein Konto"},"conversations":{"conversations":"Gespräche","messages":{"loading":"Laden Posteingang"},"types":{"cgtrader_support":"CGTrader Unterstützung","file_conversion_request":"Die Dateikonvertierung Anfrage","job_application":"3D-Projekt","model_feedback":"Product Feedback","model_support":"Model-Support","offer":"Angebotspreis","personal":"Persönliche Mitteilung","promotions":"Promotions"}},"meta":{"description":"Entdecke hochwertige 3DâModelle von %{username} auf CGTrader. Durchsuche einzigartige Assets für Spiele, VR/AR und Visualisierung.","title":"%{username} 3D Modell Designer"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"Ihre Einstellungen wurden erfolgreich aktualisiert."},"publishing":{"banned_error":"Ihr Konto wurde wegen der Veröffentlichung von Spam-Inhalten gesperrt. Wenn Sie glauben, dass dies ein Fehler ist, kontaktieren Sie bitte [email protected].","files_not_finalized":"Eine oder mehrere Dateien wurden nicht vollständig hochgeladen und können nicht veröffentlicht werden. Bitte entfernen Sie sie und laden Sie sie erneut hoch, bevor Sie veröffentlichen.","spam_suspect":"Ihr Konto ist nicht berechtigt, dieses Modell zu veröffentlichen. Wenn Sie glauben, dass dies ein Fehler ist, kontaktieren Sie bitte [email protected]."},"rating":{"anonymous_buyer":"Anonymer Käufer"},"routes":{"3d-models":"3d-modelle","3d-print-models":"3d-druck-modelle","animated-3d-models":"animierte-3d-modelle","controllers":{"three_d_studio":{"3d-models":"3d-models","images":"images"}},"discover":"entdecken","free-3d-models":"frei-3d-modelle","free-3d-print-models":"frei-3d-druck-modelle","low-poly-3d-models":"low-poly-3d-modelle","pbr-3d-models":"pbr-3d-modelle","pbr-textures":"pbr-textures","rigged-3d-models":"manipulierten-3d-modelle","search":"search"},"sale_off":{"no_overlapping_campaigns":"Die Kampagnendaten überschneiden sich mit einer anderen bestehenden Verkaufsaktion.","parse_discount_rules_text":"Zeile #{index} enthält nicht den erforderlichen Parameter 'discount:'"},"search":{"not_found":"Suchabonnement nicht gefunden","subscription_created":"Suchabonnement erstellt","successfully_unsubscribed":"Sie haben das Suchabonnement erfolgreich abbestellt"},"skills":{"3d-modeling":"3D Modeling","3d-print_modeling":"Print Modeling","3d-scanning":"Scanning","animating":"Animating","grooming":"Grooming","lighting":"Lighting","low-poly-modeling":"Low-poly Modeling","particles":"Particles","pbr-modeling":"PBR modeling","post-production":"Post Production","rendering":"Rendering","rigging":"Rigging","shaders":"Shaders","skinning":"Skinning","texturing":"Texturing","uv-mapping":"UV mapping"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"flash":{"active_subscription":"Sie haben bereits ein aktives Abonnement.","premium_upgrade_unavailable":"Das Upgrade auf Premium ist vorübergehend nicht verfügbar. Bitte versuchen Sie es später erneut.","update_payment_method":"Bei Ihrem Abonnement gibt es ein Zahlungsproblem. Bitte aktualisieren Sie Ihre Zahlungsmethode, anstatt ein neues Abonnement abzuschlieÃen."}
16518,"payment_form":{"discountedPrice":"%{price}","features":{"first":"%{downloads} Assets / Monat â Modelle herunterladen oder mit KI generieren","second":"Sofortzugriff auf über %{models_count} essenzielle 3D-Modelle","third":"Lizenzfrei, keine KI"},"from_price_label":"ab","originalPrice":24.99,"per_model_label":"pro Modell","plan_name":"CGTrader Essentials Abonnement â Jahresplan, monatlich abgerechnet","premium":{"features":{"first":"%{downloads} Assets / Monat â Modelle herunterladen oder mit KI generieren","fourth":"Royalty-free, keine KI","second":"Sofortiger Zugriff auf über %{models_count} insgesamt verfügbare Modelle","third":"Profi-Modelle, die nicht in Essentials enthalten sind"},"plan_name":"CGTrader Premium Abonnement â Jahresplan, monatlich abgerechnet"},"price_unit":"/Monat","vatAmount":"%{vat_amount}"}},"tag":{"description":{"bottle":"Wissenschaftler sagen, dass eine Flasche Wein pro Tag für Sie ist nicht schlecht, aber wenn es um stärkere Getränke wie Whisky oder Bourbon kommt, sollten wir wirklich unsere Alkoholkonsum beobachten. Offensichtlich ist ein Glas Champagner an der Bar sieht viel cooler als eine Kunststoff-Flasche Wasser, aber denken Sie über die Möglichkeit, lebt ein längeres Leben und Bier wird wie ein vernünftiges Opfer zu sein scheint. Diese Kategorie bietet eine groÃe Auswahl an Flaschen 3D Modelle, die von alkoholbedingten Objekten wie Weinregale und Korkenzieher auf alle Arten von Flaschen 3D Modelle (von Shampoo Olivenöl).","brain":"Das Gehirn ist eines der gröÃten und komplexesten Organe im menschlichen Körper. Aufgrund seiner komplizierten Struktur und Funktion ist die Anatomie des Gehirns auch sehr komplex. Doch Wissenschaftler graben tiefer in die Architektur des menschlichen Gehirns, die Aufdeckung irrsinnig Geheimnisse. Eine breite Palette von realistischen und Gehirn 3D Modellen detailliert, die für Computergrafik-Anwendungen wie Werbung bereit sind, 3D-Visualisierung, 3D-Spiele, Web und jeden anderer Bereich der 3D-Konstruktion im Zusammenhang steht zum Download zur Verfügung.","building":"Es ist unklar, wo moderne Architekten ihre Inspiration, aber einige der weltberühmten Gebäude sind so Schneiden, dass sie wie Visionen aus der Zukunft aussehen. Und wir meinen nicht nur das äuÃere Teil ... In guten Händen ein Standard-Gebäudekonstruktion wird eine atemberaubende architektonische Schöpfung mit innovativen Innenarchitektur, unabhängig davon, ob es sich um ein Büro oder ein städtisches Gebäude. Unsere Auswahl an Gebäuden 3D Modelle zum Download bereit und kann in verschiedenen Bereichen angewandt werden - 3D-Animation, Grafik-Design, Werbung, 3D-Spiele oder Internet.","camera":"Fotografieren und Filmen ist derzeit eines der beliebtesten Berufsfelder bei jungen Menschen, aber nicht jeder mit einer professionellen Kamera ist ein Künstler oder ein Fotograf. Mit der Qualität der Handy-Kameras von Jahr zu Jahr zu verbessern, sehen wir Menschen, Bilder in jedem Schritt und diejenigen, die das neu entwickelten Bild haben Fähigkeiten Bearbeitung sind wirklich berühmt. Das Leben tut ein wenig anders aussehen, wenn man auf der anderen Seite der Linse ist, aber lassen Sie sich nicht mitreiÃen ... Eine breite Palette von detaillierter Kamera 3D Modelle ist zum Herunterladen von Grafikdesignern, Animationen und Spiele-Entwickler verwendet werden und Berufstätige in anderen 3D-verwandten Bereichen.","car":"Mit Blick auf diesen sehr detailliert und äuÃerst realistische 3D-Auto-Modellen, können Sie fast den Motor brüllen hören! Eine breite Palette von Fahrzeug 3D Modelle können Ihr Leben so viel einfacher machen, wenn Sie mit Computergrafik, Animation oder anderem 3D-verwandten Bereich zu kämpfen.","cell":"Wissenschaftler haben geschätzt, dass menschliche Körper enthält 5000000000-200.000.000 Billionen Zellen. Pflanzen und Tiere haben Zellen, auch. Wir wollen nicht zu langweilen Sie mit dieser Biologie Sachen, aber das breite Spektrum der Zelle 3D Modelle, dass wir reichen von Blut, Viren und DNA an Knochenmark und Zellwände. Ist das nicht ... nervenaufreibend?","chair":"Wir nehmen sitzen in Stühle gewährt und nicht immer feststellen, wie viel Charme für unser Heim oder Büro-Interieur hinzufügen können. Stuhl ist tatsächlich eines der zentralen Möbelstücke in jedem Haushalt. Hier können Sie qualitativ hochwertige und auffälliges Design Stuhl 3D Modelle, die in verschiedenen Bereichen angewendet werden können - von der Werbung und 3D-Visualisierung 3D-Spiele.","city":"Das Stadtleben ist ein exzentrisches Spiel: StraÃen mit Renntaxen platzen, modernen Gebäuden, FuÃgängern in perfekt zugeschnittene Bürokleidung, Schlaf Brücken und Parks ... Von Shanghai, nach New York (! Manhattan), nach London oder Paris - jede Stadt hat ihre eigene Magie. Sie können aus dieser reichen Auswahl an detaillierter Stadt 3D Modelle wählen, die in einer Reihe von Bereichen verwendet werden können - Werbung, C
16518omputergrafik, Animation, 3D-Visualisierung oder Spielen. Entdecken Sie das urbane Leben.","dragon":"Dragon ist wahrscheinlich das beliebteste Tier in der Fantasy-Welt leben. Es hat sich in so viele Mythen verschiedener Kulturen, Animationen, Filme und Bücher vorgestellt, dass es legendär geworden ist. Es wird vor allem durch Spiele-Entwickler geliebt, wie es die magische Zauber zu dunklen Höhlen und Verliese hinzufügt. Eine breite Palette von realistischen, in Ordnung gebracht Drachen 3D Modelle, die für Computergrafik-Anwendungen wie Werbung bereit sind, 3D-Visualisierung, 3D-Spiele, Web-und jede andere auf 3D-Design ist zum Download zur Verfügung verwandten Bereich.","earth":"Der Detaillierungsgrad in der kürzlich hinzugefügt Erde Ansicht in Google Maps hat eine Reihe von Menschen schockiert. Sie können den ganzen Planeten erforschen - Ozeane, Berge und Wüsten, entdecken Städte und versteckten StraÃen, ohne Ihr Haus zu verlassen. Das ist einige unglaubliche Dinge Mutter Erde vor nicht erlebt hat. Eine Auswahl von realistischen Erde 3D Modellen, die für Computergrafik-Anwendungen wie Werbung bereit sind, 3D-Visualisierung, 3D-Spiele, Web und jeden anderer Bereich der 3D-Konstruktion im Zusammenhang steht zum Download zur Verfügung.","engine":"Manche Menschen sind in der Lage, den Motor zu benennen, indem Sie einfach auf den Klang hört es macht, und das ist wirklich erstaunlich. Unabhängig davon, ob es ein Düsentriebwerk oder ein Automotor, sind sie extrem Maschinen kompliziert, dass wir so oft benutzen, aber nicht zu viel Zeit denken verbringen darüber. Ein Motor ist ein Motor (bis es nicht mehr funktioniert). Diese Kategorie hat eine Reihe von verschiedenen Arten von Motor 3D Modelle, und es enthält auch Motorteile wie Propeller oder Zylinder, so dass wir sicher sind, finden Sie, was Sie brauchen.","female":"Es ist kein Witz, dass es erhebliche Unterschiede zwischen männlichen und weiblichen Gehirn, was bedeutet, dass es normal ist, dass ein durchschnittlicher Mann und Frau verhalten, fühlen und reagieren auf ganz unterschiedliche Weise. Aber es ist nicht alles über die Anatomie. Keine Liebesgeschichte, Film oder Spiel jemals ohne ein starkes Mädchen Charakter, weil die Macht der Dame Charme abziehbar ist nicht zu leugnen. Eine reiche Auswahl an realistischen weiblichen 3D Modelle bieten Ihnen alles, was Sie brauchen - von Nackt 3D Modelle weiblichen Atmungsorgane.","hand":"Der Grund, warum wir unsere Hände benutzen, für so viele Dinge, ist ihre auÃergewöhnliche Anatomie. Der Daumen allein durch neun verschiedene Muskeln gesteuert. Es ist schwer zu glauben, aber früh Hände waren exotischer als jede Hand heute - einige Arten hatten sieben Finger. Der menschliche Körper hat sich deutlich weiterentwickelt. Ein Arm oder eine Hand, wie wir sehen es heute sieht nichts, wie seine frühen Versionen. Eine breite Palette von realistischen, in Ordnung gebracht Hand 3D Modelle, die für Computergrafik-Anwendungen wie Werbung bereit sind, 3D-Visualisierung, 3D-Spiele, Web-und jede andere auf 3D-Design ist zum Download zur Verfügung verwandten Bereich.","head":"In der menschlichen Anatomie, der Kopf ist der obere Teil des menschlichen Körpers. einen 3D-Modellierung menschlichen Kopfes kann ein wenig kompliziert erweisen, da (auch wenn es so viele verschiedenen Formen und GröÃen sind) wir symmetrisch, realistisch aussehenden Köpfe schätzen - keine lustigen Augen, Ohren, Nase, Lippen oder Kiefer-Linie, bitte. Face ist ein sensibler Bereich, und es wäre einfach nur unhöflich sein, Spaà zu haben mit diesem. Unsere Auswahl umfasst realistisch männlich, weiblich, Kind und sogar Geschichte Figuren wie Harry Potter und Batman oder Prominente wie Tom Cruise und Scarlett Johansson Köpfe, die zum Download bereit sind.","helmet":"Denken Sie immer daran, dass die Gesundheit und Sicherheit an erster Stelle, so schützen Sie Ihren Kopf ist eine solide Idee. Mittelalterliche Ritter, Daft Punk und sogar die Ironman tragen Helme, so regelmäÃig Superhelden wie Radfahrer oder Bauherren sollten sich keine Sorgen über uncool suchen. Diese Sammlung von Helm 3D Modelle, die zum Download verfügbar ist, wird sich als nützlich erweisen, wenn Sie in den Bereichen Grafikdesign, 3D-Animation, 3D-Spiele oder Visualisierung arbeiten.","house":"Es ist eine alte Wahrheit, dass ein Haus des Mannes sein Schloss, aber wenn es um den Aufbau dieses perfekte Haus kommt oder eine ideale Wohnung zu kaufen, wir neigen dazu, unsere Köpfe über sie zu verlieren. Zum Glück, dieses breite Spektrum von Hause 3D Modellen, die alles von architektonischen Details, innen und auÃen, bis hin zu Möbeln umfassen, werden Sie helfen, moderne 3D-Visualisierungen erstellen, die Schmerzen zu lindern.","human":"Wenn Sie die Anatomie des Menschen beginnen zu erforschen, merkt man, dass die Menschen so komplizierten und komplexen Maschinen sind, dass sie den Atem raubt. Jeder Körperteil, Muskel-, Gelenk-, Organ- oder Knochen Kombination in einem System verbunden ist, funktioniert nichts isoliert! Diese super-realistische 3D menschlichen Modelle ermöglicht es Ihnen, aus jedem Winkel anatomischen Strukturen zu untersuchen.","lamp":"Wenn Sie Ihr Haus umsehen und die Arten von Lampen zählen, dass Sie besitzen, werden Sie überrascht sein: Lesen, Tisch, Wand, Decke, Schreibtisch, Stativ Lampen ... Es
16518ist genug, um Ihren Kopf drehen! Nicht die Stile zu erwähnen, dass sie kommen in - von extravagant modernen Lampen zu retro oder stilvollen futuristisch. In dieser Kategorie haben wir alle Arten von Lampe 3D Modellen, so durchsuchen und herunterladen in Grafik-Design zu verwenden, 3D-Visualisierung oder anderem 3D-verwandten Bereich.","light":"Haben Sie sich jemals gefragt, warum eine Glühbirne das Symbol einer brillanten Idee? Sicherlich kann eine helle Idee, die Architektur des Geistes aufzuklären, aber das ist es nicht. Eine StraÃenlaterne, ein Kronleuchter oder jede andere Art von Lampe stehen würde nie eine Chance, dass vor Ort zu nehmen. Wenn das nächste Mal, wenn Sie an der Decke schauen und starren auf einer Art architektonischen Licht der geniale Idee dich nicht schlagen, könnte es sein, weil Sie an einem falschen Blitzsystem starren sind ... Unsere Auswahl an qualitativ hochwertigem Licht 3D Modelle werden sich praktisch, wenn Sie in den Bereichen Architektur, Computergrafik, 3D-Animation oder Design arbeiten.","machine":"Stellen Sie sich vor, wenn alle die Maschinen plötzlich aufgehört zu arbeiten: keinen Kaffee, kein bequemes Wäschewaschen, keine Geldautomaten an einer Ecke der StraÃe, keine Zeit im Fitnessstudio, nicht zu teuer Automaten ... Es ist deprimierend Ton, nicht wahr? Wir sind so an diese Haushaltsgeräte und elektronische Geräte verwendet, dass es buchstäblich die Welt Drehen aufhören würde! Zum Glück, unsere Auswahl an detaillierten Maschinen 3D Modelle reichen von Maschinengewehren für Stromgeneratoren, die nützlich für Designer beweisen werden die Arbeit mit Computer-Grafik, Werbung, 3D-Animation, 3D-Spielen oder Internet.","man":"Eine groÃe Sammlung von Menschen 3D Modellen zum Download zur Verfügung. Sitzt einen Mann, einfacher Mann, fliegender Mann oder durchschnittlicher Mann, haben wir alles bekommen - auÃer dem perfekten Mann, dass jeder nach. Er ist ein fischig Charakter und wir hassen, dies zu bringen, aber es könnte ein Mythos sein ... Aber hey, sind Menschen geboren groÃartig zu werden, perfektionieren nicht.","robot":"R2D2 ist wohl der bekannteste Roboter in der Welt, aber es ist sicherlich nicht die einzige. Von der Industrie zu Spielzeug für den menschlichen Roboter, wir eine immer gröÃere Auswahl an diesen mechanischen Maschinen sehen, die beide wunderbar und ein wenig beunruhigend ist. Es ist nicht allzu schwierig, die Menschen zu verstehen, die darauf bestehen, dass Computer, Technologie, Roboter sind eine zu erheblichen Auswirkungen auf den Menschen zu machen. Eine breite Palette von realistischen, in Ordnung gebracht Roboter 3D Modelle, die für Computergrafik-Anwendungen wie Werbung bereit sind, 3D-Visualisierung, 3D-Spiele, Web-und jede andere auf 3D-Design ist zum Download zur Verfügung verwandten Bereich.","ship":"Schiffe sind mächtige Schiffe und kommen in allen GröÃen, Farben und Formen. Sie können als Frachtschiffe, Kriegsschiffe oder Passagiersc
16518hiffe klassifiziert werden, aber sie arbeiten alle in der Tiefsee Gewässern. Wenn Sie die Beschwerden von Reisekrankheit erlebt haben, kann es nicht eine Ihrer Lieblingsbeförderungsmittel sein, aber viele Leute betrachten Bootsfahrten als sehr edel und angenehm. Unsere Auswahl an Schiff 3D Modelle zum Download bereit und wird die Standards der auch den anspruchsvollsten Kapitäns treffen.","skeleton":"Das menschliche Skelett oder Skelett-System (Anatomie) ist der innere Rahmen des Körpers, die von 270 Knochen bei der Geburt besteht. Es bietet die Körperstruktur, den Schutz und die Bewegung und ist eines der komplexesten Skelettsysteme. Eine reiche Auswahl an anatomisch korrekt, realistisch und Skelett 3D Modelle skaliert, die in 3D-Animation, Grafik-Design, Werbung, 3D-Spielen und Web-perfekt für den Einsatz sind, ist zum Download zur Verfügung.","skull":"Der älteste vollständigste, genetisch intakte menschliche Schädel wurde durch eine Vielzahl von ausgestorbenen Tieren mehr als 40 Meter unter dem Meeresspiegel umgeben entdeckt. Es ist eines der ältesten Skelette in der Neuen Welt gefunden, und es enthält auch alle groÃen Knochen des Körpers und einen intakten Schädel und Gebiss. Menschliche Schädel haben vor kurzem eine Sache in Mode und Design geworden, aber wenn man es tatsächlich einige Gedanken geben, sie Art machen uns alle aussehen wie Anatomie Freaks ... Diese Kategorie bietet eine breite Palette von Schädel 3D Modelle in Grafik-Design verwendet werden 3D, Animation, 3D-Spiele oder Werbung.","sofa":"Luxus oder einfach, modern oder antik, Leder oder minimalistisches Design? Wie gefällt Ihnen Ihr Sofa? Die Palette der Sofa 3D Modelle, dass wir erfüllen haben sogar den schlechtesten Perfektionisten. Wenn Sie aufhören, darüber nachzudenken, ist Sofa im Mittelpunkt jedes Wohnzimmer, so müssen Sie kreativ sein, wenn das Design der Wahl!","table":"Die neuesten Möbeltrends sind so vielfältig, dass die Wahl ein moderner, modischer Tisch zu stressig wird immer. Früher gab es eine Zeit, wenn Sie einen einfachen Tisch für Ihre bescheidene Feste hatte und das war genug, aber heute - Tabelle soll eine Erklärung sein, oder zumindest ein Blickfang Innen Akzent. Diese Auswahl bietet Ihnen eine groÃe Auswahl an Tisch 3D Modelle bieten für jede Laune.","tower":"Jede Stadt hat einen besonderen Turm, dass jeder wirklich stolz. Denken Sie Eiffelturm oder Pisa Turm oder London Tower Bridge, geschweige denn alle modernen Wolkenkratzer, futuristische Gebäude und die Stadtlandschaft, dass die Touristen bewundern. Doch wenn es um die industriellen Teile der Stadt, Wassers oder Strommasten kommt, alle neigen dazu, ihre Augen abwenden ... Aber wir sollen jede architektonische Schöpfung, ganz gleich alten, industrielle oder modern schätzen lernen. Eine Reihe von detaillierten Turm 3D Modelle zum Download bereit und für Computergrafikanwendungen wie Werbung, 3D-Visualisierung, 3D-Spiele, Web und jedem anderen Bereich im Zusammenhang mit 3D-Design zur Verfügung.","tree":"Wenn Sie auf einer Mission sind einige Bäume oder exotischen Pflanzen zu pflanzen, sind Sie bei uns genau richtig. Diese Kategorie bietet eine Reihe von einfach zu bedienende, sehr realistische 3D-Baummodelle zu CG Künstlern und Architekten, die etwas Grün, um ihre Projekte hinzuzufügen streben. Wenn Sie gute Qualität zu schätzen wissen, sind wir diese Auswahl von 3D-Baum zu pflanzen Modellen zuversichtlich, dass Ihre Standards erfüllen!","truck":"einen LKW zu fahren ist ein harter Job, vor allem, wenn Sie Ihren Weg durch eine Stadt Stau finden müssen. Unabhängig davon, ob es ein Feuerwehrauto, Müllwagen, Nahrungsmittel-LKW oder ein generisches, dauert es eine groÃe Geschicklichkeit diese riesigen Fahrzeuge zu manövrieren. Wir sind davon überzeugt, dass diese Auswahl realistischer, hochwertiger LKW 3D Modelle in 3D-Animation, Grafik-Design, Werbung oder anderem 3D-verwandten Bereich Gebrauch perfekt ist.","tv":"Früher gab es eine Zeit, in der Kamin das Herzstück eines jeden anständigen Hause war, jetzt TV-Gerät mit Spielern und Lautsprecher ist der König des Wohnzimmers (und sogar das Schlafzimmer). In den letzten Jahren hat das Fernsehen mit neuesten Technologien gefangen. Als Ergebnis haben wir intelligentes 3D-TV, Flach- und Plasmabildschirme, Millionen neue Funktionen und Touchscreen-Design. Kein Wunder, Fernsehen treibt Kino aus dem Markt. Eine groÃe Auswahl an realistischen, detail TV 3D Modelle, die für Computergrafik-Anwendungen wie Werbung bereit sind, 3D-Visualisierung, 3D-Spiele, Web und jeden anderer Bereich der 3D-Konstruktion im Zusammenhang steht zum Download zur Verfügung."}},"tag_promotion":{"days_left_error":"muss zwischen 1 und 30 liegen","no_other_pending_promotions_for_same_item_tag":"hat bereits eine ausstehende Promotion"},"tooltips":{"buyer_loyalty_program_current_level_html":"Derzeit haben Sie ausgegeben %{total_price_paid} auf CGTrader und Ihre Kreditrate verdienen %{buyer_loyalty_rate}. \u003cbr/\u003e Es bedeutet, dass Sie erhalten %{buyer_loyalty_rate} Gutschriften aus jedem Kauf.\n","buyer_loyalty_program_html":"Dies ist der Prozentsatz, wie viel Sie von Ihren Käufen als neue Kredite bekommen. \u003cbr/\u003e Es wird bis zu 30% als Ihre Lebensdauer Ausgaben für CGTrader Erhöhung zu erhöhen. \u003cbr/\u003e Zur Zeit Ihre Kredit verdienen Rate %{buyer_loyalty_rate}.\n","buyer_loyalty_program_next_level_html":"Nächste Stufe %{next_lvl_expenses} erhöht Ihre Kreditrate verdienen bis %{next_lvl_expenses_rate}. \u003cbr/\u003e Sie müssen Kauf für $%{left_until_next_lvl} mehr zum nächsten Level zu erreichen.\n"},"trending_headers":{"models":"Sehen Sie sich weitere angesagte 3D-Modelle an","print":"Sehen Sie sich weitere angesagte 3D-Druckmodelle an"},"tutorial":{"destroy":"Tutorial wurde erfolgreich gelöscht.","submit_for_review_error":"Bitte füllen Sie alle erforderlichen Felder aus.","submitted":"Vielen Dank für das Einreichen Ihres Tutorials. Es wird überprüft und in Kürze veröffentlicht."},"valvat":{"country_adjectives":{"at":"österreichische","be":"belgische","bg"
16518:"bulgarische","cy":"zypriotische","cz":"tschechische","de":"deutsche","dk":"dänische","ee":"estnische","es":"spanische","eu":"europäische","fi":"finnische","fr":"französische","gb":"britische","gr":"griechische","hu":"ungarische","ie":"irische","it":"italienische","lt":"litauische","lu":"luxemburgische","lv":"lettische","mt":"maltesische","nl":"niederländische","pl":"polnische","pt":"portugiesische","ro":"rumänische","se":"schwedische","si":"slowenische","sk":"slowakische"}}},"en":{"_partials":{"search":{"submit":"Search"},"search_suggestions":{"group":{"cg":"3D Models","low_poly":"VR/ AR/ Low poly"},"title":"Suggestions"}},"activerecord":{"attributes":{"competition_image":{"image_name":"The uploaded images"},"content_report":{"categories":{"adult":"Adult or violent content","ai_generated":"AI-generated content","copyright":"Copyright infringement"},"category":"Reason"},"doorkeeper/application":{"name":"Name","redirect_uri":"Redirect URI"},"item_sketch":{"animated":"Animated","category":"Category","collection":"Pack","free":"Share for free","game_ready":"Game-ready","license":{"custom":"Custom","editorial":"Editorial","general":"General"},"materials":"Materials","plugins_used":"Plugins used","rigged":"Rigged","sell_source_files":"Allow downloading source files","textures":"Textures","title":"Product title","unwrapped_uvs":"Unwrapped UVs"},"job":{"agreed_to_terms_of_use":""},"job_application":{"agreed_to_terms_of_use":"You must accept Terms \u0026 Conditions"},"print":{"item_image":""}},"errors":{"messages":{"competitors_mention":"Please note that posting links to other marketplaces is not allowed %{location_title}.","embedded_script":"This file is not supported and cannot be uploaded. Please try a different file.","exceeds_daily_quota":"If you want to report more than two models, please contact us at [email protected]","file_size_limit":"should be less than %{file_size_limit}MB","file_too_big":"Attachment is too big, please try to not exceed 100MBs.","message_daily_limit":"You've reached your daily limit of active conversations. You can send more messages tomorrow.","new_username_confirmation":"New username did not match confirmation username.","personal_details":"It is not allowed to enter contact details in CGTrader conversations due to many fraud complaints and misunderstandings that occur while communicating or making purchases outside of the website. Both designer and customer are notified about new messages received on CGTrader by registered email. If you have any issues with communication please contact our \u003ca href='mailto:[email protected]'\u003esupport\u003c/a\u003e\n","record_invalid":"Validation failed: %{errors}","resolution_too_small":"should be high-resolution (minimum %{minimum} pixels)","restrict_dependent_destroy":{"has_many":"Cannot delete record because dependent %{record} exist","has_one":"Cannot delete record because a dependent %{record} exists"},"username_change_disable":"Your account is not eligible for a username change. Please contact our support team at \u003ca href='mailto:[email protected]'\[email protected]\u003c/a\u003e for assistance."},"models":{"address":{"attributes":{"base":{"invalid_vat":"The VAT number you've inserted does not exist in the country you selected","personal_or_company":"Please enter the personal or company details","vat_wrong_country":"Your inserted VAT number does not match the country you selected"},"zip_code":{"general":"Unfortunately, the ZIP code you provided in the checkout, seems to be invalid. Please double-check information you entered. If you believe the ZIP code is correct, please contact our customer support by emailing [email protected].\n","wrong_length":"Your ZIP code should only contain 5 digits","wrong_state":"Your state and ZIP code does not match. Did you mean to select state %{zip_code_state}?"}}},"comment":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements for creating comments at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}},"exceeds_comment_quota":"You have reached commenting limit. Please continue later or contact support."},"conversation":{"attributes":{"base":{"daily_limit_exceeded":{"message":"You have reached your daily limit for creating conversations."},"restricted_user":{"message":"Your account does not meet the requirements for sending messages at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}}}},"conversation_message":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements for sending messages at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}}},"doorkeeper/application":{"attributes":{"redirect_uri":{"forbidden_uri":"is forbidden by the server.","fragment_present":"cannot contain a fragment.","invali
16518d_uri":"must be a valid URI.","relative_uri":"must be an absolute URI.","secured_uri":"must be an HTTPS/SSL URI.","unspecified_scheme":"must specify a scheme."},"scopes":{"not_match_configured":"doesn't match configured on the server."}}},"forum/post":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements for creating forum posts at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}}},"forum/topic":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements for creating forum topics at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}}},"galleries":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements to publish Gallery projects at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}}},"item":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements for creating items at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"}}},"item_tag":{"invalid_tag":"This tag can't be used. Please enter a different one"},"job":{"attributes":{"base":{"restricted_user":"Your account does not meet the requirements for creating projects at this time.\u003cbr\u003e If you believe this is an error or need assistance, please contact our support\u003cbr\u003e team at [email protected]"},"deadline":{"after":"must be in future"}}},"job_application":{"attributes":{"agreed_to_terms_of_use":{"blank":" to apply for this Job."},"deadline":{"after":"must be in future"}}},"payment_agreement":{"attributes":{"base":{"invalid_vat":"VAT code you entered seem to be invalid. If you don't have one, you can leave this field empty. If you have a VAT code, try entering it again or contact the Customer Success team for help.\n"}}},"print":{"attributes":{"item_image":{"blank":"Please provide image"}}},"scholarship_application":{"attributes":{"email":{"invalid":"To confirm you are from an educational institution we ask you to apply with and .edu email (ex. [email protected]). If you have a different email, please contact us via [email protected].\n","taken":"This email has already been taken."}},"base":{"blank":"Please make sure you filled in all fields."}},"user":{"attributes":{"username":{"blocked_for_one_year":"already changed this year. You will be able to change your username again on %{available_on}.","reserved":"is already taken. Please use a different username."}}},"wish_list_item":{"attributes":{"base":{"purchased":"You have already purchased this item"}}}}}},"activity":{"sale":{"create":{"payment_account":{"moneybookers":"Skrill Account","moneybookers_credit_card":"Skrill Account","paypal":"Paypal Account","paypal_credit_card":"Paypal Account"}}}},"admin":{"access":{"Admin::AccessController":{"edit_user":"edit_user","index":"index","update_user":"update_user"},"Admin::AdobeChallengeItemsController":{"edit":"edit","update":"update"},"Admin::AdobeChallengesController":{"index":"index","show":"show"},"Admin::BannedIpsController":{"create":"create","destroy":"destroy","index":"index"},"Admin::BlogPostsController":{"create":"create","destroy":"destroy","edit":"edit","images":"images","index":"index","new":"new","publish":"publish","unpublish":"unpublish","update":"update","upload":"upload","upload_image":"upload_image"},"Admin::BonusCreditsController":{"create":"create","show":"show"},"Admin::CategoriesController":{"create":"create","edit":"edit","index":"index","new":"new","update":"update"},"Admin::ChallengesController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","publish":"publish","unpublish":"unpublish","update":"update","users":"users"},"Admin::CompetitionSubmissionsController":{"index":"index","search":"search","show":"show","update":"update"},"Admin::ConversationForbiddenWordsController":{"create":"create","destroy":"destroy","index":"index","update":"update"},"Admin::ConversationMessagesController":{"create":"create"},"Admin::ConversationsController":{"filter":"filter","index":"index","show":"show"},"Admin::CouponsController":{"destroy":"destroy","index":"index"},"Admin::CustomCtrValuesController":{"create":"create","destroy":"destroy","index":"index"},"Admin::CustomReputationPointsController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","update":"update"},"Admin::DashboardBannersController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update","update_position":"update_position"},"Admin::DashboardController":{"index":"index"},"Admin::EmployeesController":{"destroy":"destroy","edit":"edit","index":"index","update":"update"},"Admin::FeaturesController":{"disable":"disable","enable":"enable","index":"index"},"Admin::FileConversionRequestFormatsController":{"create":"create","destroy":"destroy","index":"index"},"Admin::FileConversionRequestsController":{"filter":"filter","ignore":"ignore","index":"index","reopen":"reopen","reply":"reply","show":"show"},"Admin::FileExtensionsController":{"create":"create","destroy":"destroy","edit":"edit","update":"update"},"Admin::FileTypesController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","update":"update"},"Admin::FilterPresetsController":{"create":"create","destroy":"destroy","set_default":"set_default","show":"show"},"Admin::ForumBoardsController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update","update_position":"update_position"},"Admin::ForumTopicsController":{"destroy":"destroy","hide_from_community":"hide_from_community","index":"index","update_board":"update_board","update_sticky":"update_sticky"},"Admin::GalleriesController":{"destroy":"destroy","edit":"edit","index":"index","switch_status":"switch_status","toggle_parental_lock":"toggle_parental_lock","update":"update"},"Admin::GalleryCategoriesController":{"create":"create","destroy":"destroy","index":"index","update":"update"},"Admin::HundredPercentRoyaltiesController":{"create":"create","index":"index"},"Admin::ImagesController":{"index":"index"},"Admin::IpAddressesController":{"index":"index"},"Admin::ItemFilesController":{"attached":"attached","destroy":"destroy","download":"download"},"Admin::ItemOrdersController":{"authorize_payment":"authorize_payment","batch_destroy":"batch_destroy","comment":"comment","destroy":"destroy","index":"index","make_as_refunded":"make_as_refunded","paid_orders_csv":"paid_orders_csv","remove_item_rating":"remove_item_rating","search":"search","show":"show"},"Admin::ItemsController":{"batch_destroy":"batch_destroy","batch_restore":"batch_restore","block":"block","clear_cache":"clear_cache","delete_tags_by_stop_words":"delete_tags_by_stop_words","destroy":"destroy","edit":"edit","filter":"filter","index":"index","make_as_published":"make_as_published","manage":"manage","mark_as_non_adult":"mark_as_non_adult","rate":"rate","save_tags":"save_tags","set_as_featured":"set_as_featured","
16518stats":"stats","toggle_metaverse_assignment":"toggle_metaverse_assignment","trigger_image_upload":"trigger_image_upload","unblock":"unblock","update_index":"update_index","update_stop_words":"update_stop_words"},"Admin::JobOrdersController":{"destroy":"destroy","index":"index","refund":"refund","show":"show"},"Admin::JobTagsController":{"create":"create","destroy":"destroy","send_mail_to_related_designers":"send_mail_to_related_designers","update":"update"},"Admin::JobTemplatesController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","show":"show","update":"update"},"Admin::JobsController":{"approve_switch":"approve_switch","authorize_payment":"authorize_payment","destroy":"destroy","edit":"edit","index":"index","show":"show","update":"update"},"Admin::ManufacturersController":{"activate":"activate","create":"create","deactivate":"deactivate","destroy":"destroy","edit":"edit","index":"index","new":"new","show":"show","update":"update"},"Admin::Moderate::BatchesController":{"create":"create","index":"index","new":"new"},"Admin::Moderate::ChallengeItemsController":{"index":"index","update":"update"},"Admin::Moderate::ItemsController":{"approve_status":"approve_status","filter_bar":"filter_bar","hints":"hints","index":"index"},"Admin::Moderate::KeywordsController":{"create":"create","destroy":"destroy","index":"index","new":"new","refresh":"refresh"},"Admin::Moderate::ModelsController":{"filter":"filter","index":"index","update":"update"},"Admin::Moderate::TrendingItemsController":{"destroy":"destroy","index":"index","previews":"previews","reindex_page":"reindex_page","set_rating":"set_rating"},"Admin::MqsController":{"assign_reviewers":"assign_reviewers","destroy_item_file":"destroy_item_file","edit":"edit","index":"index","search":"search","update":"update","update_item":"update_item","upload_item_file":"upload_item_file"},"Admin::Notification::TemplatesController":{"index":"index"},"Admin::PageCategoriesController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update"},"Admin::PagesController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update"},"Admin::PartnershipDealsController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","search":"search","update":"update"},"Admin::PaymentAgreementsController":{"assign_payment_agreement_attributes":"assign_payment_agreement_attributes","edit":"edit","index":"index","payment_agreements_params":"payment_agreements_params","search":"search","update":"update"},"Admin::PayoutImportsController":{"corrupted_payouts":"corrupted_payouts","create":"create","destroy":"destroy","index":"index","proceed":"proceed","show":"show"},"Admin::PbrTextureNamesController":{"destroy":"destroy","edit":"edit","index":"index","update":"update"},"Admin::PrinterTypesController":{"index":"index"},"Admin::RedirectionsController":{"approve":"approve","create":"create","destroy":"destroy","index":"index"},"Admin::ReferralsController":{"index":"index"},"Admin::RefundImportsController":{"create":"create","example_csv":"example_csv","failures_csv":"failures_csv","index":"index","new":"new","proceed":"proceed","show":"show"},"Admin::RenderersController":{"create":"create","edit":"edit","index":"index","set_as_default":"set_as_default","update":"update"},"Admin::ReportedConversationsController":{"filter":"filter","index":"index","review":"review"},"Admin::ReputationLogsController":{"index":"index"},"Admin::ReputationScoresController":{"export":"export","index":"index","update":"update"},"Admin::SaleOffController":{"create":"create","reschedule_disable_sale_off_worker":"reschedule_disable_sale_off_worker","show":"show"},"Admin::SearchDebuggerController":{"show":"show"},"Admin::SellerDashboardNewsController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update"},"Admin::SettingsController":{"clear_cache":"clear_cache","toggle_payment_agreement_lock_settings":"toggle_payment_agreement_lock_settings"},"Admin::SimpleResourcesController":{"create":"create","destroy":"destroy","index":"index","new":"new","update":"update"},"Admin::SoftwareController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","update":"update"},"Admin::SuspiciousConversationsController":{"filter":"filter","index":"index","mark_as_ok":"mark_as_ok","show":"show"},"Admin::TakeoversController":{"impersonate":"impersonate","stop_impersonating":"stop_impersonating"},"Admin::TutorialCategoriesController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update"},"Admin::TutorialSoftwaresController":{"create":"create","destroy":"destroy","edit":"edit","index":"index","new":"new","update":"update"},"Admin::TutorialsController":{"destroy":"destroy","index":"index","update":"update"},"Admin::UrlShortcutsController":{"index":"index"},"Admin::UserTrustPoliciesController":{"filter":"filter","index":"index","update":"update"},"Admin::UserWarningsController":{"create":"create"},"Admin::UsersController":{"approve_artist":"approve_artist","ban":"ban","confirm":"confirm","destroy":"destroy","donate_store_credits":"donate_store_credits","edit":"edit","filter":"filter","index":"index","show":"show","
16518suspend_messaging":"suspend_messaging","toggle_oauth_owner_role":"toggle_oauth_owner_role","unapprove_artist":"unapprove_artist","update":"update","update_ftp_settings":"update_ftp_settings","update_password":"update_password","update_value":"update_value"},"Admin::WebflowPagesController":{"create":"create","destroy":"destroy","index":"index","update":"update"},"actions":{"edit":"Edit"},"controller_names":{"Admin::AccessController":"Access","Admin::AdobeChallengeItemsController":"Adobe challenge items","Admin::AdobeChallengesController":"Adobe challenges","Admin::AdobeSalesImportsController":"Adobe sales imports","Admin::ApproveController":"Models details approval in model page","Admin::BannedIpsController":"Banned IPS","Admin::BlacklistedDomainsController":"Blacklisted email domains","Admin::BlogPostsController":"Blog posts","Admin::BonusCreditsController":"Bonus credits","Admin::BulkActionsController":"Bulk Actions","Admin::BusinessAccountsController":"Business accounts","Admin::BusinessGroupsController":"Business groups","Admin::CategoriesController":"Categories","Admin::ChallengesController":"Challenges","Admin::CompetitionSubmissionsController":"Competition submissions","Admin::ConversationForbiddenWordsController":"Conversation forbidden words","Admin::ConversationMessagesController":"Conversation messages","Admin::ConversationsController":"Conversations","Admin::CouponOrdersController":"Coupon orders","Admin::CouponsController":"Coupons","Admin::CustomCtrValuesController":"Custom CTR Values","Admin::CustomReputationPointsController":"Custom reputation points","Admin::DashboardBannersController":"Dashboard banners","Admin::DashboardController":"Dashboard","Admin::EcommerceNewsController":"E-commerce News","Admin::EmployeesController":"Employees","Admin::EventsController":"Events","Admin::FeaturesController":"Features","Admin::FileConversionRequestFormatsController":"File conversion request formats","Admin::FileConversionRequestsController":"File conversion requests","Admin::FileExtensionsController":"File extensions","Admin::FileTypesController":"File types","Admin::FilterPresetsController":"Filter presets","Admin::ForumBoardsController":"Forum boards","Admin::ForumTopicsController":"Forum topics","Admin::GalleriesController":"Galleries","Admin::GalleryCategoriesController":"Gallery categories","Admin::HundredPercentRoyaltiesController":"Hundred percent royalties","Admin::ImagesController":"Images","Admin::IpAddressesController":"IP addresses","Admin::ItemFilesController":"Item files","Admin::ItemOrdersController":"Item orders","Admin::ItemsController":"Items","Admin::JobOrdersController":"Job orders","Admin::JobTagsController":"Job tags","Admin::JobTemplatesController":"Job templates","Admin::JobsController":"Jobs","Admin::ManufacturersController":"Manufacturers","Admin::Moderate::BatchesController":"Batches","Admin::Moderate::ChallengeItemsController":"Challenge moderation","Admin::Moderate::ItemsController":"Items","Admin::Moderate::KeywordsController":"Keywords","Admin::Moderate::ModelsController":"Models","Admin::Moderate::TrendingItemsController":"Trending items","Admin::MqsController":"MQS","Admin::Notification::TemplatesController":"Notification templates","Admin::PageCacheController":"Page cache control","Admin::PageCategoriesController":"Page categories","Admin::PagesController":"Pages","Admin::PartnershipDealsController":"Partnership deals","Admin::PaymentAgreementsController":"Payment agreements","Admin::PayoutImportsController":"Payout imports","Admin::PayoutsController":"Payouts","Admin::PbrTextureNamesController":"PBR Textures","Admin::PrinterTypesController":"Printer types","Admin::PromotionalConversationBatchesController":"Promotions","Admin::RedirectionsController":"Redirections","Admin::ReferralsController":"Referrals","Admin::RefundImportsController":"Bulk refunds","Admin::RefundsController":"Refunds","Admin::RenderersController":"Renderers","Admin::ReportedConversationsController":"Reported conversations","Admin::ReportedJobsController":"Reported Jobs","Admin::ReputationLogsController":"Reputation logs","Admin::ReputationScoresController":"Reputation scores","Admin::SaleOffController":"SaleOff","Admin::SearchDebuggerController":"Search debugger","Admin::SellerDashboardNewsController":"Seller dashboard news","Admin::SeoTagsController":"Seo Tags Information","Admin::SettingsController":"Settings","Admin::SimpleResourcesController":"SimpleResources (will be removed)","Admin::SoftwareController":"Software","Admin::SuspiciousConversationsController":"Suspicious conversations","Admin::TakeoversController":"User takeover","Admin::TutorialCategoriesController":"Tutorial sategories","Admin::TutorialSoftwaresController":"Tutorial softwares","Admin::TutorialsController":"Tutorials","Admin::UnrestrictUserController":"Unrestrict User","Admin::UrlShortcutsController":"Url shortener","Admin::UserTrustPoliciesController":"User Trust Policy","Admin::UserWarningsController":"User warnings","Admin::UsersController":"Users","Admin::WebflowPagesController":"Webflow pages"},"filters":{"username":"Username"},"title":"Access Management"},"business_accounts":{"item_unassigned":"Model unassigned.","items_assigned":"Assigned %{count} model(s)."},"challenges":{"adobe_status":{"approved":"Approved by Adobe","disapproved":"Disapproved by Adobe","none":"","resubmitted":"Resubmitted to Adobe","sent":"Sent to Adobe","to_send_to_adobe":"To send to Adobe"},"problems":{"asset_rotation":"Rotate asset so the most interesting side faces toward Z Positive axis in Maya or Y Positive Axis in 3ds Max","chaosgroup_standard":"Materials assigned to geometry must be Chaosgroup V-Ray Standard Material (VRayMtl) UV Layout (0-1 space, non-overlapping)","consistent_file_names":"Use camelCase or underscores and be consistent when naming the files. English only and be descriptive","consistent_normals":"Normals for the entire asset should have consistent facing direction","fit_theme":"Model does not fit the challenge theme","flatten_modifiers":"Flatten all modifiers (\"delete history\") before submission","formats":"Autodesk Maya or 3ds Max format only (.ma, .mb, .max, .3ds)","freeze_transformations":"Freeze Transformations (Reset xForm in Max)","geometry_separated":"Assets should have the geometry separated based on the materials","missing_faces_open_holes":"Ensure asset do not have any missing faces or open holes","models_placing":"Place models so they sit on top of the origin (0, 0, 0). No floating models","no_logos_trademarks":"Model should not display any logos or trademarks","real_world_size":"Use real world size (Centimeters)","sce
16518ne_materials":"Scene should consist of 3D model and connected V-Ray Standard materials only","texture_format":"Texture maps should be in PNG format (JPG and EXR accepted, but not preferred)","texture_image_size":"Texture image size should be square resolution, minimum of 2K (2048 x 2048). Use higher resolution if needed","topology_max_pole_edges":"Poles should have maximum of 5 edges","topology_triangles_quads":"Only quads are accepted. Triangles can be used sparingly and only where absolutely necessary"},"status":{"approved":"Public","disapproved":"Disapproved","re-published-review":"Re-published Review","re_published_review":"Re-published Review","to-review":"To review","to_review":"To review","withdrawn":"Withdrawn"}},"employees":{"teams":{"designers_team":"3D team","development":"Development","marketing":"Marketing","other":"Other","product":"Product","sales":"Sales","stakeholders":"Stakeholders","support":"Support"}},"file_conversion_requests":{"reply_message":{"can_use_existing_file":"We would like to let you know that you can import the existing %{format_name} file and will work as expected. You can buy this model with confidence or download the files if you have already made the purchase.","cannot_convert":"We are sad to let you know that such a conversion is not possible. We hope that you will be able to find other models in the marketplace that will suit your needs.","converted":"We would like to let you know that your request has been successfully completed and you can buy this model with confidence or download the required file if you have already made the purchase.","other":""}},"mqs":{"problems":{"clean_edge_flow":"Clean edge flow","correct_face_normals":"Correct face normals","description":"Product description","exchange_formats":"Exchange formats","frozen_controllers":"Frozen/zeroed rig transform controllers","good_naming":"Object, texture, layer and material naming","good_oriantation":"Correct model orientation (world-up axis)","good_position":"Model position at the origin (0,0,0)","good_transforms":"Reset/frozen model's transforms (position, rotation, scale)","instructions":"Intructions for custom rigs (readme, PDF document, etc.)","logical_arrangement":"Logical object arrangement (groups, layers, hierarchy)","native":"At least one native format (.max / .ma /.mb / .c4d / .lws / .blend)","no_coincident_vertices":"No coincident vertices","no_coplanar_faces":"No coplanar faces","no_creasing":"Holding/support edges (no Creasing)","no_default_names":"Rig hierarchy naming (no default names)","no_empty_objects":"No empty objects","no_errors":"Opens and renders without errors","no_isolated_vertices":"No isolated vertices","no_materials":"No objects without materials","no_mesh_holes":"No mesh holes","no_overlap":"No overlapping UVs","no_poles":"No poles with more than 5 edges","no_t_vertices":"No T-vertices","no_unnecessary_data":"No unnecessary data in the scene","no_uv_streching":"No visible UV stretching or obvious seams","previews":"Accurate model previews","quad_based_topology":"Quad based topology","real_world_scale":"Real world scale","smooth":"Smooth animation (no glitches or hitches)","striped_file_paths":"Str
16518ipped file paths (textures and other external assets)","structure":"File \u0026 Folder structure","uv_space":"0-1 UV space","wireframe_previews":"Wireframe previews"},"status":{"approved":"Approved","disapproved":"Disapproved"}},"notifications":{"job_failed_to_finish":"Job failed to finish","job_marked_as_finished":"Job has been marked as finished, payouts released","manually_distrusted_user":"User #%{id} is now distrusted! All future projects will require manual approval.","manually_trusted_user":"User #%{id} is now trusted! All future projects will be auto-approved.","refunding_disabled":"Refunding is disabled at the moment because payouts are being processed.","trust_policy":{"manually_distrusted_user_reason":"Manual distrusted by moderator: %{username}","manually_trusted_user_reason":"Manual trusted by moderator: %{username}"}}},"ancestry":{"cannot_delete_descendants":"Cannot delete record because it has descendants.","cannot_rebuild_depth_cache":"Cannot rebuild depth cache for model without depth caching.","conflicting_parent_id":"Conflicting parent id found in node %{node_id}: %{parent_id} for node %{node_id} while expecting %{expected}","exclude_self":"%{class_name} cannot be a descendant of itself.","invalid_ancestry_column":"Invalid format for ancestry column of node %{node_id}: %{ancestry_column}.","invalid_orphan_strategy":"Invalid orphan strategy, valid ones are :rootify, :adopt, :restrict and :destroy.","no_child_for_new_record":"No child ancestry for new record. Save record before performing tree operations.","option_must_be_hash":"Options for has_ancestry must be in a hash.","reference_nonexistent_node":"Reference to nonexistent node in node %{node_id}: %{ancestor_id}.","unknown_depth_option":"Unknown depth option: %{scope_name}.","unknown_format":"Unknown ancestry format: %{value}.","unknown_option":"Unknown option for has_ancestry: %{key} =\u003e %{value}."},"api":{"profile":{"actions":{"contact":"Contact","follow":"Follow","follow_tooltip":"Start following this designer to get updates about his content and easily filter favorite designers in Search results","hide":"Hide","hire_me":"Hire me","invite_client":"Start a Project","mute_tooltip":"Hide this designerâs models in the Search results","take_over":"Take over","unfollow":"Unfollow","unhide":"Unhide","view_all_models":"View all Designer's Models"},"private_project_review":"Private Project"},"responses":{"collection_archive_request":{"bad_parameters":"Bad parameters or parameters are missing.","success":"Collection Archive Request updated."},"file_ownership":"You do not own the specified file","invalid_file_id":"Invalid or nonexistent file ID provided","invalid_model_id":"Invalid or nonexistent model ID provided in URI","model_file_mismatch":"File does not belong to model"}},"arsenal":{"meta":{"description":"CGTrader ARsenal is a scalable enterprise 3D asset development platform representing a breakthrough in the way retailers plan, implement and finance 3D product visualization.","title":"CGTrader Arsenal - 3D Product Visualization Solution"}},"blogging_contest":{"meta":{"description":"CGTrader is calling for all bloggers interested in design to join the conversation about the future of design and win $4000 along the way.\n","title":"Bloggers' competition"},"notifications":{"success":"Thank you for participating! You will receive a confirmation email from us shortly."}},"browser":{"3d_models":"3D models","3d_print":"3D Print","active_filters":{"polygons":"%{range} polygons"},"adult_content":"Show Age+","animated":"Animated","breadcrumb":{"browse_by_type":"Browse by type","collection":"3D Model Packs","free":"free","free_models":"Free 3D Models","free_print_models":"Free 3D Printer Files","low_poly":"low-poly","low_poly_models":"VR / AR / low-poly 3D Models","low_poly_print_models":"Low-poly 3D Print Models","model_3d":"3D model","model_3dp":"3D print model","models":"3D Models","models_3d":"3D models","models_3dp":"3D print models","models_variant_0":"3D Models","models_variant_1":"3D Assets","models_variant_2":"VR Models","models_variant_3":"CG Models","models_variant_4":"3D Model Store","models_variant_5":"3D Objects","print_models":"3D Print Files","print_models_variant_0":"3D Print Models","print_models_variant_1":"3D Printer Models","print_models_variant_10":"3D Models For Print","print_models_variant_11":"3D Models To Print","print_models_variant_12":"3D Files For Printing","print_models_variant_13":"3D Models For Printer","print_models_variant_14":"Models For 3D Printing","print_models_variant_15":"3D Prints Models","print_models_variant_16":"3D Printable Files","print_models_variant_2":"3D Models For Printing","print_models_variant_3":"3D Printing Models","print_models_variant_4":"3D Print Files","print_models_variant_5":"3D Printing Files","print_models_variant_6":"3D Printer Files","print_models_variant_7":"3D Printable Models","print_models_variant_8":"Printable 3D Models","print_models_variant_9":"3D Printed Models"},"buyer_engagement_program":"Discounts","categories":"Categories","categories_page_title":"Buy 3D Models or download free 3D Models","category":{"meta":{"3d_models":"%{count} %{category} 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download %{count} %{category} 3D print files ready for FDM, SLA, SLS, and other 3D printers, available formats STL, OBJ, 3DM, and more.%{page}","animated_3d_models":"%{count} %{category} animated 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Download %{count} %{category} free 3D files, available in MAX, OBJ, FBX, 3DS, C4D file formats, ready for VR / AR, animation, games and other 3D projects.%{page}","free_3d_print_models":"Download %{count} %{category} free 3D print files ready for FDM, SLA, SLS and other 3D printers, available formats STL, OBJ, 3DM and more.%{page}","lowpoly_3d_models":"Download %{count} VR / AR / low-poly %{category} 3D models ready for Virtual Reality, games and other real-time apps, available in FBX, OBJ, MAX, 3DS, C4D file formats.%{page}","rigged_3d_models":"%{count} %{category} rigged 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"cgt_verified":"3D Print Verified","collection":"Pack","descriptions":{"free_3d_models":"Here you can find and download free 3D models. Use filters at the left side of the page to find models for 3D print, game-ready 3D models or filter by file format such as Autodesk 3ds max, Maya, Softimage, Cinema4D or any other 3D modeling program.","game_ready_3d_models":"Here you can find game ready or low-polygon 3D models. Use filters at the left side of the page to filter by file format such as Autodesk 3ds max, Maya, Softimage, Cinema4D or any other 3D modeling program.","print_ready_3d_models":"Here you can find and download 3D print models. Use filters at the left side of the page to filter by file format such as Autodesk 3ds max, Maya, Softimage, Cinema4D or any other 3D modeling program."},"discounts":"Discounts","ext":{"meta":{"3d_models":"Download %{count} %{ext} files - %{software_name} 3D models ready for VR / AR, 3D design, animation, games and real-time apps.%{page}","3d_print_models":"Download %{count} %{ext} files - %{software_name} 3D print models ready for VR / AR, 3D design, animation, games and real-time apps.%{page}"}},"filter":"Filter","filter_button":"Apply filters","filters":{"adult_content_only":"Adult content only","cgt_standard_only":"CGT Standard","cgt_verified":"3D Print Verified","collections_only":"Packs only","content_filters":"Content filters","designer":"Designer","exclude_3d_print":"Exclude 3D Print","exclude_adult_content":"Exclude adult content","exclude_ai_generated":"Exclude AI generated content","exclude_editorial_license":"Exclude editorial license","exclude_free":"Exclude free","file_format":"File formats","following":"Following","free":"Free","has_marmoset":"Has 3D viewer","has_video":"Has video","include_ai_generated":"Include AI generated content","label":"Filters","poly_count":"Poly count","print_ready":"3D print","stl_files":"STL files","subscription":"Subscription","type":"Type"},"formats":"Formats","free":"Free","free_models":"Show free models only","free_to_premium":{"main":"%{category} 3D models","postfix":"in the premium listing.","prefix":"Do you need something special? You can find better quality"},"gallery":{"preview":"preview"},"game_ready":"Game ready","high_poly":"High-poly","items_page_title":"3D Models","license":{"exclude_branded":"Exclude Branded","exclude_editorial":"Exclude Editorial","prompt":"License","tooltip_more":"Read more","tooltip_text":" Don't show models that can only be used in non-commercial, educational purposes. ","tooltip_title":"Exclude Editorial:"},"low-poly":"Low-poly","low_poly":"Low-poly","meta":{"3d_models":"Browse all 3D models available on CGTrader to find the perfect one for your project. Sort, filter and compare 3D assets from professional designers.","3d_print_models":"View 3D print files from all categories on CGTrader. Refine, sort, and filter professional 3D printing objects to match your needs and printer capabilities.","animated_3d_models":"Animated models for use in games, movies and other projects. These models come pre-packed with some movements and specific actions. These help you save time and valuable resources during the development or prototyping process. Choose PBR textured models to make sure theyâd look great in all lighting conditions.\n","free_3d_models":"Download %{count} free 3D models, available in MAX, OBJ, FBX, 3DS, C4D file formats, ready for VR / AR, animation, games and other 3D projects.%{page}","free_3d_print_models":"Download %{count} free 3D print files ready for FDM, SLA, SLS and other 3D printers, available formats STL, OBJ, 3DM and more.%{page}","lowpoly_3d_models":"Low poly models for download. These models have a smaller number of polygons and require less computing power. Low-poly models are best used in applications like VR, AR, games, especially mobile games. Choose from our collection of rigged and animated models for the best performance in your apps.\n","metaverse":"Enter the metaverse with our collection of high and low-poly 3d models rigged, animated and available any any file format.","newest_cg":"Download the latest 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","newest_print":"Download the latest and newest 3D print models, available in STL and 3MF file formats.","omniverse":"Build your virtual world with our Omniverse-ready 3D models. Choose from animated, rigged and PBR models with high and low polygon count.","page_prefix":"Page %{page_number} with ","pbr_3d_models":"Physically based rendering, or PBR, denotes models which are accurately and consistently rendered in any lighting conditions due to the texturing workflows used in the process. Developers can easily use these models across all major rendering engines.\n","rigged_3d_models":"Need movable models? Check out our collection of rigged 3D models, which are your go-to choice when you need a character or object to perform unique, specific movements. Rigged 3D models are available in Autodesk 3dsmax (.max), Maya (.ma), Softimage (.xsi), Cinema4D (.c4d) and many other file formats.\n","snap-ar":"With our 3D models you can join million of Snapchatters using Snap AR to create fun augmented reality experiences.","spark-ar":"Brighten up your Facebook and Instagram with a variety of Spark AR 3D models that are rigged, animated and ready to use.","stream_3d_print_models":"Browse through a variety of stream 3D print model categories to discover some of the most extraordinary 3D printable designs from professional 3D creators.","textures":"%{count} Textures 3D assets and materials available for download in various formats including .tga .sbsar .jpeg .png .tiff and other. %{page}","tiktok":"Make your video effects more impressive with TikTok 3D models. Our library can fulfill all of your creative needs and is constantly updated.","top_selling_cg":"Download top-selling 3D models of %{year}, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","top_selling_print":"Download top-selling 3D print models of %{year}, available in STL and 3MF file formats.","trending_cg":"Download the most popular and trending 3D models of %{month} %{year}, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","trending_print":"Download the most trending 3D printed items and products of %{year}, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","unity":"Find 3D models for your Unity project in any file format and any poly count. Everything you need to create a unique virtual environment.","unreal":"Create impressive visualizations with Unreal Engine compatible 3D models in any file format. Our library has low and high-poly models from every category."},"multiple_parts":"Multiple parts","optimized":"Low-poly / PBR","pbr":"PBR","pbr_texture":"PBR Texture","pbr_textures":{"description":"Download thousands of high-quality PBR textures for 3D models and game assets. Explore a massive library built for 3D artists, designers, and game developers.","h1":"Free \u0026 premium PBR textures and materials","intro":"Download high-quality PBR textures from our huge library of free individual materials and premium packs optimized for Unreal, Unity, Blender, Sketchup, and more.","tag_description":"Download high-quality %{tag} PBR textures for 3D models and game assets. Explore a massive library built for 3D artists, designers, and game developers.","tag_h1":"Free \u0026 premium %{tag} PBR textures and materials","tag_intro":"Download %{tag} PBR textures optimized for Unreal, Unity, Blender, Sketchup, and more. %{model_count} of free individual materials and premium packs.","tag_title":"%{tag} PBR textures and materials","title":"PBR textures and materials - free \u0026 premium"}
16518,"per_page":"Per Page","polygons_options":{"custom":"Custom range","gt_250k":"250k+","lt_5k":"Up to 5k","more_than_250000":"250K+","prompt":"Poly count","range_0_5000":"Up to 5K","range_100000_250000":"100 - 250K","range_10000_50000":"10 - 50K","range_100k_250k":"100k to 250k","range_10k_50k":"10k to 50k","range_50000_100000":"50 - 100K","range_5000_10000":"5 - 10K","range_50k_100k":"50k to 100k","range_5k_10k":"5k to 10k"},"pre_supported":"Pre-supported","price":"Price: $%{from}-%{to}","price_range":"Price","print_ready":"3D print ready","printable":"3D printed","reset_button":"Reset filters","rigged":"Rigged","rounded_count":{"exact":"%{n}","million":"%{n}M+","thousand":"%{n}+"},"sale_off":"On sale","search_placeholder":"Search keywords","show_all_formats":"Show all formats","simulation_ready":"Simulation-ready","sort_by":"Sort By","sort_by_options":{"best_match":"Best Match","highest_price":"Higher price","lowest_price":"Lower price","newest":"Newest","oldest":"Oldest","sales":"Top Selling","trending":"Trending"},"subcategory":{"meta":{"3d_models":"%{count} %{category} 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download %{count} %{category} 3D print files ready for FDM, SLA, SLS, and other 3D printers, available formats STL, OBJ, 3DM, and more.%{page}","animated_3d_models":"%{count} %{category} animated 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Download %{count} %{category} free 3D models, available in MAX, OBJ, FBX, 3DS, C4D file formats, ready for VR / AR, animation, games and other 3D projects.%{page}","free_3d_print_models":"Download %{count} %{category} free 3D print files ready for FDM, SLA, SLS and other 3D printers, available formats STL, OBJ, 3DM and more.%{page}","lowpoly_3d_models":"Download VR / AR / Low poly %{tag} 3D models ready for Virtual Reality, games and other real-time apps, available in FBX, OBJ, MAX, 3DS, C4D file formats.%{page}","rigged_3d_models":"%{count} %{category} rigged 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"subtitle":{"aircraft":"In our hangar you will find 3D aircraft models from CG airplanes to drones that will elevate your simulations, videos and advertisements. Fully rigged airborne models are ready to jet off into your next game or animation project. Compatible with all 3D software our assets ensure your journey flies smoothly.","animals":"Ready to spark life into your virtual worlds? With countless 3D models of animals you are now ready to populate your digital landscapes. Find rigged animals to animate in your dynamic scenes and low-poly ones that will fit perfectly in your game. Buy or download assets for free without any format constraints to worry about.","animated":"Explore fully animated %{tag} 3D models to speed up your workflow and bring your projects to life instantly.\n","architectural":"A broad collection of 3D architecture models, each rich with elements and design details of real-world construction. They are your building blocks for creating lifelike renders, immersive game environments and engaging animations. Browse through detailed high-poly ones or simple yet beautiful low-poly PBR designs. A catalog of versatile architectural assets ensure your project's vision takes shape, no mater your software of choice.","car":"Your next ride awaits in our virtual garage. Browse through endless pages of 3D models of cars and expand your car collection for every project and occasion. Rigged low poly automobiles to be animated into your next racing movie and classic retros for a vintage vibe in your lifelike renders are ready to be discovered. Park them in your software of choice without format constraints.","character":"In our vast world of 3D models of characters, all mythical creatures, sci-fi beings and even humans are welcome.Objects of any universe are set to be the center piece of your future motion graphics project or video game. Animated assets from our collection come in all the popular 3D formats and are set to integrate into your workflow seamlessly.","custom"
16518:"Here you can buy or download free %{tag} 3D models. %{tag_heading_subtitle}","electronics":"%{count} electronics 3D models available for download. This is a category for architects, interior decorators, level designers, scene makers and other creatives. 3D models of %{smartphones_link}, %{laptops_link}, %{cameras_link}, %{tvs_link} and more will help to accurately capture modern lifeâs obsession with devices and technology. There are 3D models available in file formats including FBX, OBJ, MAX, 3DS, C4D. Download free or buy premium models and use for animation, games and VR/AR projects.","exterior":"Imagine having a wide array of 3D exterior models at your fingertips. Our collection serves every architect's and designer's needs, providing everything from general assets to urban buildings and full cities. Ease your design process of highly detailed exterior rendering and visualization or up the details of your games with ready to use, diverse and versatile models available in the most popular 3D formats.","food":"Step into our virtual pantry with 3D models of food that can add mouthwatering realism to any scene. All the appetizing 3D assets from fruits and vegetables to pizzas and burgers await to be part of your animations. Looking for some beer or wine to decorate your barbecue scenes and renders? We've got you covered, served fresh and in all the popular file formats.","formats":"There currently are %{found_items_count} 3D models ready for download in the %{required_software_title} file format on \nthe marketplace. Feel free to browse the collection and do not forget to use the other search filters to find \nPBR, rigged, animated or printable 3D models for your projects. If youâre a game developer use the âPoly countâ filter \nto view low-poly 3D models which need less computational power to render. The majority of 3D assets on CGTrader are \navailable in several file formats, and if a model you want is unavailable in the %{required_software_title} file format, \nyou can always ask for a file conversion by selecting âRequest free file format conversionâ on the product page. You can \nalso visit our 3D Jobs page and post a request for model conversion, custom models and any other modeling services you \nmight need.\n","free_general":"Free 3D models available for download from %{link_1} to %{link_2} 3D assets. Available in number of file formats including MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB. Find professional %{link_3} for any 3D design projects like virtual reality (VR), augmented reality (AR), games, 3D %{link_4} visualization or animation.","free_no_tag":"%{model_count} free 3D %{tag} models ready for 3D printing. Download %{tag} free 3D print models, file formats available including STL, OBJ, 3DM, 3DS, MAX. 3D models are ready to be used with FDM, SLA, SLS and other types of 3D printers.","free_printable":"%{model_count} free 3D models ready for 3D printing. Download free or look for premium 3D print models. File formats available including STL, OBJ, WRL. 3D models are ready to be used with FDM, SLA, SLS and other types of 3D printers.","free_tag":"Free 3D %{tag} models available for download. Available in many file formats including MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB. Find professional %{tag_link} for any 3D design projects like virtual reality (VR), augmented reality (AR), games, 3D visualization or animation.","furniture":"Ready to explore our showroom of 3D furniture where comfort meets versatility of models? At CGTrader you will find them in all shapes and forms in the file format of your choice. Expand your collection with couches, chairs and tables for your visualization projects or add a touch of realism with PBR low poly models to your game's interior or exterior scenes.","general":"This view-all page contains 3D models from every category on CGTrader. You can refine the product selection to show Animated, Rigged, PBR or Low Poly models in the most popular file formats using available filters. Sort 3d assets by price, popularity or newness to find exactly what you are looking for.","high_poly":"Buy or download Animated Professional 3D models ready to be used in CG projects, film and video production, animation, visualizations, and others. Assets are available for download in many industry-accepted formats including MAX, OBJ, FBX, 3DS, UE4 and other. If youâre in search of high poly quality 3D assets, we have a leading digital art library for all your needs.\n","household":"Make your projects feel like home with our collection of 3D household models. Familiar appliances,
16518kitchen utensils, cleaning tools and elements of decor are here to bring warmth and lifelike realism into your scenes with digital objects. Perfect for interior design renders, video games, lifestyle scenes or any digital environment, these useful assets can transform your next project into a true masterpiece, filled with the comfortable charm of home.","industrial":"Whether it's static structures or animated assets you are after, our library of industrial 3D models will add precision and detail to any scene. Ideal for constructing lively, interactive environments, illustrating intricate processes or just filling a project with raw metal goodness, these industriall-themed models are ready to rev up your creations.","interior":"With an extended selection of 3D models for interiors you have the power to shape your indoor spaces and make your interior designs pop with high quality 3D assets. Create lifelike interior visualization renders with high-poly assets for archviz or chose the low-poly highly optimized ones for your game's closed spaces. Ease into the design process worry free - whether you are a game dev, an architect or an animator, our platform's got you covered.","low_poly":"%{count} low poly 3D %{tag} models are available for download. These models contain a significantly smaller number of polygons and therefore require less computing power to render. Models which have fewer polygons are best used in real time applications that require fast processing, like virtual reality (VR), augmented reality (AR), mixed reality (MR), cross reality (XR) and games, especially mobile games. Choose from our collection of rigged and animated models to easily use them in your real-time applications. Get 3D assets for environments, pick props, objects or buy complete 3D model collections, bundles and packs with everything your game might need. Save development time and costs, make prototype experiences or use 3D models as placeholders in your project. To find models that render predictably in various engines, use the PBR filter next to the search bar.\n","military":"Arm yourself with versatile 3D military models and get to the frontline of epic medieval battles and futuristic sci-fi wars. Ideal for games, simulations or cinematic projects that are in need of some explosive action. Gear up to transform your virtual battlefield with modern weapons or historical armour. Pre-optimized 3D assets are ready to be imported in game engines and are rigged for dynamic scenes. Available in any file format for maximum compatibility.","not_custom":"%{found_items_count} 3D %{tag} models available for download. 3D %{tag} models are ready for animation, games and VR / AR projects. Use filters to find rigged, animated, low-poly or free 3D models. Available in any file format including FBX, OBJ, MAX, 3DS, C4D","optimized":"Models which have fewer polygons are best used in real time applications that require fast processing, like virtual reality (VR), augmented reality (AR), mixed reality (MR), cross reality (XR) and games, especially mobile games. Choose from our collection of rigged and animated models to easily use them in your real-time applications. Get 3D assets for environments, pick props, objects or buy complete 3D model collections, bundles and packs with everything your game might need. Save development time and costs, make prototype experiences or use 3D models as placeholders in your project. Physically based rendering, or PBR, denotes models which are rendered accurately and consistently in any lighting conditions due to the texturing workflows used in the creation process.\n","pbr":"Physically based rendering, or PBR, denotes models which are rendered accurately and consistently in any lighting conditions due to the texturing workflows used in the creation process. Reflectiveness, surface roughness and colouring, together with the principle of energy conservation and the advantages of the bidirectional reflectance distribution function (BRDF), provide the best standard for any 3D objects that can be rendered in any lighting conditions. A PBR 3D model will never reflect more light than hits its surface. PBR textures are available in all standard file formats. CGTrader also offers 3D model conversion to PBR for some models. Use PBR models across all major rendering engines, like Unity, Unreal engine, Marmoset Toolbag 3 and others, which support physically based rendering.\n","plant":"Invite nature into your projects with these 3D plants. Foliage, trees and beautiful flowers are easy to download. Perfect for enhancing outdoor scenes, architectural visual
16518s, or crafting enchanting landscapes, our catalog of 3D vegetation will breathe a breath of fresh air into your work. And with all major file formats available, you can effortlessly bring nature's charm into your next scene.","printable":"Browse all 3D printing models from various categories on CGTrader. Filter, sort and refine our extensive library of printable 3D objects by date, popularity and price to easily find the desired product for your professional needs as well as fun home projects for beginners.","printable_merged_tag":"Here you can find %{tag} 3D print files (STL, OBJ, FBX, and many others) ready for printing. Purchase and download free 3D models, stream and print with your 3D printer.","printable_tag":"Here you can find %{tag} 3D print files (STL, OBJ, FBX, and many others) ready for printing. Purchase and download 3D models, stream and print with your 3D printer.","rigged":"Browse rigged %{tag} 3D models ready for animation, ideal for game development and production pipelines.\n","scanned":"%{count} scanned 3D models are available for purchase or free download. 3D Scanned Models are ready for animation, games and VR / AR projects. You can find 3D models of objects found in nature such as rocks and natural surfaces, humans and other real life objects here...and it cannot get any more realistic than this. Use filters to find rigged, animated, low-poly or free 3D models. Available in any file format including FBX, OBJ, MAX, 3DS, C4D.","science":"%{count} science 3D models available for download in this category range from medicine, biology, physics, chemistry fields and other real world objects related to science and technology: laboratory equipment, microscopic bodies and subatomic world. Look no further, %{cell_link}, %{skull_link} and %{skeleton_link} 3D models can be found here! To buy or download a free 3D assets, browse the categories above. You can use rigged models for animation or low-poly ones for games and VR / AR projects. Both free and premium 3D models can be found in a number of file formats including FBX, OBJ, MAX, 3DS, C4D.","scripts_plugins":"%{count} 3D Scripts / Plugins are available for download. 3D Scripts / Plugins can be added to various software and used to make your work pipeline more efficiently. Filter by formats to find tools fitting your prefered software.\n","space":"Journey to the stars with myriads of space themed 3D models. Spaceships, celestial bodies and shuttles will take your future projects far and beyond, no matter your software of choice. Our space arsenal features a broad spectrum of 3D assets, including rigged and low-poly ones, ideal for efficient rendering in game development or real-time applications like VR and AR experiences. Bring your ideas light years ahead now and explore the cosmos.","sports":"%{count} sports 3D models available nest together equipment that is used for recreational activities, entertainment, exercise, leisure, pleasurable pastime, fun as well as games, children toys and full range of musical instruments. To buy or download a free 3D model in any file format needed, including FBX, OBJ, MAX, 3DS, C4D, browse the categories above. You can use models for animation, games, VR/AR projects - plenty of them are rigged, low-poly or animated already.","test":{"airplane":"Aviation enthusiasts, listen up, it has never been so easy to get the perfect 3D printed airplane model for your board game or model collection. Search through %{model_count} 3D printable airplane models and find a model you just need to have on that shelf. Discover real airplane models or made-up ones. Search for newest designs or something that counts back from the time of the Wright brothers. Itâs also a perfect gift for any child who dreams to be a pilot when he grows up. Purchase and download a 3D print model, print it by yourself or submit the model to one of our 3D printing service providers to have it printed and shipped to you in no time!\n","anatomy":"%{model_count} 3D Anatomy models available for download on our marketplace. Explore the human anatomy with high - poly bone, muscle, organ models. Perfect for any educational or scientific project. Use printable 3D models for improved education experience. Create stunning animations and video games with our\n vast library of rigged models. Use our advanced filtering system to easily find low poly, animated, PBR,\n rigged models or anything that suits your needs best. Choose from a great deal of file formats including the\n most popular ones like FBX, OBJ, MAX, 3DS, C4D.\n","castle":"Your own astonishing 3D printed castle is a click away! Search various 3D castle models ready for 3D printing. Create a unique fantasy fortress for your D\u0026D session or any other medieval rpg tabletop game. These medieval fortresses are an amazing gift for any board game enthusiast or a great addition to your own collection. Find the perfect 3D model for painting hobbyists or a one of a kind toy for children. Purchase and download your chosen 3D castle design, print it with your own printer, or submit the model to one of our 3D printing service providers to have it printed and shipped to you.\n","dice":"Luck wonât run out with 3D printed dice! If you want authentic gaming dice for your board game night, look no more. Here you can choose between %{model_count} free 3D dice models ready for 3D printing. When the game is over, use these beautiful models as an accessory. Download free 3D printable dice models, file formats available including STL, OBJ, 3DM, 3DS, MAX. Our 3D models are ready to be used with FD
16518M, SLA, SLS and other types of 3D printers. Make your game a little more interesting and get your 3D printed dice!\n","drone":"3D print and build your own drone or find parts for replacement. 3D printed drones are easy to assemble and repair after a crash landing. Discover a model with the perfect camera mounting position or request for minimal alterations. Perfect for fun leisure activities, aerial photography, videography or mapping. Find and purchase a uniquely designed 3D drone model that fits all your needs. Print it by yourself or submit the model to one of our 3D printing service providers to have it printed and shipped to you in no time! Get your own 3D printed drone and roam the wide blue skies!\n","pokemon":"Pikachu, I choose you! Choose from loads of pocket monsters ready for 3D printing. Great to expand your 3D printed pokemon collection. Search and stumble upon the best, most detailed pokemon designs for your next tabletop game with friends. Purchase and download your 3D pokemon, print it with your own 3D printer, or submit the model to one of our 3D printing service providers to have it printed and shipped to you. After all, this is one of the coolest things to 3D print!\n","ring":"3D printed jewelry is the new black in the industry, as are 3D printed rings! Search an enormous amount of %{model_count} free 3D printable ring models. Browse through unique designs and find something made just for you. Canât find anything for yourself at the store? Or maybe you want an accessory exactly like the one your favorite movie character has? Choose from a great deal of file formats including STL, OBJ, 3DM, 3DS, MAX. 3D models are ready to be used with FDM, SLA, SLS and other types of 3D printers, so browse through our selection and try on your new favorite ring.\n","shoes":"Big brands are onboard with 3D printed shoes and now you can share the experience as well. Browse and find free printable shoe designs â from sneakers to fashionable heels there are a lot of ready-to-print models just waiting for you to try them on. Make the outcome perfect by selecting materials, adjusting softness and size. Choose from 146 free 3D shoe models and download them in available file formats including STL, OBJ, 3DM, 3DS, MAX. Designs are ready to be used with FDM, SLA, SLS and other types of 3D printers. Get your 3D printed shoes today!\n","textures":"Elevate your scenes with high-quality 3D textures from our extensive catalog. Discover a vast selection of detailed 3D materials for creating various surfaces that range from wood, metal and glass to things like grass and dirt. Boost your projects with realistic PBR textures and ensure easy workflow integration with top-notch quality assets that are available in all popular file formats. "},"ukraine_items":"3D models created by Ukrainian designers and designers who are donating their earnings to Ukraine","various":"%{count} various 3D models that donât easily find their place in other categories are available for download. %{rocks_link}, %{clouds_link}, %{logos_link}, %{cigarette_link} and other non-categorized 3D models that you might need to complete your game, animation or VR/AR project are here. Use filters to find rigged, animated, low-poly or free 3D models, or sort out by available formats such as FBX, OBJ, MAX, 3DS, C4D.","vehicle":"Many projects need 3D vehicles for action scenes and our catalog full of models for every kind of transportation. Rigged for games and animations or high poly ones for breathtaking renders, all are designed to make your scenes more dynamic. All types of sport and leisure as well as commercial and military vehicles are waiting to be driven to exciting destinations without file format constraints.","watercraft":"Ready to explore the deep sea or to set sail for a relaxing cruise across the world? We harbour 3D watercraft models for any kind of adventure. From roaring speedboats to majestic digital naval vessels, our collection anchors your projects in an ocean of possibilities, bringing the authentic sailor's life to your games and animations."},"tag":{"meta":{"3d_merged_premium":"Download %{count} free and premium %{tag} 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","3d_merged_premium_print":"Download %{count} %{tag} free \u0026 premium 3D print files ready for FDM, SLA, SLS and, other 3D printers, available formats STL, OBJ, 3DM, and more.","3d_models":"%{count} %{tag} 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download %{count} %{tag} 3D print files ready for FDM, SLA, SLS, and other 3D printers, available formats STL, OBJ, 3DM, and more.%{page}","animated_3d_models":"%{count} %{tag} animated 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","description":{"3d_merged_premium":{"vr":"Download %{model_count} free and premium VR 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","vr-character":"Download %{model_count} free and premium VR Character 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","vrchat":"Download %{model_count} free and premium VRChat 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats. Avatars, skins and more."},"3d_models":{"vr-hands":"Download %{model_count} free and premium VR Hand 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","vr-rooms":"Download %{model_count} free and premium VR Room 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats, ready for VR / AR, animation, games, and other 3D projects.","vrchat-alien":"Download %{model_count} free and premium VRChat Alien avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-angel":"Download %{model_count} free and premium VRChat Angel avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-anime":"Download %{model_count} free and premium VRChat Anime avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-assets":"Download %{model_count} free and premium VRChat assets available in MAX, OBJ, FBX, 3DS, and C4D file formats.","vrchat-avatar":"Download %{model_count} free and premium VRChat Avatars 3D models, available in MAX, OBJ, FBX, 3DS, and C4D file formats. Avatars, skins and more.","vrchat-base":"Download %{model_count} free and premium VRChat Base avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-bunny":"Download %{model_count} free and premium VRChat Bunny avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-cat":"Download %{model_count} free and premium VRChat Cat avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-chibi":"Download %{model_count} free and premium VRChat Chibi avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-female":"Download %{model_count} free and premium VRChat Female avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-femboy":"Download %{model_count} free and premium VRChat Femboy avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-furry":"Download %{model_count} free and premium VRChat Furry avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-girl":"Download %{model_count} free and premium VRChat Girl avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-male":"Download %{model_count} free and premium VRChat Male avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more.","vrchat-shark":"Download %{model_count} free and premium VRChat Shark avatars available in MAX, OBJ, FBX, 3DS, and C4D file formats. Characters, skins and more."}},"free_3d_models":"Download %{count} %{tag} free 3D models, available in MAX, OBJ, FBX, 3DS, C4D file formats, ready for VR / AR, animation, games and other 3D projects.%{page}","free_3d_print_models":"Download %{count} %{tag} free 3D print files ready for FDM, SLA, SLS and other 3D printers, available formats STL, OBJ, 3DM and more.%{page}","lowpoly_3d_models":"Download %{count} VR / AR / low-poly %{tag} 3D models ready for Virtual Reality, games and other real-time apps, available in FBX, OBJ, MAX, 3DS, C4D file formats.%{page}","rigged_3d_models":"%{count} %{tag} rigged 3D models available for download in any file format, including FBX, OBJ, MAX, 3DS, C4D.%{page}","title":{"3d_models":{"vr":"VR Models - Buy 3D models for VR\u0026AR | CGTrader","vr-character":"VR Character models | CGTrader","vr-hands":"VR Hand models | CGTrader","vr-rooms":"VR Room models: designs \u0026 ideas | CGTrader","vrchat":"VRChat 3D Models, Skins \u0026 Assets for sale | CGTrader","vrchat-alien":"VRChat Alien avatars for sale | CGTrader","vrchat-angel":"VRChat Angel avatars for sale | CGTrader","vrchat-anime":"VRChat Anime avatars for sale | CGTrader","vrchat-assets":"VRChat assets: hair, clothing, and much more! | CGTrader","vrchat-avatar":"VRChat Avatars, Skins, Characters for sale | CGTrader","vrchat-base":"VRChat Base avatars for sale | CGTrader","vrchat-bunny":"VRChat Bunny avatars for sale | CGTrader","vrchat-cat":"VRChat Cat avatars for sale | CGTrader","vrchat-chibi":"VRChat Chibi avatars for sale | CGTrader","vrchat-female":"VRChat Female avatars for sale | CGTrader","vrchat-femboy":"VRChat Femboy avatars for sale | CGTrader","vrchat-furry":"VRChat Furry avatars for sale | CGTrader","vrchat-girl":"VRChat Girl avatars for sale | CGTrader","vrchat-male":"VRChat Male avatars for sale | CGTrader","vrchat-shark":"VRChat Shark avatars for sale | CGTrader"}}}},"title":{"download":"| Download","files":"3D Files","formats":"Free \u0026 Premium %{required_software_title} %{product_type_title} (%{required_extension_title})","free":"Free 3D models","free_items_section":{"cg_general":"Free %{selected_filter}3D models of the day","cg_tag":"Free %{selected_filter}%{tag} 3D models of the day","print_general":"Free %{selected_filter}3D print models of the day","print_tag":"Free %{selected_filter}%{tag} 3D print models of the day"},"free_printing":"Free files for 3D printing","free_tag":"Free %{selected_tag} 3D models","general":"%{selected_filter}3D Models","high_poly":"%{selected_filter}3D Models","low_poly":"%{selected_filter}3D Models","newest_cg":"New \u0026 Latest 3D Models","newest_print":"New \u0026 Latest 3D Print Models","page_prefix":"Page %{page_number} of ","pbr":"PBR 3D Models","printing":"3D Print %{selected_filter}Models","sales_cg":"Best-Selling 3D Models","sales_print":"Best-Selling 3D Print Models","tag_heading":{"cg":"Free %{tag} STL print files","filter":"%{selected_filter}%{tag} 3D Models","general":"%{tag}
16518 3D models","merged_premium_print_tag":"Free \u0026 Premium %{selected_tag} print files","merged_premium_tag":"Free \u0026 Premium %{selected_tag} 3D Models","printable":"%{tag} 3D print files and models","tag":{"3d_merged_premium":{"vr":"VR Models","vr-character":"VR Character Models","vrchat":"VRChat Models"},"3d_models":{"vr":"VR Models","vr-character":"VR Character Models","vr-hands":"VR Hand Models","vr-rooms":"VR Room Models","vrchat":"VRChat Models","vrchat-alien":"VRChat Alien avatars","vrchat-angel":"VRChat Angel avatars","vrchat-anime":"VRChat Anime avatars","vrchat-assets":"VRChat assets","vrchat-avatar":"Buy VRChat Avatars, Skins, and Characters","vrchat-base":"VRChat Base avatars","vrchat-bunny":"VRChat Bunny avatars","vrchat-cat":"VRChat Cat avatars","vrchat-chibi":"VRChat Chibi avatars","vrchat-female":"VRChat Female avatars","vrchat-femboy":"VRChat Femboy avatars","vrchat-furry":"VRChat Furry avatars","vrchat-girl":"VRChat Girl avatars","vrchat-male":"VRChat Male avatars","vrchat-shark":"VRChat Shark avatars"}}},"trending_cg":"Trending 3D Models","trending_print":"Trending 3D Print Models","ukraine_items":"Support Ukraine ðºð¦"},"with_makes":"Has Makes"},"cart":{"request_invoice_failed":"Oops. Something went wrong.","request_invoice_successful":"Request Invoice successfully sent.","shareable_cart_created":"Cart successfully shared.","shareable_cart_failed":"Oops. Something went wrong.","subscription_covered_items_removed":"Removed from your cart: %{titles}. Already included in your subscription.","subscription_covered_order_refused":"Your subscription now includes %{titles}, so we did not charge you. Download from your subscription instead."},"categories":{"cg":{"header_title_html":"Buy Professional \u003cstrong\u003e3D models\u003c/strong\u003e","text":"Find the exact right 3D content for your needs, including AR/VR, gaming, advertising, entertainment and others"},"head-title":{"cg":"3D Models \u0026 Assets for Games, Films \u0026 VFX","cg-models":{"sort-by":{"newest":"New 3D Models","top-selling":"Best-Selling 3D Models","trending":"Trending 3D Models"}},"print":"3D Print Models \u0026 STL Files â Download \u0026 Buy","print-models":{"sort-by":{"newest":"New 3D Print Models","top-selling":"Best-Selling 3D Print Models","trending":"Top Trending 3D Printed Items"}},"product-type":{"plural":{"capital":{"cg":"3D Models","cg-merge-premium":"3D Models â Free \u0026 Premium Downloads","print":"3D Print Files And Models","print-free":"3D printer STL files","print-free-with-tag":"3D %{tag} STL print files and models","print-merge-premium":"%{tag} 3D print files - free \u0026 premium STL models","print-with-tag":"3D %{tag} STL Print Files And Models"},"lower":{"cg":"3D models","print":"3D STL print files and models"}},"singular":{"capital":{"cg":"3D Model","print":"3D Printing Model"},"lower":{"cg":"3D model","print":"3D printing model"}}}},"index":{"browse_all":"Browse all models","info-section__description_1_html":"Buy or free-download professional 3D models ready for CG projects, film and video production, animation, visualizations, games, VR/AR, and others. Assets are available for download in many \u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eindustry-accepted file formats\u003c/a\u003e, including MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB, and others.","info-section__description_1_printable_html":"Professional 3D files, prints, and models ready to be printed at home with desktop FDM or industrial SLS 3D printers, available in many industry formats including OBJ, \u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003e, WRL. If you are 3D printing hobbyist, maker, educator or business prototyping by 3D-printing, our home decorations, trendy gadget accessories, eye-catching fashion pieces, unique jewelry, mechanical parts, and variety of miniatures will surely give you an inspiration boost.","info-section__heading_1_html":"Explore 3D Model \u003cstrong\u003eCategories\u003c/strong\u003e","info-section__heading_1_printable_html":"Explore 3D Printing Model \u003cstrong\u003eCategories\u003c/strong\u003e","info-section__heading_2_html":"3D Models \u003cstrong\u003eMarketplace\u003c/strong\u003e","info-section__heading_2_printable_html":"What's \u003cstrong\u003emore\u003c/strong\u003e?"},"marketplace":{"3d-printing":{"link_text":"Browse 3D Print Models","text":"Find 3D print models for your 3D printer.","title":"3D Printing Models"},"blender_text":"Discover thousands of Blender 3D Models available in blend format.","browse":"Browse","cinema-4d_text":"Uncover thousands of high quality Cinema 4D Models available in c4d file format.","discounted":{"link_text":"Browse Discounted 3D Models","text":"Buy professional 3D models at a discount.","title":"Discounted 3D Models"},"low-poly":{"link_text":"Browse Low-poly 3D Models","text":"Low-poly 3D models ready for video games, VR \u0026 AR real-time applications.","title":"Low-poly 3D Models"}
16518,"pbr":{"link_text":"Browse PBR 3D Models","text":"Physically Based Rendering 3D Models.","title":"PBR 3D Model"},"scripts_apps":{"link_text":"Browse all","text":"3D scripts and plugins to make your 3D modeling pipeline more efficient.","title":"Scripts \u0026 Apps"},"sketchup_text":"Browse the vast selection of Sketchup 3D Models for your architectural, interior and video game designs.","textures":{"link_text":"Browse textures","text":"Ready-to-use textures to save you some time preparing your 3D models.","title":"Textures"},"zbrush_text":"Find ZTL file format 3D assets for your digital sculpting, 3D modeling, texturing and painting projects."},"meta-description":{"cg":"Browse 2M+ professional 3D models and assets for games, VFX, architecture and animation. Characters, vehicles, environments, and more â download in FBX, OBJ, MAX and other formats.","print":"Browse 800,000+ 3D print STL files for FDM and resin printing. Figurines, miniatures, cosplay props, jewelry, and more. Instant download. Multiple formats."},"more":{"designers":{"link_text":"Browse 3D Designers List","text":"Browse thousands of 3D designer portfolios and find exactly what you need for your application.","title":"Find Best 3D Designers"},"projects":{"link_text":"Learn more about 3D Projects","text":"Hire quality freelance 3D artists and solve all your custom modeling challenges.","title":"CGTrader 3D Projects"},"visualization":{"link_text":"Learn more","text":"Turn your products into photorealistic 3D models for e-Commerce and other business applications.","title":"3D Visualization for e-Commerce"}},"navbar":{"aircraft":"Aircraft","animal":"Animals","animals":"Animals","architectural":"Architectural","art":"Art","car":"Car","character":"Character","exterior":"Exterior","fashion":"Fashion","food":"Food","furniture":"Furniture","gadgets":"Gadgets","games-toys":"Games \u0026 Toys","hobby-diy":"Hobby \u0026 DIY","house":"House","household":"Household","industrial":"Industrial","interior":"Interior","jewelry":"Jewelry","military":"Military","miniatures":"Miniatures","plant":"Plant","science":"Science","space":"Space","vehicle":"Vehicle","watercraft":"Watercraft"},"print_models":{"subtitle":"Find the exact right 3D Printing content for your needs","title_html":"Buy Professional \u003cstrong\u003e3D models for printing\u003c/strong\u003e"},"profile":{"collection":"3D model packs","free":"Free 3D models","high_poly":"High-Poly 3D models","optimized":"Low-Poly/PBR 3D models","printable":"3D Print models"},"seo":{"cg":{"aircraft":"This category covers 3D aircraft. CG {\"slug\": \"airplane\", \"title\": \"airplanes\"} will fit into simulations, visualizations, advertisements and videos. {\"slug\": \"drone\", \"title\": \"Drone\"} bodies and parts will delight fans of tiny flying vehicles. And the {\"slug\": \"aircraft\", \"title\": \"rigged models\", \"active_filter\": \"rigged\"} are ready to be imported into game engines.\n","animals":"The collection of 3D fauna - {\"slug\": \"cat\", \"title\": \"cats\"}, {\"slug\": \"horse\", \"title\": \"horses\"}, {\"slug\": \"bear\", \"title\": \"bears\"}, {\"slug\": \"rhino\", \"title\": \"rhinos\"}, {\"slug\": \"eagle\", \"title\": \"eagles\"}, {\"slug\": \"lion\", \"title\": \"lions\"} and more - can be found here. The CG 3D animals will satisfy the needs of advertisements or static scenes. We also have {\"slug\": \"animal\", \"title\": \"rigged animal\", \"active_filter\": \"rigged\"} models for games.\n","architectural":"{\"slug\": \"stairs\", \"title\": \"Stair\"}, {\"slug\": \"fireplace\"}, 3D models as well as decorations like {\"slug\": \"frame\"}, {\"slug\": \"pillow\"}, or {\"slug\": \"lamp\"} can be found in the extensive architectural detail model library. Interior and exterior can be used to build both digital kitchens, bedrooms, castle rooms or dungeons whether you are an architect, engineer or indie game developer.\n","car":"Car category contains automobile 3D models, \u003ca href=\"%{link_to_low_poly_items_url}\"\u003elow-poly\u003c/a\u003e versions of which will be attractive to game designers, others - to film makers or advertisers. From classic cars to racing and track cars to the concept ones, thereâs a great variety of 3D auto models.\n","character":"In this category you will find 3D models of {\"slug\": \"human\"}, people, sci-fi, clothing and other. From {\"slug\": \"heart\"} and {\"slug\": \"hand\"} to detailed realistic {\"slug\": \"male\"} or {\"slug\": \"female\"} models. A number of the models are rigged and could be easily added to your game or animation.\n","electronics":"Electronics is a category for architects, interior decorators, level designers, scene makers and other creatives. 3D models of {\"slug\": \"smartphone\", \"title\": \"smartphones\"}, {\"slug\": \"laptop\", \"title\": \"laptops\"}, {\"slug\": \"camera\", \"title\": \"cameras\"}, {\"slug\": \"tv\", \"title\": \"TVs\"} and more will help to accurately capture modern lifeâs obsession with devices and technology.\n","engineering-parts":"Windows, pipelines, sliding door mechanisms and other bits that are necessary for CAD projects and even DIY plans fall under this category. This is where you can find 3D models from global manufacturers like ANVER, Dynatec and FCi.\n","exterior":"Browse architectural exteriors from facades, urban buildings to landscape objects, residential houses, industrial
16518constructions, and full scale 3D {\"slug\": \"city\"} models. Some of the assets are low poly and could help you complete your game or VR/AR application.\n","food":"Food helps to create realistic scenes of domestic life. 3D fruits, vegetables, beverages and meals are all here. Advertisements for restaurants, AR applications for healthier eating. Whether you were looking for 3D {\"slug\": \"pizza\"} or a wedding {\"slug\": \"cake\"} model, theyâre here.\n","furniture":"3D tables, chairs, sofas, beds in a variety of textures (wood, metal, etc.) and styles ( {\"slug\": \"retro\"}, {\"slug\": \"modern\"}, etc.) are on-hand. This category is meant for anyone involved with architecture and interior design, as well as advertisers.\n","furniture-set":"If you need alike looking antique chair and sofa looking, or full set of kitchenware, this is a place to be as this category collect sets of 3D furniture models from kitchen and living room to office and dining hall furniture sets. This helps the interior or level design specialist build rooms with matching elements.\n","household":"Household item 3D models are used to give details to rooms. You can put a 3D dinner set on the table, or have pepper and salt containers to complete kitchen interior, maybe put some {\"slug\": \"light\", \"title\": \"lights\"} and {\"slug\": \"flowers\"} near the bed to create luxurious feel.\n","industrial":"Construction materials, {\"slug\": \"engineering\"} tools, machinery and {\"slug\": \"container\", \"title\": \"containers\"} that provide both environmental details and interactive, rigged elements. This is perfect for simulation game developers or people building {\"slug\": \"construction\"} yard level.\n","interior":"This category contains realistic 3D elements and details of architecture, construction and engineering interior design. You can use these 3D models for animation or games - some of them are rigged and low poly.\n","military":"In this category you can buy 3D models of weapons, arms, {\"title\": \"swords\", \"slug\": \"sword\"} and artillery both modern and historical used by military forces and self defence. You can use models for games - some of them are polygons optimized and ready for game engines.\n","plant":"This category contains 3D models of flora organisms such as flowers, {\"slug\": \"tree\", \"title\": \"trees\"}, grass, creepers, greenery, herbs, perennials, seedlings, shoots, shrubs, slips, sprouts, vines, weed. To buy or download a free 3D model, browse the categories below.\n","scanned":"Modelers create these models by using 3D scanning technologies like RealSense. Tree stumps, statues, even males and females are popular here. The product is ready to be used in scenes and animations, offering unparalleled levels of realism.\n","science":"This category contains 3D models related to medicine, biology, physics, chemistry and technology, such as laboratory equipment, microscopic bodies and subatomic world. Look no further, {\"slug\": \"cell\"}, {\"slug\": \"skull\"} and {\"slug\": \"skeleton\"} 3D models can be found here.\n","scripts-plugins":"Scripts and plug-ins provide you with software shortcuts. Modeling, rendering, texturing - all of these can be made easier using plug-ins that come for all sorts of software like Maya and V-Ray.\n","space":"Space is a category full of low poly, game-ready models of sci-fi {\"slug\": \"spaceship\", \"title\": \"spaceships\"}, {\"slug\": \"asteroid\", \"title\": \"asteroids\"}, planets (including {\"slug\": \"earth\", \"title\": \"Earth\"} and realistic space {\"slug\": \"shuttle\", \"title\": \"shuttles\"} for the more scientifically inclined. 3D space models are useful for VR space simulator games.\n","sport-hobby":"This category encompases anything that is related to {\"slug\": \"field\"} events, sports and hobbies in general. From {\"slug\": \"football\"} and ski-slopes to {\"slug\": \"guitar\"} and {\"slug\": \"piano\"}, these are useful 3D models for advertisements, scenes and animation. Low-poly versions are there for sports video games.\n","textures":"Browse through a library of beautifully-made 3D materials and find the best suited, ready-to-use textures to prepare \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e game-ready \u003c/a\u003e or photorealistic models, upgrade your asset library, and improve your 3D works.\n","various":"These are the 3D models that didnât easily fit into other categories, so we created one that would accept them all. {\"title\": \"Rocks\", \"slug\": \"rocks\"}, {\"slug\": \"clouds\"}, {\"title\": \"logos\", \"slug\": \"logo\"}, {\"title\": \"umbrellas\", \"slug\": \"umbrella\"} and other non-categorized 3D models are here.\n","vehicle":"Trucks, {\"title\": \"ambulances\", \"slug\": \"ambulance\"}, buses, trains, tractors, {\"title\": \"bikes\", \"slug\": \"bike\"} and motorcycles - this category is for the people who want their city streets to be filled with realistic and sci-fi vehicles, and for those making simulation games or formating posters.\n","watercraft":"Watercraft covers {\"title\": \"boats\", \"slug\": \"boat\"}, {\"title\": \"yachts\", \"slug\": \"yacht\"}, {\"title\": \"ships\", \"slug\": \"ship\"} and other water vehicles. The rigged 3D models will do well in video games, animation while CG models are there for your scenes or other applications where visual fidelity is more important than polycount.\n"},"forwarded":{"cg":{"aircraft":"This category covers 3D aircraft. CG {\"slug\": \"airplane\", \"title\": \"airplanes\"} will fit into simulations, visualizations, advertisements and videos. {\"slug\": \"drone\", \"title\": \"Drone\"} bodies and parts will delight fans of tiny flying vehicles. And the {\"slug\": \"aircraft\", \"title\": \"rigged models\", \"active_filter\": \"rigged\"} are ready to be imported into game engines.\n","animals":"The collection of 3D fauna - {\"slug\": \"cat\", \"title\": \"cats\"}, {\"slug\": \"horse\", \"title\": \"horses\"}, {\"slug\": \"bear\", \"title\": \"bears\"}, {\"slug\": \"rhino\", \"title\": \"rhinos\"}, {\"slug\": \"eagle\", \"title\": \"eagles\"}, {\"slug\": \"lion\", \"title\": \"lions\"} and more - can be found here. The CG 3D animals will satisfy the needs of advertisements or static sce
16518nes. We also have {\"slug\": \"animal\", \"title\": \"rigged animal\", \"active_filter\": \"rigged\"} models for games.\n","architectural":"{\"slug\": \"stairs\", \"title\": \"Stair\"}, {\"slug\": \"fireplace\"}, 3D models as well as decorations like {\"slug\": \"frame\"}, {\"slug\": \"pillow\"}, or {\"slug\": \"lamp\"} can be found in the extensive architectural detail model library. Interior and exterior can be used to build both digital kitchens, bedrooms, castle rooms or dungeons whether you are an architect, engineer or indie game developer.\n","car":"Car category contains automobile 3D models, \u003ca href=\"%{link_to_low_poly_items_url}\"\u003elow-poly\u003c/a\u003e versions of which will be attractive to game designers, others - to film makers or advertisers. From classic cars to racing and track cars to the concept ones, thereâs a great variety of 3D auto models.\n","character":"In this category you will find 3D models of {\"slug\": \"human\"}, people, sci-fi, clothing and other. From {\"slug\": \"heart\"} and {\"slug\": \"hand\"} to detailed realistic {\"slug\": \"male\"} or {\"slug\": \"female\"} models. A number of the models are rigged and could be easily added to your game or animation.\n","electronics":"Electronics is a category for architects, interior decorators, level designers, scene makers and other creatives. 3D models of {\"slug\": \"smartphone\", \"title\": \"smartphones\"}, {\"slug\": \"laptop\", \"title\": \"laptops\"}, {\"slug\": \"camera\", \"title\": \"cameras\"}, {\"slug\": \"tv\", \"title\": \"TVs\"} and more will help to accurately capture modern lifeâs obsession with devices and technology.\n","engineering-parts":"Windows, pipelines, sliding door mechanisms and other bits that are necessary for CAD projects and even DIY plans fall under this category. This is where you can find 3D models from global manufacturers like ANVER, Dynatec and FCi.\n","exterior":"Browse architectural exteriors from facades, urban buildings to landscape objects, residential houses, industrial constructions, and full scale 3D {\"slug\": \"city\"} models. Some of the assets are low poly and could help you complete your game or VR/AR application.\n","food":"Food helps to create realistic scenes of domestic life. 3D fruits, vegetables, beverages and meals are all here. Advertisements for restaurants, AR applications for healthier eating. Whether you were looking for 3D {\"slug\": \"pizza\"} or a wedding {\"slug\": \"cake\"} model, theyâre here.\n","furniture":"3D tables, chairs, sofas, beds in a variety of textures (wood, metal, etc.) and styles ( {\"slug\": \"retro\"}, {\"slug\": \"modern\"}, etc.) are on-hand. This category is meant for anyone involved with architecture and interior design, as well as advertisers.\n","furniture-set":"If you need alike looking antique chair and sofa looking, or full set of kitchenware, this is a place to be as this category collect sets of 3D furniture models from kitchen and living room to office and dining hall furniture sets. This helps the interior or level design specialist build rooms with matching elements.\n","household":"Household item 3D models are used to give details to rooms. You can put a 3D dinner set on the table, or have pepper and salt containers to complete kitchen interior, maybe put some {\"slug\": \"light\", \"title\": \"lights\"} and {\"slug\": \"flowers\"} near the bed to create luxurious feel.\n","industrial":"Construction materials, {\"slug\": \"engineering\"} tools, machinery and {\"slug\": \"container\", \"title\": \"containers\"} that provide both environmental details and interactive, rigged elements. This is perfect for simulation game developers or people building {\"slug\": \"construction\"} yard level.\n","interior":"This category contains realistic 3D elements and details of architecture, construction and engineering interior design. You can use these 3D models for animation or games - some of them are rigged and low poly.\n","military":"In this category you can buy 3D models of weapons, arms, {\"title\": \"swords\", \"slug\": \"sword\"} and artillery both modern and historical used by military forces and self defence. You can use models for games - some of them are polygons optimized and ready for game engines.\n","plant":"This category contains 3D models of flora organisms such as flowers, {\"slug\": \"tree\", \"title\": \"trees\"}, grass, creepers, greenery, herbs, perennials, seedlings, shoots, shrubs, slips, sprouts, vines, weed. To buy or download a free 3D model, browse the categories below.\n","scanned":"Modelers create these models by using 3D scanning technologies like RealSense. Tree stumps, statues, even males and females are popular here. The product is ready to be used in scenes and animations, offering unparalleled levels of realism.\n","scie
16518nce":"This category contains 3D models related to medicine, biology, physics, chemistry and technology, such as laboratory equipment, microscopic bodies and subatomic world. Look no further, {\"slug\": \"cell\"}, {\"slug\": \"skull\"} and {\"slug\": \"skeleton\"} 3D models can be found here.\n","scripts-plugins":"Scripts and plug-ins provide you with software shortcuts. Modeling, rendering, texturing - all of these can be made easier using plug-ins that come for all sorts of software like Maya and V-Ray.\n","space":"Space is a category full of low poly, game-ready models of sci-fi {\"slug\": \"spaceship\", \"title\": \"spaceships\"}, {\"slug\": \"asteroid\", \"title\": \"asteroids\"}, planets (including {\"slug\": \"earth\", \"title\": \"Earth\"} and realistic space {\"slug\": \"shuttle\", \"title\": \"shuttles\"} for the more scientifically inclined. 3D space models are useful for VR space simulator games.\n","sport-hobby":"This category encompases anything that is related to {\"slug\": \"field\"} events, sports and hobbies in general. From {\"slug\": \"football\"} and ski-slopes to {\"slug\": \"guitar\"} and {\"slug\": \"piano\"}, these are useful 3D models for advertisements, scenes and animation. Low-poly versions are there for sports video games.\n","textures":"Browse through a library of beautifully-made 3D materials and find the best suited, ready-to-use textures to prepare \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e game-ready \u003c/a\u003e or photorealistic models, upgrade your asset library, and improve your 3D works.\n","various":"These are the 3D models that didnât easily fit into other categories, so we created one that would accept them all. {\"title\": \"Rocks\", \"slug\": \"rocks\"}, {\"slug\": \"clouds\"}, {\"title\": \"logos\", \"slug\": \"logo\"}, {\"title\": \"umbrellas\", \"slug\": \"umbrella\"} and other non-categorized 3D models are here.\n","vehicle":"Trucks, {\"title\": \"ambulances\", \"slug\": \"ambulance\"}, buses, trains, tractors, {\"title\": \"bikes\", \"slug\": \"bike\"} and motorcycles - this category is for the people who want their city streets to be filled with realistic and sci-fi vehicles, and for those making simulation games or formating posters.\n","watercraft":"Watercraft covers {\"title\": \"boats\", \"slug\": \"boat\"}, {\"title\": \"yachts\", \"slug\": \"yacht\"}, {\"title\": \"ships\", \"slug\": \"ship\"} and other water vehicles. The rigged 3D models will do well in video games, animation while CG models are there for your scenes or other applications where visual fidelity is more important than polycount.\n"},"printable":{"art":"This is where the artistic 3D prints go. Looking for fancy sculpture design recreating classical works and statues of historic personalities, or inspiring figurines, maybe even 3D-printable logos? That is the category.\n","fashion":"Beautiful and stylish things that you can wear are found in this category. See if you can find any use for fancy space age {\"slug\": \"footwear\"}, novelty glasses and cosplay {\"slug\": \"accessories\"} found here.\n","gadgets":"All {\"title\": \"iPhone\", \"slug\": \"iphone\"}, {\"title\": \"iPad\", \"slug\": \"ipad\"} (and other smart devices) cases can be found in gadget category. From simple 3D add-ons to complex parts and âhacksâ for your items, this is the category for the creatives, and lovers of technology.\n","games-toys":"Games and toys is the category covering printable 3D alien or monster miniatures, tiny {\"title\": \"tanks\", \"slug\": \"tank\"}, funky {\"slug\": \"chess\"} pieces, movie character helmets, hobby paraphernalia and accessories. This is the to-go category for all things geeky.\n","hobby-diy":"If you are our next great inventor and want to build your DIY project or get some spare parts for your {\"slug\": \"drone\"}, this is the place to be. Additionally, it features a lot things for people who want to make their own figurines or plastic gun replicas.\n","house":"All sorts of knick-knacks can be found here. {\"title\": \"Lamps\", \"slug\": \"lamp\"}, artistic {\"title\": \"bowls\", \"slug\": \"bowl\"}, and all kinds of {\"title\": \"holders\", \"slug\": \"holder\"} whether you cannot find a right spot for your phone, keep order of toothpicks, pile of pens or jewelry on your desk.\n","jewelry":"Jewelry is where you go to get bracelets and pendants or rings with diamonds. While 3D printers arenât good enough to make diamonds - yet - you can still print out a metallic ring as a base for your IT geek proposal ring.\n","miniatures":"3D printable {\"title\": \"characters\", \"slug\": \"character\"}, famous people, {\"title\": \"landmarks\", \"slug\": \"landmark\"}, animals, {\"title\": \"Male\", \"slug\": \"male\"}, {\"slug\": \"female\"}, {\"title\": \"monsters\", \"slug\": \"monster\"}, {\"title\": \"aliens\", \"slug\": \"alien\"} - itâs all here. Whether youâre printing utility vehicles to put on your table or creating miniatures for your tabletop games, itâs your category.\n","scie
16518nce":"What can be classed as science? Well, models of skeleton {\"slug\": \"bones\"}, physicians {\"slug\": \"tools\"} and astrophysics-related 3D printable models that can be used in many study processes.\n"}},"printable":{"art":"This is where the artistic 3D prints go. Looking for fancy sculpture design recreating classical works and statues of historic personalities, or inspiring figurines, maybe even 3D-printable logos? That is the category.\n","fashion":"Beautiful and stylish things that you can wear are found in this category. See if you can find any use for fancy space age {\"slug\": \"footwear\"}, novelty glasses and cosplay {\"slug\": \"accessories\"} found here.\n","gadgets":"All {\"title\": \"iPhone\", \"slug\": \"iphone\"}, {\"title\": \"iPad\", \"slug\": \"ipad\"} (and other smart devices) cases can be found in gadget category. From simple 3D add-ons to complex parts and âhacksâ for your items, this is the category for the creatives, and lovers of technology.\n","games-toys":"Games and toys is the category covering printable 3D alien or monster miniatures, tiny {\"title\": \"tanks\", \"slug\": \"tank\"}, funky {\"slug\": \"chess\"} pieces, movie character helmets, hobby paraphernalia and accessories. This is the to-go category for all things geeky.\n","hobby-diy":"If you are our next great inventor and want to build your DIY project or get some spare parts for your {\"slug\": \"drone\"}, this is the place to be. Additionally, it features a lot things for people who want to make their own figurines or plastic gun replicas.\n","house":"All sorts of knick-knacks can be found here. {\"title\": \"Lamps\", \"slug\": \"lamp\"}, artistic {\"title\": \"bowls\", \"slug\": \"bowl\"}, and all kinds of {\"title\": \"holders\", \"slug\": \"holder\"} whether you cannot find a right spot for your phone, keep order of toothpicks, pile of pens or jewelry on your desk.\n","jewelry":"Jewelry is where you go to get bracelets and pendants or rings with diamonds. While 3D printers arenât good enough to make diamonds - yet - you can still print out a metallic ring as a base for your IT geek proposal ring.\n","miniatures":"3D printable {\"title\": \"characters\", \"slug\": \"character\"}, famous people, {\"title\": \"landmarks\", \"slug\": \"landmark\"}, animals, {\"title\": \"Male\", \"slug\": \"male\"}, {\"slug\": \"female\"}, {\"title\": \"monsters\", \"slug\": \"monster\"}, {\"title\": \"aliens\", \"slug\": \"alien\"} - itâs all here. Whether youâre printing utility vehicles to put on your table or creating miniatures for your tabletop games, itâs your category.\n","science":"What can be classed as science? Well, models of skeleton {\"slug\": \"bones\"}, physicians {\"slug\": \"tools\"} and astrophysics-related 3D printable models that can be used in many study processes.\n"},"titles":{"aircraft":"Aircraft 3D Models","animal":"Animals 3D Models","animals":"Animals 3D Models","architectural":"Architectural 3D Models","car":"Car 3D Models","character":"Character 3D Models","exterior":"Exterior 3D Models","food":"Food 3D Models","furniture":"Furniture 3D Models","household":"Household 3D Models","industrial":"Industrial 3D Models","interior":"Interior 3D Models","military":"Military 3D Models","plant":"Plant 3D Models","plants":"Plants 3D Models","space":"Space 3D Models","textures":"CG Textures 3D Models","vehicle":"Vehicle 3D Models","watercraft":"Watercraft 3D Models"}},"title":{"cg":" 3D Models","print":" 3D Print Files"}},"cgt_checks":{"verification_details":{"UV":{"text":"UVs"},"allowedCharacters":{"text":"Allowed characters","tooltip":"\u003cspan\u003e\n Allowed ASCII characters: a-zA-Z0-9-_\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12485803270929#h_01GWP88M0S448FKN1SMABDP21R' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"archive_structure":{"text":"Archive structure"},"arithmeticJpegs":{"text":"JPEG texture format","tooltip":"Arithmetic coded JPEG texture files are not allowed"},"bounding_box_x":{"text":"Bounding box X","tooltip":"Bounding box X (to be updated)"},"bounding_box_y":{"text":"Bounding box Y","tooltip":"Bounding box Y (to be updated)"},"bounding_box_z":{"text":"Bounding box Z","tooltip":"Bounding box Z (to be updated)"},"centeredChildPivots":{"text":"Child object pivot location","tooltip":"Child object pivot points should be centered"},"centeredGeometryBoundingBox":{"text":"Model centered at the origin","tooltip":"The bounding box of the model should be centered at the origin"},"checkColorValuesUsedInOpacityMap":{"text":"Separate materials","tooltip":"Separate materials should be used for transparent and opaque objects"},"connectedTextures":{"text":"Textures connected to materials","tooltip":"All PBR textures should be connected to corresponding material slots"},"consistentBoundingBox":{"text":"Consistent bounding box","tooltip":"Model should have consistent bounding box across models in the same group"},"consistentMatIdOrder":{"text":"Consistent material ID order","tooltip":"Material order should be consistent across models from the same group"},"consistentNaming":{"text":"Consistent naming","tooltip":"Geometry and material names should have consistent suffixes or prefixes"},"consistentTransforms":{"text":"Consistent transforms","tooltip":"Model should have consistent transforms across models in the same group"},"consistentUvShells":{"text":"Consistent UV islands","tooltip":"Child model UVs should sufficiently match parent model UVs"},"dccObjectTypes":{"text":"No unsupported objects","tooltip":"\u003cspan\u003eUnsupported objects:\u003c/span\u003e\n\u003c/br\u003e- Lights\n\u003c/br\u003e- Cameras\n\u003c/br\u003e\u003ca href='https://help.cgtrader.com/hc/en-us/articles/12484392675473#h_01GWP8ESMVEC66RKEHAZ0PQNYS' target='_blank'\u003eLearn more\u003c/a\u003e\n"},"dccResetTransforms":{"text":"Reset transforms","tooltip":"All objects should have reset transforms"},"dccUnitScale":{"text":"File units","tooltip":"Model exported in required system units"},"details":{"text":"Details"},"embeddedTexturesFbx":{"text":"No embed textures","tooltip":"\u003cspan\u003e\n Embedded textures are stored inside the model file, increasing its size and sometimes causing compatibility issues.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12486535401361#h_01GWP83GFSK677SPVYTBX5NBQC' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"facetedGeometry":{"text":"No faceted geometry","tooltip":"\u003cspan\u003e\n Faceted geometry uses flat surfaces without smoothing, which can look unrealistic on curves.\
16518n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12485385944849#h_01GWP8ABZ92CRXF1804RH0SN3S' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"fbxFormat":{"text":"Binary FBX","tooltip":"\u003cspan\u003e\n Binary FBX file is more compact and faster to load and process.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/14118757652881#h_01GWP8R5FAZFB7DW272VWPC70Y' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"fbxLayers":{"text":"No layers","tooltip":"Layers should not be used in FBX file"},"fbxUnits":{"text":"File units","tooltip":"Model exported in required system units"},"files":{"text":"Files"},"flippedNormals":{"text":"No flipped normals","tooltip":"\u003cspan\u003e\n Surface normals of a 3D model consistently point outward, ensuring proper lighting,\n shading, and rendering. Flipped normals can cause visual artifacts and printing issues.\n\u003c/span\u003e\n"},"flippedUv":{"text":"No flipped UVs","tooltip":"UV islands should not be flipped"},"geometry":{"text":"Geometry"},"glbSizeLimit":{"text":"GLB file size","tooltip":"GLB file size should not exceed allowed limit"},"gltfSizeLimit":{"text":"glTF file size","tooltip":"glTF file size should not exceed allowed limit"},"inconsistentTexResInMaterial":{"text":"Consistent texture resolution","tooltip":"Textures should have consistent resolution across all textures in the same texture set"},"inconsistentTexelDensity":{"text":"Consistent texel density","tooltip":"Texel density should be consistent across all UV islands"},"indexedColors":{"text":"No indexed color textures","tooltip":"Textures with indexed color should not be used"},"materialNames":{"text":"Material naming","tooltip":"Material names should follow required naming convention"},"mesh":{"text":"Mesh"},"minimal_allowed_thickness":{"text":"Minimal allowed thickness","tooltip":"Model should not have too thin walls (to be updated)"},"missingRequiredTextures":{"text":"PBR textures","tooltip":"\u003cspan\u003e\n PBR textures simulate how light interacts with materials, making the model look realistic under different lighting.\n \u003c/br\u003eRequired PBR textures::\n \u003c/br\u003e- Base Color\n \u003c/br\u003e- Roughness\n \u003c/br\u003e- Metalness\n \u003c/br\u003e- Normal\n \u003c/br\u003e\u003ca href='https://help.cgtrader.com/hc/en-us/articles/12486535401361#h_01GWP80KZMFE5299HB69Q4ZWQ2' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"multiMaterial":{"text":"No multi-materials","tooltip":"No multi-materials should be used in the model"},"multipleFileFormats":{"text":"Multiple texture file formats","tooltip":"Each texture should be saved in required multiple file formats"},"naming":{"text":"Naming"},"noBadContiguousEdges":{"text":"No bad contiguous edges","tooltip":"Model should not have faces with normals pointing in the wrong direction"},"noHardEdges":{"text":"No hard edges","tooltip":"Model should not contain any hard edges"},"noNgons":{"text":"No N-gons","tooltip":"\u003cspan\u003e\n N-gons are polygons with five or more sides which might cause issues\n in certain processes like rendering or animation. \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12485385944849#h_01GWP89PYY82N9HR4X42R98SKR' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"noSelfIntersections":{"text":"No self-intersections","tooltip":"Model should not contain self-intersections (to be updated)"},"noTransparentMeshes":{"text":"No transparent materials","tooltip":"Model should not have transparent materials"},"noUvTiling":{"text":"0-1 UV area","tooltip":"UV islands should be placed in 0-1 UV area"},"nonManifoldFaces":{"text":"Non-manifold faces","tooltip":"Model should not contain non-manifold faces (to be updated)"},"nonManifoldVertices":{"text":"Manifold geometry","tooltip":"\u003cspan\u003e\n Manifold geometry means all surfaces are properly connected avoiding issues like edges shared by more than two faces.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12485385944849#h_01GWP89YFDSNN5QRRW6W1A8KGB' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"numberOfMaterialsPerObject":{"text":"Assigned materials","tooltip":"\u003cspan\u003e\n Materials are applied to the 3D model to allow visualize a modelâs surface properties and appearance.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12486535401361#h_01GWP85Y2XHM130GNRYSWF91QE' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"numberOfUVs":{"text":"UV unwrapped model","tooltip":"\u003cspan\u003e\n A UV unwrapped model means its 3D surface is flattened into 2D space, allowing textures to be applied accurately.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12485759132177#h_01GWP86PHGJY9H3PARWNABV34J' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"objectByMaterialTypeCount":{"text":"Amount of objects by material type","tooltip":"Model should have required material count for each material type"},"objectNames":{"text":"Object naming","tooltip":"Object names should follow required naming convention"},"objectTypes":{"text":"No unsupported objects","tooltip":"\u003cspan\u003eUnsupported objects:\u003c/span\u003e\n\u003c/br\u003e- Lights\n\u003c/br\u003e- Cameras\n\u003c/br\u003e\u003ca href='https://help.cgtrader.com/hc/en-us/articles/12484392675473#h_01GWP8ESMVEC66RKEHAZ0PQNYS' target='_blank'\u003eLearn more\u003c/a\u003e\n"},"openEdges":{"text":"No open edges","tooltip":"Model should be watertight"},"overlappedUvPerMaterial":{"text":"No overlapped UVs per material","tooltip":"UV islands should not overlap across the same material"},"overlappedUvPerModel":{"text":"No overlapped UVs per model","tooltip":"All UV islands should not overlap"},"overlappedUvPerObject":{"text":"No overlapped UVs per object","tooltip":"UV islands should not overlap across the same object"},"overlappedUvPerUVIsland":{"text":"No UV overlaps","tooltip":"\u003cspan\u003e\n UVs overlap when multiple points on the 3D modelâs surface are mapped to the same point on the UV island causing texture stretching.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12485759132177#h_01GWP86YVAZRJNZ4PBARMTMWR7' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"overlappingFaces":{"text":"No overlapping faces","tooltip":"Model should not contain overlapping faces"},"potentialTextures":{"text":"Recognized textures","tooltip":"\u003cspan\u003e\n PBR (Physically Based Rendering) materials are a type of shading and rendering\n technique used in 3D computer graphics that simulates the way light interacts with\n real-world materials. PBR materials use a set of p
16518hysical properties and measurements\n to accurately represent the appearance of a material under different lighting conditions.\n \u003c/br\u003eMandatory textures for PBR material:\n \u003c/br\u003e- Base Color\n \u003c/br\u003e- Roughness\n \u003c/br\u003e- Metalness\n \u003c/br\u003e- Normal\n \u003c/br\u003e\u003ca href='https://help.cgtrader.com/hc/en-us/articles/12486535401361#h_01GWP80KZMFE5299HB69Q4ZWQ2' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"recommendedTexturesNaming":{"text":"Texture naming","tooltip":"Texture names should follow required naming convention"},"resetTransforms":{"text":"Reset transforms","tooltip":"All objects should have reset transforms"},"resolutionOrmMismatch":{"text":"Consistent AO, Roughness, Metalness texture resolution","tooltip":"Textures should have consistent resolution across AO, Roughness, Metalness in the same texture set"},"resolutionsColorOpacityMismatch":{"text":"Consistent Albedo, Opacity texture resolution","tooltip":"Textures should have consistent resolution across Albedo, Opacity in the same texture set"},"scene":{"text":"Scene"},"singleUVChannel":{"text":"One UV channel","tooltip":"Only one UV channel should be used"},"texelDensity":{"text":"Texel density","tooltip":"Texel density should be within required range"},"textureAlphaChannel":{"text":"No textures with alpha channel","tooltip":"Textures should have no alpha channel"},"textureAspectRatio":{"text":"Square textures","tooltip":"\u003cspan\u003e\n Texture aspect ratio is the width-to-height ratio of a texture. Expected texture aspect ratio: 1:1\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12486535401361#h_01GWP82FF8TT77MNKGXGW6G8KS' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span\u003e\n"},"textureMaxResolution":{"text":"Maximum texture resolution","tooltip":"Textures should meet required maximum texture resolution"},"textureMinResolution":{"text":"Minimum texture resolution","tooltip":"Textures should meet required minimum texture resolution"},"textureResolutionNotPowerOf2":{"text":"Power of 2 texture sizes","tooltip":"\u003cspan\u003e\n Textures with dimensions in power of two (e.g. 512x512px, 1024x1024px) are used to optimize performance and memory usage.\n \u003ca href='https://help.cgtrader.com/hc/en-us/articles/12486535401361#h_01GWP82FF8TT77MNKGXGW6G8KS' target='_blank'\u003eLearn more\u003c/a\u003e\n\u003c/span?\n"},"texturelessMaterial":{"text":"Materials without textures","tooltip":"Model materials should not contain any textures"},"textures_and_materials":{"text":"Textures and Materials"},"too_thin_walls_count":{"text":"Too thin walls count","tooltip":"Model should not have too thin walls (to be updated)"},"topLevelZeroPosition":{"text":"Top-level object pivot location","tooltip":"Pivot point location should be at the origin (0, 0, 0) for top-level objects"},"triangleCountRelativeToParent":{"text":"Triangle count relative to parent","tooltip":"Child model should contain required triangle count relative to parent"},"triangleMaxCount":{"text":"Triangle max count","tooltip":"Model total triangle count should not exceeded required limit"},"trianglesRatio":{"text":"Triangle ratio","tooltip":"Model triangle ratio should not exceeded required limit"},"uniqueMeshNames":{"text":"Unique mesh names","tooltip":"All scene object names should be unique"},"unparseableMaterialName":{"text":"No unsupported material names","tooltip":"Material names should follow required naming convention"},"unsupportedBmpCompression":{"text":"No unsupported BMP compression","tooltip":"Unsupported BMP compression should not be used in BMP files"},"unsupportedPng":{"text":"PNG texture format","tooltip":"8-bit depth PNG textures are required"},"unusedTextures":{"text":"Supported texture file formats","tooltip":"Textures should be saved in supported file formats: 'png', 'jpg', 'exr', 'tga', 'bmp', 'tif'"},"usdzSizeLimit":{"text":"USDZ file size","tooltip":"USDZ file size should not exceed allowed limit"},"volume":{"text":"Volume","tooltip":"Volume (to be updated)"},"zeroAngleFaceCorners":{"text":"No zero-angled corners","tooltip":"Model should not contain faces with zero-angle corners"},"zeroFaceArea":{"text":"No zero-area faces","tooltip":"Model should not contain zero-area faces"},"zeroLengthEdge":{"text":"No zero-length edges","tooltip":"Model should not contain zero-length edges"}}},"checkout":{"adyen":{"declined_non_generic_error":"Payment unsuccessful due to a credit card issue. Try purchasing with a PayPal account instead."},"braintree":{"error_messages":{"Authentication Required":"Additional authentication is required to complete this transaction.","Call Issuer. Pick Up Card.":"Please contact your bank and do not use this card.","Cannot Authorize at this time (Life cycle)":"The transaction cannot be authorized currently due to lifecycle restrictions.","Cannot Authorize at this time (Policy)":"The transaction couldn't be authorized due to policy restrictions.","Card Issuer Declined CVV":"The CVV number provided is incorrect.","Card Not Activated":"The card being used is not activated.","Closed Card":"The card being used is closed.","Declined":"Your transaction was declined.","Declined - Call Issuer":"Your bank declined the transaction. Please contact them for further details.","Do Not Honor":"Your bank is not allowing this transaction.","Expired Card":"The card being used has expired.","Funding Instrument In The PayPal Account Was Declined By The Processor Or Bank, Or It Can't Be Used For This Payment":"The payment method linked to your PayPal account was declined.","Gateway Rejected: cvv":"The CVV number is incorrect or missing.","Gateway Rejected: duplicate":"This transaction appears to be a duplicate.","Gateway Rejected: fraud":"This transaction was blocked by our fraud detection measures.","Gateway Rejected: three_d_secure":"This transaction requires additional security verification through 3D Secure.","Insufficient Funds":"Your account doesn't have enough funds to complete this transaction.","Invalid Merchant ID":"The Merchant ID used for the transaction is invali
16518d.","Invalid Transaction":"The transaction is invalid.","Issuer or Cardholder has put a restriction on the card":"There is a restriction on your card.","Limit Exceeded":"This transaction exceeds your card's limit.","No Account":"The card number does not match any account.","Payer Cannot Pay For This Transaction With PayPal":"Your PayPal account cannot be used for this transaction.","Processor Declined":"Your bank declined the transaction.","Processor Declined - Fraud Suspected":"Your transaction was declined due to suspected fraud.","Transaction Not Allowed":"This type of transaction is not allowed.","Violation":"This transaction violates a rule or restriction.","Voice Authorization Required":"A special authorization is needed to complete this transaction."}},"captcha_failed":"Please complete the captcha verification to continue with checkout.","dialogs":{"new_user":{"confirm_text":"Create account","text":"Do you want to create an account and continue?","title":"User does not exist"},"wrong_password":{"confirm_text":"Send reminder","text":"Do you want us to send you a password reminder?","title":"Wrong password!"}},"error_messages":{"bot_restriction":"We are sorry, but we cannot process your order"}},"cleverpush":{"run_succeeded":{"text":"Open CGTrader to view it.","title":"Your 3D model is ready"}},"comments":{"comment_posted":"Comment has been successfully posted","leave_comment":"Leave a comment","no_comments":"There are no comments yet.","please_enter_comment":"Please enter your comment","posted_by":"Posted by \u003ca href='%{author_profile_url}' target='_blank'\u003e%{author}\u003c/a\u003e \u003cspan class='comment-time'\u003e%{time}\u003c/a\u003e","reply":"Reply","submit":"Post Comment","title":"Comments","you_must_login":"You must \u003ca href='javascript:;' class='user-form-trigger login'\u003eLog In\u003c/a\u003e to join the conversation."}
16518,"competition":{"digital-art-competition":{"admin":{"reasons_of_disapproval":{"artwork_per_category_limit":"Participant submitted more than 3 different artworks per category\n","contains_nudity":"Artwork contains nudity and/or violence\n","copyright":"Artwork contains watermarks, company logos, trademarks or otherwise display copyrighted content which does not belong to the participant\n","duplicate_entry":"Participant submitted images of the same character, object or environment to both the concept art and illustration categories\n","low_resolution_image":"Participant submitted low-resolution image/s â less than 1920 pixels\n","no_link_to_cgtrader":"Participant has placed a participant tag/note, but have not linked it to CGTrader\n","no_tag_note_and_link_to_cgtrader":"Participant has not placed a participant tag/note \u0026 link to CGTrader\n","not_cg":"Artwork is traditional art image (not CG)\n","not_owned_by_participant":"Artwork is not owned by the participant\n"}},"categories":{"category_filters":[{"illustration_character":null,"slug":"illustration_character","label":"Character Illustration"},{"illustration_environment":null,"slug":"illustration_environment","label":"Environment Illustration"},{"illustration_object":null,"slug":"illustration_object","label":"Object Design Illustration"},{"concept_character":null,"slug":"concept_character","label":"Character Concept Art"},{"concept_environment":null,"slug":"concept_environment","label":"Environment Concept Art"},{"concept_object":null,"slug":"concept_object","label":"Object Design Concept Art"}],"concept":[{"character":null,"short_title":"Character","title":"Character Concept Art","slug":"concept_character","description":"Some character and creature concepts are works of art on their own. This is the category where you can submit your game character concepts, cartoon character sketches, including character designs of both real and imaginary creatures. You can also submit fan arts of your favorite characters.","sponsor":{"name":"Paintable","slug":"paintable","url":"https://paintable.cc"},"prizes":{"prize_pool":"~$10,000","total_values":{"first_place":4340,"second_place":2770,"third_place":2770},"first_place":[{"prize":"GT-221 PRO Pen Tablet Monitor by","sponsor":"Huion","value":1150},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"2 years subscription to","sponsor":"Stash Magazine","value":280},{"prize":"âSapphireâ creative plug-in 1 year subscription by","sponsor":"Boris FX","value":900},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 \u0026 Hexels 3 licenses by","sponsor":"Marmoset","value":240},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"second_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"third_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}]}},{"environment":null,"short_title":"Environment","title":"Environment Concept Art","slug":"concept_environment","description":"Conceptual environments, sketched interiors and exteriors or natural landscapes find their place in this category. If you have fantasy land concepts or places that are waiting to come alive, submit them to this category.","sponsor":{"name":"Pencilkings","slug":"pencilkings","url":"https://www.pencilkings.com"},"prizes":{"prize_pool":"~$10,000","total_values":{"first_place":4200,"second_place":2770,"third_place":2770},"first_place":[{"prize":"GT-221 PRO Pen Tablet Monitor by","sponsor":"Huion","value":1150},{"prize":"2 years subscription to","sponsor":"Stash Magazine","value":280}
16518,{"prize":"âMocha VRâ creative plug-in 1 year subscription by","sponsor":"Boris FX","value":500},{"prize":"Master Collection by","sponsor":"Tonytextures","value":630},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 \u0026 Hexels 3 licenses by","sponsor":"Marmoset","value":240},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"second_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"third_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}]}},{"object_design":null,"short_title":"Object","title":"Object Design Concept Art","slug":"concept_object","description":"Your greatest sketches and concept art of separate objects (e.g. furniture concepts, gun sketches, props, etc.), including prototypes and conceptual CG product design can be submitted to this category. Please note that artworks containing visible brands or watermarks cannot participate in the Competition.","sponsor":{"name":"Marmoset","slug":"marmoset","url":"https://www.marmoset.co"},"prizes":{"prize_pool":"~$10,000","total_values":{"first_place":4140,"second_place":2770,"third_place":2770},"first_place":[{"prize":"GT-221 PRO Pen Tablet Monitor by","sponsor":"Huion","value":1150},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"2 years subscription to","sponsor":"Stash Magazine","value":280},{"prize":"âContinuumâ creative plug-in 1 year subscription by","sponsor":"Boris FX","value":700},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 \u0026 Hexels 3 licenses by","sponsor":"Marmoset","value":240},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"second_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"third_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}]}}],"illustration":[{"character":null,"short_title":"Characters","title":"Character Illustration","slug":"illustration_character","description":"Whether you are creating CG humans, historical personalities or mythical beings, this is the category to showcase the best characters in your portfolio. Final versions of both real and fantasy creatures, including fan art, can be submitted for this nomination.","sponsor":{"name":"Huion","
16518slug":"huion","url":"https://www.huiontablet.com"},"prizes":{"prize_pool":"~$10,000","total_values":{"first_place":4610,"second_place":2770,"third_place":2770},"first_place":[{"prize":"GT-221 PRO Pen Tablet Monitor by","sponsor":"Huion","value":1150},{"prize":"âSapphireâ creative plug-in 1 year subscription by","sponsor":"Boris FX","value":900},{"prize":"Master Collection by","sponsor":"Tonytextures","value":630},{"prize":"2 years subscription to","sponsor":"Stash Magazine","value":280},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 \u0026 Hexels 3 licenses by","sponsor":"Marmoset","value":240},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"second_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"third_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}]}},{"environment":null,"short_title":"Environment","title":"Environment Illustration","slug":"illustration_environment","description":"Digitally designed spaces which fully convey your style and emotion are a true testament to the hard work and dedication of the artist. Finalized environments, from interiors and exteriors to natural landscapes find their place in this category.","sponsor":{"name":"Tony Textures","slug":"tonytextures","url":"http://www.tonytextures.com"},"prizes":{"prize_pool":"~$10,000","total_values":{"first_place":4210,"second_place":2770,"third_place":2770},"first_place":[{"prize":"GT-221 PRO Pen Tablet Monitor by","sponsor":"Huion","value":1150},{"prize":"2 years subscription to","sponsor":"Stash Magazine","value":280},{"prize":"âMocha VRâ creative plug-in 1 year subscription by","sponsor":"Boris FX","value":500},{"prize":"Master Collection by","sponsor":"Tonytextures","value":630},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 \u0026 Hexels 3 licenses by","sponsor":"Marmoset","value":240},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"second_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"third_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}]}},{"object_design":null,"short_title":"Object","title":"Object Design Illustration","slug":"illustration_object","description":"All detailed or stylized separate objects, from modern product design to a moldy rock or a cool spaceship design, find their place in this category. Please note that artworks containing visible brands or watermarks cannot participate in the Competition.","sponsor":{"name":"Celsys","slug":"celsys","url":"https://www.celsys.co.jp/en"},"prizes":{"prize_pool":"~$10,000","total_values":{"first_place":4140,"second_place":2770,"third_place":2770},"first_place":[{"prize":"GT-221 PRO Pen Tablet Monitor by","sponsor":"Huion","value":1150},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"2 years subscription to","sponsor":"Stash Magazine","value":280},{"prize":"âContinuumâ creative plug-in 1 year subscription by","sponsor":"Boris FX","value":700},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 \u0026 Hexels 3 licenses by","sponsor":"Marmoset","value":240},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"second_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}],"third_place":[{"prize":"GT-191 PRO Pen Tablet Monitor by","sponsor":"Huion","value":650},{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Creative software licenses set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Toolbag 3 license by","sponsor":"Marmoset","value":190},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings yearly plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"Digital Painting Academy yearly plan by","sponsor":"Paintable","value":300},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60}]}}],"landing_page":[{"title":"Illustration","slug":"illustration"},{"title":"Concept art","slug":"concept"}],"number":"six","page_description":"Participate in the CGTrader Digital Art Competition by submitting your works to Character Illustration, Character Concept Design, Environment Illustration, Environment Concept Design, Object Design, and Object Concept Design categories. If you have several great works that suit different categories, feel free to submit them to the corresponding categories. Select a category to see the prizes for that category.","public_award":[{"public_award":null,"title":"Public Award","slug":"public_award","description":"Two artworks that generate the most likes in the Competition gallery will be awarder the Public Award. This is everyone's favorite category, because you can choose the best of the best! All valid submissions to the Competition compete for this Prize.","prizes":{"total_values":{"first_place":2000,"second_place":2000,"third_place":0},"first_place":[{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Creative software license set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings annual plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"H950P Graphic Tablet by","sponsor":"Huion","value":80},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60},{"prize":"Digital Painting Academy annual plan by","sponsor":"Paintable","value":300}],"second_place":[{"prize":"Starter Collection by","sponsor":"Tonytextures","value":360},{"prize":"1 year subscription to","sponsor":"Stash Magazine","value":160},{"prize":"Creative software license set by","sponsor":"Nevercenter","value":200},{"prize":"Time tracking software license by","sponsor":"Fanurio Time Tracking","value":120},{"prize":"Selected graphic software license by","sponsor":"Escape Motions","value":90},{"prize":"Clip Studio Paint EX software license by","sponsor":"Celsys","value":220},{"prize":"Online Art Trainings annual plan by","sponsor":"Pencil Kings","value":300},{"prize":"Visual apps making software license by","sponsor":"Lightwell","value":120},{"prize":"H950P Graphic Tablet by","sponsor":"Huion","value":80},{"prize":"Black Ink painting application by","sponsor":"Bleank","value":60},{"prize":"Digital Painting Academy annual plan by","sponsor":"Paintable","value":300}]}}],"tabs":[{"title":"Illustration","slug":"illustration"},{"title":"Concept art","slug":"concept"},{"title":"Public award","slug":"public_award"}]},"description_html":"CGTrader is calling CG artists (\u003cstrong\u003eboth 2D and 3D\u003c/strong\u003e) from around the world to show their best works of art. Creativity and innovation come together in our Competition to bring out the vast potential of CG. Creatives are invited to join before September 30 and win their share of the prize pool. Our community of 1.2M+ users is waiting for your artworks! All it takes is these 3 simple steps:","gallery":{"page_description":"This is the CGTrader Digital Art Competition Gallery. Every submission to the Competition is automatically published and showcased in this gallery. Please admire, share and vote for your favorite works of art: two submissions that receive the most likes will win the Public Award!"},"header":{"title":{"description_html":"Enter your artwork to win prizes worth a total of \u003cstrong\u003e$60,000\u003c/strong\u003e","first_line_html":"CGTrader \u003cstrong\u003eDigital Art Competition\u003c/strong\u003e","second_line_html":"where best CG artworks come together"}},"judges":[{"name":"Stephen Price","title":"Founding Editor / Creative Director in","company":"Stash Media","slug":"stephen_price","url":"http://www.stashmedia.tv","description_html":"Stephen Price is the founder and creative director of Stash Media Inc. He is also the executive editor of Stash Magazine, and Stash Permanent Collection, the worldâs largest online video library of design, animation and VFX.\u003cbr /\u003e\u003cbr /\u003eStephen has given dozens of talks on design and digital production at festivals and corporate events spanning from Los Angeles to Istanbul and has curated scores of animation/VFX film screenings in over 20 countries.\u003cbr /\u003e\u003cbr /\u003ePrior to foun
16518ding Stash Media, Stephen has been the executive producer of animation and visual effects for feature films, TV series and advertising â winning multiple industry awards along the way. From 1995-2000, Stephen created and executive produced five seasons of âSplat!â a TV series for teens about animation and VFX broadcast in over 100 markets."},{"name":"Samur Isma","title":"Founder of","company":"FREEYORK","slug":"samur_isma","url":"https://freeyork.org","description_html":"Samur Isma is halfway between tech and design with a strong entrepreneurial mindset. After starting his career as a freelance graphic designer, he has studied computer science at the Eastern Mediterranean University in Mersin and, then, at the Technical University of Wroclaw â where he graduated in computer science and marketing. In 2009 he founded FREEYORK, and nowadays he divides his mind and his time between his daytime job as a project manager and the management of his editorial project FREEYORK."},{"name":"Kirill Tokarev","title":"Editor in Chief at","company":"80 Level","slug":"kirill_tokarev","url":"https://80.lv","description_html":"Kirill Tokarev is the Editor in Chief of 80.lv. Over the years he worked in one of the biggest game magazines in Ukraine â Gameplay â under the Sergey Galyonkinâs (SteamSpy) management, worked as a features editor at Igromania magazine, and a bunch of other publications in former USSR region. Coming from game marketing and journalism he turned his passion of 3d into building a powerful platform for 3d artists. Within 3 years his small team managed to grow 80.lv to the size we know today. \"Itâs a great honor to be part of this creative community and tell the stories of amazing people working in this field\" - Kirill Tokarev."}],"meta":{"description":{"categories":"Participate in the CGTrader Digital Art Competition by submitting your works to one of the six Competition categories and win great prizes. Submit your Concept Designs and Illustration of Characters, Environments and Product designs.","gallery":"This is the CGTrader Digital Art Competition Gallery. Every submission to the Competition is automatically published and showcased in this gallery. Please admire, share and vote for your favorite works of art: two submissions that receive the most likes will win the Public Award!","general":"%{artwork_name} is participating in the %{category_name} category of the CGTrader Digital Art Competition! Vote for it on https://cgtrader.com/digital-art-compet
16518ition/%{entry_link} Thanks!","judges":"Meet the industry experts who will be evaluating all submissions for Digital Art Competition and selecting the best of the best.","main_page":"CGTrader is calling digital artists from around the world to show their best works of art. Creativity and innovation come together in this competition to bring out the vast potential of CG. By taking a part, designers will get exposure and opportunity to win a share of the great prize pool.","partners":"There are several companies and brands helping us make the CGTrader Digital Art Competition happen. Find out more about the partners of the CGTrader Digital Art Competition, their products and prizes awarded to the winners.","rules":"Take a minute to familiarize yourself with the terms and conditions of the CGTrader Digital Art Competition. See key dates, find out how to take part in the Competition, how to add a competition tag on your portfolio website and how the entries will be judged.","twitter":"%{artwork_name} is participating in the CGTrader Digital Art Competition I %{category_name} | Vote for %{artwork_name}
16518 here: https://cgtrader.com/digital-art-competition/%{entry_link} #CGart #CGTrader #competition"},"title":{"categories":"CGTrader Digital Art Competition â Categories \u0026 Prizes","gallery":"CGTrader Digital Art Competition - Gallery","judges":"CGTrader Digital Art Competition - Judges","main_page":"CGTrader Digital Art Competition","partners":"CGTrader Digital Art Competition - Partners","rules":"CGTrader Digital Art Competition - Rules","social":"%{artowrk_name} - CGTrader Digital Art Competition"}},"partners":{"bronze_tier":[{"name":"Escape Motions","slug":"escape_motions","url":"http://www.escapemotions.com","description":"Escape Motions is a small studio of creatives and programmers who love to experiment with art and code to find a new visual expression in digital media. We put our heart and soul into what we do, our every application is handcrafted and we play with each bit of code to bring original innovative tools to creative people at all skill levels. This is why our Flame Painter, Amberlight and Rebelle were born."},{"name":"Fanurio Time Tracking","slug":"fanurio_time_tracking","url":"http://www.fanuriotimetracking.com","description":"Fanurio Time Tracking is a privately-held software company specialized in business applications. It develops Fanurio, a time tracking and billing application for freelancers and teams."},{"name":"Bleank","slug":"bleank","url":"http://www.bleank.com","description":"Bleank is an independent studio that creates high-end creative software for digital artists. Known for their digital painting solutions, Bleankâs mission is to provide artists with tools that allow them to be unique. Black Ink is their flagship product, and was designed to challenge the norms of the generative art world."},{"name":"Lightwell","slug":"lightwell","url":"https://lightwell.pro","description":"Lightwell is a powerful creation tool for artists, designers, and developers. Build, prototype, and publish your own native iOS app without writing code."}],"diamond_tier":[{"name":"Huion","slug":"huion","url":"https://www.huiontablet.com","description":"Huion is a professional supplier who provides the solutions of digital handwriting and digital painting. Since its foundation in 2007, Huionâs products include pen display, pen tablets, light pads, helping customers who are engaged in digital creativity field such as digital painting, 3D industrial design, film tricks, game concept art, cartoons, graphic design etc from creativity building, design and creation , visualization to the execution, which enables every creative person to make its dreams come true."}],"gold_tier":[{"name":"Tonytextures","slug":"tonytextures","url":"http://www.tonytextures.com","description":"All you need for architecture visualization! Grab our free collection of high quality cutouts and textures, browse through archiviz tutorials or get lost in our free 4000+ free texture library."},{"name":"Pencilkings","slug":"pencilkings","url":"https://www.pencilkings.com","description":"Pencilkings provides professional level art education to anyone, anywhere in the world without the traditional high costs. Price and location will not be a barrier to becoming a better artist."},{"name":"Paintable","slug":"paintable","url":"https://paintable.cc","description":"Do you dream of being a world-class digital painter? At Paintable, we design interactive exercises to help you paint the ideas in your imagination. Since 2016, we've been fortunate enough to help hundreds of thousands of motivated students in their journey towards becoming a professional illustrator, concept artist or character designer."}],"main_page_partners":[{"name":"Huion","slug":"huion","url":"https://www.huiontablet.com"},{"name":"Tonytextures","slug":"tonytextures","url":"http://www.tonytextures.com"},{"name":"Pencilkings","slug":"pencilkings","url":"https://www.pencilkings.com"},{"name":"Paintable","slug":"paintable","url":"https://paintable.cc"}],"media":[{"name":"Andy Sowards","slug":"andy_sowards","url":"http://www.andysowards.com/blog/"},{"name":"Freeyork","slug":"freeyork","url":"https://freeyork.org/"},{"name":"80 level","slug":"80level","url":"https://80.lv"},{"name":"Concept Art World","slug":"concept_art_world","url":"http://conceptartworld.com"}],"page_description":"There are several companies and brands helping us make the CGTrader Digital Art Competition happen. Our partners believe in the power of digital art and want to supp
16518ort artists globally. Find out more about the partners of the CGTrader Digital Art Competition, their products and prizes awarded to the winners.","silver_tier":[{"name":"Marmoset","slug":"marmoset","url":"https://www.marmoset.co","description":"Marmoset is the creative standard in digital art software; makers of the real-time 3D rendering and lookdev suite, Marmoset Toolbag 3, the WebGL-powered Marmoset Viewer, and the 2D grid-based painting and design suite, Marmoset Hexels 3."},{"name":"CELSYS","slug":"celsys","url":"https://www.celsys.co.jp/en","description":"CELSYS is the developer and distributor of \u003ca href=\"http://www.clipstudio.net/en\" target=\"_blank\"\u003eCLIP STUDIO PAINT\u003c/a\u003e (formerly Manga Studio), the illustration, comics and animation software that is beloved by more than 3,000,000 artists worldwide. It offers a wide variety of creative features, such as screen tones and 3D drawing models, and provides artists with brushes, pens and more that feel close to traditional media."},{"name":"Boris FX","slug":"boris_fx","url":"https://goo.gl/Uxm36w","description":"Boris FX is the leading developer of award-winning creative plug-ins for editing, visual effects, and motion graphics."},{"name":"Stash Magazine","slug":"stash_magazine","url":"http://www.stashmedia.tv","description":"Stash Magazine keeps the design, animation, and VFX world inspired with its daily news site and the subscription-based STASH PERMANENT COLLECTION â the planet's largest online creative resource of motion projects â streaming over 5,000 TV/cinema ads, music videos, title sequences, brand films, game trailers, and short films, plus behind the scenes features and exclusive interviews."},{"name":"Nevercenter","slug":"nevercenter","url":"http://nevercenter.com","description":"Nevercenter is a small group of software artists making the kind of creative software we most enjoy using. Silo 2 is our professional standalone 3D modeling software for Mac, PC, and Linux; the perfect tool for achieving 3D modeling zen."}]},"rules":{"badges":[{"title":"badge","link":"https://www.cgtrader.com/competitions/digital_art/badge.png","code":"\u003ca href=\"https://www.cgtrader.com\" target=\"_blank\"\u003e\u003cimg src=\"https://www.cgtrader.com/competitions/digital_art/badge.png\" alt=\"CGTrader Digital Art Competition\" /\u003e\u003c/a\u003e"},{"title":"badgeWithText","link":"https://www.cgtrader.com/competitions/digital_art/text_badge.png","code":"\u003ca href=\"https://www.cgtrader.com\" target=\"_blank\"\u003e\u003cimg src=\"https://www.cgtrader.com/competitions/digital_art/text_badge.png\" alt=\"CGTrader Digital Art Competition\" /\u003e\u003c/a\u003e"}],"email":"[email protected]","entry_validation":{"dates":"March 1, 2018 to September 30, 2018 (11:59 PM PT)","first_point":"The Participant shall only submit a single project per entry and assign it to the single most relevant category. The Participant should not submit images of the same character, object or environment to both the concept art and illustration categories.","max_submissions":3},"how_to_enter":{"badges_link":"https://www.dropbox.com/sh/qsjw0zbshu7w30f/AABv_9Rx5vgULtccChNW1Myma?dl=1","first_step_html":"Submit your best 2D or 3D artwork(s) to the corresponding category(-ies). There are a total of six different categories: Character Illustration, Character Concept Design, Environment Illustration, Environment Concept Design, Object Design, and Object Concept Design. You can submit up to 3 different works per each category (from six available).\u003cbr /\u003e\u003cbr /\u003eA single artwork can be submitted only once by assigning it to a relevant category.","third_step":"Submit the application form online before the deadline on September 30th, 2018 (11:59 PM Pacific Time). All submissions will also be published to the special competition gallery on CGTrader and will not only gain visibility in our community, but will also get a chance to win the Public Award."},"key_dates":{"evaluation":"October 1-20, 2018","submission":"March 1 - September 30, 2018","winners":"October 31, 2018"},"page_description":"Take a minute to familiarize yourself with the terms and conditions of the CGTrader Digital Art Competition. See key dates, find out how to take part in the Competition, how the entries will be judged and what responsibilities and rights are held by related parties.","prizes_page":"categories","sponsors":"âHuionâ, âTony Texturesâ, âPencil Kingsâ, âPaintableâ, âMarmosetâ, âBoris FXâ, âCelsysâ, âStash Magazineâ, âNevercenterâ,âEscape Motionsâ, âLightwellâ, âFanurio Time Trackingâ, âBleankâ","winner_selection":{"categories":"Character Illustration, Environment Illustration, Object Design, Character Concept Art, Environment Concept Art, Object Concept Design","public_award":"The Public Award will be given for the artwork which generates the most likes on CGTrader.","public_award2":"Two artworks that generate the most likes will be awarded the Public Award."}},"submission_form":{"categories":[{"title":"Illustration","buttons":[{"text":"Character Illustration","slug":"illustration_character"},{"text":"Environment Illustration","slug":"illustration_environment"},{"text":"Object Illustration","slug":"illustration_object"}]},{"title":"Concept art","buttons":[{"text":"Character Concept","slug":"concept_character"},{"text":"Environment Concept","slug":"concept_environment"},{"text":"Object Concept","slug":"concept_object"}]}]},"title":"Digital Art Competition"},"notifications":{"failure":"Sorry, something went wrong, please check if you have filled all fields correctly and try again","success":"Thank y
16518ou for participating! You will receive a confirmation email from us shortly"}},"conversations":{"action_button_confirmation":"Do you really want to reopen this request?","reply_posted":"Reply has been posted.","with_yourself":"can't be same with sender."},"coupons":{"bannerSubtitle":"Seeking official CGTrader coupon codes? Look no further â you're in the right spot for the best discounts","bannerTitle":"CGTrader Coupons and Promo Codes %{year}","couponExpires":"Coupon Expires","couponsList":{"discount":"Sign up and receive a 10% discount for your first purchase","discounts":"Sign up and get notified about time-limited discounts for your purchases","freeModels":"Download high-quality 3D models for free"},"deal":"DEAL","faq":"Faq","getDeal":"Get deal","title":"Coupons","useCode":"Use code:"},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"],"order":["year","month","day"]},"datetime":{"distance_in_words":{"about_x_hours":{"one":"about 1 hour","other":"about %{count} hours"},"about_x_months":{"one":"about 1 month","other":"about %{count} months"},"about_x_years":{"one":"about 1 year","other":"about %{count} years"},"almost_x_years":{"one":"almost 1 year","other":"almost %{count} years"},"half_a_minute":"half a minute","less_than_x_minutes":{"one":"less than a minute","other":"less than %{count} minutes"},"less_than_x_seconds":{"one":"less than 1 second","other":"less than %{count} seconds"},"over_x_years":{"one":"over 1 year","other":"over %{count} years"},"x_days":{"one":"1 day","other":"%{count} days"},"x_minutes":{"one":"1 minute","other":"%{count} minutes"},"x_months":{"one":"1 month","other":"%{count} months"},"x_seconds":{"one":"1 second","other":"%{count} seconds"}},"prompts":{"day":"Day","hour":"Hour","minute":"Minute","month":"Month","second":"Seconds","year":"Year"}},"design_partnership":{"benefits":{"benefits_arr":[{"title":"Start working immediately","info":"Skip the client search - work on hundreds of available modeling tasks that meet your interest and payment expectations.","icon":"rabbit-fast"},{"title":"Flexible working hours","info":"Suitable for night-owls and early birds alike - you will be the one who chooses how much to work.","icon":"clock"},{"title":"Work from the comfort of your home","info":"All freelance tasks can be completed from your workstation at home or any other place you prefer.","icon":"couch"},{"title":"Earn real money","info":"Earn real money. Transferred via Hyperwallet or Payoneer.","icon":"money-check-alt"},{"title":"Dedicated 3D support","info":"Our in-house team is ready to share 3D know-how, answer technical questions and help you complete the task.","icon":"user-friends"},{"title":"Work with industry-leading clients","info":"Create custom models for global businesses (including Fortune 500 companies).","icon":"hands-helping"}],"section_title":"What's in it for you?"},"cta_button":"Join Wildcat today","explanation_steps":{"section_title":"Join us today","step_1":{"info":"Create an account with CGTrader, if you donât have one yet. Once logged in, provide samples of your work or take a quick trial task. If your skills match, youâll get full access to our paid modeling tasks.","title":"Get on board"},"step_2":{"info":"Got approved? Instantly see all available 3D modeling tasks on our Wildcat system, work on the ones you like or come back later for more.","title":"Get started"},"step_3":{"info":"Select your favorite payout method and receive all your freelance earnings on a monthly or weekly basis.","title":"Get paid"}},"header":{"benefits":[{"text":"Earn up to $200 per delivered model"},{"text":"Pick the tasks you want, no bidding"},{"text":"Enjoy multiplier bonuses and top rates"},{"text":"A constant stream of work and income"}],"page_title":"A no-bidding freelance platform for 3D designers","subtitle":"Join an exclusive 3D design community and get full access to hundreds of curated modeling tasks. Work from anywhere, anytime!","switcher_html":"\u003ca href='/freelance-with-us' class='is-active'\u003eEN\u003c/a\u003e\n\u003cspan class='u-mr10 u-ml10'\u003e|\u003c/span\u003e\n\u003ca href='/ru/Zarabatyvayte-s-CGTrader'\u003eRU\u003c/a\u003e\n"},"help_section":{"contact_btn":"Contact us","help_center_btn":"Visit Help Center","section_title":"Got questions?"},"meta":{"description":"Join an exclusive 3D design community and get full access to hundreds of curated modeling tasks. Work from anywhere, anytime!","title":"Freelance work with CGTrader"},"positions":{"open_positions":[{"type":"pbr","title":"PBR (low-poly) modeling","info_html":"\u003cp\u003eOpen for 3D designers experienced in creating PBR models.\u003c/p\u003e\n\u003cp\u003e\n \u003cspan class=\"text-semibold\"\u003eNo software requirements\u003c/span\u003e \u003cbr /\u003e\n Delivery format: \u003cspan class=\"text-semibold\"\u003e.fbx\u003c/span\u003e\n\u003c/p\u003e\n","badge":"In demand!"},{"type":"archviz","title":"Arch-viz (high-poly) modeling","info_html":"\u003cp\u003eOpen for 3D designers skilled in 3D modeling and texturing.\u003c/p\u003e\n\u003cp\u003e\n Software requirements: \u003cspan class=\"text-semibold\"\u003e3ds Max 2020\u003c/span\u003e (earlier versions are supported but not recommended)\u003cbr /\u003e\n Renderer: \u003cspan class=\"text-semibold\"\u003eV-ray Next, update 3.2\u003c/span\u003e (other versions are supported but not recommended)\n\u003c/p\u003e\n","badge":""}],"section_title":"Currently available tasks"}},"devise":{"confirmations":{"confirmed":"Your account was successfully confirmed. You are now signed in.","send_instructions":"Confirmation email was successfully sent.","send_paranoid_instructions":"If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes.","sent_success_message":"\tâ Your email reset was successfully sent. Please check your inbox..."},"failure":{"already_authenticated":"You are already signed in. Log out and try again.","inactive":"Your account was not activated yet.","invali
16518d":"Invalid email or password.","invalid_token":"Invalid authentication token.","last_attempt":"You have one more attempt before your account is locked.","locked":"Your account is locked.","no_email":"Your Facebook privacy settings prevent from providing your email for logging in. Please change them or use alternative log in methods","not_found_in_database":"Invalid email or password.","timeout":"Your session expired, please sign in again to continue.","too_many_requests":"Youâve already requested a password reset email. Please wait a few minutes before trying again.","unauthenticated":"You need to sign in or sign up before continuing.","unconfirmed":"This email address is not confirmed yet. Please check your inbox for confirmation email."},"mailer":{"confirmation_instructions":{"subject":"Confirmation instructions"},"email_changed":{"subject":"Email Changed"},"password_change":{"subject":"Password Changed"},"reset_password_instructions":{"subject":"Reset password instructions"},"unlock_instructions":{"subject":"Unlock Instructions"}},"omniauth_callbacks":{"failure":"Could not authenticate you from %{kind} because \"%{reason}\".","success":"Successfully authenticated from %{kind} account."},"passwords":{"no_token":"You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided.","send_instructions":"You will receive an email with instructions about how to reset your password in a few minutes.","send_paranoid_instructions":"If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.","updated":"Your password was changed successfully. You are now signed in.","updated_not_active":"Your password was changed successfully."},"registrations":{"destroyed":"Bye! Your account was successfully cancelled. We hope to see you again soon.","signed_up":"Welcome! You have signed up successfully.","signed_up_but_inactive":"You have signed up successfully. However, we could not sign you in because your account is not yet activated.","signed_up_but_locked":"You have signed up successfully. However, we could not sign you in because your account is locked.","signed_up_but_unconfirmed":"Thanks for registering. Please check your inbox and confirm your email address to continue.","signed_up_in_checkout":"Thanks for registering. Feel free to continue to checkout.","update_needs_confirmation":"You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address.","updated":"You updated your account successfully.","updated_but_not_signed_in":"Your account has been updated successfully, but since your password was changed, you need to sign in again."},"sessions":{"already_signed_out":"Signed out successfully.","signed_in":"Signed in successfully.","signed_out":"Signed out successfully."},"unlocks":{"send_instructions":"You will receive an email with instructions about how to unlock your account in a few minutes.","send_paranoid_instructions":"If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.","unlocked":"Your account has been unlocked successfully. Please sign in to continue."}},"disabled_cookies_modal":{"button":"Cancel","text_1":"You will not be able explore millions of great 3D models, add them to the cart or Buy.","text_2":"If you want to experience CGTrader fully, we encourage enabling cookies on this site.","title":"It seems you have your browser's cookies disabled"},"doorkeeper":{"applications":{"buttons":{"authorize":"Authorize","cancel":"Cancel","destroy":"Destroy","edit":"Edit","submit":"Submit"},"confirmations":{"destroy":"Are you sure?"},"edit":{"title":"Edit application"},"form":{"error":"Whoops! Check your form for possible errors"},"help":{"blank_redirect_uri":"Leave it blank if you configured your provider to use Client Credentials, Resource Owner Password Credentials or any other grant type that doesn't require redirect URI.","confidential":"Application will be used where the client secret
16518can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.","native_redirect_uri":"Use %{native_redirect_uri} for local tests","redirect_uri":"Use one line per URI","scopes":"Separate scopes with spaces. Leave blank to use the default scopes."},"index":{"actions":"Actions","callback_url":"Callback URL","confidential":"Confidential?","confidentiality":{"no":"No","yes":"Yes"},"name":"Name","new":"New Application","title":"Your applications"},"new":{"title":"New Application"},"show":{"actions":"Actions","application_id":"Application Id","callback_urls":"Callback urls","confidential":"Confidential","not_defined":"Not defined","scopes":"Scopes","secret":"Secret","secret_hashed":"Secret hashed","title":"Application: %{name}"}},"authorizations":{"buttons":{"authorize":"Authorize","deny":"Deny"},"error":{"title":"An error has occurred"},"form_post":{"title":"Submit this form"},"new":{"able_to":"This application will be able to","prompt":"Authorize %{client_name} to use your account?","title":"Authorization required"},"show":{"title":"Authorization code"}},"authorized_applications":{"buttons":{"revoke":"Revoke"},"confirmations":{"revoke":"Are you sure?"},"index":{"application":"Application","created_at":"Created At","date_format":"%Y-%m-%d %H:%M:%S","title":"Your authorized applications"}}
16518,"errors":{"messages":{"access_denied":"The resource owner or authorization server denied the request.","admin_authenticator_not_configured":"Access to admin panel is forbidden due to Doorkeeper.configure.admin_authenticator being unconfigured.","credential_flow_not_configured":"Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.","forbidden_token":{"missing_scope":"Access to this resource requires scope \"%{oauth_scopes}\"."},"invalid_client":"Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.","invalid_code_challenge_method":{"one":"The code_challenge_method must be %{challenge_methods}.","other":"The code_challenge_method must be one of %{challenge_methods}.","zero":"The authorization server does not support PKCE as there are no accepted code_challenge_method values."},"invalid_grant":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.","invalid_redirect_uri":"The redirect uri included is not valid.","invalid_request":"The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.","invalid_resource_owner":"The provided resource owner credentials are not valid, or resource owner cannot be found","invalid_scope":"The requested scope is invalid, unknown, or malformed.","invalid_token":{"expired":"The access token expired","revoked":"The access token was revoked","unknown":"The access token is invalid"},"resource_owner_authenticator_not_configured":"Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.","revoke":{"unauthorized":"You are not authorized to revoke this token"},"server_error":"The authorization server encountered an unexpected condition which prevented it from fulfilling the request.","temporarily_unavailable":"The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.","unauthorized_client":"The client is not authorized to perform this request using this method.","unsupported_grant_type":"The authorization grant type is not supported by the authorization server.","unsupported_response_mode":"The authorization server does not support this response mode.","unsupported_response_type":"The authorization server does not support this response type."}},"flash":{"applications":{"create":{"notice":"Application created."},"destroy":{"notice":"Application deleted."},"update":{"notice":"Application updated."}},"authorized_applications":{"destroy":{"notice":"Application revoked."}}},"layouts":{"admin":{"nav":{"applications":"Applications","home":"Home","oauth2_provider":"OAuth2 Provider"},"title":"Doorkeeper"},"application":{"title":"OAuth authorization required"}},"pre_authorization":{"status":"Pre-authorization"},"scopes":{"public":"Access your public data","write":"Update your data"}},"emails":{"error_notification":"Subscription not found.","success_subscribed_notification":"You have successfully subscribed.","success_unsubscribed_notification":"You have successfully unsubscribed."},"embed":{"item_not_available":"This item is no longer available."},"enterprise":{"3dContent":{"list":{"assets":"More than 1.6 million readily available 3D assets to choose from","custom":"Custom 3D modeling at scale","manager":"Dedicated customer success managers","search":"Tailored search support and 3D technical support (from advice to a model conversion)"},"title":"Quality 3D content at any scale"},"apply":"Apply","applySuccess":"Successfully applied","company'":{"label":"Company name"},"email":{"label":"Email"},"errors":{"email":"Invalid email","required":"This field is required"},"formTitle":"Apply for a business account by filling your details below","full_name":{"label":"Your name"},"licensing":{"list":{"guidance":"Guidance and advice on licensing and use","licenses":"Only two default licenses with clear terms","modelsSold":"90% of the models are sold on the marketplace with a Royalty-free license","royaltyFree":"Royalty-free license allows a wide range of commercial use"},"title":"Business oriented licensing"},"meta":{"description":"Leveraging our global community of highly skilled 3D designers, CGTrader converts eCommerce 2D images into compelling, high-quality 3D models for immersive product experiences.","t
16518itle":"Transform Your eCommerce Results with 3D Product Visualization"},"payment":{"list":{"digitalAsset":"Digital Asset Management system (cloud-based 3D model storage)","flexiblePayment":"Flexible payment terms and more convenient checkout","offers":"Special offers and discounts","shareAccounts":"Ability to share accounts and simplify payments for your employees"},"title":"Easy payment and sharing"},"review":"CGTrader is a great partner for our needs. We found the Prepaid credit payments very convenient for making purchases on the platform and custom reporting solutions help us a lot with asset management.","reviewAuthor":"Shouyi Lu, Yahaha Studios","subtitle":"3D content source for any type of business - from small design studios to large enterprises","title":"Business Account"},"errors":{"connection_refused":"Oops! Failed to connect to the Web Console middleware.\nPlease make sure a rails development server is running.\n","format":"%{attribute} %{message}","messages":{"accepted":"must be accepted","already_confirmed":"was already confirmed, please try signing in","blank":"can't be blank","carrierwave_direct_allowed_extensions":"Allowed file types are %{extensions}","carrierwave_direct_allowed_schemes":"Allowed schemes are %{schemes}","carrierwave_direct_attachment_missing":"attachment is missing","carrierwave_direct_filename_invalid":"is invalid. ","carrierwave_direct_filename_taken":"filename was already taken","carrierwave_direct_upload_missing":"upload is missing","carrierwave_download_error":"could not be downloaded","carrierwave_integrity_error":"is not of an allowed file type","carrierwave_processing_error":"failed to be processed","confirmation":"doesn't match %{attribute}","confirmation_period_expired":"needs to be confirmed within %{period}, please request a new one","content_type_blacklist_error":"You are not allowed to upload %{content_type} files","content_type_whitelist_error":"You are not allowed to upload %{content_type} files","empty":"can't be empty","equal_to":"must be equal to %{count}","even":"must be even","exclusion":"is reserved","expired":"has expired, please request a new one","extension_blacklist_error":"You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}","extension_whitelist_error":"You are not allowed to upload %{extension} files, allowed types: %{allowed_types}","greater_than":"must be greater than %{count}","greater_than_or_equal_to":"must be greater than or equal to %{count}","inclusion":"is not included in the list","invalid":"is invalid","invalid_vat":"is not a valid %{country_adjective} VAT number","less_than":"must be less than %{count}","less_than_or_equal_to":"must be less than or equal to %{count}","max_size_error":"File size should be less than %{max_size}","min_size_error":"File size should be greater than %{min_size}","mini_magick_processing_error":"Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}","model_invalid":"Validation failed: %{errors}","not_a_number":"is not a number","not_allowed":"It looks like thereâs an error because your %{attribute} contains forbbiden words. Please contact [email protected] to update your username","not_an_integer":"must be an integer","not_found":"not found","not_locked":"was not locked","not_saved":{"one":"1 error prohibited this %{resource} from being saved:","other":"%{count} errors prohibited this %{resource} from being saved:"},"odd":"must be odd","other_than":"must be other than %{count}","present":"must be blank","required":"must exist","rmagick_processing_error":"Failed to manipulate with rmagick, maybe it is not an image?","size_too_big":"is too big (should be at most %{file_size}). Please compress the image","size_too_small":"is too small (should be at least %{file_size})","taken":"has already been taken","too_long":{"one":"is too long (maximum is 1 character)","other":"is too long (maximum is %{count} characters)"},"too_short":{"one":"is too short (minimum is 1 character)","other":"is too short (minimum is %{count} characters)"},"vies_down":"Unable to validate your VAT number: the VIES service is down. Please try again later.","wrong_length":{"one":"is the wrong length (should be 1 character)","other":"is the wrong length (should be %{count} characters)"},"wrong_size":"is the wrong size (should be %{file_size})"},"unacceptable_request":"A supported version is expected in the Accept header.\n","unavailable_session":"Session %{id} is no longer available in memory.\n\nIf you happen to run on a multi-process server (like Unicorn or Puma) the process\nthis request hit doesn't store %{id} in memory. Consider turning the number of\nprocesses/workers to one (1) or using a different server in development.\n"},"feature_designer":{"active":"Active","special_campaign_title":"Create here your special featured campaigns","title":"Featured Designers"}
16518,"file_conversion_request":{"not_unique":"You have already requested this format. Please wait until CGTrader team contacts you regarding this conversion.\n","not_unique_dedicated_to_designer":"You have already requested this format. Please wait until designer contacts you regarding this conversion.\n","success":"Thank you for using CGTrader! Our 3D design team will contact you shortly and inform about converted version of this 3D Model.\n","success_designer":"Thank you for using CGTrader! Your file conversion request was successfully sent to designer.\n"},"file_size_validator":{"errors":{"invalid_carrierwave":"A CarrierWave::Uploader::Base object was expected","invalid_key":":%{key} must be a nonnegative Integer","range_format":":in and :within must be a Range","range_unspecified":"Range unspecified. Specify the :within, :maximum, :minimum, or :is option."}},"file_type":{"default_error":"No path to file supplied."},"flash":{"actions":{"create":{"notice":"%{resource_name} was successfully created."},"destroy":{"alert":"%{resource_name} could not be destroyed.","notice":"%{resource_name} was successfully destroyed."},"update":{"notice":"%{resource_name} was successfully updated."}}},"footer":{"bottom-row":{"privacy":"Privacy","terms-link":"Terms \u0026 Conditions"},"links":{"buyLinks":[{"text":"Buy 3D Models","link":"/3d-models"},{"text":"For Business","link":"/discover/business-account"},{"text":"3D Datasets","link":"/discover/datasets"},{"text":"Hire a 3D Designer","link":"/3d-modeling-jobs"},{"text":"Free 3D Models","link":"/free-3d-models"},{"text":"Free 3D Print Models","link":"/free-3d-print-models"}],"communityLinks":[{"text":"Community","link":""},{"text":"Top designers","link":"/designers"},{"text":"Challenges","link":"/challenges"},{"text":"Forum","link":"/forum"}],"companyLinks":[{"text":"Company","link":"/discover/about-us"},{"text":"Blog","link":"/blog"},{"text":"Careers","link":"/pages/careers"},{"text":"Help Center","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"Sell 3D Models","link":"/discover/sell-3d-models"},{"text":"Grow your sales","link":"/discover/sell-more"},{"text":"3D Market Insights","link":"/discover/3d-market-trends"},{"text":"Top 3D Model Searches","link":"/discover/3d-models-top-searches"},{"text":"Top 3D Print Searches","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"Subscribe","button-disabled":"Subscribed","header":"Subscribe to our news:","placeholder":"Enter your email","terms-link":"Terms of Use","text":"By subscribing you confirm that you have read and accept our"}},"forum":{"board":{"1":{"meta_description":"This is where thousands of 3D designers come to share their thoughts on a variety of topics. Introduce yourself, post your thoughts about the CG industry, discuss software, design news and other ideas. The General Discussion Board is where you can find friends, get tips or simply relax in our welcoming community."},"2":{"meta_description":"Spread great knowledge you found on the web! This is the place where you can share the best tutorials and tricks with others in the CGTrader community. Come here and learn from the best! And do not forget that we also have a dedicated tutorial page on our site, where users can post their own tutorials."},"3":{"meta_description":"Have a question? Ask anything about the CG industry here, or help others find out what you already know. Get to know everything about payments, purchases, refunds and other questions about the marketplace. Donât be shy â the best and most frequent questions and answers might find their way to our FAQ."},"4":{"meta_description":"This is the most important Board for us. Tell us about your experience on CGTrader. Give feedback about our site and practices. Share your ideas on how we could improve in the future. We are the most designer-oriented 3D marketplace on the web and, with help from our users, we intend to stay that way."},"5":{"meta_description":"We know some projects are not for sale, and we realize you need a place to show your work. This is our haven for artists and show-offs. Got that new high-poly model? Show everyone that slick PBR-textured 3D spaceship. This is where you can get inspired, discuss, give feedback and provide constructive criticism."},"6":{"meta_description":"All things marketplace. Find out the dos and donâts every new buyer or seller should know. Share your ideas and thoughts about the demand and use of stock 3D models. Tell us if you canât find something on the marketplace. Talk about the industry, pricing practices, start selling or buying models."},"7":{"meta_description":"Everything 3D printing. Talk about your favorite 3D hardware, materials, software and modeling practices. Share your 3D print models and printing results, talk about service providers or news coming out of the 3D printing industry."},"8":{"meta_description":"Feeling ready for a challenge? Enter our friendly competitions to win cash prizes, software licenses and other great stuff. Learn by competing with the best designers in our themed challenges and awards â thereâs something for everyone! Discuss ideas and entries, share your insights about our competitions here."}},"index":{"meta_description":"Hop on our forums and engage a friendly and supportive designer community. This is the place where you can introduce yourself, read design news, ask questions about 3D modeling and 3D printing, showcase your work, give feedback or just have plain old fun chatting with the most interesting people in the design world!"}},"general":{"description":"CGTrader is an online marketplace where 3D artists and designers can buy, sell or share 3D models. It was founded and is being developed by a team of 3D designers and engineers. Our goal is to democratize 3D stock market and change the way
16518we sell 3D models online. By letting authors earn maximum royalties, we strive to increase their motivation and raise the quality of 3D models.","licenses":{"custom":"applies to this model.","editorial":"The intellectual property depicted in this model is not endorsed by or affiliated with the original intellectual property right holders and must be used under the","general":"applies to this model."},"menu":{"admin":"Admin","dashboard":"Dashboard","inbox":"Inbox","my_feed":"My Feed","my_purchases":"My Purchases","sign_in":"Sign In","sign_out":"Sign Out","upload_model":"Upload 3D Model"},"messages":{"server_not_responding":"Server not responding. Please try again later"},"navigation":{"buy_3d_models":"Buy 3D Models","sell_3d_models":"Sell 3D Models"},"search_placeholder":"Search over 2 million models","site-search__field":"Search %{model_count} 3D models","site_title":"3D Model Store","site_title_postfix":" | CGTrader","update":{"failed":"Failed to update","success":"Successfully updated"}},"generator":{"assets":{"errors":{"file_too_large":"This model's files exceed the %{limit}MB generator limit.","no_compatible_file":"This model has no GLB, glTF, FBX, OBJ or STL file that can be used in the generator."}},"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"Make AI Realize Your Dreams","subtitle":"Turn a prompt or a reference image into a production-ready 3D model, then refine, retexture and export it in the format you need."},"faq":{"heading":"Frequently Asked Questions","items":{"commercial":{"answer":"Commercial use of your 3D %{object} model is available on a paid CGTrader AI plan. Please review the CGTrader Terms and Conditions for the licence terms that apply to AI-generated models.","question":"Can I use the generated %{object} model for commercial purposes?"},"formats":{"answer":"The 3D models of %{object} are available in GLB, FBX, OBJ, STL or USDZ format.","question":"In which file format can I get my %{object} model?"},"no_skills":{"answer":"No knowledge of 3D modeling is required. All modeling is done through the %{object} model generator. The system handles the geometry, proportions, and structure when you input your desired prompt or upload an image. Even beginners can create a comprehensive 3D %{object} model in minutes.","question":"Does using a %{object} model generator need any knowledge of 3D modeling?"},"what_is":{"answer":"The CGTrader 3D %{object} Model generator, an AI-based tool, creates a three-dimensional %{object} model from written instructions or reference images. The CGTrader %{object} Model Generator looks at your idea and creates a downloadable model for design, prototyping, and visualization. Our paid subscriptions offer higher monthly limits.","question":"What is a 3D %{object} Model generator?"},"why_cgtrader":{"answer":"Users can trust CGTrader to provide a smooth experience, fast processing times, and high-quality 3D outputs. This tool is suitable for both professionals and beginners who are looking for a trustworthy solution to make 3D %{object} models.","question":"Why use the AI %{object} generator from CGTrader?"}}},"h1":"AI %{object} 3D model generator","hero_alt":"AI %{object} 3D model generator","hero_height":617,"hero_width":1080,"how_to":{"heading":"Generate %{object} From Image or Text Prompts","paragraphs":["It is very easy to design a three-dimensional %{object} model. In the left sidebar, on the top-left, click the button to upload your image of the %{object} to construct a 3D model. Users can also enter a prompt in the \"Describe what you want to create\" field at the bottom. CGTrader AI refines your prompt for you, so a short description is enough to get started.","The right-hand sidebar gives you good control of your 3D %{object} model. Choose settings like the mesh type, material, prompt guidance, and file format. You can also use texturing to customize your %{object} model. This means that you can choose between a textured 3D %{object} model or a texture-free one. After entering your text instructions or image, click \"Generate\". The tool will process your input in a few minutes, depending on system load, material, mesh type, shapes, seeding values, and quality."],"steps":["Write your text description and/or attach a reference image to improve the final accuracy of your 3D %{object} model.","Select one of our presets, or pick an AI Engine, add a custom polygon count, and select the material type for your 3D %{object} model.","Hit Generate to create a 3D %{object} model from your prompt and/or reference image.","Download your created 3D %{object} model in different formats (GLB, FBX, OBJ, STL or USDZ)."]},"intro":"Are you looking for a simple and quick way to create a high-quality 3D %{object} model in minutes? Our advanced 3D %{object} model generator, CGTrader AI, can turn written commands or reference images into fully working models. It runs on production 3D generation engines including Meshy, Hunyuan and Tripo3D. This helps with the quick modeling of 3D models for both design beginners and experts for visualization, experimentation, and prototyping. It supports both text-to-3d and image-to-3d, and is compatible with 3D printers. This means that you can upload an image in a JPG or PNG format. You can also write a description in the form of text. CGTrader AI takes care of the steps for you.","meta_description":"AI %{object} 3D Model Generator by CGTrader âï¸ Generate detailed %{object} 3D models from text or images. Start creating free now.","primary_cta":"Start generating for free","title":"AI %{object}
16518 3d model generator (free) | CGTrader"}}},"rules":{"errors":{"front_view_required":"Front view image is required."}},"runs":{"errors":{"cannot_delete_active":"You can't delete a generation that is still in progress. Wait for it to finish, then delete it.","concurrency_cap_reached":"You have reached the maximum number of concurrent generations for your plan (%{cap}). Wait for a generation to finish before starting another.","generation_not_entitled":"Generating is not available on your current plan. Start a free trial or subscribe to start generating.","marketplace_input_must_stay_private":"This generation used a model you purchased and must stay private.","not_riggable":"Tripo pre-rig check determined this model cannot be rigged for animation.","nsfw_must_stay_private":"This generation is flagged as NSFW and must stay private."}}},"helpers":{"label":{"address":{"first_name":"First Name","last_name":"Last Name","state":"State / Province","street_address":"Street Address","street_address_second":"Street Address Line 2","vatin":"VAT number","zip_code":"Postal / Zip Code"},"print":{"printer_type_id":"Name of the printer"},"printer_page":{"image":"Image (1800x500px)","listing_image":"Printer's image","name":"Printer name"}},"select":{"prompt":"Please select"},"submit":{"create":"Create %{model}","submit":"Save %{model}","update":"Update %{model}"}},"home":{"index":{"3D-projects":{"info-section__cta":"Learn more","info-section__description":"Where people with exciting 3D Projects meet talented 3D designers","info-section__heading_html":"\u003cstrong\u003e3D Projects\u003c/strong\u003e Freelance Hub"},"categories-conatainer":{"browse_all":"Browse all models","browse_all_tooltip":"Browse all 3D models","discounts":"Discounts"},"cgdream":{"cta":"Get started for Free!","heading_html":"\u003cstrong\u003eExplore CGDream,\u003c/strong\u003e\u003c/br\u003e where AI meets 3D models.","text_html":"\u003cstrong\u003eCGDream\u003c/strong\u003e is a cutting-edge application that leverages the power of generative AI and 3D models to produce stunning 2D images. \u003cstrong\u003e Your creative journey starts now.\u003c/strong\u003e"},"community":{"info-section__cta":"Join the community","info-section__heading_html":"Join CGTrader \u003cstrong\u003eCommunity\u003c/strong\u003e","info-section__icon-list_1":{"description":"Showcase your best renders, get feedback and recognition","heading":"Galleries"},"info-section__icon-list_2":{"description":"Learn new skills and teach others","heading":"Tutorials"},"info-section__icon-list_3":{"description":"Find tutorials and discuss other 3D related matters","heading":"Forum"}},"covid":{"timer-strip__item":"Free 3D Printable Resources for COVID-19 Protection","timer-strip__item--button":"Browse 3D Models"},"enterprise":{"info-section__cta":"Learn more","info-section__heading_html":"3D Services for the \u003cstrong\u003eEnterprise\u003c/strong\u003e","info-section__icon-list_1":"We can do the AR implementation for you","info-section__icon-list_2":"More sales conversions, less product returns","info-section__icon-list_3":"Quality ensured with stringent QA"},"header":"3D models for VR / AR, 3D printing and computer graphics","marketplace":{"info-section__description":"Choose from %{models_count} 3D models for applications such as gaming, AR/VR, advertising, animation, movies and 3D printing","info-section__heading_html":"3D Model \u003cstrong\u003eMarketplace\u003c/strong\u003e","info-section__image-list_1":{"description":"Buy professional 3D Models for your project","heading":"3D Models"},"info-section__image-list_2":{"description":"Low-poly PBR 3D Models ready for video games, VR \u0026 AR real-time applications","heading":"Low-poly PBR 3D Models"},"info-section__image-list_3":{"description":"Find 3D Print Designs for your 3D Printer","heading":"3D Printing Models"},"view_all":"View All"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"Turn an image into a 3D model","title":"Image to 3D"},"text_to_3d":{"description":"Describe your idea to create a 3D model","title":"Text to 3D"}},"ai_section_title":"Create with AI","aria_label":"Search suggestions","columns":{"cg":{"search_label":"Search in 3D Models","title":"3D Models"},"print":{"search_label":"Search in 3D Print","title":"3D Print Models"}}},"sell":{"info-section__heading_html":"\u003cstrong\u003eSell\u003c/strong\u003e your 3D Models and Find Freelance Projects","info-section__icon-list_1":{"de
16518scription":"Sell your 3D models and earn up to 85% royalties","link":"Sell 3D Models"},"info-section__icon-list_2":{"description":"Work with enterprise clients","link":"Get Qualified"},"info-section__icon-list_3":{"description":"Outsource your skills \u0026 get up to 95% royalties","link":"Browse 3D Modeling Jobs"},"info-section__icon-list_4":{"description":"Build your portfolio and be visible","link":"Browse 3D Designers"}},"seo":{"description":"Explore 2M+ 3D models online for print, game, VR/AR \u0026 design projects. Download, customize, or hire 3D experts - all on CGTrader.","title":"CGTrader - 3D Models And 3D Printing Marketplace"}}},"homepage":{"budget_counter":{"range_0_10":"Under $10","range_10_20":"$10 - $20","range_20_15000":"More than $20"},"quotes":{"quote_0":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Lower commissions taken from the sellers means better prices for the buyers. Check out and compare the prices at CGTrader and the other shops."},"quote_1":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"The most striking advantage of CGTrader is flat-fee activation system which gives us high returns. You are NOT taking a commission percentage of our sales. After the sale, we receive the 100% of the price. Only if we want to continue selling that product, we may re-activate it again by paying $5. Elegant solution."},"quote_10":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"The flat fee activation system is ingenious. I was wondering why no one had thought of this before. After the sale, pay a small fee to activate a product and that's it. The seller is in full control."},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"There are two things I like the most about CGTrader. First, there is no hidden meaning to anything here. You don't need to be careful with CGTrader. Second, this store is By the Artists and For the Artists. They understand you better. Something is bothering you here?... let them know and they will make sure that you feel comfortable here."},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Flat-fee activation system is the best! (at least I haven't come across anything better than this). Its very realistic and fair to the sellers. They don't care how much profit you make, just pay the fixed rent. BUT if you don't make any sales, you don't have to pay the rent either. Fair CG trade is here!"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"CGTrader attracts customers even from developing countries, because prices are cheaper than on other stores. At the same time authors can earn more, because there is no such thing as high commission rates. It is a right way to value the work of 3D artists."},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"Intuitive interface of the publisher and innovative tools like tag recommendation and flexible description forms makes the publishing process easy and fast."},"quote_15":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTraderâs approach of selling 3D is different and have nothing in common with other stores I used to sell. Pay a low fee of 5$ after the sale is a great idea and allow me to offer lowest prices here. Customer and artist are benefited with this way of working."},"quote_16":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"The upload system is easy and clear. Itâs good to know that behind the project are people with years of experience in computer graphic matters. Anytime I had a problem, CGTrader team fixed it quickly."},"quote_17":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTrader allows me to link my profile with my personal webpage. Customers can contact me, if they are not certain about a characteristic of an item they want to buy or just want a modification of it. Itâs like owning a personal 3D store in a big marketplace!"},"quote_2":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"We have enjoyed a great and responsive support from CGTrader team. The staff kindly offered to do the publishing of all the models for us, which is a great help for professional sellers."},"quote_3":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"On this platform we can offer much better prices to our customers. For example all our products are priced 20% lower than anywhere else and we still get more profits compared to other stores!"},"quote_4":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"This is the BEST system to date. All the other online 3D stores take a % from our profits. This was THE feature that caught our interest in CGTrader from the beginning. Customers, buying on CGTrader, know that the most part of their money go to the author, who in the end will make more and better models if their profits improve."},"quote_5":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"CGTrader is the online 3D store which made the fastest growing sales and profit for us. The flat-fee activation system is the best you can find, as it rewards content creators instead of middlemen. "},"quote_6":{"author":{"name":"RiÄardas Marozas","username":"Pumper"},"text":"When I received $160 to my Paypal account, did not know what's going on as it never happened before but then I thought that it might be a CGTrader sale and I was right. Sold the same pack on Turbosquid last month for $189 but after 40% earning rate and 30% tax, all I got was $52.92 - pennies compared to $160 from CGTrader. Plus the customer payed $29 less - now that's a proper business."},"quote_7":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"At first I was skeptical about such a good deal for sellers which is not the norm for major online 3D stores. When I learnt about the flat-fee activation system, I was impressed by such a creative way of selling digital assets. Sell, then activate by paying a $5 fee. It all make sense to me. I uploaded a few to try out and truly, when I got my first sale, it was 100% earnings!"},"quote_8":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"I was so used to many others sites that charge between 30% - 60% commission until I discovered CGTrader. As a seller, I definitely like the high percentage of earning returns."},"quote_9":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"The seller experience is fantastic. Product submission is a breeze. And yes, the system allowed me to save a draft of my product submission every stage of the way."}},"subscription_confirmation":{"body":{"text":"Your notification preference is registered.\nYou will c
16518ontinue to receive notifications emails from our team.\n"},"head":{"text":"Thank you!"}}},"hyperwallet":{"failed_payment_agreement":"Something unexpected happened","success_notification":"Payment Agreement has been updated successfully.","success_payment_agreement":"Payment Agreement has been submitted successfully."},"invoices":{"reverse_charging":"Reverse Charging","seller_info":"UAB \"CGTRADER\"\nAntakalnio g. 17, LT-10312 Vilnius, Lithuania\nCompany code: 302935696\n"},"item-search-filters":{"3d-models-url":"3d-models","3d-print-models-url":"3d-print-models","dedicated-search-page-url":{"animated":"/animated-","free":"/free-","low_poly":"/low-poly-","pbr":"/pbr-","rigged":"/rigged-"}},"item_use_case":{"not_valid":"Invalid file","pundit":{"not_authorized":"You are not authorized to perform this action."},"title":"Use case for %{item_name}"},"items":{"already_purchased":"You have already purchased this item.","filters":{"attributes":"Select attribute","free":"Free","max_value":"$500+","min_value":"$2","reset":"Reset filters","select":"Select"},"footer":{"next":"Next","per_page":"Per page:","previous":"Previous"},"geometry_type_forbidden":"Geometry type forbidden!","last_card":{"button_text":"Request a custom 3D model","text":"Couldn't find what you're looking for?"},"migrations":{"errors":{"invalid_owner":"New owner is not able to take items.","unpublished_items":"All items must be published."}},"new_price_applied":"New prices have been successfully applied to all items.","new_price_applied_to_selected_items":"New prices have been successfully applied to selected items.","new_prices_to_filtered_models":"New prices have been successfully applied to all filtered items.","order_processed":"Order processed.","order_processing":"Order processing.","something_went_wrong":"Something went wrong.","title_error":"Title should not contain non-latin symbols","uniq_user":"has already submitted a use case for this item","upload_error":"Upload error.","validate_license_for_zero_price":"is not valid for free item","validate_minimum_price":"Price offers should not be below the minimum of 50% of the original price","verify_printable_formats_error":"Please upload at least one .stl, .obj or .wrl file.","you_can_not_delete_models":"You can not delete models"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projects makes it easy to hire quality freelance 3D artists and solve all your modeling challenges.","heading_html":"Meet the best freelance platform for your \u003cstrong\u003e3D modeling jobs\u003c/strong\u003e"},"sections":{"call_to_action":{"description":"Post your Project for free and see how easy it is to solve your next modeling challenge with 3D Projects.","title":"Hire the best 3D talent today!"},"freelancer_selection":{"title":"Make your next 3D Project a success","widest_selection":{"description":"Don't settle for anything less. Home to 40,000 freelance 3D designers, CGTrader is the largest platform to help you connect with skilled specialists: modelers, animators, riggers, 3D print pros and everything in between.","title":"Widest selection of 3D freelancers"}},"how_it_works":{"steps":{"describe":{"description":"Tell us what you need. Use our simple form, add images and publish your freelance offer in minutes.","title":"Describe your Project"},"pay":{"description":"Securely prepay the budget to CGTrader and let your freelancer know you're ready to start. Chat, share attachments and view Project progress conveniently in your dedicated workspace. Release the payment when you're happy with the end result.","title":"Pay for the result"},"select":{"bullets":["Receive quotes from qualified designers straight to your inbox","Chat with designers in real time","Browse their previous Projects","You can also search, filter and invite freelancers according to 3D skills, ratings and your software or format preferences"],"title":"Select the best freelancer"}},"title":"Get your job done in 3 simple steps"},"payment_quality":{"description":"CGTrader ensures that the freelance services will meet your requirements and be delivered on time. Our QA Team is available whenever you need them.","title":"Quality guaranteed"},"secure_payments":{"description":"Our escrow service means your funds are protected and you only pay when you're happy with the final results.","title":"Secure payments"}
16518,"workspace_convenience":{"description":"Forget the frustration of jumping between tabs and different tools. With the dedicated workspace, you can easily manage everything in one place: multiple projects, invoices, conversations, file sharing and more.","title":"Single screen convenience"}},"shared":{"post_project_cta":"Post project"}},"meta":{"description":{"find_projects":"Browse and find 3D modeling jobs and work from the comfort of your home. New freelance projects daily. Secure payments. Get hired today.\n","hire_designers":"Discover the largest platform to find freelance designers and artists for your next 3D Project. Post a 3D modeling job for free today.\n"},"title":{"find_projects":"Jobs For Freelance 3D Artists","hire_designers":"Hire Freelancers For 3D Modeling Jobs"}},"navigation":{"find_jobs_cta":"Find 3D jobs","hire_freelancers_cta":"Hire 3D freelancers","how_it_works":"How it works","why_projects":"Why 3D Projects"}},"agreed_to_terms_of_use":"You must agree with 3D Projects Terms \u0026 Conditions to continue.","budget_error_message":"is too high","check_designer_uniqueness_error":"Designer can only be invited once","check_ownership_error":"Inviter does not own job","check_status_error":"Designers can be invited only to approved jobs.","create_message_dedicated":"Thank you for starting a 3D Project. %{username} will receive a personal email and a notification about this Project.\n","create_message_private":"Thank you for starting a 3D Project. Designer(s) will receive a personal email and a notification about this Project.\n","create_message_public":"Thank you for creating your Project. You should now be able to see it in our 3D Projects listing page.","deadline_error_message":"Deadline must be in future","discount_code_error":"Sorry, discount code does not exist or is expired.","email_subject":"3D Project opportunity: %{subject}","error_check_application_uniqueness":"You can only apply once","error_check_applier":"You cannot apply to your own 3D Project","error_check_job_availability":"User not authorized to apply","error_check_job_status":"Project applications are on hold until our new moderation process is completed, typically within 3 business days. Your understanding is appreciated!","modeling_request_failed":"Modeling Request failed!","offer_has_been_sent":"Thank you, your offer has been sent!","offer_is_closed":"Offer is closed.","order_status_messages_for_admin":{"paid":"Paid","pending":"Pending","refunded":"Refunded"},"payment_successful":"Payment successfully paid.","payment_under_review":"Payment is under review.","private_job_message":{"initiated_by_designer_html":"Hi %{buyer_username}, \u003cbr\u003e\u003cbr\u003e I invited you to start a 3D Project. Click \u003ca href=\"%{job_template_link}\"\u003ehere\u003c/a\u003e to review the details of the Project and make any adjustments. \u003cbr\u003e\u003cbr\u003e I am looking forward to hearing from you. \u003cbr\u003e\u003cbr\u003e Best, %{designer_username}","private_html":"Hi %{designer_username}, \u003cbr\u003e\u003cbr\u003e I invited you to work on a 3D Project. See my \u003ca href=\"%{application_link}\"\u003erequest\u003c/a\u003e for more details. \u003cbr\u003e\u003cbr\u003e I look forward to hearing from you soon. \u003cbr\u003e\u003cbr\u003e Best, %{buyer_username}"},"share_job_template_message":"Your Project invitation was successfully sent.","share_with_yourself_error":"Sharing Hire Me templates with yourself is not allowed","status_messages":{"approved":"Waiting for applicants","expired":"Expired","finished":"Finished","prepaid":"Job in progress","refunded":"Refunded","started":"Started","unapproved":"Waiting for approval"},"status_messages_for_admin":{"approved":"Approved","canceled":"Canceled","expired":"Expired","finished":"Finished","refunded":"Refunded","started":"Started","unapproved":"Unapproved"},"status_messages_for_client":{"approved":"Waiting for your selection","canceled":"Canceled","confirmed_by_designer":"Confirmed by designer","expired":"Expired","finished":"Finished","in_progress":"In progress","started":"In progress","unapproved":"Waiting for approval","waiting_for_their_confirmation":"Waiting for designer's confirmation","waiting_for_your_approval":"Waiting for your approval","waiting_for_your_confirmation":"Waiting for your confirmation","waiting_for_your_review":"Waiting for your review"},"status_messages_for_designer":{"approved":"Not yet selected","canceled":"Canceled","confirmed_by_designer":"Confirmed","declined":"Declined","expired":"Expired","finished":"Finished","not_selected":"Not selected","started":"Running","unapproved":"Waiting for approval","waiting_for_answer":"Waiting for answer","waiting_for_payment":"Waiting for client's payment","waiting_for_their_review":"Waiting for client's review","waiting_for_your_confirmation":"Waiting for your confirmation","waiting_for_your_review":"Waiting for your review"},"system_messages":{"buyer_cancels_job":"Project was canceled and moved to %{archive_url} tab.","buyer_edits_hire_me_template":"Project details were updated by client.","buyer_edits_job_details":"Project details were updated.","buyer_marks_job_as_finished":"Project was marked as finished and moved to %{archive_url} tab.","buyer_marks_job_as_finished_with_resell":"Client marked the Project as finished and allowed you to sell the results on CGTrader. Make sure to \u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003eupload\u003c/a\u003e\u003c/b\u003e the created model!","buyer_negotiates":"Client negotiated your price offer.","buyer_pays_for_the_job":"Project was prepaid and moved to %{in_progress_url} tab.","designer_accepts_changes":"Designer reviewed updated details.","designer_accepts_offer":"Designer accepted y
16518our offer.","designer_edits_offer":"Designer edited his offer.","designer_negotiates":"Designer negotiated your offer.","designer_withdraws_offer":"Designer withdrawn his offer.","job_expires":"Project expired and was moved to %{archive_url} tab."},"template_error":"No jobs were created!","tooltip":{"approx_revenue_html":"Your approximate revenue is counted after calculating approximate payment \u003cbr/\u003e processing fees and 5% royalties received by CGTrader. Please note that your \u003cbr/\u003e final revenue may vary a little bit due to payment processing fee calculation.\n","confirm_t_a_c_html":"By clicking this button you confirm that you agree with 3D Jobs \u003ca target='_blank' href=\"https://www.cgtrader.com/pages/3d-jobs-agreement\"\u003eTerms \u0026 Conditions\u003c/a\u003e\n","ip_rights_html":"By checking this checkbox you agree that you renounce exclusive rights to content \u003cbr/\u003e created with this 3D job offer, furthermore allow designer to retain the Intellectual \u003cbr/\u003e property rights and publish job results on the CGTrader marketplace.\n","ip_rights_renounced_html":"Buyer renounced exclusive rights to content created with this 3D job offer, \u003cbr /\u003e furthermore you are allowed to retain the Intellectual property rights and \u003cbr /\u003e publish job results on the marketplace.\n","level":"Level shows designer's reputation on CGTrader. It defines his input into 3D modelling community, number of models uploaded, feedback from buyers and many other factors.","private_type":"Only invited designers will see and be able to apply for this job.","public_type_html":"Your job will be posted in public 3D jobs listing page. \u003cbr/\u003e All community designers will be allowed to apply for this job.\n","quality":"Quality is average rating of designer's models on CGTrader. This rating should help you to compare one designer against another.","vat_html":"Value Added Tax (VAT), also known as Sales tax or Goods \u003cbr/\u003e and services tax (GST), is a tax applied at the point of sale \u003cbr/\u003e to the end buyer and paid to the government of the buyerâs country. "},"user_not_exists":"User with that username does not exist.","want_that_job":"I want this job!"},"kodama":{"invalid_request":"Invalid request!"},"landing":{"consent_not_saved":"Consent was not saved","failure_notification":"All required API access request fields should be valid.","success_notification":"Thank you for your request. We will contact you shortly."},"layout":{"chunk_load_notice":"Something went wrong while loading this page. Please refresh.","cookies_policy":{"accept":"Accept","learn_more":"Learn more","text":"Our website uses cookies to collect statistical visitor data and track interaction with direct marketing communication / improve our website and improve your browsing experience. Please see our Cookie Notice for more information about cookies, data they collect, who may access them, and your rights."}},"licenses":{"custom_html":"\u003cp\u003eContent published with the Custom License label shall be deemed applicable if and only if the Seller provides additional license terms on the content.\u003c/p\u003e\n\n%{content}\n","editorial_html":"\u003cp\u003eThis product may be used in an editorial manner, but other uses such as commercial, promotional, advertising or merchandising use may require legal clearances from intellectual property owners.\u003c/p\u003e\n\u003cp\u003eTERMS OF LICENSE AGREEMENT BETWEEN THE SELLER AND THE BUYER\u003c/p\u003e\n\n\u003cp\u003e1. General Terms of Licensing\u003c/p\u003e\n\n\u003cp\u003e1.1. Following the payment of any applicable license fee for Product, the Buyer acquires a license in accordance with the terms and conditions of this section. Any license rights relating to the Product are contingent upon the transfer of money (except for the free Products) from the Buyer to the Seller. All license rights terminate immediately and without notice if a sale is reversed for any reason.\u003c/p\u003e\n\n\u003cp\u003e1.2. Upon uploading the Product to the Site, the Seller shall indicate the terms of license, upon which a respective Product is licensed to the Buyer. If the Seller does not indicate any licensing conditions in his posting, terms of Royalty free license (see section 2 âRoyalty Free Licenseâ) shall be applicable. Royalty free license shall be applicable to Products that are made available for free download but the Sellerâs, unless it is expressly indicated otherwise.\u003c/p\u003e\n\n\u003cp\u003e 1.3. Certain Products with third party copyrighted or trademarked images, logos, brand names, etc., may require additional licensing, rights, permissions, releases, or clearance for non-editorial use. It is the sole responsibility of the Buyer and their legal advisor to determine, before purchasing, downloading or using any Product, whether additional licensing, rights, permissions, releases, or clearance are necessary for the intended use of Product. It is the Buyerâs sole responsibility to obtain any licensing, rights, permissions, or clearance. Buyers should understand additional licensing, rights, permissions, releases, or clearance may be relevant for Product, if the intended use involves religious groups or affiliations, pharmaceuticals, health care, tobacco, liquor, adult entertainment, personal hygiene, birth control, or any other area that could be considered sensitive, offensive, or immoral.\u003c/p\u003e\n\n\u003cp\u003e1.4. All licenses of the Products are non-transferrable. Buyers do not own any Product and are only licensed to use it in accordance with terms and conditions of the applicable license. Unless explicitly provided for in custom license terms set forth in the special area âCustom license termsâ provided by CG Trader in the Product description section of the Site, the Seller retains copyright in Products purchased or downloaded by any Buyer. \u003c/p\u003e\n\n\u003cp\u003e1.5. The license to use the Product is non-exclusive, non-transferable and is granted only to you as the original Buyer.\u003c/p\u003e\n\n\u003cp\u003e1.6. Any Product, returned to CG Trader and (or) the Seller in accordance with applicable law for whatever reason must be destroyed by the Buyer immediately. The license to use any Product is revoked at the time Product is returned. Product obtained by means of theft or fraudulent activity of any kind is not granted a license.\u003c/p\u003e\n\n\u003cp\u003e1.7. By using the Site and (or) accepting this EULA the Seller agrees that any additional end user license agreements, licenses, custom licenses, or Seller requirements inserted into Seller Products in any area outside that explicitly provided by CG Trader for additional license terms are invalid, void ab initio, and without effect as they relate to those purchases made on the Site.\u003c/p\u003e\n\n\u003cp\u003e1.8. The license grant contained in this EULA can be terminated using the guidelines below. CG Trader reserves the right to terminate this agreement at any time and without notice if any Content submitted violates the representations and warranties of paragraph three (3) below. This agreement may be terminated at any time by either party upon written notice via email or regular mail. Nothing in this agreement shall be construed to mean that a Seller may not submit or delete Content from the material submitted by such Seller as part of general maintenance of such Sellerâs account.\u003c/p\u003e\n\n\u003cp\u003e3. Editorial License\u003c/p\u003e\n\n\u003cp\u003e3.1. In addition to the restrictions that are applicable to the Royalty free license, certain Products may be marked âeditorialâ or âeditorial licenseâ and has additional license restrictions. \u003c/p\u003e\n\n\u003cp\u003e3.2. Buyerâs may only use Products marked âeditorialâ or âeditorial licenseâ for legitimate, editorial purposes on some issue of journalistic, editorial, cultural or otherwise newsworthy value. Examples of editorial use/fair use may include illustrating issues of general interest, social commentary, reporting news, etc. Editorial uses include use of the Product in a news program, news-related website, or news-related video media. The Buyer understands and agrees that such Products may contain material that is not released from its rights holders. \u003c/p\u003e\n","royalty_free_html":"\u003cp\u003e Royalty Free License allows you to use copyright material or intellectual property without the need to pay earnings or license fees for each use or per volume sold, or some time period of use or sales. Content published with this license may not be sold, given, or assigned to another person or entity in the form it is downloaded from the site but can be used in your projects multiple times after paying for it just once.\u003c/p\u003e\n\n\u003cp\u003eIV. TERMS OF LICENSE AGREEMENT BETWEEN THE SELLER AND THE BUYER\u003c/p\u003e\n\n\u003cp\u003e1. General Terms of Licensing\u003c/p\u003e\n\n\u003cp\u003e1.1. Following the payment of any applicable license fee for Product, the Buyer acquires a license in accordance with the terms and conditions of this section. Any license rights relating to the Product are contingent upon the transfer of money (except for the free Products) from the Buyer to the Seller. All license rights terminate immediately and without notice if a sale is reversed for any reason.\u003c/p\u003e\n\n\u003cp\u003e1.2. Upon uploading the Product to the Site, the Seller shall indicate the terms of license, upon which a respective Product is licensed to the Buyer. If the Seller does not indicate any licensing conditions in his posting, terms of Royalty free license (see section 2 âRoyalty Free Licenseâ) shall be applicable. Royalty free license shall be applicable to Products that are made available for free download but the Sellerâs, unless it is expressly indicated otherwise.\u003c/p\u003e\n\n\u003cp\u003e1.3. Certain Products with third party copyrighted or trademarked images, logos, brand names, etc., may require additional licensing, rights, permissions, releases, or clearance for non-editorial use. It is the sole responsibility of the Buyer and their legal advisor to determine, before purchasing, downloading or using any Product, whether additional licensing, rights, permissions, releases, or clearance are necessary for the intended use of Product. It is the Buyerâs sole responsibility to obtain any licensing, rights, permissions, or clearance. Buyers should understand additional licensing, rights, permissions, releases, or clearance may be relevant for Product, if the intended use involves religious groups or affiliations, pharmaceuticals, health care, tobacco, liquor, adult entertainment, personal hygiene, birth control, or any other area that could be considered sensitive, offensive, or immoral.\u003c/p\u003e\n\n\u003cp\u003e1.4. All licenses of the Products are non-transferrable. Buyers do not own any Product and are only licensed to use it in accordance with terms and conditions of the applicable license. Unless explicitly provided for in custom license terms set forth in the special area âCustom license termsâ provided by CG Trader in the Product description section of the Site, the Seller retains copyright in Products purchased or downloaded by any Buyer. \u003c/p\u003e\n\n\u003cp\u003e1.5. The license to use the Product is non-exclusive, non-transferable and is granted only to you as the original Buyer.\u003c/p\u003e\n\n\u003cp\u003e1.6. Any Product, returned to CG Trader and (or) the Seller in accordance with applicable law for whatever reason must be destroyed by the Buyer immediately. The license to use any Product is revoked at the time Product is returned. Product obtained by means of theft or fraudulent activity of any kind is not granted a license.\u003c/p\u003e\n\n\u003cp\u003e1.7. By using the Site and (or) accepting this EULA the Seller agrees that any additional end user license agreements, licenses, custom licenses, or Seller requirements inserted into Seller Products in any area outside that explicitly provided by CG Trader for additional license terms are invalid, void ab initio, and without effect as they relate to those purchases made on the Site.\u003c/p\u003e\n\n\u003cp\u003e1.8. The license grant contained in this EULA can be terminated using the guidelines below. CG Trader reserves the right to terminate this agreement at any time and without notice if any Content submitted violates the representations and warranties of paragraph three (3) below. This agreement may be terminated at any time by either party upon written notice via email or regular mail. Nothing in this agreement shall be construed to mean that a Seller may not submit or delete Content from the material submitted by such Seller as part of general maintenance of such Sellerâs account.\u003c/p\u003e\n\n\u003cp\u003e2. Royalty Free License \u
16518003c/p\u003e\n\n\u003cp\u003e2.1. Product may not be sold, given, or assigned to another person or entity in the form it is downloaded from the Site\u003c/p\u003e\n\n\u003cp\u003e\n 2.2. The Buyerâs license to Product in this paragraph is strictly limited to Incorporated Product. Any use or republication, including sale or distribution of Product that is not Incorporated Product is strictly prohibited. For illustration, approved distribution or use of Product as Incorporated Product includes, but is not limited to:\n (1) as rendered still images or moving images; resold as part of a feature film, broadcast, or stock photography;\u003cbr\u003e\n (2) as purchased by a gameâs creators as part of a game if the Product is contained inside a proprietary format and displays inside the game during play, but not for users to re-package as goods distributed or sold inside a virtual world;\u003cbr\u003e\n (3) as Product published within a book, poster, t-shirt or other item;\u003cbr\u003e\n (4) as part of a physical object such as a toy, doll, or model.\n\u003c/p\u003e\n\n\u003cp\u003e2.3. If you use any Product in software products (such as video games, simulations, or VR-worlds) you must take all reasonable measures to prevent the end user from gaining access to the Product. Methods of safeguarding the Product include but are not limited to:\u003c/p\u003e\n\u003cp\u003e(1) using a proprietary disc format such as Xbox 360, Playstation 3, etc.;\u003c/p\u003e\n\u003cp\u003e(2) using a proprietary Product format;\u003c/p\u003e\n\u003cp\u003e(3) using a proprietary and/or password protected database or resource file that stores the Product data;\u003c/p\u003e\n\u003cp\u003e(4) encrypting the Product data.\u003c/p\u003e\n\n\u003cp\u003e2.4. Without prejudice to subparagraphs 2.1-2.3 of this paragraph, the Seller grants to the Buyer who purchases license rights to Product and uses it solely as Incorporated Product a non-exclusive, worldwide, license in any medium now known or hereinafter invented to:\u003c/p\u003e\n\u003cp\u003e(1) reproduce, post, promote, license, sell, publicly perform, publicly display, digitally perform, or transmit for promotional and commercial purposes;\u003c/p\u003e\n\u003cp\u003e(2) use any trademarks, service marks or trade names incorporated in the Product in connection with Seller material; \u003c/p\u003e\n\u003cp\u003e(3) use the name and likeness of any individuals represented in the Product only in connection with Your material. \u003c/p\u003e\n\n\u003cp\u003e2.5. Absent a written grant of rights greater than that contained in paragraph 2 âRoyalty free licenseâ, all other rights or sub-divisions of rights generally included in copyright are excluded from this license and remain the property of Seller.\u003c/p\u003e\n\n\u003cp\u003e2.6. The resale or redistribution by the Buyer of any Product, obtained from the Site is expressly prohibited unless it is an Incorporated Product as licensed above.\u003c/p\u003e\n","summary":{"custom_html":"Content published with the %{link} label shall be deemed applicable if and only if the Seller provides additional license terms on the content.","editorial_html":"Content published with the %{link} label may only be used in an editorial manner and may not be used for any commercial, promotional, advertising or merchandising use.","royalty_free_html":"Content published with the %{link} label may not be sold, given, or assigned to another person or entity in the form it is downloaded from the site."}},"licenses_new":{"custom_html":"\u003cp\u003e Custom License allows uses of the product as specified by designer. Such additional license terms shall be applied and interpreted as additions and (or) exceptions to the conditions set by general licensing terms and Royalty Free License. The product published with the Custom License label shall be deemed applicable if and only if the Seller provides additional license terms on the content.\u003c/p\u003e\n\u003cp\u003eHere are additional conditions set by the Seller for model %{model_title}:\u003c/p\u003e\n%{content}\n\u003cp\u003eRefer to legally binding \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' target='_blank'\u003eGeneral Terms and Conditions\u003c/a\u003e to learn more about conditions regarding extracting product from end product created, which applies to all models under any license.\u003c/p\u003e\n","custom_no_ai_html":"\u003cp\u003e Custom License allows uses of the product as specified by designer. Such additional license terms shall be applied and interpreted as additions and (or) exceptions to the conditions set by general licensing terms and Royalty Free License. The product published with the Custom License label shall be deemed applicable if and only if the Seller provides additional license terms on the content. Licenses marked with \"no AI\" tag do not permit Product use for machine learning or training of neural network models, including generative AI models.\u003c/p\u003e\n\u003cp\u003eHere are additional conditions set by the Seller for model %{model_title}:\u003c/p\u003e\n%{content}\n\u003cp\u003eRefer to legally binding \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' target='_blank'\u003eGeneral Terms and Conditions\u003c/a\u003e to learn more about conditions regarding extracting product from end product created, which applies to all models under any license.\u003c/p\u003e\n","editorial_no_ai_html":"\u003cp\u003eEditorial license gives a permission to use the product only in an editorial manner, relating to events that are newsworthy, or of public interest, and may not be used for any commercial, promotional, advertising or merchandising use. Licenses marked with \"no AI\" tag do not permit Product use for machine learning or training of neural network models, including generative AI models.\u003c/p\u003e\n\u003cp\u003eIn a few instances, you may otherwise have the rights to IP in content that is under Editorial license. For instance, you may be the advertising agency for a brand/IP owner or you may be the brand/IP owner itself purchasing user generated content. Given you have the rights clearance through other means, you may use the content under Editorial License commercially. Every user failing to comply with Editorial Use restrictions takes the responsibility to prove the ownership of IP rights.\u003c/p\u003e\n\u003cp\u003eFor users, who are not brand/IP owners or official affiliates, the restrictions of Editorial
16518-licensed content usage include, but are not limited to, the following cases:\u003c/p\u003e\n\u003cul\u003e\n \u003cli\u003eProducts may not be used on any item/product created for resale such as, commercials, for-profit animations, video games, VR/AR applications, or physical products such as a merchandise or t-shirt.\u003c/li\u003e\n \u003cli\u003eProducts may not be used as part of own product promotional materials, billboard, trade show or exhibit display.\u003c/li\u003e\n \u003cli\u003eThe product may not be incorporated into a logo, trademark or service mark. As an example, you cannot use Editorial content to create a logo design.\u003c/li\u003e\n \u003cli\u003eProducts may not be used in any insulting, abusive or otherwise unlawful manner.\u003c/li\u003e\n \u003cli\u003eThe product may not be used for any commercial related purpose.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eRead more about \u003ca href='/pages/terms-and-conditions#editorial-license' target='_blank'\u003eEditorial License\u003c/a\u003e and product usage allowed by different licenses in our legally binding \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' target='_blank'\u003eGeneral Terms and Conditions\u003c/a\u003e.\u003c/p\u003e\n","editorial_royalty_free_html":"\u003cp\u003eRoyalty Free License allows you to use the product without the need to pay earnings or other license fees for multiple uses, per volume sold, or some time period of use or sales. Products published with this license may not be sold, given, or assigned to another person or entity in the form it is downloaded from the site, but can be used in your commercial projects multiple times after paying for it just once.\u003c/p\u003e\n\u003cp\u003eThis is, however, a non-exclusive license and the product remains the property of a seller for further distribution. Please, refer to legally binding \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' target='_blank'\u003eGeneral Terms and Conditions\u003c/a\u003e to learn more about \u003ca href=/pages/terms-and-conditions#royalty-free-license target='_blank'\u003eRoyalty Free License\u003c/a\u003e, other types of licenses and general rules applicable to all products.\u003c/p\u003e\n","royalty_free_html":"\u003cp\u003eRoyalty Free License allows you to use the product without the need to pay earnings or other license fees for multiple uses, per volume sold, or some time period of use or sales. You can use it as long as it is incorporated into the product and the 3rd party cannot retrieve it individually in either the digital or physical form. You cannot resell the model you bought in the digital or printed form, but can use it in your commercial projects multiple times after paying for it just once.\u003c/p\u003e\n\u003cp\u003eThis is, however, a non-exclusive license and the product remains the property of a seller for further distribution. Please, refer to legally binding \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' target='_blank'\u003eGeneral Terms and Conditions\u003c/a\u003e to learn more about \u003ca href=/pages/terms-and-conditions#royalty-free-license target='_blank'\u003eRoyalty Free License\u003c/a\u003e, other types of licenses and general rules applicable to all products.\u003c/p\u003e\n","royalty_free_no_ai_html":"\u003cp\u003eRoyalty Free License allows you to use the product without the need to pay earnings or other license fees for multiple uses, per volume sold, or some time period of use or sales. You can use it as long as it is incorporated into the product and the 3rd party cannot retrieve it individually in either the digital or physical form. You cannot resell the model you bought in the digital or printed form, but can use it in your commercial projects multiple times after paying for it just once. Licenses marked with \"no AI\" tag do not permit Product use for machine learning or training of neural network models, including generative AI models.\u003c/p\u003e\n\u003cp\u003eThis is, however, a non-exclusive license and the product remains the property of a seller for further distribution. Please, refer to legally binding \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' target='_blank'\u003eGeneral Terms and Conditions\u003c/a\u003e to learn more about \u
16518003ca href=/pages/terms-and-conditions#royalty-free-license target='_blank'\u003eRoyalty Free License No AI\u003c/a\u003e, other types of licenses and general rules applicable to all products.\u003c/p\u003e\n","summary":{"custom_html":"Content published with the %{link} label shall be deemed applicable if and only if the Seller provides additional license terms on the content.","editorial_html":"Content published with the %{link} label may only be used in an editorial manner and may not be used for any commercial, promotional, advertising or merchandising use.","editorial_royalty_free_html":"Content published with the %{link} label may not be sold, given, or assigned to another person or entity in the form it is downloaded from the site.","royalty_free_html":"Content published with the %{link} label may not be sold, given, or assigned to another person or entity in the form it is downloaded from the site."},"tooltips":{"custom_html":"Custom License allows uses of the product as specified by designer. Such additional license\u003cbr/\u003e terms shall be applied and interpreted as additions and (or) exceptions to the conditions set\u003cbr/\u003e by general licensing terms and Royalty Free License.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n","custom_no_ai_html":"Custom License allows uses of the product as specified by designer. Such additional license\u003cbr/\u003e terms shall be applied and interpreted as additions and (or) exceptions to the conditions set\u003cbr/\u003e by general licensing terms and Royalty Free License.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n","editorial_html":"The product can only be used in an editorial manner (educational, non-commercializable\u003cbr/\u003e personal project, in newsworthy and of public interest events) and may not be used for any\u003cbr/\u003e commercial, promotional, or merchandising purposes.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n","editorial_no_ai_html":"The product can only be used in an editorial manner (educational, non-commercializable\u003cbr/\u003e personal project, in newsworthy and of public interest events) and may not be used for any\u003cbr/\u003e commercial, promotional, or merchandising purposes.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n","editorial_royalty_free_html":"Products under Royalty Free License can be used without liability to pay any license fees for\u003cbr/\u003e multiple lifelong uses, or sales volume of final product after being paid for once. The product\u003cbr/\u003e may not be sold, given, or assigned to another person or entity in the form it is downloaded from the site.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n","royalty_free_html":"Products under Royalty Free License can be used without liability to pay any license fees for\u003cbr/\u003e multiple lifelong uses, or sales volume of final product after being paid for once. You can use it as\u003cbr/\u003e long as it is incorporated into the product and the 3rd party cannot retrieve it\u003cbr/\u003e individually in either the digital or physical form.\u003cbr/\u003e You cannot resell the model you bought in the digital or printed form.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n","royalty_free_no_ai_html":"Products under Royalty Free License can be used without liability to pay any license fees for\u003cbr/\u003e multiple lifelong uses, or sales volume of final product after being paid for once. You can use it as\u003cbr/\u003e long as it is incorporated into the product and the 3rd party cannot retrieve it\u003cbr/\u003e individually in either the digital or physical form.\u003cbr/\u003e You cannot resell the model you bought in the digital or printed form.\u003cbr/\u003e \u003ca href='/pages/terms-and-conditions#general-terms-of-licensing' rel='nofollow' target='_blank'\u003eRead more\u003c/a\u003e\n"}},"likes":{"like_failure":"You can like up to 20 models or galleries per day. Please come back tomorrow to continue choosing your favorites."},"mailers":{"static_message_body":"Please log in to your account to see the full message."},"meta":{"description":{"boards#index":"Connect with fellow 3D designers on CGTrader forum. Share your 3D models, design knowledge and improve your assets in forum dedicated for 3D experts.\n","boards#show":"Visit %{board_title} board on CGTrader forum. Share your design knowledge and improve your assets in forum dedicated for 3D experts.\n","challenges#index":"Join CGTrader 3D model and 3D print challenges. Take part in creative 3D contests, showcase your skills, win prizes, and get recognition in the global 3D community.","events#index":"Meet us at these industry events near you. Here's your opportunity to discu
16518ss your 3D modelling and AR/VR needs with our seasoned pros.\n","events#show":"%{event_description}\n","faq#show":"Find answers to the most frequently asked questions on CGTraderâs site. From buying to selling 3D models, information about CGTrader 3D community and more.\n","faq#show_page":"Find answers to the most frequently asked questions on CGTraderâs site. From buying to selling 3D models, information about CGTrader 3D community and more. %{page_number}\n","galleries#author":"Browse through 3D art portfolio by %{username}, see digital modeling creations the designer made, donât hesitate to share your thoughts about authorâs artwork.\n","galleries#category":"Browse through 3D art in %{category_name} category, post and showcase your works, enrich your portfolio, get valuable feedback and inspire fellow 3D designers.\n","galleries#index":"Browse through some of the best 3D art, post and showcase your design works, enrich your portfolio, get valuable feedback and inspire fellow 3D designers.\n","galleries#show":"Take a look at %{project_name} - digital artwork made by %{username}. Find more 3D galleries and designer portfolios on CGTrader.\n","galleries#tag":"Browse through all 3D or 2D work related to by %{tag}, see digital modeling creations and donât hesitate to share your thoughts about the artwork.\n","items#top_items":"Browse through the currently trending 3D models that CGTrader marketplace has to offer. Find 3D assets for your VR project, video game or architectural design.\n","items#top_print_items":"Browse through the currently trending 3D models for printing that CGTrader marketplace has to offer. Find 3D printable models and make them into real objects.\n","jobs#index":"Find %{filter} jobs currently available on 3D Projects platform. Search jobs by 3D software, modeling type and more.\n","posts#3d-printing-inspiration":"CGTraderâs 3D Printing inspiration provides best 3D printing examples, trending works, coolest gadgets in the industry and other must-see 3D printing content.\n","posts#cg-inspiration":"CGTraderâs CG inspiration provides best 3D modelling examples, realistic 3D renders, expert design works and other great CG examples for fellow 3D designers.\n","posts#cgtrader-news":"Find all CGTrader-related content here. New features and partnership, important notes, latest 3D infographics, and what you need to know about CGTrader.\n","posts#challenges":"Find latest news about 3D modelling, PBR and design challenges going on in CGTrader. Win 3D modeling software and other prizes given away for every challenge.\n","posts#designer-sportlight":"Find interesting, newest and influential 3D designers talking about 3D modeling profession, coming up in 3D industry and difficulties they had to overcome.\n","posts#guest-posting-guidelines":"CGTrader, the leading 3D stock model marketplace, accepts guest posts from qualified industry professionals. Pitch us your written articles, infographics, interviews or opinion pieces and approach one of the largest digital design communities in the world.\n","posts#index":"Read the 3D news, insights and updates into CGTrader marketplace, 3D designer interviews, best industry tutorials - all things regarding 3D modeling.\n","posts#interviews":"Read CGTrader interviews with 3D, 2D, Low-poly and VR modeling experts, industry influencers, software makers and find trending 3D industry news here.\n","posts#tag":"Read CGTraderâs news and posts about %{tag_name} â find more about CGTrader marketplace news, 3D designer interviews or best industry tutorials in CGTrader blog.\n","posts#tutorials-tips-and-tricks":"Learn 3D modeling from industry professionals. Find tutorial lists, tips \u0026 tricks about 3D software, and upgrade your 3D modeling skills to the next level.\n","posts#whats-hot":"Read trending 3D news, interviews with up-and-coming designers and other newest insights into 3D modeling community, 3D industry and CGTrader marketplace.\n","registrations#new":"Join CGTrader â leading 3D model marketplace with over %{model_count} models available, participate in strong 3D designer community and share your 3D knowledge.\n","reputation#index":"Learn about CGTrader reputation system for a fair \u0026 transparent payments, find out how to climb the reputation ladder and make the most of you 3D modeling.\n","scholarship#annual":"Write an essay on a specific 3D, VR or technology based topic, enter the annual CGTrader Scholarship challenge and get funded for your education bills.\n","scholarship#new":"Enter the CGTrader Scholarship 2016 challenge to win $1,000 for your education bills.\n","sessions#new":"Sign in to CGTrader, upload and share your works or purchase 3D models available on the 3D model marketplace and get involved with 3D designer community.\n","topics#show":"%{title} - join CGTrader's forum and discuss 3D model related topics. Get modelling feedback from 3D experts.\n","tutorials#index":"Watch and learn from the best 3D designers out there. Find more about 3D modeling, sculpting, texturing, baking with 3D tutorials available on CGTrader.\n","tutorials#show":"Watch the 3D Tutorial called %{title} created by %{username}. Learn from 3D designers with CGTrader tutorials.\n"},"title":{"events#index":"Meet us in person at the next event near you!","events#show":"Join us at %{event_title}"}},"modals":{"request_to_buy_gallery":{"subtitle":"Are you interested in buying 3D model used in this project? Add your proposal for the author below.","title":"Request to Buy it as 3D model"}},"model":{"already_purchased":"You have already purchased this product. You can download from your \u003ca href='/profile/cart/purchased'\u003eshopping cart\u003c/a\u003e. If you wish, you can purchase it again.","animated":"Animated","artist_profile":"Artist Profile","attributes":{"animated":"Animated","game_ready":"Low-poly","pbr":"PBR","rigged":"Rigged"},"author":"Author","author_get_your_payment":"Author will get 100% of your payment. CGTrader enables artists to earn maximum earnings and motivates to sell high quality content.","author_products":"More products by \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e","authorised_seller":"CGTrader's Authorised Seller","authority":"Authority","breadcrumb":{"3d_models":"3D models","home":"Home"},"bulk_download":{"download_all":"Download all files","files_included":{"one":"%{count} file included","other":"%{count} files included"},"too_large":"This model is too large to download as one archive (over %{limit}). Please download the files individually."},"buy":"Buy","cannot_download":"Only users with %{experience_needed} reputation points can download more than %{models} free models. Learn more about levels and reputation by \u003ca href='%{reputation_url}' target='_blank'\u003eclicking here\u003c/a\u003e.","collection":"Pack","comments":{"comment_posted":"Comment has been successfully posted","comment_reported":"Comment has been successfully reported","leave_comment":"Leave a comment","no_comments":"There are no comments for this item yet.","parent_not_exists":"Parent comment not exists","please_enter_comment":"Please enter your comment","posted_by":"Posted by \u003ca href='%{author_profile_url}' target='_blank'\u003e%{author}\u003c/a\u003e \u003cspan class='comment-time'\u003e%{time}\u003c/a\u003e","really_want_report":"Do you really want to report this comment?","reply":"Reply","report":"Report","submit":"Post Comment","title":"Comments","you_must_login":"You must \u003ca href='javascript:;' class='user-form-trigger login'\u003eLog In\u003c/a\u003e to join the conversation."},"contact_author":"Contact Author","customer_support":{"content":"This author is certified CGTrader seller that meets requirements of excellent product quality and customer support. We guarantee you will get the first class technical support from the author and CGTrader team. If the product is unacceptable for your needs or you have other issues, please contact us for assistance.","sub_title":"CGTrader and author support","title":"Customer Support"},"description":"Description","download":"Download","download_limit_exceeded":"You have exceeded your daily download limit. Please try again tomorrow. This limit does not apply to users who have made a purchase in the last 12 months.","download_modal":{"chat_with_us":"Chat with us","contact_support":"Please contact us via chat.","download_file":"Download %{name}","empty":"No files have been found","generic_error":"Something went wrong, please try again","link_error":"We apologize, but there seems to be a minor issue with your download link.","pbr_ready":"PBR-ready","preparing":"Preparing your download...","title":"Download Files"},"format_downloads":"3D Software Format Downloads","game_ready":"Game-ready (lowpoly)","geometry":"Geometry","geometry_types":{"gaussian_splats":"Point-based (Gaussian Splats)","nurbs":"Nurbs","other":"Other","polygon_mesh":"Polygon mesh","subdivision_ready":"Subdivision ready"},"license":"License","low_poly":"Low poly","lowest_price":{"content":"In other words, the author guarantees that the price of this 3D model is %{discount}% lower on CGTrader.com than on any other 3D store, except at authors personal website.","sub_title":"%{discount}% cheaper than anywhere else","title":"Lowest Price Guarantee"},"make_offer":"Make Offer","materials":"Materials","messages":{"no_files":"No uploaded files","no_rating":"No rating available for this model yet"},"model_details":"3D Model Details","offers":{"default_offer_message":"Hi, I would like to make an offer for this model.","make_offer_tooltip":"Send your price offer to the author if you want to buy it at lower price. When author accepts it, you will be notified to your Inbox and email.","make_offer_tooltip_title":"Buy this model at lower price."},"order":{"cant_buy_own_item":"You can't buy your own product","offer_is_not_accepted":"Offer is not accepted"},"pbr_textures":"PBR Textures","plugin_used":"Plugin Used","polygons":"Polygons","price":"Price","print_ready":"3D Print-ready","product_id":"Product ID","product_support":"Product Support","product_type":"Product Type","published":"Published on","quality_guarantee":{"content":"CGTrader guarantees to refund the money for all products purchased from this seller. If you found defects that are not listed in the product description or the product is not suitable for your needs, please contact us within 7 days from purchasing.","sub_title":"Money back guarantee","t
16518itle":"Quality Guarantee"},"rated":{"error":"You have already rated this model","success":"Thank you for rating this model"},"rating":"3D Model Rating","ratings":{"desc":{"negative":"Users who bought this 3D model thought it's of lower quality than expected","positive":"Users who bought this 3D model thought it's of good quality"},"negative":"negative","positive":"positive"},"recently_viewed_models":"Recently viewed models","renderer":"Renderer","report":"Report","report_form":{"cancel":"Cancel","comment":"Comment","messages":{"fill_field":"Please enter comment and/or link","reported":"Product has been successfully reported","success":"Thank you. Your report has been sent."},"optional":"(Optional)","submit":"Submit","url":"Original model"},"rigged":"Rigged","scanned":"Scanned","scripts-plugins":"Scripts \u0026 Plugins","similar_models":"Similar Models","statistics":"Statistics","subscription":{"limit_reached":"You have reached the limit of downloads for this billing period.","limit_reached_detailed":"You've reached your %{limit} download limit for this month. Your limit resets on %{reset_date}. To download more models now, you can purchase them individually.","limit_reached_detailed_no_date":"You've reached your %{limit} download limit for this month. To download more models now, you can purchase them individually."},"support_form":{"cancel":"Cancel","enter_message":"Please fill message field","item_id":"3D Model ID:","message":"Message","message_sent":"Message has been successfully sent","submit":"Send"},"tags":"Tags","textures":"Textures","title":"%{item_title} 3D model","unwrapped_uvs":"Unwrapped UVs","unwrapped_uvs_options":{"mixed":"Mixed","no":"No","non_overlapping":"Non-overlapping","overlapping":"Overlapping","unknown":"Unknown"},"uv_mapping":"UV mapping","vat_notice":"All prices are exclusive of VAT","version":"Version","vertices":"Vertices","vr":"VR models","vr_badges":{"animated":"Animated","game_ready":"Lowpoly","pbr":"PBR","rigged":"Rigged"}},"models":{"error":{"cannot_be_blank":" cannot be blank."},"item":{"unwrapped_uvs":{"mixed":"Mixed","no":"No","non_overlapping":"Non-overlapping","overlapping":"Overlapping","unknown":"Unknown"}}},"navigation":{"3d-models":{"3d-printing":"3D Print Files","discounts":"Discounts","find_designers":"Best designers","free":"Free","pbr":"PBR","scanned_3d-models":"Scanned 3D Models","scripts_apps":"Scripts \u0026 Apps","show-all":"Show all","textures":"CG Textures","title":"3D Models","vr_low-poly":"Low-poly"},"already_added_message":"has already been added to the cart","already_purchased_message":"You have already purchased this item.","aria":{"account":"Account","cart":"Cart","close_menu":"Close menu","logo":"CGTrader - 3D Models / 3D Designers","messages":"Messages","notifications":"Notifications","open_menu":"Open menu","search":"Search","search_by_image":"Search by image"},"budgets":{"below_10":"Under $10","collections":"Packs","free":"Free","more_than_20":"More than $20","more_than_50":"More than $50","sale":"On Sale","subscription":"Subscription","up_to_10":"Up to $10"},"cart_limit_reached":"You've reached the 500-item limit in your cart. To continue shopping, please complete your current order and start a new one for any additional items.","cart_widget":{"continue_shopping":"Continue shopping","discount":"Discount with enterprise coupon: ","discount_applied":"Discounts applied:","final":"Final price: ","have":"You have ","items":" items in your shopping cart.","left_to_unlock_discounts":"{{leftToUnlock}} Left to unlock discounts","potential_discount":"Potential discount:","proceed":"Proceed to Checkout","recently_viewed_empty_text":"Start exploring and your recently viewed items will appear here.","recently_viewed_empty_title":"Nothing here yet","recently_viewed_tab":"Recently viewed","remainer":"To activate CGTrader Points add: ","sale_discounts":"Discounts applied: ","sale_time_left":"Sale ends in","sale_tooltip":"Discounts from our Sale-Off campaigns are only applied when your cart reaches ${{threshold}} or more.","sale_tooltip_text":"This item is on sale, but the discount will only be applied once your cart subtotal reaches ${{threshold}} or more.","text":"Your shopping cart is empty.","title":"Shopping Cart","total":"Total: ","used":"CGTrader Points used: ","view":" View cart","wishlist_empty_text":"Start exploring and save your favorites for later â theyâll show up here.","wishlist_empty_title":"Your wishlist is empty","wishlist_tab":"Wishlist items"},"community":{"awards":"Designer Awards ð","blog":"Blog","challenges":"Challenges","community_ratings":"Community ratings","de
16518signers":"3D Designers","digital_art":"Digital Art Competition","forum":"Forum","galleries":"Galleries","invite":"Invite a friend","printlist":"3D PrintList","sell_3d-models":"Sell 3D Models","title":"Community","tutorials":"Tutorials"},"conversations_widget":{"conversations":"Conversations","messages":{"loading":"Loading inbox"},"types":{"cgtrader_support":"CGTrader Support","file_conversion_request":"File conversion request","job_application":"3D Project","model_feedback":"Product Feedback","model_support":"Model Support","offer":"Price Offer","personal":"Personal Message","promotions":"Promotions"}},"create_ai":{"community_gallery":"Community Gallery","free_trial":"Free trial","generate_3d_model":"Generate 3D Model","generation":{"dismiss":"Dismiss notification","error_title":"Generation issue","generating_title":"Your 3D model is being generated","open_model":"Open Model","ready_title":"Your 3D model is ready!"}},"create_with_ai":"Create with AI","credits_guest_widget":{"create":"Create an account now!","discount":" discount","for":" for your ","get":" and get up to ","learn_more":"Learn more about CGTrader Points ","link":"here","purchase":"first purchase!","sign-up":"Sign up","text_below_1":"Points can be used when purchasing \"","text_below_2":"\" sign marked models and cover up to 30% discount of the price."},"credits_user_widget":{"condition_1":"CGTrader Points can be applied toward the purchase of models marked with the \u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e sign, providing up to a 30% discount off their price.","condition_2":"Points can only be used if your cart's total value is \u003cstrong\u003e$%{minimum}\u003c/strong\u003e or more.","condition_3":"During active sales or promotions, points cannot be used.","condition_4":"\u003cstrong\u003eKeep in mind\u003c/strong\u003e that points have an expiration date - your points will expire in \u003cstrong\u003e%{days}\u003c/strong\u003e days.","earn_rate":"Points earn rate ","first_text_1":"Consider it a gift for your first purchase - you can use points when purchasing \" ","first_text_2":" \" marked models and get up to 30% discount of it's price. Points can only be used if the total value of your cart is equal to or greater than","learn_more":"Learn more","lifetime_spending":"Lifetime spending: ","list_item":"By increasing your lifetime spending on CGTrader, your Points earn rate increases as well.","more_credits":"How do I get more points?","next_level":"Next level: ","notice":"\u003cstrong\u003eNOTE:\u003c/strong\u003e CGTrader Points cannot be used during the ongoing sale, but they will be available again once the sale ends. In the meantime, check out great deals on 3D models \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003ehere\u003c/a\u003e","par_1":"You have ","par_2":" CGTrader points.","par_2_variation":" in Points that you can spend when no sale off is available.","regular_text_1":"Points can be used when purchasing \" ","regular_text_2":" \" sign marked models and cover up to 30% discount of it's price.","title":"CGTrader Points"},"enterprise":{"management":"3D Asset Management","title":"3D Content Production"},"hire_a_freelancer":"Hire a Freelancer","item_add_message":"has successfully been added to the cart","item_restricted_message":"This item can't be bought due to sanctions placed on designers country(RU/BY).","navbar":{"3d_models":{"about":"About 3D Models","about_print":"About 3D Printing","all_models":"All models","browse_all":"All 3D Models","browse_all_print":"All 3D Printing","budget":"Budget","categories":"Categories","types":"Types"},"actions":{"new":"New","top_selling":"Top Selling","trending":"Trending"},"budgets":{"below_10":"Under $10","free":"Free","more_than_20":"More than $20","more_than_50":"More than $50","sale":"On Sale","up_to_10":"Up to $10"}},"projects":{"3d_customs":"Custom 3D","3d_printing":"3D Printing","about":"About 3D Projects","browse":"Browse Projects","buyer_perspective":"Hire 3D Designers","for_designers":"For Designers","my_projects":"My Projects","seller_perspective":"Freelance 3D Projects","start":"Start a Project","work":"Work with CGTrader"},"sell_3d-models":"Sell 3D Models","sellers_hub":"Sellers Hub","subscription_includes_item_message":"This item is already included in your subscription.","tooltips":{"cart":"Shopping Cart","conversations":"My Conversations","discounts":"CGTrader Points","notifications":"Notifications","publisher":"Publisher"},"user":{"ban_notification":"This user account is suspended. Please contact our support for explanation.","cannot_refer_yourself":"cannot refer yourself","email_confirmation":"Your email address has been verified.","email_reconfirmation":"was already confirmed, please try signing in","ends_at":"Ends at: %{date}","handle_error_tfa_code_missmatch":"Security code you entered is incorrect. Please try again.","handle_error_tfa_code_missmatch_last":"Your security code has expired. If you want to continue, click resend email and enter the new provided code.","handle_error_tfa_default":"Something went wrong, please try again later.","handle_error_tfa_expired":"Your security code has expired.","hundred_percent_royalties_popover":"You are taking part in a temporary 100% earnings campaign: all the sales proceeds from new models will go to you until the campaign's end","invali
16518d_email_message":"Please enter a valid e-mail address to continue.","login":"Log in","meta_description":"Take a look at %{username} CGTrader 3D designer profile, portfolio and 3D models available. Check out best 3D models from top modeling artists in 3D industry.","meta_title_suffix":"3D Designer","not_valid_birthday":"Birthday is not valid.","offline":"Offline","online":"Online","page_title":"Designer profile","rate_models_limit":"You cannot rate more models today.","semantic_description":"Designer's 3D models, artworks and portfolio. Take a look at his creations on CGTrader","semantic_title":"Designer Profile","session_failure":"Wrong username/e-mail or password has been provided","session_password_expired":"Your password has expired due to inactivity. Please reset your password via the email link weâve sent.","session_two_fa_failure":"Code verification has failed","session_unconfirmed":"Your email address has not been confirmed yet.","token_not_recognized":"Token was not recognized","twitter_shareable_text":"A #3dartist worth following","username_error":"should not contain spaces or non-latin symbols"},"user_menu":{"buyer":{"freelancers":"Find Freelancers","purchases":"My Purchases","sell":"Sell 3D Models","wishlist":"3D Model Wishlist"},"dashboard":"Admin Dashboard","logout":"Log out","public_profile":"Public Profile","seller":{"analytics":"Analytics","find_new_projects":"Find New 3D Projects","freelance":"My 3D Projects","freelance_cgtrader":"Freelance with CGTrader","models":"My models","publish_project":"Post a Project","publishing":"Upload 3D Model","sales":"My sales","subscription":"Subscription","wishlist":"3D Model Wishlist"},"settings":"Account Settings"}},"notification":{"events":{"category":{"Notification::Forum::PostCreatedTemplate":"Forum","Notification::ItemPriceOfferBuyerNegotiatesTemplate":"3D Projects","Notification::ItemPriceOfferDesignerAcceptsTemplate":"3D Projects","Notification::ItemPriceOfferDesignerNegotiatesTemplate":"3D Projects","Notification::ItemUseCaseAcceptedTemplate":"Feedback","Notification::ItemUseCaseRejectedTemplate":"Feedback","Notification::ItemUseCaseSubmittedTemplate":"Feedback","Notification::Job::ApplicationChangesAcceptedTemplate":"3D Projects","Notification::Job::ApplicationCreatedTemplate":"3D Projects","Notification::Job::ApplicationUpdatedTemplate":"3D Projects","Notification::Job::ApplicationWithdrawnTemplate":"3D Projects","Notification::JobCanceledTemplate":"3D Projects","Notification::JobCustomJobRequestedTemplate":"3D Projects","Notification::JobExpiredTemplate":"3D Projects","Notification::JobFinishedTemplate":"3D Projects","Notification::JobPaidTemplate":"3D Projects","Notification::JobRepostedTemplate":"3D Projects","Notification::JobTemplateCreatedTemplate":"3D Projects","Notification::JobTemplateReviewedTemplate":"3D Projects","Notification::JobUpdatedTemplate":"3D Projects","Notification::JobWillExpireTemplate":"3D Projects","Notification::ModelAdultBlockedTemplate":"Feedback","Notification::ModelBlockedTemplate":"Feedback","Notification::ModelFilesUpdatedTemplate":"Purchases","Notification::PublicActivity::ActivityAnnouncementTemplate":"Community","Notification::ReputationLogAdditionalItemOfReferralTemplate":"Referral","Notification::ReputationLogAdditionalPurchaseOfReferralTemplate":"Referral","Notification::ReputationLogAnswerToUserTopicTemplate":"Forum","Notification::ReputationLogCommentVoteTemplate":"Forum","Notification::ReputationLogDownloadedFreeTemplate":"Downloads","Notification::ReputationLogFirstItemOfReferralTemplate":"Referral","Notification::ReputationLogFirstPurchaseOfReferralTemplate":"Referral","Notification::ReputationLogForumTopicAnswerTemplate":"Forum","Notification::ReputationLogMyLikeTemplate":"My activity","Notification::ReputationLogNegativeItemRatingTemplate":"Feedback","Notification::ReputationLogNewCommentTemplate":"Feedback","Notification::ReputationLogNewFollowerTemplate":"Following","Notification::ReputationLogNewForumTopicTemplate":"My activity","Notification::ReputationLogNewItemTemplate":"My activity","Notification::ReputationLogNewLikeTemplate":"Feedback","Notification::ReputationLogNewProjectTemplate":"My activity","Notification::ReputationLogPositiveForumTopicVoteTemplate":"Forum","Notification::ReputationLogPositiveItemRatingTemplate":"Feedback","Notification::ReputationLogReferralUserRegistrationTemplate":"Referral","Notification::ReputationLogSaleTemplate":"Sales","Notification::ReputationLogTutorialTemplate":"My activity","Notification::ReputationLogTutorialVoteTemplate":"Feedback","Notification::TagPromotionApprovedTemplate":"Feedback","Notification::TagPromotionDeclinedTemplate":"Feedback","Notification::TagPromotionExpiredTemplate":"Feedback"},"errors":{"user_and_event_triggered_are_not_same":"User who triggered the event cannot be the same as the event's user."}}},"number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","significant":false,"strip_insignificant_zeros":false,"unit":"$"}},"format":{"delimiter":",","precision":3,"round_mode":"default","separator":".","significant":false,"strip_insignificant_zeros":false},"human":{"decimal_units":{"format":"%n%u","units":{"billion":"b","million":"m","quadrillion":"q","thous
16518and":"k","trillion":"t","unit":""}},"format":{"delimiter":"","precision":3,"significant":true,"strip_insignificant_zeros":true},"storage_units":{"format":"%n %u","units":{"byte":{"one":"Byte","other":"Bytes"},"eb":"EB","gb":"GB","kb":"KB","mb":"MB","pb":"PB","tb":"TB"}}},"nth":{"ordinalized":{},"ordinals":{}},"percentage":{"format":{"delimiter":"","format":"%n%"}},"precision":{"format":{"delimiter":""}}},"orders":{"errors":{"download_link_expired":{"guest":"Your download link has expired. Please confirm your email and finish registration to download your product. You should have your confirmation link in your inbox or you can ask to resend it in this page.\n","user":"Your download link has expired. Please Sign in to download your product."}}},"owly":{"failed_set_pending":"Failed to set pending.","failed_to_approve":"Failed to approve.","failed_to_suspend":"Failed to suspend.","failed_to_update_license":"Failed to update license.","failed_to_update_status":"Failed to update approve status."},"payments":{"agreement":{"address":"Street Address / ZIP","attachments":"Files uploaded","bank_account":"Bank account (IBAN)","bank_name":"Bank name","city":"City","company_address":"Street Address / ZIP","company_city":"City","company_code":"Company code","company_country":"Country","company_name":"Company name","country":"Country","datebirth":"Date of Birth","name":"Name","paypal_address":"PayPal email address","person_id":"Personal Identification Number","surname":"Surname","swift":"SWIFT (BIC)","tooltips":{"company_registration_number":"The business registration number is a unique number given to a company when it is incorporated, formed or registered with the state, province or country. The number will appear on any registration or corporate documents. It may also be referred to as the Company Number or Entity Number.","company_vat":"If the business is registered for VAT (Value Added Tax) in the European Union (EU), please indicate your VAT Identification (registration) number here.","email":"This email address will be used for activation of Hyperwallet Pay portal and sending payout and other notifications from Hyperwallet, which is a payout service provider for CGTrader.","legal_name":"The name should match the official business name in its incorporation documents.","minimum_available_balance":"For example, if you wish to get paid only if your balance is greater than $100 please enter this amount in the field above.","payout_option":"Sellers getting paid to Payoneer may choose payout frequency.","person_id":"Personal Identification Number (national ID, personal code, social security number, etc.) is assigned to you by the state and used for identification purposes. The number should be printed on your national identification document that you will have to upload. If you havenât got a Personal Identification Number please use the number of your national identification document (passport, ID-card, etc.).","tax_residence_country":"Country of tax residence is the country to which you are responsible for paying taxes.","vat":"If you are registered for VAT (Value Added Tax) in the European Union (EU), please indicate your VAT Identification (registration) number here."},"vat":"VAT Identification Number","vat_id":"VAT identifier","webmoney_wallet":"WebMoney purse (WMZ)"}},"payoneer":{"service_unavailable":"Payoneer service is temporarily unavailable, please try again later or contact \u003ca href='mailto:[email protected]'\[email protected]\u003c/a\u003e for more information.\n","status_message":{"approved":"Your account was successfully approved by Payoneer","declined":"Payoneer application has been declined. Please choose another payment method or contact \u003ca href='https://payoneer.custhelp.com/' target='_blank'\u003ePayoneer\u003c/a\u003e for further information.\n","registered":"Thank you for submitting your information. You'll be contacted by Payoneer team when your account is activated.\n"}},"price_offers":{"status":{"accepted":"Accepted","buyer_offer":"Buyer proposed an offer","declined":"Declined","in_progress":"In Progress","seller_offer":"Seller responded","withdrawn":"Withdrawn"},"status_for_buyer":{"accepted":"Approved","buyer_offer":"Waiting for answer","declined":"Declined","in_progress":"Waiting for answer","seller_offer":"Waiting for your approval","withdrawn":"Withdrawn"},"status_for_seller":{"accepted":"Approved","buyer_offer":"Waiting for your approval","declined":"Declined","in_progress":"Waiting for your approval","seller_offer":"Waiting for answer","withdrawn":"Withdrawn"}},"print_models":{"browse_all_makes":"Browse all 3D Makes","browse_all_models":"Browse all models","description":"Discover trending 3D print-ready models, printable assets, and STL files for gaming, art, home projects, and more.","makes_description":"Explore the latest 3D Makes uploaded by the community - real printed examples showing how 3D models look in the physical world.","makes_title":"New 3D Makes","new_description":"Check out the newest 3D prints added to our collection - fresh designs ready to download and print for your next project.","new_title":"New 3D print models","title":"Trending 3D print models"},"product":{"description":"Download %{title} 3D model or browse %{similar_items}
16518 similar %{short_name} 3D models. Available in max, obj, fbx, 3ds and other formats. Browse 140000+ 3D Models on CGTrader.","money_guarantee":{"text":"You are buying from a trusted seller - this means you will get back your money if you are not satisfied with the product.","title":"Money Back Guarantee"},"sidebar":{"details":{"Collection_id":"Pack ID","Model_id":"Model ID","animated":"Animated","game_ready":"VR / AR / Low-poly","geometry_type":"Geometry","materials":"Materials","pbr":"PBR","plugins_used":"Plugins used","polygons":"Polygons","published_at":"Publish date","rigged":"Rigged","textures":"Textures","unwrapped_uvs":"Unwrapped UVs","uv_mapping":"UV Mapping","vertices":"Vertices"},"tab":{"download":"Download","get_printed":"Get printed","print":"Use my 3D printer"}},"store_credits_discount_html":"\u003cdiv class=\"u-text-center\"\u003e\n %{discounted} discount from your remaining %{available}\n \u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts' target='_blank'\u003eCGTrader points\u003c/a\u003e. \u003cbr\u003e\n The points can be used for up to 30% discount for each purchased model.\n\u003c/div\u003e\n","verified":"Your 3D model has been reviewed and received a verification score. This score measures the quality of your model, with a higher score indicating more successful standard checks. The date of verification is displayed below the score. You can now re-upload your model after making changes and track how it affects the score. Below you can see the specific factors that contribute to your model's score.","verified_info":"\u003cdiv class=\"cgt-verified-notice__text cgt-legacy-text-tiny cgt-legacy-color-typography-secondary\"\u003e\n Verified models are of higher quality as they have passed CGT Standard technical and visual checks, making them more professional-grade 3D assets.\n \u003cspan class=\"cgt-verified-notice__link\"\u003e\u003ca class=\"cgt-legacy-text-caption\" target=\"__blank\" href=\"https://help.cgtrader.com/hc/en-us/sections/12602641776913-PBR-model-standard\"\u003eMore details\u003c/a\u003e\u003c/span\u003e\n\u003c/div\u003e\n"},"profile":{"account_settings":{"account":{"email":"Email","submit":"Save","title":"Profile","update":{"updated":"Profile updated"},"username":"Username"},"email_settings":{"descriptions":{"ai_studio_notifications":"Notifications about your CGTrader AI generations, including when a model you have not opened yet is ready","communication":"Information about your communication with other CGTrader users, including personal messages, new price and custom job offers, feedback and product support requests","news":"Information about CGTrader products, new feature announcements and community news","onboarding_and_edu":"Information about your onboarding process and tips to help you get the most out of CGTrader","push_notifications":"Notifications about important account activity and updates","sales_and_offers":"Information about special offers, 3D model Sales and CGTrader bonus credits","seller_sold_item":"Information about your sold 3D models and received payments"},"privacy_policy_html":"Please read our \u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003ePrivacy Policy\u003c/a\u003e for more information. ","titles":{"ai_studio_notifications":"CGTrader AI notifications","communication":"Communication (Personal messages, 3D model feedback, community activity, offers)","news":"3D News / CGTrader updates","onboarding_and_edu":"Onboarding \u0026 Education","sales_and_offers":"Sales \u0026 special offers","seller_sold_item":"Sales \u0026 Payments information"},"tracking_attributes":{"ai_studio_notifications":"CGTrader AI notifications","communication":"Communication","news":"3D News / CGTrader updates","onboarding_and_edu":"Onboarding \u0026 Education","push_notifications":"Push Notifications","sales_and_offers":"Sales \u0026 special offers","seller_sold_item":"Sales \u0026 Payments information"},"update":{"updated":"Your email has been updated successfully."}},"gdpr_success_notification":{"opt_in":"Thank you! You have successfully re-subscribed to our emails.","opt_out":"You have successfully unsubscribed from our newsletters. You can change this preference anytime by visiting your profile settings.\n"},"location_tooltip_text":"\u003cdiv\u003eThis checkbox enables showing location on the Profile page.\u003c/div\u003e \u003cdiv\u003eNote that in any case due to compliance reasons your location will be shown to your buyers (if you are a seller) and to the sellers you bought from.\u003c/div\u003e","moneybookers":{"account":"Skrill Account"},"password":{"current_password":"Current password","new_password":"New password","submit":"Change Password","title":"Password","updated":"Your password has been updated successfully. You can now use your new password to log in.","verify_password":"Verify password"},"paypal":{"account":"Paypal Account","submit":"Save","title":"Paypal Settings","update":{"updated":"Your Paypal settings were updated"}},"personal_info":{"areas_of_expertise":"Areas of Expertise","country":"Country","description":"A few sentences about yourself","full_name":"Full name","languages":"Languages","preffered_tools":"Preferred Tools","submit":"Save","title":"Personal and professional information","update":{"updated":"Your information was successfully updated"},"website":"Website"},"personalization":{"mute":"Hide","no_muted_title":"No hidden designers","title":"Hidden Designers","tooltip":"3D models of listed designers are excluded from your search results.","unmute":"Unhide","unmute_designer":{"confirm":"Are you sure?"}},"professional_info":{"allow_private_job_requests":"Buyers will be able to send you custom 3D job requests.","buyer_engagement_program_html":"Attract more customers by letting them purchase your models with CGTrader CGTrader Points. \u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003eMore information\u003c/a\u003e\n","pbr_program":"The lower earning rate is applied only when the converted file is downloaded","pbr_program_agreement":"You have agreed to take part in the PBR program for 24 months on %{date}. See Terms \u0026 Conditions for more details. Please contact our support should you have any questions.","product_analytics_participation_html":"I participate in \u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eAnalytics\u003c/a\u003e and agree with their Terms and Conditions\n","product_analytics_participation_tooltip_html":"You have agreed to participate in Analytics and agreed with Analytics Terms and Conditions (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003elink\u003c/a\u003e) at %{accepted_at}. If you want to terminate your participation, please contact CGTrader support\n"},"security":{"allow_mfa":"Enable 2-step verification to protect your account","use_authenticator_app":"Use an authenticator app for 2-step verification","use_authenticator_app_tooltip":"Scan the QR code with your authenticator app (Google Authenticator / Authy) to generate verification codes.","use_email":"Use email for 2-step verification"},"sidebar":{"general_settigns":"General Settings","member_since":"Member Since","paypal":"PayPal","title":"Account Info"},"title":"My Account"},"archiver_download":{"request_error":"Something has gone wrong with your request. Please, try again later.","request_received":"Your download request was received. You will be notified by email when it's ready."},"cart":{"messages":{"order_deleted":"Order has been successfully deleted","rating_saved":"Your rating has been successfully saved"},"product_kind_label":{"cg":"3D model"}},"conversations":{"conversations":"Conversations","messages":{"loading":"Loading inbox"},"types":{"cgtrader_support":"CGTrader Support","file_conversion_request":"File conversion request","job_application":"3D Project","model_feedback":"Product Feedback","model_support":"Model Support","offer":"Price Offer","personal":"Personal Message","promotions":"Promotions"}},"dashboard":{"feed":{"scopes":{"all":"All activities","announcements":"Announcements","following":"Following","forum":"Forum","notifications":"Notifications"}},"latest_activity":"Reputation","latest_sales":{"buyer":"Buyer","price":"Price","product":"Product","purchase_date":"Purchase date","royalties":"Royalties","title":"Latest Sales","upload_first_model":"Upload your first model now"},"offers":{"accept":"Accept","buyer_offers_new_price":"Buyer offers a new price","no_offers":"You do not have any offers.","reject":"Reject","title":"Offers","update_offer":"Update Offer","waiting_response_from_buyer":"Waiting response from buyer (Offered price: $%{price})"},"sidebar":{"authority":"Authority","average_price":"Average price","inactive_models":"Inactive Models","number_models":"Number of models","royalty_rate":"Your Earning rate","title":"Profile Info","total_items":"Total 3D Models","total_sales":"Total Sales"}},"meta":{"description":"Explore high-quality 3D models by %{username} on CGTrader. Browse unique assets for games, VR/AR, and visualization.","title":"%{username} 3D Model Designer"},"my_products":{"errors":{"empty":"This field cannot be empty","max_duration_limit":"Duration must be between 1 and %{max} days","max_fixed":"Please enter a value less than or equal to 10000","max_percent":"Please enter a value less than or equal to 99","max_reached":"Price cannot be greater than 10000","max_title":"Product title should not be longer than 64 characters","min_3dp_fixed":"Please enter a value greater than or equal to 3","min_fixed":"Please enter a value greater than or equal to 2","min_percent":"This value cannot be less than 0","min_reached":"Price cannot be less than 2","min_t
16518itle":"Product title should be at least 5 characters long","numeric":"This field should contain numeric values only","promotion_limit":"You already have 3 active campaigns using the tag \"%{tag}.\" To promote another item with this tag, please wait for an existing campaign to finish or choose a different tag.","promotion_rejected":"You're not allowed to promote this item because it contains adult content or copyrighted material."},"status_tooltips":{"pending":{"adult":"Your model contains adult content and must be approved by our team before it is published on the marketplace.","copyright":"Your model is pending for review, because it possibly contains trademarked or copyrighted material."},"suspended":{"adult":"Contains adult or violent content.","copyright":"Contains potential trademark or copyright infringement.","reported":"The model was reported and must be approved by our team before it is published on the marketplace again."}},"suspension_appeal":{"accepted":"Appeal accepted","appeal":"Appeal","modal":{"acknowledgement":"I confirm this model does not violate the policy above, and understand that submitting a false appeal may affect my account standing.","cancel":"Cancel","error":"Failed to submit your appeal. Please try again.","exception":"Clearly non-sexual figures - such as untextured base meshes, mannequins, or dolls - are permitted.","exception_label":"Exception:","footer":"Each suspension may be appealed once. Reviews take up to 5 business days. Decisions are final.","header":"Appeal a Content Suspension","intro":"This listing was suspended for adult or sexually suggestive content, which cannot be displayed under search engine safety requirements. Submit an appeal if you believe this is a mistake.","note":"Our Support team can't review or handle suspension appeals sent by email or support ticket. Sending an email to Support won't start or speed up the review of your appeal.","note_label":"Note:","policy_intro":"Appeals only succeed if the model contains no sexual or suggestive content, including:","policy_items":["Suggestive themes or poses","Revealing or partially removed clothing","Partial or implied nudity"],"reason_field_label":"Tell us why this listing does not violate the policy above","reason_placeholder":"Describe what the model depicts and why it contains no suggestive content.","reason_word_limit":"Reason must be %{count} words or fewer","submit":"Submit Appeal","success":"Your appeal has been submitted."},"pending":"Appeal pending","reasons":{"copyright":"Copyright violation","designers_request":"Suspended at designer's request","gun":"Prohibited print-gun content","missing_kyc":"Verification required","not_available":"N/A","nsfw":"NSFW content","reported_model":"Reported model","spam_scam":"Spam / Scam","stolen_model":"Stolen model"},"rejected":"Appeal rejected"},"types":{"cad":"CAD Model","cg":"CG Model","printable":"Printable Model"}},"my_sales":{"followers":{"actions":"Actions","date":"Follows since","no_followers":"You don't have any followers yet.","no_followers_heading":"Oops, no followers!","username":"Username"},"latest_downloads":{"created_at":"Download Date","downloader":"Downloader","file_name":"File name","no_downloads":"Unfortunately nobody downloaded your models (at least in the past 6 months). %{link} to improve that!","no_downloads_heading":"Oops, no downloads!","price":"Price","product":"Product","product_id":"Product ID"},"latest_sales":{"buyer":"Buyer","country":"Country","evermotion_id":"Evermotion ID","no_sales":"Ah, unfortunately you don't have any sales yet. We wish you best of luck in getting them soon!","no_sales_heading":"Oops, no sales!","order_id":"OID","original_price":"Original Price","payment_processing":"Payment Processing","payment_processing_tooltip_html":"Transaction fees are applied for every purchase. You can find more about transaction fees by \u003ca href='https://help.cgtrader.com/hc/en-us/articles/33947843875345-Payment-processing-fees' target='_blank'\u003eclicking here\u003c/a\u003e.","payout_transaction_id":"Transaction ID","price":"Sold For","price_tooltip_html":"This tab shows the price that the buyer paid after applying coupon code, price offer, sales campaign discount or Customer Loyalty discount.","price_without_fees":"After tax","price_without_fees_tooltip_html":"Earnings are calculated after applying payment processing fees to the sales price.","product":"Product","product_id":"Product ID","purchased":"Purchased","royalty":"Earning rate","royalty_amount":"Final Earnings","status":"Status","title":"Latest Sales","vat_tooltip":"%{vat}% VAT should be charged for buyers from this country"},"menu_tabs":{"latest":"Latest","monthly":"Monthly"},"monthly_sales":{"date":"Date","downloads":"Downloads","revenue":"Revenue","royalty":"Avg. Earning rate","sales":"Sales","title":"Monthly Sales"},"payouts":{"fees":{"no_fees":"There are no previous payout fees.","payoneer":"Payouts for Payoneer users are free! You will only have to pay a conversion fee when withdrawing earnings from Payoneer to your local bank account.\n","paypal":"A money transfer to your Paypal account is processed through \u003ca href='https://www.paypal.com/lt/webapps/mpp/ua/useragreement-full#16' target='_blank' rel='nofollow'\u003ePaypal Mass Payments\u003c/a\u003e. \u003c/br\u003e The amount of payout fee may vary based on your location.\n","refunds":"Click to see list of refunds.","webmoney":"A money transfer to Webmoney system is processed through Paysera and costs â¬0.29 (approximately $0.31 based on exchange rate as on Dec 30, 2016). Also, a standard 0.8% Webmoney fee (calculated from the total payout fee) is applied. More details can be found \u003ca href='https://www.paysera.com/v2/e
16518n-GB/fees/transfers-in-other-currencies' target='_blank' rel='nofollow'\u003ehere\u003c/a\u003e.\n","wire":"A money transfer to your Wire account is processed through Paysera and costs from â¬7.00 to â¬30.00 depending on the country of your bank. More details can be found \u003ca href='https://www.paysera.com/v2/en/fees/additional-transfers-services-fees' target='_blank' rel='nofollow'\u003ehere\u003c/a\u003e.\n"},"status":{"all_time":"Yet to be paid","limit_not_reached":"To be paid when $200 minimum is reached","ongoing":"Earned this month","paid":"Paid","pending":"To be paid until 20th of this month","revoked":"Revoked","to_be_paid":"To be paid","upcoming":"To be paid until 20th of next month"}},"refunds":{"default_reason":"This item purchase was refunded. For more details please contact our support."}},"purchases":{"author":"Author","author_v2":"By","download":"Download","download_files":"Download Files","item":"Product","no_items":"You don't have purchased products.","order_id":"Order ID","price":"Price","rate_purchases":"Rate Your Purchases","support":"Support","title":"My Purchases"},"referrals":{"actions":{"uploaded_model":"Uploaded model","user_registration":"Registered"}},"settings_updated":"Your settings have been updated successfully."},"publisher":{"geometry_types":[{"value":null,"label":"Choose geometry"},{"value":"gaussian_splats","label":"Point-based (Gaussian Splats)"},{"value":"polygon_mesh","label":"Polygon mesh"},{"value":"subdivision_ready","label":"Subdivision-ready"},{"value":"nurbs","label":"Nurbs"},{"value":"other","label":"Other"}],"licenses_free":[{"value":"royalty_free_no_ai","label":"Royalty free, no AI"},{"value":"custom_no_ai","label":"Custom, no AI"},{"value":"editorial_no_ai","label":"Editorial, no AI"}],"licenses_paid":[{"value":"royalty_free","label":"Royalty free"},{"value":"royalty_free_no_ai","label":"Royalty free, no AI"},{"value":"custom","label":"Custom"},{"value":"custom_no_ai","label":"Custom, no AI"},{"value":"editorial_no_ai","label":"Editorial, no AI"}],"messages":{"filetypes":{"unsupported":{"any":"File type not supported.","printable":"File type not supported, please upload .stl, .obj or .wrl files only."}},"size":{"over_the_limit":"Image size must be less than 15 megabytes."},"url":{"not_allowed":"Image URL is not allowed."}},"payment_agreement_blocker":{"cta":"Complete Payment Agreement","dismiss":"Continue editing","message":"Before you can publish your model, you need to complete and verify your Payment Agreement. This ensures you can receive payments for your sales.","pre_activation_message":"Your Hyperwallet account is not activated. Please activate and verify your Hyperwallet account by \u003cstrong\u003efollowing the instructions sent to your email address\u003c/strong\u003e to become eligible to publish models and receive payments for your sales."},"units":[{"value":"mm","label":"millimeters (mm)"},{"value":"cm","label":"centimeters (cm)"},{"value":"in","label":"inches (in)"},{"value":"m","label":"meters (m)"}],"unwrapped_uvs":[{"value":"unknown","label":"Unknown"},{"value":"non_overlapping","label":"Non-overlapping"},{"value":"overlapping","label":"Overlapping"},{"value":"mixed","label":"Mixed"},{"value":"no","label":"No"}]},"publishing":{"banned_error":"Your account has been banned for publishing spam content. If you believe this is a mistake, please contact [email protected].","files_not_finalized":"One or more files haven't finished uploading and can't be published. Please remove them and upload again before publishing.","spam_suspect":"Your account is not authorized to publish this model. If you believe this is a mistake, please contact [email protected]."},"rating":{"anonymous_buyer":"Anonymous Buyer","errors":{"not_verified_buyer":"Only verified buyers can leave a review"}},"reputation":{"additional_item_of_referral":"Model upload of your referral","additional_purchase_of_referral":"Purchase of your referral","answer_to_user_topic":"Answer to your topic","approved_challenge_item":"Model participating in a challenge","comment":"Posted new comment on model","comment_on_your_content":"Comment on your model, gallery or tutorial","comment_vote":"Like of your comment","community_rating":"Community rating with 80% accuracy","community_rating_high_accuracy":"Community rating with 85% accuracy or more","custom_points":"Custom Points","downloaded_free":"Free model download","first_item_of_referral":"First model upload of your referral","first_purchase_of_referral":"First purchase of your referral","forum_topic_answer":"Reply to topic","forum_topic_vote":"Thread vote","item_purchase":"Make new purchase","job_finished":"Job closed","my_like":"Like of a model, gallery or tutorial","negative_item_rating":"Negative rating after model purchase","neutral_item_rating":"Neutral 3D model rating","new_comment":"New comment","new_follower":"New follower","new_forum_topic":"New topic in forum","new_item":"New model upload","new_like":"Like of your model, gallery or tutorial","new_project":"Gallery project accepted","new_tutorial":"Tutorial published","positive_first_topic_answer":"First positive topic answer","positive_forum_topic_vote":"Like of your topic","positive_item_rating":"Positive rating after model purchase","positive_topic_answer":"Positive topic answer","purchase":"Make new purchase","referral_uploaded_model":"Model upload of your referral","referral_user_registration":"Referral Registration","sale":"Model sold","social_model_like":"Social like of your model","social_profile_like":"Social like of your profile","tutorial":"New tutorial","tutorial_vote":"Like of your tutorial"},"routes":{"3d-models":"3d-models","3d-models-new":"3d-models/new","3d-models-trending":"3d-models/trending","3d-modles-top-selling":"3d-models/top-selling","3d-print-models":"3d-print-models","3d-print-models-new":"3d-print-models/new","3d-print-models-top-selling":"3d-print-models/top-selling","3d-print-models-trending":"3d-print-models/trending","animated-3d-models":"animated-3d-models","discover":"discover","free-3d-models":"free-3d-models","free-3d-print-models":"free-3d-print-models","low-poly-3d-models":"low-poly-3d-models","pbr-3d-models":"pbr-3d-models","pbr-textures":"pbr-textures","rigged-3d-models":"rigged-3d-models"},"sale_off":{"ends_at_before_starts_at":"End date must be later than the start date.","ends_at_in_past":"End date cannot be in the past.","invali
16518d_condition_format":"Line %{index} has an invalid condition format.","invalid_condition_key":"Line %{index} has invalid condition key '%{key}'.","invalid_condition_value":"Line %{index} has invalid %{key} value '%{value}'.","invalid_discount_value":"Line %{index} has invalid discount value '%{value}'.","invalid_price_range":"Line %{index} has an invalid price range (gt must be less than lt).","invalid_webp_format":"Must be a .webp file.","no_overlapping_campaigns":"Campaign dates overlap with another existing sale campaign.","overlapping_price_rules":"Discount rules overlap for the same conditions (lines %{first} and %{second}).","parse_discount_rules_text":"Line %{index} missing required 'discount:'","starts_at_in_past":"Start date cannot be in the past."},"sale_page":{"meta":{"description":"Quality 3D models available with loyalty discounts of up to 30% on CGTrader","title":"Buy quality 3D models with loyalty discounts. Up to 30% off"},"twitter_shareable_text":"Quality 3D models available with loyalty discounts of up to 30% on CGTrader #discounts #3d #3dmodels #cgtrader\n"},"scholarships":{"annual_scholarship":{"description_html":"\u003ca href='/' target='_blank'\u003eCGTrader\u003c/a\u003e is the leading 3D content provider globally, running an online 3D model marketplace alongside with custom modeling platform and mass 3D modeling solutions for enterprise customers. \u003ca href='/' target='_blank'\u003eCGTrader\u003c/a\u003e gives talented 3D designers the opportunity to showcase their work, get valuable feedback from the community, learn from their peers and interact in a designer-friendly environment. Every year \u003ca href='/' target='_blank'\u003eCGTrader\u003c/a\u003e challenges students to dig into the field of technology by writing an essay on how innovative technologies are transforming our lives. Enter the \u003ca href='/' target='_blank'\u003eCGTrader\u003c/a\u003e Scholarship 2019 challenge to win $3,000 for your education bills. The best submission will be awarded $2,000 while the two runners-up will receive $500 each.\n","meta":{"title":"Annual scholarship"}},"meta":{"title":"Scholarship"}},"search":{"not_found":"Search subscription not found","subscription_created":"Search subscription created","successfully_unsubscribed":"You have successfully unsubscribed from the search subscription"},"settings":{"payment_agreement_lock":"We are currently processing payouts. Once done, you will be able to change your payout method for the next month.\n","payment_agreement_lock_no_agreement":"We are currently processing payouts. Once done, you will be able to fill your payment agreement to start receiving your earned income.\n"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"extra_usage_payment_form":{"item_bullets":{"first":"25 extra generations","second":"Don't expire or reset monthly","third":"Used after you've reached your monthly generation limit"},"item_title":"Extra Usage purchase (one-time payment)"},"flash":{"active_subscription":"You already have an active subscription.","premium_upgrade_unavailable":"Upgrading to Premium is temporarily unavailable. Please try again later.","update_payment_method":"Your subscription has a payment issue. Please update your payment method instead of buying a new subscription."},"item_page":{"essentials":{"bullets":{"first":"Designed to meet your everyday needs","second":"Download up to %{downloads} models per month","third":"Access a library of %{count} premium models"}},"premium":{"bullets":{"first":"Download up to %{downloads} models per month","second":"Access a library of %{count}+ total accessible models","third":"Unlock professional-grade models not included in Essentials"}}},"payment_form":{"current_price":"%{price}","features":{"first":"%{downloads} assets / month â download models or generate with AI","second":"Instant access to %{models_count}+ essential 3D models","third":"Royalty-free, No AI"},"from_price_label":"from","original_price":24.99,"per_model_label":"per model","plan_name":"CGTrader Essentials Subscription â annual plan, billed monthly","premium":{"features":{"first":"%{downloads} assets / month â download models or generate with AI","fourth":"Royalty-free, No-AI license","second":"Instant access to %{models_count}+ total accessible models","third":"Professional-grade models not included in Essentials"},"original_price":34.99,"plan_name":"CGTrader Premium Subscription â annual plan, billed monthly"},"price_unit":"/month","vat_amount":"%{vat_amount}"}},"support":{"array":{"last_word_connector":", and ","two_words_connector":" and ","words_connector":", "}}
16518,"tag":{"description":{"anime":"%{found_items_count} anime 3D models available for download. Looking for free anime 3D models? We have them as well. All models are ready for animation, games and VR / AR projects. Use filters to find rigged, animated, low-poly or free 3D models. Available in any file format including FBX, OBJ, MAX, 3DS, C4D","bottle":"Scientists say that bottle of wine a day is not bad for you, but when it comes to stronger drinks like whiskey or bourbon, we should really watch our alcohol intake. Obviously, a glass of champagne at the bar looks way cooler than a plastic bottle of water, but think about the possibility of living a longer life and beer will seem like a reasonable sacrifice. This category offers a wide selection of bottle 3D models, ranging from alcohol-related objects like wine racks and corkscrews to all types of bottle 3D models (from shampoo to olive oil).","brain":"The brain is one of the largest and most complex organs in the human body. Due to its intricate structure and function, the anatomy of the brain is also very complex. However, scientists dig deeper into the architecture of human brain, uncovering mind-boggling secrets. A wide range of realistic and detailed brain 3D models that are ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design is available for download.","building":"It's unclear where modern architects take their inspiration from, but some of the world famous buildings are so cutting edge that they look like visions from the future. And we don't just mean the exterior part... In capable hands a standard building construction becomes a breathtaking architectural creation with innovative interior design regardless of whether it's an office or an urban building. Our selection of building 3D models is ready for download and can be applied in various fields - 3D animation, graphic design, advertising, 3D games or web.","camera":"Photography and filming is currently one of the most popular career fields among young people, but not everyone with a professional camera is an artist or a photographer. With the quality of phone cameras improving year on year, we see people taking pictures in every step and those who have the newly-developed image editing skills are truly celebrated. Life does look a little different when you're on the other side of the lens, but let's not get carried away... A wide range of detailed camera 3D models is available for download to be used by graphic designers, animation and game developers and professionals working in other 3D-related fields.","car":"Looking at these very detailed and highly realistic 3D car models, you can almost hear the engine roar! A wide range of vehicle 3D models can make your life so much easier, if you're grappling with computer graphics, animation or any other 3D-related field.","cell":"Scientists have estimated that human body contains from 5 billion to 200 million trillion cells. Plants and animals have cells, too. We don't want to bore you with this biology stuff, but the wide range of cell 3D models that we have covers everything from blood, virus and DNA to bone marrow and cell walls. Isn't that...nerve-racking?","chair":"We take sitting in chairs for granted and don't always notice how much charm they can add to our home or office interior. Chair is actually one of the central pieces of furniture in any household. Here you can find high quality and eye-catching design chair 3D models that can be applied in various fields - from advertising and 3D visualization to 3D games.","city":"City life is an eccentric game: streets bursting with racing taxis, modern buildings, pedestrians in perfectly tailored office clothes, sleeping bridges and parks... From Shanghai, to New York (Manhattan!), to London or Paris - every city has its own magic. You can choose from this rich selection of detailed city 3D models that can be used in a number of fields - advertising, computer graphics, animation, 3D visualization or games. Explore the urban life.","dragon":"Dragon is probably the most popular creature living in the fantasy world. It has featured in so many myths of various cultures, animations, movies and books that it has become legendary. It is especially loved by game developers, as it adds that magical charm to dark caves and dungeons. A wide range of realistic, rigged dragon 3D models that are ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design is available for download.","earth":"The level of detail in the recently added earth view in Google maps has shocked a number of people. You can explore the whole planet - oceans, mountains and deserts, discover cities and hidden roads without leaving your house. That's some incredible things Mother Earth hasn't experienced before. A selection of realistic earth 3D models that are ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design is available for download.","engine":"Some people are able to name the engine by simply listening to the sound it makes, and that is truly amazing. Regardless of whether it's a jet engine or a car engine, they're extremely complicated machines that we use so often, but don't spend too much time thinking about it. A motor is a motor (until it stops working). This category has a range of different types of engine 3D models, and it also includes engine parts like propeller or cylinder, so we're confident you will find what you need.","female":"It's no joke that there are significant differences between male and female brain, which means that it is normal that an average man and woman behave, feel and respond in completely different ways. But it's not all about the anatomy. No love story, film or game ever pulled it off without a strong girl character, cause the power of lady charm is undeniable. A rich selection of realistic female 3D models can offer you everything you need - from nude 3D models to female respiratory system.","hand":"The reason we use our hands for so many things is their extraordinary anatomy. The thumb alone is controlled by nine separate muscles. It's hard to believe, but early hands were more exotic than any hand today - some species had seven fingers. Human body has significantly evolved. An arm or a hand as we see it today looks nothing like its early versions. A wide range of realistic, rigged hand 3D models that are ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design is available for download.","head":"In human anatomy, the head is the upper portion of the human body. Modelling a 3D human head can prove a little complicated, because (even though there are so many different shapes and sizes) we appreciate symmetric, realistic-looking heads - no funny eyes, ears, nose, lips or jaw line, please. Face is a sensitive area and it would just be plain rude to have fun with that. Our selection encompasses realistic male, female, child and even story characters like Harry Potter and Batman or celebrities like Tom Cruise and Scarlett Johansson heads that are ready for download.","helmet":"Always remember that health \u0026 safety comes first, so protecting your head is a sound idea. Medieval knights, Daft Punk and even the Ironman wear helmets, so regular superheroes like cyclists or builders should not worry about looking uncool. This collection of helmet 3D models that is available for download will prove useful if you're working in the fields of graphic design, 3D animation, 3D games or visualization.","house":"It's an old truth that a man's home is his castle, but when it comes to building that perfect house or buying an ideal apartment, we do tend to lose our heads over it. Luckily, this wide spectrum of house 3D models that encompasses everything from architectural details, interior and exterior, to furniture, will help you create modern 3D visualizations to ease that pain.","human":"When you start exploring the human anatomy, you realize that people are such intricate and complex machines that it takes your breath away. Every body part, muscle, joint, organ or bone combination is connected into one system, nothing works in isolation! These super realistic 3D human models will allow you to examine anatomical structures from every angle.","lamp":"If you look around your home and count the types of lamps that you own, you will be surprised: reading, table, wall, ceiling, desk, tripod lamps... It's enough to make your head spin! Not to mention the styles that they come in - from extravagant modern lamps to retro or stylish futuristic. In this category we have all kinds of lamp 3D models, so browse and download to use in graphic design, 3D visualizations or any other 3D-related field.","light":"Have you ever wondered why a light bulb is the symbol of a brilliant idea? Surely, a bright idea can enlighten the architecture of the mind, but that is not it. A street light, a chandelier or any other type of lamp would never stand a chance to take that spot. If the next time when you look up at the ceiling and stare at some kind of architectural light the genius idea doesn't hit you, it might be because you're staring at a wrong lightning system... Our selection of high quality light 3D models will prove handy if you work in the fields of architecture, computer graphics, 3D animation or design.","machine":"Imagine if all the machines suddenly stopped working: no coffee, no convenient laundry washing, no cash points on a corner of the street, no gym time, no overpriced vending machines... It does sound depressing, doesn't it? We are so used to these home appliances and electronic gadgets that it would literally stop the world turning! Luckily, our selection of detailed machine 3D models covers everything from machine guns to electricity generators that will prove useful to de
16518signers working with computer graphics, advertising, 3D animation, 3D games or web.","man":"A vast collection of man 3D models is available for download. Sitting man, simple man, flying man or average man, we've got everything - except that perfect man that everyone's after. He's a fishy character and we hate to bring this up, but it might be a myth... But hey, human beings are born to be awesome, not perfect.","robot":"R2D2 is probably the most famous robot in the world, but it's certainly not the only one. From industrial to toy to human robots, we see an increasingly wider choice of these mechanical machines, which is both wonderful and a little worrying. It's not too difficult to understand the people who insist that computers, technology, robots are making a too significant impact on human beings. A wide range of realistic, rigged robot 3D models that are ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design is available for download.","ship":"Ships are powerful vessels and come in all sizes, colors and shapes. They can be classified as cargo ships, warships or passenger ships, but they all operate in deep sea waters. If you have experienced the discomfort of motion sickness, it may not be a your favorite means of transport, but many people regard boat trips as quite classy and enjoyable. Our selection of ship 3D models is ready for download and will meet the standards of even the most demanding captain.","skeleton":"The human skeleton or skeletal system (anatomy) is the internal framework of the body that is composed of 270 bones at birth. It provides the body structure, protection and movement and is one of the most complex skeletal systems. A rich selection of anatomically correct, realistic and scaled skeleton 3D models that are perfect for use in 3D animation, graphic design, advertising, 3D games and web is available for download.","skull":"The oldest most complete, genetically intact human skull was discovered surrounded by a variety of extinct animals more than 40 meters below sea level. It is one of the oldest skeletons found in the New World and it also includes all of the major bones of the body and an intact cranium and set of teeth. Human skulls have recently become a thing in fashion and design, but when you actually give it some thought, they kind of make us all look like anatomy freaks... This category offers a wide range of skull 3D models to be used in graphic design, 3D animation, 3D games or advertising.","sofa":"Luxury or simple, modern or antique, leather or minimalist design? How do you like your sofa? The range of sofa 3D models that we have will satisfy even the worst perfectionist. When you stop to think about it, sofa is the center of every living room, so you must be creative when choosing the design!","table":"The newest furniture trends are so diverse that choosing a modern, fashionable table is becoming too stressful. There used to be a time when you had a simple dinner table for your modest feasts and that was enough, but today - table is supposed to be a statement or at least an eye-catching interior accent. This selection gives you a vast range of table 3D models to cater to every whim.","tower":"Every city has a special tower that everyone's really proud of. Think Eiffel tower or Pisa tower, or London tower bridge, let alone all the modern skyscrapers, futuristic buildings and the urban landscape that tourists admire. However, when it comes to the industrial parts of the city, water or electrical towers, everyone tend to turn their eyes away...But we should learn to appreciate every architectural creation, no matter ancient, industrial or modern. A range of detailed tower 3D models are available for download and ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design.","tree":"If you're on a mission to plant some trees or exotic plants, you've come to the right place. This category offers a range of easy-to-use, very realistic 3D tree models to CG artists and architects, who are striving to add some greenery to their projects. If you appreciate good quality, we're confident this selection of 3D tree plant models will meet your standards!","truck":"Driving a truck is a tough job, especially if you need to find your way through a city traffic jam. Regardless of whether it's a firetruck, garbage truck, food truck or a generic one, it takes a great skill to maneuver these giant vehicles. We are confident that this selection of realistic, high quality truck 3D models are perfect for use in 3D animation, graphic design, advertising or any other 3D-related field.","tv":"There used to be a time when fireplace was the centerpiece of every respectable home, now TV set with players and speakers is the king of the living room (and even the bedroom). In recent years television has caught up with
16518newest technologies. As a result, we have smart 3D TV, flat and plasma screens, million new functions and touchscreen design. No wonder television is pushing cinema out of the market. A wide range of realistic, detailed TV 3D models that are ready for computer graphics applications like advertising, 3D visualization, 3D games, web and any other field related to 3D design is available for download.","woman":"%{found_items_count} woman 3D models available for download. Looking for free woman 3D models? We have them as well. All models are ready for animation, games and VR / AR projects. Use filters to find rigged, animated, low-poly or free 3D models. Available in any file format including FBX, OBJ, MAX, 3DS, C4D"}},"tag_promotion":{"days_left_error":"must be between 1 and 30","no_other_pending_promotions_for_same_item_tag":"already has a pending promotion"},"three_d_studio":{"flash":{"run_unavailable":"This 3D model is no longer available."},"seo":{"gallery":{"description":"Explore AI-generated 3D models created by the CGTrader community. Browse, download and create AI 3D assets in FBX, OBJ, STL and other formats.","title":"AI 3D Models Generated By Community | CGTrader AI"},"images":{"description":"Explore AI-generated images created by the CGTrader community. Browse, download and turn AI images into 3D models with CGTrader AI.","title":"AI Images Generated By Community | CGTrader AI"},"index":{"description":"Use text prompts or image references to generate production-ready 3D models for any use case.","title":"3D AI Generator | CGTrader"},"landing":{"description":"AI 3D model generator that WORKS! Generate production-ready 3D models in seconds with CGTrader AI. Turn text prompts or images into detailed 3D assets.","title":"AI 3D Model Generator - Text \u0026 Image to 3D | CGTrader"},"output":{"description":"AI-generated %{name} 3D model. Download or remix this asset created by CGTrader AI using text prompts or image references.","title":"%{name} 3D model | CGTrader AI"}}},"time":{"am":"am","formats":{"datetime":"%Y-%m-%d %H:%M","default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"pm":"pm"},"time_zones":[{"value":"UTC â 12:00","label":"UTC â 12:00"},{"value":"UTC â 11:00","label":"UTC â 11:00"},{"value":"UTC â 10:00","label":"UTC â 10:00"},{"value":"UTC â 09:30","label":"UTC â 09:30"},{"value":"UTC â 09:00","label":"UTC â 09:00"},{"value":"UTC â 08:00","label":"UTC â 08:00"},{"value":"UTC â 07:00","label":"UTC â 07:00"},{"value":"UTC â 06:00","label":"UTC â 06:00"},{"value":"UTC â 05:00","label":"UTC â 05:00"},{"value":"UTC â 04:00","label":"UTC â 04:00"},{"value":"UTC â 03:30","label":"UTC â 03:30"},{"value":"UTC â 03:00","label":"UTC â 03:00"},{"value":"UTC â 02:00","label":"UTC â 02:00"},{"value":"UTC â 01:00","label":"UTC â 01:00"},{"value":"UTC ± 00:00","label":"UTC ± 00:00"},{"value":"UTC + 01:00","label":"UTC + 01:00"},{"value":"UTC + 02:00","label":"UTC + 02:00"},{"value":"UTC + 03:00","label":"UTC + 03:00"},{"value":"UTC + 03:30","label":"UTC + 03:30"},{"value":"UTC + 04:00","label":"UTC + 04:00"},{"value":"UTC + 04:30","label":"UTC + 04:30"},{"value":"UTC + 05:00","label":"UTC + 05:00"},{"value":"UTC + 05:30","label":"UTC + 05:30"},{"value":"UTC + 05:45","label":"UTC + 05:45"},{"value":"UTC + 06:00","label":"UTC + 06:00"},{"value":"UTC + 06:30","label":"UTC + 06:30"},{"value":"UTC + 07:00","label":"UTC + 07:00"},{"value":"UTC + 08:00","label":"UTC + 08:00"},{"value":"UTC + 08:45","label":"UTC + 08:45"},{"value":"UTC + 09:00","label":"UTC + 09:00"},{"value":"UTC + 09:30","label":"UTC + 09:30"},{"value":"UTC + 10:00","label":"UTC + 10:00"},{"value":"UTC + 10:30","label":"UTC + 10:30"},{"value":"UTC + 11:00","label":"UTC + 11:00"},{"value":"UTC + 12:00","label":"UTC + 12:00"},{"value":"UTC + 12:45","label":"UTC + 12:45"},{"value":"UTC + 13:00","label":"UTC + 13:00"},{"value":"UTC + 14:00","label":"UTC + 14:00"}],"tips":{"tip":{"build_links":"Build links from other sites to your models on CGTrader. Itâs the best way to increase sales","popular_formats":"Export your models to MAX, FBX, OBJ, STL file formats. These are the most popular file formats.","preview_images":"Render at least 5 final and 3 wireframe preview images. It will increase your sales by 5.5x times.","rich_descriptions":"Write informative descriptions. Models with rich descriptions sell up to 1.6x more than without descriptions."}},"tooltips":{"buyer_loyalty_program_current_level_html":"Currently you have spent %{total_price_paid} on CGTrader and your Points earn rate is %{buyer_loyalty_rate}. \u003cbr/\u003e It means that you will get %{buyer_loyalty_rate} of points from each purchase.\n","buyer_loyalty_program_html":"This is the percentage of how much you will get from your purchases as new points. \u003cbr/\u003e It will increase up to 30% as your lifetime spending on CGTrader increase. \u003cbr/\u003e Currently your Points earn rate is %{buyer_loyalty_rate}.\n","buyer_loyalty_program_next_level_html":"Next level %{next_lvl_expenses} will increase your Points earn rate up to %{next_lvl_expenses_rate}. \u003cbr/\u003e You need to purchase for $%{left_until_next_lvl} more to reach next level.\n","buyers_sign_in_page":{"bonus_credits_tooltip_html":"These points will take priority over your permanent Points - meaning they will be counted first. \u003cbr/\u003e \u003ca href=\"/pages/cgtrader-loyalty-discounts\" class='js-tooltip-link' target='_blank'\u003eLearn more\u003c/a\u003e\n","cgtrader_credits_tooltip_html":"Every dollar spent on CGTrader brings you money back for future purchases. \u003cbr/\u003e \u003ca href=\"/pages/cgtrader-loyalty-discounts\" class='js-tooltip-link' target='_blank'\u003eLearn more\u003c/a\u003e\n","pro_tip_tooltip_html":"You can also earn Bonus Points by adding more models to the cart. \u003cbr/\u003e \u003ca href=\"/pages/cgtrader-loyalty-discounts\" class='js-tooltip-link' target='_blank'\u003eLearn more\u003c/a\u003e\n","sale_campaign_tooltip_html":"However, your loyalty level and points earn rate can be increased. \u003cbr/\u003e \u003ca href=\"/pages/cgtrader-loyalty-discounts\" class='js-tooltip-link' target='_blank'\u003eLearn more\u003c/a\u003e\n"},"common_credits_used_tooltip_html":"\u003cdiv class=\"u-text-left\"\u003e\n %{storeCreditsUsedText}\n %{temporaryCreditsUsedText}\n Total: \u003cstrong\u003e%{totalCreditsUsed}\u003c/strong\u003e\u003cbr/\u003e\n \u003cbr/\u003e\n Points can be used when purchasing \"$\" sign marked models and cover up to 30% discount of model's price.\n\u003c/div\u003e\n","low_cart_value_html":"Points can only be used if the total value of your cart is equal to or greater than %{minCartValue}\n","no_credits_used_html":"\u003cdiv class=\"u-text-center\"\u003e\n Points can be used when purchasing \"$\" sign marked models and cover up to 30% discount of model's price.\n\u003c/div\u003e\n","product_analytics":{"description_html":"A good description can make or break the deal - it lets your customer get an informative explanation about the model technical details before purchasing your asset. Make sure you have as detailed description as possible (100 - 200 words is recommended).\n","formats_html":"File Formats are very important for sales as different customers use different software. The most demanded formats are FBX, OBJ, MAX, STL, ZTL. We recommend uploading at least 3 different formats with FBX and OBJ included.\n","images_html":"Images are essential and have very high impact on sales and conversion. Our data shows that models with 20+ images sell 5 - 10 times better than those with just 1. Render as much images as possible and include at least several wireframe images that show topology.\n","models_score_html":"The Publishing Score is calculated by taking the number of unique file formats, number of images, model tags, word count in description. The scope of the score is 0-10 - with 10 being the highest.\n","tags_html":"Model tags help your assets show up in the search and attract traffic. Provide at least 10-20 related tags s
16518o that customers could find your model.\n"},"publisher":{"adult_content":"All models with nudity or violent content will be reviewed prior to publishing by CGTrader within 1â3 business days. CGTrader uses RSAC standards to evaluate content. Level 0 content is available to everyone. Models classified as Level 1-2 can be published under an age lock. Models classified as Level 3-4 are not approved for publishing on the marketplace.\n","description":"Write a proper description with relevant technical information about your product to drive more traffic and customers from around the web and increase buyers' confidence.\n","embeds":"Products with embedded video previews are sold significantly more often. If your asset is animated, make sure to embed a demo of those animations â it will make your model even more irresistible.\n","gaussian_splats":"Gaussian Splats point-based scenes only. Raw scan point clouds â 3D scanned models.","images":"Good preview images earn more sales. Add detailed preview images of your product, including wireframe preview images, from all angles. Add lighting and shadows to let buyers see the final look of the model. Your preview images must not contain any assets or details not included in the product. Use a neutral background to focus the buyersâ attention on the product.\n","license_html":"\u003cul\u003e\n \u003cli\u003e\u003cstrong\u003eEditorial license\u003c/strong\u003e should be applied when you do not want your model to be used in commercial projects and only educational, journalistic and otherwise newsworthy uses are allowed.\u003c/li\u003e\n \u003cli\u003e\u003cstrong\u003eRoyalty Free License\u003c/strong\u003e allows customers purchasing/downloading your product to use it for both commercial and noncommercial purposes for unlimited time and with no further royalty and other licensing fees to be paid to you. The buyer, however, is not allowed to sell, give, or assign your product to another person or entity in the form it is downloaded from the site.\u003c/li\u003e\n \u003cli\u003e\u003cstrong\u003eCustom license\u003c/strong\u003e should be applied when you want to impose extra terms on the usage of product and must contain exact conditions. If no terms are provided, Royalty Free License will be assumed.\u003c/li\u003e\n\u003c/ul\u003e\n","tags":"Add specific words that target your model, broad words which will generalize it and note its qualities or characteristics (like color, material, condition, etc). Do not add unrelated tags to your product.\n","technical_details":"Help buyers decide to purchase your product â state the software, polycount, maps, scripts and plugins you used to create the product.\n","title":"Write a relevant and specific title, which clearly represents and distinguishes your model. Keep the title length at 4-6 words: note the general category (e.g. âcar engineâ) and distinguish its type (e.g. âvintage V8â).\n"},"store_credits_used_html":"\u003cstrong\u003e%{storeCreditsUsed}\u003c/strong\u003e points\u003cbr/\u003e\n","temporary_credits_used_html":"\u003cstrong\u003e%{temporaryCreditsUsed}\u003c/strong\u003e bonus points (%{bonusCreditsTitle})\u003cbr/\u003e\n"},"trending_headers":{"models":"Check other trending 3D models","print":"Check other trending 3D print models"},"tutorial":{"aasm_state":{"draft":"Draft","published":"Published","under_review":"Under review"},"destroy":"Tutorial was successfully destroyed.","submit_for_review_error":"Please fill in all required fields.","submitted":"Thank you for submitting your tutorial. It will be reviewed and published shortly."},"users":{"active_user_not_found":"Active user could not be found.","banned":"User has been banned successfully","cannot_be_deleted":"Account cannot be deleted. Please contact our support team at [email protected].","confirmation":"Thanks for completing your registration. Please check your inbox and confirm your email address to continue.\n","content":{"cg":"3D Models","free":"Free 3D Models","low_poly":"VR / Low-Poly models","printable":"3DP Models"},"deleted":"Account has been deleted successfully","email":{"admin_changed":{"success":"Email has been successfully changed"}},"expertise":{"categories":"Categories","skills":"Expertise","software":"Preferred Tools"},"instructions":{"account_settings":{"subtitle":"Review your sales settings","text":"Let customers know whether you accept price offers or file conversion requests.","title":"Account settings"},"analytics_about_page":{"subtitle":"Marketplace Analytics","text":"View real-time insights about the market from millions of searches, purchases and models available on CGTrader.","title":"Analytics About page"},"batch_uploader":{"subtitle":"3D Model batch","text":"Upload multiple models or even your whole portfolio in one sitting!","title":"Batch uploader"},"empty_search":{"subtitle":"Browse other models","text":"See what other designers are selling on the marketplace.","title":"Empty search"},"payment_agreement_page":{"subtitle":"Sign your payment agreement","text":"Enter your payment details and prefered payment methods.","title":"Payment agreement page"},"projects_listing_page":{"subtitle":"Freelance 3D Projects","text":"Apply for unique 3D Projects â build your portfolio and earn extra money.","title":"3D Projects listing page"},"publisher":{"subtitle":"Upload another model","text":"Become more visible on the marketplace.","title":"Publisher"},"seller_handbook":{"subtitle":"Seller Handbook","text":"Find information about everything from earning rates to model presentation guidelines.","t
16518itle":"Seller handbook"}},"location_updated":"Location has been updated successfully","password":{"messages":{"send_failure":"We were not able to send you an e-mail with password recovery instructions! Please contact our support","send_success":"Password recovery instructions have been sent to your e-mail"}},"payout_options":{"monthly":"Monthly","undecided":"Undecided","weekly":"Weekly"},"removal":{"missing_params":"Unable to remove messages, please provide all required parameters","scheduled":"Records are scheduled for removal (type `%{type}`)"},"stats":{"followers_count":"Followers","items_count":"Models","likes_count":"Likes","message_response_rate":"Response Rate","message_response_time_avg":"Average Response Time","pageviews":"Views","reputation":"Reputation Score"},"suspended_messaging":"Due to continuous breaching of CGTrader communication policy, your ability to send messages was suspended. If you want to solve this issue, please contact CGTrader support.\n","unbanned":"User has been unbanned successfully","username":{"admin_changed":{"success":"Username has been successfully changed"},"changed":{"success":"Your username has been changed successfully."}}},"valvat":{"country_adjectives":{"at":"Austrian","be":"Belgian","bg":"Bulgarian","cy":"Cypriot","cz":"Czech","de":"German","dk":"Danish","ee":"Estonian","es":"Spanish","eu":"European","fi":"Finnish","fr":"French","gb":"British","gr":"Greek","hu":"Hungarian","ie":"Irish","it":"Italian","lt":"Lithuanian","lu":"Luxembourgian","lv":"Latvian","mt":"Maltese","nl":"Dutch","pl":"Polish","pt":"Portuguese","ro":"Romanian","se":"Swedish","si":"Slovenian","sk":"Slovakian"}},"wildcat_referrals":{"invitation_template_html":"Hi %{recipient_username},\n\nYour friend %{sender_username} is inviting you to join CGTraderâs freelance platform wildcat - take a look at some of the requests that should fit your type of work in %{specialization}!\n\n%{invitation_link}\n\nBest,\nCGTrader and %{sender_username}\n"},"will_paginate":{"container_aria_label":"Pagination","next_aria_label":"Next page","next_label":"Next \u0026#8594;","page_aria_label":"Page %{page}","page_entries_info":{"multi_page":"Displaying %{model} %{from} - %{to} of %{count} in total","multi_page_html":"Displaying %{model} \u003cb\u003e%{from}\u0026nbsp;-\u0026nbsp;%{to}\u003c/b\u003e of \u003cb\u003e%{count}\u003c/b\u003e in total","single_page":{"one":"Displaying 1 %{model}","other":"Displaying all %{count} %{model}","zero":"No %{model} found"},"single_page_html":{"one":"Displaying \u003cb\u003e1\u003c/b\u003e %{model}","other":"Displaying \u003cb\u003eall\u0026nbsp;%{count}\u003c/b\u003e %{model}","zero":"No %{model} found"}},"page_gap":"\u0026hellip;","previous_aria_label":"Previous page","previous_label":"\u0026#8592; Previous"}},"es":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"Adulto o contenidos violentos","ai_generated":"Contenido generado por IA","copyright":"infracción de copyright"}}},"errors":{"messages":{"embedded_script":"Este archivo no es compatible y no se puede subir. Prueba con otro archivo."}}},"api":{"profile":{"actions":{"contact":"Contactar","follow":"Seguir","follow_tooltip":"Start following this designer to get updates about his content and easily filter favorite designers in Search results","hide":"Ocultar","hire_me":"Contrátame","invite_client":"Iniciar un proyecto","mute_tooltip":"Hide this designerâs models in the Search results","take_over":"Take over","unfollow":"Dejar de seguir","unhide":"Mostrar","view_all_models":"View all Designer's Models"},"private_project_review":"Private Project"}},"browser":{"3d_models":"modelos 3D","3d_print":"impresión 3D","active_filters":{"polygons":"%{range} polÃgonos"},"adult_content":"Ver Edad +","animated":"Animado","breadcrumb":{"browse_by_type":"Explorar por tipo","collection":"packs 3D","free":"gratis","free_models":"Modelos en 3D gratuitos","free_print_models":"Modelos en 3D gratuitos de impresión","low_poly":"bajo poli","low_poly_models":"VR / AR / bajas-poli 3D Modelos","low_poly_print_models":"Modelos 3D de impresión Low-Poly","model_3d":"modelo 3d","model_3dp":"modelo de impresión 3D","models":"Modelos 3D","models_3d":"modelos 3D","models_3dp":"modelos de impresión 3D","models_variant_0":"Modelos 3D","models_variant_1":"Recursos 3D","models_variant_2":"Modelos VR","models_variant_3":"Modelos CG","models_variant_4":"Tienda de modelos 3D","models_variant_5":"Objetos 3D","print_models":"Archivos de impresión 3D","print_models_variant_0":"Modelos para impresión 3D","print_models_variant_1":"Modelos para impresoras 3D","print_models_variant_10":"Modelos 3D para impresión","print_models_variant_11":"Modelos 3D para imprimir","print_models_variant_12":"Archivos 3D para impresión","print_models_variant_13":"Modelos para impresora 3D","print_models_variant_14":"Modelos para impresión 3D","print_models_variant_15":"Modelos de impresión 3D","print_models_variant_16":"Archivos 3D imprimibles","print_models_variant_2":"Modelos 3D para imprimir","print_models_variant_3":"Modelos de impresión 3D","print_models_variant_4":"Archivos de impresión 3D","print_models_variant_5":"Archivos para impresión 3D","print_models_variant_6":"Archivos de impresora 3D","print_models_variant_7":"Modelos 3D imprimibles","print_models_variant_8":"Modelos 3D para imprimir","print_models_variant_9":"Modelos 3D impresos"},"buyer_engagement_program":"descuentos","categories":"categorÃas","category":{"meta":{"3d_models":"%{count} %{category} 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}","3d_print_models":"Descarga %{count} %{category} 3D modelos de impresión, disponible para su descarga en STL, OBJ y otros formatos de archivo, listo para imprimir con FDM, SLS y otras impresoras 3D.%{page}","animated_3d_models":"%{count} %{category} de animación en 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}","free_3d_models":"Descarga %{count} %{category} gratuitas 3D modelos, disponibles en MAX, OBJ, FBX, 3DS, formatos de archivo C4D, listos para VR / AR, animación, juegos y otros proyectos en 3D.%{page}","free_3d_print_models":"Descarga %{count} %{category} modelos libres de impresión 3D listos para la FDM, SLA, SLS y otras impresoras 3D, formatos disponibles STL, OBJ, 3DM y más.%{page}","lowpoly_3d_models":"Descargar %{count} VR / AR / bajo poli %{category} de modelos 3D listo para la realidad virtual, juegos y otras aplicaciones en tiempo real, disponible en FBX, OBJ, MAX, 3DS, formatos de archivo C4D. %{page}","rigged_3d_models":"%{count} %{category} aparejado 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}"}},"collection":"pack 3D","discounts":"descuentos","ext":{"meta":{"3d_models":"Descarga %{rounded_count} modelos 3D en formato %{format_upper}. Archivos %{format_lower} gratis y premium.","3d_print_models":"Descarga %{count}% {ext} archivos - %{software_name} modelos de impresión 3D listos para VR / AR, diseño 3D, animación, juegos y aplicaciones en tiempo real%{page}."}}
16518,"filter":"Filtrar","filter_button":"aplicar filtros","filters":{"adult_content_only":"Solo contenido para adultos","cgt_standard_only":"CGT Standard","collections_only":"Solo paquetes","content_filters":"Filtros de contenido","designer":"Diseñador","exclude_3d_print":"Excluir impresión 3D","exclude_adult_content":"Excluir contenido para adultos","exclude_ai_generated":"Excluir contenido generado por IA","exclude_editorial_license":"Excluir licencia editorial","exclude_free":"Excluir los gratuitos","file_format":"Formatos de archivo","following":"Siguiendo","free":"Gratis","has_marmoset":"Con visor 3D","has_video":"Con video","include_ai_generated":"Incluir contenido generado por IA","label":"Filtros","poly_count":"Cantidad de polÃgonos","print_ready":"Impresión 3D","stl_files":"Archivos STL","subscription":"Suscripción","type":"Tipo"},"formats":"formatos","free":"Gratis","free_models":"Mostrar sólo los modelos gratuitas","free_to_premium":{"main":"modelos 3D de %{category}","postfix":"en el listado premium.","prefix":"Necesitas algo especial? Puedes encontrar una mejor calidad"},"gallery":{"preview":"vista previa"},"game_ready":"juego listo","high_poly":"De alta poli","items_page_title":"Modelos 3D","license":{"exclude_branded":"Excluir Branded","exclude_editorial":"Excluir editorial","prompt":"Licencia","tooltip_more":"Lee mas","tooltip_text":" No mostrar los modelos que sólo pueden ser utilizados en fines no comerciales, educativos.","tooltip_title":"Excluir editorial:"},"low-poly":"Low-poli","low_poly":"Low-poli","meta":{"3d_models":"Descarga %{rounded_count} modelos 3D profesionales. Modelos gratis y premium para juegos, cine, VFX, AR/VR e impresión 3D. FBX, OBJ, BLEND, GLB y más.","3d_print_models":"Descarga %{rounded_count} modelos 3D para imprimir. Archivos STL gratis y premium para impresora 3D: figuras, miniaturas, piezas, decoración y más.","animated_3d_models":"Descarga %{rounded_count} modelos 3D animados con animaciones incluidas. Personajes y objetos game-ready en FBX, BLEND y GLB.","free_3d_models":"Descarga %{rounded_count} modelos 3D gratis, libres de derechos. Objetos 3D y archivos gratuitos en FBX, OBJ, BLEND y GLB para tus proyectos.","free_3d_print_models":"%{rounded_count} archivos STL gratis para impresión 3D. Descarga figuras y modelos 3D para imprimir gratis en tu impresora 3D.","lowpoly_3d_models":"Descarga %{rounded_count} modelos 3D low poly para juegos, AR/VR y render en tiempo real. Gratis y premium.","metaverse":"Ingrese el Metaverse con nuestra colección de modelos 3D de alto y bajo poli manipulado, animado y disponible en cualquier formato de archivo.","omniverse":"Construya su mundo virtual con nuestros modelos 3D listos para Omniverse. Elija entre modelos animados, manipulados y PBR con recuento de polÃgono alto y bajo.","page_prefix":"Página %{page_number} con","pbr_3d_models":"Descarga %{rounded_count} modelos 3D con texturas PBR para Unity, Unreal y motores en tiempo real.","rigged_3d_models":"Descarga %{rounded_count} modelos 3D riggeados con esqueleto, listos para animar en Blender, Maya, 3ds Max, Unity y Unreal.","snap-ar":"Con nuestros modelos 3D, puede unirse a un millón de Snapchatters usando Snap AR para crear experiencias de realidad aumentada divertidas.","spark-ar":"Alejuee su Facebook e Instagram con una variedad de modelos Spark AR 3D que están manipulados, animados y listos para usar.","stream_3d_print_models":"Navegar a través de una variedad de categorÃas corriente 3D modelo de impresión para descubrir algunos de los más extraordinarios diseños imprimibles 3D de 3D profesionales creadores.","textures":"%{count} activos Texturas 3D y materiales disponibles para su descarga en varios formatos incluyendo .tga .sbsar .jpeg .png .tiff y otra. %{page}","tiktok":"Haga que sus efectos de video sean más impresionantes con los modelos 3D Tiktok. Nuestra biblioteca puede satisfacer todas sus necesidades creativas y se actualiza constantemente.","unity":"Encuentre modelos 3D para su proyecto Unity en cualquier formato de archivo y cualquier recuento de poli. Todo lo que necesita para crear un entorno virtual único.","unreal":"Cree visualizaciones impresionantes con modelos 3D compatibles con un motor Unreal en cualquier formato de archivo. Nuestra biblioteca tiene modelos bajos y de alto poder de ca
16518da categorÃa."},"optimized":"Low-poli / PBR","page_title":{"animated_3d_models":"Modelos 3D Animados â Gratis y Premium","format_page":"Modelos 3D %{format_upper} â Archivos %{format_lower} Gratis y Premium","free_3d_models":"Modelos 3D Gratis â Descarga Libre de Derechos","free_3d_print_models":"Archivos STL Gratis â Modelos 3D para Imprimir","lowpoly_3d_models":"Modelos 3D Low Poly â Gratis y Premium","pbr_3d_models":"Modelos 3D PBR â Gratis y Premium","rigged_3d_models":"Modelos 3D Rigged (Riggeados) â Gratis y Premium","software_page":"Modelos 3D para %{software} â Descarga %{ext_file}","tag":{"3d_merged_premium":"%{tag_cap} 3D â Modelos 3D Gratis y Premium","3d_merged_premium_print":"%{tag_cap} para Imprimir en 3D â Archivos STL","3d_models":"%{tag_cap} 3D â Modelos 3D Gratis y Premium","3d_print_models":"%{tag_cap} para Imprimir en 3D â Archivos STL"}},"pbr":"PBR","per_page":"Por página","polygons_options":{"custom":"Rango personalizado","gt_250k":"250k +","lt_5k":"Hasta 5k","prompt":"recuento de poli","range_0_5000":"Hasta 5K","range_100k_250k":"100k a 250k","range_10k_50k":"10k a 50k","range_50k_100k":"50k a 100k","range_5k_10k":"5k a 10k"},"price":"Precio: $%{from}-%{to}","price_range":"Precio","print_ready":"3D de impresión listo","printable":"impresión 3D","reset_button":"Restablecer filtros","rigged":"Equipado","rounded_count":{"delimiter":".","exact":"%{n}","million":"%{n} M+","separator":",","thousand":"%{n}+"},"sale_off":"En oferta","search_placeholder":"Buscar palabras clave","show_all_formats":"Mostrar todos los formatos","simulation_ready":"Listo para simulación","software":{"meta":{"3d_models":"Descarga %{rounded_count} modelos 3D para %{software}. Archivos %{ext_file} gratis y premium, listos para importar."}},"sort_by":"Ordenar por","sort_by_options":{"best_match":"Mejor partido","highest_price":"Precio más alto","lowest_price":"precios má bajo","newest":"El más nuevo","oldest":"Más antiguo","sales":"Más vendidos","trending":"Tendencias"},"subcategory":{"meta":{"3d_models":"%{count} %{category} 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}","3d_print_models":"Descarga %{count} %{category} 3D modelos de impresión, disponible para su descarga en STL, OBJ y otros formatos de archivo, listo para imprimir con FDM, SLS y otras impresoras 3D.%{page}","animated_3d_models":"%{count} %{category} de animación en 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}","free_3d_models":"Descarga %{count} %{catgeory} gratuitas 3D modelos, disponibles en MAX, OBJ, FBX, 3DS, formatos de archivo C4D, listos para VR / AR, animación, juegos y otros proyectos en 3D.%{page}","free_3d_print_models":"Descarga %{count} %{category} modelos libres de impresión 3D listos para la FDM, SLA, SLS y otras impresoras 3D, formatos disponibles STL, OBJ, 3DM y más.%{page}","lowpoly_3d_models":"Descargar VR / AR / baja poli %{tag} modelos 3D listo para la realidad virtual, juegos y otras aplicaciones en tiempo real, disponible en FBX, OBJ, MAX, 3DS, formatos de archivo C4D.%{page}","rigged_3d_models":"%{count} %{category} aparejado 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}"}},"subtitle":{"aircraft":"Modelos %{count} aviones en 3D están disponibles para su descarga en nuestro mercado. CG %{airplanes_link} encajará en simulaciones, visualizaciones, anuncios y videos. %{drone_link} cuerpos y partes harán las delicias de los amantes de los vehÃculos voladores pequeños. Y los %{rigged_link} modelos están listos para ser importados en los motores de juego y ser usado para los proyectos de VR / AR animación o. Juegos de vuelo, simuladores y videos del CG tanto regulares como los de bajo poli pueden ser llenados con modelos 3D en la mayorÃa de los formatos más populares, incluyendo FBX, OBJ, MAX, 3DS, C4d.","animals":"%{count} de animales CG 3D - %{cats_link}, %{horses_link}, %{bears_link}, %{rhinos_link}, %{eagles_link}, %{lions_link},ficticia %{dragons_link} y más - están disponibles aquà para su descarga. La colección de la fauna en 3D va a satisfacer las necesidades de los anuncios o las escenas estáticas. También tenemos %{rigged_link} modelos para juegos, animación, producción de video y VR / AR proyectos. Use filtros para encontrar manipuladas, animada, bajo poli o 3D modelos gratuitas disponibles en la mayorÃa de formatos de archivo aceptados en la industria, incluyendo FBX, OBJ, MAX, 3DS, C4d, y otros.","animated":"Descarga %{rounded_count} modelos 3D animados con movimientos listos para usar: personajes, animales y objetos para juegos, cine y proyectos en tiempo real.","architectural":"%{count} de los modelos arquitectónicos 3D disponibles para su descarga contiene elementos y detalles de la arquitectura, construcción y diseño de ingenierÃa. Para comprar o descargar un modelo 3D gratis, navegar por las categorÃas anteriormente. Puede utilizar modelos para animaciones o juegos - algunos de ellos se aparejan y poli baja para servir VR / AR necesidades del proyecto. modelos en 3D están disponibles en formatos de archivo como FBX, OBJ, MAX, 3DS, C4d.","car":"Modelos %{count} coche en 3D están disponibles para su descarga. versiones de bajo poli de los cuales serán atractivos para los diseña
16518dores de juegos o VR / AR desarrolladores de aplicaciones, otros - para cineastas, animadores o anunciantes. De los coches clásicos y antiguos a las carreras y concepto visto en las pelÃculas, hay una gran variedad de modelos de automóviles 3D esencialmente en cualquier formato (FBX, OBJ, MAX, 3DS, C4d, etc.) que pueda necesitar. Utilice animados 3D y gratuitas modelos de prototipo y el tiempo de desarrollo se acortan.","character":"%{count} caracteres 3D modelos están disponibles para su descarga, por lo que navegar por esta categorÃa se encuentran los modelos de 3D %{human_link}, personas, figuras mÃticas, ciencia ficción %{robots_link}, ropa y otras cosas relacionadas con los personajes. De %{heart_link} y para hand_link se detalla realista %{male_link} o %{female_link} modelos. Varios de los modelos están manipuladas y podrÃa ser fácilmente añadidos a su juego, VR / AR proyecto, vÃdeo o animación. Ambos modelos de baja poli alta poli y se pueden encontrar en una serie de formatos, incluyendo FBX, OBJ, MAX, 3DS, C4d.","custom":"Aquà se puede comprar o descargar libres %{tag} modelos 3D. %{tag_heading_subtitle}","electronics":"%{count} electrónica 3D modelos disponibles para su descarga. Esto es una categorÃa para arquitectos, decoradores de interiores, diseñadores de niveles, los responsables de escena y otros creativos. modelos 3D de %{smartphones_link}, %{laptops_link}, %{cameras_link}, %{tvs_link} y más ayudarán a capturar con precisión la obsesión de la vida moderna con los dispositivos y la tecnologÃa. Hay modelos 3D disponibles en formatos de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d. Descargar gratis o comprar modelos de primera calidad y el uso de animación, juegos y proyectos VR / AR.","exterior":"%{count} de los modelos exteriores de arquitectura 3D disponibles para su descarga gama de fachadas, edificios urbanos, objetos paisaje, casas residenciales a construcciones industriales, edificios de infraestructura y %{city_link} modelos a escala real. Para comprar o descargar un modelo 3D gratis, navegar por las categorÃas anteriormente. Usar los filtros para encontrar aparejado, animado, bajo poli, libre de 3D o modelos ordenar por formato necesario, incluyendo FBX, OBJ, MAX, 3DS, C4d. Algunos de los activos son de baja poli y podrÃan ayudar a completar el medio ambiente en su juego o aplicación VR / AR.","food":"%{count} modelos 3D de alimentos están disponibles para download..Food sirve bien para crear escenas realistas de la vida doméstica. 3D frutas, verduras, bebidas y comidas son todos aquà para anuncios completas para los restaurantes, las aplicaciones de RA para una alimentación saludable, y visualizaciones arquitectos y diseñadores de interiores están trabajando. Ya sea que usted está buscando en 3D %{pizza_link} y %{ketchup_link} modelos o un modelo 3D de una boda %{cake_link}, están aquÃ. Varias versiones de baja poli están disponibles para aquellos en el juego, el desarrollo VR / AR. modelos 3D se pueden encontrar en FBX, OBJ, MAX, 3DS, formatos C4D.","formats":"Descarga %{rounded_count} modelos 3D en formato %{format_upper}, gratis y premium. Todos los archivos de esta página están disponibles en %{format_upper} nativo, sin conversión.","free_general":"Descarga %{rounded_count} modelos 3D gratis para proyectos personales y comerciales. Modelos 3D gratuitos y libres de derechos en FBX, OBJ, BLEND y GLB, sin costos ocultos.","free_no_tag":"%{model_count} 3D gratis %{tag} modelos listo para la impresión en 3D. Descargar %{tag} modelos de impresión en 3D gratuitos, formatos de archivo disponibles, incluyendo STL, OBJ, 3DM, 3DS, MAX. modelos 3D están listos para ser utilizado con FDM, SLA, SLS y otros tipos de impresoras 3D.","free_printable":"Descarga %{rounded_count} archivos STL gratis: modelos 3D para imprimir gratis, probados por la comunidad. Figuras, miniaturas, piezas útiles y decoración para tu impresora 3D.","free_tag":"Gratis 3D %{tag} modelos disponibles para su descarga. Disponible en varios formatos de archivo, incluyendo MAX, OBJ, FBX, 3DS, STL, C4d, mezcla, MA, MB. Encuentra profesional %{tag_link} para cualquier proyecto de diseño en 3D, como la realidad virtual (VR), la realidad aumentada (AR), juegos, visualización en 3D o animación.","furniture":"Modelos %{count} muebles 3D disponibles para su descarga incluyen mesas, sillas, sofás, camas y otros muebles en una variedad de texturas (madera, metal, etc.) y estilos (%{retro_link}, %{modern_link}, etc. ). Esta categorÃa es para cualquier persona involucrada con la arquitectura y diseño de interiores, asà como los anunciantes y los animadores. activos en tiempo real pueden ayudar a juegos y aplicaciones VR / AR a los desarrolladores de proyectos completos. Usar los filtros para encontrar aparejado, animada, bajo poli o 3D modelos libres. Disponible en cualquier formato de archivo FBX incluyendo, OBJ, MAX, 3DS, C4d.","general":"Descarga o compra %{rounded_count} modelos 3D profesionales: diseños 3D y objetos 3D para juegos, cine, VFX, AR/VR e impresión 3D. Gratis y premium, en FBX, OBJ, BLEND, GLB y más de 100 formatos.","high_poly":"Comprar o descarga de animación 3D Profesional modelos listos para su uso en proyectos de CG, producción de cine y vÃdeo, animación, visualizaciones y otros. Los activos están disponibles para su descarga en muchos formatos aceptados por la industria, incluyendo MAX, OBJ, FBX, 3DS, UE4 y otra. Si estás en busca de activos de alta calidad en 3D poli, tenemos una biblioteca de arte digital lÃder para todas sus necesidades.\n","household":"Modelos %{count} 3D hogar disponibles para su descarga se pueden utilizar para dar detalles a las salas. Es posible que desee poner un juego de cena en la mesa, tener recipientes pimienta y sal a interior de la cocina completa, o poner un poco de %{lights_link} y %{flowers_link}
16518 cerca de la cama para crear sensación de lujo. Si usted es un diseñador, animador, VR application / AR o juego interior creador, esta categorÃa es para usted. Usar los filtros para encontrar aparejado, animada, bajo poli o 3D modelos libres. Disponible en cualquier formato de archivo FBX incluyendo, OBJ, MAX, 3DS, C4d.","industrial":"%{count} modelos industriales 3D disponibles para su descarga - materiales de construcción, %{engineering_link} herramientas, maquinaria y %{containers_link} -, permitirán a los detalles y elementos interactivos, manipuladas para crear entornos animados. Esta es una categorÃa ideal para simulaciones / VR / AR o los desarrolladores que crean %{construction_link} nivel de sitio en el juego. Los modelos 3D servirán profesionales de la construcción visualizaciones precisas que trabajan con el software variados como modelos en formatos tales como FBX, OBJ, MAX, 3DS, C4d están disponibles.","interior":"%{count} modelos de interiores en 3D están disponibles para su descarga e incluyen elementos y detalles utilizados en la arquitectura, la construcción y la ingenierÃa, el diseño de interiores. Para comprar prima o descargar un modelo de libre 3D, navegar por las categorÃas mencionadas anteriormente. Puede utilizar modelos para animaciones o juegos - algunos de ellos se aparejan, animada y poli baja. Disponible en una variedad de formatos de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.","low_poly":"Descarga %{rounded_count} modelos 3D low poly: assets ligeros y game-ready para juegos, AR/VR y proyectos móviles.","military":"%{count}
16518 3D modelos militares de armas, las armas, %{swords_link} y la artillerÃa moderna y histórica utilizados por las fuerzas militares y de defensa personal están disponibles para su descarga. Puede utilizar modelos para juegos o contenido de VR / AR - algunos de ellos son polÃgonos optimizados y listos para ser añadido a un motor de juego. modelos CAMBIAR LAS animados pueden facilitar su trabajo más. Seguramente encontrará activos relevantes, ya que hay muchos modelos 3D disponibles en cualquier formato de archivo que pueda necesitar (FBX, OBJ, MAX, 3DS, C4d, etc.).","not_custom":"Descarga %{rounded_count} modelos 3D de %{tag_low} para tu proyecto. Modelos de %{tag_low} gratis y premium, realistas y estilizados, en FBX, OBJ, BLEND y GLB.","optimized":"Los modelos que tienen un menor número de polÃgonos son los más utilizados en aplicaciones en tiempo real que requieren un procesamiento rápido, como la realidad virtual (VR), la realidad aumentada (AR), la realidad mixta (MR), la realidad cruz (XR) y los juegos, especialmente los juegos móviles. Elija entre nuestra colección de modelos CAMBIAR LAS animados de manera fácil utilizarlos en sus aplicaciones en tiempo real. Obtener 3D activos para entornos, recoger objetos o accesorios, comprar completas modelo 3D colecciones, paquetes y paquetes con todo lo que su necesidad de juego de fuerzas. Guardar el tiempo de desarrollo y los costos, las experiencias prototipo realizar o utilizar modelos 3D como marcadores de posición en su proyecto. FÃsicamente representación basada, o PBR, denota modelos que se vuelven precisa y consistente en cualquier condición de iluminación debido a la texturización flujos de trabajo usados ââen el proceso de creación.\n","pbr":"Descarga %{rounded_count} modelos 3D con texturas PBR (renderizado basado en fÃsica): materiales realistas y consistentes para Unity, Unreal y otros motores en tiempo real.","plant":"%{count} Plant 3D modelos disponibles para su descarga contienen flora organismos que crecen como plantas domésticas y en la naturaleza, tales como flores, %{trees_link}, hierba, enredaderas, verdor, hierbas, plantas vivaces, plántulas, brotes, arbustos, notas, coles, vides, malas hierbas. Para comprar prima o descargar un modelo 3D gratis, navegar por las categorÃas de arriba para encontrar el mejor ajuste entre los modelos disponibles. Use filtros para encontrar manipuladas, animada, bajo poli (para su uso en juegos y aplicaciones de VR / AR) modelos, o para filtrar los formatos requeridos (en modelos FBX, OBJ, MAX, 3DS, C4d y más están disponibles).","printable":"Descarga %{rounded_count} modelos 3D para imprimir en tu impresora 3D. Archivos STL gratis y premium probados en impresoras FDM y de resina: figuras, miniaturas, piezas y decoración.","printable_merged_tag":"Descarga %{rounded_count} figuras y modelos de %{tag_low} para imprimir en 3D. Archivos STL gratis y premium para impresoras FDM y de resina.","printable_tag":"Descarga %{rounded_count} figuras y modelos de %{tag_low} para imprimir en 3D. Archivos STL gratis y premium para impresoras FDM y de resina.","rigged":"Descarga %{rounded_count} modelos 3D rigged (riggeados): personajes, animales y criaturas con esqueleto, listos para animar en Blender, Maya, 3ds Max, Unity y Unreal.","scanned":"%{count} escaneado 3D modelos están disponibles para su compra o descarga gratuita. Modelos 3D examinados están preparados para la animación, juegos y proyectos VR / AR. Puede encontrar modelos 3D de objetos que se encuentran en la naturaleza tales como rocas y superficies naturales, humanos y otros objetos de la vida real aquà ... y no se puede estar más realista que esto. Usar los filtros para encontrar aparejado, animada, bajo poli o 3D modelos libres. Disponible en cualquier formato de archivo FBX incluyendo, OBJ, MAX, 3DS, C4d.","science":"%{count} ciencia 3D modelos disponibles para su descarga en esta categorÃa van desde la medicina, la biologÃa, la fÃsica, la quÃmica y la otra campos mundo real objetos relacionados con la ciencia y la tecnologÃa: equipos de laboratorio, los organismos microscópicos y el mund
16518o subatómico. No busque más,%{cell_link}, %{skull_link} y %{skeleton_link} 3D modelos se puede encontrar aquÃ! Para comprar o descargar gratis 3D activos, navegar por las categorÃas anteriormente. Puede utilizar modelos manipuladas para los de animación o de bajo-poli para juegos y proyectos VR / AR. Ambos modelos 3D de alta calidad libres y se pueden encontrar en una serie de formatos de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.","scripts_plugins":"%{count} 3D Scripts / Complementos están disponibles para su descarga. 3D Scripts / Complementos pueden ser añadidos a distintos programas informáticos y se utilizan para hacer su trabajo de manera más eficiente la tuberÃa. Filtrar por formatos para encontrar herramientas de adaptación de su software preferido.\n","software_page":"Descarga %{rounded_count} modelos 3D para %{software}, gratis y premium. Los archivos %{ext_file} nativos se importan directamente; otros formatos se convierten en pocos clics.","space":"%{count} modelos de espacio en 3D están disponibles para su descarga en CGTrader. El espacio es una categorÃa completa de poli baja, los modelos de juego listo de la ciencia ficción %{spaceships_link}. También hay %{asteroids_link}, planetas (incluyendo la Luna y Marte, a la colonización simular) y el espacio realista %{shuttles_link} para el inclinado de forma más cientÃfica. Los modelos sin duda se pueden utilizar en juegos de simulador de realidad virtual, espacio de aplicaciones de RA y animaciones para demostrar al mundo exterior del planeta %{earth_link}. Los filtros están aquà para ayudarle a buscar, animados, activos o modelos de bajo-poli manipuladas en formatos especÃficos, incluyendo FBX, OBJ, MAX, 3DS, C4d.","sports":" %{count} Sports 3D modelos disponibles de equipos juntos nido que se utiliza para actividades recreativas, entretenimiento, ejercicio, ocio, pasatiempo placentero, divertido, asà como juegos, juguetes infantiles y una amplia gama de instrumentos musicales. Para comprar o descargar un modelo 3D gratis en cualquier formato de archivo necesario, incluyendo FBX, OBJ, MAX, 3DS, C4d, navegar por las categorÃas anteriormente. Puede utilizar modelos de animación, juegos, proyectos VR / AR - muchos de ellos estén provistas, bajo poli o ya animado.","test":{"airplane":"Entusiastas de la aviación, escuchen, nunca ha sido tan fácil de obtener el modelo perfecto 3D avión impresa para su juego de mesa o colección modelo. Buscar a través de modelos de aviones imprimible %{model_count} 3D y encontrar un modelo que sólo tiene que tener en ese estante. modelos reales de avión descubrir o los confeccionados. Buscar nuevos diseños o algo que una cuenta atrás desde el tiempo de los hermanos Wright. Es también un regalo perfecto para cualquier niño que sueña con ser un piloto cuando sea grande. Comprar y descargar un modelo de impresión 3D, imprimir por sà mismo o someter el modelo a uno de nuestros proveedores de servicios de impresión en 3D para tenerlo impreso y enviado a usted en ningún momento!\n","anatomy":"%{model_count} modelos 3D anatomÃa disponibles para su descarga en nuestro mercado. Explora la anatomÃa humana con alta - hueso poli, músculo, modelos de órganos. Perfecto para cualquier proyecto educativo o cientÃfico. Utilizar modelos para imprimir en 3D para mejorar la experiencia de la educación. Crear impresionantes animaciones y juegos de video con nuestra\n amplia biblioteca de modelos manipuladas. Utilice nuestro sistema de filtrado avanzado para encontrar fácilmente poli baja, animado, PBR,\n modelos fraudulentas o cualquier cosa que se adapte mejor a sus necesidades. Elegir entre una gran cantidad de formatos de archivo, incluyendo la\n la mayorÃa de los más populares como FBX, OBJ, MAX, 3DS, C4d.\n","castle":"Su propia asombrosa 3D castillo impresa es un clic de distancia! Buscar varios modelos del castillo 3D listos para la impresión 3D. Crear una fortaleza de fantasÃa único para la sesión de D \u0026 D o cualquier otro juego de mesa RPG medieval. Estas fortalezas medievales son un regalo increÃble para cualquier entusiasta del tablero de juego o una gran adición a su propia cole
16518cción. Encontrar el modelo 3D perfecta para pintar aficionados o una parte de una especie de juguete para los niños. La compra y descarga tu diseño del castillo 3D elegido, imprimirlo con su propia impresora, o someter el modelo a uno de nuestros proveedores de servicios de impresión en 3D para tenerlo impreso y enviado a usted.\n","dice":"La suerte no se acabará con 3D impreso dados! Si quieres juegos de dados de partida ideal para la noche tablero de juego, no busque más. Aquà se puede elegir entre %{model_count} gratuitas modelos dados en 3D listos para la impresión 3D. Cuando el juego ha terminado, utilice estas hermosas modelos como accesorio. Descargar gratis 3D modelos dados imprimibles, formatos de archivo disponibles, incluyendo STL, OBJ, 3DM, 3DS, MAX. Nuestra modelos 3D están listos para ser utilizado con FDM, SLA, SLS y otros tipos de impresoras 3D. Hacer su juego un poco más interesante y obtener sus dados impresos en 3D!\n","drone":"3D imprimir y construir su propio avión no tripulado o encontrar piezas de reemplazo. 3D impreso aviones no tripulados son fáciles de montar y reparación después de un aterrizaje de emergencia. Descubre un modelo con la posición de montaje de la cámara perfecta o solicitud de alteraciones mÃnimas. Perfecto para actividades de ocio diversión, la fotografÃa aérea, videografÃa o mapeo. Encontrar y comprar un modelo de avión no tripulado 3D de diseño único que se adapte a todas sus necesidades. Imprimir por sà mismo o someter el modelo a uno de nuestros proveedores de servicios de impresión en 3D para tenerlo impreso y enviado a usted en ningún momento! Obtener su propio avión no tripulado 3D impreso y estudiar los cielos azules de ancho!\n","pokemon":"Pikachu, yo te elijo! Elegir entre un montón de monstruos de bolsillo listos para la impresión 3D. Gran para ampliar su colección de pokemon impresa en 3D. Buscar y tropezar con los mejores diseños, pokemon detallada para su próximo juego de mesa con amigos. La compra y descarga tu Pokémon en 3D, imprimirlo con su propia impresora 3D, o someter el modelo a uno de nuestros proveedores de servicios de impresión en 3D para tenerlo impreso y enviado a usted. Después de todo, esta es una de las mejores cosas a la impresión 3D!\n","ring":"Joyas impresa en 3D es el nuevo negro en la industria, como son impresos en 3D anillos! Buscar una enorme cantidad de %{model_count} modelos de anillos para imprimir gratis 3D. Navegar a través de diseños únicos y encontrar algo hecho sólo para usted. No se puede encontrar nada por sà mismo en la tienda? O tal vez quiere un accesorio exactamente como la que su personaje de la pelÃcula favorita tiene? Elegir entre una gran cantidad de formatos de archivo, incluyendo STL, OBJ, 3DM, 3DS, MAX. modelos 3D están listos para ser utilizado con FDM, SLA, SLS y otros tipos de impresoras 3D, por lo que navegar a través de nuestra selección y tratar en su nuevo anillo favorito.\n","shoes":"Las grandes marcas están a bordo con 3D impreso zapatos y ahora se puede compartir la experiencia también. Examinar y busque diseños libres del zapato imprimibles - zapatillas de deporte de los talones de moda hay una gran cantidad de modelos de listas para imprimir a la espera de que los pruebe. Hacer el perfecto resultado mediante la selección de materiales, el ajuste de la suavidad y el tamaño. Elija entre 146 modelos de zapatos libres 3D y descargarlos en formatos de archivo disponibles, incluyendo STL, OBJ, 3DM, 3DS, MAX. Los diseños están listos para ser utilizado con FDM, SLA, SLS y otros tipos de impresoras 3D. Ponte los zapatos impresos en 3D hoy en dÃa!\n","textures":"Buscar a través de una vasta cantidad de %{model_count} CG texturas disponibles para su descarga, incluidos los materiales hechos bellamente. Navegar a través de la categorÃa y encontrar tejido sin costuras, madera, metal, plástico, texturas de ladrillo hasta el final ayuda a su proyecto más rápido. Utilice nuestra búsqueda avanzada para encontrar texturas manipuladas y animados para el juego o la creación de vÃdeo. Nuestros materiales están disponibles para su descarga en varios formatos, incluyendo TGA, SBSAR, JPG, PNG, TIFF y otros, asà que no pierda tiempo y encontrar texturas CG-listas para usar para casi cualquier imaginable proyecto.\n"},"various":"%{count} diferentes modelos en 3D que no encuentran fácilmente su lugar en otras categorÃas están disponibles para su descarga. %{rocks_link}, %{clouds_link}, %{logos_link}, %{cigarette_link} y otros modelos no categorizado en 3D que pueda necesitar para completar su juego, animación o proyecto VR / AR están aquÃ. Use filtros para encontrar manipuladas, animada, bajo poli o 3D modelos libres, o bien ordenar a cabo por los formatos disponibles, tales como FBX, OBJ, MAX, 3DS, C4d.","vehicle":"3D modelos %{count} de vehÃculos disponibles para descarga incluyen camiones, %{ambulances_link}, autobuses, %{bikes_link} y moto - Esta categorÃa es para las personas que quieren que sus calles se llenen de vehÃculos ya sea realista o de ciencia ficción. Aquellos que hacen los juegos de simulación o aplicaciones VR / AR, creativos en la producción de vÃdeo o incluso el diseño de carteles más probable es encontrar formatos de archivo más populares, tales como FBX, OBJ, MAX, 3DS, C4d utilizable. Otros vehÃculos de transporte terrestre como modelos %{tractor_link} 3D tren o también se pueden encontrar en esta vasta colección. Usar los filtros para encontrar aparejado, animada, bajo poli o libre 3D modelos más rápido.","watercraft":"%{count} motos acuáticas 3D modelos disponibles para su descarga incluyen %{boats_link}, %{yachts_link}, %{ships_link} y otros vehÃculos acuáticos pasando de todo tipo. Los modelos de baja manipuladas 3D-poli va a hacer bien en los videojuegos, VR / AR proyectos, asà como animaciones, mientras que los modelos CG están aquà para sus escenas y otras aplicaciones en las que la fidelid
16518ad visual es más importante que polycount. Los modelos están disponibles en cualquier formato de archivo, incluyendo, pero no limitado a FBX, OBJ, MAX, 3DS, C4d."},"tag":{"meta":{"3d_merged_premium":"Descarga %{rounded_count} modelos 3D de %{tag_low}, gratis y premium. En FBX, OBJ, BLEND, GLB y más, para juegos, cine, AR/VR e impresión 3D.","3d_merged_premium_print":"Descarga %{rounded_count} archivos STL de %{tag_low} para imprimir en 3D, gratis y premium, probados en impresoras FDM y de resina.","3d_models":"Descarga %{rounded_count} modelos 3D de %{tag_low}, gratis y premium. En FBX, OBJ, BLEND, GLB y más, para juegos, cine, AR/VR e impresión 3D.","3d_print_models":"Descarga %{rounded_count} archivos STL de %{tag_low} para imprimir en 3D, gratis y premium, probados en impresoras FDM y de resina.","animated_3d_models":"%{count} %{tag} de animación en 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}","free_3d_models":"Descarga %{count} %{tag} libres 3D modelos, disponibles en MAX, OBJ, FBX, 3DS, formatos de archivo C4D, listos para VR / AR, animación, juegos y otros proyectos en 3D.%{page}","free_3d_print_models":"Descarga %{count} %{tag} gratis modelos de impresión 3D listos para la FDM, SLA, SLS y otras impresoras 3D, formatos disponibles STL, OBJ, 3DM y más.%{page}","lowpoly_3d_models":"Descargar %{count} VR / AR / bajo poli %{tag} modelos 3D listo para la realidad virtual, juegos y otras aplicaciones en tiempo real, disponible en FBX, OBJ, MAX, 3DS, formatos de archivo C4D.%{page}","rigged_3d_models":"%{count} %{tag} aparejado 3D modelos disponibles para su descarga en cualquier formato de archivo, incluyendo FBX, OBJ, MAX, 3DS, C4d.%{page}"}},"title":{"download":"| descargar","files":"archivos 3D","formats":"Modelos 3D %{format_upper}","free":"Modelos 3D Gratis","free_printing":"Archivos STL Gratis","free_tag":"Libres %{selected_tag} ââmodelos 3D","general":"Modelos 3D","high_poly":"Comprar o descargar %{selected_filter}Modelos 3D","landing":{"animated_3d_models":"Modelos 3D Animados","lowpoly_3d_models":"Modelos 3D Low Poly","pbr_3d_models":"Modelos 3D PBR","rigged_3d_models":"Modelos 3D Rigged"},"low_poly":"%{selected_filter}3D Modelos","newest_cg":"Nuevos y últimos modelos 3D","newest_print":"Nuevos y últimos modelos de impresión 3D","page_prefix":"Página %{page_number} de ","pbr":"PBR 3D Modelos","printing":"Modelos 3D para Imprimir â Archivos STL","sales_cg":"Modelos 3D más vendidos","sales_print":"Modelos de impresión 3D más vendidos","software_page":"Modelos 3D para %{software}","tag_heading":{"cg":"Libres %{tag} modelos de impresión 3D","filter":"%{selected_filter}%{tag} Modelos 3D","general":"%{tag_cap} 3D â Modelos 3D","merged_premium_print_tag":"%{tag_cap} para Imprimir en 3D","merged_premium_tag":"%{tag_cap} 3D â Modelos 3D","printable":"%{tag_cap} para Imprimir en 3D"},"trending_cg":"Modelos 3D de tendencia","trending_print":"Modelos de impresión 3D de tendencia"}},"cart":{"request_invoice_failed":"Vaya. Algo salió mal.","request_invoice_successful":"La solicitud de factura se ha enviado correctamente.","shareable_cart_created":"El carrito se ha compartido correctamente.","shareable_cart_failed":"Vaya. Algo salió mal.","subscription_covered_items_removed":"Eliminado de tu carrito: %{titles}. Ya está incluido en tu suscripción.","subscription_covered_order_refused":"Tu suscripción ahora incluye %{titles}, por lo que no te hemos cobrado. Descárgalo desde tu suscripción."},"categories":{"cg":{"header_title_html":"Modelos 3D","text":"Encuentra el contenido 3D exacto para tus necesidades, incluyendo AR/VR, juegos, publicidad, entretenimiento y más."},"head-title":{"cg":"Modelos 3D â Descarga Gratis y Premium","cg-models":{"sort-by":{"newest":"Los modelos 3D más nuevos","top-selling":"Los modelos 3D más vendidos","trending":"Modelos 3D de tendencia"}},"print":"Modelos 3D para Imprimir â Archivos STL","print-models":{"sort-by":{"newest":"Archivos de impresión 3D más nuevos","top-selling":"Archivos de impresión 3D más vendidos","trending":"Archivos de impresión 3D de tendencia"}}
16518,"product-type":{"plural":{"capital":{"cg":"Modelos 3D","cg-merge-premium":"Modelos 3D: descargas gratuitas y premium","print":"Archivos y Modelos de Impresión 3D","print-merge-premium":"%{tag} Archivos de impresión 3D: modelos STL gratuitos y premium"},"lower":{"cg":"modelos 3d","print":"archivos y modelos de impresión 3D"}},"singular":{"capital":{"cg":"Modelo 3D","print":"Modelo 3D Printing"},"lower":{"cg":"modelo 3d","print":"modelo de la impresión 3d"}}}},"index":{"browse_all":"Ver todos los modelos","info-section__description_1_html":"Compra o descarga gratuita de modelos 3D profesionales listos para usar en proyectos CG, producción de video, animación, visualizaciones, juegos, VR/AR y más. Los archivos están disponibles en \u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eformatos ampliamente aceptados\u003c/a\u003e como MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB y otros. Si buscas modelos de alta calidad o listos para tiempo real, tenemos una biblioteca digital lÃder para cubrir cualquier necesidad.","info-section__description_1_printable_html":"Archivos, impresiones y modelos 3D profesionales listos para imprimir en casa con impresoras 3D FDM de escritorio o SLS industriales, disponibles en muchos formatos industriales, incluidos OBJ, \u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003e, WRL. Si eres un aficionado a la impresión 3D, creador, educador o una empresa que crea prototipos mediante impresión 3D, nuestras decoraciones para el hogar, accesorios de gadgets de moda, piezas de moda llamativas, joyerÃa única, piezas mecánicas y una variedad de miniaturas seguramente te darán un impulso de inspiración.","info-section__heading_1_html":"Explorar \u003cstrong\u003ecategorÃas\u003c/strong\u003e de modelos 3D","info-section__heading_1_printable_html":"Explora Modelo 3D de impresión \u003cstrong\u003e CategorÃas \u003c/strong\u003e","info-section__heading_2_html":"\u003cstrong\u003eMercado\u003c/strong\u003e de modelos 3D","info-section__heading_2_printable_html":"¿Qué \u003cstrong\u003emás\u003c/strong\u003e?"},"marketplace":{"3d-printing":{"link_text":"Navegar en 3D de impresión Modelos","text":"Encontrar modelos de impresión 3D para su impresora 3D.","title":"Los modelos de impresión 3D"},"blender_text":"Descubre miles de modelos 3D Blender disponibles en formato mezcla.","browse":"Vistazo","cinema-4d_text":"Destape miles de modelos Cinema 4D de alta calidad disponibles en el formato de archivo de C4d.","discounted":{"link_text":"Buscar modelos 3D con descuento","text":"Comprar modelos 3D profesionales con un descuento.","title":"Modelos en 3D con descuento"},"low-poly":{"link_text":"Modelos en 3D Navegar bajo poli","text":"3D modelos de poli bajas listo para videojuegos, VR y AR aplicaciones en tiempo real.","title":"Poli bajas 3D Modelos"},"pbr":{"link_text":"Modelos 3D Navegar PBR","text":"FÃsicamente modelos basados ââen la representación 3d.","title":"Modelo 3D PBR"},"scripts_apps":{"link_text":"Ver todas las","text":"scripts y plugins 3D para hacer su tuberÃa de modelado 3D más eficiente.","title":"Scripts y Aplicaciones"},"sketchup_text":"Navegar por la amplia selección de modelos de SketchUp 3D para sus arquitectónicos interiores y diseños de videojuegos,.","textures":{"link_text":"Recorrer las texturas","text":"texturas listas para su uso para ahorrar algo de tiempo la preparación de sus modelos en 3D.","title":"Texturas"},"zbrush_text":"Encuentra formato de archivo ZTL 3D activos para su escultura digital, 3D modelado, texturizado y proyectos de pintura."},"meta-description":{"cg":"Descarga %{rounded_count} modelos 3D profesionales. Modelos gratis y premium para juegos, cine, VFX, AR/VR e impresión 3D. FBX, OBJ, BLEND, GLB y más.","print":"Descarga %{rounded_count} modelos 3D para imprimir. Archivos STL gratis y premium para impresora 3D: figuras, miniaturas, piezas, decoración y más."},"more":{"designers":{"link_text":"Lista de exploración de diseñadores 3D","text":"Recorrer miles de carteras de diseño 3D y encontrar exactamente lo que necesita para su aplicación.","title":"Encontrar mejores diseña
16518dores 3D"},"projects":{"link_text":"Más información sobre Proyectos en 3D","text":"Contratar en calidad independientes 3D artistas y resolver todos los desafÃos de modelado personalizados.","title":"CGTrader Proyectos 3D"},"visualization":{"link_text":"Aprende más","text":"Convertir sus productos en modelos 3D fotorrealistas para el comercio electrónico y otras aplicaciones empresariales.","title":"La visualización en 3D para el comercio electrónico"}},"navbar":{"aircraft":"Aeronave","animal":"Animales","animals":"Animales","architectural":"Arquitectónico","art":"Arte","car":"Coche","character":"Personaje","exterior":"Exterior","fashion":"Moda","food":"Comida","furniture":"Mueble","gadgets":"Artilugio","games-toys":"Juegos y Juguetes","hobby-diy":"ManÃa y bricolaje","house":"Casa","household":"Casa","industrial":"Industrial","interior":"Interior","jewelry":"JoyerÃa","military":"Militar","miniatures":"Miniaturas","plant":"Planta","science":"Ciencias","space":"Espacio","vehicle":"VehÃculo","watercraft":"Motos Acuáticas"},"print_models":{"hero_title_html":"Modelos 3D para Imprimir â Archivos STL","subtitle":"Encontrar el derecho exacto contenido de la impresión 3D para sus necesidades","title_html":"Comprar Profesional \u003cstrong\u003e 3D modelos para impresión \u003c/strong\u003e"},"profile":{"collection":"packs 3D","free":"Modelos 3D gratuitos","high_poly":"Modelos 3D de alta poligonización","optimized":"Modelos 3D Low-Poly/PBR","printable":"Modelos para impresión 3D"},"seo":{"cg":{"aircraft":"Esta categorÃa abarca los aviones 3D. CG { \"slug\": \"avión\", \"title\": \"aviones\"} encajará en simulaciones, visualizaciones, anuncios y videos. { \"slug\": \"drone\", \"title\": \"Drone\"} cuerpos y partes harán las delicias de los amantes de los vehÃculos voladores pequeños. Y el { \"slug\": \"aeronaves\", \"title\": \"aparejado modelos\", \"active_filter\": \"rigged\"} están listos para ser importados en los motores de juego.\n","animals":"La colección de la fauna 3D - { \"slug\": \"gato\", \"title\": \"gatos\"}, { \"slug\": \"caballo\", \"title\": \"caballos\"}, { \"slug\": \"oso\" , \"title\": \"osos\"}, { \"slug\": \"rinoceronte\", \"title\": \"rinocerontes\"}, { \"slug\": \"águila\", \"title\": \"águilas\"}, { \"slug\" : \"león\", \"title\": \"leones\"} y más - se pueden encontrar aquÃ. Los animales CG 3D va a satisfacer las necesidades de los anuncios o las escenas estáticas. También tenemos { \"slug\": \"animal\", \"title\": \"amañadas animal\", \"active_filter\": \"rigged\"} modelos para juegos.\n","architectural":"{ \"slug\": \"escalera\", \"title\": \"Escalera\"}, { \"slug\": \"chimenea\"}, 3D modelos, asà como decoraciones como { \"slug\": \"marco\"}, { \"slug\": \"almohada\"}, o { \"slug\": \"lámpara\"} se pueden encontrar en la amplia categorÃa del detalle del coche arquitectónica contiene 3D modelos de automóviles, { \"slug\": \"coche\", \"title\": \"low poly\", \"active_filter\": \"low_poly\"} biblioteca de modelos. Interior y exterior pueden ser utilizados para construir las dos cocinas digitales y dormitorios, asà como habitaciones del castillo y mazmorras si usted es un arquitecto, ingeniero o desarrollador de juegos independiente.\n","car":"CategorÃa de coches del automóvil 3D contiene modelos, versiones \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e baja poli \u003c/a\u003e de los cuales serán atractivos para los diseñadores de juegos, otros - a los directores de cine o anunciantes. De los coches clásicos a las carreras de coches y pistas a los conceptuales, hay una gran variedad de modelos de automóviles en 3D.\n","character":"En esta categorÃa se encuentran los modelos 3D de { \"slug\": \"humana\"}, la gente, la ciencia ficción, ropa y otros. Desde { \"slug\": \"corazón\"} y { \"slug\": \"mano\"} detallada realista {\"slug\": \"macho\"} o {\"slug\": \"hembra\"} modelos. Algunos de los modelos son manipuladas y podrÃa ser fácilmente añadidos a su juego o animación.\n","electronics":"La electrónica es una categorÃa para arquitectos, decoradores de interiores, diseñadores de niveles, los responsables de escena y otros creativos. modelos 3D de { \"slug\": \"teléfono inteligente\", \"title\": \"teléfonos inteligentes\"}, { \"slug\": \"portátil\", \"title\": \"portátiles\"}, { \"slug\": \"cámara\", \"tÃtulo \": 'cámaras'}, {\"slug\": 'TV', 'title': 'TV'}
16518 y más ayudará a capturar con precisión la obsesión de la vida moderna con los dispositivos y la tecnologÃa.\n","engineering-parts":"Ventanas, tuberÃas, herrajes para puertas correderas y otros bits que son necesarios para proyectos CAD e incluso planes de bricolaje se incluyen en esta categorÃa. Aquà es donde se pueden encontrar modelos 3D de los fabricantes mundiales como ANVER, Dynatec y la FCI.\n","exterior":"Exteriores arquitectónicos Examinar en fachadas de edificios urbanos, a los objetos paisaje, casas residenciales, construcciones industriales, y la escala completa en 3D { \"slug\": \"ciudad\"} modelos. Algunos de los activos son poli baja y podrÃa ayudarle a completar su juego o aplicación VR / AR.\n","food":"Alimentos ayuda a crear escenas realistas de la vida doméstica. 3D frutas, verduras, bebidas y comidas están todos aquÃ. Los anuncios para los restaurantes, las aplicaciones de RA para una alimentación saludable. Ya sea que estabas buscando en 3D { \"slug\": \"pizza\"} o una boda { \"slug\": \"torta\" } modelo, ya están aquÃ.\n","furniture":"3D tablas, sillas, sofás, camas en una variedad de texturas (madera, metal, etc.) y estilos ({ \"slug\": \"retro\"}, { \"slug\": \"modernas\"}, etc.) son On- mano. Esta categorÃa es para cualquier persona involucrada con la arquitectura y diseño de interiores, asà como los anunciantes.\n","furniture-set":"Si necesita una silla antigua por igual buscando y sofá mirando, o conjunto completo de menaje, este es un lugar de imitar a este conjuntos de categorÃas de cobro de modelos de muebles en 3D de cocina y sala de estar a la oficina y comedor sala de juegos de muebles. Esto ayuda a los interiores de diseño o nivel de habitaciones especialista en construcción con elementos coincidentes.\n","household":"Modelos artÃculo de la casa 3D se utilizan para dar información a las salas. Se puede poner un conjunto de cena 3D sobre la mesa, o tienen contenedores pimienta y sal al interior de la cocina completa, tal vez poner un poco { \"slug\": \"luz\", \"title\": \"luces\"} y { \"slug\": \"flores\"} cerca de la cama para crear sensación de lujo.\n","industrial":"Los materiales de construcción, { \"slug\": \"ingenierÃa\"} herramientas, maquinaria y { \"slug\": \"contenedores\", \"title\": \"contenedores\"} que proporcionan ambos detalles ambientales e interactivos, elementos manipuladas. Esto es perfecto para los desarrolladores de juegos de simulación o la gente que construye { \"slug\": \"construcción\"} planta de jardin.\n","interior":"Esta categorÃa contiene 3D elementos y detalles de la arquitectura, la construcción y la ingenierÃa de diseño de interiores realistas. Puede utilizar estos modelos en 3D para animaciones o juegos - algunos de ellos se aparejan y poli baja.\n","military":"En esta categorÃa se pueden comprar en 3D modelos de armas, brazos, { \"title\": \"espadas\", \"slug\": \"espada\"} y de artillerÃa a la vez moderno e histórico utilizado por las fuerzas militares y de defensa personal. Puede utilizar modelos para juegos - algunos de ellos son polÃgonos optimizados y listos para motores de juego.\n","plant":"Esta categorÃa contiene 3D modelos de flora organismos tales como flores, { \"slug\": \"árbol\", \"title\": \"árboles\"}, hierba, enredaderas, verdor, hierbas, plantas vivaces, plántulas, brotes, arbustos, resbalones, coles, vides, malas hierbas. Para comprar o descargar un modelo 3D gratis, navegar por las categorÃas de abajo.\n","scanned":"Modeladores crean estos modelos en 3D mediante el uso de tecnologÃas de escaneado, como REALSENSE. Tocones de árboles, estatuas, incluso hombres y mujeres son muy populares aquÃ. El producto está listo para ser utilizado en las escenas y animaciones, que ofrece niveles incomparables de realismo.\n","science":"Esta categorÃa contiene 3D modelos relacionados con la medicina, la biologÃa, la fÃsica, la quÃmica y la tecnologÃa, tales como equipos de laboratorio, los organismos microscópicos y el mundo subatómico. No busque más, { \"slug\": \"célula\"}, { \"slug\": \"cráneo\"} y { \"slug\": \"esqueleto\"} 3D modelos se pueden encontrar aquÃ.\n","scripts-plugins":"Scripts y plug-ins que proporcionan atajos de softw
16518are. Modelado, renderizado, texturizar - todos estos se pueden hacer más fácil el uso de plug-ins que vienen de todo tipo de software como Maya y V-Ray.\n","space":"El espacio es una categorÃa completa de poli baja, los modelos de juego listo de la ciencia ficción { \"slug\": \"nave espacial\", \"title\": \"naves espaciales\"}, { \"slug\": \"asteroide\", \"title\": \"asteroides \"}, planetas (incluyendo {\"slug\": \"tierra\", \"title\": \"tierra\"} y el espacio realista {\"slug\": \"lanzadera\", \"title\": \"lanzaderas\"} para el inclinado de forma más cientÃfica 3D modelos espaciales son útiles para juegos de simulador de realidad virtual espacio.\n","sport-hobby":"Esta categorÃa encompases todo lo que está relacionado con { \"slug\": \"campo\"} eventos, deportes y aficiones en general. Desde { \"slug\": \"el fútbol\"} y las pistas de esquà a { \"slug\": \"guitarra\"} y { \"slug\": \"piano\"}, los cuales son útiles en 3D modelos para anuncios, escenas y animación. versiones poli-bajos están ahà para los videojuegos de deportes.\n","textures":"Navegar a través de una biblioteca de hecho muy bien en 3D-materiales y encontrar los precios, listos para su uso texturas adecuados para preparar \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e listo para jugar \u003c/a\u003e o modelos fotorrealistas, actualizar su biblioteca de activos, y mejorar sus trabajos en 3D.\n","various":"Estos son los modelos 3D que no encajan fácilmente en otras categorÃas, por lo que creamos una que aceptar a todos. { \"title\": \"rocas\", \"slug\": \"rocas\"}, { \"slug\": \"nubes\"}, { \"title\": \"logos\", \"slug\": \"logo\"}, { \"tÃtulo\" : \"paraguas\", \"slug\": \"paraguas\"} y otros modelos no categorizado 3D están aquÃ.\n","vehicle":"Camiones, { \"title\": \"ambulancias\", \"slug\": \"ambulancia\"}, autobuses, trenes, tractores, { \"title\": \"bicicletas\", \"slug\": \"bicicleta\"} y motocicletas - Esta categorÃa es para las personas que quieren que sus calles se llenen de vehÃculos realistas y de ciencia ficción, y para aquellos que hacen juegos de simulación o formatear carteles.\n","watercraft":"Cubiertas de embarcaciones { \"title\": \"barcos\", \"slug\": \"barco\"}, { \"title\": \"yates\", \"slug\": \"yate\"}, { \"title\": \"naves\", \"slug\" : \"barco\"} y otros vehÃculos acuáticos. El aparejado 3D modelos se hacen bien en los juegos de video, animación CG mientras que los modelos están ahà para sus escenas u otras aplicaciones en las que la fidelidad visual es más importante que polycount.\n"},"forwarded":{"cg":{"aircraft":"Esta categorÃa incluye modelos 3D de aviones. Los aviones digitales son ideales para simulaciones, visualizaciones, anuncios y videos. Los drones y sus partes encantarán a los fans de los vehÃculos aéreos pequeños. También hay modelos con rig listos para usar en motores de juego.","animals":"Aquà encontrarás modelos 3D de fauna: gatos, caballos, osos, rinocerontes, águilas, leones y más. Perfectos para escenas estáticas o publicitarias. También hay modelos riggeados para juegos.","architectural":"Escaleras, chimeneas, decoraciones como marcos, cojines o lámparas están disponibles en esta extensa biblioteca de detalles arquitectónicos. Ya sea para cocinas, dormitorios, castillos o mazmorras, estos modelos sirven tanto para arquitectos, ingenieros como desarrolladores de juegos independientes.","car":"Incluye modelos 3D de automóviles. Las versiones low poly son ideales para juegos; otras para pelÃculas o publicidad. Desde autos clásicos y de carrera hasta conceptuales, hay una gran variedad disponible.","character":"Aquà puedes adquirir modelos 3D de armas, espadas y artillerÃa, tanto modernas como históricas, usadas por fuerzas armadas o para defensa personal. Muchos están optimizados para juegos y listos para motores gráficos.","electronics":"La electrónica es una categorÃa para arquitectos, decoradores de interiores, diseñadores de niveles, los responsables de escena y otros creativos. modelos 3D de { \"slug\": \"smartphone\", \"title\": \"teléfonos inteligentes\"}, { \"slug\": \"laptop\", \"title\": \"portátiles\"}, { \"slug\": \"camera\", \"title\" : \"cámaras\"}, {\"slug\": \"TV\", \"title\": \"TV\"}
16518 y más ayudará a capturar con precisión la obsesión de la vida moderna con los dispositivos y la tecnologÃa.\n","engineering-parts":"Ventanas, tuberÃas, herrajes para puertas correderas y otros bits que son necesarios para proyectos CAD e incluso planes de bricolaje se incluyen en esta categorÃa. Aquà es donde se pueden encontrar modelos 3D de los fabricantes mundiales como ANVER, Dynatec y la FCI.\n","exterior":"Explora exteriores arquitectónicos: fachadas, edificios urbanos, paisajes, casas residenciales, construcciones industriales y ciudades en 3D a escala real. Algunos modelos son low poly y pueden integrarse fácilmente en proyectos VR/AR o videojuegos.","food":"Modelos 3D de frutas, verduras, bebidas y platos listos. Ãtiles para anuncios de restaurantes o apps AR sobre alimentación saludable. ¿Buscas una pizza en 3D o una tarta de boda? Están aquÃ.","furniture":"Mesas, sillas, sofás, camas en diferentes texturas (madera, metal, etc.) y estilos (retro, moderno, etc.). Esta categorÃa es ideal para diseñadores de interiores, arquitectos y publicidad.","furniture-set":"Si necesita una silla antigua por igual buscando y sofá mirando, o conjunto completo de menaje, este es un lugar de imitar a este conjuntos de categorÃas de cobro de modelos de muebles en 3D de cocina y sala de estar a la oficina y comedor sala de juegos de muebles. Esto ayuda a los interiores de diseño o nivel de habitaciones especialista en construcción con elementos coincidentes.\n","household":"Modelos 3D de objetos domésticos para agregar realismo a las habitaciones. Añade vajillas a la mesa, saleros en la cocina o lámparas y flores junto a la cama para crear un ambiente lujoso.","industrial":"Materiales de construcción, herramientas, maquinaria y contenedores que ofrecen tanto detalle visual como elementos interactivos riggeados. Perfecto para desarrolladores de simuladores o niveles de construcción.","interior":"Contiene elementos realistas de arquitectura, construcción y diseño interior. Algunos modelos están riggeados y optimizados en polÃgonos, ideales para animaciones o videojuegos.","military":"Aquà puedes adquirir modelos 3D de armas, espadas y artillerÃa, tanto modernas como históricas, usadas por fuerzas armadas o para defensa personal. Muchos están optimizados para juegos y listos para motores gráficos.","plant":"Incluye modelos 3D de flores, árboles, césped, enredaderas, arbustos, brotes y más. Puedes comprar o descargar modelos gratuitos en las subcategorÃas.","scanned":"Modeladores crean estos modelos en 3D mediante el uso de tecnologÃas de escaneado, como REALSENSE. Tocones de árboles, estatuas, incluso hombres y mujeres son muy populares aquÃ. El producto está listo para ser utilizado en las escenas y animaciones, que ofrece niveles incomparables de realismo.\n","science":"Esta categorÃa contiene 3D modelos relacionados con la medicina, la biologÃa, la fÃsica, la quÃmica y la tecnologÃa, tales como equipos de laboratorio, los organismos microscópicos y el mundo subatómico. No busque más, { \"slug\": \"cell\", \"title\": \"célula\"}, { \"slug\": \"skull\", \"title\": \"cráneo\"} y { \"slug\": \"skeleton\", \"title\": \"esqueleto\"} 3D modelos se pueden encontrar aquÃ.\n","scripts-plugins":"Scripts y plug-ins que proporcionan atajos de software. Modelado, renderizado, texturizar - todos estos se pueden hacer más fácil el uso de plug-ins que vienen de todo tipo de software como Maya y V-Ray.\n","space":"Modelos low poly listos para juegos de naves espaciales, asteroides, planetas y transbordadores. Muy útiles para simuladores espaciales en VR.","sport-hobby":"Esta categorÃa encompases todo lo que está relacionado con { \"slug\": \"field\", \"title\": \"campo\"}
16518 eventos, deportes y aficiones en general. Desde { \"slug\": \"football\", \"title\": \"el fútbol\"} y las pistas de esquà a { \"slug\": \"guitar\", \"title\": \"guitarra\"} y { \"slug\": \"piano\", \"title\": \"piano\"}, los cuales son útiles en 3D modelos para anuncios, escenas y animación. versiones poli-bajos están ahà para los videojuegos de deportes.\n","textures":"Explora una biblioteca de materiales 3D y encuentra las texturas listas para usar que mejor se adapten a tus proyectos: modelos para videojuegos, visuales fotorealistas o para ampliar tu colección.","various":"Estos son los modelos 3D que no encajan fácilmente en otras categorÃas, por lo que creamos una que aceptar a todos. { \"title\": \"rocas\", \"slug\": \"rocks\"}, { \"slug\": \"clouds\", \"title\": \"nubes\"}, { \"title\": \"logos\", \"slug\": \"logo\"}, { \"title\" : \"paraguas\", \"slug\": \"umbrella\"} y otros modelos no categorizado 3D están aquÃ.\n","vehicle":"Camiones, ambulancias, autobuses, trenes, tractores, bicicletas y motocicletas. Para quienes desean calles urbanas con vehÃculos realistas o de ciencia ficción. Ideal para juegos de simulación o carteles promocionales.","watercraft":"Incluye barcos, yates, naves y otros vehÃculos acuáticos. Los modelos riggeados son ideales para videojuegos y animaciones; los modelos CG para escenas donde la calidad visual es más importante que el conteo de polÃgonos."},"printable":{"art":"Aquà es donde las impresiones artÃsticas en 3D van. Buscando diseño de la escultura de fantasÃa que recrea obras clásicas y estatuas de personajes históricos, o inspirar figuritas, tal vez incluso logotipos 3D imprimibles? Esa es la categorÃa.\n","fashion":"Cosas bonitas y sofisticadas que se pueden usar se encuentran en esta categorÃa. Ver si se puede encontrar ningún uso para la era espacial de fantasÃa { \"slug\": \"footwear\", \"title\": \"calzado\"}, novedad de los vidrios y cosplay { \"slug\": \"accessories\", \"title\": \"accesorios\"} encontrar aquÃ.\n","gadgets":"Todo { \"title\": \"iPhone\", \"slug\": \"iphone\"}, { \"title\": \"IPAD\", \"slug\": \"ipad\"} (y otros dispositivos inteligentes) de los casos se puede encontrar en la categorÃa de gadget. Desde simples 3D complementos para piezas complejas y âhacksâ para sus artÃculos, esta es la categorÃa de los mensajes publicitarios, y los amantes de la tecnologÃa.\n","games-toys":"Juegos y juguetes es la categorÃa que cubre extrañas o monstruo imprimibles miniaturas 3D, pequeño { \"title\": \"tanques\", \"slug\": \"tank\"}, cobarde { \"slug\": \"chess\", \"title\": \"ajedrez\"} pedazos, cascos personaje de la pelÃcula, afición parafernalia y accesorios. Esta es la categorÃa a-go para todas las cosas geek.\n","hobby-diy":"Si usted es nuestro próximo gran inventor y quiere construir su proyecto de bricolaje o conseguir algunas piezas de repuesto para su { \"slug\": \"drone\", \"title\": \"drone\"}, este es el lugar para estar. Además, cuenta con un bajo número de cosas para las personas que quieren tomar sus propias figuritas o réplicas de armas de plástico.\n","house":"Todo tipo de baratijas se pueden encontrar aquÃ. { \"title\": \"Lámparas\", \"slug\": \"lamp\"}, artÃstico { \"title\": \"copas\", \"slug\": \"bowl\"}, y todo tipo de { \"title\": \"titulares\", \"slug\": \"holder\"} si no se puede encontrar un lugar adecuado para su teléfono, mantener el orden de los palillos de dientes, pila de plumas o joyas en su escritorio.\n","jewelry":"La joyerÃa es donde se va a conseguir las pulseras y los colgantes o anillos con diamantes. Mientras que las impresoras 3D no son lo suficientemente buenos para hacer diamantes - sin embargo - aún puede imprimir un anillo metálico como base para su anillo de TI propuesta friki.\n","miniatures":"3D imprimible { \"title\": \"caracteres\", \"slug\": \"character\"}, gente famosa, { \"title\": \"puntos de referencia\", \"slug\": \"landmark\"}, animales, { \"title\": \"Hombre\", \"slug\": \"male\"}, { \"slug\": \"female\", \"title\": \"hembra\"}, { \"title\": \"monstruos\", \"slug\": \"monster\"}, { \"title\": \"extraterrestres\", \"slug\": \"alien\"} - todo está aquÃ. Tanto si imprime vehÃculos utilitarios para poner en su mesa o la creación de miniaturas para sus juegos de mesa, es su categorÃa.\n","scie
16518nce":"Lo que puede ser clasificado como ciencia? AsÃ, los modelos de esqueleto { \"slug\": \"bones\", \"title\": \"los huesos\"}, {médicos \"slug\": \"tools\", \"title\": \"herramientas\"} y astrofÃsica relacionados con el 3D modelos imprimibles que se pueden utilizar en muchos procesos de estudio.\n"}},"printable":{"art":"Aquà es donde las impresiones artÃsticas en 3D van. Buscando diseño de la escultura de fantasÃa que recrea obras clásicas y estatuas de personajes históricos, o inspirar figuritas, tal vez incluso logotipos 3D imprimibles? Esa es la categorÃa.\n","fashion":"Cosas bonitas y sofisticadas que se pueden usar se encuentran en esta categorÃa. Ver si se puede encontrar ningún uso para la era espacial de fantasÃa { \"slug\": \"calzado\"}, novedad de los vidrios y cosplay { \"slug\": \"accesorios\"} encontrar aquÃ.\n","gadgets":"Todo { \"title\": \"iPhone\", \"slug\": \"iPhone\"}, { \"title\": \"IPAD\", \"slug\": \"ipad\"} (y otros dispositivos inteligentes) de los casos se puede encontrar en la categorÃa de gadget. Desde simples 3D complementos para piezas complejas y âhacksâ para sus artÃculos, esta es la categorÃa de los mensajes publicitarios, y los amantes de la tecnologÃa.\n","games-toys":"Juegos y juguetes es la categorÃa que cubre extrañas o monstruo imprimibles miniaturas 3D, pequeño { \"title\": \"tanques\", \"slug\": \"tanque\"}, cobarde { \"slug\": \"ajedrez\"} pedazos, cascos personaje de la pelÃcula, afición parafernalia y accesorios. Esta es la categorÃa a-go para todas las cosas geek.\n","hobby-diy":"Si usted es nuestro próximo gran inventor y quiere construir su proyecto de bricolaje o conseguir algunas piezas de repuesto para su { \"slug\": \"drone\"}, este es el lugar para estar. Además, cuenta con un bajo número de cosas para las personas que quieren tomar sus propias figuritas o réplicas de armas de plástico.\n","house":"Todo tipo de baratijas se pueden encontrar aquÃ. { \"title\": \"Lámparas\", \"slug\": \"lámpara\"}, artÃstico { \"title\": \"copas\", \"slug\": \"tazón\"}, y todo tipo de { \"title\": \"titulares\", \"slug\": \"titular\"} si no se puede encontrar un lugar adecuado para su teléfono, mantener el orden de los palillos de dientes, pila de plumas o joyas en su escritorio.\n","jewelry":"La joyerÃa es donde se va a conseguir las pulseras y los colgantes o anillos con diamantes. Mientras que las impresoras 3D no son lo suficientemente buenos para hacer diamantes - sin embargo - aún puede imprimir un anillo metálico como base para su anillo de TI propuesta friki.\n","miniatures":"3D imprimible { \"title\": \"caracteres\", \"slug\": \"caracteres\"}, gente famosa, { \"title\": \"puntos de referencia\", \"slug\": \"punto de referencia\"}, animales, { \"title\": \"Hombre\", \"slug\": \"macho\"}, { \"slug\": \"hembra\"}, { \"title\": \"monstruos\", \"slug\": \"monstruo\"}, { \"title\": \"extraterrestres\", \"slug\": \"extranjero\"} - todo está aquÃ. Tanto si imprime vehÃculos utilitarios para poner en su mesa o la creación de miniaturas para sus juegos de mesa, es su categorÃa.\n","science":"Lo que puede ser clasificado como ciencia? AsÃ, los modelos de esqueleto { \"slug\": \"los huesos\"}, {médicos \"slug\": \"herramientas\"} y astrofÃsica relacionados con el 3D modelos imprimibles que se pueden utilizar en muchos procesos de estudio.\n"},"titles":{"aircraft":"Modelos 3D de aviación","animal":"Modelos 3D de animales","animals":"Modelos 3D de animales","architectural":"Modelos 3D arquitectónicos","car":"Modelos 3D de coches","character":"Modelos 3D de personajes","exterior":"Modelos 3D de exteriores","food":"Modelos 3D de comida","furniture":"Modelos 3D de muebles","household":"Modelos 3D del hogar","industrial":"Modelos 3D industriales","interior":"Modelos 3D de interiores","military":"Modelos 3D militares","plant":"Modelos 3D de plantas","space":"Modelos 3D del espacio","textures":"Modelos 3D de texturas","vehicle":"Modelos 3D de transporte","watercraft":"Modelos 3D de transporte acuático"}},"title":{"cg":" Modelos 3D","print":" Archivos de impresión 3D"}}
16518,"competition":{"digital-art-competition":{"categories":{"number":"seis","page_description":"Participar en el Concurso de Arte Digital CGTrader mediante la presentación de sus trabajos de ilustración de carácter, carácter concepto de diseño, la ilustración de Medio Ambiente, Medio Ambiente concepto de diseño, objetos de diseño, y objetos de categorÃas concepto de diseño. Si usted tiene varias grandes obras que se adapten a diferentes categorÃas, no dude en aportar a las categorÃas correspondientes. Seleccione una categorÃa para ver los premios correspondientes a esa categorÃa."}}},"conversations":{"action_button_confirmation":"¿Realmente quieres reabrir esta solicitud?","reply_posted":"La respuesta ha sido publicada.","with_yourself":"no puede ser el mismo que el remitente."},"date":{"month_names":[null,"Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"]},"devise":{"failure":{"too_many_requests":"Ya solicitaste un correo para restablecer la contraseña. Por favor, espera unos minutos antes de intentarlo de nuevo."}},"disabled_cookies_modal":{"button":"Cancelar","text_1":"Usted no será capaz de explorar millones de grandes modelos 3D, añadir a la cesta o Comprar.","text_2":"Si quieres experimentar CGTrader totalmente, le recomendamos habilitar las cookies en este sitio.","title":"Parece que tiene las cookies del navegador desactivados"},"emails":{"error_notification":"Suscripción no encontrada.","success_subscribed_notification":"Te has suscrito correctamente.","success_unsubscribed_notification":"Te has dado de baja correctamente."},"errors":{"messages":{"invalid_vat":"no es un número de IVA intracomunitario %{country_adjective} válido","vies_down":"No se ha podido validar su número de IVA: El servicio VIES no está disponible, por favor inténtelo más tarde."}},"file_size_validator":{"errors":{"invalid_carrierwave":"Se esperaba un objeto CarrierWave::Uploader::Base","invalid_key":":%{key} debe ser un número entero no negativo","range_format":":in y :within deben ser un rango","range_unspecified":"Rango no especificado. Especifica la opción :within, :maximum, :minimum o :is."}},"file_type":{"default_error":"No se ha proporcionado la ruta al archivo."},"footer":{"bottom-row":{"privacy":"PolÃtica de privacidad","terms-link":"Términos y condiciones"},"links":{"buyLinks":[{"text":"Comprar modelos 3D","link":"/es/3d-modelos"},{"text":"Para empresas","link":"/discover/business-account"},{"text":"Conjuntos de datos 3D gratis","link":"/discover/datasets"},{"text":"Contratar a un diseñador 3D","link":"/3d-modeling-jobs"},{"text":"Modelos 3D gratis","link":"/es/gratis-3d-modelos"},{"text":"Modelos 3D para imprimir gratis","link":"/es/gratis-3d-de-impresion-modelos"}],"communityLinks":[{"text":"Comunidad","link":""},{"text":"Mejores diseñadores","link":"/designers"},{"text":"DesafÃos","link":"/challenges"},{"text":"Foro","link":"/forum"}],"companyLinks":[{"text":"Empresa","link":"/discover/about-us"},{"text":"Blog","link":"/blog"},{"text":"Empleos","link":"/pages/careers"},{"text":"Centro de ayuda","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"Vender modelos 3D","link":"/discover/sell-3d-models"},{"text":"Haz crecer tus ventas","link":"/discover/sell-more"},{"text":"Información del mercado 3D","link":"/discover/3d-market-trends"},{"text":"Principales búsquedas de modelos 3D","link":"/discover/3d-models-top-searches"},{"text":"Principales búsquedas de impresión 3D","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"Suscribir","button-disabled":"Suscrito","header":"SuscrÃbete a nuestras noticias:","placeholder":"Introduce tu correo electrónico","terms-link":"Términos de Uso","text":"Mediante la suscripción de confirmar que ha leÃdo y acepta nuestra"}},"general":{"description":"CGTrader es un mercado en lÃnea donde los artistas y diseñadores 3D puede comprar, vender o compartir modelos 3D. Fue fundada y está siendo desarrollado por un equipo de ingenieros y diseñadores 3D. Nuestro objetivo es democratizar mercado de valores 3D y cambiar la forma en que vendemos modelos 3D en lÃnea. Por autores dejar ganar el máximo regalÃas, nos esforzamos para aumentar su motivación y elevar la calidad de los modelos 3D.","navigation":{"buy_3d_models":"Modelos 3D Comprar","sell_3d_models":"Vender Modelos 3D"},"search_placeholder":"Buscar entre más de 2 millones de modelos","site-search__field":"Buscar entre %{model_count}
16518 modelos 3D","site_title":"3D tienda Modelo","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"Deja que la IA haga realidad tus sueños","subtitle":"Convierte un prompt o una imagen de referencia en un modelo 3D listo para producción, luego refÃnalo, retexturÃzalo y expórtalo en el formato que necesites."},"faq":{"heading":"Preguntas frecuentes","items":{"commercial":{"answer":"El uso comercial de tu modelo 3D de %{object} está disponible con un plan de pago de CGTrader AI. Consulta los Términos y Condiciones de CGTrader para conocer las condiciones de licencia aplicables a los modelos generados por IA.","question":"¿Puedo usar el modelo de %{object} generado con fines comerciales?"},"formats":{"answer":"Los modelos 3D de %{object} están disponibles en formato GLB, FBX, OBJ, STL o USDZ.","question":"¿En qué formato de archivo puedo obtener mi modelo de %{object}?"},"no_skills":{"answer":"No se requieren conocimientos de modelado 3D. Todo el modelado se realiza a través del generador de modelos de %{object}. El sistema gestiona la geometrÃa, las proporciones y la estructura cuando introduces el prompt o subes una imagen. Incluso los principiantes pueden crear un modelo 3D completo de %{object} en minutos.","question":"¿Se necesitan conocimientos de modelado 3D para usar un generador de modelos de %{object}?"},"what_is":{"answer":"El generador de modelos 3D de %{object} de CGTrader, una herramienta basada en IA, crea un modelo tridimensional de %{object} a partir de instrucciones escritas o imágenes de referencia. Analiza tu idea y crea un modelo descargable para diseño, prototipos y visualización. Nuestras suscripciones de pago ofrecen lÃmites mensuales más altos.","question":"¿Qué es un generador de modelos 3D de %{object}?"},"why_cgtrader":{"answer":"Los usuarios pueden confiar en CGTrader para disfrutar de una experiencia fluida, tiempos de procesamiento rápidos y resultados 3D de alta calidad. Esta herramienta es adecuada tanto para profesionales como para principiantes que buscan una solución fiable para crear modelos 3D de %{object}.","question":"¿Por qué usar el generador de %{object} con IA de CGTrader?"}}},"h1":"Generador de modelos 3D de %{object} con IA","hero_alt":"Generador de modelos 3D de %{object} con IA","hero_height":617,"hero_width":1080,"how_to":{"heading":"Genera %{object} a partir de imágenes o prompts de texto","paragraphs":["Es muy sencillo diseñar un modelo tridimensional de %{object}. En la barra lateral izquierda, en la parte superior izquierda, haz clic en el botón para subir tu imagen de %{object} y crear un modelo 3D. También puedes introducir un prompt en el campo «Describe lo que quieres crear» en la parte inferior. CGTrader AI mejora tu prompt automáticamente, por lo que una descripción breve es suficiente para comenzar.","La barra lateral derecha te ofrece un buen control de tu modelo 3D de %{object}. Elige ajustes como el tipo de malla, material, guÃa de prompts y formato de archivo. También puedes aplicar texturas para personalizar tu modelo de %{object}. Tras introducir tus instrucciones de texto o imagen, haz clic en «Generar». La herramienta procesará tu entrada en pocos minutos, según la carga del sistema, el material, el tipo de malla, las formas, los valores de seed y la calidad."],"steps":["Escribe tu descripción en texto y/o adjunta una imagen de referencia para mejorar la precisión final de tu modelo 3D de %{object}.","Selecciona uno de nuestros presets, o elige un motor de IA, añade un número de polÃgonos personalizado y selecciona el tipo de material para tu modelo 3D de %{object}.","Pulsa Generar para crear un modelo 3D de %{object} a partir de tu prompt y/o imagen de referencia.","Descarga tu modelo 3D de %{object} creado en distintos formatos (GLB, FBX, OBJ, STL o USDZ)."]},"intro":"¿Busca una forma sencilla y rápida de crear un modelo 3D de %{object} de alta calidad en minutos? Nuestro avanzado generador de modelos 3D de %{object}, CGTrader AI, puede convertir comandos escritos o imágenes de referencia en modelos completamente funcionales. Funciona con los mejores motores de generación 3D, incluidos Meshy, Hunyuan y Tripo3D. Permite crear modelos 3D de forma rápida tanto para principiantes como para expertos en diseño, para visualización, experimentación y prototipos. Es compatible con texto a 3D e imagen a 3D, y con impresoras 3D. Puede cargar una imagen en formato JPG o PNG, o escribir una descripción en texto. CGTrader AI se encarga del resto.","meta_description":"Generador de modelos 3D de %{object} con IA de CGTrader âï¸ Crea modelos 3D de %{object} detallados a partir de texto o imágenes. Empieza gratis ahora.","primary_cta":"Empieza a generar gratis","title":"Generador de modelos 3D de %{object} con IA (gratis) | CGTrader"}}},"rules":{"errors":{"front_view_required":"Se requiere una imagen de la vista frontal."}}},"home":{"index":{"3D-projects":{"info-section__cta":"Aprende más","info-section__description":"Donde las personas con emocionantes Proyectos en 3D se reúnen talentos del diseño 3D","info-section__heading_html":"\u003cStrong\u003e Proyectos en 3D \u003c/strong\u003e Hub Freelance"},"categories-conatainer":{"browse_all":"Ver todos los modelos","browse_all_tooltip":"Explorar todos los modelos 3D","discounts":"Descuentos"},"cgdream":{"cta":"¡Empiece gratis!","heading_html":"\u003cstrong\u003eExplora CGDream,\u003c/strong\u003e\u003c/br\u003e donde la IA se encuentra con los modelos 3D.","text_html":"\u003cstrong\u003e CGDream \u003c/strong\u003e es una aplicación de vanguardia que aprovecha el poder de los modelos generativos de IA y 3D para producir impresionantes imágenes 2D. \u003cstrong\u003e Tu viaje creativo comienza ahora. \u003c/strong\u003e"},"community":{"info-section__cta":"Unete a la communidad","info-section__heading_html":"Ãnete CGTrader \u003cstrong\u003e Comunidad \u003c/strong\u003e","info-section__icon-list_1":{"de
16518scription":"Mostrar sus mejores renders, obtener retroalimentación y reconocimiento","heading":"GalerÃas"},"info-section__icon-list_2":{"description":"Aprender nuevas habilidades y enseñar a los demás","heading":"Tutoriales"},"info-section__icon-list_3":{"description":"Encontrar tutoriales y discutir otros asuntos relacionados con 3D","heading":"Foro"}},"covid":{"timer-strip__item":"Recursos gratuitos para imprimir en 3D para COVID-19 Protección","timer-strip__item--button":"Modelos 3D Navegar"},"enterprise":{"info-section__cta":"Aprende más","info-section__heading_html":"Servicios 3D para el \u003cstrong\u003e Empresa \u003c/strong\u003e","info-section__icon-list_1":"Podemos hacer la implementación de AR para usted","info-section__icon-list_2":"Más conversiones de ventas, menos las devoluciones de productos","info-section__icon-list_3":"Calidad garantizada con control de calidad estricto"},"header":"Modelos 3D para VR / AR, impresión 3D y gráficos por computadora","marketplace":{"info-section__description":"Elegir %{models_count} 3D modelos para aplicaciones tales como juegos, AR / VR, publicidad, animación, pelÃculas y la impresión en 3D","info-section__heading_html":"Modelo 3D \u003cstrong\u003e del mercado \u003c/strong\u003e","info-section__image-list_1":{"description":"Comprar Modelos 3D profesional para su proyecto","heading":"Modelos 3D"},"info-section__image-list_2":{"description":"-Poli bajos Modelos PBR 3D listo para videojuegos, VR y AR aplicaciones en tiempo real","heading":"Bajo poli modelos 3D PBR"},"info-section__image-list_3":{"description":"Encuentra 3D Print diseños para su impresora 3D","heading":"Los modelos de impresión 3D"},"view_all":"Ver todos"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"Convierte una imagen en un modelo 3D","title":"Imagen a 3D"},"text_to_3d":{"description":"Describe tu idea para crear un modelo 3D","title":"Texto a 3D"}},"ai_section_title":"Crear con IA","aria_label":"Sugerencias de búsqueda","columns":{"cg":{"search_label":"Buscar en Modelos 3D","title":"Modelos 3D"},"print":{"search_label":"Buscar en Impresión 3D","title":"Modelos para impresión 3D"}}},"sell":{"info-section__heading_html":"\u003cstrong\u003e Vender \u003c/strong\u003e los modelos 3D y encontrar proyectos independientes","info-section__icon-list_1":{"description":"Vender sus modelos en 3D y ganar hasta 85% de regalÃas","link":"Vender modelos 3D"},"info-section__icon-list_2":{"description":"Trabaja con clientes de la empresa","link":"Recibe Calificado"},"info-section__icon-list_3":{"description":"Externalizar sus habilidades y obtener hasta un 95% de regalÃas","link":"Navegar Modelado 3D Empleos"},"info-section__icon-list_4":{"description":"Construir su cartera y ser visible","link":"Ver diseñadores 3D"}},"seo":{"description":"Explora más de 2 millones de modelos 3D en lÃnea para proyectos de impresión, juegos, VR/AR y diseño. Descarga, personaliza o contrata expertos 3D - todo en CGTrader.","title":"CGTrader - Modelos 3D y Mercado de Impresión 3D"}}},"homepage":{"budget_counter":{"range_0_10":"Menos de $10","range_10_20":"$10 - $20","range_20_15000":"Más de $20"},"quotes":{"quote_0":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Menores comisiones tomadas de los medios vendidos mejores precios para los compradores. Comprobar y comparar los precios en CGTrader y las otras tiendas."},"quote_1":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"La ventaja más notable de CGTrader es el sistema de activación de tarifa plana que nos da altos rendimientos. Usted no está tomando un porcentaje de la comisión de las ventas. Después de la venta, recibimos el 100% del precio. Sólo si queremos continuar la venta de ese producto, es posible volver a activar de nuevo mediante el pago de $ 5. solución elegante."},"quote_10":{"author":{"name":"threed Ken","username":"3DKen"},"text":"El sistema de activación de tarifa plana es ingenioso. Me preguntaba por qué nadie habÃa pensado en esto antes. Después de la venta, pagar una pequeña cuota para activar un producto y eso es todo. El vendedor está en pleno control."},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Hay dos cosas que me gusta de CGTrader. En primer lugar, no hay ocultos que significa que cualquier cosa aquÃ. No es necesario tener cuidado con CGTrader. En segundo lugar, esta tienda es por los artistas y para los artistas. Ellos se entienden mejor. Algo le molesta aquÃ? ... hacerles saber y que se asegurará de que usted se sienta cómodo aquÃ."},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"El sistema de activación de tarifa plana es el mejor! (Al menos no he encontrado nada mejor que esto). Es muy realista y justo para los vendedores. No les importa la cantidad de beneficios que usted hace, simplemente pagar la renta fija. Pero si usted no hace ninguna venta, usted no tiene que pagar el alquiler, ya sea. El comercio justo CG está aquÃ!"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"CGTrader atrae a los clientes incluso de paÃses en desarrollo, ya que los precios son más baratos que en otras tiendas. Al mismo tiempo, los autores pueden ganar más, porque no hay tal cosa como altas tasas de comisión. Es una forma correcta de valorar el trabajo de los artistas 3D."},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"La interfaz intuitiva de los editores y herramientas innovadoras como la recomendación de la etiqueta y formas flexibles descripción hace que el proceso de publicación fácil y rápido."},"quote_15":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"enfoque de la venta 3D de CGTrader es diferente y no tienen nada en común con otras tiendas que vendÃa. Pagar un precio rebajado de $ 5 si la venta es una gran idea y me permite ofrecer precios más bajos aquÃ. Cliente y el artista se beneficiaron con esta forma de trabajar."},"quote_16":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"El sistema de carga es fácil y clara. Es bueno saber que detrás del proyecto son personas con años de experiencia en materia de gráficos de ordena
16518dor. Cada vez que tenÃa un problema, el equipo CGTrader fija rápidamente."},"quote_17":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTrader me permite vincular mi perfil con mi página web personal. Los clientes pueden ponerse en contacto conmigo, si no están seguros acerca de una caracterÃstica de un artÃculo que desea comprar o simplemente desea una modificación de la misma. Es como tener una tienda 3D personal en un mercado grande!"},"quote_2":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Hemos disfrutado de una gran y sensible apoyo del equipo CGTrader. El personal muy amablemente se ofreció a hacer la publicación de todos los modelos para nosotros, lo cual es una gran ayuda para los vendedores profesionales."},"quote_3":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"En esta plataforma podemos ofrecer precios mucho mejor a nuestros clientes. Por ejemplo, todos nuestros productos tienen un precio 20% menor que en cualquier otro lugar y aún asà obtener más beneficios en comparación con otras tiendas!"},"quote_4":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"Este es el mejor sistema hasta la fecha. Todas las otras tiendas en 3D en lÃnea toman un% de nuestros beneficios. Esta fue la caracterÃstica que captó nuestro interés en CGTrader desde el principio. Clientes, la compra de CGTrader, saben que la mayor parte de su dinero para ir al autor, que al final va a hacer más y mejores modelos si mejoran sus ganancias."},"quote_5":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"CGTrader es la tienda en lÃnea 3D que hizo que los de más rápido crecimiento de ventas y ganancias para nosotros. El sistema de activación de tarifa plana es el mejor que se puede encontrar, ya que premia a los creadores de contenido en lugar de los intermediarios."},"quote_6":{"author":{"name":"RiÄardas Marozas","username":"autobomba"},"text":"Cuando recibà $ 160 a mi cuenta de Paypal, no sabÃa lo que está pasando, ya que nunca antes habÃa sucedido, pero luego pensé que podrÃa ser una venta CGTrader y yo estaba en lo cierto. Se vende el mismo paquete en Turbosquid el mes pasado por $ 189, pero después de 40% tasa de regalÃas y el impuesto del 30%, todo lo que tengo $ 52.92 - monedas de un centavo en comparación con $ 160 desde CGTrader. Además, el cliente pagado $ 29 de menos - ahora que es un buen negocio."},"quote_7":{"author":{"name":"threed Ken","username":"3DKen"},"text":"Al principio estaba escéptico sobre tal un acuerdo bueno para los vendedores que no es la norma para las grandes tiendas en lÃnea 3D. Cuando supe de la activación del sistema de tarifa plana, me impresionó de tal manera creativa de la venta de activos digitales. Venta, a continuación, active mediante el pago de una cuota de $ 5. Todo tiene sentido para mÃ. He subido unos cuantos para probar y verdaderamente, cuando llegué a mi primera venta, que era 100% de la realeza!"},"quote_8":{"author":{"name":"threed Ken","username":"3DKen"},"text":"Estaba tan acostumbrada a muchos otros sitios que cobran entre 30% - 60% de comisión hasta que descubrà CGTrader. Como vendedor, definitivamente como el alto porcentaje de los rendimientos de regalÃas."},"quote_9":{"author":{"name":"threed Ken","username":"3DKen"},"text":"La experiencia vendedor es fantástico. presentación del producto es una brisa. Y sÃ, el sistema me permitió guardar un borrador de mi presentación de productos de cada etapa del camino."}}},"hyperwallet":{"failed_payment_agreement":"Ocurrió algo inesperado","success_notification":"El acuerdo de pago se ha actualizado correctamente.","success_payment_agreement":"El acuerdo de pago se ha enviado correctamente."},"item-search-filters":{"3d-models-url":"3d-modelos","3d-print-models-url":"3d-de-impresion-modelos","dedicated-search-page-url":{"animated":"/animados-","free":"/gratis-","low_poly":"/de-bajo-poli-","pbr":"/pbr-","rigged":"/aparejado-"}},"item_use_case":{"not_valid":"Archivo no válido","pundit":{"not_authorized":"No está autorizado para realizar esta acción."},"title":"Caso de uso para %{item_name}"},"items":{"already_purchased":"Ya has comprado este artÃculo.","filters":{"attributes":"atributos","free":"Gratis","max_value":"$ 500 +","min_value":"$ 2","reset":"Restablecer filtros"},"footer":{"next":"Próximo","per_page":"Por página:","previous":"Previo"},"geometry_type_forbidden":"¡Tipo de geometrÃa prohibido!","last_card":{"button_text":"Solicitar un modelo 3D personalizada","text":"No se pudo encontrar lo que estás buscando?"}
16518,"migrations":{"errors":{"invalid_owner":"El nuevo propietario no puede hacerse cargo de los artÃculos.","unpublished_items":"Todos los artÃculos deben estar publicados."}},"new_price_applied":"Los nuevos precios se han aplicado correctamente a todos los artÃculos.","new_price_applied_to_selected_items":"Los nuevos precios se han aplicado correctamente a los artÃculos seleccionados.","new_prices_to_filtered_models":"Los nuevos precios se han aplicado correctamente a todos los artÃculos filtrados.","order_processed":"Pedido procesado.","order_processing":"Procesando pedido.","something_went_wrong":"Algo salió mal","title_error":"El tÃtulo no debe contener sÃmbolos que no sean latinos","uniq_user":"ya ha enviado un caso de uso para este artÃculo","upload_error":"Error de carga.","validate_license_for_zero_price":"no es válido para un artÃculo gratuito","validate_minimum_price":"Las ofertas de precio no deben estar por debajo del mÃnimo del 50% del precio original","verify_printable_formats_error":"Por favor, sube al menos un archivo .stl, .obj o .wrl.","you_can_not_delete_models":"No puedes eliminar modelos"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projects facilita la contratación de artistas 3D freelance de calidad y te ayuda a resolver todos tus retos de modelado.","heading_html":"Descubre la mejor plataforma de freelancers para tus \u003cstrong\u003etrabajos de modelado 3D\u003c/strong\u003e"},"sections":{"call_to_action":{"description":"Publica tu proyecto gratis y descubre lo fácil que es resolver tu próximo reto de modelado con Proyectos 3D.","title":"¡Contrata al mejor talento 3D hoy mismo!"},"freelancer_selection":{"title":"Haz que tu próximo proyecto 3D sea un éxito","widest_selection":{"description":"No te conformes con menos. Con 40.000 diseñadores 3D freelance, CGTrader es la plataforma más grande para ayudarte a conectar con especialistas cualificados: modeladores, animadores, riggers, expertos en impresión 3D y todo lo demás.","title":"La mayor selección de freelancers 3D"}},"how_it_works":{"steps":{"describe":{"description":"Cuéntanos lo que necesitas. Usa nuestro formulario sencillo, añade imágenes y publica tu oferta freelance en minutos.","title":"Describe tu proyecto"},"pay":{"description":"Prepara el presupuesto de forma segura en CGTrader y hazle saber a tu freelancer que estás listo para empezar. Chatea, comparte archivos y visualiza el progreso del proyecto fácilmente en tu espacio de trabajo dedicado. Libera el pago cuando estés satisfecho con el resultado final.","title":"Paga por el resultado"},"select":{"bullets":["Recibe presupuestos de diseñadores calificados directamente en tu bandeja de entrada","Chatea con diseñadores en tiempo real","Explora sus proyectos anteriores","También puedes buscar, filtrar e invitar a freelancers según sus habilidades 3D, valoraciones y tus preferencias de software o formatos"],"title":"Selecciona al mejor freelancer"}},"title":"Realiza tu trabajo en 3 pasos simples"},"payment_quality":{"description":"CGTrader garantiza que los servicios freelance cumplirán con tus requisitos y se entregarán a tiempo. Nuestro equipo de control de calidad está disponible siempre que lo necesites.","title":"Calidad garantizada"},"secure_payments":{"description":"Nuestro servicio de depósito en garantÃa asegura que tus fondos estén protegidos y que solo pagues cuando estés satisfecho con el resultado final.","title":"Pagos seguros"},"workspace_convenience":{"description":"OlvÃdate de la frustración de cambiar entre pestañas y diferentes herramientas. Con el espacio de trabajo dedicado, puedes gestionar fácilmente todo en un solo lugar: múltiples proyectos, facturas, conversaciones, intercambio de archivos y mucho más.","title":"Comodidad de una sola pantalla"}},"shared":{"post_project_cta":"Publicar proyecto"}},"navigation":{"find_jobs_cta":"Encontrar trabajos 3D","hire_freelancers_cta":"Contrata freelancers 3D","how_it_works":"Cómo funciona","why_projects":"Por qué los proyectos 3D"}},"agreed_to_terms_of_use":"Debes aceptar los Términos y Condiciones de 3D Projects para continuar.","budget_error_message":"es demasiado alto","check_designer_uniqueness_error":"El diseñador solo puede ser invitado una vez","check_ownership_error":"El invitador no es propietario del proyecto","check_status_error":"Los diseña
16518dores solo pueden ser invitados a proyectos aprobados.","deadline_error_message":"La fecha lÃmite debe estar en el futuro","discount_code_error":"Lo sentimos, el código de descuento no existe o ha caducado.","email_subject":"Oportunidad de proyecto 3D: %{subject}","error_check_application_uniqueness":"Solo puedes postularte una vez","error_check_applier":"No puedes postularte a tu propio proyecto 3D","error_check_job_availability":"El usuario no está autorizado para postularse","error_check_job_status":"Las solicitudes de proyectos están en espera hasta que se complete nuestro nuevo proceso de moderación, normalmente dentro de 3 dÃas hábiles. ¡Gracias por tu comprensión!","modeling_request_failed":"¡La solicitud de modelado ha fallado!","offer_has_been_sent":"¡Gracias, tu oferta ha sido enviada!","offer_is_closed":"La oferta está cerrada.","payment_successful":"Pago realizado con éxito.","payment_under_review":"El pago está en revisión.","share_with_yourself_error":"No está permitido compartir plantillas de Contrátame contigo mismo","system_messages":{"buyer_cancels_job":"El proyecto fue cancelado y movido a la pestaña %{archive_url}.","buyer_edits_hire_me_template":"Los detalles del proyecto fueron actualizados por el cliente.","buyer_edits_job_details":"Los detalles del proyecto fueron actualizados.","buyer_marks_job_as_finished":"El proyecto fue marcado como finalizado y movido a la pestaña %{archive_url}.","buyer_marks_job_as_finished_with_resell":"El cliente marcó el proyecto como finalizado y te permitió vender los resultados en CGTrader. ¡Asegúrate de \u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003esubir\u003c/a\u003e\u003c/b\u003e el modelo creado!","buyer_negotiates":"El cliente negoció tu oferta de precio.","buyer_pays_for_the_job":"El proyecto fue prepagado y movido a la pestaña %{in_progress_url}.","designer_accepts_changes":"El diseñador revisó los detalles actualizados.","designer_accepts_offer":"El diseñador aceptó tu oferta.","designer_edits_offer":"El diseñador editó su oferta.","designer_negotiates":"El diseñador negoció tu oferta.","designer_withdraws_offer":"El diseñador retiró su oferta.","job_expires":"El proyecto expiró y fue movido a la pestaña %{archive_url}."},"template_error":"¡No se han creado proyectos!","user_not_exists":"El usuario con ese nombre de usuario no existe.","want_that_job":"¡Quiero este trabajo!"},"kodama":{"invalid_request":"¡Solicitud no válida!"},"landing":{"consent_not_saved":"El consentimiento no se guardó","failure_notification":"Todos los campos obligatorios de la solicitud de acceso a la API deben ser válidos.","success_notification":"Gracias por tu solicitud. Nos pondremos en contacto contigo en breve."},"layout":{"chunk_load_notice":"Algo salió mal al cargar esta página. Por favor, actualÃzala.","cookies_policy":{"accept":"Aceptar","learn_more":"Aprende más","text":"Nuestros utiliza el sitio web cookies para recopilar datos estadÃsticos de visitantes y la interacción pista con la comunicación de marketing directo / mejorar nuestro sitio web y mejorar su experiencia de navegación. Por favor, vea nuestro Aviso de cookies para obtener más información acerca de las cookies, datos que recogen, que puedan acceder a ellos, y sus derechos."},"translations_notice":{"cta":"Cambiar a English","text":"¡Hola! Estamos traduciendo CGTrader. Las traducciones están en curso y algunas secciones pueden no estar disponibles en español."}},"model":{"already_purchased":"Ya has comprado este producto. Puedes descargarlo desde tu \u003ca href='/profile/cart/purchased'\u003ecarrito de compras\u003c/a\u003e. Si lo deseas, puedes comprarlo nuevamente.","animated":"Animado","artist_profile":"Perfil del artista","author":"Autor","author_get_your_payment":"El autor recibirá el 100% de tu pago. CGTrader permite a los artistas ganar al máximo y los motiva a vender contenido de alta calidad.","author_products":"Más productos de \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e","authorised_seller":"Vendedor autorizado de CGTrader","authority":"Autoridad","breadcrumb":{"3d_models":"Modelos 3D","home":"Inicio"},"bulk_download":{"download_all":"Descargar todos los archivos","files_included":{"one":"%{count} archivo incluido","other":"%{count} archivos incluidos"},"too_large":"Este modelo es demasiado grande para descargarlo como un solo archivo (más de %{limit}). Por favor, descarga los archivos individualmente."},"buy":"Comprar","cannot_download":"Solo los usuarios con %{experience_needed} puntos de reputación pueden descargar más de %{models} modelos gratuitos. Aprende más sobre niveles y reputación \u003ca href='%{reputation_url}' target='_blank'\u003eaquÃ\u003c/a\u003e.","collection":"pack 3D","contact_author":"Contactar al autor","description":"Descripción","download":"Descargar","download_limit_exceeded":"Has excedido tu lÃmite diario de descargas. Por favor, inténtalo de nuevo mañana. Este lÃmite no aplica para usuarios que han realizado una compra en los últimos 12 meses.","download_modal":{"chat_with_us":"Chatea con nosotros","contact_support":"Por favor, contáctanos a través del chat.","download_file":"Descargar %{name}","empty":"No se han encontrado archivos","generic_error":"Algo salió mal, por favor inténtalo de nuevo","link_error":"Lo sentimos, pero parece haber un pequeño problema con tu enlace de descarga.","pbr_ready":"Compatible con PBR","preparing":"Preparando tu descarga...","title":"Descargar ar
16518chivos"},"format_downloads":"Descargas de formato de software 3D","game_ready":"Listo para juegos (lowpoly)","geometry":"GeometrÃa","license":"Licencia","low_poly":"Low poly","make_offer":"Hacer oferta","materials":"Materiales","messages":{"no_files":"No hay archivos subidos","no_rating":"No hay valoraciones disponibles para este modelo aún"},"model_details":"Detalles del modelo 3D","pbr_textures":"Texturas PBR","plugin_used":"Plugin usado","polygons":"PolÃgonos","price":"Precio","print_ready":"Listo para impresión 3D","product_id":"ID del producto","product_support":"Soporte del producto","product_type":"Tipo de producto","published":"Publicado el","rated":{"error":"Ya has calificado este modelo","success":"Gracias por calificar este modelo"},"rating":"Calificación del modelo 3D","ratings":{"desc":{"negative":"Los usuarios que compraron este modelo 3D creen que es de menor calidad de lo esperado","positive":"Los usuarios que compraron este modelo 3D creen que es de buena calidad"},"negative":"negativo","positive":"positivo"},"recently_viewed_models":"Modelos vistos recientemente","renderer":"Renderizador","report":"Reportar","rigged":"RÃgido","scanned":"Escaneado","scripts-plugins":"Scripts y complementos","similar_models":"Modelos similares","statistics":"EstadÃsticas","subscription":{"limit_reached":"Has alcanzado el lÃmite de descargas para este perÃodo de facturación.","limit_reached_detailed":"Has alcanzado tu lÃmite de %{limit} descargas de este mes. Tu lÃmite se restablece el %{reset_date}. Para descargar más modelos ahora, puedes comprarlos individualmente.","limit_reached_detailed_no_date":"Has alcanzado tu lÃmite de %{limit} descargas de este mes. Para descargar más modelos ahora, puedes comprarlos individualmente."},"tags":"Etiquetas","textures":"Texturas","title":"%{item_title} modelo 3D","unwrapped_uvs":"UVs desplegadas","uv_mapping":"Mapeo UV","vat_notice":"Todos los precios son sin IVA","version":"Versión","vertices":"Vértices","vr":"Modelos VR"},"models":{"error":{"cannot_be_blank":" no puede estar vacÃo."}},"navigation":{"3d-models":{"3d-printing":"Archivos de impresión 3D","discounts":"Descuentos","find_designers":"Encuentra los mejores diseñadores","free":"Modelos en 3D gratuitos","pbr":"PBR","scanned_3d-models":"Modelos escaneados 3D","scripts_apps":"Scripts y Aplicaciones","show-all":"Mostrar todo","textures":"Texturas","title":"Modelos 3D","vr_low-poly":"VR / Low-poli"},"already_added_message":"ya ha sido añadido a la cesta","already_purchased_message":"Que ya han comprado este producto.","aria":{"account":"Cuenta","cart":"Carrito","close_menu":"Cerrar menú","logo":"CGTrader - Modelos 3D / Diseñadores 3D","messages":"Mensajes","notifications":"Notificaciones","open_menu":"Abrir menú","search":"Buscar","search_by_image":"Buscar por imagen"},"budgets":{"below_10":"Menos de $10","collections":"Paquetes","free":"Gratis","more_than_20":"Más de $20","more_than_50":"Más de $50","sale":"En Oferta","subscription":"Suscripción"},"cart_limit_reached":"Has alcanzado el lÃmite de 500 artÃculos en tu carrito. Para continuar comprando, por favor completa tu pedido actual y comienza uno nuevo para cualquier artÃculo adicional.","cart_widget":{"continue_shopping":"Continuar comprando","discount":"De descuento con el cupón de la empresa: ","discount_applied":"Descuentos aplicados:","final":"Precio final: ","have":"Tienes ","items":" artÃculos en su carrito de compras.","left_to_unlock_discounts":"Faltan {{leftToUnlock}} para desbloquear descuentos","potential_discount":"Descuento potencial:","proceed":"Pasar por la caja","recently_viewed_empty_text":"Comienza a explorar y tus artÃculos vistos recientemente aparecerán aquÃ.","recently_viewed_empty_title":"Nada aquà todavÃa","recently_viewed_tab":"Visto recientemente","remainer":"Para activar los puntos de CGTrader, añade: ","sale_discounts":"Descuentos aplicados: ","sale_time_left":"La venta termina en","sale_tooltip":"Los descuentos de nuestras campañas de venta solo se aplican cuando tu carrito llega a ${{threshold}} o más.","sale_tooltip_text":"Este artÃculo está en venta, pero el descuento solo se aplicará una vez que el subtotal de tu carrito llegue a ${{threshold}} o más.","text":"Su cesta está vacÃa.","title":"Carrito de compras","total":"Total: ","used":"Créditos utilizados: ","view":" Ver carrito","wishlist_empty_text":"Comienza a explorar y guarda tus favoritos para más tarde â aparecerán aquÃ.","wishlist_empty_title":"Tu lista de deseos está vacÃa","wishlist_tab":"Lista de deseos"},"community":{"awards":"Premios de Diseñadores ð","blog":"Blog","challenges":"DesafÃos","community_ratings":"Valoración de la comunidad","designers":"Diseñadores 3D","digital_art":"Concurso de Arte Digital","forum":"Foro","galleries":"GalerÃas","invite":"Invita a un amigo","printlist":"ImprimeLista 3D","sell_3d-models":"Vender Modelos 3D","title":"Comunidad","tutorials":"Tutoriales"},"conversations_widget":{"conversations":"conversaciones","messages":{"loading":"Cargando la bandeja de entrada"},"types":{"cgtrader_support":"Soporte CGTrader","file_conversion_request":"solicitud de conversión de archivos","
16518job_application":"Proyecto 3D","model_feedback":"Comentarios sobre el producto","model_support":"modelo de ayuda","offer":"Precio de oferta","personal":"Mensaje personal","promotions":"promociones"}},"create_ai":{"community_gallery":"GalerÃa de la comunidad","free_trial":"Prueba gratuita","generate_3d_model":"Generar modelo 3D","generation":{"dismiss":"Descartar notificación","error_title":"Problema de generación","generating_title":"Tu modelo 3D se está generando","open_model":"Abrir modelo","ready_title":"¡Tu modelo 3D está listo!"}},"create_with_ai":"Crear con IA","credits_guest_widget":{"create":"Crear una cuenta ahora!","discount":" descuento","for":" para tu ","get":" y obtener hasta ","learn_more":"Más información sobre los créditos de Fidelidad CGTrader ","link":"aquÃ","purchase":"¡primera compra!","sign-up":"RegÃstrate","text_below_1":"Los créditos pueden ser utilizados en la compra \"","text_below_2":"\"Firmar los modelos marcados y cubrir hasta el 30% de descuento del precio."},"credits_user_widget":{"condition_1":"Los puntos de CGTrader se pueden aplicar a la compra de modelos marcados con el signo \u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e, proporcionando hasta un 30% de descuento sobre su precio.","condition_2":"Los puntos solo se pueden usar si el valor total de su carrito es de \u003cstrong\u003e$%{minimum}\u003c/strong\u003e o mas.","condition_3":"Durante ventas o promociones activas, no se pueden usar puntos.","condition_4":"Tenga en cuenta que los puntos tienen una fecha de vencimiento: sus puntos caducarán en \u003cstrong\u003e%{days}\u003c/strong\u003e dias.","earn_rate":"Crédito ganan tasa ","first_text_1":"Consideramos que es un regalo para su primera compra - se puede utilizar en la compra de créditos \"","first_text_2":" \"Modelos marcados y obtener hasta un 30% de descuento de su precio. Los créditos sólo se pueden utilizar si el valor total de su compra es igual o superior a","important":"IMPORTANTE:","learn_more":"Aprende más","lifetime_spending":"Gasto de por vida: ","list_item":"Mediante el aumento de sus gastos por vida en CGTrader, su crédito ganan tasa aumenta también.","message":" Los créditos no pueden ser utilizados durante las campañas de venta, pero todavÃa se puede aumentar su nivel de regalÃas y recoger más créditos para su próxima compra.","more_credits":"¿Cómo puedo obtener más créditos?","next_level":"Siguiente nivel: ","notice":"AVISO: Los puntos de CGTrader no se pueden usar durante la venta en curso, pero estarán disponibles nuevamente una vez que finalice la venta. Mientras tanto, descubre grandes ofertas en modelos 3D \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003eaquÃ\u003c/a\u003e","par_1":"Tienes ","par_2":" CGTrader créditos.","par_2_variation":" en Puntos que puedes usar cuando los sale off no estan activos.","regular_text_1":"Los créditos pueden ser utilizados en la compra \"","regular_text_2":" \"Firmar los modelos marcados y cubrir hasta el 30% de descuento de su precio.","title":"CGTrader descuento de fidelidad"},"enterprise":{"management":"Gestión de activos 3D","title":"Producción de Contenido 3D"},"hire_a_freelancer":"Contratar freelancer","item_add_message":"éxito ha sido añadido a la cesta","item_restricted_message":"Este artÃculo no se puede comprar debido a las sanciones impuestas al paÃs del diseñador (RU/BY).","navbar":{"actions":{"new":"Nuevos","top_selling":"Más vendidos","trending":"Tendencias"},"budgets":{"below_10":"Menos de $10","free":"Gratis","more_than_20":"Más de $20","more_than_50":"Más de $50","sale":"En Oferta","up_to_10":"Hasta $10"}},"projects":{"3d_customs":"3D a medida","3d_printing":"Impresión 3D","about":"Acerca de los proyectos en 3D","browse":"Ver proyectos","buyer_perspective":"Los diseñadores de coches en 3D","for_designers":"Para diseñadores","my_projects":"Mis proyectos","seller_perspective":"Proyectos en 3D independientes","start":"Iniciar un proyecto","work":"Trabaja con CGTrader"},"sell_3d-models":"Vender Modelos 3D","sellers_hub":"Centro de vendedores","subscription_includes_item_message":"Este artÃculo ya está incluido en tu suscripción.","tooltips":{"cart":"Carrito de compras","conversations":"Mis conversaciones","discounts":"CGTrader descuento de fidelidad","notifications":"Notificaciones","publisher":"Editor"},"user":{"ban_notification":"Esta cuenta de usuario está suspendida. Por favor, contacta con nuestro soporte para obtener una explicación.","cannot_refer_yourself":"no puedes recomendarte a t
16518i mismo","email_confirmation":"Tu dirección de correo electrónico ha sido verificada.","email_reconfirmation":"ya estaba confirmada, por favor intenta iniciar sesión","ends_at":"Finaliza en: %{date}","handle_error_tfa_code_missmatch":"El código de seguridad que ingresaste es incorrecto. Por favor, inténtalo de nuevo.","handle_error_tfa_code_missmatch_last":"Tu código de seguridad ha caducado. Si deseas continuar, haz clic en reenviar correo y utiliza el nuevo código proporcionado.","handle_error_tfa_default":"Algo salió mal, por favor inténtalo más tarde.","handle_error_tfa_expired":"Tu código de seguridad ha caducado.","hundred_percent_royalties_popover":"Estás participando en una campaña temporal de ganancias del 100%: todos los ingresos de las ventas de nuevos modelos irán a ti hasta el final de la campaña","invalid_email_message":"Por favor, introduce una dirección de correo electrónico válida para continuar.","login":"Iniciar sesión","meta_description":"Mira el perfil del diseñador 3D %{username} en CGTrader, su portafolio y modelos 3D disponibles. Descubre los mejores modelos 3D de los principales artistas de la industria.","meta_title_suffix":"Diseñador 3D","not_valid_birthday":"La fecha de nacimiento no es válida.","offline":"Desconectado","online":"En lÃnea","page_title":"Perfil del diseñador","rate_models_limit":"Hoy no puedes calificar más modelos.","semantic_description":"Modelos 3D, obras y portafolio del diseñador. Mira sus creaciones en CGTrader","semantic_title":"Perfil del diseñador","session_failure":"Se ha proporcionado un nombre de usuario/correo electrónico o contraseña incorrectos","session_password_expired":"Tu contraseña ha caducado por inactividad. Restablécela a través del enlace enviado a tu correo electrónico.","session_two_fa_failure":"La verificación del código ha fallado","session_unconfirmed":"Tu dirección de correo electrónico aún no ha sido confirmada.","token_not_recognized":"El token no fue reconocido","twitter_shareable_text":"Un #3dartist que vale la pena seguir","username_error":"no debe contener espacios ni sÃmbolos que no sean latinos"},"user_menu":{"buyer":{"freelancers":"encontrar freelancers","purchases":"Mis compras","sell":"Vender Modelos 3D","wishlist":"Modelo 3D Lista"},"dashboard":"administrador del tablero de instrumentos","logout":"Cerrar sesión","public_profile":"Perfil público","seller":{"analytics":"AnalÃtica","find_new_projects":"Encontrar nuevos proyectos 3D","freelance":"Proyectos en 3D independientes","freelance_cgtrader":"Independiente con CGTrader","models":"Mis modelos","publish_project":"Publicar un proyecto","publishing":"Publicación","sales":"Mis ventas","subscription":"Suscripción","wishlist":"Modelo 3D Lista"},"settings":"ajustes"}},"number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"â¬"}}},"owly":{"failed_set_pending":"Error al establecer como pendiente.","failed_to_approve":"Error al aprobar.","failed_to_suspend":"Error al suspender.","failed_to_update_license":"Error al actualizar la licencia.","failed_to_update_status":"Error al actualizar el estado de aprobación."},"print_models":{"browse_all_makes":"Ver todos los Ejemplos 3D","browse_all_models":"Ver todos los modelos","description":"Descubre modelos populares listos para impresión 3D, recursos imprimibles y archivos STL para juegos, arte, proyectos del hogar y más.","makes_description":"Explora los últimos ejemplos 3D subidos por la comunidad - ejemplos reales impresos que muestran cómo se ven los modelos 3D en el mundo fÃsico.","makes_title":"Nuevos Ejemplos 3D","new_description":"Descubre las últimas incorporaciones a nuestra colección â diseños frescos listos para descargar e imprimir en tu próximo proyecto.","new_title":"Nuevos modelos para impresión 3D","title":"Modelos 3D de impresión en tendencia"},"profile":{"account_settings":{"account":{"email":"Correo Electrónico","submit":"Guardar","title":"Perfil","update":{"updated":"Perfil actualizado"},"username":"Nombre de Usuario"},"email_settings":{"descriptions":{"ai_studio_notifications":"Notificaciones sobre tus generaciones de CGTrader AI, incluido cuando un modelo que aún no has abierto está listo","communication":"Información sobre tu c
16518omunicación con otros usuarios de CGTrader, incluidos mensajes personales, nuevas ofertas de precios y trabajos personalizados, comentarios y solicitudes de soporte de productos","news":"Información sobre productos de CGTrader, anuncios de nuevas funciones y noticias de la comunidad","onboarding_and_edu":"Información sobre tu proceso de incorporación y consejos para aprovechar al máximo CGTrader","push_notifications":"Notificaciones sobre actividad y actualizaciones importantes de la cuenta","sales_and_offers":"Información sobre ofertas especiales, ventas de modelos 3D y créditos de bonificación de CGTrader","seller_sold_item":"Información sobre tus modelos 3D vendidos y pagos recibidos"},"privacy_policy_html":"Por favor lee nuestra \u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003ePolÃtica de Privacidad\u003c/a\u003e para más información. ","titles":{"ai_studio_notifications":"Notificaciones de CGTrader AI","communication":"Comunicación (Mensajes personales, comentarios de modelos 3D, actividad de la comunidad, ofertas)","news":"Noticias 3D / Actualizaciones de CGTrader","onboarding_and_edu":"Incorporación y Educación","push_notifications":"Notificaciones Push","sales_and_offers":"Ventas y ofertas especiales","seller_sold_item":"Información de Ventas y Pagos"},"tracking_attributes":{"ai_studio_notifications":"Notificaciones de CGTrader AI","communication":"Comunicación","news":"Noticias 3D / Actualizaciones de CGTrader","onboarding_and_edu":"Incorporación y Educación","sales_and_offers":"Ventas y ofertas especiales","seller_sold_item":"Información de Ventas y Pagos"},"update":{"updated":"Tu correo electrónico ha sido actualizado exitosamente."}},"gdpr_success_notification":{"opt_in":"¡Gracias! Te has vuelto a suscribir exitosamente a nuestros correos electrónicos.","opt_out":"Te has dado de baja exitosamente de nuestros boletines. Puedes cambiar esta preferencia en cualquier momento visitando la configuración de tu perfil.\n"},"location_tooltip_text":"\u003cdiv\u003eEsta casilla permite mostrar la ubicación en la página de perfil.\u003c/div\u003e \u003cdiv\u003eTenga en cuenta que, en cualquier caso, por razones de cumplimiento, su ubicación se mostrará a sus compradores (si es vendedor) y a los vendedores de los que compró.\u003c/div\u003e","moneybookers":{"account":"Cuenta de Skrill"},"password":{"current_password":"Contraseña actual","new_password":"Nueva contraseña","submit":"Cambiar Contraseña","title":"Contraseña","updated":"Tu contraseña ha sido actualizada exitosamente. Ahora puedes usar tu nueva contraseña para iniciar sesión.","verify_password":"Verificar contraseña"},"paypal":{"account":"Cuenta de PayPal","submit":"Guardar","title":"Configuración de PayPal","update":{"updated":"Tu configuración de PayPal ha sido actualizada"}},"personal_info":{"areas_of_expertise":"Ãreas de experiencia","country":"PaÃs","description":"Unas pocas frases sobre ti","full_name":"Nombre completo","languages":"Idiomas","preffered_tools":"Herramientas preferidas","submit":"Guardar","title":"Información personal y profesional","update":{"updated":"Tu información se actualizó exitosamente"},"website":"Sitio web"},"personalization":{"no_muted_title":"No hay diseñadores silenciados","title":"Diseñadores Silenciados","tooltip":"Los modelos 3D de los diseñadores listados están excluidos de tus resultados de búsqueda.","unmute_designer":{"confirm":"¿Estás seguro?"}},"professional_info":{"allow_private_job_requests":"Los compradores podrán enviarte solicitudes de trabajos 3D personalizados.","buyer_engagement_program_html":"Atrae más clientes permitiéndoles comprar tus modelos con CGTrader Points. \u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003eMás información\u003c/a\u003e\n","pbr_program":"La tasa de ganancia más baja se aplica solo cuando se descarga el archivo convertido.","pbr_program_agreement":"Has aceptado participar en el programa PBR durante 24 meses desde %{date}. Consulta los Términos y Condiciones para más detalles. Por favor contacta a
16518nuestro soporte si tienes alguna pregunta.","product_analytics_participation_html":"Participo en \u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eAnalytics\u003c/a\u003e y estoy de acuerdo con sus Términos y Condiciones\n","product_analytics_participation_tooltip_html":"Has aceptado participar en Analytics y estás de acuerdo con los Términos y Condiciones de Analytics (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003eenlace\u003c/a\u003e) desde %{accepted_at}. Si deseas terminar tu participación, por favor contacta al soporte de CGTrader\n"},"security":{"allow_mfa":"Habilitar verificación en 2 pasos para proteger tu cuenta","use_authenticator_app":"Usar una aplicación de autenticación para la verificación en 2 pasos","use_authenticator_app_tooltip":"Escanea el código QR con tu aplicación de autenticación (Google Authenticator / Authy) para generar códigos de verificación.","use_email":"Usar correo electrónico para la verificación en 2 pasos"},"sidebar":{"general_settigns":"Configuración General","member_since":"Miembro Desde","paypal":"PayPal","title":"Información de la Cuenta"},"title":"Mi Cuenta"},"conversations":{"conversations":"conversaciones","messages":{"loading":"Cargando la bandeja de entrada"},"types":{"cgtrader_support":"Soporte CGTrader","file_conversion_request":"solicitud de conversión de archivos","job_application":"Proyecto 3D","model_feedback":"Comentarios sobre el producto","model_support":"modelo de ayuda","offer":"Precio de oferta","personal":"Mensaje personal","promotions":"promociones"}},"meta":{"description":"Explora modelos 3D de alta calidad de %{username} en CGTrader. Navega activos únicos para juegos, VR/AR y visualización.","title":"Diseñador de modelos 3D: %{username}"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"Tu configuración se ha actualizado correctamente."},"publishing":{"banned_error":"Su cuenta ha sido suspendida por publicar contenido spam. Si cree que se trata de un error, póngase en contacto con [email protected].","files_not_finalized":"Uno o más archivos no terminaron de subirse y no se pueden publicar. ElimÃnelos y vuelva a subirlos antes de publicar.","spam_suspect":"Su cuenta no está autorizada para publicar este modelo. Si cree que se trata de un error, póngase en contacto con [email protected]."},"rating":{"anonymous_buyer":"Comprador Anónimo","errors":{"not_verified_buyer":"Solo los compradores verificados pueden dejar una reseña"}},"routes":{"3d-models":"3d-modelos","3d-print-models":"3d-de-impresion-modelos","animated-3d-models":"animados-3d-modelos","controllers":{"three_d_studio":{"3d-models":"3d-models","images":"images"}},"discover":"descubrir","free-3d-models":"gratis-3d-modelos","free-3d-print-models":"gratis-3d-de-impresión-modelos","low-poly-3d-models":"de-bajo-poli-3d-modelos","pbr-3d-models":"pbr-3d-modelos","pbr-textures":"pbr-textures","rigged-3d-models":"aparejado-3d-modelos","search":"search"},"sale_off":{"no_overlapping_campaigns":"Las fechas de la campaña se superponen con otra campaña de oferta existente.","parse_discount_rules_text":"La lÃnea #{index} no contiene el parámetro requerido 'discount:'"},"search":{"not_found":"Suscripción de búsqueda no encontrada","subscription_created":"Suscripción de búsqueda creada","successfully_unsubscribed":"Te has dado de baja correctamente de la suscripción de búsqueda"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"flash":{"active_subscription":"Ya tienes una suscripción activa.","premium_upgrade_unavailable":"La mejora a Premium no está disponible temporalmente. Inténtalo de nuevo más tarde.","update_payment_method":"Tu suscripción tiene un problema de pago. Actualiza tu método de pago en lugar de comprar una nueva suscripción."},"payment_form":{"current_price":"%{price}","features":{"first":"%{downloads} recursos / mes â descarga modelos o genera con IA","second":"Acce
16518so instantáneo a más de %{models_count} modelos 3D esenciales","third":"Libre de regalÃas, sin IA"},"from_price_label":"desde","original_price":24.99,"per_model_label":"por modelo","plan_name":"Suscripción CGTrader Essentials â plan anual, facturado mensualmente","premium":{"features":{"first":"%{downloads} recursos / mes â descarga modelos o genera con IA","fourth":"Libre de regalÃas, sin IA","second":"Acceso instantáneo a más de %{models_count} modelos accesibles en total","third":"Modelos de nivel profesional no incluidos en Essentials"},"plan_name":"Suscripción CGTrader Premium â plan anual, facturado mensualmente"},"price_unit":"/mes","vat_amount":"%{vat_amount}"}},"tag":{"description":{"bottle":"Los cientÃficos dicen que la botella de vino al dÃa no es malo para usted, pero cuando se trata de bebidas más fuertes como whisky o bourbon, que realmente deben vigilar la ingesta de alcohol. Obviamente, una copa de champán en el refrigerador de la manera bar parece que una botella de plástico de agua, pero pensar en la posibilidad de vivir una vida más larga y la cerveza se parece como un sacrificio razonable. Esta categorÃa ofrece una amplia selección de modelos en 3D de botella, que van desde los objetos relacionados con el alcohol como bastidores de vino y sacacorchos a todo tipo de botella 3D (modelos de champú al aceite de oliva).","brain":"El cerebro es uno de los órganos más grandes y más complejos del cuerpo humano. Debido a su compleja estructura y función, la anatomÃa del cerebro también es muy complejo. Sin embargo, los cientÃficos profundizar en la arquitectura del cerebro humano, el descubrimiento de secretos alucinantes. Una amplia gama de modelos en 3D del cerebro realistas y detallados están listos para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, juegos en 3D, web y cualquier otro campo relacionado con el diseño 3D está disponible para su descarga.","building":"No está claro que los arquitectos modernos se inspiran, pero algunos de los edificios famosos del mundo están tan de vanguardia que se parezcan a las visiones del futuro. Y no nos limitamos a decir la parte exterior ... En buenas manos una construcción de edificios estándar se convierte en una creación arquitectónica impresionante, con un diseño interior innovador, independientemente de si se trata de una oficina o un edificio urbano. Nuestra selección de la construcción de modelos 3D está listo para su descarga y se puede aplicar en diversos campos - animación 3D, diseño gráfico, publicidad, juegos en 3D o en la web.","camera":"La fotografÃa y la filmación es en la actualidad uno de los más campos de la carrera popular entre los jóvenes, pero no todo el mund
16518o con una cámara profesional es un artista o un fotógrafo. Con la calidad de las cámaras de teléfonos mejorando año tras año, vemos a la gente de tomar imágenes en cada paso y los que tienen la imagen recién desarrollada edición de habilidades verdaderamente célebre. La vida tiene un aspecto un poco diferente cuando estás en el otro lado de la lente, pero no vamos a dejarse llevar ... Una amplia gama de modelos de cámara 3D detallado está disponible para su descarga a ser utilizado por los diseñadores gráficos, animaciones y los desarrolladores de juegos y los profesionales que trabajan en otros campos relacionados con el 3D.","car":"En cuanto a estos modelos de coches muy detallado y altamente realistas en 3D, casi se puede oÃr el rugido del motor! Una amplia gama de modelos de vehÃculos en 3D puede hacer su vida mucho más fácil, si usted está luchando con los gráficos por ordenador, animación o cualquier otro campo 3D-relacionado.","cell":"Los cientÃficos han estimado que el cuerpo humano contiene de 5 mil millones a 200 millones de billones de células. Las plantas y los animales tienen células, también. Nosotros no queremos aburrir con esta materia de biologÃa, pero la amplia gama de teléfonos 3D modelos que tenemos abarca todo, desde la sangre, el virus y el ADN de la médula ósea y las paredes celulares. No es que ... estresante?","chair":"Tomamos sentados en sillas por sentado y no siempre se dan cuenta de cuánto se puede añadir encanto a nuestro interior hogar u oficina. Silla es en realidad una de las piezas centrales de muebles en cualquier hogar. Aquà puede encontrar modelos 3D silla de diseño llamativos que se pueden aplicar en diversos campos de alta calidad y - de la publicidad y la visualización en 3D para juegos en 3D.","city":"La vida urbana es un juego de excéntrica: calles llena de taxis de carreras, edificios modernos, los peatones en la ropa de oficina perfectamente adaptados para dormir, puentes y parques ... de Shanghai, a Nueva York (! Manhattan), a Londres o ParÃs - cada ciudad tiene su propia magia. Usted puede elegir de esta amplia selección de modelos 3D detallada de la ciudad que se puede utilizar en un número de campos - Publicidad, gráficos por ordenador, animación, visualización en 3D o juegos. Explorar la vida urbana.","dragon":"Dragón es probablemente la criatura más populares que viven en el mundo de fantasÃa. Ha aparecido en tantos mitos de culturas diferentes, animaciones, pelÃculas y libros que se ha convert
16518ido en una leyenda. Está especialmente amado por los desarrolladores de juegos, ya que añade que el encanto mágico a oscuras cuevas y mazmorras. Una amplia gama de realista, aparejado modelos 3D dragón están listos para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, juegos en 3D, web y cualquier otro campo relacionado con el diseño 3D está disponible para su descarga.","earth":"El nivel de detalle en la vista de la tierra recientemente añadido en los mapas de Google ha conmocionado a un número de personas. Usted puede explorar todo el planeta - océanos, montañas y desiertos, descubrir ciudades y caminos ocultos sin salir de su casa. Eso es algunas cosas increÃbles Madre Tierra no ha experimentado antes. Una selección de modelos 3D realistas tierra están listos para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, 3D juegos, web y cualquier otro campo relacionado con el diseño 3D está disponible para su descarga.","engine":"Algunas personas son capaces de nombrar el motor simplemente escuchando el sonido que hace, y que es realmente sorprendente. Independientemente de si se trata de un motor a reacción o un motor de automóvil, son extremadamente complicadas máquinas que utilizamos tan a menudo, pero no pasamos demasiado tiempo pensando en ello. Un motor es un motor (hasta que deja de funcionar). Esta categorÃa tiene una gama de diferentes tipos de modelos de motor 3D, y también incluye partes de motor como de la hélice o cilindro, por lo que estamos seguros de que encontrará lo que necesita.","female":"No es ninguna broma que existen diferencias significativas entre el cerebro masculino y femenino, lo que significa que es normal que un hombre y una mujer se comportan promedio, sentir y responder de una manera completamente diferente. Pero no es todo acerca de la anatomÃa. No hay historia de amor, pelÃcula o juego nunca lo logró sin un fuerte carácter de la muchacha, porque el poder de encanto dama es innegable. Una amplia selección de 3D realistas modelos de mujer que puede ofrecer todo lo que necesita - a partir de modelos 3D desnudas las vÃas respiratorias femenina.","hand":"La razón por la que usamos nuestras manos para hacer muchas cosas es su extraordinaria anatomÃa. El pulgar solo es controlado por nueve músculos separados. Es difÃcil de creer, pero las primeras manos eran más exótico que cualquier mano hoy en dÃa - algunas especies tenÃan siete dedos. El cuerpo humano ha evolucionado significativamente. Un brazo o una mano como lo vemos hoy en dÃa parece en nada a sus primeras versiones. Una amplia gama de realista, aparejado modelos de mano 3D están listos para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, 3D juegos, web y cualquier otro campo relacionado con el diseño 3D está disponible para su descarga.","head":"En anatomÃa humana, la cabeza es la parte superior del cuerpo humano. Modelado de una cabeza humana en 3D puede resultar un poco complicado, debido a que (a pesar de que hay muchas formas y tamaños diferentes) apreciamos cabezas simétricas, de aspecto realista - no hay divertidos ojos, los oÃdos, la nariz, los labios o la lÃnea de la mandÃbula, por favor. La cara es una zona sensible y que sólo serÃa grosero para divertirse con eso. Nuestra selección abarca masculino realista, mujer, niño y personajes de la historia incluso como Harry Potter y Batman o celebridades como Tom Cruise cabezas y Scarlett Johansson están listos para su descarga.","helmet":"Recuerde siempre que la salud y la seguridad es lo primero, por lo que protege su cabeza es una buena idea. caballeros medievales, Daft Punk y hasta los cascos de desgaste Ironman, superhéroes tan regulares como ciclistas o constructores no deben preocuparse de buscar fuera de moda. Esta colección de cascos 3D modelos que está disponible para su descarga será útil si está trabajando en los campos del diseño gráfico, animación 3D, 3D juegos o visualización.","house":"Es una vieja verdad de que la casa de un hombre es su castillo, pero cuando se trata de construir la casa perfecta o la compra de un apartamento ideal, que tienden a perder la cabeza sobre ella. Por suerte, esta amplia gama de modelos de la casa 3D que abarca todo, desde los detalles arquitectónicos, interiores y exteriores, a los muebles, le ayudará a crear modernas y diseño 3D para aliviar el dolor.","human":"Al iniciar la exploración de la anatomÃa humana, se da cuenta de que la gente es tan intrincada y máquinas complejas que quita el aliento. Cada combinación de parte del cuerpo, los músculos, articulaciones, órganos o de médula se conecta en un solo sistema, nada funciona de manera aislada! Estos modelos humanos 3D realistas súper le permitirá examinar las estructuras anatómicas de cada ángulo.","lamp":"Si se mira alrededor de su casa y contar los tipos de lámparas de su propiedad, usted se sorprenderá: la lectura, mesa, pared, techo, escritorio, trÃpode lámparas ... Es suficiente para hacer girar su
16518cabeza! Por no hablar de los estilos que vienen en - de las lámparas modernas extravagantes a retro o futurista con estilo. En esta categorÃa tenemos todo tipo de lámpara 3D modelos, por lo que navegar y descargar para su uso en diseño gráfico, diseño 3D o cualquier otro campo 3D-relacionado.","light":"¿Se ha preguntado por qué una bombilla de luz es el sÃmbolo de una idea brillante? Sin duda, una idea brillante puede iluminar a la arquitectura de la mente, pero eso no es todo. Una luz de calle, una lámpara de araña o cualquier otro tipo de lámpara no tendrÃa ninguna oportunidad de tomar ese lugar. Si la próxima vez cuando se mira hacia el techo y la mirada en algún tipo de luz arquitectónica de la idea del genio no le golpeó, podrÃa ser porque usted está mirando a un sistema de iluminación mal ... Nuestra selección de luz de alta calidad modelos 3D serán resultar útil si trabaja en los campos de la arquitectura, gráficos por ordenador, animación 3D o diseño.","machine":"ImagÃnese si todas las máquinas de repente dejó de funcionar: no hay café, sin lavar la ropa cómoda, no hay cajeros automáticos en una esquina de la calle, no hay tiempo gimnasio, ni demasiado caro máquinas expendedoras ... No deprimente sonido, ¿verdad? Estamos tan acostumbrados a estos electrodomésticos y aparatos que serÃa literalmente detener el giro mundo! Por suerte, nuestra selección de máquina detallada modelos 3D portadas de todo, desde ametralladoras a los generadores de electricidad que serán de utilidad para los diseñadores que trabajan con gráficos por ordenador, publicidad, animación 3D, juegos en 3D o la Web.","man":"Una gran colección de modelos 3D hombre se encuentra disponible para su descarga. hombre sentado, hombre sencillo, hombre volador o el hombre promedio, tenemos todo - excepto que el hombre perfecto que todo el mund
16518o está después. Es un personaje sospechoso y no nos gusta hablar de esto, pero podrÃa ser un mito ... Pero bueno, los seres humanos nacen a ser impresionante, no es perfecto.","robot":"R2D2 es, probablemente, el robot más famoso en el mundo, pero ciertamente no es el único. De industrial a juguete para robots humanos, vemos una opción cada vez más amplia de estas máquinas mecánicas, que es a la vez maravilloso y un poco preocupante. No es demasiado difÃcil de entender a las personas que insisten en que las computadoras, la tecnologÃa, los robots están teniendo un impacto muy significativo en los seres humanos. Una amplia gama de realista, aparejado modelos de robots en 3D están listos para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, 3D juegos, web y cualquier otro campo relacionado con el diseño 3D está disponible para su descarga.","ship":"Los barcos son embarcaciones de gran alcance y vienen en todos los tamaños, colores y formas. Pueden ser clasificados como buques de carga, buques de guerra o buques de pasaje, pero todos ellos operan en aguas de alta mar. Si usted ha experimentado la incomodidad de la enfermedad de movimiento, puede que no sea una de sus medios de transporte preferido, pero muchas personas consideran como excursiones en barco bastante elegante y agradable. Nuestra selección de modelos de barcos en 3D está listo para su descarga y cumplirá con los estándares de incluso el capitán más exigentes.","skeleton":"El esqueleto humano o sistema esquelético (anatomÃa) es el marco interno del cuerpo que se compone de 270 huesos en el nacimiento. Se proporciona la estructura de la carrocerÃa, la protección y el movimiento y es uno de los sistemas más complejos esqueléticos. Una amplia selección de anatómicamente correcta, realista y escalado esqueleto modelos 3D que son perfectos para su uso en la animación 3D, diseño gráfico, publicidad, juegos en 3D y la web está disponible para su descarga.","skull":"El más antiguo cráneo humano más completa, genéticamente intacta fue descubierto rodeado de una gran variedad de animales extintos más de 40 metros bajo el nivel del mar. Es uno de los esqueletos más antiguos encontrados en el Nuevo Mundo y también incluye todos los principales huesos del cuerpo y un cráneo intacto y conjunto de dientes. cráneos humanos se han convertido recientemente en una cosa en la moda y el diseño, pero cuando realmente se da un poco de pensamiento, que tipo de hacer que todos se parecen a los monstruos de anatomÃa ... Esta categorÃa ofrece una amplia gama de modelos de cráneo 3D para ser utilizado en el diseño gráfico , animación 3D, juegos en 3D o la publicidad.","sofa":"De lujo o simple, moderno o antiguo, cuero o diseño minimalista? ¿Qué le parece su sofá? La gama de modelos en 3D sofá que tenemos para satisfacer a la peor perfeccionista. Cuando uno se detiene a pensar en ello, sofá es el centro de cada sala de estar, por lo que debe ser creativos al elegir el diseño!","table":"Las nuevas tendencias de muebles son tan diversas que la elección de una mesa moda moderna se está convirtiendo en demasiado estresante. Hay que solÃa ser un momento en que habÃa una mesa simple para sus fiestas modestas y eso fue suficiente, pero hoy en dÃa - la tabla se supone que es una declaración o, al menos, un acento interior impresionante. Esta selección le da una amplia gama de modelos de mesa en 3D para atender a todos los caprichos.","tower":"Cada ciudad tiene una torre especial que todo el mund
16518o está muy orgulloso. Piense Torre Eiffel o la torre de Pisa, o puente de la torre de Londres, por no hablar de todos los modernos rascacielos, edificios futuristas y el paisaje urbano que los turistas admiran. Sin embargo, cuando se trata de las piezas industriales de la ciudad, el agua o torres eléctricas, todos tienden a girar sus ojos lejos ... Pero debemos aprender a apreciar cada creación arquitectónica, no importa antiguo, industrial o moderna. Una gama de modelos de torre detallada en 3D están disponibles para su descarga y listo para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, 3D juegos, web y cualquier otro campo relacionado con el diseño 3D.","tree":"Si usted está en una misión para plantar algunos árboles o plantas exóticas, has venido al lugar correcto. Esta categorÃa ofrece una amplia gama de uso fácil de, modelos muy realistas de árboles en 3D a artistas y arquitectos CG, que se esfuerzan por añadir algo de verde a sus proyectos. Si usted aprecia buena calidad, estamos seguros de que esta selección de modelos de plantas de árboles en 3D se adapte a sus estándares!","truck":"La conducción de un camión es un trabajo duro, especialmente si usted necesita para encontrar su camino a través de un atasco de tráfico de la ciudad. Independientemente de si se trata de un camión de bomberos, camión de basura, camión de comida o un ser genérico, se necesita una gran habilidad para maniobrar estos vehÃculos gigantes. Estamos seguros de que esta selección de realistas, camiones modelos 3D de alta calidad son perfectos para su uso en la animación 3D, diseño gráfico, publicidad o cualquier otro campo relacionado 3D.","tv":"SolÃa ââhaber un momento en que la chimenea era la pieza central de cada hogar respetable, ahora aparato de TV con los jugadores y los altavoces es el rey de la sala de estar (e incluso el dormitorio). En los últimos años la televisión ha puesto al dÃa con la última tecnologÃa. Como resultado, tenemos pantallas de televisión en 3D inteligente, planas y de plasma, millones de nuevas funciones y diseño de pantalla táctil. No es de extrañar la televisión está empujando el cine fuera del mercado. Una amplia gama de modelos realistas, detallados de TV 3D están listos para aplicaciones gráficas de ordenador, como la publicidad, la visualización en 3D, juegos en 3D, web y cualquier otro campo relacionado con el diseño 3D está disponible para su descarga."}},"tag_promotion":{"days_left_error":"debe estar entre 1 y 30","no_other_pending_promotions_for_same_item_tag":"ya tiene una promoción pendiente"},"tooltips":{"buyer_loyalty_program_current_level_html":"Actualmente se han gastado %{total_price_paid} en CGTrader y su crédito ganar tasa es %{buyer_loyalty_rate}. \u003cbr/\u003e Esto significa que obtendrá %{buyer_loyalty_rate} de créditos de cada compra.\n","buyer_loyalty_program_html":"Este es el porcentaje de la cantidad que se obtiene de sus compras como nuevos créditos. \u003cbr/\u003e Se aumentará hasta un 30% en sus gastos de por vida en aumento CGTrader. \u003cbr/\u003e ganar Actualmente su crédito tasa es %{buyer_loyalty_rate}.\n","buyer_loyalty_program_next_level_html":"Siguiente nivel %{next_lvl_expenses} aumentará su crédito ganan velocidad de hasta % {next_lvl_expenses_rate}. \u003cbr/\u003e usted necesita comprar por $%{left_until_next_lvl} más para llegar a un nivel superior.\n"},"trending_headers":{"models":"Consulta otros modelos 3D en tendencia","print":"Consulta otros modelos 3D para impresión en tendencia"},"tutorial":{"destroy":"El tutorial se ha eliminado correctamente.","submit_for_review_error":"Por favor, completa todos los campos obligatorios.","submitted":"Gracias por enviar tu tutorial. Será revisado y publicado en breve."},"valvat":{"country_adjectives":{"at":"austriaco","be":"belga","bg":"búlgaro","cy":"chipriota","cz":"checo","de":"alemán","dk":"danés","ee":"estonio","es":"español","eu":"europeo","fi":"finlandés","fr":"francés","gb":"británico","gr":"griego","hu":"húngaro","ie":"irlandés","it":"italiano","lt":"lituano","lu":"luxemburgués","lv":"letón","mt":"maltés","nl":"holandés","pl":"polaco","pt":"portugués","ro":"rumano","se":"sueco","si":"esloveno","sk":"eslovaco"}}},"fr":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"Adulte ou contenu violent","ai_generated":"Contenu généré par IA","copyright":"violation de copyright"}}},"errors":{"messages":{"embedded_script":"Ce fichier n'est pas pris en charge et ne peut pas être importé. Veuillez essayer un autre fichier."}}},"api":{"profile":{"actions":{"contact":"Contact","follow":"Suivre","follow_tooltip":"Commencez à suivre ce designer pour recevoir des mises à jour sur son contenu et filtrer facilement vos favoris dans les résultats de recherche.","hide":"Masquer","hire_me":"Engagez-moi","invite_client":"Lancer un projet","mute_tooltip":"Masquez les modèles de ce designer dans les résultats de recherche.","take_over":"Prendre le contrôle","unfollow":"Ne plus suivre","unhide":"Afficher","view_all_models":"Voir tous les modèles du designer"},"private_project_review":"Projet privé"}},"browser":{"3d_models":"modèles 3D","3d_print":"Impression 3D ","active_filters":{"polygons":"%{range} polygones"},"adult_content":"Afficher l'âge +","animated":"Animé","breadcrumb":{"browse_by_type":"Parcourir par type","collection":"packs 3D","free":"libre","free_models":"Modèles 3D gratuits","free_print_models":"Modèles d'impression 3D gratuits","low_poly":"low-poly","low_poly_models":"VR / AR / low-poly 3D Modèles","low_poly_print_models":"Modèles 3D d'impression Low-Poly","model_3d":"modèle 3D","model_3dp":"modèle d'impression 3D","models":"Modèles 3D","models_3d":"modèles 3D","models_3dp":"modèles d'impression 3D","models_variant_0":"Modèles 3D","models_variant_1":"Ressources 3D","models_variant_2":"Modèles VR","models_variant_3":"Modèles CG","models_variant_4":"Boutique de modèles 3D","models_variant_5":"Objets 3D","print_models":"Fichiers d'impression 3D","print_models_variant_0":"Modèles pour impression 3D","print_models_variant_1":"Modèles d'imprimante 3D","print_models_variant_10":"Modèles 3D pour impression","print_models_variant_11":"Modèles 3D à imprimer","print_models_variant_12":"Fichiers 3D pour impression","print_models_variant_13":"Modèles pour imprimante 3D","print_models_variant_14":"Modèles pour impression 3D","print_models_variant_15":"Modèles d'impression 3D","print_models_variant_16":"Fichiers 3D imprimables","print_models_variant_2":"Modèles 3D à imprimer","print_models_variant_3":"Modèles d'impression 3D","print_models_variant_4":"Fichiers d'impression 3D","print_models_variant_5":"Fichiers pour impression 3D","print_models_variant_6":"Fichiers pour imprimante 3D","print_models_variant_7":"Modèles 3D imprimables","print_models_variant_8":"Modèles 3D à imprimer","print_models_variant_9":"Modèles 3D imprimés"},"buyer_engagement_program":"Réductions","categories":"Catégories","category":{"meta":{"3d_models":"%{count} %{category} modèles 3D disponibles en téléchargement dans un format de fic
16518hier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Télécharger %{count} %{category} Modèles d'impression 3D prêts à FDM, SLA, SLS et autres imprimantes 3D, STL formats disponibles, OBJ, 3DM et plus.%{page}","animated_3d_models":"%{count} %{category} d'animation des modèles 3D disponibles en téléchargement dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Télécharger %{count} %{category} 3D gratuits modèles, disponibles en MAX, OBJ, FBX, 3DS, formats de fichiers C4D, prêts pour VR / AR, animation, jeux et autres projets 3D.%{page}","free_3d_print_models":"Télécharger %{count} %{catégorie} Modèles d'impression 3D prêts à FDM, SLA, SLS et autres imprimantes 3D, STL formats disponibles, OBJ, 3DM et plus.%{page}","lowpoly_3d_models":"Télécharger %{count} VR / AR / low-poly %{category} modèles 3D prêts pour la réalité virtuelle, des jeux et d'autres applications à temps réel, disponible en FBX, OBJ, MAX, 3DS, les formats de fichiers C4D. %{page}","rigged_3d_models":"%{count} %{category} gréé modèles 3D disponibles en téléchargement dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"collection":"pack 3D","discounts":"Réductions","ext":{"meta":{"3d_models":"Téléchargez %{rounded_count} modèles 3D au format %{format_upper}. Fichiers %{format_lower} gratuits et premium.","3d_print_models":"Télécharger %{count} %{ext} fichiers - %{software_name} modèles d'impression 3D prêts à VR / AR, la conception 3D, l'animation, des jeux et des applications en temps réel%{page}."}},"filter":"Filtre","filter_button":"Appliquer les filtres","filters":{"adult_content_only":"Contenu adulte uniquement","cgt_standard_only":"Norme CGT","collections_only":"Packs uniquement","content_filters":"Filtres de contenu","designer":"Designer","exclude_3d_print":"Exclure impression 3D","exclude_adult_content":"Exclure contenu adulte","exclude_ai_generated":"Exclure contenu généré par IA","exclude_editorial_license":"Exclure licence éditoriale","exclude_free":"Exclure gratuits","file_format":"Formats de fichier","following":"Abonnements","free":"Gratuit","has_marmoset":"Avec visionneuse 3D","has_video":"Avec vidéo","include_ai_generated":"Inclure contenu généré par IA","label":"Filtres","poly_count":"Nombre de polygones","print_ready":"Impression 3D","stl_files":"Fichiers STL","subscription":"Abonnement","type":"Type"},"formats":"Formats","free":"Gratuit","free_models":"Afficher uniquement les modèles gratuits ","free_to_premium":{"main":"modèles 3D %{category}","postfix":"dans la liste premium.","prefix":"Avez-vous besoin de quelque chose de spécial ? Vous pouvez trouver une meilleure qualité"},"gallery":{"preview":"aperçu"},"game_ready":"Prêt pour le jeu","high_poly":"Haut-poly","items_page_title":"Modèles 3D","license":{"exclude_branded":"Exclure les marques","exclude_editorial":"Exclure l'éditorial","prompt":"Licence","tooltip_more":"Lire la suite","tooltip_text":" Ne pas montrer les modèles qui ne peuvent être utilisés qu'à des fins non commerciales, éducatives.","tooltip_title":"Exclure l'éditorial:"},"low-poly":"Low-poly","low_poly":"Low-poly","meta":{"3d_models":"Téléchargez ou achetez %{rounded_count} modèles 3D professionnels. Modèles gratuits et premium pour jeux, cinéma, VFX, AR/VR et impression 3D. FBX, OBJ, BLEND, GLB.","3d_print_models":"Téléchargez %{rounded_count} fichiers 3D pour impression 3D. Fichiers STL gratuits et premium pour imprimante 3D: figurines, miniatures, déco et plus.","animated_3d_models":"Téléchargez %{rounded_count} modèles 3D animés avec animations incluses. Personnages et objets game-ready en FBX, BLEND, GLB.","free_3d_models":"Téléchargez %{rounded_count} modèles 3D gratuits, libres de droits. Objets 3D et fichiers 3D gratuits en FBX, OBJ, BLEND et GLB.","free_3d_print_models":"%{rounded_count} fichiers STL gratuits pour imprimante 3D. Téléchargez des fichiers 3D et figurines à imprimer gratuitement.","lowpoly_3d_models":"Téléchargez %{rounded_count} modèles 3D low poly pour jeux, AR/VR et rendu temps réel. Gratuits et premium.","metaverse":"Entrez dans le métaverse avec notre collection de modèles 3D hauts et à faible puant gréés, animés et disponibles n'importe quel format de fic
16518hier.","omniverse":"Construisez votre monde virtuel avec nos modèles 3D prêts pour l'omniverse. Choisissez parmi les modèles animés, truqués et PBR avec nombre de polygones élevés et bas.","page_prefix":"Page %{page_number} avec","pbr_3d_models":"Téléchargez %{rounded_count} modèles 3D avec textures PBR pour Unity, Unreal et moteurs temps réel.","rigged_3d_models":"Téléchargez %{rounded_count} modèles 3D riggés avec squelette, prêts à animer dans Blender, Maya, 3ds Max, Unity et Unreal.","snap-ar":"Avec nos modèles 3D, vous pouvez rejoindre Million of Snapchatters en utilisant Snap AR pour créer des expériences de réalité augmentée amusantes.","spark-ar":"Illuminez votre Facebook et Instagram avec une variété de modèles Spark AR 3D qui sont truqués, animés et prêts à l'emploi.","stream_3d_print_models":"Parcourez une variété de flux catégories de modèles d'impression 3D pour découvrir quelques-unes des plus extraordinaires dessins imprimables en 3D des créateurs professionnels 3D.","textures":"%{count} Textures actifs et matériaux 3D disponibles en téléchargement dans différents formats, y compris .tga .sbsar .jpeg .png .tiff et autres. %{page}","tiktok":"Rendez vos effets vidéo plus impressionnants avec les modèles TIKTOK 3D. Notre bibliothèque peut répondre à tous vos besoins créatifs et est constamment mis à jour.","unity":"Trouvez des modèles 3D pour votre projet Unity dans n'importe quel format de fichier et tout nombre de poly. Tout ce dont vous avez besoin pour créer un environnement virtuel unique.","unreal":"Créez des visualisations impressionnantes avec des modèles 3D de moteur Unreal dans n'importe quel format de fichier. Notre bibliothèque a des modèles faibles et élevés de toutes les catégories."},"optimized":"Faible poly / PBR","page_title":{"animated_3d_models":"Modèles 3D Animés â Gratuits \u0026 Premium","format_page":"Modèles 3D %{format_upper} â Fichiers %{format_lower} Gratuits \u0026 Premium","free_3d_models":"Modèles 3D Gratuits â Télécharger","free_3d_print_models":"Fichiers STL Gratuits â Impression 3D","lowpoly_3d_models":"Modèles 3D Low Poly â Gratuits \u0026 Premium","pbr_3d_models":"Modèles 3D PBR â Gratuits \u0026 Premium","rigged_3d_models":"Modèles 3D Riggés (Rigged) â Gratuits \u0026 Premium","software_page":"Modèles 3D %{software} â Télécharger %{ext_file}","tag":{"3d_merged_premium":"%{tag_cap} 3D â Modèles 3D Gratuits \u0026 Premium","3d_merged_premium_print":"Fichiers STL %{tag_cap} â Impression 3D","3d_models":"%{tag_cap} 3D â Modèles 3D Gratuits \u0026 Premium","3d_print_models":"Fichiers STL %{tag_cap} â Impression 3D"}},"pbr":"PBR","per_page":"Par page","polygons_options":{"custom":"Gamme personnalisée","gt_250k":"250k +","lt_5k":"Jusqu'à 5 k","more_than_250000":"250K+","prompt":"Nombre de poly ","range_0_5000":"Jusqu'à 5K","range_100000_250000":"100 - 250K","range_10000_50000":"10 - 50K","range_100k_250k":"de 100k à 250k","range_10k_50k":"de 10k à 50k","range_50000_100000":"50 - 100K","range_5000_10000":"5 - 10K","range_50k_100k":"de 50k à 100k","range_5k_10k":"de 5k à 10k"},"price":"Prix: $%{from}-%{to}","price_range":"Prix","print_ready":" Prêt pour l'impression en 3D","printable":"Impression 3D","reset_button":"Réinitialiser les filtres","rigged":"Squeletté","rounded_count":{"delimiter":" ","exact":"%{n}","million":"%{n} M+","separator":",","thousand":"%{n}+"},"sale_off":"En promotion","search_placeholder":"Rechercher des mots-clés","show_all_formats":"Afficher tous les formats","simulation_ready":"Prêt pour la simulation","software":{"meta":{"3d_models":"Téléchargez %{rounded_count} modèles 3D pour %{software}. Fichiers %{ext_file} gratuits et premium, prêts à importer."}},"sort_by":"Trier par","sort_by_options":{"best_match":"Pertinence","highest_price":"Prix décroissant","lowest_price":"Prix croissant","newest":"Plus récent","oldest":"Plus ancien","sales":"Meilleures ventes","trending":"Tendances"},"subcategory":{"meta":{"3d_models":"%{count} %{category} modèles 3D disponibles en téléchargement dans un format de fic
16518hier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Télécharger %{count} %{category} Modèles d'impression 3D prêts à FDM, SLA, SLS et autres imprimantes 3D, STL formats disponibles, OBJ, 3DM et plus.%{page}","animated_3d_models":"%{count} %{category} d'animation des modèles 3D disponibles en téléchargement dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Télécharger %{count} %{category} 3D gratuits modèles, disponibles en MAX, OBJ, FBX, 3DS, formats de fichiers C4D, prêts pour VR / AR, animation, jeux et autres projets 3D.%{page}","free_3d_print_models":"Télécharger %{count} %{catégorie} Modèles d'impression 3D prêts à FDM, SLA, SLS et autres imprimantes 3D, STL formats disponibles, OBJ, 3DM et plus.%{page}","lowpoly_3d_models":"Télécharger VR / AR / low poly %{tag} modèles 3D prêts pour la réalité virtuelle, jeux et autres applications à temps réel, disponible en FBX, OBJ, MAX, 3DS, les formats de fichiers C4D.%{page}","rigged_3d_models":"%{count} %{category} gréé modèles 3D disponibles en téléchargement dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"subtitle":{"aircraft":"Avions modèles 3D %{count} sont disponibles en téléchargement sur notre marché. CG %{airplanes_link} s'intégrera dans des simulations, des visualisations, des publicités et des vidéos. %{drone_link} corps et parties ravira les amateurs de véhicules petits volants. Et les %{rigged_link} modèles sont prêts à être importés dans les moteurs de jeu et être utilisé pour l'animation ou des projets VR / AR. Jeux volants, simulateurs et vidéos à la fois CG régulière et types à faible poly peuvent être remplis avec des modèles 3D dans la plupart des formats populaires, y compris FBX, OBJ, MAX, 3DS, C4D.","animals":"%{count} de CG animaux 3D - %{cats_link}, %{horses_link}, %{bears_link}, %{rhinos_link}, %{eagles_link}, %{lions_link}, fictif de %{dragons_link} et plus - sont disponibles ici pour le téléchargement. La collection de la faune 3D satisfera les besoins des publicités ou des scènes statiques. Nous avons aussi %{rigged_link} modèles pour les jeux, l'animation, la production vidéo et VR / projets AR. Utilisez les filtres pour trouver truquées, animé, low-poly ou libres modèles 3D disponibles dans la plupart des formats de fichiers reconnues par l'industrie, y compris FBX, OBJ, MAX, 3DS, C4D, et d'autres.","animated":"Téléchargez %{rounded_count} modèles 3D animés avec des mouvements prêts à l'emploi: personnages, animaux et objets pour jeux, cinéma et temps réel.","architectural":"%{count} de modèles architecturaux 3D disponibles en téléchargement contient des éléments et des détails de l'architecture, la construction et la conception technique. Pour acheter ou télécharger un modèle 3D libre, parcourir les catégories ci-dessus. Vous pouvez utiliser des modèles pour l'animation ou des jeux - certains d'entre eux sont truqués et low poly pour servir VR / AR besoins du projet. modèles 3D sont disponibles dans des formats de fichiers tels que FBX, OBJ, MAX, 3DS, C4D.","car":"%{count} voiture modèles 3D sont disponibles pour téléchargement. Les versions à faible poly dont seront attrayants pour les concepteurs de jeux ou d'applications VR / AR développeurs, d'autres - à des cinéastes, animateurs ou annonceurs. Des voitures antiques et classiques à ceux de course et concepts vus dans les films, il y a une grande variété de modèles d'automobiles 3D essentiellement tout format (FBX, OBJ, MAX, 3DS, C4D, etc.) que vous pourriez avoir besoin. Utilisez modèles 3D animés gratuits et de prototype et de raccourcir le temps de développement.","character":"%{count} Caractères modèles 3D sont disponibles en téléchargement, donc parcourant cette catégorie, vous trouverez des modèles de 3D %{human_link}, personnages, figures mythiques, de science-fiction %{robots_link}, des vêtements et d'autres choses liées à des personnages. De %{heart_link} et %{hand_link} à réaliste détaillé de %{male_link} ou modèles de %{female_link}. Un certain count de modèles sont truqués et pourrait être facilement ajouté à votre jeu, projet VR / AR, vidéo ou animation. Les deux poly haut et modèles bas poly peuvent être trouvés dans un certain count de formats, y compris FBX, OBJ, MAX, 3DS, C4D.","custom"
16518:"Ici, vous pouvez acheter ou télécharger gratuitement %{tag} modèles 3D. %{tag_heading_subtitle}","electronics":"%{count} électronique des modèles 3D disponibles pour le téléchargement. Cette catégorie pour les architectes, décorateurs d'intérieur, les concepteurs de niveau, les responsables de la scène et d'autres créateurs. modèles 3D de %{smartphones_link}, %{laptops_link}, %{cameras_link}, %{tvs_link} et plus vous aideront à saisir avec précision l'obsession de la vie moderne avec des appareils et de la technologie. Il existe des modèles 3D disponibles dans des formats de fichiers, y compris FBX, OBJ, MAX, 3DS, C4D. Télécharger gratuitement ou acheter des modèles haut de gamme et de l'utilisation pour l'animation, des jeux et des projets VR / AR.","exterior":"%{count} de l'extérieur architectural des modèles 3D disponibles pour la gamme de téléchargement de façades, bâtiments urbains, objets de paysage, maisons d'habitation à des constructions industrielles, des bâtiments d'infrastructure et pleine échelle modèles de %{city_link}. Pour acheter ou télécharger un modèle 3D libre, parcourir les catégories ci-dessus. Utilisez les filtres pour trouver truqué, animé, low-poly, modèles 3D gratuits ou trier selon le format nécessaire, y compris FBX, OBJ, MAX, 3DS, C4D. Certains actifs sont faibles poly et pourrait vous aider à compléter l'environnement dans votre jeu ou une application VR / AR.","food":"%{count} aliments modèles 3D sont disponibles pour download..Food sert bien pour créer des scènes réalistes de la vie domestique. fruits 3D, les légumes, les boissons et les repas sont ici à des annonces complètes pour les restaurants, les applications AR pour manger plus sain et visualisations architectes et designers d'intérieur travaillent. Que vous soyez à la recherche de 3D et %{pizza_link} modèles de %{ketchup_link} ou un modèle 3D d'un de mariage de %{cake_link}, ils sont là . Un certain count de versions de poly-bas sont disponibles pour ceux dans le jeu, le développement VR / AR. Les modèles 3D peuvent être trouvés dans FBX, OBJ, MAX, 3DS, formats C4D.","formats":"Téléchargez %{rounded_count} modèles 3D au format %{format_upper}, gratuits et premium. Chaque fichier de cette page est disponible en %{format_upper} natif, sans conversion.","free_general":"Téléchargez %{rounded_count} modèles 3D gratuits pour vos projets personnels et commerciaux. Objets 3D et fichiers 3D gratuits, libres de droits, en FBX, OBJ, BLEND et GLB.","free_no_tag":"%{model_count} gratuit 3D modèles %{tag} prêt pour l'impression 3D. Télécharger %{tag} gratuits modèles d'impression 3D, les formats de fichiers disponibles, y compris STL, OBJ, 3DM, 3DS, MAX. modèles 3D sont prêts à être utilisés avec FDM, SLA, SLS et d'autres types d'imprimantes 3D.","free_printable":"Téléchargez %{rounded_count} fichiers STL gratuits pour imprimante 3D: figurines, miniatures, objets utiles et déco à imprimer en 3D gratuitement, testés par la communauté.","free_tag":"Modèles 3D %{tag} disponibles pour téléchargement. Disponible dans de nombreux formats de fichiers, y compris MAX, OBJ, FBX, 3DS, STL, C4D, MELANGE, MA, MB. Trouvez professionnels de %{tag_link} pour tout projet de conception 3D comme la réalité virtuelle (VR), la réalité augmentée (AR), les jeux, la visualisation ou de l'animation 3D.","furniture":"%{count} meubles modèles 3D disponibles en téléchargement comprennent des tables, chaises, canapés, lits et autres meubles dans une variété de textures (bois, métal, etc.) et de styles (%{retro_link}, %{modern_link}, etc. ). Cette catégorie est destinée à toute personne impliquée avec l'architecture et le design intérieur, ainsi que les annonceurs et les animateurs. actifs en temps réel peuvent aider les développeurs de jeux et d'applications VR / AR à des projets complets. Utilisez les filtres pour trouver truqué, animé, faible ou poly Modèles 3D. Disponible dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.","general":"Téléchargez ou achetez %{rounded_count}
16518 modèles 3D professionnels: objets 3D et assets pour jeux, cinéma, VFX, AR/VR et impression 3D. Gratuits et premium, en FBX, OBJ, BLEND, GLB et plus de 100 formats.","high_poly":"Acheter ou télécharger des modèles 3D d'animation professionnels prêts à être utilisés dans des projets CG, la production de films et de vidéos, animation, visualisations, et d'autres. Les actifs sont disponibles en téléchargement dans de nombreux formats acceptés par l'industrie, y compris MAX, OBJ, FBX, 3DS, UE4 et autres. Si vous êtes à la recherche de haute qualité poly actifs 3D, nous avons une importante bibliothèque d'art numérique pour tous vos besoins.\n","household":"%{count} ménages modèles 3D disponibles en téléchargement peuvent être utilisés pour donner des détails aux chambres. Vous voudrez peut-être mettre un ensemble de dîner sur la table, ont des récipients de poivre et de sel à l'intérieur de la cuisine complète, ou mettre un peu %{lights_link} et %{flowers_link} près du lit pour créer la sensation de luxe. Si vous êtes un architecte d'intérieur, animateur, l'application VR / AR ou créateur jeu, cette catégorie est pour vous. Utilisez les filtres pour trouver truqué, animé, faible ou poly Modèles 3D. Disponible dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.","industrial":"%{count} industriels modèles 3D disponibles pour téléchargement - matériaux de construction, %{engineering_link} outils, machines et %{containers_link} - fournira les détails et interactifs, des éléments truqués pour créer des environnements animés. Cette catégorie est parfaite pour les simulations / VR / AR ou les développeurs de %{construction_link} niveau du site dans le jeu. Les modèles 3D serviront les professionnels du bâtiment qui travaillent avec des visualisations précis des logiciels variés que les modèles dans des formats tels que FBX, OBJ, MAX, 3DS, C4D sont disponibles.","interior":"%{count} intérieur des modèles 3D sont disponibles pour le téléchargement et comprennent des éléments et des détails utilisés dans l'architecture, la construction et l'ingénierie, design d'intérieur. Pour acheter ou télécharger prime un modèle 3D gratuit, parcourir les catégories énumérées ci-dessus. Vous pouvez utiliser des modèles pour l'animation ou des jeux - certains d'entre eux sont truquées, animé et low poly. Disponible dans une variété de formats de fichiers, y compris FBX, OBJ, MAX, 3DS, C4D.","low_poly":"Téléchargez %{rounded_count} modèles 3D low poly: des assets légers et game-ready pour les jeux, l'AR/VR et les projets mobiles.","military":"%{count} 3D des modèles militaires d'armes, armes,%{swords_link} et de l'artillerie à la fois moderne et historique utilisés par les forces militaires et la légitime défense sont disponibles pour téléchargement. Vous pouvez utiliser des modèles pour les jeux ou le contenu VR / AR - certains d'entre eux sont des polygones optimisés et prêts à être ajouté à un moteur de jeu. modèles gréés et animés peuvent faciliter davantage votre travail. Vous trouverez sûrement des actifs pertinents car il existe de countux modèles 3D disponibles dans un format de fichier que vous pourriez avoir besoin (FBX, OBJ, MAX, 3DS, C4D, etc.).","not_custom":"Téléchargez %{rounded_count} modèles 3D de %{tag_low}: gratuits et premium, réalistes et stylisés, en FBX, OBJ, BLEND et GLB.","optimized":"Les modèles qui ont moins de polygones sont mieux utilisés dans des applications en temps réel qui nécessitent un traitement rapide, comme la réalité virtuelle (VR), la réalité augmentée (AR), la réalité mixte (MR), la réalité croisée (XR) et des jeux, en particulier les jeux mobiles. Faites votre choix parmi notre collection de modèles truqués et animés de les utiliser facilement dans vos applications en temps réel. Obtenez 3D actifs pour les environnements, choisissez des accessoires, des objets ou acheter des collections complètes modèles 3D, des paquets et des paquets avec tout ce que votre jeu pourrait avoir besoin. Gagnez du temps de développement et les coûts, assurez-vous des expérience
16518s de prototypes ou de l'utilisation de modèles 3D comme des espaces réservés dans votre projet. Physiquement basé rendu, ou PBR, désigne les modèles qui sont rendus avec précision et de manière cohérente dans toutes les conditions d'éclairage en raison de la texturation les flux de travail utilisés dans le processus de création.\n","pbr":"Téléchargez %{rounded_count} modèles 3D avec textures PBR (rendu physique réaliste): des matériaux cohérents et réalistes pour Unity, Unreal et les moteurs temps réel.","plant":"%{count} plantes modèles 3D disponibles pour téléchargement contiennent des organismes de la flore qui poussent comme des plantes domestiques et dans la nature, comme les fleurs, %{trees_link}, herbe, barboteuses, verdure, herbes, plantes vivaces, plants, pousses, des arbustes, des glissades, les choux, les vignes, les mauvaises herbes. Pour acheter ou télécharger prime un modèle 3D libre, parcourir les catégories ci-dessus pour trouver le meilleur ajustement entre les modèles disponibles. Utilisez les filtres pour trouver truquées, animé, low-poly (pour une utilisation dans les jeux et VR / applications AR) modèles, ou pour filtrer les formats requis (modèles FBX, OBJ, MAX, 3DS, C4D et plus sont disponibles).","printable":"Téléchargez %{rounded_count} fichiers 3D pour votre imprimante 3D: fichiers STL gratuits et premium, testés pour l'impression FDM et résine. Figurines, miniatures, déco, outils et pièces détachées.","printable_merged_tag":"Téléchargez %{rounded_count} fichiers STL de %{tag_low} pour imprimante 3D: modèles gratuits et premium pour impression FDM et résine.","printable_tag":"Téléchargez %{rounded_count} fichiers STL de %{tag_low} pour imprimante 3D: modèles gratuits et premium pour impression FDM et résine.","rigged":"Téléchargez %{rounded_count} modèles 3D rigged (riggés): personnages, animaux et créatures avec squelette, prêts à animer dans Blender, Maya, 3ds Max, Unity et Unreal.","scanned":"%{count} scannée modèles 3D sont disponibles à l'achat ou téléchargement gratuit. Les modèles 3D sont scannées prêts pour l'animation, des jeux et des projets VR / AR. Vous pouvez trouver des modèles 3D d'objets trouvés dans la nature tels que des roches et des surfaces naturelles, les humains et les autres objets ... la vraie vie ici et il ne peut pas obtenir plus réaliste que ça. Utilisez les filtres pour trouver truqué, animé, faible ou poly Modèles 3D. Disponible dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.","science":"%{count} la science modèles 3D disponibles en téléchargement dans cette gamme de catégorie de la médecine, la biologie, la physique, les champs de la chimie et d'autres objets du monde réel liés à la science et de la technologie: matériel de laboratoire, des organismes microscopiques et dans le monde subatomique. Ne cherchez pas plus loin,%{cell_link}, et %{skull_link}, %{skeleton_link} modèles 3D peuvent être trouvés ici! Pour acheter ou télécharger un 3D gratuitement actifs, parcourir les catégories ci-dessus. Vous pouvez utiliser des modèles pour les truquées d'animation ou poly faible pour les jeux et les projets VR / AR. Les deux modèles gratuits et premium 3D peuvent être trouvésdans un certain count de formats de fichiers, y compris FBX, OBJ, MAX, 3DS, C4D.","scripts_plugins":"%{count} Scripts 3D / plugins sont disponibles pour téléchargement. Scripts 3D / plugins peuvent être ajoutés à différents logiciels et utilisés pour rendre votre pipeline de travail plus efficacement. Filtrer par formats pour trouver des outils adaptés à vos logiciels préféré.\n","software_page":"Téléchargez %{rounded_count} modèles 3D pour %{software}, gratuits et premium. Les fichiers %{ext_file} natifs s'ouvrent directement ; les autres formats s'importent en quelques clics.","space":"%{count} espace modèles 3D sont disponibles en téléchargement sur CGTrader. L'espace est une catégorie à part entière de la low poly, modèles de jeu prêts de science-fiction %{spaceships_link}. Il y a aussi %{asteroids_link}, les planètes (y compris la Lune et Mars, pour simuler la colonisation) et de l'espace réaliste de %{shuttles_link} pour plus scientifiquement incliné. Les modèles peuvent certainement être utilisés dans les jeux de simulateur spatial VR, les applications AR et des animations pour illustrer le monde extérieur planète de %{earth_link}. Les filtres sont ici pour vous aider à trouver truquées, animés, actifs ou poly-bas modèles dans des formats spécifiques, y compris FBX, OBJ, MAX, 3DS, C4D.","sports":"%{count}
16518 sports modèles 3D d'équipement ensemble nid disponible qui est utilisé pour les activités de loisirs, de divertissement, exercice, loisir, passe-temps agréable, amusant ainsi que des jeux, jouets pour enfants et une gamme complète d'instruments de musique. Pour acheter ou télécharger un modèle 3D gratuitement dans un format de fichier nécessaire, y compris FBX, OBJ, MAX, 3DS, C4D, parcourir les catégories ci-dessus. Vous pouvez utiliser des modèles pour l'animation, des jeux, des projets VR / AR - beaucoup d'entre eux sont truqués, low-poly ou déjà animé.","test":{"airplane":"Les amateurs de l'aviation, écoutez, il n'a jamais été aussi facile d'obtenir le modèle d'avion imprimé 3D parfait pour votre jeu de société ou d'une collection de modèle. Faites une recherche parmi %{model_count} modèles d'avion imprimer 3D et trouver un modèle que vous juste besoin d'avoir sur cette étagère. Découvrez réel des modèles d'avion ou ceux confectionnés. Recherchez des projets les plus ou quelque chose qui compte retour de l'époque des frères Wright. Il est aussi un cadeau parfait pour tout enfant qui rêve d'être pilote quand il grandit. Acheter et télécharger un modèle d'impression 3D, imprimez-le par vous-même ou soumettre le modèle à l'un de nos fournisseurs de services d'impression 3D pour qu'il soit imprimé et expédié en peu de temps!\n","anatomy":"%{model_count} modèles 3D disponibles Anatomie en téléchargement sur notre marché. Explorez l'anatomie humaine avec haut - os poly, les muscles, les modèles d'organes. Parfait pour tout projet éducatif ou scientifique. Utiliser des modèles 3D imprimables pour une expérience de meilleure éducation. Créer de superbes animations et des jeux vidéo avec notre\n vaste bibliothèque de modèles truqués. Utilisez notre système de filtrage avancé pour trouver facilement low poly, animé, PBR,\n modèles truquées ou tout ce qui convient le mieux à vos besoins. Faites votre choix parmi un grand nombre de formats de fichiers, y compris la\n la plupart des plus populaires comme FBX, OBJ, MAX, 3DS, C4D.\n","castle":"Votre propre château imprimé 3D étonnant est un clic! Rechercher divers modèles 3D château prêt pour l'impression 3D. Créer une forteresse fantastique unique pour votre session D \u0026 D ou tout autre jeu de plateau de jeu de rôle médiéval. Ces forteresses médiévales sont un cadeau incroyable pour tous les amateurs de jeu de société ou un excellent ajout à votre collection. Trouver le modèle 3D parfait pour la peinture des amateurs ou un d'un jouet genre pour les enfants. Achetez et téléchargez votre choix de conception du château 3D, imprimer avec votre propre imprimante, ou soumettre le modèle à l'un de nos fournisseurs de services d'impression 3D pour qu'il soit imprimé et livré à vous.\n","dice":"La chance ne va pas manquer avec des dés imprimé 3D! Si vous voulez dés de jeu authentique pour votre jeu de plateau nuit, ne cherchez pas plus. Ici, vous pouvez choisir entre %{model_count} gratuit dés 3D modèles prêts pour l'impression 3D. Lorsque le jeu est terminé, utiliser ces beaux modèles comme accessoire. Télécharger des modèles 3D gratuits dés imprimables, formats de fichiers disponibles, y compris STL, OBJ, 3DM, 3DS, MAX. Nos modèles 3D sont prêts à être utilisés avec FDM, SLA, SLS et d'autres types d'imprimantes 3D. Faites votre jeu un peu plus intéressant et obtenir vos dés imprimés 3D!\n","drone":"Imprimer 3D et construire votre propre drone ou trouver des pièces de remplacement. drones imprimé 3D sont faciles à assembler et à réparer après un atterrissage d'accident. Découvrez un modèle avec la position de montage de la caméra parfaite ou demande de modification minimale. Parfait pour les activités de loisirs amusantes, photographie aérienne, la cartographie ou la vidéographie. Trouver et acheter un modèle de drone 3D de conception unique qui correspond à tous vos besoins. Imprimez-le par vous-même ou soumettre le modèle à l'un de nos fournisseurs de services d'impression 3D pour qu'il soit imprimé et expédié en peu de temps! Obtenez votre propre drone imprimé 3D et parcourir le ciel à large bleu!\n","pokemon":"Pikachu, je vous choisissez! Faites votre choix parmi des tas de monstres de poche prêt pour l'impression 3D. Grand pour élargir votre collection pokemon imprimé 3D. Rechercher et tomber par hasard sur les meilleurs, les dessins pokemon plus détaillées pour votre prochain jeu de table avec des amis. Achetez et téléchargez votre pokemon 3D, imprimer avec votre propre imprimante 3D, ou soumettre le modèle à l'un de nos fournisseurs de services d'impression 3D pour qu'il soit imprimé et livré à vous. Après tout, c'est l'une des choses les plus cool à imprimer 3D!\n","ring":"Bijoux imprimé 3D est le nouveau noir dans l'industrie, comme les anneaux imprimés 3D! Rechercher une énorme quantité de %{model_count} Modèles anneau imprimable 3D. Parcourez des conceptions uniques et trouver quelque chose faite pour vous. Vous ne trouvez pas quoi que ce soit pour vous-même au magasin? Ou peut-être que vous voulez un accessoire exactement comme celui de votre personnage de film préféré est? Faites votre choix parmi un grand nombre de formats de fichiers, y compris STL, OBJ, 3DM, 3DS, MAX. modèles 3D sont prêts à être utilisés avec FDM, SLA, SLS et d'autres types d'imprimantes 3D, donc naviguer à travers notre sélection et essayer sur votre nouvel anneau favori.\n","shoes":"Les grandes marques sont à bord avec des chaussures imprimé 3D et maintenant vous pouvez partager l'expérience aussi bien. Parcourir et trouver gratuitement des designs de chaussures imprimables - de baskets à talons à la mode, il y a beaucoup de modèles prêts à imprimer pour vous attendre de les essayer. Faire le parfait résultat en choisissant des matériaux, en ajustant la douceur et la taille. Faites votre choix parmi 146 modèles gratuits de chaussures 3D et de les télécharger dans de
16518s formats de fichiers disponibles, y compris STL, OBJ, 3DM, 3DS, MAX. Les dessins sont prêts à être utilisés avec FDM, SLA, SLS et d'autres types d'imprimantes 3D. Enfilez vos chaussures imprimées en 3D aujourd'hui!\n","textures":"Faites une recherche parmi une grande quantité de %{model_count} CG textures disponibles pour téléchargement, y compris les matériaux magnifiquement réalisés. Parcourez la catégorie et trouver le tissu sans couture, bois, métal, plastique, textures de briques pour aider à terminer votre projet plus rapidement. Utilisez notre recherche avancée pour trouver des textures truquées et d'animation pour jeu ou la création vidéo. Nos matériaux sont disponibles en téléchargement dans différents formats, y compris TGA, SBSAR, JPG, PNG, TIFF et d'autres, alors ne perdez pas de temps et trouver prêt à utiliser des textures CG pour presque tous les imaginables du projet.\n"},"various":"%{count} différents modèles 3D qui ne trouvent pas facilement leur place dans d'autres catégories sont disponibles pour téléchargement. %{rocks_link}, %{clouds_link}, %{logos_link}, %{cigarette_link} et d'autres modèles non classés 3D que vous pourriez avoir besoin pour compléter votre jeu, animation ou projet VR / AR sont ici. Utilisez les filtres pour trouver truquées, animé, low-poly ou libres modèles 3D, ou trier par formats disponibles tels que FBX, OBJ, MAX, 3DS, C4D.","vehicle":"%{count} véhicules modèles 3D disponibles en téléchargement comprennent les camions, %{ambulances_link}, bus, %{bikes_link} et moto - cette catégorie est pour les gens qui veulent que leurs rues de la ville à être remplie de véhicules qu'elles soient réalistes ou de science-fiction. Ceux qui font des jeux de simulation ou VR / applications AR, créations dans la production vidéo ou même la conception des affiches seront plus susceptibles de trouver des formats de fichiers les plus populaires tels que FBX, OBJ, MAX, 3DS, utilisable C4D. D'autres véhicules de transport terrestre comme le train ou %{tractor_link} modèles 3D peuvent également être trouvés dans cette vaste collection. Utilisez les filtres pour trouver truqué, animé, faible ou poly libre modèles 3D plus rapide.","watercraft":"%{count} motomarines modèles 3D disponibles pour téléchargement incluent %{boats_link}, %{yachts_link}, %{ships_link} et d'autres véhicules allant de l'eau de toutes sortes. Les poly-bas modèles 3D truquées se comportent bien dans les jeux vidéo, les projets VR / AR ainsi que des animations, tandis que les modèles CG sont ici pour vos scènes et d'autres applications où la fidélité visuelle est plus important que polycount. Les modèles sont disponibles dans tous les formats de fichiers, y compris, mais sans s'y limiter FBX, OBJ, MAX, 3DS, C4D."},"tag":{"meta":{"3d_merged_premium":"Téléchargez %{rounded_count} modèles 3D de %{tag_low}, gratuits et premium. En FBX, OBJ, BLEND, GLB et plus, pour jeux, cinéma, AR/VR et impression 3D.","3d_merged_premium_print":"Téléchargez %{rounded_count} fichiers STL %{tag_low} pour impression 3D, gratuits et premium, testés pour imprimantes FDM et résine.","3d_models":"Téléchargez %{rounded_count} modèles 3D de %{tag_low}, gratuits et premium. En FBX, OBJ, BLEND, GLB et plus, pour jeux, cinéma, AR/VR et impression 3D.","3d_print_models":"Téléchargez %{rounded_count} fichiers STL %{tag_low} pour impression 3D, gratuits et premium, testés pour imprimantes FDM et résine.","animated_3d_models":"%{count} %{tag} animation des modèles 3D disponibles en téléchargement dans un format de fichier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Télécharger %{count} %{tag} 3D gratuits modèles, disponibles en MAX, OBJ, FBX, 3DS, formats de fichiers C4D, prêts pour VR / AR, animation, jeux et autres projets 3D.%{page}","free_3d_print_models":"Télécharger %{count} %{tag} Modèles d'impression 3D prêts à FDM, SLA, SLS et autres imprimantes 3D, STL formats disponibles, OBJ, 3DM et plus.%{page}","lowpoly_3d_models":"Télécharger %{count} VR / AR / low-poly %{tag} modèles 3D prêts pour la réalité virtuelle, jeux et autres applications à temps réel, disponible en FBX, OBJ, MAX, 3DS, les formats de fichiers C4D.%{page}","rigged_3d_models":"%{count} %{tag} truqué modèles 3D disponibles en téléchargement dans un format de fic
16518hier, y compris FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"title":{"download":"| télécharger","files":"fichiers 3D","formats":"Modèles 3D %{format_upper}","free":"Modèles 3D Gratuits","free_printing":"Fichiers STL Gratuits","free_tag":"Gratuit %{selected_tag} ââmodèles 3D","general":"Modèles 3D","high_poly":"%{selected_filter} Modèles 3D","landing":{"animated_3d_models":"Modèles 3D Animés","lowpoly_3d_models":"Modèles 3D Low Poly","pbr_3d_models":"Modèles 3D PBR","rigged_3d_models":"Modèles 3D Riggés"},"low_poly":"%{selected_filter} 3D modèles","newest_cg":"Nouveaux et derniers modèles 3D","newest_print":"Nouveaux et derniers modèles d'impression 3D","page_prefix":"Page %{page_number} de ","pbr":"PBR 3D modèles","printing":"Fichiers 3D \u0026 STL pour Imprimante 3D","sales_cg":"Meilleures ventes de modèles 3D","sales_print":"Meilleures ventes de modèles d'impression 3D","software_page":"Modèles 3D pour %{software}","tag_heading":{"cg":"Gratuit %{tag} Modèles d'impression 3D","filter":"%{selected_filter} %{tag} Modèles 3D","general":"%{tag_cap} 3D â Modèles 3D","merged_premium_print_tag":"Fichiers STL %{tag_cap}","merged_premium_tag":"%{tag_cap} 3D â Modèles 3D","printable":"Fichiers STL %{tag_cap}"},"trending_cg":"Modèles 3D tendance","trending_print":"Modèles d'impression 3D tendance"}},"cart":{"request_invoice_failed":"Oups. Une erreur sâest produite.","request_invoice_successful":"La demande de facture a été envoyée avec succès.","shareable_cart_created":"Le panier a été partagé avec succès.","shareable_cart_failed":"Oups. Une erreur sâest produite.","subscription_covered_items_removed":"Retiré de votre panier : %{titles}. Déjà inclus dans votre abonnement.","subscription_covered_order_refused":"Votre abonnement inclut désormais %{titles}, nous ne vous avons donc rien facturé. Téléchargez-le depuis votre abonnement."},"categories":{"cg":{"header_title_html":"Modèles 3D","text":"Trouvez le contenu 3D exact qui correspond à vos besoins, y compris AR/VR, jeux, publicité, divertissement et autres"},"head-title":{"cg":"Modèles 3D â Téléchargement Gratuit \u0026 Premium","cg-models":{"sort_by":{"newewst":"Les plus récents Modèles 3D","top-selling":"Modèles 3D les plus vendus","trending":"Modèles 3D tendance"}},"print":"Fichiers 3D pour Imprimante 3D â Fichiers STL","print-models":{"sort_by":{"newewst":"Les plus récents Fichiers d'impression 3D","top-selling":"Fichiers d'impression 3D les plus vendus","trending":"Fichiers d'impression 3D tendance"}},"product-type":{"plural":{"capital":{"cg":"Modèles 3D","cg-merge-premium":"Modèles 3D â Téléchargements gratuits et premium","print":"Fichiers et Modèles d'Impression 3D","print-merge-premium":"%{tag} Fichiers d'impression 3D - modèles STL gratuits et premium"},"lower":{"cg":"modèles 3D","print":"fichiers et modèles d'impression 3D"}},"singular":{"capital":{"cg":"Modèle 3D","print":"Modèle d'impression 3D"},"lower":{"cg":"modèle 3D","print":"modèle d'impression 3D,"}}}},"index":{"browse_all":"Parcourir tous les modèles","info-section__description_1_html":"Achetez ou téléchargez gratuitement des modèles 3D professionnels prêts à être utilisés dans des projets CG, la production de films et vidéos, lâanimation, les visualisations, les jeux, la VR/AR et autres. Les ressources sont disponibles dans de nombreux \u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eformats acceptés par lâindustrie\u003c/a\u003e, y compris MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB et autres. Si vous recherchez des assets high poly ou temps réel, nous avons une bibliothèque dâart numérique leader pour tous vos besoins.","info-section__description_1_printable_html":"Fichiers, impressions et modèles 3D professionnels prêts à être imprimés à domicile avec des imprimantes 3D FDM de bureau ou SLS industrielles, disponibles dans de nombreux formats industriels, y compris OBJ, \u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003e, WRL. Si vous êtes un passionné d'impression 3D, un maker, un éducateur ou une entreprise réalisant des prototypes par impression 3D, nos décorations pour la maison, accessoires de gadgets tendance, pièces de mode accrocheuses, bijoux uniques, pièces mécaniques et une variété de miniatures vous inspireront certainement.","info-section__heading_1_html":"Explorer les \u003cstrong\u003ecatégories\u003c/strong\u003e de modèles 3D","info-section__heading_1_printable_html":"Explorer \u003cstrong\u003e les catégories \u003c/strong\u003ede modèle d'impression 3D ","info-section__heading_2_html":"\u003cstrong\u003eMarché\u003c/strong\u003e des modèles 3D","info-section__heading_2_printable_html":"Quoi dâ\u003cstrong\u003eautre\u003c/strong\u003e ?"},"marketplace":{"3d-printing":{"link_text":"Parcourir les modèles dâimpression 3D","text":"Trouvez des modèles dâimpression 3D pour votre imprimante 3D.","title":"Modèles dâimpression 3D"},"blender_text":"Découvrez des milliers de modèles 3D Blender disponibles au format blend.","browse":"Parcourir","cinema-4d_text":"Découvrez des milliers de modèles Cinema 4D de haute qualité disponibles au format c4d.","discounted":{"link_text":"Parcourir Modèles 3D à prix réduits","text":"Acheter des modèles 3D professionnels à prix réduit.","title":"Modèles 3D à prix réduits"},"low-poly":{"link_text":"Parcourir les modèles 3D low poly","text":"Modèles 3D low poly prêts pour les jeux vidéo, applications VR et AR en temps réel.","title":"Modèles 3D low poly"}
16518,"pbr":{"link_text":"Parcourir les modèles 3D PBR","text":"Modèles 3D basés sur le rendu physique.","title":"Modèle 3D PBR"},"scripts_apps":{"link_text":"Parcourir tout","text":"Scripts et plugins 3D pour rendre votre pipeline de modélisation 3D plus efficace.","title":"Scripts \u0026 Applications"},"sketchup_text":"Parcourez la vaste sélection de modèles 3D Sketchup pour vos conceptions architecturales, intérieures et de jeux vidéo.","textures":{"link_text":"Parcourir les textures","text":"Textures prêtes à lâemploi pour gagner du temps dans la préparation de vos modèles 3D.","title":"Textures"},"zbrush_text":"Trouvez des assets 3D au format ZTL pour vos projets de sculpture numérique, de modélisation 3D, de texturation et de peinture."},"meta-description":{"cg":"Téléchargez ou achetez %{rounded_count} modèles 3D professionnels. Modèles gratuits et premium pour jeux, cinéma, VFX, AR/VR et impression 3D. FBX, OBJ, BLEND, GLB.","print":"Téléchargez %{rounded_count} fichiers 3D pour impression 3D. Fichiers STL gratuits et premium pour imprimante 3D: figurines, miniatures, déco et plus."},"more":{"designers":{"link_text":"Parcourir la liste des designers 3D","text":"Parcourez des milliers de portfolios de designers 3D et trouvez exactement ce dont vous avez besoin pour votre application.","title":"Trouvez les meilleurs designers 3D"},"projects":{"link_text":"En savoir plus sur les projets 3D","text":"Engagez des artistes 3D freelance de qualité et résolvez tous vos défis de modélisation personnalisée.","title":"Projets 3D CGTrader"},"visualization":{"link_text":"En savoir plus","text":"Transformez vos produits en modèles 3D photoréalistes pour le e-commerce et dâautres applications professionnelles.","title":"Visualisation 3D pour e-Commerce"}},"navbar":{"aircraft":"Avion","animal":"Animaux","animals":"Animaux","architectural":"Architectural","art":"Art","car":"Voiture","character":"Personnage","exterior":"Extérieur","fashion":"Mode","food":"Nourriture","furniture":"Meubles","gadgets":"Gadgets","games-toys":"Jeux et jouets","hobby-diy":"Hobby \u0026 Bricolage","house":"Maison","household":"Ménage","industrial":"Industriel","interior":"Intérieur","jewelry":"Bijoux","military":"Militaire","miniatures":"Miniatures","plant":"Plante","science":"Science","space":"Espace","vehicle":"Véhicule","watercraft":"Nautisme"},"print_models":{"hero_title_html":"Fichiers 3D \u0026 STL pour Imprimante 3D","subtitle":"Trouvez le contenu dâimpression 3D exact qui correspond à vos besoins","title_html":"Acheter des \u003cstrong\u003emodèles 3D professionnels pour lâimpression\u003c/strong\u003e"},"profile":{"collection":"packs 3D","free":"Modèles 3D","high_poly":"High Poly Modèles 3D","optimized":"Poly-Bas / Pbr Modèles 3D","printable":"Modèles D'Impression 3D"},"seo":{"cg":{"aircraft":"Cette catégorie couvre les avions 3D. Les avions CG conviennent aux simulations,\nvisualisations, publicités et vidéos. Les corps et pièces de drones raviront\nles amateurs de petits véhicules volants. Et les modèles riggés sont prêts à \nêtre importés dans les moteurs de jeu.\n","animals":"La collection de faune 3D â chats, chevaux, ours, rhinocéros, aigles, lions\net plus â se trouve ici. Les animaux CG répondent aux besoins des publicités ou\ndes scènes statiques. Nous avons également des modèles dâanimaux riggés pour les jeux.\n","architectural":"Escaliers, cheminées, modèles 3D ainsi que des décorations comme cadres,\noreillers ou lampes se trouvent dans la vaste bibliothèque de modèles de détails\narchitecturaux. Intérieurs et extérieurs peuvent être utilisés pour construire des\ncuisines, chambres, salles de château ou donjons numériques, que vous soyez\narchitecte, ingénieur ou développeur indépendant.\n","car":"La catégorie Voitures contient des modèles 3D dâautomobiles, dont les versions\nlow poly séduiront les concepteurs de jeux, dâautres les cinéastes ou publicitaires.\nDes voitures classiques aux voitures de course et concept cars, il existe une\ngrande variété de modèles 3D.\n","character":"Dans cette catégorie, vous trouverez des modèles 3D dâhumains, de personnes,\nde science-fiction, de vêtements et autres. Du cÅur et de la main aux modèles\nréalistes détaillés masculins ou féminins. De nombreux modèles sont riggés et\npeuvent être facilement ajoutés à votre jeu ou animation.\n","electronics":"Electronics est une catégorie pour les architectes, décorateurs d'intérieur, les concepteurs de niveau, les responsables de la scène et d'autres créateurs. modèles 3D de { \"slug\": \"smartphone\", \"title\": \"smartphones\"}, { \"slug\": \"ordinateur portable\", \"title\": \"ordinateurs portables\"}, { \"slug\": \"appareil photo\", \"title\" : \" caméras \"}, { \"slug\": \"tv\", \"title\": \" téléviseurs \"} et plus vous aidera à saisir avec précision l'obsession de la vie moderne avec des appareils et de la technologie.\n","engineering-parts":"Windows, les pipelines, les mécanismes de portes coulissantes et d'autres b
16518its qui sont nécessaires pour des projets de CAO et même des plans de bricolage entrent dans cette catégorie. C'est là que vous pouvez trouver des modèles 3D des fabricants mondiaux tels que ANVER, Dynatec et CFi.\n","exterior":"Parcourez des extérieurs architecturaux allant des façades, bâtiments urbains\naux objets paysagers, maisons résidentielles, constructions industrielles et\nmodèles de ville 3D à grande échelle. Certains assets sont low poly et peuvent\nvous aider à finaliser votre jeu ou application VR/AR.\n","food":"La nourriture aide à créer des scènes réalistes de vie domestique. Fruits,\nlégumes, boissons et repas en 3D sont tous ici. Publicités pour restaurants,\napplications AR pour une alimentation plus saine. Que vous cherchiez un modèle\nde pizza 3D ou de gâteau de mariage, ils sont ici.\n","furniture":"Tables, chaises, canapés, lits 3D dans une variété de textures (bois, métal,\netc.) et de styles (rétro, moderne, etc.) sont disponibles. Cette catégorie\nsâadresse à tous ceux impliqués dans lâarchitecture, le design dâintérieur et la publicité.\n","furniture-set":"Si vous avez besoin se ressembler chaise antique et un canapé à la recherche, ou un ensemble complet d'ustensiles de cuisine, c'est un endroit pour être aussi cette catégorie ensembles de modèles de Collectionnez meubles 3D de la cuisine et le salon au bureau et salle à manger ensembles de meubles de salle. Cela aide les chambres spécialisées design d'intérieur ou de niveau construction avec des éléments correspondants.\n","household":"Les modèles 3D dâobjets ménagers sont utilisés pour donner des détails aux pièces.\nVous pouvez placer un service de table 3D sur la table ou utiliser des salières et\npoivrières pour compléter la cuisine, peut-être mettre des lumières et des fleurs\nprès du lit pour créer une ambiance luxueuse.\n","industrial":"Matériaux de construction, outils dâingénierie, machines et conteneurs\nfournissant à la fois des détails environnementaux et des éléments interactifs riggés.\nParfait pour les développeurs de jeux de simulation ou ceux qui construisent des\nniveaux de chantier.\n","interior":"Cette catégorie contient des éléments 3D réalistes et des détails dâarchitecture,\nde construction et de design dâintérieur. Vous pouvez utiliser ces modèles 3D\npour lâanimation ou les jeux â certains sont riggés et low poly.\n","military":"Dans cette catégorie, vous pouvez acheter des modèles 3D dâarmes, dâarmures,\ndâépées et dâartillerie â modernes et historiques â utilisés par les forces\nmilitaires ou pour lâautodéfense. Vous pouvez utiliser les modèles pour des\njeux â certains sont optimisés en polygones et prêts pour les moteurs de jeu.\n","plant":"Cette catégorie contient des modèles 3D dâorganismes de flore tels que fleurs,\narbres, herbes, plantes grimpantes, verdure, herbes, vivaces, semis, pousses,\narbustes, boutures, germes, vignes, mauvaises herbes. Pour acheter ou télécharger\ngratuitement un modèle 3D, parcourez les catégories ci-dessous.\n","scanned":"Modélisateurs créer ces modèles en utilisant les technologies 3D comme RealSense. Les souches d'arbres, statues, les mâles et les femelles même sont très populaires ici. Le produit est prêt à être utilisé dans des scènes et des animations, offrant des niveaux inégalés de réalisme.\n","science":"Cette catégorie contient des modèles 3D liés à la médecine, la biologie, la physique, la chimie et de la technologie, tels que les équipements de laboratoire, des organismes microscopiques et dans le monde subatomique. Ne cherchez pas plus loin, { \"slug\": \"cellule\"}, { \"slug\": \"crâne \"} et { \"slug\": \"squelette\"} modèles 3D peuvent être trouvés ici.\n","scripts-plugins":"Les scripts et les plug-ins que vous fournissent des raccourcis logiciels. La modélisation, le rendu, texturation - tous ces éléments peuvent être facilitée en utilisant des plug-ins qui viennent pour toutes sortes de logiciels comme Maya et V-Ray.\n","space":"Lâespace est une catégorie remplie de modèles low poly et prêts pour les jeux\nde vaisseaux spatiaux de science-fiction, astéroïdes, planètes (y compris la Terre\net des navettes spatiales réalistes pour les plus scientifiques). Les modèles 3D\ndâespace sont utiles pour les jeux de simulation spatiale VR.\n","sport-hobby":"Cette catégorie encompases tout ce qui est lié à { \"slug\": \" champ \"} événements, sports et loisirs en général. De { \"slug\": \"football \"} et des pistes de ski à { \"slug\": \"guitare\"} et { \"slug\": \"piano\"}, ce sont des modèles 3D utiles pour des publicités, des scènes et des animations. versions low-poly sont là pour les jeux vidéo de sport.\n","textures":"Parcourez une bibliothèque de matériaux 3D magnifiquement réalisés et trouvez\nles textures prÃ
16518ªtes à lâemploi les plus adaptées pour préparer des modèles prêts\npour les jeux ou photoréalistes, améliorer votre bibliothèque de ressources et\nperfectionner vos travaux 3D.\n","various":"Ce sont les modèles 3D qui ne correspondaient pas facilement dans d'autres catégories, nous avons donc créé un qui les accepter tous. { \"title\": \"Rocks\", \"slug\": \"rochers\"}, { \"slug\": \"nuages\"}, { \"title\": \"logos\", \"slug\": \"logo\"}, { \"title\" : \" parapluies \", \"slug\": \"parapluie\"} et d'autres non classés modèles 3D sont ici.\n","vehicle":"Camions, ambulances, bus, trains, tracteurs, vélos et motos â cette catégorie\nsâadresse aux personnes qui veulent que leurs rues soient remplies de véhicules\nréalistes et de science-fiction, ainsi quâà ceux qui créent des jeux de simulation\nou des affiches.\n","watercraft":"Les bateaux couvrent les embarcations, yachts, navires et autres véhicules\nmaritimes. Les modèles 3D riggés conviennent bien aux jeux vidéo, animations, tandis\nque les modèles CG sont destinés aux scènes ou autres applications où la fidélité\nvisuelle est plus importante que le nombre de polygones.\n"},"forwarded":{"cg":{"aircraft":"Cette catégorie couvre les aéronefs 3D. CG { \"slug\": \"avions\", \"title\": \"avions\"} s'intégrera dans des simulations, des visualisations, des publicités et des vidéos. { \"slug\": \"drone\", \"title\": \"Drone\"} corps et parties vont ravir les amateurs de petits engins volants. Et les { \"slug\": \"avions\", \"title\": \"modèles squelettés\", \"active_filter\": \"rigged\"} sont prêts à être importés dans les moteurs de jeu.\n","animals":"La collection de la faune 3D - { \"slug\": \"cat\", \"title\": \"chats\"}, { \"slug\": \"horse\", \"title\": \"chevaux\"}, { \"slug\": \"ours\" , \"title\": \"ours\"}, { \"slug\": \"rhinocéros\", \"title\": \"rhinocéros\"}, { \"slug\": \"aigles\", \"title\": \"aigles\"}, { \"slug\": \"lions\", \"title\": \"lions\"} et plus - peuvent être trouvés ici. Les animaux CG en 3D satisferont les besoins de la publicité ou des scènes statiques. Nous avons aussi des modèles { \"slug\": \"animaux\", \"title\": \"d'animaux squelettés\", \"active_filter\": \"rigged\"} pour les jeux.\n","architectural":"Des { \"slug\": \"escaliers\", \"title\": \" escaliers\"}, { \"slug\": \"cheminées\", \"title\": \"des cheminées\"}, en modèles 3D, ainsi que des décorations comme { \"slug\": \"cadre\", \"title\": \"des cadres\"}, { \"slug\": \"oreiller\", \"title\": \"des oreillers\"} ou { \"slug\": \"lampe\", \"title\": \"des lampes\"} se trouvent dans le détail architectural étendu. La catégorie voitures contient des modèles d'automobile 3D, { \"slug\": \"voiture\", \"title\": \"low poly\", \"active_filter\" : \"low_poly\"} dans la bibliothèque de modèles. Intérieurs et extérieurs peuvent être utilisés pour construire des cuisines numériques et des chambres ainsi que des chambres de château et des donjons que vous soyez un architecte, un ingénieur ou un développeur de jeux indépendant.\n","car":"La catégorie des voitures contient des modèles 3D d'automobiles,dont les versions \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e low poly \u003c/a\u003e seront attractives pour les concepteurs de jeux, d'autres - pour les cinéastes ou les annonceurs. Des voitures classiques aux voitures de course et de piste à celles de conception, il y a une grande variété de modèles d'automobiles 3D.\n","character":"Dans cette catégorie, vous trouverez des modèles 3D de { \"slug\": \"humain\", \"title\": \"humain\"}, gens, de science-fiction, de vêtements et d'autres. Du { \"slug\": \"coeur\", \"title\": \"coeur\"} et { \"slug\": \"mains\", \"title\": \"des mains\"} à de réalistes et détaillés modèles {\"slug\": \"mâle\", \"title\": \"de mâle\"} ou { \"slug\": \"femelle\", \"title\": \"femelle\"} . Un certain nombre de modèles sont suqelettés et pourrait être facilement ajouté à votre jeu ou animation.\n","electronics":"Electroniques est une catégorie pour les architectes, décorateurs d'intérieur, concepteurs de niveau, créateur de scènes et d'autres concepteurss. Les modèles 3D de { \"slug\": \"smartphone\", \"title\": \"smartphones\"}
16518, { \"slug\": \"lordinateurs-portables\", \"title\": \"ordinateurs portables\"}, { \"slug\": \"appareils-photos\", \"title\" : \" appareils photos\"}, { \"slug\": \"téléviseurs, \"title\": \" téléviseurs\"} et plus encore vous aideront à saisir avec précision l'obsession de la vie moderne pour des appareils et de la technologie.\n","engineering-parts":"Les fenêtres, les tuyaux, les mécanismes de portes coulissantes et d'autres éléments qui sont nécessaires pour des projets de CAO et même des plans de bricolage entrent dans cette catégorie. C'est là que vous pouvez trouver des modèles 3D des fabricants mondiaux tels que ANVER, Dynatec et CFi.\n","exterior":"Explorez les extérieurs architecturaux de façades, bâtiments urbains jusqu'à à des objets de paysage, des maisons d'habitation, des constructions industrielles, et des modèles 3D de { \"slug\": \"ville\", \"title\": \"ville\"} en taille réelle. Certains des actifs sont en low poly et pourrait vous aider à compléter votre jeu ou une application VR / AR.\n","food":"La nourriture aide à créer des scènes réalistes de la vie domestique. Les fruits 3D, les légumes, les boissons et les repas sont tous présents ici. Les publicités pour les restaurants, les applications AR pour manger plus sain. Que vous cherchiez un modèle 3D de{ \"slug\": \"pizza\", \"title\": \"pizza\"} ou un { \"slug\": \"gâteau\", \"title\": \"gâteau\"} de mariage , ils sont là .\n","furniture":"Les tables, chaises, canapés, lits 3D dans une variété de textures (bois, métal, etc.) et de styles ({ \"slug\": \"retro\", \"title\": \"retro\"}, { \"slug\": \"moderne\", \"title\": \"moderne\"}, etc.) sont à portée de main. Cette catégorie est destinée à toute personne impliquée dans l'architecture et le design intérieur, ainsi que les annonceurs.\n","furniture-set":"Si vous avez besoin de chaises anciennes et de canapés qui se ressemblent, ou un ensemble complet d'ustensiles de cuisine, c'est l'endroit où être car cette catégorie rassemble des modèles 3D de set de meubles, de la cuisine et du salon au bureau et à la salle à manger. Cela aide les spécialistes du design d'intérieur ou de niveau a construire des chambres avec des éléments correspondants.\n","household":"Les modèles 3D d'articles ménagers sont utilisés pour donner des détails aux chambres. Vous pouvez mettre un ensemble de dîner 3D sur la table, ou avoir des poivriers et des salières pour complèter l'intérieur de la cuisine, peut-être mettre un peu de{ \"slug\": \"lumière\", \"title\": \"lumière \"} et des { \"slug\": \"fleurs\", \"title\": \"fleurs\" } près du lit pour créer une sensation luxueuse.\n","industrial":"Les matériaux de construction, outils, machines et { \"slug\": \"conteneurs\", \"title\": \"conteneurs\"} d' { \"slug\": \"ingénierie\", \"title\": \"ingénierie\"} fournissent les détails environnementaux et interactifs, des éléments squelettés. C'est parfait pour les développeurs de jeux de simulation ou les personnes qui construisent { \"slug\": \"bâtiments\", \"title\": \"bâtiments\"} au niveau du sol.\n","interior":"Cette catégorie contient des éléments 3D réalistes et des détails d'architecture, de construction et de décoration intérieure de l'ingénierie. Vous pouvez utiliser ces modèles 3D pour l'animation ou des jeux - certains d'entre eux sont squelettés et low poly.\n","military":"Dans cette catégorie, vous pouvez acheter des modèles 3D d'armes, { \"title\": \"épées\", \"slug\": \"épées\"} et de l'artillerie à la fois moderne et historique utilisé par les forces militaires et pour la légitime défense. Vous pouvez utiliser des modèles pour les jeux - certains d'entre eux sont en polygones optimisés et prêts pour les moteurs de jeu.\n","plant":"Cette catégorie contient des modèles 3D d'organismes de la flore tels que des fleurs, { \"slug\": \"arbres\", \"title\": \"arbres\"}, gazon, lianes, verdure, herbes, plantes vivaces, plants, pousses, arbustes, germes, vignes, mauvaises herbes. Pour acheter ou télécharger un modèle 3D gratuit, explorez les catégories ci-dessous.\n","scanned":"Les modélisateurs ont créé ces modèles en utilisant les technologies 3D comme RealSense. Les souches d'arbres, les statues, les mâles et les femelles même sont très populaires ici. Le produit est prêt à être utilisé dans de
16518s scènes et des animations, offrant des niveaux inégalés de réalisme.\n","science":"Cette catégorie contient des modèles 3D liés à la médecine, la biologie, la physique, la chimie et à la technologie, tels que les équipements de laboratoire, les organismes microscopiques et le monde subatomique. Ne cherchez pas plus loin, les modèles 3D de { \"slug\": \"cellule\", \"title\": \"cellule\"}, { \"slug\": \"crâne\", \"title\": \"crâne\"} et { \"slug\": \"squelette\", \"title\": \"squelette\"} peuvent être trouvés ici.\n","scripts-plugins":"Les scripts et les plug-ins vous fournissent des raccourcis logiciels. La modélisation, le rendu, la texturation - tous cela peut être facilité en utilisant des plug-ins disponibles pour toutes sortes de logiciels comme Maya et V-Ray.\n","space":"L'espace est une catégorie remplie de modèles prêts-à -jouer low poly de science-fiction, des { \"slug\": \"vaisseaux-spatiaux\", \"title\": \"vaisseaux spatiaux\"}, { \"slug\": \"astéroïdes\", \"title\": \"astéroïdes\"}, les planètes (y compris la {\"slug\": \"terre\", \"title\": \"terre\"} et les {\"slug\": \"navettes\", \"title\": \"navettes\"} de l'espace réalistes, pour les plus portés scientifiquement. Les modèles 3D spatiaux sont utiles pour les jeux de simulateur spatial VR.\n","sport-hobby":"Cette catégorie englobe tout ce qui est lié aux événements, sports et loisirs en général de { \"slug\": \"terrain\", \"title\": \"terrain\"}. Du { \"slug\": \"football\", \"title\": \"football\"} et des pistes de ski à la{ \"slug\": \"guitare\", \"title\": \"guitare\"} et au { \"slug\": \"piano\", \"title\": \"piano\"}, ce sont des modèles 3D utiles pour des publicités, des scènes et des animations. les versions low-poly sont là pour les jeux vidéo de sport.\n","textures":"Parcourez une bibliothèque de matériaux 3D magnifiquement réalisés et trouver les textures les mieux adaptées et prêtes-à -l'emploi pour préparer des modèles prêts-à -jouer ou photoréalistes \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e\u003c/a\u003e, ou mettre à jour votre bibliothèque d'actifs, et d'améliorer vos travaux en 3D.\n","various":"Ceux-ci sont les modèles 3D qui ne correspondaient pas facilement à d'autres catégories, nous en avons donc créé une qui les accepterait tous. Les { \"title\": \"rochers\", \"slug\": \"rochers\"}, les { \"slug\": \"nuages\", \"title\": \"nuages\"}, les { \"title\": \"logos\", \"slug\": \"logos\"}, les { \"title\" : \"parapluies\", \"slug\": \"parapluies\"} et d'autres modèles 3D non classés sont ici.\n","vehicle":"Camions, { \"title\": \"ambulances\", \"slug\": \"ambulances\"}, les autobus, trains, tracteurs, { \"title\": \"motos\", \"slug\": \"motos\"} et motos - cette catégorie est pour les personnes qui veulent que les rues de leur ville soient remplies avec des véhicules réalistes et de science-fiction, et pour ceux qui font des jeux de simulation ou compositions d'affiches.\n","watercraft":"Le nautisme couvre les { \"title\": \"bateaux\", \"slug\": \"bateaux\"}, les { \"title\": \"yachts\", \"slug\": \"yachts\"}, les { \"title\": \"navires\", \"slug\": \"navires\"} et d'autres embarcations. Les modèles 3D squelettés se comportent bien dans les jeux vidéo, l'animation tandis que les modèles CG sont là pour vos scènes ou d'autres applications où la fidélité visuelle est plus importante que le polycount.\n"},"printable":{"art":"C'est là que se trouvent les impressions 3D artistiques. Vous recherchez des dessins de sculpture chics recréant des Åuvres classiques et des statues de personnalités historiques, ou des figurines inspirantes, peut-être même des logos 3D imprimables? C'est cette catégorie.\n","fashion":"Les belles et élégantes choses que vous pouvez porter se trouvent dans cette catégorie. Voyez si vous pouvez trouver une utilisation pour des { \"slug\": \"chaussures\", \"title\": \"chaussures\"} fantaisies de l'âge spatial, des lunettes dernier cri et des {\"slug\": \"accessoires\", \"title\": \"accessoires\"} de costumes ici.\n","gadgets":"Toutes les coques d'{ \"title\": \"iPhone\", \"slug\": \"iphone\"}, d'{ \"title\": \"iPad\", \"slug\": \"ipad\"} (et d'autres appareils smart) peuvent être trouvés dans la catégorie gadget. De simples ajouts 3D à des pièces complexes et \"astuces\" pour vos articles, c'est la catégorie pour les créateurs et les amateurs de technologie.\n","games-toys":"Jeux et jouets est la catégorie qui comprend les aliens ou monstre miniatures 3D imprimables, les tout petits { \"title\": \"chars\", \"slug\": \"chars\"}, les géniales pièces d' { \"slug\": \"échec\", \"title\": \"échec\"}, les casques de caractère de film, les accessoires de collection. C'est la catégorie où aller pour toutes les choses un peu geek.\n","hobby-diy":"Si vous êtes n
16518otre prochain grand inventeur et que vous voulez construire votre projet de bricolage ou obtenir des pièces de rechange pour votre { \"slug\": \"drone\", \"title\": \"drone\"}, c'est l'endroit idéal. De plus, elle dispose de nombreux éléménts pour les personnes qui veulent faire leurs propres figurines ou des répliques d'armes à feu en plastique.\n","house":"Toutes sortes de bric-à -brac peuvent être trouvés ici. Des { \"title\": \"Lampes\", \"slug\": \"lampes\"}, des { \"title\": \"bols\", \"slug\": \"bols\"} artistiques, et toutes sortes de { \"title\": \"contenants\", \"slug\": \"contenants\"} que vous ne trouviez pas un bon endroit pour votre téléphone, mettre en ordre des cure-dents, un tas de stylos ou des bijoux sur votre bureau.\n","jewelry":"Bijoux est où vous allez trouver des bracelets, des pendentifs ou des bagues avec des diamants. Alors que les imprimantes 3D ne sont pas, encore, capables de faire des diamants, vous pouvez toujours imprimer un anneau métallique comme base pour votre bague de fiançaille IT geek.","miniatures":"Les { \"title\": \"caractères\", \"slug\": \"caractères\"}, les gens célèbres, les { \"title\": \"monuments\", \"slug\": \"monuments\"}, les animaux, { \"title\": \"Homme\", \"slug\": \"mâle\"}, { \"slug\": \"femelle\", \"title\": \"femelle\"}, les { \"title\": \"monstres\", \"slug\": \"monstres\"}, les { \"title\": \"aliens\",\"slug\": \"aliens\"} imprimables en 3D - tout est là . Que vous imprimiez des véhicules utilitaires à mettre sur votre table ou la création de miniatures pour vos jeux de table, c'est votre catégorie.\n","science":"Qu'est-ce qui peut être considéré comme faisant partie de la science? Eh bien, les modèles de squelette d'{ \"slug\": \"os\", \"title\": \"os\"},des {\"slug\": \"outils\", \"title\": \"outils\"} de médecins et des modèles 3D imprimables relatifs à l'astrophysique, qui peuvent être utilisés dans de nombreux processus d'étude.\n"}},"printable":{"art":"C'est là vont les impressions artistiques 3D. Vous recherchez la conception de sculpture de fantaisie recréer des Åuvres classiques et des statues de personnalités historiques, ou figurines inspirant, peut-être même des logos 3D imprimables? Telle est la catégorie.\n","fashion":"Choses belles et élégantes que vous pouvez porter se trouvent dans cette catégorie. Voyez si vous pouvez trouver toute utilisation pour l'âge de l'espace de fantaisie { \"slug\": \"chaussures\"}, lunettes de nouveauté et cosplay {\"slug\": \"accessoires\"} ici.\n","gadgets":"Tous les { \"title\": \"iPhone\", \"slug\": \"iphone\"}, { \"title\": \"iPad\", \"slug\": \"ipad\"} (et d'autres appareils intelligents) les cas peuvent être trouvés dans la catégorie gadget. De simples add-ons 3D à des pièces complexes et \" hacks \" pour vos articles, c'est la catégorie pour les créateurs et les amateurs de technologie.\n","games-toys":"Jeux et jouets est la catégorie qui couvre imprimables miniatures étrangers ou monstre 3D, petit { \"title\": \" chars \", \"slug\": \"tank\"}, génial { \"slug\": \"échecs\"} pièces, casques de caractère de film, passe-temps accessoires et accessoires. C'est à aller catégorie pour toutes les choses geeks.\n","hobby-diy":"Si vous êtes notre prochain grand inventeur et que vous voulez construire votre projet de bricolage ou d'obtenir des pièces de rechange pour votre { \"slug\": \"bourdon\"}, c'est l'endroit idéal. De plus, il dispose d'une des choses beaucoup pour les gens qui veulent faire leurs propres figurines ou des répliques d'armes à feu en plastique.\n","house":"Toutes sortes de bric-à -brac peuvent être trouvés ici. { \"title\": \"Lampes\", \"slug\": \"lampe\"}, artistique { \"title\": \"bols\", \"slug\": \"bol\"}, et toutes sortes de { \"title\": \"détenteurs\", \"slug\": \"support\"} si vous ne pouvez pas trouver un bon endroit pour votre téléphone, maintenir l'ordre de cure-dents, tas de stylos ou de bijoux sur votre bureau.\n","jewelry":"Bijoux est où vous allez obtenir des bracelets et des pendentifs ou des bagues avec des diamants. Alors que les imprimantes 3D ne sont pas assez bon pour faire des diamants - encore - vous pouvez toujours imprimer un anneau métallique comme base pour votre IT geek anneau de proposition.\n","miniatures":"3D imprimable { \"title\": \"caractères\", \"slug\": \"caractère\"}, les gens célèbres, { \"title\": \"points de repère\", \"slug\": \"repère\"}, animaux, { \"title\": \"Homme\", \"slug\": \"mâle\"}, { \"slug\": \"femme\"}, { \"title\": \"monstres\", \"slug\": \"monstre\"}, { \"title\": \"étrangers\",\"slug\" : \"alien\"}
16518 - il est là . Que vous imprimez des véhicules utilitaires pour mettre sur votre table ou la création de miniatures pour vos jeux de table, il est votre catégorie.\n","science":"Ce qui peut être considéré comme la science? Eh bien, les modèles de squelette { \"slug\": \"os\"}, médecins {\"slug\": \"outils\"} et Astrophysique-modèles liés imprimables 3D qui peuvent être utilisés dans de nombreux processus d'étude.\n"},"titles":{"aircraft":"Modèles 3D dâavions","animals":"Modèles 3D dâanimaux","architectural":"Modèles 3D architecturaux","car":"Modèles 3D de voitures","character":"Modèles 3D de personnages","exterior":"Modèles 3D dâextérieur","food":"Modèles 3D dâaliments","furniture":"Modèles 3D de meubles","household":"Modèles 3D domestiques","industrial":"Modèles 3D industriels","interior":"Modèles 3D dâintérieur","military":"Modèles 3D militaires","plant":"Modèles 3D de plantes","space":"Modèles 3D de lâespace","textures":"Modèles 3D de textures CG","vehicle":"Modèles 3D de véhicules","watercraft":"Modèles 3D de bateaux"}},"title":{"cg":" Modèles 3D","print":" Fichiers d'impression 3D"}}
16518,"competition":{"digital-art-competition":{"categories":{"page_description":"Participez au Concours Art numérique CGTrader en soumettant vos Åuvres à l'illustration de caractère, caractère Design Concept, Illustration Environnement, Environnement Design Concept, objet design, et les catégories d'objets Concept design. Si vous avez plusieurs grandes Åuvres qui conviennent à différentes catégories, ne hésitez pas à les soumettre aux catégories correspondantes. Sélectionnez une catégorie pour voir les prix pour cette catégorie."}}},"conversations":{"action_button_confirmation":"Voulez-vous vraiment rouvrir cette demande ?","reply_posted":"La réponse a été publiée.","with_yourself":"ne peut pas être identique à lâexpéditeur."},"date":{"month_names":[null,"Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"]},"devise":{"failure":{"too_many_requests":"Vous avez déjà demandé un e-mail pour réinitialiser le mot de passe. Veuillez attendre quelques minutes avant de réessayer."}},"disabled_cookies_modal":{"button":"Annuler","text_1":"Vous ne pourrez pas explorer des millions de grands modèles 3D, les ajouter au panier ou acheter.","text_2":"Si vous voulez faire l'expérience CGTrader pleinement, nous encourageons l'activation des cookies sur ce site.","title":"Il semble que vous avez les cookies de votre navigateur désactivée"},"emails":{"error_notification":"Abonnement introuvable.","success_subscribed_notification":"Vous vous êtes abonné avec succès.","success_unsubscribed_notification":"Vous vous êtes désabonné avec succès."},"errors":{"messages":{"invalid_vat":"nâest pas un numéro de TVA %{country_adjective} valide","vies_down":"Impossible de valider votre numéro de TVA : le service de validation VIES est indisponible. Merci de réessayer ultérieurement."}},"file_size_validator":{"errors":{"invalid_carrierwave":"Un objet CarrierWave::Uploader::Base était attendu","invali
16518d_key":":%{key} doit être un entier non négatif","range_format":":in et :within doivent être une plage (Range)","range_unspecified":"Plage non spécifiée. Indiquez lâoption :within, :maximum, :minimum ou :is."}},"file_type":{"default_error":"Aucun chemin de fichier fourni."},"footer":{"bottom-row":{"privacy":"Confidentialité","terms-link":"Conditions générales"},"links":{"buyLinks":[{"text":"Acheter des modèles 3D","link":"/fr/3d-modeles"},{"text":"Pour les entreprises","link":"/discover/business-account"},{"text":"Jeux de données 3D","link":"/discover/datasets"},{"text":"Embaucher un designer 3D","link":"/3d-modeling-jobs"},{"text":"Modèles 3D gratuits","link":"/fr/libre-3d-modeles"},{"text":"Modèles d'impression 3D gratuits","link":"/fr/libre-3d-imprimer-modeles"}],"communityLinks":[{"text":"Communauté","link":""},{"text":"Top designers","link":"/designers"},{"text":"Défis","link":"/challenges"},{"text":"Forum","link":"/forum"}],"companyLinks":[{"text":" Compagnie","link":"/discover/about-us"},{"text":"Blog","link":"/blog"},{"text":"Carrières","link":"/pages/careers"},{"text":"Centre d'aide","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"Vendre des modèles 3D","link":"/discover/sell-3d-models"},{"text":"Développez vos ventes","link":"/discover/sell-more"},{"text":"Tendances du marché 3D","link":"/discover/3d-market-trends"},{"text":"Recherches de modèles 3D populaires","link":"/discover/3d-models-top-searches"},{"text":"Recherches d'impression 3D populaires","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"Souscrire","button-disabled":"Inscrit","header":"Abonnez-vous à nos nouvelles:","placeholder":"Entrer votre Email","terms-link":"Conditions d'utilisation","text":"En vous abonnant confirmez que vous avez lu et accepté notre"}},"general":{"description":"CGTrader est un marché en ligne où les artistes 3D et les concepteurs peuvent acheter, vendre ou partager des modèles 3D. Elle a été fondée et est mis au point par une équipe de designers et d'ingénieurs en 3D. Notre objectif est de démocratiser le marché boursier 3D et changer la façon dont nous vend
16518ons des modèles 3D en ligne. En laissant les auteurs gagnent des redevances maximales, nous nous efforçons d'accroître leur motivation et améliorer la qualité des modèles 3D.","navigation":{"buy_3d_models":"Acheter Modèles 3D","sell_3d_models":"Vendre Modèles 3D"},"search_placeholder":"Rechercher dans plus de 2 millions de modèles","site-search__field":"Recherchez parmi %{model_count} modèles 3D","site_title":"Modèle 3D Magasin","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"Laissez l'IA réaliser vos rêves","subtitle":"Transformez un prompt ou une image de référence en un modèle 3D prêt pour la production, puis affinez-le, retexturez-le et exportez-le dans le format dont vous avez besoin."},"faq":{"heading":"Questions fréquemment posées","items":{"commercial":{"answer":"L'utilisation commerciale de votre modèle 3D %{object} est disponible avec un plan payant CGTrader AI. Veuillez consulter les Conditions Générales de CGTrader pour les conditions de licence applicables aux modèles générés par IA.","question":"Puis-je utiliser le modèle %{object} généré à des fins commerciales ?"},"formats":{"answer":"Les modèles 3D de %{object} sont disponibles aux formats GLB, FBX, OBJ, STL ou USDZ.","question":"Dans quel format de fichier puis-je obtenir mon modèle %{object} ?"},"no_skills":{"answer":"Aucune connaissance en modélisation 3D n'est requise. Toute la modélisation est effectuée via le générateur de modèles %{object}. Le système gère la géométrie, les proportions et la structure lorsque vous saisissez votre prompt ou téléchargez une image. Même les débutants peuvent créer un modèle 3D %{object} complet en quelques minutes.","question":"Faut-il des connaissances en modélisation 3D pour utiliser un générateur de modèles %{object} ?"},"what_is":{"answer":"Le générateur de modèles 3D %{object} de CGTrader, un outil basé sur l'IA, crée un modèle tridimensionnel de %{object} à partir d'instructions écrites ou d'images de référence. Il analyse votre idée et crée un modèle téléchargeable pour la conception, le prototypage et la visualisation. Nos abonnements payants offrent des limites mensuelles plus élevées.","question":"Qu'est-ce qu'un générateur de modèles 3D %{object} ?"},"why_cgtrader":{"answer":"Les utilisateurs peuvent faire confiance à CGTrader pour une expérience fluide, des temps de traitement rapides et des sorties 3D de haute qualité. Cet outil convient aussi bien aux professionnels qu'aux débutants qui recherchent une solution fiable pour créer des modèles 3D %{object}.","question":"Pourquoi utiliser le générateur %{object} par IA de CGTrader ?"}}},"h1":"Générateur de modèles 3D %{object} par IA","hero_alt":"Générateur de modèles 3D %{object} par IA","hero_height":617,"hero_width":1080,"how_to":{"heading":"Générer un %{object} à partir d'images ou de prompts texte","paragraphs":["Il est très facile de concevoir un modèle tridimensionnel de %{object}. Dans la barre latérale gauche, en haut à gauche, cliquez sur le bouton pour télécharger votre image de %{object} et créer un modèle 3D. Vous pouvez également saisir un prompt dans le champ « Décrivez ce que vous souhaitez créer » en bas. CGTrader AI affine automatiquement votre prompt, donc une courte description suffit pour commencer.","La barre latérale droite vous donne un bon contrôle sur votre modèle 3D %{object}. Choisissez des paramètres tels que le type de maillage, le matériau, le guidage du prompt et le format de fichier. Vous pouvez également appliquer des textures pour personnaliser votre modèle %{object}. Après avoir saisi vos instructions texte ou image, cliquez sur « Générer ». L'outil traitera votre entrée en quelques minutes, selon la charge système, le matériau, le type de maillage, les formes, les valeurs de seed et la qualité."],"steps":["Rédigez votre description textuelle et/ou joignez une image de référence pour améliorer la précision finale de votre modèle 3D %{object}.","Sélectionnez l'un de nos préréglages, ou choisissez un moteur IA, ajoutez un nombre de polygones personnalisé et sélectionnez le type de matériau pour votre modèle 3D %{object}.","Cliquez sur Générer pour créer un modèle 3D %{object} à partir de votre prompt et/ou de votre image de référence.","Téléchargez votre modèle 3D %{object} créé dans différents formats (GLB, FBX, OBJ, STL ou USDZ)."]}
16518,"intro":"Vous cherchez un moyen simple et rapide de créer un modèle 3D %{object} de haute qualité en quelques minutes ? Notre générateur de modèles 3D %{object} avancé, CGTrader AI, peut transformer des commandes écrites ou des images de référence en modèles entièrement fonctionnels. Il fonctionne sur les meilleurs moteurs de génération 3D, notamment Meshy, Hunyuan et Tripo3D. Il permet la modélisation rapide de modèles 3D aussi bien pour les débutants que pour les experts en design, pour la visualisation, l'expérimentation et le prototypage. Il prend en charge le texte vers 3D et l'image vers 3D, et est compatible avec les imprimantes 3D. Vous pouvez télécharger une image au format JPG ou PNG, ou saisir une description en texte. CGTrader AI s'occupe du reste.","meta_description":"Générateur de modèles 3D %{object} par IA de CGTrader âï¸ Créez des modèles 3D %{object} détaillés à partir de texte ou d'images. Commencez gratuitement.","primary_cta":"Commencer à générer gratuitement","title":"Générateur de modèles 3D %{object} par IA (gratuit) | CGTrader"}}},"rules":{"errors":{"front_view_required":"Une image de la vue de face est requise."}}},"home":{"index":{"3D-projects":{"info-section__cta":"Apprendre encore plus","info-section__description":"Où les gens avec des projets 3D passionnants rencontrent talentueux designers 3D","info-section__heading_html":"\u003cStrong\u003e Projets 3D \u003c/strong\u003e Freelance Hub"},"categories-conatainer":{"browse_all":"Parcourir tous les modèles","browse_all_tooltip":"Parcourir tous les modèles 3D","discounts":"Réductions"},"cgdream":{"cta":"Commencez gratuitement!","heading_html":"\u003cstrong\u003eDécouvrez CGDream,\u003c/strong\u003e\u003c/br\u003e où lâIA rencontre les modèles 3D.","text_html":"\u003cstrong\u003e CGDream \u003c/strong\u003e est une application de pointe qui tire parti de la puissance des modèles Génératifs AI et 3D pour produire de superbes images 2D. \u003cstrong\u003e Votre voyage créatif commence maintenant. \u003c/strong\u003e"},"community":{"info-section__cta":"Rejoignez la communauté","info-section__heading_html":"Joignez-vous à CGTrader \u003cstrong\u003e Communauté \u003c/strong\u003e","info-section__icon-list_1":{"description":"Présentez votre rend le mieux, obtenir des commentaires et de la reconnaissance","heading":"Galeries"},"info-section__icon-list_2":{"description":"Apprenez de nouvelles compétences et enseigner aux autres","heading":"Tutoriels"},"info-section__icon-list_3":{"description":"Trouver des tutoriels et de discuter d'autres questions liées à la 3D","heading":"Forum"}},"covid":{"timer-strip__item":"Ressources gratuites imprimables 3D pour Covid-19 Protection","timer-strip__item--button":"Parcourir les modèles 3D"},"enterprise":{"info-section__cta":"Apprendre encore plus","info-section__heading_html":"Services 3D pour la \u003cstrong\u003e l'entreprise \u003c/strong\u003e","info-section__icon-list_1":"Nous pouvons faire la mise en oeuvre de AR pour vous","info-section__icon-list_2":"Plus de conversions de ventes, moins les retours de produits","info-section__icon-list_3":"Qualité assurée avec AQ strictes"},"header":"Modèles 3D pour VR / AR, impression 3D et infographie","marketplace":{"info-section__description":"Choisissez parmi %{models_count} modèles 3D pour des applications telles que les jeux, AR / VR, la publicité, l'animation, les films et l'impression 3D","info-section__heading_html":"Modèle 3D \u003cstrong\u003e marché \u003c/strong\u003e","info-section__image-list_1":{"description":"Acheter des modèles professionnels 3D pour votre projet","heading":"Modèles 3D"},"info-section__image-list_2":{"description":"Low-poly PBR Modèles 3D prêts pour les jeux vidéo, VR et AR applications en temps réel","heading":"Poly faible PBR Modèles 3D"},"info-section__image-list_3":{"description":"Trouver 3D imprimer des dessins pour votre imprimante 3D","heading":"Modèles d'impression 3D"},"view_all":"Voir tous"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"Transformez une image en modèle 3D","title":"Image vers 3D"},"text_to_3d":{"description":"Décrivez votre idée pour créer un modèle 3D","title":"Texte vers 3D"}},"ai_section_title":"Créer avec l'IA","aria_label":"Suggestions de recherche","columns":{"cg":{"search_label":"Rechercher dans les modèles 3D","title":"Modèles 3D"},"print":{"search_label":"Rechercher dans l'impression 3D","title":"Modèles pour impression 3D"}}},"sell":{"info-section__heading_html":"\u003cstrong\u003e Vendre \u003c/strong\u003e 3D vos modèles et projets indépendants Trouver","info-section__icon-list_1":{"de
16518scription":"Vendez vos modèles 3D et gagnez jusqu'à 85% des redevances","link":"Vendre Modèles 3D"},"info-section__icon-list_2":{"description":"Travailler avec les clients de l'entreprise","link":"Obtenez qualifié"},"info-section__icon-list_3":{"description":"Externaliser vos compétences et obtenir jusqu'à 95% des redevances","link":"Parcourir Modélisation 3D Offres d'emploi"},"info-section__icon-list_4":{"description":"Construisez votre portefeuille et être visible","link":"Parcourir les concepteurs 3D"}},"seo":{"description":"Explorez plus de 2 millions de modèles 3D en ligne pour les projets d'impression, de jeu, VR/AR et de design. Téléchargez, personnalisez ou engagez des experts 3D - tout sur CGTrader.","title":"CGTrader - Modèles 3D et Marché d'Impression 3D"}}},"homepage":{"budget_counter":{"range_0_10":"Moins de 10 $","range_10_20":"10 $ - 20 $","range_20_15000":"Plus de 20 $"},"quotes":{"quote_0":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Baisser les commissions prélevées sur les vendeurs moyens meilleurs prix pour les acheteurs. Consultez et comparez les prix à CGTrader et les autres magasins."},"quote_1":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Le plus frappant avantage de CGTrader est le système d'activation des frais fixes qui nous donne un rendement élevé. Vous ne prenez pas un pourcentage de commission de notre chiffre d'affaires. Après la vente, nous recevons 100% du prix. Seulement si nous voulons continuer à vendre ce produit, nous pouvons réactiver à nouveau en payant 5 $. Solution élégante."},"quote_10":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"Le système d'activation de frais fixes est ingénieux. Je me demandais pourquoi personne ne l'avait pensé auparavant. Après la vente, payer une petite taxe pour activer un produit et c'est tout. Le vendeur est en plein contrôle."},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Il y a deux choses que j'aime le plus CGTrader. Tout d'abord, il n'y a pas de sens caché à quoi que ce soit ici. Vous n'avez pas besoin d'être prudent avec CGTrader. En second lieu, ce magasin est par les artistes et les artistes. Ils comprennent mieux vous. Quelque chose vous tracasse ici? ... leur faire savoir et ils feront en sorte que vous vous sentez à l'aise ici."},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"système d'activation des frais fixes est le meilleur! (Je ne l'ai pas au moins sur quoi que ce soit mieux venir que cela). Il est très réaliste et équitable aux vendeurs. Ils ne se soucient pas beaucoup de profit que vous faites, juste payer le loyer fixe. Mais si vous ne faites des ventes, vous n'avez pas de ne pas payer le loyer soit. Le commerce équitable CG est ici!"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"CGTrader attire les clients, même des pays en développement, parce que les prix sont moins chers que d'autres magasins. En même temps les auteurs peuvent gagner plus, parce qu'il n'y a pas une telle chose que des taux élevés de commission. Il est une bonne façon de valoriser le travail des artistes 3D."},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"Interface intuitive de l'éditeur et des outils innovants comme recommandation tag et formulaires de description flexibles rend le processus d'édition facile et rapide."},"quote_15":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"L'approche de CGTrader de vente 3D est différent et ont rien en commun avec d'autres magasins que je vendais. Payer une somme modique de 5 $ après la vente est une excellente idée et me permettent d'offrir des prix les plus bas ici. Client et l'artiste sont avantagés avec cette façon de travailler."},"quote_16":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"Le système de téléchargement est facile et claire. Il est bon de savoir que derrière le projet sont des personnes avec des années d'expérience en matière de graphiques informatique. Chaque fois que j'avais un problème, l'équipe CGTrader fixe rapidement."},"quote_17":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTrader me permet de lier mon profil avec ma page web personnelle. Les clients peuvent me contacter, si elles ne sont pas certains au sujet d'une caractéristique d'un élément qu'ils veulent acheter ou tout simplement une modification de celui-ci. Il est comme posséder un magasin 3D personnel dans un grand marché!"},"quote_2":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Nous avons bénéficié d'un grand soutien et réactif de l'équipe CGTrader. Le personnel a gentiment proposé de faire la publication de tous les modèles pour nous, ce qui est d'une grande aide pour les vendeurs professionnels."},"quote_3":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Sur cette plate-forme nous pouvons offrir de meilleurs prix à nos clients. Par exemple, tous nos produits sont vendus 20% plus bas que partout ailleurs et nous obtenons encore plus de profits par rapport à d'autres magasins!"},"quote_4":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"Ce système est le meilleur à ce jour. Tous les autres magasins en ligne 3D prennent% de nos bénéfices. Ce fut la caractéristique qui a attiré notre intérêt pour CGTrader depuis le début. Les clients, l'achat sur CGTrader, sac
16518hez que la plupart de leur argent vont à l'auteur, qui à la fin fera des modèles plus et mieux si leurs bénéfices améliorer."},"quote_5":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"CGTrader est la boutique en ligne 3D qui a fait la plus forte croissance des ventes et des bénéfices pour nous. Le système d'activation des frais de plat est le meilleur que vous pouvez trouver, car il récompense les créateurs de contenu au lieu d'intermédiaires."},"quote_6":{"author":{"name":"RiÄardas Marozas","username":"autopompe"},"text":"Quand j'ai reçu 160 $ ââà mon compte Paypal, ne savait pas ce qui se passe car il n'a jamais eu lieu auparavant, mais je pensais que ce pourrait être une vente CGTrader et j'avais raison. Vendu le même pack sur Turbosquid le mois dernier pour 189 $, mais après 40% de taux de redevance et 30% de taxe, je ne ai obtenu 52,92 $ - quelques centimes par rapport à 160 $ ââde CGTrader. De plus le client a payé 29 $ de moins - maintenant c'est une entreprise appropriée."},"quote_7":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"Au début, j'étais sceptique sur une bonne affaire pour les vendeurs qui ne sont pas la norme pour les grands magasins en ligne 3D. Quand j'appris sur le système d'activation des frais de plat, j'ai été impressionné par cette façon créative de la vente d'actifs numériques. Vendre, puis activer en payant des frais de 5 $. Tout sens pour moi. J'uploadé un peu pour essayer et vraiment, quand je suis arrivé ma première vente, il était de 100% de Royauté!"},"quote_8":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"Je suis tellement habitué à beaucoup d'autres sites qui charge entre 30% - 60% de commission jusqu'à ce que je découvre CGTrader. En tant que vendeur, je doute que le pourcentage élevé des rendements de redevances."},"quote_9":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"L'expérience du vendeur est fantastique. présentation des produits est un jeu d'enfant. Et oui, le système m'a permis de sauver un projet de ma soumission de produit chaque étape du chemin."}}},"hyperwallet":{"failed_payment_agreement":"Une erreur inattendue sâest produite","success_notification":"Lâaccord de paiement a été mis à jour avec succès.","success_payment_agreement":"Lâaccord de paiement a été soumis avec succès."},"item-search-filters":{"3d-models-url":"3d-modeles","3d-print-models-url":"3d-imprimer-modeles","dedicated-search-page-url":{"animated":"/animes-","free":"/libre-","low_poly":"/low-poly-","pbr":"/pbr-","rigged":"/gree-"}},"item_use_case":{"not_valid":"Fichier invalide","pundit":{"not_authorized":"Vous n'êtes pas autorisé à effectuer cette action."},"title":"Cas d'utilisation pour %{item_name}"},"items":{"already_purchased":"Vous avez déjà acheté cet article.","filters":{"attributes":"Les attributs","free":"Gratuit","max_value":"500 $ +","min_value":"2 $","reset":"Réinitialiser les filtres"},"footer":{"next":"Prochain","per_page":"Par page:","previous":"Précédent"},"geometry_type_forbidden":"Type de géométrie interdit !","last_card":{"button_text":"Demander un modèle 3D sur mesure","text":"Impossible de trouver ce que vous cherchez?"},"migrations":{"errors":{"invalid_owner":"Le nouveau propriétaire ne peut pas reprendre les articles.","unpublished_items":"Tous les articles doivent être publiés."}},"new_price_applied":"Les nouveaux prix ont été appliqués avec succès à tous les articles.","new_price_applied_to_selected_items":"Les nouveaux prix ont été appliqués avec succès aux articles sélectionnés.","new_prices_to_filtered_models":"Les nouveaux prix ont été appliqués avec succès à tous les articles filtrés.","order_processed":"Commande traitée.","order_processing":"Traitement de la commande.","something_went_wrong":"Une erreur sâest produite","title_error":"Le titre ne doit pas contenir de symboles non latins","uniq_user":"a déjà soumis un cas dâutilisation pour cet article","upload_error":"Erreur de téléversement.","validate_license_for_zero_price":"nâest pas valide pour un article gratuit","validate_minimum_price":"Les offres de prix ne doivent pas être inférieures à 50 % du prix initial","verify_printable_formats_error":"Veuillez téléverser au moins un fichier .stl, .obj ou .wrl.","you_can_not_delete_models":"Vous ne pouvez pas supprimer des modèles"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projects facilite lâembauche dâartistes 3D freelances qualifiés et vous aide à relever tous vos défis de modélisation.","heading_html":"Découvrez la meilleure plateforme de freelances pour vos \u003cstrong\u003emissions de modélisation 3D\u003c/strong\u003e"},"sections":{"call_to_action":{"description":"Publiez votre projet gratuitement et voyez à quel point il est facile de résoudre votre prochain défi de modélisation avec des Projets 3D.","title":"Engagez les meilleurs talents 3D dès aujourdâhui !"},"freelancer_selection":{"title":"Faites de votre prochain projet 3D un succès","widest_selection":{"description":"Ne vous contentez pas de moins. Avec 40 000 designers 3D freelances, CGTrader est la plus grande plateforme pour vous connecter à des spécialistes qualifiés : modeleurs, animateurs, riggers, pros de lâimpression 3D et bien dâautres.","title":"La plus large sélection de freelances 3D"}},"how_it_works":{"steps":{"describe":{"description":"Dites-nous ce dont vous avez besoin. Utilisez notre formulaire simple, ajoutez des images et publiez votre offre freelance en quelques minutes.","title":"Décrivez votre projet"},"pay":{"description":"Payez le budget à lâavance en toute sécurité à CGTrader et faites savoir à votre freelance que vous êtes prêt à commencer. Discutez, partagez des pièces jointes et suivez lâavancement du projet facilement dans votre espace de travail. Libérez le paiement lorsque vous êtes satisfait du résultat final.","title":"Payez pour le résultat"},"select":{"bullets":["Recevez des devis de designers qualifiés directement dans votre boîte de réception","Discutez en temps réel avec les designers","Parcourez leurs projets précédents","Vous pouvez également rechercher, filtrer et inv
16518iter des freelances selon leurs compétences 3D, évaluations et préférences logicielles ou de format"],"title":"Sélectionnez le meilleur freelance"}},"title":"Réalisez votre travail en 3 étapes simples"},"payment_quality":{"description":"CGTrader garantit que les services freelances répondront à vos exigences et seront livrés à temps. Notre équipe QA est disponible à tout moment.","title":"Qualité garantie"},"secure_payments":{"description":"Notre service dâentiercement signifie que vos fonds sont protégés et que vous ne payez que lorsque vous êtes satisfait du résultat final.","title":"Paiements sécurisés"},"workspace_convenience":{"description":"Oubliez la frustration de devoir passer dâun onglet à lâautre et entre différents outils. Avec lâespace de travail dédié, vous pouvez facilement tout gérer en un seul endroit : plusieurs projets, factures, conversations, partage de fichiers et plus encore.","title":"Commodité sur un seul écran"}},"shared":{"post_project_cta":"Publier un projet"}},"navigation":{"find_jobs_cta":"Trouver des emplois 3D","hire_freelancers_cta":"Engager des freelances 3D","how_it_works":"Comment ça marche","why_projects":"Pourquoi Projets 3D"}},"agreed_to_terms_of_use":"Vous devez accepter les Termes et Conditions de 3D Projects pour continuer.","budget_error_message":"est trop élevé","check_designer_uniqueness_error":"Le concepteur ne peut être invité quâune seule fois","check_ownership_error":"Lâinvitant nâest pas propriétaire du projet","check_status_error":"Les concepteurs ne peuvent être invités quâà des projets approuvés.","deadline_error_message":"La date limite doit être dans le futur","discount_code_error":"Désolé, le code de réduction nâexiste pas ou a expiré.","email_subject":"Opportunité de projet 3D : %{subject}","error_check_application_uniqueness":"Vous ne pouvez postuler quâune seule fois","error_check_applier":"Vous ne pouvez pas postuler à votre propre projet 3D","error_check_job_availability":"Lâutilisateur nâest pas autorisé à postuler","error_check_job_status":"Les candidatures aux projets sont en attente jusquâà ce que notre nouveau processus de modération soit terminé, généralement sous 3 jours ouvrables. Merci de votre compréhension !","modeling_request_failed":"La demande de modélisation a échoué !","offer_has_been_sent":"Merci, votre offre a été envoyée !","offer_is_closed":"Lâoffre est clôturée.","payment_successful":"Paiement effectué avec succès.","payment_under_review":"Le paiement est en cours de révision.","share_with_yourself_error":"Le partage de modèles « Hire Me » avec vous-même nâest pas autorisé","system_messages":{"buyer_cancels_job":"Le projet a été annulé et déplacé vers lâonglet %{archive_url}.","buyer_edits_hire_me_template":"Les détails du projet ont été mis à jour par le client.","buyer_edits_job_details":"Les détails du projet ont été mis à jour.","buyer_marks_job_as_finished":"Le projet a été marqué comme terminé et déplacé vers lâonglet %{archive_url}.","buyer_marks_job_as_finished_with_resell":"Le client a marqué le projet comme terminé et vous a autorisé à vendre les résultats sur CGTrader. Assurez-vous de \u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003etéléverser\u003c/a\u003e\u003c/b\u003e le modèle créé !","buyer_negotiates":"Le client a négocié votre offre de prix.","buyer_pays_for_the_job":"Le projet a été prépayé et déplacé vers lâonglet %{in_progress_url}.","designer_accepts_changes":"Le concepteur a examiné les détails mis à jour.","designer_accepts_offer":"Le concepteur a accepté votre offre.","designer_edits_offer":"Le concepteur a modifié son offre.","designer_negotiates":"Le concepteur a négocié votre offre.","designer_withdraws_offer":"Le concepteur a retiré son offre.","job_expires":"Le projet a expiré et a été déplacé vers lâonglet %{archive_url}."},"template_error":"Aucun projet nâa été créé !","user_not_exists":"Lâutilisateur avec ce nom dâutilisateur nâexiste pas.","want_that_job":"Je veux ce travail !"}
16518,"kodama":{"invalid_request":"Requête invalide !"},"landing":{"consent_not_saved":"Le consentement nâa pas été enregistré","failure_notification":"Tous les champs obligatoires de la demande dâaccès à lâAPI doivent être valides.","success_notification":"Merci pour votre demande. Nous vous contacterons sous peu."},"layout":{"chunk_load_notice":"Une erreur s'est produite lors du chargement de cette page. Veuillez l'actualiser.","cookies_policy":{"accept":"J'accepte","learn_more":"Apprendre encore plus","text":"Notre site Web utilise des cookies pour recueillir des données statistiques des visiteurs et l'interaction de piste avec la communication de marketing direct / améliorer notre site Web et d'améliorer votre expérience de navigation. S'il vous plaît voir notre avis Cookie pour plus d'informations sur les cookies, les données qu'ils recueillent, qui peuvent y avoir accès, et vos droits."},"translations_notice":{"cta":"Basculer vers English","text":"Salut! Nous traduisons CGTrader. Les traductions sont en cours et certaines sections pourraient ne pas être disponibles en français."}},"model":{"already_purchased":"Vous avez déjà acheté ce produit. Vous pouvez le télécharger depuis votre \u003ca href='/profile/cart/purchased'\u003epanier\u003c/a\u003e. Si vous le souhaitez, vous pouvez l'acheter à nouveau.","animated":"Animé","artist_profile":"Profil de l'artiste","author":"Auteur","author_get_your_payment":"L'auteur recevra 100% de votre paiement. CGTrader permet aux artistes de maximiser leurs revenus et les motive à vendre du contenu de haute qualité.","author_products":"Plus de produits par \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e","authorised_seller":"Vendeur autorisé CGTrader","authority":"Autorité","breadcrumb":{"3d_models":"Modèles 3D","home":"Accueil"},"bulk_download":{"download_all":"Télécharger tous les fichiers","files_included":{"one":"%{count} fichier inclus","other":"%{count} fichiers inclus"},"too_large":"Ce modèle est trop volumineux pour être téléchargé en une seule archive (plus de %{limit}). Veuillez télécharger les fichiers individuellement."},"buy":"Acheter","cannot_download":"Seuls les utilisateurs ayant %{experience_needed} points de réputation peuvent télécharger plus de %{models} modèles gratuits. En savoir plus sur les niveaux et la réputation en \u003ca href='%{reputation_url}' target='_blank'\u003ecliquant ici\u003c/a\u003e.","collection":"pack 3D","contact_author":"Contacter l'auteur","description":"Description","download":"Télécharger","download_limit_exceeded":"Vous avez dépassé votre limite quotidienne de téléchargements. Veuillez réessayer demain. Cette limite ne s'applique pas aux utilisateurs ayant effectué un achat au cours des 12 derniers mois.","download_modal":{"chat_with_us":"Discuter avec nous","contact_support":"Veuillez nous contacter via le chat.","download_file":"Télécharger %{name}","empty":"Aucun fichier trouvé","generic_error":"Une erreur est survenue, veuillez réessayer","link_error":"Nous sommes désolés, mais votre lien de téléchargement semble présenter un léger problème.","pbr_ready":"Compatible PBR","preparing":"Préparation de votre téléchargement...","title":"Télécharger les fichiers"},"format_downloads":"Téléchargements de formats 3D","game_ready":"Prêt pour le jeu (low-poly)","geometry":"Géométrie","license":"Licence","make_offer":"Faire une offre","materials":"Matériaux","messages":{"no_files":"Aucun fichier téléchargé","no_rating":"Pas encore d'évaluation disponible pour ce modèle"},"model_details":"Détails du modèle 3D","pbr_textures":"Textures PBR","plugin_used":"Plugin utilisé","polygons":"Polygones","price":"Prix","print_ready":"Prêt pour l'impression 3D","product_id":"ID du produit","product_support":"Support produit","product_type":"Type de produit","published":"Publié le","rated":{"error":"Vous avez déjà évalué ce modèle","success":"Merci d'avoir évalué ce modèle"},"rating":"Ãvaluation du modèle 3D","ratings":{"desc":{"negative":"Les utilisateurs ayant acheté ce modèle 3D le considèrent de qualité inférieure aux attentes","positive":"Les utilisateurs ayant acheté ce modèle 3D le considèrent de bonne qualité"},"negative":"négatif","positive":"positif"},"recently_viewed_models":"Modèles récemment consultés","renderer":"Moteur de rendu","report":"Signaler","rigged":"Rigged","scripts-plugins":"Scripts et Plugins","similar_models":"Modèles similaires","statistics":"Statistiques","subscription":{"limit_reached":"Vous avez atteint la limite de téléchargements pour cette période de facturation.","limit_reached_detailed":"Vous avez atteint votre limite de %{limit} téléchargements pour ce mois. Votre limite est réinitialisée le %{reset_date}. Pour télécharger plus de modèles maintenant, vous pouvez les acheter individuellement.","limit_reached_detailed_no_date":"Vous avez atteint votre limite de %{limit} téléchargements pour ce mois. Pour télécharger plus de modèles maintenant, vous pouvez les acheter individuellement."},"tags":"Tags","textures":"Textures","title":"%{item_title} Modèle 3D","unwrapped_uvs":"UVs dépliées","uv_mapping":"Cartographie UV","vat_notice":"Tou
16518s les prix sont hors TVA","version":"Version","vertices":"Sommets","vr":"Modèles VR"},"models":{"error":{"cannot_be_blank":" ne peut pas être vide."}},"navigation":{"3d-models":{"3d-printing":"Fichiers d'impression 3D","discounts":"Remises","find_designers":"Trouvez les meilleurs concepteurs","free":"Modèles 3D gratuits","pbr":"Modèles 3D PBR","scanned_3d-models":"Modèles 3D scannés","scripts_apps":"Scripts \u0026 applications","show-all":"Afficher tout","textures":"Textures CG","title":"Modèles 3D","vr_low-poly":"Modèles 3D low-poly"},"already_added_message":"a déjà été ajouté au panier","already_purchased_message":"Vous avez déjà acheté cet article.","aria":{"account":"Compte","cart":"Panier","close_menu":"Fermer le menu","logo":"CGTrader - Modèles 3D / Concepteurs 3D","messages":"Messages","notifications":"Notifications","open_menu":"Ouvrir le menu","search":"Rechercher","search_by_image":"Recherche par image"},"budgets":{"below_10":"Moins de 10$","collections":"Packs","free":"Gratuit","more_than_20":"Plus de 20$","more_than_50":"Plus de 50$","sale":"En vente","subscription":"Abonnement"},"cart_limit_reached":"Vous avez atteint la limite de 500 articles dans votre panier. Pour continuer vos achats, veuillez compléter votre commande actuelle et en commencer une nouvelle pour tout article supplémentaire.","cart_widget":{"continue_shopping":"Continuer les achats","discount":"Remise avec coupon de l'entreprise: ","discount_applied":"Remises appliquées :","final":"Prix ââfinal: ","have":"Vous avez","items":" articles dans votre panier.","left_to_unlock_discounts":"Encore {{leftToUnlock}} pour débloquer les remises","potential_discount":"Remise potentielle :","proceed":"Procédez au paiement","recently_viewed_empty_text":"Commencez à explorer et vos articles récemment consultés apparaîtront ici.","recently_viewed_empty_title":"Rien ici pour l'instant","recently_viewed_tab":"Récemment consultés","remainer":"Pour activer les points de CGTrader, ajoutez: ","sale_discounts":"Remises appliquées: ","sale_time_left":"La vente se termine dans","sale_tooltip":"Les remises de nos campagnes de soldes ne s'appliquent que lorsque votre panier atteint ${{threshold}} ou plus.","sale_tooltip_text":"Cet article est en promotion, mais la réduction ne sera appliquée que lorsque le sous-total de votre panier atteindra ${{threshold}} ou plus.","text":"Votre panier est vide.","title":"Panier","total":"Total: ","used":"Crédits utilisés: ","view":" Voir le panier","wishlist_empty_text":"Commencez à explorer et enregistrez vos favoris pour plus tard â ils apparaîtront ici.","wishlist_empty_title":"Votre liste de souhaits est vide","wishlist_tab":"Liste de souhaits"},"community":{"awards":"Prix des Designers ð","blog":"Blog","challenges":"Défis","community_ratings":"Ãvaluations de la communauté","designers":"Designers 3D","digital_art":"Concours d'art numérique ","forum":"Forum","galleries":"Galeries","invite":"Invitez un ami","printlist":"Liste d'impression 3D","sell_3d-models":"Vendre des modèles 3D","title":"Communauté","tutorials":"Tutoriels"},"conversations_widget":{"conversations":"conversations","messages":{"loading":"boîte de réception de chargement"},"types":{"cgtrader_support":"Assistance CGTrader ","file_conversion_request":"demande de conversion de fichier","job_application":"projet 3D","model_feedback":"Commentaires sur le produit","model_support":"Modèle de support","offer":"Offre de prix","personal":"Message personnel","promotions":"promotions"}},"create_ai":{"community_gallery":"Galerie de la communauté","free_trial":"Essai gratuit","generate_3d_model":"Générer un modèle 3D","generation":{"dismiss":"Ignorer la notification","error_title":"Problème de génération","generating_title":"Votre modèle 3D est en cours de génération","open_model":"Ouvrir le modèle","ready_title":"Votre modèle 3D est prêt !"}},"create_with_ai":"Créer avec IA","credits_guest_widget":{"create":"Créez un compte maintenant!","discount":" remise","for":" pour votre ","get":" et obtenez jusqu'à ","learn_more":"En savoir plus sur les crédits de fidélité de CGTrader","link":"ici","purchase":"Premier ach
16518at !","sign-up":"S'inscrire","text_below_1":"Les crédits peuvent être utilisés lors de l'achat \"","text_below_2":"\" validez les modèles marqués et obtenez jusqu'à 30% de réduction du prix."},"credits_user_widget":{"condition_1":"Les points CGTrader peuvent être utilisés pour l achat de modèles marqués du signe \u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e, offrant jusqu à 30% de reduction sur leur prix.","condition_2":"Les points ne peuvent être utilisés que si la valeur totale de votre panier est de \u003cstrong\u003e$%{minimum}\u003c/strong\u003e ou plus.","condition_3":"Pendant les ventes ou promotions actives, les points ne peuvent pas être utilisés.","condition_4":"Gardez à l esprit que les points ont une date d expiration - vos points expireront dans \u003cstrong\u003e%{days}\u003c/strong\u003e jours.","earn_rate":"Taux d'obtenrion de crédit ","first_text_1":"Considérez-le un cadeau pour votre premier achat - vous pouvez utiliser des crédits lors d'achats \"","first_text_2":" \" validez les modèles marqués et obtenez jusqu'à 30% de réduction du prix. Les crédits ne peuvent être utilisés que si la valeur totale de votre panier est égal ou supérieur à ","important":"IMPORTANT:","learn_more":"En savoir plus","lifetime_spending":"Les dépenses de toute une vie: ","list_item":"En augmentant vos dépenses de toute une vie sur CGTrader, votre taux d'obtention de crédit augmente également.","message":" Les crédits ne peuvent être utilisés lors des campagnes de vente, mais vous pouvez toujours augmenter votre niveau de royalties et recueillir plus de crédits pour votre prochain achat.","more_credits":"Comment puis-je obtenir plus de crédits?","next_level":"Niveau suivant: ","notice":"REMARQUE: Les points CGTrader ne peuvent pas être utilisés pendant la vente en cours, mais ils seront à nouveau disponibles une fois la vente terminée. En attendant, découvrez d'excellentes offres sur les modèles 3D \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003eici\u003c/a\u003e","par_1":"Vous avez","par_2":" crédits CGTrader.","par_2_variation":" en Points que vous pouvez dépenser lorsqu'aucune promotion n'est disponible.","regular_text_1":"Les crédits peuvent être utilisés lors d'achats \"","regular_text_2":" \" validez les modèles marqués et obtenez jusqu'à 30% de réduction du prix.","title":" rabais de fidélité de CG Trader"},"enterprise":{"management":"Gestion des ressources 3D","title":"Production de contenu 3D"},"hire_a_freelancer":"Engager freelance","item_add_message":"a été ajouté avec succès au panier","item_restricted_message":"Cet article ne peut pas être acheté en raison des sanctions imposées au pays du concepteur (RU/BY).","navbar":{"actions":{"new":"Nouveau","top_selling":"Meilleures ventes","trending":"Tendances"},"budgets":{"below_10":"Moins de 10$","free":"Gratuit","more_than_20":"Plus de 20$","more_than_50":"Plus de 50$","sale":"En vente","up_to_10":"Jusqu'à 10$"}},"projects":{"3d_customs":"3D personnalisé","3d_printing":"Impression 3D","about":"A propos des projets 3D","browse":"Explorez les projets ","buyer_perspective":"Recruter des concepteurs 3D","for_designers":"Pour les designers","my_projects":"Mes projets","seller_perspective":"Projets 3D en free-lance","start":"Démarrez un projet","work":"Travaillez avec CGTrader"},"sell_3d-models":"Vendre des modèles 3D","sellers_hub":"Espace vendeurs","subscription_includes_item_message":"Cet article est déjà inclus dans votre abonnement.","tooltips":{"cart":"Panier","conversations":"Mes conversations","discounts":" rabais de fidélité de CG Trader","notifications":"notifications","publisher":"Ãditeur"},"user":{"ban_notification":"Ce compte utilisateur est suspendu. Veuillez contacter notre support pour obtenir des explications.","cannot_refer_yourself":"vous ne pouvez pas vous parrainer vous-même","email_confirmation":"Votre adresse e-mail a été vérifiée.","email_reconfirmation":"était déjà confirmée, veuillez essayer de vous connecter","ends_at":"Se termine le : %{date}
16518","handle_error_tfa_code_missmatch":"Le code de sécurité que vous avez saisi est incorrect. Veuillez réessayer.","handle_error_tfa_code_missmatch_last":"Votre code de sécurité a expiré. Pour continuer, cliquez sur renvoyer lâe-mail et saisissez le nouveau code fourni.","handle_error_tfa_default":"Une erreur sâest produite, veuillez réessayer plus tard.","handle_error_tfa_expired":"Votre code de sécurité a expiré.","hundred_percent_royalties_popover":"Vous participez à une campagne temporaire de gains à 100 % : tous les revenus des ventes de nouveaux modèles vous seront versés jusquâà la fin de la campagne","invalid_email_message":"Veuillez entrer une adresse e-mail valide pour continuer.","login":"Se connecter","meta_description":"Découvrez le profil de concepteur 3D %{username} sur CGTrader, son portfolio et ses modèles 3D disponibles. Consultez les meilleurs modèles 3D des artistes de modélisation les plus talentueux de lâindustrie.","meta_title_suffix":"Concepteur 3D","not_valid_birthday":"La date de naissance nâest pas valide.","offline":"Hors ligne","online":"En ligne","page_title":"Profil du concepteur","rate_models_limit":"Vous ne pouvez plus noter de modèles aujourdâhui.","semantic_description":"Modèles 3D, Åuvres et portfolio du concepteur. Découvrez ses créations sur CGTrader","semantic_title":"Profil du concepteur","session_failure":"Nom dâutilisateur/e-mail ou mot de passe incorrect","session_password_expired":"Votre mot de passe a expiré en raison dâune inactivité. Veuillez le réinitialiser via le lien envoyé par e-mail.","session_two_fa_failure":"La vérification du code a échoué","session_unconfirmed":"Votre adresse e-mail nâa pas encore été confirmée.","token_not_recognized":"Le jeton nâa pas été reconnu","twitter_shareable_text":"Un #3dartist à suivre absolument","username_error":"ne doit pas contenir dâespaces ni de symboles non latins"},"user_menu":{"buyer":{"freelancers":"Trouvez des freelance ","purchases":"Mes achats","sell":"Vendre des modèles 3D","wishlist":" Liste de souhait de modèles 3D"},"dashboard":"Tableau de bord admin","logout":"Se déconnecter","public_profile":"Profil public","seller":{"analytics":"Analytiques","find_new_projects":"Trouver de nouveaux projets 3D","freelance":"Projets 3D Freelance","freelance_cgtrader":"Travailler en freelance avec CGTrader","models":"Mes modèles","publish_project":"Publier un projet","publishing":"Ãdition","sales":"Mes ventes","subscription":"Abonnement","wishlist":" Liste de souhait de modèles 3D"},"settings":"Paramètres"}},"owly":{"failed_set_pending":"Ãchec de la mise en attente.","failed_to_approve":"Ãchec de lâapprobation.","failed_to_suspend":"Ãchec de la suspension.","failed_to_update_license":"Ãchec de la mise à jour de la licence.","failed_to_update_status":"Ãchec de la mise à jour du statut dâapprobation."},"print_models":{"browse_all_makes":"Parcourir toutes les créations 3D","browse_all_models":"Parcourir tous les modèles","description":"Découvrez des modèles 3D prêts à imprimer, des ressources imprimables et des fichiers STL pour les jeux, lâart, les projets domestiques et plus encore.","makes_description":"Explorez les dernières créations 3D téléchargées par la communauté â des exemples réels montrant à quoi ressemblent les modèles 3D dans le monde physique.","makes_title":"Nouvelles créations 3D","new_description":"Découvrez les dernières impressions 3D ajoutées à notre collection â des designs frais prêts à télécharger et à imprimer pour votre prochain projet.","new_title":"Nouveaux modèles 3D à imprimer","title":"Modèles 3D dâimpression tendance"},"profile":{"account_settings":{"account":{"email":"Email","submit":"Enregistrer","title":"Profil","update":{"updated":"Profil mis à jour"},"username":"Nom d'utilisateur"},"email_settings":{"descriptions":{"ai_studio_notifications":"Notifications concernant vos générations CGTrader AI, y compris lorsqu'un modèle que vous n'avez pas encore ouvert est prêt","communication":"Informations sur votre communication avec d'autres utilisateurs de CGTrader, y compris les messages personnels, les nouvelles offres de prix et de travail personnalisé, les retours et les demandes de support produit","news":"Informations sur les produits CGTrader, les annonces de nouvelles fonctionnalités et les actualités de la communauté","onboarding_and_edu":"Informations sur votre processus d'intégration et des conseils pour tirer le meilleur parti de CGTrader","push_notifications":"Notifications concernant les activités et mises à jour importantes du compte","sales_and_offers":"Informations sur les offres spéciales, les ventes de modèles 3D et les crédits bonus CGTrader","seller_sold_item":"Informations sur vos modèles 3D vendus et les paiements reçus"},"privacy_policy_html":"Veuillez lire notre \u003ca href=''https://www.cgtrader.com/pages/privacy-policy'' ''target=''_blank''\u003ePolitique de Confidentialité\u003c/a\u003e pour plus d'informations. ","titles":{"ai_studio_notifications":"Notifications CGTrader AI","communication":"Communication (Messages personnels, retours sur modèles 3D, activité communautaire, offres)","news":"Actualités 3D / Mises à jour CGTrader","onboarding_and_edu":"Intégration \u0026 Ãducation","push_notifications":"Notifications Push","sales_and_offers":"Ventes \u0026 offres spéciales","seller_sold_item":"Informations sur les Ventes \u0026 Paiements"},"tracking_attributes":{"ai_studio_notifications":"Notifications CGTrader AI","communication":"Communication","news":"Actualités 3D / Mises à jour CGTrader","onboarding_and_edu":"Intégration \u0026 Ãducation","sales_and_offers":"Ventes \u0026 offres spéciales","seller_sold_item":"Informations sur les Ventes \u0026 Paiements"},"update":{"updated":"Votre email a été mis à jour avec succès."}},"gdpr_success_notification":{"opt_in":"Merci ! Vous vous êtes réabonné avec succès à nos emails.","opt_out":"Vous vous êtes désabonné avec succès de nos newsletters. Vous pouvez modifier cette préférence à tout moment en visitant les paramètres de votre profil.\n"},"location_tooltip_text":"\u003cdiv\u003eCette case à cocher permet d'afficher l'emplacement sur la page de profil.\u003c/div\u003e \u003cdiv\u003eNotez que, dans tous les cas, pour des raisons de conformité, votre emplacement sera affiché à vos acheteurs (si vous êtes un vendeur) et aux vendeurs auprès desquels vous avez acheté.\u003c/div\u003e","moneybookers":{"account":"Compte Skrill"},"password":{"current_password":"Mot de passe actuel","new_password":"Nouveau mot de passe","submit":"Changer le Mot de Passe","title":"Mot de Passe","updated":"Votre mot de passe a été mis à jour avec succès. Vous pouvez maintenant utiliser votre nouveau mot de passe pour vous connecter.","verify_password":"Vérifier le mot de passe"},"paypal":{"account":"Compte PayPal","submit":"Enregistrer","title":"Paramètres PayPal","update":{"updated":"Vos paramètres PayPal ont été mis à jour"}},"personal_info":{"areas_of_expertise":"Domaines d'expertise","country":"Pays","description":"Quelques phrases sur vous","full_name":"Nom complet","languages":"Langues","preffered_tools":"Outils Préférés","submit":"Enregistrer","title":"Informations personnelles et professionnelles","update":{"updated":"Vos informations ont été mises à jour avec succès"},"website":"Site Web"},"personalization":{"no_muted_title":"Aucun designer muet","title":"Designers Muets","tooltip":"Les modèles 3D des designers listés sont exclus de vos résultats de recherche.","unmute_designer":{"confirm":"Ãtes-vous sûr ?"}},"professional_info":{"allow_private_job_requests":"Les acheteurs pourront vous envoyer des demandes de travail 3D personnalisées.","buyer_engagement_program_html":"Attirez plus de clients en leur permettant d'acheter vos modèles avec les Points CGTrader. \u003ca href=''https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained'' target=''_blank''\u003ePlus d'informations\u003c/a\u003e\n","pbr_program":"Le taux de gain inférieur est appliqué uniquement lorsque le fichier
16518converti est téléchargé","pbr_program_agreement":"Vous avez accepté de participer au programme PBR pour 24 mois à partir du %{date}. Consultez les Termes \u0026 Conditions pour plus de détails. Veuillez contacter notre support si vous avez des questions.","product_analytics_participation_html":"Je participe à \u003ca href=''https://www.cgtrader.com/profile/analytics''target=''_blank''\u003eAnalytics\u003c/a\u003e et j'accepte leurs Termes et Conditions\n","product_analytics_participation_tooltip_html":"Vous avez accepté de participer à Analytics et accepté les Termes et Conditions d'Analytics (\u003ca href=''https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service''target=''_blank''\u003elien\u003c/a\u003e) le %{accepted_at}. Si vous souhaitez mettre fin à votre participation, veuillez contacter le support CGTrader\n"},"security":{"allow_mfa":"Activer la vérification en 2 étapes pour protéger votre compte","use_authenticator_app":"Utiliser une application d'authentification pour la vérification en 2 étapes","use_authenticator_app_tooltip":"Scannez le code QR avec votre application d'authentification (Google Authenticator / Authy) pour générer des codes de vérification.","use_email":"Utiliser l'email pour la vérification en 2 étapes"},"sidebar":{"general_settigns":"Paramètres Généraux","member_since":"Membre Depuis","paypal":"PayPal","title":"Infos du Compte"},"title":"Mon Compte"},"conversations":{"conversations":"conversations","messages":{"loading":"boîte de réception de chargement"},"types":{"cgtrader_support":"CGTrader soutien","file_conversion_request":"demande de conversion de fichier","job_application":"projet 3D","model_feedback":"Commentaires sur le produit","model_support":"modèle de soutien","offer":"Offre de prix","personal":"Message personnel","promotions":"promotions"}},"meta":{"description":"Découvrez des modèles 3D de haute qualité réalisés par %{username} sur CGTrader. Parcourez des assets uniques pour jeux, VR/AR et visualisation.","title":"Créateur·rice de modèles 3D : %{username}"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"Vos paramètres ont été mis à jour avec succès."},"publishing":{"banned_error":"Votre compte a été banni pour publication de contenu spam. Si vous pensez qu'il s'agit d'une erreur, veuillez contacter [email protected].","files_not_finalized":"Un ou plusieurs fichiers n''ont pas terminé leur téléversement et ne peuvent pas être publiés. Veuillez les supprimer et les téléverser à nouveau avant de publier.","spam_suspect":"Votre compte n'est pas autorisé à publier ce modèle. Si vous pensez qu'il s'agit d'une erreur, veuillez contacter [email protected]."},"rating":{"anonymous_buyer":"Acheteur Anonyme","errors":{"not_verified_buyer":"Seuls les acheteurs vérifiés peuvent laisser un avis"}},"routes":{"3d-models":"3d-modèles","3d-print-models":"3d-imprimer-modèles","animated-3d-models":"animés-3d-modèles","controllers":{"three_d_studio":{"3d-models":"3d-models","images":"images"}},"discover":"decouvrir","free-3d-models":"libre-3d-modèles","free-3d-print-models":"libre-3d-imprimer-modèles","low-poly-3d-models":"low-poly-3d-modèles","pbr-3d-models":"pbr-3d-modèles","pbr-textures":"pbr-textures","rigged-3d-models":"gréé-3d-modèles","search":"search"},"sale_off":{"no_overlapping_campaigns":"Les dates de la campagne se chevauchent avec une autre campagne de soldes existante.","parse_discount_rules_text":"La ligne #{index} ne contient pas le paramètre requis 'discount:'"},"search":{"not_found":"Abonnement de recherche introuvable","subscription_created":"Abonnement de recherche créé","successfully_unsubscribed":"Vous vous êtes désabonné avec succès de lâabonnement de recherche"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"flash":{"active_subscription":"Vous avez déjà un abonnement actif.","premium_upgrade_unavailable":"Le passage à Premium est temporairement indisponible. Veuillez réessayer plus tard.","update_payment_method":"Votre abonnement rencontre un problème de paiement. Veuillez mettre à jour votre moyen de paiement au lieu de souscrire un nouvel abonnement."},"payment_form":{"current_price":"%{price}","features":{"first":"%{downloads} ressources / mois â téléchargez des modèles ou générez avec l'IA","second":"Accès instantané à plus de %{models_count} modèles 3D essentiels","third":"Libre de droits, sans IA"},"from_price_label":"à partir de","original_price":24.99,"per_model_label":"par modèle","plan_name":"Abonnement CGTrader Essentials â plan annuel, facturé mensuellement","premium":{"features":{"first":"%{downloads} ressources / mois â téléchargez des modèles ou générez avec l'IA","fourth":"Libre de droits, sans IA","second":"Accès instantané à plus de %{models_count} modèles accessibles au total","third":"Modèles de niveau professionnel non inclus dans Essentials"},"plan_name":"Abonnement CGTrader Premium â plan annuel, facturé mensuellement"},"price_unit":"/mois","vat_amount":"%{vat_amount}"}},"tag":{"description":{"bottle":"Les scientifiques disent que la bouteille de vin par jour est pas mal pour vous, mais quand il s'agit de boissons fortes comme le whisky ou bourbon, nous devrions vraiment regarder notre c
16518onsommation d'alcool. De toute évidence, un verre de champagne au bar ressemble refroidisseur façon qu'une bouteille d'eau en plastique, mais pensez à la possibilité de vivre une vie et de la bière plus semblera comme un sacrifice raisonnable. Cette catégorie offre une large sélection de bouteilles modèles 3D, allant des objets liés à l'alcool comme porte-vin et tire-bouchons à tous les types de bouteilles de modèles 3D (de shampooing à l'huile d'olive).","brain":"Le cerveau est l'un des plus grands et les organes les plus complexes du corps humain. En raison de sa structure complexe et la fonction, l'anatomie du cerveau est également très complexe. Cependant, les scientifiques creusent plus profondément dans l'architecture du cerveau humain, découvrant des secrets ahurissants. Une large gamme de cerveau réalistes et détaillées des modèles 3D qui sont prêts pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D est disponible en téléchargement.","building":"On ne sait pas où les architectes modernes prennent leur inspiration, mais quelques-uns des célèbres bâtiments du monde réduisent si bord qu'ils ressemblent à des visions de l'avenir. Et nous ne voulons pas dire que la partie extérieure ... Dans les mains capables d'une construction de bâtiment standard devient une création architecturale à couper le souffle avec un design intérieur innovant, peu importe que ce soit un bureau ou un bâtiment urbain. Notre sélection de construire des modèles 3D est prêt pour le téléchargement et peut être appliquée dans divers domaines - animation 3D, design graphique, publicité, jeux 3D ou web.","camera":"Photographier et filmer est actuellement l'un des domaines les plus populaires de carrière chez les jeunes, mais pas tout le monde avec un appareil photo professionnel est un artiste ou un photographe. Avec la qualité des caméras de téléphone améliore d'année en année, nous voyons des gens qui prennent des photos à chaque étape et ceux qui ont l'image nouvellement développé des compétences d'édition sont vraiment célèbre. La vie a l'air un peu différent quand vous êtes de l'autre côté de la lentille, mais nous allons pas se laisser emporter ... Une large gamme de caméra détaillée des modèles 3D est disponible en téléchargement à utiliser par des graphistes, des animations et des développeurs de jeux et les professionnels qui travaillent dans d'autres domaines liés à la 3D.","car":"En regardant ces modèles de voitures 3D très détaillées et très réalistes, vous pouvez presque entendre le bruit du moteur! Une large gamme de véhicules modèles 3D peut rendre votre vie beaucoup plus facile, si vous êtes aux prises avec l'infographie, l'animation ou tout autre domaine connexe 3D.","cell":"Les scientifiques ont estimé que le corps humain contient de 5 milliards de cellules de 200 millions de billions de dollars. Les plantes et les animaux ont des cellules aussi. Nous ne voulons pas vous ennuyer avec ce genre de choses de la biologie, mais la vaste gamme de modèles cellulaires 3D que nous avons couvre tout du sang, le virus et de l'ADN à la moelle osseuse et les parois cellulaires. Est-ce pas ... énervant?","chair":"Nous prenons assis sur des chaises pour acquis et ne remarquent pas toujours combien le charme qu'ils peuvent ajouter à notre maison ou à l'intérieur bureau. Président est en fait l'une des pièces maîtresses de meubles dans tous les ménages. Vous trouverez ci-chaise design de haute qualité et accrocheur modèles 3D qui peuvent être appliqués dans différents domaines - de la publicité et de visualisation 3D pour des jeux en 3D.","city":"la vie de la ville est un jeu excentrique: rues débordant de taxis de course, des bâtiments modernes, des piétons dans les vêtements de bureau parfaitement adaptés, des ponts de couchage et des parcs ... De Shanghai, à New York (! Manhattan), à Londres ou à Paris - chaque ville a son propre magie. Vous pouvez choisir parmi cette riche sélection de ville détaillée des modèles 3D qui peuvent être utilisés dans un certain
16518nombre de domaines - la publicité, l'infographie, l'animation, la visualisation 3D ou des jeux. Découvrez la vie urbaine.","dragon":"Dragon est probablement la créature la plus populaire vivant dans le monde fantastique. Il a figuré dans tant de mythes de différentes cultures, des animations, des films et des livres qu'il est devenu légendaire. Il est particulièrement apprécié par les développeurs de jeux, car il ajoute que le charme magique des grottes sombres et donjons. Une large gamme de réaliste, truqué de dragon modèles 3D qui sont prêts pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D est disponible en téléchargement.","earth":"Le niveau de détail dans la vue de la terre récemment ajoutée dans les cartes Google a choqué un certain nombre de personnes. Vous pouvez explorer l'ensemble de la planète - les océans, les montagnes et les déserts, les villes et les routes découvrent cachées sans quitter votre maison. C'est des choses incroyables Mère Terre n'a pas connu auparavant. Une sélection de terre réalistes des modèles 3D qui sont prêts pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D est disponible en téléchargement.","engine":"Certaines personnes sont en mesure de nommer le moteur en écoutant simplement le bruit qu'il fait, et qui est vraiment incroyable. Peu importe que ce soit un moteur à réaction ou un moteur de voiture, ils sont des machines extrêmement compliquées que nous utilisons si souvent, mais ne passent pas trop de temps à penser à ce sujet. Un moteur est un moteur (jusqu'à ce qu'il cesse de fonctionner). Cette catégorie comprend une gamme de différents types de moteur modèles 3D, et il comprend également des pièces de moteur comme l'hélice ou d'un cylindre, donc nous sommes confiants que vous trouverez ce dont vous avez besoin.","female":"Il est pas une blague qu'il existe des différences importantes entre le cerveau des hommes et des femmes, ce qui signifie qu'il est normal qu'un homme moyen se comportent et femme, sentir et d'y répondre de manière complètement différente. Mais ce n'est pas tout au sujet de l'anatomie. Aucune histoire d'amour, film ou jeu jamais tiré hors tension sans un fort caractère de fille, parce que la puissance de charme dame est indéniable. Une riche sélection de modèles féminins 3D réalistes peut vous offrir tout ce dont vous avez besoin - à partir de modèles 3D nu féminin pour les voies respiratoires.","hand":"La raison pour laquelle nous utilisons nos mains pour tant de choses est leur anatomie extraordinaire. Le pouce est contrôlé seul par neuf muscles séparés. Il est difficile à croire, mais les mains étaient au début plus exotiques que toute main aujourd'hui - certaines espèces avaient sept doigts. Le corps humain a considérablement évolué. Un bras ou une main comme nous le voyons aujourd'hui ressemble rien comme ses premières versions. Une large gamme de réaliste, truqué la main des modèles 3D qui sont prêts pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D est disponible en téléchargement.","head":"Dans l'anatomie humaine, la tête est la partie supérieure du corps humain. Modélisation d'une tête humaine 3D peut se révéler un peu compliqué, parce que (même si il y a tellement de formes et de tailles différentes), nous apprécions symétriques têtes réalistes prospectifs - sans yeux drôles, les oreilles, le nez, les lèvres ou la ligne mâchoire, s'il vous plaît. Le visage est une zone sensible et il serait juste simplement grossier d'avoir du plaisir avec ça. Notre sélection comprend des hommes réalistes, des femmes, des enfants et même des personnages de l'histoire comme Harry Potter et Batman ou des célébrités comme Tom Cruise tête et Scarlett Johansson qui sont prêts à télécharger.","helmet":"Rappelez-vous toujours que la santé et la sécurité vient en premier, afin de protéger votre tête est une idée de son. chevaliers médiévaux, Daft Punk et même les casques d'usure Ironman, si les superhéros réguliers comme les cyclistes ou les constructeurs ne devraient pas se soucier de regarder pas cool. Cette c
16518ollection de modèles de casque 3D qui est disponible pour le téléchargement se révélera utile si vous travaillez dans les domaines de la conception graphique, animation 3D, jeux 3D ou la visualisation.","house":"C'est une vieille vérité que la maison d'un homme est son château, mais quand il vient à la construction de cette maison parfaite ou l'achat d'un appartement idéal, nous avons tendance à perdre la tête au-dessus. Heureusement, ce large éventail de modèles internes 3D qui englobe tout, de détails architecturaux, intérieurs et extérieurs, des meubles, vous aidera à créer 3D modernes visualisations pour soulager la douleur.","human":"Lorsque vous commencez à explorer l'anatomie humaine, on se rend compte que les gens sont telles machines complexes et complexes qu'il enlève votre souffle. Chaque partie du corps, les muscles, articulations, combinaison d'organes ou d'os est relié en un seul système, rien ne fonctionne en vase clos! Ces super réalistes modèles humains 3D vous permettra d'examiner les structures anatomiques sous tous les angles.","lamp":"Si vous regardez autour de votre maison et compter les types de lampes que vous possédez, vous serez surpris: lecture, table, mur, plafond, bureau, lampes ... trépied Il suffit de faire tourner la tête! Sans oublier les styles qu'ils viennent - des lampes modernes extravagantes à rétro ou futuriste élégant. Dans cette catégorie, nous avons toutes sortes de lampe modèles 3D, donc parcourir et télécharger à utiliser dans la conception graphique, 3D ou visualizations tout autre domaine connexe 3D.","light":"Avez-vous déjà demandé pourquoi une ampoule est le symbole d'une idée brillante? Certes, une idée brillante peut éclairer l'architecture de l'esprit, mais ce ne l'est pas. Une lumière de la rue, un lustre ou tout autre type de lampe ne serait jamais une chance de prendre cette place. Si la prochaine fois que vous levez les yeux vers le plafond et regarder une sorte de lumière architecturale l'idée de génie ne vous a frappé, il pourrait être parce que vous êtes à regarder un système d'éclairage mal ... Notre sélection de lumière de haute qualité modèles 3D se révéleront très pratique si vous travaillez dans les domaines de l'architecture, l'infographie, l'animation ou la conception 3D.","machine":"Imaginez si toutes les machines soudainement cessé de fonctionner: pas de café, pas de laver le linge pratique, pas de points de trésorerie sur un coin de la rue, pas de temps de gym, pas trop cher distributeurs automatiques ... Il ne semble déprimant, non? Nous sommes tellement habitués à ces appareils ménagers et gadgets qu'il serait littéralement arrêter le tournant du monde! Heureusement, notre sélection de la machine détaillée des modèles 3D couvre tout, de mitrailleuses aux producteurs d'électricité qui se révéleront utiles aux concepteurs travaillant avec l'infographie, la publicité, l'animation 3D, jeux 3D ou web.","man":"Une vaste collection de modèles 3D homme est disponible en téléchargement. homme assis, homme simple, homme volant ou homme moyen, nous avons tout - sauf que l'homme parfait que tout le monde est après. Il est un personnage louche et nous déteste en parler, mais il pourrait être un mythe ... Mais bon, les êtres humains sont nés pour être génial, pas parfait.","robot":"R2D2 est probablement le plus célèbre robot dans le monde, mais il est certainement pas le seul. De l'industrie à jouets aux robots humains, nous voyons de plus en plus un choix plus large de ces machines mécaniques, ce qui est à la fois merveilleux et un peu inquiétant. Il est pas trop difficile de comprendre les gens qui insistent sur le fait que les ordinateurs, la technologie, les robots ont un impact trop important sur les êtres humains. Une large gamme de réaliste, truqué robots modèles 3D qui sont prêts pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D est disponible en téléchargement.","ship":"Les navires sont des navires puissants et sont disponibles dans toutes les tailles, les couleurs et les formes. Ils peuvent être classés comme des navires de charge, les navires de guerre ou des navires à passagers, mais ils fonctionnent tous dans les eaux profondes de la mer. Si vous avez connu l'inconfort de la maladie de mouvement, il ne peut pas être un de vos moyens de transport favori, mais beaucoup de gens considèrent comme des excursions en bateau tout à fait chic et agréable. Notre sélection de bateaux modèles 3D est prêt pour le téléchargement et répondra aux normes de même le plus exigeant capitaine.","skeleton":"Le squelette humain ou d'un système squelettique (anatomie) est le cadre interne du corps qui est composé de 270 os à la naissance. Il fournit la structure du corps, la protection et le mouvement et est l'un des systèmes les plus complexes du squelette. Une sélection riche anatomiquement correcte, le squelette des modèles 3D réalistes et mis à l'échelle qui sont parfaits pour une utilisation dans l'animation 3D, la conception graphique, la publicité, les jeux 3D et le Web est disponible en téléchargement.","skull":"Le plus ancien, le crâne humain génétiquement intact le plus complet a été découvert entouré par une variété d'animaux éteints plus de 40 mètres en dessous du niveau de la mer. Il est l'un des plus anciens squelettes trouvés dans le Nouveau Monde et comprend également tous les principaux os du corps et un crâne intact et ensemble de dents. crânes humains sont devenus récemment une chose à la mode et le design, mais quand vous donnez réellement une certaine pensée, ils genre d'entre nous font tous l'air freaks anatomie ... Cette catégorie offre une large gamme de modèles 3D crâne à utiliser dans la conception graphique , l'animation 3D, jeux 3D ou de la publicité.","sofa":"Luxe simple, moderne ou antique, cuir ou design minimaliste? Comment aimez-vous votre canapé? La gamme de canapé modèles 3D que nous avons satisfera même le pire perfectionniste. Lorsque vous arrêtez d'y penser, un canapé est le centre de chaque salon, vou
16518s devez donc faire preuve de créativité lors du choix de la conception!","table":"Les nouvelles tendances meubles sont si diverses que le choix d'une table moderne, la mode devient trop stressant. Il y avait un moment où vous aviez une table simple dîner pour vos fêtes modestes et cela suffisait, mais aujourd'hui - la table est censé être une déclaration ou tout au moins un accent intérieur accrocheur. Cette sélection vous donne une vaste gamme de tables modèles 3D pour répondre à tous les caprices.","tower":"Chaque ville a une tour spéciale que tout le monde est vraiment fier. Pensez Tour Eiffel ou la tour de Pise, ou pont tour de Londres, et encore moins tous les gratte-ciel modernes, les bâtiments futuristes et le paysage urbain que les touristes admirent. Cependant, en ce qui concerne les pièces industrielles de la ville, l'eau ou des tours électriques, tout le monde a tendance à tourner les yeux loin ... Mais nous devons apprendre à apprécier chaque création architecturale, peu importe l'ancienne, industrielle ou moderne. Une gamme de tour des modèles 3D détaillés sont disponibles pour le téléchargement et prêt pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D.","tree":"Si vous êtes sur une mission de planter des arbres ou des plantes exotiques, vous êtes au bon endroit. Cette catégorie offre une gamme de facile à utiliser, très réalistes modèles d'arbres 3D aux artistes et aux architectes CG, qui luttent pour ajouter un peu de verdure à leurs projets. Si vous appréciez de bonne qualité, nous sommes convaincus que cette sélection de modèles de plantes d'arbres 3D répondra à vos besoins!","truck":"Conduire un camion est un travail difficile, surtout si vous avez besoin de trouver votre chemin à travers un embouteillage de la ville. Peu importe que ce soit un camion de pompier, camion à ordures, camion de nourriture ou d'un générique, il faut une grande habileté à manÅuvrer ces véhicules géants. Nous sommes convaincus que cette sélection de réalistes, camion de haute qualité des modèles 3D sont parfaits pour une utilisation dans l'animation 3D, la conception graphique, la publicité ou tout autre domaine connexe 3D.","tv":"Il y avait un temps où cheminée était la pièce maîtresse de chaque maison respectable, maintenant télévision avec les joueurs et les haut-parleurs est le roi du salon (et même la chambre à coucher). à la télévision ces dernières années a rattrapé les technologies les plus récentes. En conséquence, nous avons smart TV 3D, écrans plats et plasma, millions de nouvelles fonctions et la conception de l'écran tactile. Pas de télévision miracle pousse le cinéma du marché. Une large gamme de réalistes, TV modèles 3D détaillés qui sont prêts pour les applications graphiques informatiques comme la publicité, la visualisation 3D, jeux 3D, web et tout autre domaine lié à la conception 3D est disponible en téléchargement."}},"tag_promotion":{"days_left_error":"doit être compris entre 1 et 30","no_other_pending_promotions_for_same_item_tag":"a déjà une promotion en attente"},"tooltips":{"buyer_loyalty_program_current_level_html":"Actuellement, vous avez passé %{total_price_paid} sur CGTrader et votre crédit gagner taux est %{buyer_loyalty_rate}. \u003cbr/\u003e Cela signifie que vous obtiendrez %{buyer_loyalty_rate} des crédits de chaque achat.\n","buyer_loyalty_program_html":"Ceci est le pourcentage de combien vous obtiendrez de vos achats en tant que nouveaux crédits. \u003cbr/\u003e Il augmentera jusqu'à 30% de vos dépenses à vie sur l'augmentation CGTrader. \u003cbr/\u003e Actuellement, votre crédit gagner taux est %{buyer_loyalty_rate}.\n","buyer_loyalty_program_next_level_html":"Niveau suivant %{next_lvl_expenses} de va augmenter votre taux de crédit gagner jusqu'à %{next_lvl_expenses_rate}. \u003cbr/\u003e Vous devez acheter pour $%{left_until_next_lvl} plus pour atteindre le niveau suivant.\n"},"trending_headers":{"models":"Découvrez dâautres modèles 3D tendance","print":"Découvrez dâautres modèles 3D imprimables tendance"},"tutorial":{"destroy":"Le tutoriel a été supprimé avec succès.","submit_for_review_error":"Veuillez remplir tous les champs obligatoires.","submitted":"Merci dâavoir soumis votre tutoriel. Il sera examiné et publié sous peu."}
16518,"valvat":{"country_adjectives":{"at":"autrichien","be":"belge","bg":"bulgare","cy":"chypriote","cz":"tchèque","de":"allemand","dk":"danois","ee":"estonien","es":"espagnol","eu":"intracommunautaire","fi":"finlandais","fr":"français","gb":"britannique","gr":"grec","ie":"irlandais","it":"italien","lt":"lituanien","lu":"luxembourgeois","lv":"letton","mt":"maltais","nl":"hollandais","pl":"polonais","pt":"portugais","ro":"roumain","se":"suédois","si":"slovène","sk":"slovaque"}}},"ja":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"ã¢ãã«ããæ´åçãªã³ã³ãã³ã","ai_generated":"AIçæã³ã³ãã³ã","copyright":"è使¨©ä¾µå®³"}}},"errors":{"messages":{"embedded_script":"ãã®ãã¡ã¤ã«ã¯ãµãã¼ãããã¦ããªããããã¢ãããã¼ãã§ãã¾ãããå¥ã®ãã¡ã¤ã«ãã試ããã ããã"}}},"api":{"profile":{"actions":{"contact":"ã³ã³ã¿ã¯ã","follow":"ãã©ãã¼","follow_tooltip":"ãã®ãã¶ã¤ãã¼ããã©ãã¼ãã¦ã³ã³ãã³ãã®æ´æ°ãåãåããæ¤ç´¢çµæã§ãæ°ã«å
¥ãã®ãã¶ã¤ãã¼ãç°¡åã«çµãè¾¼ã¿ã¾ãããã","hide":"é表示","hire_me":"ä¾é ¼ãã","invite_client":"ããã¸ã§ã¯ããéå§","mute_tooltip":"æ¤ç´¢çµæã§ãã®ãã¶ã¤ãã¼ã®ã¢ãã«ãé表示ã«ãã¾ãã","take_over":"å¼ãç¶ã","unfollow":"ãã©ãã¼è§£é¤","unhide":"表示ãã","view_all_models":"ãã¶ã¤ãã¼ã®ã¢ãã«ããã¹ã¦è¦ã"},"private_project_review":"éå
¬éããã¸ã§ã¯ã"}},"browser":{"3d_models":"3Dã¢ãã«","3d_print":"3Dããªã³ã","active_filters":{"polygons":"%{range}ããªã´ã³"},"adult_content":"æäºº","animated":"ã¢ãã¡ã¼ã·ã§ã³","breadcrumb":{"browse_by_type":"ã¿ã¤ãã§é²è¦§","collection":"3Dããã¯","free":"èªç±","free_models":"ç¡æã®3Dã¢ãã«","free_print_models":"ç¡æã®3Dããªã³ãã¢ãã«","low_poly":"ä½ããª","low_poly_models":"VR / AR /ä½ããª3Dã¢ãã«","low_poly_print_models":"ãã¼ããª3Dããªã³ãã¢ãã«","model_3d":"3Dã¢ãã«","model_3dp":"3Dããªã³ãã¢ãã«","models":"3Dã¢ãã«","models_3d":"3Dã¢ãã«","models_3dp":"3Dããªã³ãã¢ãã«","models_variant_0":"3Dã¢ãã«","models_variant_1":"3Dã¢ã»ãã","models_variant_2":"VRã¢ãã«","models_variant_3":"CGã¢ãã«","models_variant_4":"3Dã¢ãã«ã¹ãã¢","models_variant_5":"3Dãªãã¸ã§ã¯ã","print_models":"3Dããªã³ããã¡ã¤ã«","print_models_variant_0":"3Dããªã³ãã¢ãã«","print_models_variant_1":"3Dããªã³ã¿ã¼ã¢ãã«","print_models_variant_10":"å°å·ç¨ã®3Dã¢ãã«","print_models_variant_11":"å°å·ããããã®3Dã¢ãã«","print_models_variant_12":"å°å·ç¨3Dãã¡ã¤ã«","print_models_variant_13":"3Dããªã³ã¿ã¼ç¨ã¢ãã«","print_models_variant_14":"3Dããªã³ãç¨ã¢ãã«","print_models_variant_15":"3Dããªã³ãã¢ãã«ãº","print_models_variant_16":"å°å·å¯è½ãª3Dãã¡ã¤ã«","print_models_variant_2":"å°å·ç¨3Dã¢ãã«","print_models_variant_3":"3Då°å·ã¢ãã«","print_models_variant_4":"3Dããªã³ããã¡ã¤ã«","print_models_variant_5":"3Då°å·ç¨ãã¡ã¤ã«","print_models_variant_6":"3Dããªã³ã¿ã¼ãã¡ã¤ã«","print_models_variant_7":"å°å·å¯è½ãª3Dã¢ãã«","print_models_variant_8":"å°å·ç¨ã®3Dã¢ãã«","print_models_variant_9":"3Dããªã³ããããã¢ãã«"},"buyer_engagement_program":"å²å¼","categories":"ã«ãã´ãªã¼","category":{"meta":{"3d_models":"%{count} %{category} FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ã%{page}","3d_print_models":"FDMãSLAãSLSããã³ä»ã®3Dããªã³ã¿ãå©ç¨å¯è½ãªãã©ã¼ãããã®STLãOBJã3DMã®æºåãã§ãã¦ãããã%{page}ãã¦ã³ãã¼ã %{count} %{category}ç¡æã®3Dããªã³ãã¢ãã«","animated_3d_models":"%{count} %{category}ã¯FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ããã¢ãã¡ã¼ã·ã§ã³ã%{page}","free_3d_models":"ãã¦ã³ãã¼ãMAXãOBJãFBXã3DSãC4Dãã¡ã¤ã«ãã©ã¼ããããVR / ARã®ããã®æºåãã§ãã¦ãã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã ããã®ä»ã®3Dããã¸ã§ã¯ãã§å©ç¨ã§ãã %{count} %{category}ç¡æã®3Dã¢ãã«ãã%{page}","free_3d_print_models":"FDMãSLAãSLSããã³ä»ã®3Dããªã³ã¿ãå©ç¨å¯è½ãªãã©ã¼ãããã®ST
16518LãOBJã3DMã®æºåãã§ãã¦ãããã%{page}ãã¦ã³ãã¼ã %{count} %{category}ç¡æã®3Dããªã³ãã¢ãã«","lowpoly_3d_models":"ãã¦ã³ãã¼ã %{count} VR / AR /ä½ããª%{category} 3Dã¢ãã«ãFBXãOBJãMAXã3DSãC4Dãã¡ã¤ã«å½¢å¼ã§å©ç¨å¯è½ãªãã¼ãã£ã«ãªã¢ãªãã£ãã²ã¼ã ãä»ã®ãªã¢ã«ã¿ã¤ã ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¾ããã%{page}","rigged_3d_models":"%{count} %{category}ã¯FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ãè£
åã%{page}"}},"collection":"3Dããã¯","discounts":"å²å¼","ext":{"meta":{"3d_models":"%{format_upper}å½¢å¼ã®3Dã¢ãã«%{rounded_count}ç¹ãç¡æ\u0026ææã®%{format_lower}ãã¼ã¿ããã¦ã³ãã¼ãã","3d_print_models":"ãã¦ã³ãã¼ã%{count}%{ext}ãã¡ã¤ã« - %{software_name}ã®3Dããªã³ãã¢ãã«VR / ARã3Dãã¶ã¤ã³ãã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã ããªã¢ã«ã¿ã¤ã ã®ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦%{page}ã"}},"filter":"ãã£ã«ã¿","filter_button":"ãã£ã«ã¿ãé©ç¨","filters":{"adult_content_only":"ã¢ãã«ãã³ã³ãã³ãã®ã¿","cgt_standard_only":"CGTåºæº","collections_only":"ããã¯ã®ã¿","content_filters":"ã³ã³ãã³ããã£ã«ã¿ã¼","designer":"ãã¶ã¤ãã¼","exclude_3d_print":"3Dããªã³ããé¤å¤","exclude_adult_content":"ã¢ãã«ãã³ã³ãã³ããé¤å¤","exclude_ai_generated":"AIçæã³ã³ãã³ããé¤å¤","exclude_editorial_license":"ç·¨éã©ã¤ã»ã³ã¹ãé¤å¤","exclude_free":"ç¡æãé¤å¤","file_format":"ãã¡ã¤ã«å½¢å¼","following":"ãã©ãã¼ä¸","free":"ç¡æ","has_marmoset":"3Dãã¥ã¼ã¢ã¼ãã","has_video":"åç»ãã","include_ai_generated":"AIçæã³ã³ãã³ããå«ãã","label":"ãã£ã«ã¿","poly_count":"ããªã´ã³æ°","print_ready":"3Dããªã³ã","stl_files":"STLãã¡ã¤ã«","subscription":"ãµãã¹ã¯ãªãã·ã§ã³","type":"ã¿ã¤ã"},"formats":"ãã©ã¼ããã","free":"ç¡æ","free_models":"ç¡æã®ã¢ãã«ã®ã¿ã表示","free_to_premium":{"main":"%{category} 3Dã¢ãã«","postfix":"ããã¬ãã¢ã ãªã¹ãã«ããã¾ãã","prefix":"ç¹å¥ãªãã®ãå¿
è¦ã§ããï¼ããé«å質ãª"},"gallery":{"preview":"ãã¬ãã¥ã¼"},"game_ready":"ã²ã¼ã ç¨","high_poly":"ãã¤ããª","items_page_title":"3Dã¢ãã«","license":{"exclude_branded":"ãã©ã³ããé¤å¤","exclude_editorial":"ã¨ãã£ããªã¢ã«ãé¤å¤","prompt":"ã©ã¤ã»ã³ã¹","tooltip_more":"ç¶ããèªã","tooltip_text":"é忥çãæè²ç®çã§ã®ã¿ä½¿ç¨ã§ããã¢ãã«ã表示ããªãã","tooltip_title":"ã¨ãã£ããªã¢ã«ã®é¤å¤ï¼"},"low-poly":"ãã¼ããª","low_poly":"ãã¼ããª","meta":{"3d_models":"ããå質ã®3Dã¢ãã«%{rounded_count}ç¹ã販売ã»è³¼å
¥ã»ç¡æãã¦ã³ãã¼ããã²ã¼ã ã»æ åã»VFXã»AR/VRã»3Dããªã³ãåããFBXãOBJãBLENDãGLB対å¿ã","3d_print_models":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ããã¦ã³ãã¼ããç¡æ\u0026ææã®STLãã¼ã¿ã»3Dããªã³ãã¢ãã«ï¼ãã£ã®ã¥ã¢ããããã¥ã¢ãå®ç¨åãªã©ã","animated_3d_models":"ã¢ãã¡ã¼ã·ã§ã³ä»ã3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããFBXãBLENDãGLBå½¢å¼ã®ã²ã¼ã 対å¿ãã£ã©ã¯ã¿ã¼ã»ãªãã¸ã§ã¯ãã","free_3d_models":"ç¡æ3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããåç¨å©ç¨å¯ã®ããªã¼3Dç´ æã»3Dãã¼ã¿ãFBXãOBJãBLENDãGLBå½¢å¼ã«å¯¾å¿ã","free_3d_print_models":"ç¡æã®3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ããã£ã®ã¥ã¢ãå®ç¨åã®STLãã¼ã¿ãç¡æãã¦ã³ãã¼ãã","lowpoly_3d_models":"ãã¼ããª3Dã¢ãã«%{rounded_count}ç¹ãã²ã¼ã ã»AR/VRã»ãªã¢ã«ã¿ã¤ã ã¬ã³ããªã³ã°åãã®è»½éã¢ãã«ããã¦ã³ãã¼ãã","metaverse":"ãã¡ã¤ã«å½¢å¼ãè£
åããã¢ãã¡ã¼ã·ã§ã³åããå©ç¨å¯è½ãªé«ããª3Dã¢ãã«ã¨ä½ããª3Dã¢ãã«ã®ã³ã¬ã¯ã·ã§ã³ã§ã¡ã¿ãã¼ã¹ãå
¥åãã¾ãã","omniverse":"Omniverse対å¿ã®3Dã¢ãã«ã§ä»®æ³ä¸çãæ§ç¯ãã¾ããããªã´ã³æ°ãé«ããä½ãã¢ãã¡ããªã°ãPBRã¢ãã«ãã鏿ãã¾ãã","page_prefix":"page %{page_number} with","pbr_3d_models":"PBRãã¯ã¹ãã£ä»ã3Dã¢ãã«%{rounded_count}ç¹ãUnityãUnrealããªã¢ã«ã¿ã¤ã ã¨ã³ã¸ã³åãã","rigged_3d_models":"ãªã°ï¼ãã¼ã³ï¼å
¥ã3Dã¢ãã«%{rounded_count}
16518ç¹ãBlenderãMayaã3ds MaxãUnityãUnreal対å¿ãã¢ãã¡ã¼ã·ã§ã³å¯¾å¿ã","snap-ar":"3Dã¢ãã«ã使ç¨ããã¨ãSnap ARã使ç¨ãã¦ä½ç¾ä¸ãã®Snapchattersã«åå ãã¦ã楽ããæ¡å¼µç¾å®ä½é¨ã使ã§ãã¾ãã","spark-ar":"Facebookã¨Instagramãæãããããã¾ãã¾ãªSpark AR 3Dã¢ãã«ã使ç¨ãã¦ããªã°ããããã¢ãã¡ã¼ã·ã§ã³åãããããã«ä½¿ç¨ã§ãã¾ãã","stream_3d_print_models":"ã¹ããªã¼ã 3Dããªã³ãã¢ãã«ã«ãã´ãªã®ãã¾ãã¾ãªã表示ãã¦ãããã®3Dã¯ãªã¨ã¤ã¿ã¼ããæãç°å¸¸ãª3Då°å·å¯è½ãªè¨è¨ã®ããã¤ããçºè¦ãã¾ãã","textures":".TGA .sbsar .JPEGã®.png .TIFFããã³ä»ãå«ãæ§ã
ãªãã©ã¼ãããã§ãã¦ã³ãã¼ãå¯è½%{count}ãã¯ã¹ãã£3Dã¢ã»ããããã³ææã %{page}","tiktok":"Tiktok 3Dã¢ãã«ã使ç¨ãã¦ããããªã¨ãã§ã¯ããããå°è±¡çã«ãã¾ããç§ãã¡ã®ã©ã¤ãã©ãªã¯ããªãã®åµé çãªãã¼ãºããã¹ã¦æºãããã¨ãã§ããçµ¶ããæ´æ°ããã¦ãã¾ãã","unity":"ä»»æã®ãã¡ã¤ã«å½¢å¼ã¨ããªã«ã¦ã³ãã§Unityããã¸ã§ã¯ãã®3Dã¢ãã«ãè¦ã¤ãã¾ãã䏿ã®ä»®æ³ç°å¢ã使ããããã«å¿
è¦ãªãã¹ã¦ã","unreal":"ä»»æã®ãã¡ã¤ã«å½¢å¼ã§Unreal Engineã«äºææ§ã®ãã3Dã¢ãã«ã使ç¨ãã¦ãå°è±¡çãªè¦è¦åã使ãã¾ããç§ãã¡ã®ã©ã¤ãã©ãªã«ã¯ãããããã«ãã´ãªã®ä½ãã¢ãã«ã¨é«ããªã¢ãã«ãããã¾ãã"},"optimized":"ãã¼ããª/ PBR","page_title":{"animated_3d_models":"ã¢ãã¡ã¼ã·ã§ã³ä»ã3Dã¢ãã« â ç¡æ\u0026ææ","format_page":"%{format_upper} 3Dã¢ãã« â %{format_lower}ãã¼ã¿ ç¡æ\u0026ææ","free_3d_models":"ç¡æ3Dã¢ãã« â ããªã¼ç´ æãã¦ã³ãã¼ãï¼åç¨å©ç¨å¯ï¼","free_3d_print_models":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿ ç¡æ â ããªã¼STLãã¼ã¿","lowpoly_3d_models":"ãã¼ããª3Dã¢ãã« â ç¡æ\u0026ææ","pbr_3d_models":"PBR 3Dã¢ãã« â ç¡æ\u0026ææ","rigged_3d_models":"ãªã°å
¥ã3Dã¢ãã«ï¼Riggedï¼ â ç¡æ\u0026ææ","software_page":"%{software}ç¨3Dã¢ãã« â %{ext_file}ãã¦ã³ãã¼ã","tag":{"3d_merged_premium":"%{tag_cap} 3Dã¢ãã« %{rounded_count}ç¹ â ç¡æ\u0026ææ","3d_merged_premium_print":"%{tag_cap} 3Dããªã³ã¿ã¼ãã¼ã¿ â STL ç¡æ\u0026ææ","3d_models":"%{tag_cap} 3Dã¢ãã« %{rounded_count}ç¹ â ç¡æ\u0026ææ","3d_print_models":"%{tag_cap} 3Dããªã³ã¿ã¼ãã¼ã¿ â STL ç¡æ\u0026ææ"}},"pbr":"PBR","per_page":"1ãã¼ã¸ããã","polygons_options":{"custom":"ã«ã¹ã¿ã ç¯å²","gt_250k":"250K +","lt_5k":"æå¤§5K","more_than_250000":"250K以ä¸","prompt":"ããªæ°","range_0_5000":"æå¤§5K","range_100000_250000":"100ï½250K","range_10000_50000":"10ï½50K","range_100k_250k":"250Kã«100K","range_10k_50k":"50Kã¸ã®10K","range_50000_100000":"50ï½100K","range_5000_10000":"5ï½10K","range_50k_100k":"100Kã«50K","range_5k_10k":"10Kã«5K"},"price":"ä¾¡æ ¼ï¼$%{from}-%{to}","price_range":"ä¾¡æ ¼","print_ready":"3Dããªã³ãç¨","printable":"3Dããªã³ãã¢ãã«","reset_button":"ãã£ã«ã¿ããªã»ãã","rigged":"ãªã°","rounded_count":{"delimiter":",","exact":"%{n}","separator":".","ten_thousand":"%{n}ä¸","thousand":"%{n}"},"sale_off":"ã»ã¼ã«ä¸","search_placeholder":"æ¤ç´¢ãã¼ã¯ã¼ã","show_all_formats":"ãã¹ã¦ã®ãã©ã¼ãããã表示","simulation_ready":"ã·ãã¥ã¬ã¼ã·ã§ã³å¯¾å¿","software":{"meta":{"3d_models":"%{software}ç¨ã®3Dã¢ãã«%{rounded_count}ç¹ãç¡æ\u0026ææã®%{ext_file}ãã¡ã¤ã«ããã®ã¾ã¾ã¤ã³ãã¼ãå¯è½ã"}},"sort_by":"ä¸¦ã³æ¿ã","sort_by_options":{"best_match":"ãã¹ãããã","highest_price":"ä¾¡æ ¼ãé«ãé ","lowest_price":"ä¾¡æ ¼ãä½ãé ","newest":"ææ°","oldest":"å¤ãé ","sales":"人æ°åå","trending":"ãã¬ã³ã"},"subcategory":{"meta":{"3d_models":"%{count} %{category} FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ã%{page}","3d_print_models":"FDMãSLAãSLSããã³ä»ã®3Dããªã³ã¿ãå©ç¨å¯è½ãªãã©ã¼ãããã®ST
16518LãOBJã3DMã®æºåãã§ãã¦ãããã%{page}ãã¦ã³ãã¼ã %{count} %{category}ç¡æã®3Dããªã³ãã¢ãã«","animated_3d_models":"%{count} %{category}ã¯FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ããã¢ãã¡ã¼ã·ã§ã³ã%{page}","free_3d_models":"ãã¦ã³ãã¼ãMAXãOBJãFBXã3DSãC4Dãã¡ã¤ã«ãã©ã¼ããããVR / ARã®ããã®æºåãã§ãã¦ãã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã ããã®ä»ã®3Dããã¸ã§ã¯ãã§å©ç¨ã§ãã %{count} %{category}ç¡æã®3Dã¢ãã«ãã%{page}","free_3d_print_models":"FDMãSLAãSLSããã³ä»ã®3Dããªã³ã¿ãå©ç¨å¯è½ãªãã©ã¼ãããã®STLãOBJã3DMã®æºåãã§ãã¦ãããã%{page}ãã¦ã³ãã¼ã %{count} %{category}ç¡æã®3Dããªã³ãã¢ãã«","lowpoly_3d_models":"VR / AR /ãã¼ã¯ããª%{tag} 3Dã¢ãã«ã¯ãã¼ãã£ã«ãªã¢ãªãã£ãã²ã¼ã ãä»ã®ãªã¢ã«ã¿ã¤ã ã¢ããªã±ã¼ã·ã§ã³ãFBXã§å©ç¨å¯è½ãªãOBJãMAXã3DSãC4Dãã¡ã¤ã«ãã©ã¼ãããã®æºåãã§ãã¦ãã¦ã³ãã¼ããã¦ãã ããã%{page}","rigged_3d_models":"%{count} %{category}ã¯FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ãè£
åã%{page}"}},"subtitle":{"aircraft":"%{count}èªç©ºæ©ã®3Dã¢ãã«ã¯,å½ç¤¾ã®å¸å ´ãããã¦ã³ãã¼ãã§ãã¾ãã CGã®%{airplanes_link}ã¯ã·ãã¥ã¬ã¼ã·ã§ã³,è¦è¦å,åºåããã³ãããªã«åã¾ãã¾ãã %{drone_link}ä½åã³é¨åã¯,å°åé£è¡è»ä¸¡ã®ãã¡ã³ãåã°ãã¾ããããã¦%{rigged_link}ã¢ãã«ã¯,ã²ã¼ã ã¨ã³ã¸ã³ã«ã¤ã³ãã¼ãããæºåãã§ãã¦ããã¨ã¢ãã¡ã¼ã·ã§ã³ãVR / ARããã¸ã§ã¯ãã®ããã«ä½¿ç¨ãããã¨ãã§ãã¾ãããã©ã¤ã³ã°ã²ã¼ã ,ã·ãã¥ã¬ã¼ã¿ã宿çãªCGã¨ä½ããªã¿ã¤ãã®ä¸¡æ¹ã®ãããªã¯FBX,OBJ,MAX,3DS,C4Dãå«ãæã人æ°ã®ãããã©ã¼ãããã§3Dã¢ãã«ãå
å¡«ãããã¨ãã§ãã¾ãã","animals":"CG 3Dåç©ã®%{count} - %{cats_link},%{horses_link},%{bears_link},%{rhinos_link},%{eagles_link},%{lions_link},æ¶ç©º%{dragons_link}ãã - ããã§å©ç¨å¯è½ã§ããã¦ã³ãã¼ããã¾ãã 3Dã®åç©ã®ã³ã¬ã¯ã·ã§ã³ã¯,åºåã¾ãã¯éçãªã·ã¼ã³ã®ãã¼ãºãæºè¶³ããã¾ããæã
ã¯ã¾ã,ã²ã¼ã ,ã¢ãã¡ã¼ã·ã§ã³,æ åå¶ä½ããã³VR / ARããã¸ã§ã¯ãã«å¯¾ãã%{rigged_link}ã¢ãã«ãæã£ã¦ãã¾ãããã£ã«ã¿ã使ç¨ãã¦,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªã¾ãã¯FBX,OBJ,MAX,3DS,C4D,ãã®ä»ãå«ãã»ã¨ãã©ã®æ¥çã§èªãããããã¡ã¤ã«å½¢å¼ã§å©ç¨ã§ããç¡æã®3Dã¢ãã«ãè£
åè¦ã¤ãããã¨ã","animated":"ã¢ãã¡ã¼ã·ã§ã³ä»ã3Dã¢ãã«%{rounded_count}ç¹ãæ©è¡ãµã¤ã¯ã«ãã¢ã¯ã·ã§ã³ãªã©ããã使ããã¢ã¼ã·ã§ã³å
¥ãã®ãã£ã©ã¯ã¿ã¼ã»åç©ã»ãªãã¸ã§ã¯ãã","architectural":"ãã¦ã³ãã¼ãå¯è½ãªå»ºç¯3Dã¢ãã«ã®%{count}ã¯è¦ç´ ã建ç¯,建è¨,ã¨ã³ã¸ãã¢ãªã³ã°è¨è¨ã®è©³ç´°ãå«ã¾ãã¦ãã¾ããç¡æã®3Dã¢ãã«ãè³¼å
¥ããã,ãã¦ã³ãã¼ãããã«ã¯,ä¸è¨ã®ã«ãã´ãªãåç
§ãã¾ãã VR / ARããã¸ã§ã¯ãã®ãã¼ãºã«å¿ããããã«ãããã®ããã¤ãã¯,䏿£ãã¦ãã,ä½ã㪠- ããªãã¯ã¢ãã¡ãã²ã¼ã ã®ããã®ã¢ãã«ã使ç¨ãããã¨ãã§ãã¾ãã 3Dã¢ãã«ã¯,FBX,OBJ,MAX,3DS,C4Dãªã©ã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨å¯è½ã§ãã","car":"%{count}ã®è»ã®3Dã¢ãã«ããã¦ã³ãã¼ããããã¨ãã§ãã¾ããæ ç»è£½ä½è
,ã¢ãã¡ã¼ã¿ã¼ãåºå主㫠- ã®ä½ããªã®ãã¼ã¸ã§ã³ã§ã¯,ã²ã¼ã ãã¶ã¤ãã¼ãVR / ARã¢ããªã±ã¼ã·ã§ã³ã®éçºè
,ä»ã®äººã«é
åçã«ãªãã¾ããæ ç»ã§è¦ãã¬ã¼ã¹ãæ¦å¿µã®ãã®ã«ã¯ã©ã·ãã¯ã¨ã¢ã³ãã£ã¼ã¯ã«ã¼ããã¯,åºæ¬çã«ä»»æã®å½¢å¼(FBX,OBJ,MAX,3DS,C4D,ãªã©)ããªããå¿
è¦ãªå ´åãããã¾ãå
ã®3Dèªåã¢ãã«ã®å¤ç¨®å¤æ§ãããã¾ãããããã¿ã¤ãã¨çã,éçºæéãã¢ãã¡ã¼ã·ã§ã³ã§ç¡æã®3Dã¢ãã«ã使ç¨ãã¦ãã ããã","character":"ããªãã¯%ã®3Dã¢ãã«%{human_link},人ã
,ç¥è©±ä¸ã®äººç©,ãµã¤ãã¡ã¤%{robots_link},è¡£é¡ãæåã«é¢é£ããä»ã®ãã®ãè¦ã¤ããã§ããã,ãã®ã«ãã´ãªãé²è¦§ãã¦%{count}ãã£ã©ã¯ã¿ã¼ã®3Dã¢ãã«ã¯,ãã¦ã³ãã¼ããããã¨ãã§ãã¾ãã%{heart_link}ã¨%{hand_link}ãã詳細ãªç¾å®çãª%{male_link}åã¯%{female_link}ã¢ãã«ã«ãã¢ãã«ã®æ°ã䏿£ãã¦ãã,ç°¡åã«ã²ã¼ã ,VR / ARããã¸ã§ã¯ã,ãããªãã¢ãã¡ã¼ã·ã§ã³ã«è¿½å ãããã¨ãã§ãã¾ãã両æ¹ã®é«ãããªãã¤ä½ããªã¢ãã«ã¯FBX,OBJ,MAX,3DS,C4Dãå«ããã©ã¼ãããã®æ°ã«è¦åºããã¨ãã§ãã¾ãã","custom"
16518:"ããã§ã¯,ç¡æ%{tag} 3Dã¢ãã«ãè³¼å
¥ããã,ãã¦ã³ãã¼ããããã¨ãã§ãã¾ãã %{tag_heading_subtitle}","electronics":"ãã¦ã³ãã¼ãå¯è½ãª%{count}ã¨ã¬ã¯ãããã¯ã¹3Dã¢ãã«ãããã¯,建ç¯å®¶,ã¤ã³ããªã¢ãã³ã¬ã¼ã¿ã¼,ã¬ãã«ãã¶ã¤ãã¼,ã·ã¼ã³ã®ã¡ã¼ã«ã¼ãä»ã®ã¯ãªã¨ã¤ãã£ãã®ããã®ã«ãã´ãªã§ãã ã®3Dã¢ãã«%{smartphones_link},%{laptops_link},%{cameras_link},%{tvs_link},ããæ£ç¢ºããã¤ã¹ãæè¡ã¨ç¾ä»£ã®çæ´»ã®å¼·è¿«è¦³å¿µããã£ããã£ããã®ã«å½¹ç«ã¡ã¾ãã FBX,OBJ,MAX,3DS,C4Dãå«ããã¡ã¤ã«å½¢å¼ã§å©ç¨å¯è½ãª3Dã¢ãã«ãããã¾ããç¡æãã¦ã³ãã¼ããã¢ãã¡ã¼ã·ã§ã³,ã²ã¼ã ,VR / ARããã¸ã§ã¯ãã®ããã®ãã¬ãã¢ã ã¢ãã«ã¨ä½¿ç¨ãè²·ãã¾ãã","exterior":"ãã¡ãµã¼ã,é½å¸ã®å»ºç©,風æ¯,ãªãã¸ã§ã¯ã,ä½å®
ããã®ç£æ¥æ§é ,ã¤ã³ãã©ã®å»ºç©ã¨ãã«ã¹ã±ã¼ã«ã®%{city_link}ã¢ãã«ã¸ã®ãã¦ã³ãã¼ãã®ç¯å²ã§ä½¿ç¨å¯è½ãªå»ºç¯å¤è£
3Dã¢ãã«ã®%{count}ãç¡æã®3Dã¢ãã«ãè³¼å
¥ããã,ãã¦ã³ãã¼ãããã«ã¯,ä¸è¨ã®ã«ãã´ãªãåç
§ãã¾ããå©ç¨ã¯ç¡æ,ä½ããª,ã¢ãã¡ã¼ã·ã§ã³,3Dã¢ãã«ã䏿£ã«æä½ã¾ãã¯ã½ã¼ãå½¢å¼ã§FBX,OBJ,MAX,3DS,C4Dãå«ã,å¿
è¦ãªè¦ã¤ãããã¨ã¯ãã£ã«ã¿ãªã³ã°ãã¾ããè³ç£ã®ä¸é¨ã¯,ä½ããªã§ãã,ããªããããªãã®ã²ã¼ã ãVR / ARã¢ããªã±ã¼ã·ã§ã³ç°å¢ã宿ã«å½¹ç«ã¤å¯è½æ§ãããã¾ãã","food":"é£ç©ã¯,å½å
ã®äººçã®ãªã¢ã«ãªã·ã¼ã³ã使ããããã«ãæ©è½ããããã«%{count}é£åã®3Dã¢ãã«ãç¨æããã¦ãã¾ãã 3Dæç©,éè,飲æãé£äºã¯å»ºç¯å®¶ãã¤ã³ããªã¢ãã¶ã¤ãã¼ã¯ã«åãçµãã§ããå®å
¨ãªã¬ã¹ãã©ã³ã®åºå,å¥åº·çãªé£äºã®ããã®ARã¢ããªã±ã¼ã·ã§ã³,ããã³è¦è¦åã«ãã¹ã¦ããã«ããã¾ããããªãã¯,3D %{pizza_link}ã¨%{ketchup_link}ã¢ãã«ãçµå©å¼%{cake_link}ã®3Dã¢ãã«ãæ¢ãã¦ãããã©ãã,å½¼ãã¯ããã«ããã¾ããä½ããªãã¼ã¸ã§ã³ã®%{count}ã¯,ã²ã¼ã ,VR / ARéçºä¸ã®ãã®ã®ããã«ç¨æããã¦ãã¾ãã 3Dã¢ãã«ã¯,FBX,OBJ,MAX,3DS,C4Dãã©ã¼ãããã«è¦åºããã¨ãã§ãã¾ãã","formats":"%{format_upper}å½¢å¼ã®3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ãããã®ãã¼ã¸ã®ãã¡ã¤ã«ã¯ãã¹ã¦ãã¤ãã£ã%{format_upper}ã§ã夿ãªãã§å©ç¨ã§ãã¾ãã","free_general":"ç¡æ3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããããªã¼3Dç´ æã»3Dãã¼ã¿ã¨ãã¦å人å©ç¨ãåç¨å©ç¨ãå¯è½ãªã¢ãã«ã夿°æ²è¼ãFBXãOBJãBLENDãGLB対å¿ã","free_no_tag":"%{model_count}ããªã¼ã®3D %{tag}ã¢ãã«ã¯,3Då°å·ã®æºåãã¾ãããã¦ã³ãã¼ã%{tag}èªç±ãª3Dããªã³ãã¢ãã«,STL,OBJ,3DM,3DS,MAXãå«ãå©ç¨å¯è½ãªãã¡ã¤ã«å½¢å¼ã 3Dã¢ãã«ã¯,FDM,SLA,SLSåã³3Dããªã³ã¿ã®ä»ã®ã¿ã¤ãã¨ä¸ç·ã«ä½¿ç¨ãããæºåãã§ãã¦ãã¾ãã","free_printable":"ç¡æã®3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ããã¦ã³ãã¼ããã³ãã¥ããã£æ¤è¨¼æ¸ã¿ã®ããªã¼STLãã¼ã¿ â ãã£ã®ã¥ã¢ããããã¥ã¢ãå®ç¨åãã¤ã³ããªã¢é貨ãªã©ã","free_tag":"ãã¦ã³ãã¼ãå¯è½ãªç¡æã®3D%{tag}ã¢ãã«ã MAX,OBJ,FBX,3DS,STL,C4D,BLEND,MA,MBãå«ãå¤ãã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨ã§ãã¾ãããã¼ãã£ã«ãªã¢ãªãã£(VR),æ¡å¼µç¾å®(AR),ã²ã¼ã ,3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ãã¢ãã¡ã¼ã·ã§ã³ãªã©ã®ä»»æã®3次å
è¨è¨ããã¸ã§ã¯ãã®ããã®å°éã®%{tag_link}ãè¦ã¤ãã¾ãã","furniture":"%{count}ãã¦ã³ãã¼ãå¯è½å®¶å
·3Dã¢ãã«ã¯,ãã¯ã¹ãã£ã®æ§ã
ãªãã¼ãã«,æ¤
å,ã½ãã¡ã¼,ããã,ä»ã®å®¶å
·ãå«ãç(æ¨æ,éå±,ç)ãã¹ã¿ã¤ã«(%{retro_link},%{modern_link} )ããã®ã«ãã´ãªã¯,建ç¯ã¨ã¤ã³ããªã¢ãã¶ã¤ã³ã ãã§ãªã,åºå主ãã¢ãã¡ã¼ã¿ã¼ã«é¢ä¸ã,誰ã®ããã®ãã®ã§ãããªã¢ã«ã¿ã¤ã ã®è³ç£ã¯å®å
¨ãªããã¸ã§ã¯ãã«ã²ã¼ã ãVR / ARã¢ããªã±ã¼ã·ã§ã³éçºè
ãæ¯æ´ãããã¨ãã§ãã¾ãã使ç¨ã¯ä¸æ£,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªã¾ãã¯ç¡æã®3Dã¢ãã«ãè¦ã¤ããããã«ãã£ã«ã¿ãªã³ã°ãã¾ãã FBX,OBJ,MAX,3DS,C4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨ã§ãã¾ãã","general":"ã²ã¼ã ã»æ åã»VFXã»AR/VRã»3Dããªã³ãåãã®ããå質3Dã¢ãã«%{rounded_count}ç¹ãç¡æãã¦ã³ãã¼ãã¾ãã¯è³¼å
¥ã§ããFBXãOBJãBLENDãGLBã»ã100以ä¸ã®å½¢å¼ã«å¯¾å¿ãã¦ãã¾ãã","high_poly":"è³¼å
¥ã¾ãã¯ãã¦ã³ãã¼ãã¢ãã¡ã¼ã·ã§ã³ãããã§ãã·ã§ãã«3Dã¢ãã«ã¯,CGã®ããã¸ã§ã¯ãã§ä½¿ç¨ããããã«,ãã£ã«ã ããããªå¶ä½,ã¢ãã¡ã¼ã·ã§ã³,è¦è¦å,ããã³ãã®ä»ã®æºåãã§ãã¾ãããè³ç£ã¯MAX,OBJ,FBX,3DS,UE4ããã³ãã®ä»ãå«ãå¤ãã®æ¥çã§èªãããããã©ã¼ãããã§ãã¦ã³ãã¼ãã§ãã¾ããããªãã¯,é«å質ã®ããª3Dè³ç£ã®æ¤ç´¢ã«ãã¦ããå ´åã¯,æã
ã¯ãã¹ã¦ã®ãã¼ãºã®ããã®ä¸»è¦ãªãã¸ã¿ã«ã¢ã¼ãã©ã¤ãã©ãªã¼ãæã£ã¦ãã¾ãã\n","household":"ãã¦ã³ãã¼ãå¯è½ãª%{count}å®¶åºã®3Dã¢ãã«ãé¨å±ã«è©³ç´°ãä¸ããããã«ä½¿ç¨ãããã¨ãã§ãã¾ããããªãã¯,ãã¼ãã«ã®ä¸ã«ãã£ãã¼ã»ãããå
¥ãã¦,å®å
¨ãªãããã³ã®ã¤ã³ããªã¢ã«åè¾åã¨å¡©ã®å®¹å¨ãæã£ã¦ããã,é«ç´æã使ããããã«,ãããã®è¿ãã«ããã¤ãã®%{lights_link}ã¨%{flowers_link}ãç½®ãããããããã¾ãããããªããã¤ã³ããªã¢ãã¶ã¤ãã¼,ã¢ãã¡ã¼ã¿ã¼,VR / ARã¢ããªã±ã¼ã·ã§ã³ãã²ã¼ã ã¯ãªã¨ã¤ã¿ã¼ã§ããã°,ãã®ã«ãã´ãªã¯ããªãã®ããã§ãã使ç¨ã¯ä¸æ£,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªã¾ãã¯ç¡æã®3Dã¢ãã«ãè¦ã¤ããããã«ãã£ã«ã¿ãªã³ã°ãã¾ãã FBX,OBJ,MAX,3DS,C4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨ã§ãã¾ãã","industrial":"建è¨è³æ,%{engineering_link}ãã¼ã«,æ©æ¢°,%{containers_link} - - ãã¦ã³ãã¼ãå¯è½ãª%{count}å·¥æ¥ç¨3Dã¢ãã«ã®ä¸¡æ¹ã®è©³ç´°ãæä¾ã,ã¤ã³ã¿ã©ã¯ãã£ãã¯,æ´»æ°ã®ããç°å¢ã使ããããã®è¦ç´ ãè£
åãã¾ãããããã¯,ã²ã¼ã ä¸%{construction_link}ãµã¤ãã¬ãã«ãæ§ç¯ã,ã·ãã¥ã¬ã¼ã·ã§ã³/ VR / ARãéçºè
ã®ããã®å®ç§ãªã«ãã´ãªã§ãã 3Dã¢ãã«ã¯,FBX,OBJ,MAX,3DS,C4Dãªã©ã®å½¢å¼ã§ã®ã¢ãã«ãç¨æããã¦ãã¦æ§ã
ãªã½ããã¦ã§ã¢ã§ã®ä½æ¥ã®æ£ç¢ºãªãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ãæ§ç¯ããå°éå®¶ãæ
16518ä¾ãã¾ãã","interior":"%{count}å
é¨3Dã¢ãã«ã¯,ãã¦ã³ãã¼ãã®ããã«å©ç¨å¯è½ã§ãã,建ç¯,建è¨,ã¨ã³ã¸ãã¢ãªã³ã°,ã¤ã³ããªã¢ãã¶ã¤ã³ã§ä½¿ç¨ãããè¦ç´ ã¨è©³ç´°ãå«ã¿ã¾ãããã¬ãã¢ã ãè³¼å
¥ããã,ç¡æã®3Dã¢ãã«ããã¦ã³ãã¼ãããã«ã¯,ä¸è¨ã®ã«ãã´ãªãåç
§ãã¾ããããªãã¯,ã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã ã®ããã®ã¢ãã«ã使ç¨ãããã¨ãã§ãã¾ã - ãã®ãã¡ã®ããã¤ãã¯,ã¢ãã¡ã¼ã·ã§ã³ãä½ããª,è£
åããã¦ãã¾ãã FBX,OBJ,MAX,3DS,C4Dãå«ããã¡ã¤ã«å½¢å¼ã®ãã¾ãã¾ãªå©ç¨ã§ãã¾ãã","low_poly":"ãã¼ããª3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããã²ã¼ã ã»AR/VRã»ã¢ãã¤ã«åãã®è»½éã§ã²ã¼ã ã¬ãã£ãªã¢ã»ããã","military":"%{count}è»äºåã¨èªå·±é²è¡ã使ç¨ããæ¦å¨,æ¦å¨,%{swords_link}ã¨ç¾ä»£ã¨æ´å²ã®ä¸¡æ¹å¤§ç ²ã®è»äº3Dã¢ãã«ããã¦ã³ãã¼ããããã¨ãã§ãã¾ããããªãã¯ã²ã¼ã ãVR / ARã³ã³ãã³ãã®ããã®ã¢ãã«ã使ç¨ãããã¨ãã§ãã¾ã - ãã®ãã¡ã®ããã¤ãã®ããªã´ã³ãæé©åãã,ã²ã¼ã ã¨ã³ã¸ã³ã«è¿½å ããæºåãã§ãã¦ãã¾ãã䏿£ãã¢ãã¡ã®ã¢ãã«ã¯,ããã«ããªãã®ä»äºã容æã«ãããã¨ãã§ãã¾ããããªãã¯(FBX,OBJ,MAX,3DS,C4D,ãªã©)ãå¿
è¦ã«ãªãå ´åãããã¾ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨ã§ããå¤ãã®3Dã¢ãã«ãããã¨ãã¦,ããªãã¯ãã£ã¨,é¢é£ããè³ç£ãæ¤ç´¢ãã¾ãã","not_custom":"%{tag_cap}ã®3Dã¢ãã«%{rounded_count}ç¹ããªã¢ã«ç³»ããããã©ã«ã¡ã¾ã§ãç¡æ\u0026ææã®ã¢ãã«ãFBXãOBJãBLENDãGLBå½¢å¼ã§ãã¦ã³ãã¼ãã§ãã¾ãã","optimized":"å°ãªãããªã´ã³ãæã¤ã¢ãã«ã¯,æé«ã®é«éå¦ç,ãã¼ãã£ã«ãªã¢ãªãã£(VR)ã®ããã«,æ¡å¼µç¾å®(AR),è¤åç¾å®æ(MR),ã¯ãã¹ç¾å®(XR)ã¨ã²ã¼ã ãå¿
è¦ã¨ãããªã¢ã«ã¿ã¤ã ã¢ããªã±ã¼ã·ã§ã³,ç¹ã«ã¢ãã¤ã«ã²ã¼ã ã§ä½¿ç¨ããã¦ãã¾ããç°¡åã«ãªã¢ã«ã¿ã¤ã ã¢ããªã±ã¼ã·ã§ã³ã§ãããã使ç¨ããè£
åãã¢ãã¡ã®ã¢ãã«ã®ç§éã®ã³ã¬ã¯ã·ã§ã³ãã鏿ãã¦ãã ããã ,ç°å¢ã®ããã®3Dè³ç£ãåå¾å°éå
·ãé¸ã¶,ãªãã¸ã§ã¯ãã¾ãã¯ããªãã®ã²ã¼ã ãå¿
è¦ã«ãªãå ´åãããã¾ããã¹ã¦ãå®å
¨ãª3Dã¢ãã«ã³ã¬ã¯ã·ã§ã³,ãã³ãã«ã¨ã®ããã¯ãè³¼å
¥ãä¿åã®éçºæéã¨ã³ã¹ã,ã¡ã¤ã¯ãããã¿ã¤ãã®çµé¨ãããã¸ã§ã¯ãå
ã®ãã¬ã¼ã¹ãã«ãã¨ãã¦3Dã¢ãã«ã使ç¨ãã¦ãã¾ããç©çãã¼ã¹ã®ã¬ã³ããªã³ã°,ã¾ãã¯PBRèµ·å ãã¯ã¹ãã£ã«ä»»æã®ç
§ææ¡ä»¶ã§æ£ç¢ºã«ãã¤ä¸è²«ãã¦ã¬ã³ããªã³ã°ãããã¢ãã«ã¯,使ããã»ã¹ã§ä½¿ç¨ãããã¯ã¼ã¯ããã¼ã§ãã\n","pbr":"PBRï¼ç©çãã¼ã¹ã¬ã³ããªã³ã°ï¼ãã¯ã¹ãã£ä»ã3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããUnityãUnrealãªã©ã§ããããã©ã¤ãã£ã³ã°ã«ä¸è²«ãããªã¢ã«ãªè³ªæã","plant":"ãã¦ã³ãã¼ãå¯è½ãª%{count}æ¤ç©ã®3Dã¢ãã«ã¯,ãã®ãããªè±,%{trees_link},è,ã¤ã,ç·,ãã¼ã,å¤å¹´çæ¤ç©,è,è½,使¨,ã¹ãªãããªã©å½å
å·¥å ´ã¨ãã¦,ããã¦èªç¶ã®ä¸ã§è²ã¤æ¤ç©ã®çç©ã,å«ã¾ãã¦ãã¾ãããã,ã¤ã,éèããã¬ãã¢ã ãè³¼å
¥ããã,ç¡æã®3Dã¢ãã«ããã¦ã³ãã¼ãããã«ã¯,å©ç¨å¯è½ãªã¢ãã«ã®ä¸ã§æé«ã®ãã£ãããè¦ã¤ããããã«,ä¸è¨ã®ã«ãã´ãªãåç
§ãã¾ãã使ç¨ãã£ã«ã¿ãã¢ãã«(ã²ã¼ã ãVR / ARã¢ããªã±ã¼ã·ã§ã³ã§ä½¿ç¨ããããã«),ã¢ãã¡å,ä½ããªä¸æ£è¦ã¤ãããã¨,ã¾ãã¯å¿
è¦ãªå½¢å¼ãé¤å¤ãã(FBX,OBJ,MAX,3DS,C4Dã§ã®ã¢ãã«ã¨ã¯,ããå©ç¨å¯è½ã§ã)ã","printable":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ããã¦ã³ãã¼ããFDMã»å
é å½¢ããªã³ã¿ã¼ã§ãã¹ãæ¸ã¿ã®STLãã¼ã¿ã»STLãã¡ã¤ã«ãç¡æ\u0026ææã§æä¾ããã£ã®ã¥ã¢ããããã¥ã¢ãå®ç¨åããã¼ããªã©ã","printable_merged_tag":"%{tag_cap}ã®3Dããªã³ãç¨ãã¼ã¿%{rounded_count}ç¹ããã¦ã³ãã¼ããç¡æ\u0026ææã®STLãã¼ã¿ã§ãFDMã»å
é å½¢ã©ã¡ãã«ã対å¿ã","printable_tag":"%{tag_cap}ã®3Dããªã³ãç¨ãã¼ã¿%{rounded_count}ç¹ããã¦ã³ãã¼ããç¡æ\u0026ææã®STLãã¼ã¿ã§ãFDMã»å
é å½¢ã©ã¡ãã«ã対å¿ã","rigged":"ãªã°ï¼ãã¼ã³ï¼å
¥ã3Dã¢ãã«%{rounded_count}
16518ç¹ããã¦ã³ãã¼ããããã«ã¢ãã¡ã¼ã·ã§ã³ã§ãããã£ã©ã¯ã¿ã¼ãåç©ãã¯ãªã¼ãã£ã¼ãBlenderãMayaã3ds MaxãUnityãUnreal対å¿ã","scanned":"%{count}ã¯3Dã¢ãã«ãè³¼å
¥ã¾ãã¯ç¡æã§ãã¦ã³ãã¼ãã§ãã¾ãã¹ãã£ã³ãã¾ããã 3Dã¹ãã£ã³ã¢ãã«ã¯,ã¢ãã¡ã¼ã·ã§ã³,ã²ã¼ã ,VR / ARããã¸ã§ã¯ãã®æºåãã§ãã¦ãã¾ããããªãã¯,ãã®ãããªå²©ãèªç¶ã®è¡¨é¢,ããããã³ä»ã®ç¾å®ã®çæ´»ãããã«ãªãã¸ã§ã¯ãã¨ãã¦èªç¶çã«è¦ãããç©ä½ã®3Dã¢ãã«ãè¦ã¤ãããã¨ãã§ãã¾ã...ããã¦,ããã¯ãããããããç¾å®çãªåå¾ãããã¨ã¯ã§ãã¾ããã使ç¨ã¯ä¸æ£,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªã¾ãã¯ç¡æã®3Dã¢ãã«ãè¦ã¤ããããã«ãã£ã«ã¿ãªã³ã°ãã¾ãã FBX,OBJ,MAX,3DS,C4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨ã§ãã¾ãã","science":"å®é¨è£
ç½®,é¡å¾®é¡æ¬ä½ã¨ç´ ç²åã®ä¸çï¼å»å¦,çç©å¦,ç©çå¦,åå¦ã®åéãä»ã®ç¾å®ã®ä¸çãããã®ã«ãã´ãªã¼ã®ç¯å²å
ã§,ãã¦ã³ãã¼ãç¨ã®3Dã¢ãã«ãå©ç¨ã§ãã%{count}ç§å¦ã¯,ç§å¦æè¡ã«é¢é£ãããªãã¸ã§ã¯ãããã以ä¸,%{cell_link},%{skull_link}ã¨%{skeleton_link} 3Dã¢ãã«ããã§è¦ã¤ãããã¨ãã§ãã¾ããè¦ã¦ãã¾ããï¼ç¡æã®3Dè³ç£ãè³¼å
¥ããã,ãã¦ã³ãã¼ãããã«ã¯,ä¸è¨ã®ã«ãã´ãªãåç
§ãã¾ããããªãã¯ã²ã¼ã ãVR / ARããã¸ã§ã¯ãã®ããã«ã¢ãã¡ã¼ã·ã§ã³ãä½ããªãã®ã®ããã«ä¸æ£ãªã¢ãã«ã使ç¨ãããã¨ãã§ãã¾ããã©ã¡ããç¡æã¨ãã¬ãã¢ã 3Dã¢ãã«ã¯FBX,OBJ,MAX,3DS,C4Dãå«ããã¡ã¤ã«ãã©ã¼ãããã®countã§è¦ã¤ãããã¨ãã§ãã¾ãã","scripts_plugins":"%{count} 3Dã¹ã¯ãªãã/ãã©ã°ã¤ã³ããã¦ã³ãã¼ããããã¨ãã§ãã¾ãã 3Dã¹ã¯ãªãã/ãã©ã°ã¤ã³ã¯ããã¾ãã¾ãªã½ããã¦ã§ã¢ã«è¿½å ãããããå¹ççã«ããªãã®ä»äºã®ãã¤ãã©ã¤ã³ãä½ãããã«ä½¿ç¨ãããã¨ãã§ãã¾ããã好ã¿ã®ã½ããã¦ã§ã¢ããã£ããã£ã³ã°ãã¼ã«ãè¦ã¤ããããã®å½¢å¼ã«ãããã£ã«ã¿ã\n","software_page":"%{software}ç¨3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ãããã¤ãã£ã%{ext_file}ãã¡ã¤ã«ã¯ãã®ã¾ã¾éããä»å½¢å¼ãæ°ã¯ãªãã¯ã§ã¤ã³ãã¼ãã§ãã¾ãã","space":"%{count}ã¹ãã¼ã¹3Dã¢ãã«ã¯CGTraderãããã¦ã³ãã¼ãã§ãã¾ããã¹ãã¼ã¹ã¯,ä½ããª,ãµã¤ãã¡ã¤%{spaceships_link}ã®ã²ã¼ã 対å¿ã¢ãã«ã®å®å
¨ãªã«ãã´ãªã§ãã %{asteroids_link},ææ(æããã³ç«æãªã©,ã·ãã¥ã¬ã¼ã·ã§ã³ã³ããã¼å½¢æ)ã¨ç¾å®çãªç©ºé%{shuttles_link}ã¯,ããç§å¦çã«å¾æã®ããã«ãåå¨ãã¾ããã¢ãã«ã¯ééããªãææ% %{earth_link}å¤ã®ä¸çã証æããããã«VRã¹ãã¼ã¹ã·ãã¥ã¬ã¼ã¿ã¼ã²ã¼ã ,ARã¢ããªã±ã¼ã·ã§ã³ãã¢ãã¡ã¼ã·ã§ã³ã§ä½¿ç¨ãããã¨ãã§ãã¾ãããã£ã«ã¿ã使ç¨ããã¨,FBX,OBJ,MAX,3DS,C4Dãå«ãç¹å®ã®ãã©ã¼ãããã§ä¸æ£,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªè³ç£ãã¢ãã«ãè¦ã¤ããã®ãå©ããããã«ããã«ãã¾ãã","sports":"%{count}ã¹ãã¼ã3Dã¢ãã«å©ç¨ã§ãããã¹ãä¸ç·ã«ã¬ã¯ãªã¨ã¼ã·ã§ã³æ´»å,娯楽,éå,ã¬ã¸ã£ã¼,楽ããæ°æ´ããã®ããã«ä½¿ç¨ããã¦ããæ©å¨,楽ããã ãã§ãªã,ã²ã¼ã ,åä¾ã®ããã¡ããæ¥½å¨ã®ãã«ã¬ã³ã¸ã FBX,OBJ,MAX,3DS,C4Dãå«ãå¿
è¦ãªä»»æã®ãã¡ã¤ã«å½¢å¼ã§ç¡æã®3Dã¢ãã«ã,è³¼å
¥ããã,ãã¦ã³ãã¼ãããã«ã¯,ä¸è¨ã®ã«ãã´ãªãåç
§ãã¾ããããªãã¯,ã¢ãã¡ã¼ã·ã§ã³,ã²ã¼ã ,VR / ARããã¸ã§ã¯ãã®ããã®ã¢ãã«ã使ç¨ãããã¨ãã§ãã¾ã - ãããã®å¤ãã¯,è£
åä½ããªã¾ãã¯æ¢ã«ã¢ãã¡ã¼ã·ã§ã³åããã¦ãã¾ãã","test":{"airplane":"èªç©ºæå¥½å®¶,ã¢ããèãã¦,ããã¯å®ç§ãª3Dã¯,ããªãã®ãã¼ãã²ã¼ã ãã¢ãã«ã®åéã®ããã«é£è¡æ©ã¢ãã«ãå°å·åå¾ããã®ã§,ç°¡åã§ã¯ããã¾ããã§ããã %{model_count} 3Då°å·å¯è½ãªé£è¡æ©ã®ã¢ãã«ãæ¤ç´¢ã,ããªãã ãã§ã¯æ£ã®ä¸ã«æã£ã¦ããå¿
è¦ãããã¾ãã¢ãã«ãè¦ã¤ãã¾ããåºä¼ãæ¬ç©ã®é£è¡æ©ã¢ãã«ã¾ãã¯ä½ãã¢ããã®ãã®ãææ°ã®ãã¶ã¤ã³ãæ°ã¯ã©ã¤ãå
å¼ã®æããæ»ã£ã¦ãããã¨ãä½ããæ¤ç´¢ãã¾ããããã¯ã¾ã,å½¼ãè²ã¤ã¨ã,ãã¤ãããã§ãããã¨ã夢è¦ããã¹ã¦ã®åã®ããã®å®å
¨ãªã®ããã§ããè³¼å
¥ã¨3Dããªã³ãã¢ãã«ããã¦ã³ãã¼ãã,èªåã§ãããå°å·ããã,å½ç¤¾ã®3Dããªã³ããµã¼ãã¹ãããã¤ãã¼ã®ä¸ã¤ã«ã¢ãã«ãæåºããã«ã¯,ãããå°å·ãã,æéããªãã®ããªãã«åºè·ããã¦ããããã«ï¼\n","anatomy":"ç§ãã¡ã®å¸å ´ã§ãã¦ã³ãã¼ãã§ãã¾ã%{model_count} 3Dè§£åã¢ãã«ãããªéª¨,çè,èå¨ã¢ãã« - é«ãã¨äººä½è§£åå¦ãæ¢æ¤ãã©ããªæè²ãç§å¦çãªããã¸ã§ã¯ãã®ããã®å®ç§ãªãæ¹åã®æè²çµé¨ã®ããã«å°å·å¯è½ãª3Dã¢ãã«ã使ç¨ãã¦ãã ãããå½ç¤¾ã¨ã®è¦äºãªã¢ãã¡ã¼ã·ã§ã³ããããªã²ã¼ã ã使ãã¾ãã\n 䏿£ã¢ãã«ã®è¨å¤§ãªã©ã¤ãã©ãªãç°¡åPBR,ã¢ãã¡ã¼ã·ã§ã³ã®ä½ãããª,è¦ã¤ããããã«ç§ãã¡ã®é«åº¦ãªãã£ã«ã¿ãªã³ã°ã·ã¹ãã ã使ç¨ãã¦,\n ã¢ãã«ããã¼ãºã«æé©ãªãã®ãè£
åãå«ããã¡ã¤ã«å½¢å¼ã®å¤å¤§ãã鏿ãã¦ãã ãã\n FBX,OBJ,MAX,3DS,C4Dã®ãããªæã人æ°ã®ãããã®ã\n","castle":"ç¬èªã®é©ç°çãª3Då°å·åé¢ãã¦ã¯ãªãã¯ã§ãï¼æ¤ç´¢æ§ã
ãª3Dåã®ã¢ãã«ã¯,3Dããªã³ãã®æºåãã§ãã¦ãããªãã®Dï¼Dã»ãã·ã§ã³ãä»ã®ä¸ä¸ã®RPGã®ãã¼ãã«ã²ã¼ã ã®ããã®ã¦ãã¼ã¯ãªãã¡ã³ã¿ã¸ã¼è¦å¡ã使ãã¾ãããããã®ä¸ä¸ã®è¦å¡ã¯,ä»»æã®ãã¼ãã²ã¼ã ã®æå¥½å®¶ãç¬èªã®ã³ã¬ã¯ã·ã§ã³ã«ç´ æ´ããã追å ããããã®ç´ æ´ãããè´ãç©ã§ããæå¥½å®¶ãåä¾ã®ããã®ä¸ç¨®ã®ããã¡ãã®1ãå¡è£
ããããã®å®ç§ãª3Dã¢ãã«ãæ¤ç´¢ãã¾ããè³¼å
¥ã¨ã¯,鏿ãã3Dã®åã®ãã¶ã¤ã³ããã¦ã³ãã¼ãã,ç¬èªã®ããªã³ã¿ã§ãããå°å·ããã,ãããå°å·ã,ããªãã«åºè·ãã¦ããã¨ç§ãã¡ã®3Dããªã³ããµã¼ãã¹ãããã¤ãã¼ã®ä¸ã¤ã«ã¢ãã«ãæåºãã¾ãã\n","dice":"3Dã¯ãµã¤ã³ããå°å·ãã¦éãå°½ãã¾ããï¼ããªãã®ãã¼ãã²ã¼ã ã®å¤ã®ããã®æ¬æ ¼çãªã²ã¼ã ç¨ãµã¤ã³ãããããå ´åã¯,ãã以䏿¢ãå¿
è¦ã¯ããã¾ãããããã§ã¯,3Dããªã³ãã®æºåãã§ãã¦%{model_count}ç¡æã®3Dãµã¤ã³ãã®ã¢ãã«ã®éã§é¸æãããã¨ãã§ãã¾ããã²ã¼ã ãçµäºããã¨,ã¢ã¯ã»ãµãªã¨ãã¦ãããã®ç¾ããã¢ãã«ã使ç¨ãã¦ãã¾ãããã¦ã³ãã¼ãç¡æã®3Då°å·å¯è½ãªãµã¤ã³ãã®ã¢ãã«,STL,OBJ,3DM,3DS,MAXãå«ãå©ç¨å¯è½ãªãã¡ã¤ã«å½¢å¼ãå½ç¤¾ã®3Dã¢ãã«ã¯,FDM,SLA,SLSã¨3Dããªã³ã¿ã®ä»ã®ã¿ã¤ãã§ä½¿ç¨ãããæºåãã§ãã¦ãã¾ããããªãã®ã²ã¼ã ã¯,ããå°ãé¢ç½ãããã¨,ããªãã®3Då°å·ããããµã¤ã³ããå
¥æï¼\n","drone":"3Dããªã³ãã¨ç¬èªã®ããã¼ã³ãæ§ç¯ããã,交æç¨é¨åãè¦ã¤ãã¾ãã 3Dã¯,ç¡äººåµå¯æ©ãå¢è½çé¸å¾çµã¿ç«ã¦ãä¿®çã容æãªå°å·ãã¾ãããæå°éã®å¤æ´ã®ããã®å®ç§ãªã«ã¡ã©ã®åãä»ãä½ç½®ãè¦æ±ã«ã¢ãã«ãçºè¦ã楽ããã¬ã¸ã£ã¼,èªç©ºåç,ãããªæ®å½±ããããã³ã°ã®ããã®ãã¼ãã§ã¯ãããã¹ã¦ã®ãã¼ãºã«åã£ãã¦ãã¼ã¯ãªãã¶ã¤ã³ã®3Dããã¼ã³ã¢ãã«ãæ¤ç´¢ã,è³¼å
¥ãã¾ããèªåã§ãããå°å·ããã,ããã¯æéããªãã§å°å·ã,ããªãã«åºè·ãããã®ã
16518¯,å½ç¤¾ã®3Dããªã³ããµã¼ãã¹ãããã¤ãã¼ã®ä¸ã¤ã«ã¢ãã«ãæåºï¼ç¬èªã®3Då°å·ãããããã¼ã³ãåå¾ã,åºãéç©ºãæ©ãåãã¾ãï¼\n","pokemon":"ãã«ãã¥ã¦,ç§ã¯ããªãã鏿ãã¦ãã ããï¼ 3Dããªã³ãã®æºåãã§ãã¦ãã±ããã¢ã³ã¹ã¿ã¼ã®è² è·ãã鏿ãã¦ãã ãããã°ã¬ã¼ãã¯,ããªãã®3Då°å·ããããã±ã¢ã³ã³ã¬ã¯ã·ã§ã³ãå±éãã¾ããæ¤ç´¢ãå人ã¨ããªãã®æ¬¡ã®ãã¼ãã«ã²ã¼ã ã®ããã®æé«ã®,æã詳細ãªãã±ã¢ã³ã®ãã¶ã¤ã³æã«ã¤ã¾ããã¾ããè³¼å
¥ã¨ã¯,ããªãã®3Dãã±ã¢ã³ããã¦ã³ãã¼ãã,ç¬èªã®3Dããªã³ã¿ã§ãããå°å·ããã,ãããå°å·ã,ããªãã«åºè·ãã¦ããã¨ç§ãã¡ã®3Dããªã³ããµã¼ãã¹ãããã¤ãã¼ã®ä¸ã¤ã«ã¢ãã«ãæåºãã¾ããçµå±ã®ã¨ãã,ããã¯,3Dããªã³ãã®ã¯ã¼ã«ãªãã®ã®ä¸ã¤ã§ãï¼\n","ring":"3Då°å·ãããã¸ã¥ã¨ãªã¼ã¯,ã¨ãã¦,3Dããªã³ããç°ã§ãã,æ¥çã§ã¯æ°ããé»ã§ãï¼ %{model_count}ããªã¼3Då°å·å¯è½ãªãªã³ã°ã¢ãã«ã®è¨å¤§ãªæ¤ç´¢ãã¦ãã¼ã¯ãªãã¶ã¤ã³ããã©ã¦ãºã,ããªãã®ããã ãã«ä½ãããä½ããè¦ã¤ãã¾ããåºã§èªåã®ããã«ä½ããè¦ã¤ãããã¨ãã§ãã¾ãããï¼ããã¨ã,ããªãã¯æ£ç¢ºã«ããªãã®å¥½ããªæ ç»ã®ãã£ã©ã¯ã¿ã¼ãæã£ã¦ãããããªã¢ã¯ã»ãµãªã¼ããããã§ããï¼ STL,OBJ,3DM,3DS,MAXãªã©ã®ãã¡ã¤ã«å½¢å¼ã®å¤å¤§ãããé¸ã³ããã ãã¾ãã 3Dã¢ãã«ã¯,ããç§éã®é¸æãé²è¦§ã,ããªãã®æ°ãããæ°ã«å
¥ãã®æè¼ªã試ç,FDM,SLA,SLSã¨3Dããªã³ã¿ã®ä»ã®ã¿ã¤ãã§ä½¿ç¨ãããæºåãã§ãã¦ãã¾ãã\n","shoes":"ããã°ãã©ã³ãã¯3Dãé´ãå°å·ã,ä»ããªããçµé¨ãå
±æããã ãã§ãªããããã¨ãã§ã,ãªã³ãã¼ãã§ããç¡æã®å°å·å¯è½ãªé´ã®ãã¶ã¤ã³ãåç
§ãã¦è¦ã¤ãã - ã¹ãã¼ã«ã¼ãããã¡ãã·ã§ããã«ãªããã¨ã«ããªãã®ä¸ã«ãããããããã¨ããããã ãå¾
ã£ã¦ããã«ããªã³ãã¢ãã«ãããããããã¾ããæãããã¨å¤§ããã調æ´ã,ææã鏿ãããã¨ã§,ææå®ç§ã«ãã¾ãã 146ã®ç¡æã®3Dã·ã¥ã¼ã¢ãã«ãã鏿ã,STL,OBJ,3DM,3DS,MAXãå«ãå©ç¨å¯è½ãªãã¡ã¤ã«å½¢å¼ã§ãããããã¦ã³ãã¼ããã¦ãã ãããè¨è¨ã¯,FDM,SLA,SLSåã³3Dããªã³ã¿ã®ä»ã®ã¿ã¤ãã¨ä¸ç·ã«ä½¿ç¨ãããæºåãã§ãã¦ãã¾ããããªãã®3Då°å·ã®é´ä»æ¥ãå
¥æï¼\n","textures":"ç¾ããä½ãããææãå«ããã¦ã³ãã¼ãå¯è½%{model_count} CGãã¯ã¹ãã£ã®è¨å¤§ãªéãæ¤ç´¢ããã©ã¦ãºã«ãã´ãªã¼ãéã£ã¦,è¿
éã«ããªãã®ããã¸ã§ã¯ãã¾ã§,ãã«ããã£ããã·ã¥ã¸ã®ã·ã¼ã ã¬ã¹ãªãã¡ããªãã¯,æ¨æ,éå±,ãã©ã¹ããã¯,ã¬ã³ã¬ã®ãã¯ã¹ãã£ãè¦ã¤ãã¾ããã²ã¼ã ããããªã使ããããã®è£
åãã¢ãã¡ã¼ã·ã§ã³ãã¯ã¹ãã£ãè¦ã¤ããããã«ç§ãã¡ã®é«åº¦ãªæ¤ç´¢ã使ç¨ãã¦ãã ãããç§ãã¡ã®ææã¯ããã»ã©æéãç¡é§ã«ã,ã»ã¼ãã¹ã¦ã®ããã¸ã§ã¯ãæ³åã®ããã«ããã«ä½¿ç¨ã§ããCGã®ãã¯ã¹ãã£ãè¦ã¤ãããªã,TGA,SBSAR,JPG,PNG,TIFFãªã©ãå«ãæ§ã
ãªãã©ã¼ãããã§ãã¦ã³ãã¼ãã§ãã¾ãã\n"},"various":"ç°¡åã«ä»ã®ã«ãã´ãªã¼ã§ãã®å ´æãè¦ã¤ãããã¨ãã§ãã¾ãã%{count}ãã¾ãã¾ãª3Dã¢ãã«ããã¦ã³ãã¼ããããã¨ãã§ãã¾ãã %{rocks_link},%{clouds_link},%{logos_link},%{cigarette_link},ããªããããªãã®ã²ã¼ã ,ã¢ãã¡ã¼ã·ã§ã³ãVR / ARããã¸ã§ã¯ããå®äºããå¿
è¦ãããå ´åãããã¾ããã¨ã,ä»ã®éåé¡3Dã¢ãã«ã¯ããã«ããã¾ãããã£ã«ã¿ã使ç¨ãã¦,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªã¾ãã¯ç¡æã®3Dã¢ãã«ãè£
å,ã¾ãã¯,FBX,OBJ,MAX,3DS,C4Dã¨ãã¦ä½¿ç¨å¯è½ãªå½¢å¼ã§æ´çè¦ã¤ãããã¨ã","vehicle":"ãã¦ã³ãã¼ãã«å©ç¨ã§ãã%{count}è»ä¸¡3Dã¢ãã«ã¯ãã©ãã¯,%{ambulances_link},ãã¹,%{bikes_link}ã¨ã¢ããå«ã¾ãã - ãã®ã«ãã´ãªã«ã¯,ç¾å®çã¾ãã¯SFã®ãã©ãããèªåã®è¡ã¯è»ã§ãã£ã±ãã«ããã人ã®ããã®ãã®ã§ãããããä½ãã·ãã¥ã¬ã¼ã·ã§ã³ã²ã¼ã ãVR / ARã¢ããªã±ã¼ã·ã§ã³,ãããªå¶ä½ã«ãããã¯ãªã¨ã¤ãã£ã,ãããã¯ãã¹ã¿ã¼ã®ãã¶ã¤ã³ã¯,ã»ã¨ãã©ã®å ´å,ãã®ãããªFBX,OBJ,MAX,3DS,C4D使ç¨å¯è½ãªã©ã®æãä¸è¬çãªãã¡ã¤ã«å½¢å¼ãããã¾ããé»è»ã %{tractor_link} 3Dã¢ãã«ã®ãããªä»ã®é¸ä¸è¼¸éè»ä¸¡ã,ãã®è¨å¤§ãªã³ã¬ã¯ã·ã§ã³ã§è¦ã¤ãããã¨ãã§ãã¾ãã使ç¨ãã¦,ããé«éãªè£
å,ã¢ãã¡ã¼ã·ã§ã³,ä½ããªã¾ãã¯ç¡æã®3Dã¢ãã«ãè¦ã¤ããããã«ãã£ã«ã¿ãªã³ã°ãã¾ãã","watercraft":"%{count}ã¯ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ã¯%{boats_link},%{yachts_link},%{ships_link}åã³ãããã種é¡ã®ä»ã®æ°´è¡ãè»ä¸¡ãå«ãè¹è¶ã CGã¢ãã«ã¯,ããªãã®ã·ã¼ã³ã¨è¦è¦å¿ å®åº¦ãããªcountãããéè¦ã§ããä»ã®ã¢ããªã±ã¼ã·ã§ã³ã®ããã«ããã«ããé,ä½ããªã®3Dã¢ãã«ã¯,ãããªã²ã¼ã ,VR / ARããã¸ã§ã¯ãã ãã§ãªã,ã¢ãã¡ã¼ã·ã§ã³ã§ããè¡ãã¾ãè£
åãã¢ãã«ã¯,以ä¸ãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§å©ç¨å¯è½ã§ããã,FBX,OBJ,MAX,3DS,C4Dã«éå®ããã¾ããã"},"tag":{"meta":{"3d_merged_premium":"%{tag_cap}ã®3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããç¡æ\u0026ææãFBXãOBJãBLENDãGLB対å¿ãã²ã¼ã ã»æ åã»AR/VRã»3Dããªã³ãåãã","3d_merged_premium_print":"%{tag_cap}ã®3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ãç¡æ\u0026ææã®STLãã¼ã¿ãFDMã»å
é å½¢ããªã³ã¿ã¼å¯¾å¿ã","3d_models":"%{tag_cap}ã®3Dã¢ãã«%{rounded_count}ç¹ããã¦ã³ãã¼ããç¡æ\u0026ææãFBXãOBJãBLENDãGLB対å¿ãã²ã¼ã ã»æ åã»AR/VRã»3Dããªã³ãåãã","3d_print_models":"%{tag_cap}ã®3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ãç¡æ\u0026ææã®STLãã¼ã¿ãFDMã»å
é å½¢ããªã³ã¿ã¼å¯¾å¿ã","animated_3d_models":"%{count} %{tag} FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ããã¢ãã¡ã¼ã·ã§ã³ã%{page}","free_3d_models":"ãã¦ã³ãã¼ãMAXãOBJãFBXã3DSãC4Dãã¡ã¤ã«ãã©ã¼ããããVR / ARã®ããã®æºåãã§ãã¦ãã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã ããã®ä»ã®3Dããã¸ã§ã¯ãã§å©ç¨ã§ãã %{count} %{tag}ç¡æã®3Dã¢ãã«ãã%{page}","free_3d_print_models":"FDMãSLAãSLSããã³ä»ã®3Dããªã³ã¿ãå©ç¨å¯è½ãªãã©ã¼ãããã®ST
16518LãOBJã3DMã®æºåãã§ãã¦ãããã%{page}ãã¦ã³ãã¼ã %{count} %{tag}ç¡æã®3Dããªã³ãã¢ãã«","lowpoly_3d_models":"ãã¦ã³ãã¼ã %{count} VR / AR /ä½ããª%{tag} 3Dã¢ãã«ãFBXãOBJãMAXã3DSãC4Dãã¡ã¤ã«å½¢å¼ã§ã®ãã¼ãã£ã«ãªã¢ãªãã£ãã²ã¼ã ãä»ã®ãªã¢ã«ã¿ã¤ã ã¢ããªã±ã¼ã·ã§ã³ãå©ç¨ã§ããããã®æºåã%{page}","rigged_3d_models":"%{count} %{tag} FBXãOBJãMAXã3DSãC4Dãå«ãä»»æã®ãã¡ã¤ã«å½¢å¼ã§ãã¦ã³ãã¼ãå¯è½ãª3Dã¢ãã«ãè£
åã%{page}"}},"title":{"download":"|ãã¦ã³ãã¼ã","files":"3Dãã¡ã¤ã«","formats":"%{format_upper} 3Dã¢ãã«","free":"ç¡æ3Dã¢ãã«ã»ããªã¼3Dç´ æ","free_printing":"ç¡æ3Dããªã³ã¿ã¼ç¨ãã¼ã¿","free_tag":"ããªã¼%{selected_tag} 3Dã¢ãã«","general":"ããã®3Dã¢ãã«ãè³¼å
¥","high_poly":"%{selected_filter}3D ã¢ãã«","landing":{"animated_3d_models":"ã¢ãã¡ã¼ã·ã§ã³ä»ã3Dã¢ãã«","lowpoly_3d_models":"ãã¼ããª3Dã¢ãã«","pbr_3d_models":"PBR 3Dã¢ãã«","rigged_3d_models":"ãªã°å
¥ã3Dã¢ãã«"},"low_poly":"%{selected_filter}3D ã¢ãã«","newest_cg":"æ°çããã³ææ°ã®3Dã¢ãã«","newest_print":"æ°çããã³ææ°ã®3Dããªã³ãã¢ãã«","page_prefix":"page %{page_number}","pbr":"ç©çãã¼ã¹ã®ã¬ã³ããªã³ã° 3D ã¢ãã«","printing":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿ã»STLãã¼ã¿","sales_cg":"ãã¹ãã»ã©ã¼3Dã¢ãã«","sales_print":"ãã¹ãã»ã©ã¼3Dããªã³ãã¢ãã«","software_page":"%{software}ç¨3Dã¢ãã«","tag_heading":{"cg":"ç¡æã® %{tag} 3D ããªã³ã ã¢ãã«","filter":"%{selected_filter}%{tag} 3D ã¢ãã«","general":"%{tag_cap} 3Dã¢ãã«","merged_premium_print_tag":"%{tag_cap} 3Dããªã³ã¿ã¼ãã¼ã¿","merged_premium_tag":"%{tag_cap} 3Dã¢ãã«","printable":"%{tag_cap} 3Dããªã³ã¿ã¼ãã¼ã¿"},"trending_cg":"ãã¬ã³ã3Dã¢ãã«","trending_print":"ãã¬ã³ã3Dããªã³ãã¢ãã«"}},"cart":{"request_invoice_failed":"ãã£ã¨ãåé¡ãçºçãã¾ããã","request_invoice_successful":"è«æ±æ¸ã®ãªã¯ã¨ã¹ããæ£å¸¸ã«éä¿¡ããã¾ããã","shareable_cart_created":"ã«ã¼ããæ£å¸¸ã«å
±æããã¾ããã","shareable_cart_failed":"ãã£ã¨ãåé¡ãçºçãã¾ããã","subscription_covered_items_removed":"ã«ã¼ãããåé¤ããã¾ããï¼%{titles}ããã§ã«ãµãã¹ã¯ãªãã·ã§ã³ã«å«ã¾ãã¦ãã¾ãã","subscription_covered_order_refused":"%{titles} ã¯ãµãã¹ã¯ãªãã·ã§ã³ã«å«ã¾ããããã«ãªã£ããããæéã¯è«æ±ããã¦ãã¾ããããµãã¹ã¯ãªãã·ã§ã³ãããã¦ã³ãã¼ããã¦ãã ããã"},"categories":{"cg":{"header_title_html":"ããã®3Dã¢ãã«ãè³¼å
¥","text":"ãã¼ãºã«åã£ãæ£ç¢ºãª3Dã³ã³ãã³ããè¦ã¤ãã¾ããããAR/VRãã²ã¼ã ãåºåãã¨ã³ã¿ã¼ãã¤ã³ã¡ã³ããªã©ã«å¯¾å¿ã\n"},"head-title":{"cg":"3Dã¢ãã« %{rounded_count}ç¹ â 販売ã»è³¼å
¥ã»ç¡æãã¦ã³ãã¼ã","cg-models":{"sort-by":{"newest":"æ°ç3Dã¢ãã«","top-selling":"ãã¹ãã»ã©ã¼3Dã¢ãã«","trending":"ãã¬ã³ã3Dã¢ãã«"}},"print":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿ â STLãã¼ã¿ ç¡æ\u0026ææ","print-models":{"sort-by":{"newest":"æ°ç3Dããªã³ãã¢ãã«","top-selling":"ãã¹ãã»ã©ã¼3Dããªã³ãã¢ãã«","trending":"ãã¬ã³ã3Dããªã³ãåå"}},"product-type":{"cg":"3Dã¢ãã«","cg-merge-premium":"3Dã¢ãã« â ç¡æããã³ãã¬ãã¢ã ãã¦ã³ãã¼ã","lower":{"cg":"3Dã¢ãã«","print":"3Dããªã³ããã¡ã¤ã«ã¨ã¢ãã«"},"plural":{"capital":null},"print":"3Dããªã³ããã¡ã¤ã«ã¨ã¢ãã«","print-merge-premium":"%{tag} 3Dããªã³ããã¡ã¤ã« - ç¡æããã³ãã¬ãã¢ã STLã¢ãã«","singular":{"capital":null}}},"index":{"browse_all":"ãã¹ã¦ã®ã¢ãã«ãé²è¦§","info-section__description_1_html":"ãã仿§ã®3Dã¢ãã«ãè³¼å
¥ã¾ãã¯ç¡æãã¦ã³ãã¼ããCGããã¸ã§ã¯ããæ ç»ã»ãããªå¶ä½ãã¢ãã¡ã¼ã·ã§ã³ããã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ãã²ã¼ã ãVR/ARãªã©ã
16518§ããã«ä½¿ç¨å¯è½ã§ããã¢ã»ããã¯MAXãOBJãFBXã3DSãSTLãC4DãBLENDãMAãMBãªã©ãå¤ãã®\u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eæ¥çæ¨æºãã©ã¼ããã\u003c/a\u003eã§å©ç¨ã§ãã¾ããé«ããªã´ã³ããªã¢ã«ã¿ã¤ã 3Dã¢ã»ãããæ¢ãã¦ãããªããç§ãã¡ã®ãã¸ã¿ã«ã¢ã¼ãã©ã¤ãã©ãªãæé©ã§ãã\n","info-section__description_1_printable_html":"å®¶åºç¨ãã¹ã¯ãããFDMãç£æ¥ç¨SLS 3Dããªã³ã¿ã¼ã§å°å·å¯è½ãªããããã§ãã·ã§ãã«ãª3Dãã¡ã¤ã«ãããªã³ããã¢ãã«ã夿°ã®æ¥çãã©ã¼ãããï¼OBJã\u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003eãWRLãªã©ï¼ã§æä¾ããã¦ãã¾ããããããªãã3Dããªã³ãã®æå¥½å®¶ãã¡ã¼ã«ã¼ãæè²è
ãã¾ãã¯3Dããªã³ãã§ãããã¿ã¤ãã使ãã伿¥ã§ãããªããç§ãã¡ã®å®¶åºç¨è£
飾åããã¬ã³ãã®ã¬ã¸ã§ããã¢ã¯ã»ãµãªã¼ãç®ãå¼ããã¡ãã·ã§ã³ã¢ã¤ãã ãã¦ãã¼ã¯ãªã¸ã¥ã¨ãªã¼ãæ©æ¢°é¨åãå¤ç¨®å¤æ§ãªãããã¥ã¢ãããã£ã¨ã¤ã³ã¹ãã¬ã¼ã·ã§ã³ãä¸ãããã¨ã§ãããã","info-section__heading_1_html":"3Dã¢ãã«\u003cstrong\u003eã«ãã´ãªã¼\u003c/strong\u003eãæ¢ã","info-section__heading_1_printable_html":"3Dããªã³ãã¢ãã«ã®\u003cstrong\u003eã«ãã´ãªã¼\u003c/strong\u003eãæ¤ç´¢ãã","info-section__heading_2_html":"3Dã¢ãã«\u003cstrong\u003eãã¼ã±ãããã¬ã¤ã¹\u003c/strong\u003e","info-section__heading_2_printable_html":"ãã®\u003cstrong\u003eä»\u003c/strong\u003eã¯ï¼"},"marketplace":{"3d-printing":{"link_text":"3Dããªã³ãã¢ãã«ãé²è¦§","text":"3Dããªã³ã¿ã¼ç¨ã®3Dããªã³ãã¢ãã«ãæ¢ãã","title":"3Dããªã³ãã¢ãã«"},"blender_text":"Blendå½¢å¼ã§å©ç¨å¯è½ãªæ°åã®Blender 3Dã¢ãã«ãçºè¦ã","browse":"é²è¦§","cinema-4d_text":"C4Då½¢å¼ã§å©ç¨ã§ããé«å質ãªCinema 4Dã¢ãã«ã夿°çºè¦ã","discounted":{"link_text":"å¤ä¸ãä¸ã®3Dã¢ãã«ãè¦ã¦ã¿ã","text":"å²å¼ä¾¡æ ¼ã§æ¬æ ¼ç3Dã¢ãã«ãè³¼å
¥ã","title":"å¤ä¸ãä¸ã®3Dã¢ãã«"},"low-poly":{"link_text":"ãã¼ããª3Dã¢ãã«ãé²è¦§","text":"ãããªã²ã¼ã ãVRã»ARãªã¢ã«ã¿ã¤ã ã¢ããªç¨ã®ãã¼ããª3Dã¢ãã«ã","title":"ãã¼ããª3Dã¢ãã«"},"pbr":{"link_text":"PBR 3Dã¢ãã«ãé²è¦§","text":"ç©çãã¼ã¹ã¬ã³ããªã³ã°ã®3Dã¢ãã«ã","title":"PBR 3Dã¢ãã«"},"scripts_apps":{"link_text":"ãã¹ã¦é²è¦§","text":"3Dã¢ããªã³ã°ã®ä½æ¥å¹çãä¸ãã3Dã¹ã¯ãªããã¨ãã©ã°ã¤ã³ã","title":"ã¹ã¯ãªããï¼ã¢ããª"},"sketchup_text":"建ç¯ãã¤ã³ããªã¢ãã²ã¼ã ãã¶ã¤ã³ç¨ã®Sketchup 3Dã¢ãã«ãè±å¯ã«é²è¦§ã","textures":{"link_text":"ãã¯ã¹ãã£ãé²è¦§","text":"3Dã¢ãã«æºåã®æéãçãããã«ä½¿ãããã¯ã¹ãã£ã","title":"ãã¯ã¹ãã£"},"zbrush_text":"ãã¸ã¿ã«ã¹ã«ã«ããã3Dã¢ããªã³ã°ããã¯ã¹ãã£ãªã³ã°ããã¤ã³ãç¨ã®ZTLå½¢å¼3Dã¢ã»ãããæ¢ãã"},"meta-description":{"cg":"ããå質ã®3Dã¢ãã«%{rounded_count}ç¹ã販売ã»è³¼å
¥ã»ç¡æãã¦ã³ãã¼ããã²ã¼ã ã»æ åã»VFXã»AR/VRã»3Dããªã³ãåããFBXãOBJãBLENDãGLB対å¿ã","print":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿%{rounded_count}ç¹ããã¦ã³ãã¼ããç¡æ\u0026ææã®STLãã¼ã¿ã»3Dããªã³ãã¢ãã«ï¼ãã£ã®ã¥ã¢ããããã¥ã¢ãå®ç¨åãªã©ã"},"more":{"designers":{"link_text":"3Dãã¶ã¤ãã¼ãªã¹ããé²è¦§","text":"æ°åã®3Dãã¶ã¤ãã¼ãã¼ããã©ãªãªãé²è¦§ããå¿
è¦ãªã¹ãã«ãè¦ã¤ãã¾ãããã","title":"æé«ã®3Dãã¶ã¤ãã¼ãæ¢ã"},"projects":{"link_text":"3Dããã¸ã§ã¯ãã«ã¤ãã¦ãã£ã¨ç¥ã","text":"åªç§ãªããªã¼ã©ã³ã¹ã®3Dã¢ã¼ãã£ã¹ããéã£ã¦ãããããã«ã¹ã¿ã ã¢ããªã³ã°ã®èª²é¡ã解決ã","title":"CGTrader 3Dããã¸ã§ã¯ã"},"visualization":{"link_text":"詳細ãè¦ã","text":"ååããã©ããªã¢ã«ãª3Dã¢ãã«ã«å¤æããeã³ãã¼ã¹ããã¸ãã¹ç¨éã§æ´»ç¨ã","title":"eã³ãã¼ã¹ç¨3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³"}},"navbar":{"aircraft":"èªç©ºæ©","animal":"åç©","animals":"åç©","architectural":"建ç¯","art":"ã¢ã¼ã","car":"è»","character":"ãã£ã©ã¯ã¿ã¼","exterior":"å¤è¦³","fashion":"ãã¡ãã·ã§ã³","food":"é£å","furniture":"å®¶å
·","gadgets":"ã¬ã¸ã§ãã","games-toys":"ã²ã¼ã ã»ç©å
·","hobby-diy":"ããã¼ã»DIY","house":"å®¶","household":"çæ´»ç¨å","industrial":"å·¥æ¥","interior":"ã¤ã³ããªã¢","jewelry":"å®ç³é¡","military":"è»äºç","miniatures":"ãããã¥ã¢","plant":"æ¤ç©","science":"ç§å¦","space":"å®å®","vehicle":"è»ä¸¡","watercraft":"èè"},"print_models":{"hero_title_html":"3Dããªã³ã¿ã¼ç¨ãã¼ã¿ã»STLãã¼ã¿","subtitle":"ãã¼ãºã«åã£ã3Dããªã³ãã³ã³ãã³ããè¦ã¤ãã¾ããã","title_html":"ãã仿§ã®\u003cstrong\u003e3Dããªã³ãã¢ãã«\u003c/strong\u003eãè³¼å
¥"},"profile":{"collection":"3Dããã¯","free":"ç¡æã®3Dã¢ãã«","high_poly":"é«ããª3Dã¢ãã«","optimized":"ä½ããª/ PBR 3Dã¢ãã«","printable":"3Dããªã³ãã¢ãã«"},"seo":{"cg":{"aircraft":"ãã®ã«ãã´ãªã«ã¯3Dèªç©ºæ©ãå«ã¾ãã¾ããCGé£è¡æ©ã¯ã·ãã¥ã¬ã¼ã·ã§ã³ããã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ãåºåãæ åã«é©ãã¦ãã¾ããããã¼ã³ã®ããã£ãé¨åã¯å°åé£è¡æ©ãã¡ã³ãåã°ãã¾ãããªã®ã³ã°æ¸ã¿ã¢ãã«ã¯ã²ã¼ã ã¨ã³ã¸ã³ã«ããã¤ã³ãã¼ãå¯è½ã§ãã\n","animals":"3Dã®åç©ã³ã¬ã¯ã·ã§ã³ï¼ç«ã馬ãçããµã¤ãã¯ã·ãã©ã¤ãªã³ãªã©ï¼ãããã«ããã¾ããCGåç©ã¯åºåãéçã·ã¼ã³ã®ãã¼ãºã«å¯¾å¿ãã²ã¼ã ç¨ã®ãªã®ã³ã°æ¸ã¿åç©ã¢ãã«ãç¨æãã¦ãã¾ãã\n","architectural":"éæ®µãæçã3Dã¢ãã«ãé¡ç¸ãæãã©ã³ããªã©ã®è£
飾åã¯ãå
å®ãã建ç¯ãã£ãã¼ã«ã¢ãã«ã©ã¤ãã©ãªã§è¦ã¤ããã¾ããã¤ã³ããªã¢ãã¨ã¯ã¹ããªã¢ãå©ç¨ãã¦ããã¸ã¿ã«ã®ãããã³ãå¯å®¤ãåã®é¨å±ããã³ã¸ã§ã³ãæ§ç¯ã§ãã¾ãã建ç¯å®¶ãã¨ã³ã¸ãã¢ãã¤ã³ãã£ã¼ã²ã¼ã éçºè
ã®ãããã§ãå©ç¨å¯è½ã§ãã\n","car":"è»ã«ãã´ãªã«ã¯èªåè»ã®3Dã¢ãã«ãå«ã¾ãã¦ããããã¼ããªçã¯ã²ã¼ã ãã¶ã¤ãã¼ã«ããã®ä»ã¯æ ç»è£½ä½è
ãåºå主ã«é
åçã§ããã¯ã©ã·ãã¯ã«ã¼ããã¬ã¼ã·ã³ã°ã«ã¼ãã³ã³ã»ããã«ã¼ã¾ã§ãå¤å½©ãª3Dèªåè»ã¢ãã«ãããã¾ãã\n","character":"ãã®ã«ãã´ãªã§ã¯ã人éã人ç©ãSFãè¡£é¡ãªã©ã®3Dã¢ãã«ãè¦ã¤ããã¾ããå¿èãæããã精巧ãªç·æ§ã»å¥³æ§ã®ãªã¢ã«ã¢ãã«ã¾ã§ãå¤ãã®ã¢ãã«ã¯ãªã®ã³ã°æ¸ã¿ã§ãã²ã¼ã ãã¢ãã¡ã«ç°¡åã«è¿½å ã§ãã¾ãã\n","electronics":"ã¨ã¬ã¯ãããã¯ã¹ã§ã¯,建ç¯å®¶,ã¤ã³ããªã¢ãã³ã¬ã¼ã¿ã¼,ã¬ãã«ãã¶ã¤ãã¼,ã·ã¼ã³ã®ã¡ã¼ã«ã¼ãä»ã®ã¯ãªã¨ã¤ãã£ãã®ããã®ã«ãã´ãªã§ãã 3Dã¢ãã«{ \"slug\": \"smartphone\", \"title\": \"ã¹ãã¼ããã©ã³\"},{ \"slug\": \"laptop\", \"title\": \"ã©ããããã\"}
16518,{ \"slug\": \"camera\",\"title\": \"ã«ã¡ã©\"},{\"slug\":\"tv\",\"title\":\"ãã¬ã\"},ããæ£ç¢ºããã¤ã¹ãæè¡ã¨ç¾ä»£ã®çæ´»ã®å¼·è¿«è¦³å¿µããã£ããã£ããã®ã«å½¹ç«ã¡ã¾ãã\n","engineering-parts":"Windowsã¯,ãã¤ãã©ã¤ã³,ã¹ã©ã¤ããã¢ã®ã¡ã«ããºã ã¨CADã®ããã¸ã§ã¯ã,ããã«ã¯DIYã®è¨ç»ã®ããã«å¿
è¦ãªä»ã®ãããã¯,ãã®ã«ãã´ãªã«åé¡ããã¾ããããã¯,ããªããANVER,ãã¤ãããã¯ã¨ãFCiã®ãããªã°ãã¼ãã«ã¡ã¼ã«ã¼ããã®3Dã¢ãã«ãè¦ã¤ãããã¨ãã§ããå ´æã§ãã\n","exterior":"ãã¡ãµã¼ããé½å¸å»ºç¯ãããã©ã³ãã¹ã±ã¼ããªãã¸ã§ã¯ããä½å®
ãç£æ¥æ½è¨ããã«ã¹ã±ã¼ã«ã®3Dé½å¸ã¢ãã«ã¾ã§ã建ç¯å¤è¦³ãé²è¦§ã§ãã¾ããä¸é¨ã®ã¢ã»ããã¯ãã¼ããªã§ãã²ã¼ã ãVR/ARã¢ããªã®å®æã«å½¹ç«ã¡ã¾ãã\n","food":"é£åã¯å®¶åºçæ´»ã®ãªã¢ã«ãªã·ã¼ã³ãä½ãã®ã«å½¹ç«ã¡ã¾ãã3Dã®æç©ãéèã飲ã¿ç©ãé£äºããã¹ã¦æã£ã¦ãã¾ããã¬ã¹ãã©ã³åºåãå¥åº·çãªé£äºã®ããã®ARã¢ããªã3Dãã¶ãã¦ã§ãã£ã³ã°ã±ã¼ãã®ã¢ãã«ãæ¢ãã¦ãããªããããã«ããã¾ãã\n","furniture":"3Dã®ãã¼ãã«ãæ¤
åãã½ãã¡ãããããªã©ãæ¨æãéå±ãªã©ãã¾ãã¾ãªãã¯ã¹ãã£ãã¬ãããã¢ãã³ãªã©å¤æ§ãªã¹ã¿ã¤ã«ã§å©ç¨å¯è½ã§ãããã®ã«ãã´ãªã¯å»ºç¯ãã¤ã³ããªã¢ãã¶ã¤ã³ãåºåã«æºãã人åãã§ãã\n","furniture-set":"ããªãã¯åæ§ã«ã¢ã³ãã£ã¼ã¯ã®æ¤
åãã½ãã¡è¦ãã,å°æç¨åã®ãã«ã»ãããæ¢ãã¦å¿
è¦ãªå ´åã¯,ããã¯ãããã³ã¨ãªãã£ã¹ã«ãªãã³ã°ã«ã¼ã ,ãã¤ãã³ã°ãã¼ã«ã®å®¶å
·ã»ãããã3Dã®å®¶å
·ã¢ãã«ã®ãã®ã«ãã´ãªã³ã¬ã¯ãã»ããã¨ãã¦ããå ´æã§ããããã¯,ä¸è´ããè¦ç´ ãæã¤ã¤ã³ããªã¢ãã¬ãã«ãã¶ã¤ã³å°éãã«ãé¨å±ã«å½¹ç«ã¡ã¾ãã\n","household":"å®¶åºç¨3Dã¢ã¤ãã ã¯é¨å±ã«ãã£ãã¼ã«ãå ããããã«ä½¿ç¨ããã¾ããé£åã«3Dé£å¨ã»ãããç½®ããããå¡©è¡æ¤å
¥ãã追å ãã¦ãããã³ã宿ããããããããã®æ¨ªã«ã©ã¤ããè±ã飾ã£ã¦é«ç´æãæ¼åºã§ãã¾ãã\n","industrial":"建ç¯è³æãã¨ã³ã¸ãã¢ãªã³ã°ãã¼ã«ãæ©æ¢°ãã³ã³ãããªã©ãç°å¢ãã£ãã¼ã«ã¨ã¤ã³ã¿ã©ã¯ãã£ããªãªã®ã³ã°æ¸ã¿è¦ç´ ãæä¾ãã¾ããã·ãã¥ã¬ã¼ã·ã§ã³ã²ã¼ã éçºè
ãå·¥äºç¾å ´ã¬ãã«ãæ§ç¯ããäººã«æé©ã§ãã\n","interior":"ãã®ã«ãã´ãªã«ã¯ã建ç¯ã建è¨ãã¤ã³ããªã¢ãã¶ã¤ã³ã®ãªã¢ã«ãª3Dè¦ç´ ã詳細ãå«ã¾ãã¾ãããããã®3Dã¢ãã«ã¯ã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã ã«ä½¿ç¨ã§ããä¸é¨ã¯ãªã®ã³ã°æ¸ã¿ã§ãã¼ããªã§ãã\n","military":"ãã®ã«ãã´ãªã§ã¯ãæ¦å¨ãé²å
·ãå£ãå¤§ç ²ãªã©ã®3Dã¢ãã«ãè³¼å
¥ã§ãã¾ããç¾ä»£ããæ´å²çãªãã®ã¾ã§ãè»ç¨ãèªè¡ç¨ã«å©ç¨å¯è½ã§ããã²ã¼ã ç¨ã«ããªã´ã³æé©åãããã¢ãã«ããããããã«ã²ã¼ã ã¨ã³ã¸ã³ã§ä½¿ç¨ã§ãã¾ãã\n","plant":"ãã®ã«ãã´ãªã«ã¯ãè±ãæ¨ãèãã¤ãæ¤ç©ãç·ããã¼ããå¤å¹´èãèãè½ã使¨ãæ¿ãæ¨ãè¥è½ãããã¦ãéèãªã©ã®æ¤ç©ã®3Dã¢ãã«ãå«ã¾ãã¾ãã3Dã¢ãã«ãè³¼å
¥ã¾ãã¯ç¡æã§ãã¦ã³ãã¼ãããã«ã¯ã以ä¸ã®ã«ãã´ãªãé²è¦§ãã¦ãã ããã\n","scanned":"ã¢ãã©ã¼ã¯RealSenseã®ãããª3Dã¹ãã£ã³æè¡ã使ç¨ãã¦ãããã®ã¢ãã«ã使ãã¾ããããªã¼ã§ã,ç·æ§ã¨å¥³æ§ãããã«äººæ°ããã,彫åãåãæ ªã製åã¯,ãªã¢ãªãºã ã®æ¯é¡ã®ãªãã¬ãã«ãæä¾ã,ã·ã¼ã³ãã¢ãã¡ã¼ã·ã§ã³ã§ä½¿ç¨ã§ããããã«ãªãã¾ããã\n","scripts-plugins":"ã¹ã¯ãªããã¨ãã©ã°ã¤ã³ã¯,ã½ããã¦ã§ã¢ã®ã·ã§ã¼ãã«ãããæä¾ãã¾ããã¢ããªã³ã°,ã¬ã³ããªã³ã°,ãã¯ã¹ãã£ãªã³ã°ã¯ - ãããã®ãã¹ã¦ã¯,Mayaã¨V-Rayã®ãããªã½ããã¦ã§ã¢ã®ãã¹ã¦ã®ç¨®é¡ã®ããã«æ¥ããã©ã°ã¤ã³ã使ç¨ãã¦å®¹æã«è¡ããã¨ãã§ãã¾ãã\n","space":"å®å®ã«ãã´ãªã«ã¯ãSFå®å®è¹ãå°ææãææï¼å°çãç§å¦å¿åã®äººåãã®ãªã¢ã«ãªã¹ãã¼ã¹ã·ã£ãã«ãå«ãï¼ã®ãã¼ããªã»ã²ã¼ã 対å¿ã¢ãã«ã夿°å«ã¾ãã¾ãã3Då®å®ã¢ãã«ã¯VRå®å®ã·ãã¥ã¬ã¼ã¿ã¼ã²ã¼ã ã«å½¹ç«ã¡ã¾ãã\n","sport-hobby":"ä¸è¬ã®ã¤ãã³ã,ã¹ãã¼ããè¶£å³:ãã®ã«ãã´ãªã«ã¯,{\"slug\":\"field\",\"title\":\"ãã£ã¼ã«ã\"}ã«é¢é£ãã¦ãããã®ãã¾ã¨ããã {\"slug\":\"football\",\"title\":\"ããããã¼ã«\"}ã«ã¹ãã¼æé¢ã{\"slug\":\"guitar\",\"title\":\"ã®ã¿ã¼\"}:{\"slug\":\"piano\",\"title\":\"ãã¢ã\"}ãã,ãããã¯,åºå,ã·ã¼ã³ãã¢ãã¡ã¼ã·ã§ã³ã®ããã«æç¨ãª3Dã¢ãã«ãããã¾ããä½ããªã®ãã¼ã¸ã§ã³ã§ã¯,ã¹ãã¼ãã®ãããªã²ã¼ã ã®ããã«ããã«ããã¾ãã\n","textures":"ç¾ããä½ããã3Dç´ æã®ã©ã¤ãã©ãªãé²è¦§ããã²ã¼ã 対å¿ããã©ããªã¢ã«ãªã¢ãã«ã«æé©ãªãã使ãããã¯ã¹ãã£ãè¦ã¤ããã¢ã»ããã©ã¤ãã©ãªãå
å®ããã3Dä½åãåä¸ããã¾ãããã\n","various":"ãããã¯,æã
ã¯ããããã¹ã¦ãåãå
¥ãããã®ã使ããã®ã§,ç°¡åã«,ä»ã®ã«ãã´ãªã«åã¾ããªãã£ã3Dã¢ãã«ã§ãã { \"title\": \"ããã¯ã¹\", \"slug\": \"rocks\"}
16518,{ \"slug\": \"clouds\",\"title\":\"é²\"},{ \"title\": \"ãã´\", \"slug\": \"logo\"},{ \"title\" :\"å\",\"slug\":\"umbrella\"}ããã³ãã®ä»ã®éåé¡3Dã¢ãã«ã¯ããã«ããã¾ãã\n","vehicle":"ãã©ãã¯ãææ¥è»ããã¹ãé»è»ããã©ã¯ã¿ã¼ãèªè»¢è»ããã¤ã¯ãªã©âè¡è·¯ããªã¢ã«ã§SFçãªè»ä¸¡ã§æºãããã人ããã·ãã¥ã¬ã¼ã·ã§ã³ã²ã¼ã ããã¹ã¿ã¼å¶ä½ããã人åãã®ã«ãã´ãªã§ãã\n","watercraft":"æ°´ä¸ä¹ãç©ã«ãã´ãªã«ã¯ããã¼ããã¨ãããè¹ãªã©ã®æ°´ä¸äº¤éæ©é¢ãå«ã¾ãã¾ãããªã®ã³ã°æ¸ã¿3Dã¢ãã«ã¯ãããªã²ã¼ã ãã¢ãã¡ã¼ã·ã§ã³ã«é©ããCGã¢ãã«ã¯ããªã´ã³æ°ãããè¦è¦çå¿ å®åº¦ãéè¦ãªã·ã¼ã³ãä»ã®ç¨éã«é©ãã¦ãã¾ãã\n"},"forwarded":{"cg":{"aircraft":"ãã®ã«ãã´ãªã¯3Dèªç©ºæ©ã対象ã¨ãã¦ãã¾ãã CG {\"slug\": \"airplane\",\"title\":\"é£è¡æ©\"}ã¯,ã·ãã¥ã¬ã¼ã·ã§ã³ãè¦è¦åãåºåãåç»ã«ãã使ããã¾ãã {\"slug\": \"drone\",\"title\":\"ããã¼ã³\"}ã®æ¬ä½ãé¨åã¯å°ããªç©ºé£ã¶ä¹ãç©ã好ããªäººãåã°ãã¾ããããã¦{\"slug\": \"aircraft\", \"title\": \"ãªã°ãããã¢ãã«\", \"active_filter\": \"rigged\"}ã¯ã²ã¼ã ã¨ã³ã¸ã³ã«ã¤ã³ãã¼ãã§ãã¾ãã","animals":"3Dã®åç©ã³ã¬ã¯ã·ã§ã³ - { \"slug\": \"cat\", \"title\": \"ç«\"}ã{ \"slug\": \"horse\", \"title\": \"馬\"}ã{ \"slug\": \"bear\" , \"title\": \"ã¯ã\"}ã{ \"slug\": \"rhino\", \"title\": \"ãµã¤\"}ã{ \"slug\": \"eagle\", \"title\": \"ã¯ã·\"}ã{ \"slug\": \"lion\", \"title\": \"ã©ã¤ãªã³\"}ãªã©ãããã§è¦ã¤ãããã¨ãã§ãã¾ãã3DCGã®åç©ã¯ãåºåã¾ãã¯éçãªã·ã¼ã³ã®ãã¼ãºãæºãããã¨ãã§ãã¾ãã ã²ã¼ã ç¨ã«{\"slug\": \"animal\", \"title\": \"ãªã°ãããåç©\", \"active_filter\": \"rigged\"}ã®ã¢ãã«ãæã£ã¦ãã¾ãã","architectural":"{\"slug\": \"stairs\", \"title\": \"éæ®µ\"}ã {\"slug\": \"fireplace\", \"title\":\"æç\"}ã®3Dã¢ãã«ãã¾ãã {\"slug\": \"frame\", \"title\":\"ãã¬ã¼ã \"}ã {\"slug\": \"pillow\", \"title\":\"æ\"}ã {\"slug\": \"lamp\",\"title\":\"ã©ã³ã\"}ã®è£
飾ãªã©ã å¹
åºã建ç¯ã¢ãã«ãè¦ã¤ãããã¨ãã§ãã¾ããè»ã®ã«ãã´ãªã§ã¯ãèªåè»ã®3Dã¢ãã«ã {\"slug\": \"car\", \"title\": \"ãã¼ããª\", \"active_filter\": \"low_poly\"} ã¢ãã«ãã©ã¤ãã©ãªã«å«ã¾ãã¦ãã¾ããã¤ã³ããªã¢ãå®¶ã®å¤è¦³ã
16518®ãã¸ã¿ã«ãããã³ããããã«ã¼ã ããåã®é¨å±ããã®å°ä¸å®¤ãªã©ãããªãã建ç¯å®¶ãã¨ã³ã¸ãã¢ãã¾ãã¯ã¤ã³ãã£ã¼ãºã²ã¼ã ã®éçºè
ã§ãã£ã¦ãããã¼ãºã«åããã¦æ§ã
ãªæ§ç¯ããããã¨ãã§ãã¾ãã","car":"è»ã®ã«ãã´ãªã«ã¯ãèªåè»ã®3Dã¢ãã«ãããã® \u003ca href=\"%{link_to_low_poly_items_url}\"\u003eãã¼ããª\u003c/a\u003eãã¼ã¸ã§ã³ãå«ã¾ãã¦ãããã²ã¼ã ãã¶ã¤ãã¼ãæ ç»è£½ä½è
ãåºå主ã«ã¨ã£ã¦é
åçã§ããã¯ã©ã·ãã¯ã«ã¼ããã¹ãã¼ãã«ã¼ãã¾ãã¯ãã©ãã¯ãã³ã³ã»ããã«ã¼ã¾ã§ãå¤ç¨®å¤æ§ãª3Dã®èªåè»ã¢ãã«ãæã£ã¦ãã¾ãã","character":"ãã®ã«ãã´ãªã§ã¯ {\"slug\": \"human\", \"title\":\"人é\"} ã人ç©ãSFãæ´æãªã©ã®3Dã¢ãã«ãè¦ã¤ãããã¨ãã§ãã¾ãã {\"slug\": \"heart\", \"title\":\"å¿è\"}ã{\"slug\": \"hand\", \"title\":\"æ\"}ã¾ãããªã¢ã«ãª{\"slug\": \"male\", \"title\":\"ç·æ§\"}ã¢ãã«{\"slug\": \"female\", \"title\":\"女æ§\"}ã¾ã§ãå¤ãã®ã¢ãã«ããªã°ããã¦ãããç°¡åã«ã²ã¼ã ãã¢ãã¡ã¼ã·ã§ã³ã«è¿½å ãããã¨ãã§ãã¾ãã\\n","electronics":"é»åæ©å¨ã«ãã´ãªã«ã¯ã建ç¯å®¶ãã¤ã³ããªã¢ã³ã¼ãã£ãã¼ã¿ã¼ãç°å¢ãã¶ã¤ãã¼ããã·ã¼ã³ã®è£½ä½è
ãªã©ã®ã¯ãªã¨ã¤ãã£ããã£ã¼ãªè£½ä½ã«å½¹ç«ã¤ã¢ãã«ãå«ã¾ãã¦ãã¾ãã { \"slug\": \"smartphone\", \"title\": \"ã¹ãã¼ããã©ã³\"}ã{ \"slug\": \"laptop\", \"title\": \"ãã½ã³ã³\"}ã{ \"slug\": \"camera\", \"title\": \"ã«ã¡ã©\"}ã{\"slug\": \"tv\", \"title\":\"ãã¬ã\"}ãªã©ã®3Dã¢ãã«ã¯ãããæ£ç¢ºã«ç¾ä»£ã®çæ´»ãããã¤ã¹ãæè¡ã§è¡¨ããã¨ãã§ãã¾ãã","engineering-parts":"CADã®ããã¸ã§ã¯ãã«å¿
è¦ãªçªããã¤ãã©ã¤ã³ãã¹ã©ã¤ããã¢ããã³ããã®ä»ã®ããããDIYãã©ã³ããã®ã«ãã´ãªã«åé¡ããã¾ããANVERãDynatecãFCiã®ãããªã°ãã¼ãã«ã¡ã¼ã«ã¼ã®3Dã¢ãã«ãè¦ã¤ãããã¨ãã§ããå ´æã§ãã","exterior":"çºã®å¤è¦³ãé½å¸ã®å»ºç©ããã風æ¯ã®ãªãã¸ã§ã¯ããä½å®
ããã³ãç£æ¥æ½è¨ã®ãã«ã¹ã±ã¼ã«3D {\"slug\": \"city\", \"title\":\"é½å¸\"}ã¢ãã«ã¾ã§ã®å»ºç©ã®å¤è¦³ãé²è¦§ã§ãã¾ããä¸é¨ã®ã¢ã»ããã¯ãã¼ããªã§ãããã²ã¼ã ãVR / ARã¢ããªã±ã¼ã·ã§ã³ã®å®æã«å½¹ç«ã¡ã¾ãã","food":"é£åã¢ãã«ã¯ãå®¶åºã§ã®çæ´»ã®ãªã¢ã«ãªã·ã¼ã³ã使ããã®ã«å½¹ç«ã¡ã¾ãã3Dã®æç©ãéèã飲ã¿ç©ãæçã¯ãã¹ã¦ãã®ã«ãã´ãªã«åãæãããã¦ãã¾ããã¬ã¹ãã©ã³ã®åºåããå¥åº·çãªé£äºã®ããã®ARã¢ããªã±ã¼ã·ã§ã³ãªã©ã«ã使ãã¾ããããªããæ¢ãã¦ããã®ã{\"slug\": \"pizza\", \"title\":\"ãã¶\"}ã§ãã¦ã§ãã£ã³ã°{\"slug\": \"cake\", \"title\":\"ã±ã¼ã\"}ã§ããæ¬²ããã£ããã®ãä½ã§ãè¦ã¤ããã§ãããã","furniture":"3Dãã¼ãã«ãæ¤
åãã½ãã¡ã¼ãããããªã©ã®æ§ã
ãªãã¯ã¹ãã£ï¼æ¨æãéå±çï¼ãã¹ã¿ã¤ã«ï¼{\"slug\": \"retro\", \"title\":\"ã¬ãã\"}ã{\"slug\": \"modern\", \"title\":\"ã¢ãã³\"}ãªã©ï¼ã¯ããã«ããã¾ãããã®ã«ãã´ãªã¯ã建ç¯ãã¤ã³ããªã¢ãã¶ã¤ã³ã ãã§ãªããåºåæ¥çã«ãå½¹ç«ã¤ååãåãæãã¦ãã¾ãã","furniture-set":"ã¢ã³ãã£ã¼ã¯èª¿ã®æ¤
åãã½ãã¡ã¼ãå°æç¨åã®ä¸å¼ãªã©ãå¿
è¦ãªãããã®ã«ãã´ãªã¼ãã´ã£ããã§ãããããã³ããªãã£ã¹ã«ãªãã³ã°ã«ã¼ã ãããã«ã¯ãã¤ãã³ã°ãã¼ã«ã®3Då®¶å
·ã¢ãã«ããç¨æãã¦ãã¾ããããã3Då®¶å
·ã¢ãã«ã¯ã¤ã³ããªã¢ã¾ãã¯ç°å¢ãã¶ã¤ãã¼ãæãéãã®é¨å±ãä½ãããã¨ãã«å½¹ç«ã¡ã¾ãã","household":"å®¶åºç¨ã¢ã¤ãã ã®3Dã¢ãã«ã¯ãé¨å±ã®è©³ç´°ãªé¨åã表ç¾ããããã«ä½¿ç¨ããã¾ãããã¼ãã«ã®ä¸ã«3Dã®ãã£ãã¼ã»ãããç½®ãããããããã³ã®ã¤ã³ããªã¢ã¨ãã¦å¡©ãè¡æ¤ã®å®¹å¨ãè¨ç½®ããããããã¨ãã§ãã¾ããããã«ã{\"slug\": \"light\", \"title\":\"鿥ç
§æ\"}ã{\"slug\": \"flowers\", \"title\":\"è±\"}ããããã®è¿ãã«ç½®ããã¨ã§é«ç´æãæ¼åºãããã¨ãã§ãã¾ãã","industrial":"ãã®ã«ãã´ãªã¯å»ºè¨è³æã{\"slug\": \"engineering\", \"title\":\"建ç¯\"}æ©æãæ©æ¢°ã{\"slug\": \"container\", \"title\":\"ã³ã³ãã\"}ã®ããã«å·¥æ¥ç°å¢ã¨ãããã«é¢ä¿ããéå
·é¡ãæä¾ãã¾ãããããã¯ã·ãã¥ã¬ã¼ã·ã§ã³ã²ã¼ã ã®éçºè
ã{\"slug\": \"construction\", \"title\":\"建è¨\"}ã®æ§ç¯ãããäººã«æé©ã§ãã","interior":"ãã®ã«ãã´ãªã«ã¯ããªã¢ã«ãª3Dã®è¦ç´ ã建ç¯ã建è¨ãããã¦å·¥å¦çãªã¤ã³ããªã¢ãã¶ã¤ã³ã®ãã£ãã¼ã«ãå«ã¾ãã¦ãã¾ãããããã®3Dã¢ãã«ã¯ä¸é¨ãªã®ã³ã°ããããã¼ããªã´ã³ã®ããã¢ãã¡ãã²ã¼ã ã«ã使ç¨ã§ãã¾ãã","military":"ãã®ã«ãã´ãªã§ã¯ãæ¦å¨ãé²å
·ã {\"slug\": \"sword\", \"title\": \"å£\"} ãå¤§ç ²ãªã©ã®3Dã¢ãã«ãè³¼å
¥ãããã¨ãã§ãã¾ãããããã®ã¢ãã«ã¯ç¾ä»£ã«ä½¿ç¨ããã¦ãããã¾ãã¯æ´å²çã«è»éãèªè¡éã§ä½¿ç¨ãããã®ãåèã«ãã¦ãã¾ãããã®ãã¡ã®ããã¤ãã¯ããªã´ã³ãæé©åãããã²ã¼ã ã¨ã³ã¸ã³ã«å¯¾å¿ãã¦ããã®ã§ãã²ã¼ã ä¸ã§ä½¿ç¨ã§ãã¾ãã","plant":"{\"slug\": \"tree\", \"title\":\"æ¤ç©\"}ãã®ã«ãã´ãªã«ã¯ãè±ãæ¨ãèããã«ãç·ã®èãæããã¼ããå¤å¹´çæ¤ç©ãèæ¨ãæ°è½ã使¨ãããæãåèãã¤ãæ¤ç©ãéèãªã©ã®æ¤ç©ã®3Dã¢ãã«ãå«ã¾ãã¾ãã3Dã¢ãã«ãè³¼å
¥ã¾ãã¯ç¡æã§ãã¦ã³ãã¼ãããã«ã¯ã以ä¸ã®ã«ãã´ãªãåç
§ãã¦ãã ããã\\n","scanned":"模åã®è£½ä½è
ã¯ãªã¢ã«ãª3Dã¹ãã£ã³æè¡ã使ç¨ãã¦ãããã®ã¢ãã«ã使ãã¾ããæ¨ã®åãæ ªã彫å»ãããã¦ç·æ§ã¨å¥³æ§ã®ã¢ãã«ã¯ç¹ã«äººæ°ãããã¾ããç¾å®ä¸çã¨å¤ãããªãã¯ãªãªãã£ã¼ã®ãã®ããæ åãã¢ãã¡ã¼ã·ã§ã³ã§ä½¿ç¨ã§ãã¾ãã","scie
16518nce":"ãã®ã«ãã´ãªã«ã¯ãå»å¦ãçç©å¦ãç©çå¦ãåå¦ãã¨ãã£ãæè¡ã«é¢é£ãã3Dã¢ãã«ãå«ã¾ãã¦ãã¾ãã{\"slug\": \"cell\", \"title\":\"ç´°è\"}ã{\"slug\": \"skull\", \"title\":\"é è骨\"}ãããã¦{\"slug\": \"skeleton\", \"title\":\"éª¨æ ¼\"}ã®3Dã¢ãã«ãããã«æã£ã¦ããã®ã§ãè²ã
ãªãµã¤ãã§ãããããæ¢ãå¿
è¦ã¯ããããã¾ããã","scripts-plugins":"ã¹ã¯ãªããããã©ã°ã¤ã³ã§ãã½ããã¦ã§ã¢ã®ã·ã§ã¼ãã«ãããä½ããã¨ãã§ãã¾ããã¢ããªã³ã°ãã¬ã³ããªã³ã°ããã¯ã¹ãã£ãªã³ã°ã¯ãã¹ã¦ãMayaãV-Rayã®ãããªãããã種é¡ã®ã½ããã¦ã§ã¢ã«ä»å±ãããã©ã°ã¤ã³ã使ç¨ãã¦å®¹æã«è¡ããã¨ãã§ãã¾ãã","space":"å®å®ã®ã«ãã´ãªã¼ã¯ããããªã¢ã«ãª{\"slug\": \"spaceship\", \"title\":\"å®å®è¹\"}ã{\"slug\": \"asteroid\", \"title\":\"å°ææ\"}ãå«ãææï¼{\"slug\": \"earth\", \"title\": \"å°ç\"}ããªã¢ã«ãª{\"slug\": \"shuttle\", \"title\":\"ã¹ãã¼ã¹ã·ã£ãã«\"}ãªã©ï¼ããããã²ã¼ã 対å¿ã®ãã¼ããªã¢ãã«ã夿°ããã¾ãã3D空éã¢ãã«ã¯VR空éã·ãã¥ã¬ã¼ã¿ã¼ã²ã¼ã ã«å½¹ç«ã¡ã¾ãã","sport-hobby":"ãã®ã«ãã´ãªã«ã¯ã {\"slug\": \"field\", \"title\":\"éå¤\"} ã¤ãã³ããã¹ãã¼ããè¶£å³å
¨è¬ã«é¢é£ãã¦ãããã®ãã¾ã¨ãããã¦ãã¾ãã {\"slug\": \"football\", \"title\":\"ãµãã«ã¼\"}ãã¹ãã¼ã{\"slug\": \"guitar\", \"title\":\"ã®ã¿ã¼\"}ã{\"slug\": \"piano\", \"title\":\"ãã¢ã\"}ã¾ã§ãåºåã¾ãã¯æ åãã¢ãã¡ã¼ã·ã§ã³ã«å½¹ç«ã¤3Dã¢ãã«ãæã£ã¦ãã¾ãããã¼ããªã®ãã¼ã¸ã§ã³ã¯ãã¹ãã¼ãç³»ã®ãããªã²ã¼ã ã«ä½¿ç¨ãããã¨ãã§ãã¾ãã","textures":"ç¾ããä½ããã3Dç´ æã®ã©ã¤ãã©ãªãåç
§ããããã«ä½¿ç¨ã§ããæé©ãªãã¯ã¹ãã£ãè¦ã¤ãã\u003ca href=\"%{link_to_low_poly_items_url}\"\u003eã²ã¼ã 対å¿\u003c/a\u003eã¾ãã¯åçã®ããã«ãªã¢ã«ãªã¢ãã«ãæ¢ãã¾ãããããããã®ã¢ãã«ã¯ããªãã®ã¢ã»ããã©ã¤ãã©ãªãã¢ããã°ã¬ã¼ãããããªãã®3Dä½åã®è³ªãæ ¼æ®µã«åä¸ããã¾ãã","various":"ãã¡ãã«å«ã¾ãã¦ããã®ã¯ãä»ã®ã«ãã´ãªã«åã¾ããªãã£ã3Dã¢ãã«ã§ãã{\"slug\": \"rocks\", \"title\": \"岩\"}ã {\"slug\": \"clouds\", \"title\": \"é²\"} ã{\"slug\": \"logos\", \"title\": \"ããã´\"}ã{\"slug\": \"umbrellas\", \"title\": \"å\"}ããã³ããã®ä»ã®åé¡ããã¦ããªã3Dã¢ãã«ãè¦ã¤ããã¾ãã","vehicle":"ãã®ã«ãã´ãªã«ã¯ãã©ãã¯ã {\"slug\": \"ambulance\", \"title\": \"ææ¥è»\"} ã ãã¹ã é»è»ã ãã©ã¯ã¿ã¼ã {\"title\": \"èªè»¢è»\", \"slug\": \"bike\"} ããªã¼ããã¤ãå«ã¾ãã¾ããè¡ã®éãããªã¢ã«ãªè»ãSFç³»ã®ä¹ãç©ã§ãã£ã±ãã«ããã人ãã¾ãã¯ã·ãã¥ã¬ã¼ã·ã§ã³ã²ã¼ã ãããã¹ã¿ã¼ã®ãã©ã¼ãããã使ãã人åãã§ãã","watercraft":"è¹è¶ã®ã«ãã´ãªã«ã¯ã{\"slug\": \"boat\", \"title\": \"å°åè¹\"}ã{\"slug\": \"yacht\", \"title\": \"ã¨ãã\"}ã{\"slug\": \"ship\", \"title\": \"ãã§ãªã¼\"}ãªã©ã®æ°´ä¸è»ä¸¡ãå«ã¾ãã¾ãããªã°ããã3Dã¢ãã«ã¯ã主ã«ãããªã²ã¼ã ãã¢ãã¡ã¼ã·ã§ã³ã§ä½¿ç¨ã§ããCGã¢ãã«ã¯æ åããã®ä»ã®ã¢ããªã§ããªã´ã³æ°ãããè¦è¦çãªå¿ å®åº¦ãéè¦ãªå ´åã«ä¾¿å©ã§ãã"},"printable":{"art":"è¸è¡çãª3Dããªã³ããè¡ãã¤ãå ´æãå¤å
¸çãªä½åãæ´å²çãªäººç©ã®å½«åãã¾ãã¯åºæ¿çãªç½®ç©ã豪è¯ãªå½«å»ãã¶ã¤ã³ãªã©ããæ¢ãã§ããï¼ãããªããã®ã«ãã´ãªãã´ã£ããã§ããããã«ã3Då°å·å¯è½ãªãã´ãããã¾ãã","fashion":"ãã®ã«ãã´ãªã§ã¯ç¾ããã¹ã¿ã¤ãªãã·ã¥ãªæãè¦ã¤ãããã¨ãã§ãã¾ãã空æ³ã®ä¸ã«ããå®å®æä»£ã®{\"slug\": \"footwear\", \"title\":\"å±¥ç©\"}ã ã£ãããè¦ããã¨ã®ãªãç¼é¡ããã³ã¹ãã¬ç¨ã®{\"slug\": \"accessories\", \"title\":\"ã¢ã¯ã»ãµãªã¼\"}ãªã©ãé²è¦§ãã¾ãããã ","gadgets":"ãã®ã¬ã¸ã§ããã«ãã´ãªã§ã¯ããã¹ã¦ã®{ \"title\": \"iPhone\", \"slug\": \"iphone\"}ã{ \"title\": \"iPadã®\", \"slug\": \"ipad\"}ï¼ããã³ããã®ä»ã®ã¹ãã¼ãããã¤ã¹ï¼ãè¦ã¤ãããã¨ãã§ãã¾ããã·ã³ãã«ãª3Dã¢ããªã³ãããç·»å¯ãªãã®ã«ããã¢ã¤ãã ã®\"ã«ã¹ã¿ã \"ã¾ã§ã§ãã¾ããã¯ãªã¨ã¤ãã£ããªäººãã
16518ã¯ããã¸ã¼å¥½ãã®ããã®ã«ãã´ãªã§ãã","games-toys":"å°å·å¯è½ãª3Dã¨ã¤ãªã¢ã³ããããã¥ã¢ã®ã¢ã³ã¹ã¿ã¼ãå°ã㪠{\"slug\": \"tank\", \"title\": \"æ¦è»\"} ããä¸é¢¨å¤ãã£ã {\"slug\": \"chess\",\"title\":\"ãã§ã¹\"} ãæ ç»ã®ãã£ã©ã¯ã¿ã¼ã®ãã«ã¡ãããè¶£å³ã§éãããããªéå
·ãã¢ã¯ã»ãµãªã¼ãªã©ãå«ãã²ã¼ã ãããã¡ãã®ã«ãã´ãªã¼ã§ãã","hobby-diy":"ã¢ã¤ãã£ã¢ãã³ãDIYããã¸ã§ã¯ããæ§ç¯ãã人ã {\"slug\": \"drone\",\"title\":\"ããã¼ã³\"}ã®ã¹ãã¢ãã¼ããæ¬²ãã人ã«ã¯ãã¡ãã®ã«ãã´ãªã¼ãã´ã£ããã§ããããã«ãèªåç¨ã®ãã£ã®ã¥ã¢ããã©ã¹ããã¯éã®ã¬ããªã«ãä½ããã人ã®ããã®ã¢ãã«ãªã©ãæ§ã
ãªç¨®é¡ãæä¾ãã¦ãã¾ãã","house":"{\"slug\": \"Lamps\", \"title\": \"ã©ã³ã\"}ãã¢ã¼ãã£ã¹ãã£ãã¯ãª{\"slug\": \"bowl\", \"title\": \"ãç¿\"}ãåã³ã®ãããã種é¡ã®{\"slug\": \"holder\", \"title\": \"å
¥ãç©\"}ãå°ç©ã¯ãããã§è¦ã¤ãããã¨ãã§ãã¾ããæºã®ä¸ã«ã¯é»è©±ããã®ä»ãã³ãã¤ã¾ããããå®ç³é¡ãªã©ãç½®ããã¨ãã§ãã¾ãã","jewelry":"ãã¤ã¤ã¢ã³ããã¤ãã¦ãããã¬ã¹ã¬ããããã³ãã³ããã¾ãã¯ãªã³ã°ãªã©ãããã¸ã¥ã¨ãªã¼ã®ã«ãã´ãªã¼ã§ãã3Dããªã³ã¿ã§ãã¤ã¤ã¢ã³ããå°å·ããæè¡ã¯ã¾ã éçºããã¦ãã¾ããããIT好ãã®äººããããã¼ãºããçºã®éå±ã®ãªã³ã°ã®ãã¼ã¹ãä½ãã«ã¯ããã¿ãªããããã¾ããã","miniatures":"3Dããªã³ãå¯è½ãª{ \"slug\": \"character\", \"title\": \"æå\"}ãæå人ã{ \"slug\": \"landmark\", \"title\": \"æ¨è\"}ãåç©ã{ \"slug\": \"male\", \"title\": \"ç·æ§\"}ã{ \"slug\": \"female\", \"title\": \"女æ§\"}ã{ \"slug\": \"monster\", \"title\": \"ã¢ã³ã¹ã¿ã¼\"}ã{ \"slug\": \"alien\", \"title\": \"å¤å½äºº\"}ãªã©ã¯ãã¹ã¦ãã®ã«ãã´ãªã«ããã¾ããããªãããã¼ãã«ã®ä¸ã«ç½®ãããããªç¬èªã®ãã¼ã¯ã«ãå°å·ãããããã¼ãã«ã²ã¼ã ã®ãããã¥ã¢ã使ããå ´åããã®ã«ãã´ãªãã´ã£ããã§ãã","science":"ç§å¦ã«åé¡ãããã¢ãã«ã¨è¨ããã¦ãæ³åãä»ãã¥ããã§ããï¼ {\"slug\": \"bones\", \"title\":\"éª¨æ ¼\"} 模åã®ã¢ãã«ãå»å¸«ã使ã {\"slug\": \"tools\", \"title\":\"éå
·\"} ã天ä½ç©çå¦ã«é¢é£ããç©ãªã©ãå¤ãã®ç ç©¶ããã»ã¹ã§ä½¿ç¨ã§ãã3Dããªã³ãå¯è½ãªã¢ãã«ãè¦ã¤ããã«ãã´ãªã§ãã"}},"printable":{"art":"è¸è¡çãª3Dããªã³ããè¡ãã¨ããã§ããã§ã3D-å°å·å¯è½ãªãã´å¤å,æ´å²çãªæ§æ ¼ã®å¤å
¸ä½åã彫åãå使,ã¾ãã¯äººå½¢ãé¼èæ´¾æãªå½«å»ã®ãã¶ã¤ã³ããæ¢ãã§ããï¼ããã¯ã«ãã´ãªã§ãã\n","fashion":"ããªããçããã¨ãã§ããç¾ããã¹ã¿ã¤ãªãã·ã¥ãªãã®ã,ãã®ã«ãã´ãªã§çºè¦ããã¦ãã¾ããããªãã¯ç©ºæ³ã®å®å®æä»£{\"slug\":\"footwear\",\"title\":\"å±¥ç©\"}ã®ããã®ä»»æã®ä½¿ç¨ãè¦ã¤ãããã¨ãã§ãããã©ããã確èªã,æ°è¦æ§ã¬ã©ã¹ãã³ã¹ãã¬{\"slug\":\"accessories\",\"title\":\"ä»å±å\"}ãã¡ããã覧ãã ããã\n","gadgets":"ãã¹ã¦{ \"title\": \"iPhone\", \"slug\": \"iphone\"},{ \"title\": \"iPadã®\", \"slug\": \"ipad\"}ï¼ã®ããã³ä»ã®ã¹ãã¼ãããã¤ã¹ï¼ã®å ´åã¯,ã¬ã¸ã§ããã®ã«ãã´ãªã¼ã§è¦ã¤ãããã¨ãã§ãã¾ããã·ã³ãã«ãª3Dããã¢ããªã³è¤éãªé¨åããã³\"ããã¯\"ã«ããªãã®é
ç®ã®ããã«,ããã¯ã¯ãªã¨ã¤ãã£ã,æè¡ã®æå¥½å®¶ã®ããã®ã«ãã´ãªã§ãã\n","games-toys":"ã²ã¼ã ,ããã¡ã,å°å·å¯è½ãª3Dã¨ã¤ãªã¢ã³ãã¢ã³ã¹ã¿ã¼ã®ãããã¥ã¢ãã«ãã¼ã,ã«ãã´ãª,å°ããª{\"title\":\"æ¦è»\",\"slug\":\"tank\"}ã§,ãã¡ã³ãã¼{\"slug\":\"chess\",\"title\":\"ãã§ã¹\"}ä½å,æ ç»ã®ãã£ã©ã¯ã¿ã¼ãã«ã¡ãã,è¶£å³éå
·ãã¢ã¯ã»ãµãªã¼ãããã¯,ãã¹ã¦ã®ç©äºã®ãªã¿ã¯ã®ããã®to-Goã®ã«ãã´ãªã§ãã\n","hobby-diy":"ããªããç§ãã¡ã®æ¬¡ã®å大ãªçºæè
ã§ãã,ããªãã®DIYããã¸ã§ã¯ããæ§ç¯ããã,{\"slug\":\"drone\",\"title\":\"ããã¼ã³\"}ã®ããã®ããã¤ãã®ã¹ãã¢ãã¼ããåå¾ãããå ´åã¯,ããã¯ããå ´æã§ããããã«,ããã¯èªåã®ãã£ã®ã¥ã¢ããã©ã¹ããã¯éã®ã¬ããªã«ãä½ããã人ã®ããã«ããããã®ãã®ãæä¾ãã¦ãã¾ãã\n","house":"å°ç©ã®ãã¹ã¦ã®ç¨®é¡ã¯,ããã§è¦ã¤ãããã¨ãã§ãã¾ãã {\"title\":\"ã©ã³ã\",\"slug\":\"lamp\"},è¸è¡{\"title\":\"ãã¦ã«\",\"slug\":\"bowl\"},åã³ã®ãã¹ã¦ã®ç¨®é¡{\"title\":\"ãã«ã\", \"slug\":\"holder\"}ããªãã¯,ããªãã®æºå¸¯é»è©±ã®ããã®å³ã®å ´æãè¦ã¤ããçªæ¥æ,ããªãã®æºã®ä¸ã«ãã³ãå®ç³ã®å±±ã®ç§©åºãç¶æãããã¨ã¯ã§ãã¾ãããã\n","jewelry":"ããªãã¯ãã¤ã¤ã¢ã³ããã¬ã¹ã¬ããããã³ãã³ãããªã³ã°ãå¾ãããã«è¡ãã¨ããã¸ã¥ã¨ãªã¼ã§ããã¾ã - - 3Dããªã³ã¿ã¯,ãã¤ã¤ã¢ã³ããä½ãããã®è¯ãååã§ã¯ããã¾ããã,ããªãã¯ã¾ã ããªãã®ITãªã¿ã¯ã®ææ¡ãªã³ã°ã®ãã¼ã¹ã¨ãã¦éå±è£½ã®ãªã³ã°ãããªã³ãã¢ã¦ããããã¨ãã§ãã¾ãã\n","miniatures":"3Då°å·å¯è½{ \"title\": \"æå\", \"slug\": \"character\"},æåãªäºº,{ \"title\": \"ã©ã³ããã¼ã¯\", \"slug\": \"landmark\"},åç©,{ \"title\":\"ç·æ§\",\"slug\": \"male\"}
16518,{ \"slug\": \"female\",\"title\":\"女æ§\"},{ \"title\": \"ã¢ã³ã¹ã¿ã¼\", \"slug\": \"monster\"},{ \"title\": \"å¤å½äºº\",\"slug\": \"alien\"}㯠- ããã¯,ããã§ãã¹ã¦ã§ããããªãããã¼ãã«ã®ä¸ã«ç½®ãããã«ã¦ã¼ãã£ãªãã£ãã¼ã¯ã«ãå°å·ããã,ãã¼ãã«ã²ã¼ã ã®ããã®ãããã¥ã¢ã使ãã¦ãããã©ãã,ããã¯ããªãã®ã«ãã´ãªã§ãã\n","science":"ä½ãç§å¦ã¨ãã¦åé¡ãããã¨ãã§ãã¾ããï¼ãã¦,ã¹ã±ã«ãã³ã®ã¢ãã«{\"slug\":\"bones\",\"title\":\"éª¨æ ¼\"},å»å¸«{\"slug\":\"tools\",\"title\":\"ãã¼ã«\"}ã¨å¤ãã®ç ç©¶ã®éç¨ã§ä½¿ç¨ãããã¨ãã§ãã天ä½ç©çå¦ã«é¢é£ãã3次å
å°å·å¯è½ãªã¢ãã«ã\n"},"titles":{"aircraft":"èªç©ºæ©3Dã¢ãã«","animals":"åç©3Dã¢ãã«","architectural":"建ç¯3Dã¢ãã«","car":"è»3Dã¢ãã«","character":"ãã£ã©ã¯ã¿ã¼3Dã¢ãã«","exterior":"å¤è£
3Dã¢ãã«","food":"é£å3Dã¢ãã«","furniture":"å®¶å
·3Dã¢ãã«","household":"å®¶åºç¨3Dã¢ãã«","industrial":"ç£æ¥ç¨3Dã¢ãã«","interior":"ã¤ã³ããªã¢3Dã¢ãã«","military":"ããªã¿ãªã¼3Dã¢ãã«","plant":"æ¤ç©3Dã¢ãã«","space":"å®å®3Dã¢ãã«","textures":"CGãã¯ã¹ãã£3Dã¢ãã«","vehicle":"ä¹ãç©3Dã¢ãã«","watercraft":"è¹è¶3Dã¢ãã«"}},"title":{"cg":" 3Dã¢ãã«","print":" 3Dããªã³ããã¡ã¤ã«"}}
16518,"competition":{"digital-art-competition":{"categories":{"page_description":"ãã£ã©ã¯ã¿ã¼ã¤ã©ã¹ãããã£ã©ã¯ã¿ã¼ã³ã³ã»ãããã¶ã¤ã³ãç°å¢ã¤ã©ã¹ããç°å¢ã³ã³ã»ãããã¶ã¤ã³ããªãã¸ã§ã¯ãã®ãã¶ã¤ã³ãããã³ãªãã¸ã§ã¯ãã³ã³ã»ãããã¶ã¤ã³ã«ãã´ãªã«ããªãã®ä½åãæåºãããã¨ã«ãã£ã¦CGTraderãã¸ã¿ã«ã¢ã¼ãã³ã³ãã«åå ãã¦ãã¾ããããªããç°ãªãã«ãã´ãªã«åããã¦ãããã¤ãã®ç´ æ´ãããä½åãæã£ã¦ããå ´åã¯ã該å½ããã«ãã´ãªã«æåºãã¦èªç±ã«æãã¾ãããã®ã«ãã´ãªã®è³ãåç
§ããã«ã¯ã«ãã´ãªã¼ã鏿ãã¾ãã"}}},"conversations":{"action_button_confirmation":"ãã®ãªã¯ã¨ã¹ããæ¬å½ã«åéãã¾ããï¼","reply_posted":"è¿ä¿¡ãæç¨¿ããã¾ããã","with_yourself":"éä¿¡è
ã¨åãã«ãããã¨ã¯ã§ãã¾ããã"},"date":{"month_names":[null,"1æ","2æ","3æ","4æ","5æ","6æ","7æ","8æ","9æ","10æ","11æ","12æ"]},"devise":{"failure":{"too_many_requests":"ãã¹ã¯ã¼ããªã»ããã®ã¡ã¼ã«ã¯æ¢ã«ãªã¯ã¨ã¹ãããã¦ãã¾ããæ°åå¾
ã£ã¦ããå度ã試ããã ããã"}},"disabled_cookies_modal":{"button":"ãã£ã³ã»ã«","text_1":"ããªãã¯ãå大ãª3Dã¢ãã«ã®ä½ç¾ä¸äººãæ¢ãã«ã¼ããè³¼å
¥ã«ãããã追å ã§ããªããªãã¾ãã","text_2":"ããªãã¯å®å
¨ã«CGTraderãä½é¨ããããªãã°ãæã
ã¯ãã®ãµã¤ãã§Cookieãæå¹ã«å¥¨å±ãã¾ãã","title":"ããªãã®ãã©ã¦ã¶ã®ã¯ããã¼ãç¡å¹ã«ãªã£ã¦ãããã§ã"},"emails":{"error_notification":"è³¼èªãè¦ã¤ããã¾ããã","success_subscribed_notification":"è³¼èªã«æåãã¾ããã","success_unsubscribed_notification":"è³¼èªãæ£å¸¸ã«è§£é¤ãã¾ããã"},"file_size_validator":{"errors":{"invalid_carrierwave":"CarrierWave::Uploader::Base ãªãã¸ã§ã¯ããå¿
è¦ã§ã","invalid_key":":%{key} ã¯éè² ã®æ´æ°ã§ãªããã°ãªãã¾ãã","range_format":":in 㨠:within ã¯ç¯å² (Range) ã§ãªããã°ãªãã¾ãã","range_unspecified":"ç¯å²ãæå®ããã¦ãã¾ããã:withinã:maximumã:minimumãã¾ã㯠:is ãªãã·ã§ã³ãæå®ãã¦ãã ããã"}},"file_type":{"default_error":"ãã¡ã¤ã«ã¸ã®ãã¹ãæå®ããã¦ãã¾ããã"},"footer":{"bottom-row":{"privacy":"ãã©ã¤ãã·ã¼","terms-link":"å©ç¨è¦ç´"},"links":{"buyLinks":[{"text":"3Dã¢ãã«ãè³¼å
¥","link":"/ja/3d-models"},{"text":"ãã¸ãã¹åã","link":"/discover/business-account"},{"text":"ç¡æã®3Dãã¼ã¿ã»ãã","link":"/discover/datasets"},{"text":"3Dãã¶ã¤ãã¼ãéã","link":"/3d-modeling-jobs"},{"text":"ç¡æã®3Dã¢ãã«","link":"/ja/free-3d-models"},{"text":"ç¡æã®3Då°å·ã¢ãã«","link":"/ja/free-3d-print-models"}],"communityLinks":[{"text":"ã³ãã¥ããã£","link":""},{"text":"ããããã¶ã¤ãã¼","link":"/designers"},{"text":"ãã£ã¬ã³ã¸","link":"/challenges"},{"text":"ãã©ã¼ã©ã ","link":"/forum"}],"companyLinks":[{"text":"ä¼ç¤¾","link":"/discover/about-us"},{"text":"ããã°","link":"/blog"},{"text":"ãã£ãªã¢","link":"/pages/careers"},{"text":"ãã«ãã»ã³ã¿ã¼","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"3Dã¢ãã«ã販売","link":"/discover/sell-3d-models"},{"text":"売ä¸ã伸ã°ã","link":"/discover/sell-more"},{"text":"3Dãã¼ã±ããã¤ã³ãµã¤ã","link":"/discover/3d-market-trends"},{"text":"人æ°ã®3Dã¢ãã«æ¤ç´¢","link":"/discover/3d-models-top-searches"},{"text":"人æ°ã®3Då°å·æ¤ç´¢","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"ç»é²","button-disabled":"ç»é²ãã¾ãã","header":"å½ç¤¾ã®ãã¥ã¼ã¹ã«ç»é²ï¼","placeholder":"ã¡ã¼ã«ã¢ãã¬ã¹ãå
¥å","terms-link":"å©ç¨è¦ç´","text":"ç»é²ãããã¨ã«ãããããªãã¯å½ç¤¾ã®(Terms of Use)ãèªãã§åæããã¨ã¿ãªããã¾ã"}},"general":{"description":"CGTraderã¯ã3Dã¢ã¼ãã£ã¹ãããã¶ã¤ãã¼ã3Dã¢ãã«ãè³¼å
¥ã売å´ã¾ãã¯å
±æã§ãããªã³ã©ã¤ã³å¸å ´ã§ããããã¯ãè¨ç«ãããã¨3Dãã¶ã¤ãã¼ã¨ã¨ã³ã¸ãã¢ã®ãã¼ã ã«ãã£ã¦éçºããã¦ãã¾ããç§ãã¡ã®ç®æ¨ã¯ã3Dã®æ ªå¼å¸å ´ãæ°ä¸»åããæã
ã¯ããªã³ã©ã¤ã³3Dã¢ãã«ã販売ããæ¹æ³ã夿´ãããã¨ã§ã
16518ãèè
ã¯æå¤§ã®ãã¤ã¤ãªãã£ãç²å¾ããããã¨ã«ãã£ã¦ãæã
ã¯å½¼ãã®ã¢ããã¼ã·ã§ã³ãé«ãã3Dã¢ãã«ã®å質ãé«ããããã«åªåãã¦ãã¾ãã","navigation":{"buy_3d_models":"3Dã¢ãã«ãè³¼å
¥","sell_3d_models":"3Dã¢ãã«ã販売"},"search_placeholder":"200ä¸ä»¥ä¸ã®ã¢ãã«ãæ¤ç´¢","site-search__field":"%{model_count}件以ä¸ã®3Dã¢ãã«ãæ¤ç´¢","site_title":"3Dã¢ãã«é販","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"AIãããªãã®å¤¢ãå®ç¾ãã¾ã","subtitle":"ããã³ãããåèç»åãæ¬çªç°å¢ã«å¯¾å¿ãã3Dã¢ãã«ã«å¤æãããªãã¡ã¤ã³ã»ãªãã¯ã¹ãã£ãªã³ ã°ãã¦å¿
è¦ãªå½¢å¼ã§ã¨ã¯ã¹ãã¼ããã¦ãã ããã"},"faq":{"heading":"ãããã質å","items":{"commercial":{"answer":"%{object}ã®3Dã¢ãã«ã®åæ¥å©ç¨ã¯ãCGTrader AIã®ææãã©ã³ã§å©ç¨ã§ãã¾ããAIçæã¢ã ã«ã«é©ç¨ãããã©ã¤ã»ã³ã¹æ¡ä»¶ã«ã¤ãã¦ã¯ãCGTraderã®å©ç¨è¦ç´ãã確èªãã ããã","question":"çæãã%{object}ã¢ãã«ã忥ç®çã§ä½¿ç¨ã§ãã¾ããï¼"},"formats":{"answer":"%{object}ã®3Dã¢ãã«ã¯GLBãFBXãOBJãSTLãUSDZå½¢å¼ã§å©ç¨ã§ãã¾ãã","question":"ã©ã®ãã¡ã¤ã«å½¢å¼ã§%{object}ã¢ãã«ãåå¾ã§ãã¾ããï¼"},"no_skills":{"answer":"3Dã¢ããªã³ã°ã®ç¥èã¯ä¸è¦ã§ãããã¹ã¦ã®ã¢ããªã³ã°ã¯%{object}ã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ãé ãã¦è¡ããã¾ããããã³ãããå
¥åãããç»åãã¢ãããã¼ãããã¨ãã·ã¹ãã ãèªåçã«ã¸ ãªã¡ããªããããã¼ã·ã§ã³ãæ§é ãå¦çãã¾ããåå¿è
ã§ãæ°åã§å
æ¬çãª%{object}ã®3D ã¢ãã«ã使ã§ãã¾ãã","question":"%{object}ã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ã®ä½¿ç¨ã«3Dã¢ããªã³ã°ã®ç¥èã¯å¿
è¦ã§ããï¼"},"what_is":{"answer":"CGTrader 3D %{object}ã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ã¯ãAIãã¼ã¹ã®ãã¼ã«ã§ãããã¹ãæç¤ºãåè ç»åãã%{object}ã®3Dã¢ãã«ã使ãã¾ããã¢ã¤ãã¢ãåæãããã¶ã¤ã³ã»ãããã¿ã¤ãã³ ã°ã»å¯è¦åã®ããã®ãã¦ã³ãã¼ãå¯è½ãªã¢ãã«ã使ãã¾ããææãµãã¹ã¯ãªãã·ã§ã³ã§ã¯ã ããé«ãæéä¸éãæä¾ããã¾ãã","question":"3D %{object}ã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ã¨ã¯ä½ã§ããï¼"},"why_cgtrader":{"answer":"CGTraderã¯ã¹ã ã¼ãºãªä½é¨ãé«éãªå¦çæéãé«å質ãª3Dåºåãæä¾ãã¾ãããã®ãã¼ã«ã¯ %{object}ã®3Dã¢ãã«ã使ããããã®ä¿¡é ¼æ§ã®é«ãã½ãªã¥ã¼ã·ã§ã³ãæ±ãããããã§ãã·ã§ ãã«ã¨åå¿è
ã®ä¸¡æ¹ã«é©ãã¦ãã¾ãã","question":"CGTraderã®AI %{object}ã¸ã§ãã¬ã¼ã¿ã¼ã使ç¨ããçç±ã¯ï¼"}}},"h1":"AI %{object} 3Dã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼","hero_alt":"AI %{object} 3Dã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼","hero_height":617,"hero_width":1080,"how_to":{"heading":"ç»åã¾ãã¯ããã¹ãããã³ãããã%{object}ãçæãã","paragraphs":["%{object}ã®3Dã¢ãã«ã®è¨è¨ã¯é常ã«ç°¡åã§ããå·¦ãµã¤ããã¼ã®å·¦ä¸ã«ãããã¿ã³ãã¯ãªã㯠ãã¦%{object}ã®ç»åãã¢ãããã¼ããã3Dã¢ãã«ã使ãã¾ããã¾ããä¸é¨ã®ã使ããã ãã®ã説æãã¦ãã ããããã£ã¼ã«ãã«ããã³ãããå
¥åãããã¨ãã§ãã¾ããCGTrader AI ãããã³ãããèªåçã«æ´ç·´ããããããçã説æã§ååã§ãã","å³å´ã®ãµã¤ããã¼ã§ã¯ã%{object}ã®3Dã¢ãã«ãç´°ããå¶å¾¡ã§ãã¾ããã¡ãã·ã¥ã¿ã¤ãããã ãªã¢ã«ãããã³ããã¬ã¤ãã³ã¹ããã¡ã¤ã«å½¢å¼ãªã©ã®è¨å®ã鏿ãã¦ãã ããããã¯ã¹ãã£ãªã³ ã°ã§%{object}ã¢ãã«ãã«ã¹ã¿ãã¤ãºãããã¨ãå¯è½ã§ããããã¹ãæç¤ºã¾ãã¯ç»åãå
¥åãã å¾ããçæããã¯ãªãã¯ãã¦ãã ãããã·ã¹ãã ã®è² è·ããããªã¢ã«ãã¡ãã·ã¥ã¿ã¤ããå½¢ç¶ã ã
16518·ã¼ãå¤ãå質ã«ãã£ã¦ç°ãªãã¾ãããæ°åã§å¦çããã¾ãã"],"steps":["ããã¹ã説æãå
¥åããåèç»åãæ·»ä»ãããã¨ã§ã%{object}ã®3Dã¢ãã«ã®æçµçãªç²¾åº¦ã åä¸ããã¦ãã ããã","ããªã»ãããã鏿ããããAIã¨ã³ã¸ã³ã鏿ããã«ã¹ã¿ã ããªã´ã³æ°ãè¨å®ãã¦ã%{object} ã®3Dã¢ãã«ã®ãããªã¢ã«ã¿ã¤ãã鏿ãã¦ãã ããã","ãçæããã¯ãªãã¯ãã¦ãããã³ããã¨åèç»åãã%{object}ã®3Dã¢ãã«ã使ãã¦ãã ããã","使ãã%{object}ã®3Dã¢ãã«ãGLBãFBXãOBJãSTLãUSDZãªã©ã®ãã¾ãã¾ãªå½¢å¼ã§ãã¦ã³ ãã¼ããã¦ãã ããã"]},"intro":"æ°åã§é«å質ãª%{object}ã®3Dã¢ãã«ã使ããç°¡åã§è¿
éãªæ¹æ³ããæ¢ãã§ããï¼é«åº¦ãª %{object} 3Dã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ãCGTrader AIãã¯ãããã¹ãæç¤ºãåèç»åãå®å
¨ã« æ©è½ããã¢ãã«ã«å¤æãã¾ããMeshyãHunyuanãTripo3Dãªã©ã®æå
端ã®3Dçæã¨ã³ã¸ã³ã§ åä½ãããã¶ã¤ã³åå¿è
ããå°éå®¶ã¾ã§ãå¯è¦åã»å®é¨ã»ãããã¿ã¤ãã³ã°ã®ããã®3Dã¢ãã« ãç´ æ©ã使ã§ãã¾ããããã¹ããã3Dããã³ç»åãã3Dã«å¯¾å¿ãã3Dããªã³ã¿ã¼ã¨ãäºææ§ ãããã¾ããJPGã¾ãã¯PNGå½¢å¼ã®ç»åãã¢ãããã¼ãããããããã¹ãã§èª¬æãå
¥åãã¦ãã ãããCGTrader AIãæ®ãã®æé ã代ããã«è¡ãã¾ãã","meta_description":"CGTrader AI %{object} 3Dã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ âï¸ ããã¹ããç»åãã精細ãª%{object}ã®3Dã¢ãã«ãçæãä»ããç¡æã§å§ãã¾ãããã","primary_cta":"ç¡æã§çæãéå§","title":"AI %{object} 3Dã¢ãã«ã¸ã§ãã¬ã¼ã¿ã¼ï¼ç¡æï¼| CGTrader"}}},"rules":{"errors":{"front_view_required":"æ£é¢ãã¥ã¼ã®ç»åãå¿
è¦ã§ãã"}}},"home":{"index":{"3D-projects":{"info-section__cta":"ãã£ã¨è©³ããç¥ã","info-section__description":"ã¨ããµã¤ãã£ã³ã°ãª3Dããã¸ã§ã¯ããæã¤äººã
ãæè½ãª3Dãã¶ã¤ãã¼ã¨åºä¼ãå ´æ","info-section__heading_html":"\u003cstrong\u003e 3Dããã¸ã§ã¯ã\u003c/strong\u003eããªã¼ã©ã³ã¹ãã"},"categories-conatainer":{"browse_all":"ãã¹ã¦ã®ã¢ãã«ãé²è¦§","browse_all_tooltip":"ãã¹ã¦ã®3Dã¢ãã«ããã©ã¦ãº","discounts":"å²å¼"},"cgdream":{"cta":"ç¡æã§å§ãã¾ããã","heading_html":"\u003cstrong\u003eCGDream ãæ¢ç´¢,\u003c/strong\u003e\u003c/br\u003e ããã§AIã¨3Dã¢ãã«ãåºä¼ãã","text_html":"\u003cstrong\u003e CGDream \u003c/strong\u003eã¯ãçæAIããã³3Dã¢ãã«ã®åãæ´»ç¨ãã¦ãè¦äºãª2Dç»åãçæããæå
端ã®ã¢ããªã±ã¼ã·ã§ã³ã§ãã \u003cstrong\u003e ããªãã®åµé çãªæ
ãä»å§ã¾ãã¾ãã\u003c/strong\u003e"},"community":{"info-section__cta":"ã³ãã¥ããã£ã«åå ","info-section__heading_html":"CGTraderã®\u003cstrong\u003eã³ãã¥ããã£\u003c/strong\u003eã«åå ","info-section__icon-list_1":{"description":"ã¬ã³ããªã³ã°ããªãã®æé«ã®ã·ã§ã¼ã±ã¼ã¹ããã£ã¼ãããã¯ã¨ã®èªèãå¾ã¾ã","heading":"ã®ã£ã©ãªã¼"},"info-section__icon-list_2":{"description":"æ°ããã¹ãã«ãå¦ã³ãä»ã®äººã«æãã","heading":"ãã¥ã¼ããªã¢ã«"},"info-section__icon-list_3":{"description":"ãã¥ã¼ããªã¢ã«ãè¦ã¤ããä»ã®3Dé¢é£ã®åé¡ãè°è«ãã","heading":"ãã©ã¼ã©ã "}},"covid":{"timer-strip__item":"COVID-19ã®ä¿è·ã®ããã®ç¡æã®3Dããªã³ããå¯è½ãªãªã½ã¼ã¹","timer-strip__item--button":"3Dã¢ãã«ããã©ã¦ãº"},"enterprise":{"info-section__cta":"ãã£ã¨è©³ããç¥ã","info-section__heading_html":"\u003cstrong\u003eã¨ã³ã¿ã¼ãã©ã¤ãº\u003c/strong\u003eåãã®3Dãµã¼ãã¹","info-section__icon-list_1":"ç§ãã¡ã¯ããªãã®ããã®ARå®è£
ãè¡ããã¨ãã§ãã¾ã","info-section__icon-list_2":"ããå¤ãã®è²©å£²ã³ã³ãã¼ã¸ã§ã³ããã¡å°ãªãè¿å","info-section__icon-list_3":"峿 ¼ãªQAã§å質ãä¿è¨¼ããã¦ãã¾ã"},"header":"VR / ARã3Dããªã³ãã¨ã³ã³ãã¥ã¼tagã©ãã£ãã¯ã¹ã®ããã®3Dã¢ãã«","marketplace":{"info-section__description":"ã²ã¼ã ãAR / VRãåºåãã¢ãã¡ã¼ã·ã§ã³ãæ ç»ã3Dããªã³ããªã©ã®ã¢ããªã±ã¼ã·ã§ã³ã3Dã¢ãã«%{models_count}ãã鏿","info-section__heading_html":"3Dã¢ãã«\u003cstrong\u003eå¸å ´\u003c/strong\u003e","info-section__image-list_1":{"de
16518scription":"ããªãã®ããã¸ã§ã¯ãã®ããã®ãããã§ãã·ã§ãã«ãª3Dã¢ãã«ãè³¼å
¥","heading":"3Dã¢ãã«"},"info-section__image-list_2":{"description":"ãããªã²ã¼ã ãVRï¼ARãªã¢ã«ã¿ã¤ã ã¢ããªã±ã¼ã·ã§ã³ã®ããã®ä½ããªPBRã®3Dã¢ãã«","heading":"ä½ããªPBR 3Dã¢ãã«"},"info-section__image-list_3":{"description":"3Dããªã³ã¿ã¼ã®ããã®3Dããªã³ããã¶ã¤ã³ãè¦ã¤ãããã¾ãã","heading":"3Dããªã³ãã¢ãã«"},"view_all":"ãã¹ã¦è¡¨ç¤º"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"ç»åã3Dã¢ãã«ã«å¤æ","title":"ç»åãã3D"},"text_to_3d":{"description":"ã¢ã¤ãã¢ã説æãã¦3Dã¢ãã«ã使","title":"ããã¹ããã3D"}},"ai_section_title":"AIã§ä½æ","aria_label":"æ¤ç´¢åè£","columns":{"cg":{"search_label":"3Dã¢ãã«ãæ¤ç´¢","title":"3Dã¢ãã«"},"print":{"search_label":"3Dããªã³ããæ¤ç´¢","title":"3Dããªã³ãã¢ãã«"}}},"sell":{"info-section__heading_html":"3Dã¢ãã«ã\u003cstrong\u003e販売\u003c/strong\u003eããããªã¼ã©ã³ã¹ããã¸ã§ã¯ããè¦ã¤ãã","info-section__icon-list_1":{"description":"3Dã¢ãã«ã販売ãã¦85%ã®å°ç¨ã¾ã§ç²å¾ãã¾ã","link":"3Dã¢ãã«ã販売\u003e"},"info-section__icon-list_2":{"description":"ã¨ã³ã¿ã¼ãã©ã¤ãºã¯ã©ã¤ã¢ã³ãã¨ä»äºãä¸ç·ã«åã","link":"\u003eèªå®ãåå¾"},"info-section__icon-list_3":{"description":"ã¹ãã«ã夿³¨ãã¦95%ã®å°ç¨ã¾ã§åå¾ãã¾ã","link":"3Dã¢ããªã³ã°ã¸ã§ããºããã©ã¦ãº"},"info-section__icon-list_4":{"description":"èªåã®ãã¼ããã©ãªãªãæ§ç¯ãã表示ãããããã«ãªãã","link":"3Dãã¶ã¤ãã¼ããã©ã¦ãº\u003e"}},"seo":{"description":"200ä¸ä»¥ä¸ã®ãªã³ã©ã¤ã³3Dã¢ãã«ãæ¢ç´¢ãã¾ããããããªã³ããã²ã¼ã ãVR/ARããã¶ã¤ã³ããã¸ã§ã¯ãç¨ãCGTraderã§ãã¦ã³ãã¼ããã«ã¹ã¿ãã¤ãºãã¾ãã¯3Dã¨ãã¹ãã¼ããéç¨ã§ãã¾ãã","title":"CGTrader - 3Dã¢ãã«ã¨3Dããªã³ããã¼ã±ãããã¬ã¤ã¹"}}},"homepage":{"budget_counter":{"range_0_10":"10ãã«æªæº","range_10_20":"10ãã« - 20ãã«","range_20_15000":"20ãã«ä»¥ä¸"},"quotes":{"quote_0":{"author":{"name":"ãã¢ã³ã»ã«ã«ãã¹ã»ãã¡ãã¹","username":"CGShape"},"text":"ä½ãææ°æã¯å£²ãæææ®µãããã¤ã¤ã¼ã®ããã®ããè¯ãä¾¡æ ¼ãæ®å½±ãã¾ããããã§ãã¯ã¢ã¦ãããCGTraderã®ä¾¡æ ¼ããã®ä»ã®ãåºãæ¯è¼ãã¾ãã"},"quote_1":{"author":{"name":"ãã¢ã³ã»ã«ã«ãã¹ã»ãã¡ãã¹","username":"CGShape"},"text":"CGTraderã®æãé¡èãªå©ç¹ã¯ãé«ãåçãããããå®é¡å¶ã¢ã¯ãã£ãã¼ã·ã§ã³ã·ã¹ãã ã§ãã ããªãã¯å½ç¤¾ã®å£²ä¸ã®ææ°æã®å²åãåã£ã¦ãã¾ããã ã»ã¼ã«çµäºå¾ã100%ã®ä»£éãé æ´ãããã¾ãã ãã®è£½åã®è²©å£²ãç¶ç¶ããå ´åã«ã®ã¿ã5ãã«ãæ¯æããã¨ã§å度æå¹åã§ãã¾ãã ã¨ã¬ã¬ã³ããªã½ãªã¥ã¼ã·ã§ã³ã§ãã"},"quote_10":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"å®é¡å¶ã¢ã¯ãã£ãã¼ã·ã§ã³ã·ã¹ãã ã¯ç¬åµçã§ãã ãªãããã¾ã§èª°ããããèããªã
16518ã£ãã®ãã¨æã£ã¦ãã¾ããã 販売å¾ã製åãã¢ã¯ãã£ãã¼ãããããã«å°é¡ã®ææ°æãæ¯æãã ãã§ãã 売ãæã¯å®å
¨ã«å¶å¾¡ããã¦ãã¾ãã"},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"CGTraderã«ã¤ãã¦ç§ãæãæ°ã«å
¥ã£ã¦ããç¹ã¯2ã¤ããã¾ãã ã¾ããããã«ã¯ä½ãé ãããæå³ã¯ããã¾ããã CGTraderã«æ³¨æããå¿
è¦ã¯ããã¾ããã 2ã¤ç®ã¯ããã®ã¹ãã¢ã¯ã¢ã¼ãã£ã¹ãã«ãããã¢ã¼ãã£ã¹ãã®ããã«ã§ãã å½¼ãã¯ããªããããããçè§£ãã¦ãã¾ãã ä½ããããªããããã§æ©ã¾ãã¦ãã¾ããï¼...å½¼ãã«ç¥ããã¦ãã ãããããã¦å½¼ãã¯ããªããããã§å¿«é©ã«æãããã¨ã確èªãã¾ãã"},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"å®é¡å¶ã¢ã¯ãã£ãã¼ã·ã§ã³ã·ã¹ãã ãæé«ï¼ ï¼å°ãªãã¨ãç§ã¯ããããè¯ããã®ã«ééãã¦ãã¾ããï¼ã ããã¯å£²ãæã«ã¨ã£ã¦é常ã«ç¾å®çã§å
¬å¹³ã§ãã å½¼ãã¯ããªããã©ãã ãã®å©çãä¸ããããæ°ã«ãããåºå®å®¶è³ãæ¯æãã ãã§ãã ãã ãã売ãä¸ãããªãå ´åã§ãå®¶è³ãæãå¿
è¦ã¯ããã¾ããã ãã§ã¢CGTraderã¯ãã¡ãï¼"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"ä¾¡æ ¼ãä»ã®åºãããå®ããããCGTraderã¯çºå±éä¸å½ããã§ã顧客ãå¼ãä»ãã¾ãã åæã«ãé«ãææ°æçãªã©ããªããããèè
ã¯ããå¤ãã®åå
¥ãå¾ããã¨ãã§ãã¾ãã ããã¯ã3Dã¢ã¼ãã£ã¹ãã®ä½åãè©ä¾¡ããæ£ããæ¹æ³ã§ãã"},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"ãããªãã·ã£ã¼ã®ç´æçãªã¤ã³ã¿ã¼ãã§ã¤ã¹ã¨ãtagã®æ¨å¥¨ãæè»ãªèª¬æãã©ã¼ã ãªã©ã®é©æ°çãªãã¼ã«ã«ããããããªãã·ã³ã°ããã»ã¹ãç°¡åãã¤è¿
éã«ãªãã¾ãã"},"quote_15":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"3Dã販売ããCGTraderã®ã¢ããã¼ãã¯ç°ãªããç§ã以å販売ãã¦ããä»ã®ã¹ãã¢ã¨å
±éç¹ã¯ããã¾ããã ã»ã¼ã«å¾ã«5 $ã®ä½æéãæ¯æãã®ã¯ç´ æ´ãããã¢ã¤ãã¢ã§ãããããã§æä½ä¾¡æ ¼ãæä¾ãããã¨ãã§ãã¾ãã 顧客ã¨ã¢ã¼ãã£ã¹ãã¯ããã®ãããªåãæ¹ã®æ©æµãåãã¦ãã¾ãã"},"quote_16":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"ã¢ãããã¼ãã·ã¹ãã ã¯ç°¡åã§æç¢ºã§ãã ããã¸ã§ã¯ãã®èå¾ã«ã¯ãã³ã³ãã¥ã¼tagã©ãã£ãã¯ã®åé¡ã§é·å¹´ã®çµé¨ãæã¤äººã
ããããã¨ãç¥ã£ã¦ããã®ã¯è¯ããã¨ã§ãã åé¡ãçºçããã¨ãã¯ãã¤ã§ããCGTraderãã¼ã ãè¿
éã«ä¿®æ£ãã¾ããã"},"quote_17":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTraderã使ç¨ããã¨ãèªåã®ãããã¡ã¤ã«ãå人ã®ã¦ã§ããã¼ã¸ã«é£çµã§ãã¾ãã è³¼å
¥ãããã¢ã¤ãã ã®ç¹æ§ãããããªãå ´åãã夿´ãããå ´åã¯ãã客æ§ããé£çµ¡ãåãããã¨ãã§ãã¾ãã 大ããªå¸å ´ã§å人ã®3Dã¹ãã¢ãææãã¦ãããããªãã®ã§ãã"},"quote_2":{"author":{"name":"ãã¢ã³ã»ã«ã«ãã¹ã»ãã¡ãã¹","username":"CGShape"},"text":"ç§ãã¡ã¯ãCGTraderãã¼ã ããç´ æ´ãããã¨è¿
éãªãµãã¼ããæ¥½ããã§ãã¾ãããã¹ã¿ããã親åãããã®å£²ãæã®ããã®å¤§ããªå©ãã§ããç§ãã¡ã®ããã«ãã¹ã¦ã®ã¢ãã«ã®å
¬éããè¡ããã¨ãç³ãåºã¾ããã"},"quote_3":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"ãã®ãã©ãããã©ã¼ã ã§ã¯ãã客æ§ã«ããè¯ãä¾¡æ ¼ãæä¾ã§ãã¾ãã ä¾ãã°ãå½ç¤¾ã®ãã¹ã¦ã®è£½åã®ä¾¡æ ¼ã¯ä»ã®ã©ãããã20%å®ããä»ã®åºã¨æ¯ã¹ã¦ããå¤ãã®å©çãå¾ã¦ãã¾ãï¼"},"quote_4":{"author":{"name":"ãã¹ã¹ã»ããããµã´ã£ãã«","username":"NoneCG"},"text":"ããã¯ãããã¾ã§ã®æé©ãªã·ã¹ãã ã§ããä»ã®ãã¹ã¦ã®ãªã³ã©ã¤ã³ã®3Dåºã¯ãå½ç¤¾ã®å©çãã%ãåãã¾ããããã¯ãæåããCGTraderã§ç§ãã¡ã®é¢å¿ãå¼ããæ©è½ã§ããã顧客ãCGTraderã®è²·ãããå½¼ãã®å©çãæ¹åãããå ´åãæçµçã«ã¯ããå¤ãã®ãããè¯ãã¢ãã«ãä½ãä½è
ã«å½¼ãã®ãéããå¤åºå
ã®å¤§é¨åãããã¨ãç¥ã£ã¦ãã¾ãã"},"quote_5":{"author":{"name":"ãã¹ã¹ã»ããããµã´ã£ãã«","username":"NoneCG"},"text":"CGTraderã¯ãç§ãã¡ã«ã¨ã£ã¦æãæé·ãã¦ãã売ä¸ã¨å©çãçã¿åºãããªã³ã©ã¤ã³3Dã¹ãã¢ã§ãã å®é¡å¶ã®ã¢ã¯ãã£ãã¼ã·ã§ã³ã·ã¹ãã ã¯ã仲仿¥è
ã§ã¯ãªãã³ã³ãã³ã使è
ã«å ±é
¬ãä¸ãããããè¦ã¤ãããã¨ãã§ããæé«ã®ã·ã¹ãã ã§ãã"},"quote_6":{"author":{"name":"RiÄardasMarozas","username":"Pumper"},"text":"ç§ã¯Paypalã¢ã«ã¦ã³ãã«160ãã«ãåãåã£ãã¨ããããã¾ã§ã«èµ·ãã£ããã¨ããªãã®ã§ä½ãèµ·ãã£ã¦ããã®ããããã¾ããã§ããããããã¯CGTraderã»ã¼ã«ã®å¯è½æ§ãããã¨æããæ£ããã£ãã§ãã åãããã¯ãå
æTurbosquidã§189ãã«ã§è²©å£²ãã¾ãããã40%ã®å°ç¨ã¨30%ã®ç¨éã®å¾ãCGTraderã®160ãã«ã¨æ¯è¼ãã¦ã52.92ããã¼ããå¾ããã¾ããã§ããã å ãã¦ãã客æ§ã¯29ãã«ã®æ¯æããæ¸ããã¾ãããããã¯é©åã
16518ªãã¸ãã¹ã§ãã"},"quote_7":{"author":{"name":"Threedã±ã³","username":"3DKen"},"text":"æåãç§ã¯ã大æãªã³ã©ã¤ã³3Dã¹ãã¢ã®æ¨æºã§ã¯ãªãã売ãæã«ã¨ã£ã¦ãã®ãããªããªãã®åå¼ã«æççã§ããã å®é¡å¶ã¢ã¯ãã£ãã¼ã·ã§ã³ã·ã¹ãã ã«ã¤ãã¦ç¥ã£ãã¨ããç§ã¯ãã¸ã¿ã«è³ç£ã販売ãããã®ãããªç¬åµçãªæ¹æ³ã«æéãåãã¾ããã $ 5ã®ææ°æãæ¯æããã¨ã§è²©å£²ããã¢ã¯ãã£ãåãã¾ãã ããã¯ãã¹ã¦ç§ã«ã¯çã«ããªã£ã¦ãã¾ãã ç§ã¯ããã¤ããã¢ãããã¼ããã¦è©¦ãã¦ã¿ã¾ããããæ¬å½ã«æåã®ã»ã¼ã«ãåãåã£ãã¨ããããã¯100%ã®ãã¤ã¤ã«ãã£ã§ããï¼"},"quote_8":{"author":{"name":"Threedã±ã³","username":"3DKen"},"text":"ç§ã¯CGTraderãçºè¦ããã¾ã§ã30%ãã60%ã®ææ°æãè«æ±ããä»ã®å¤ãã®ãµã¤ãã«æ
£ãã¦ãã¾ããã 売ãæã¨ãã¦ãç§ã¯ééããªãé«ãå²åã®ãã¤ã¤ã«ãã£ã®è¿åã好ãã§ãã"},"quote_9":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"売ãæã®ä½é¨ã¯ç´ æ´ãããã§ãã 製åã®æåºã¯ç°¡åã§ãã ããã¦ãã¯ããã·ã¹ãã ã«ããã製åæåºã®ãã©ãããããããæ®µéã§ä¿åãããã¨ãã§ãã¾ããã"}}},"hyperwallet":{"failed_payment_agreement":"äºæããªãåé¡ãçºçãã¾ãã","success_notification":"æ¯æãå¥ç´ãæ£å¸¸ã«æ´æ°ããã¾ããã","success_payment_agreement":"æ¯æãå¥ç´ãæ£å¸¸ã«éä¿¡ããã¾ããã"},"item-search-filters":{"3d-models-url":"3d-models","3d-print-models-url":"3d-print-models","dedicated-search-page-url":{"animated":"/animated-","free":"/free-","low_poly":"/low-poly-","pbr":"/pbr-","rigged":"/rigged-"}},"item_use_case":{"not_valid":"ç¡å¹ãªãã¡ã¤ã«","pundit":{"not_authorized":"ãã®æä½ãå®è¡ããæ¨©éãããã¾ãã"},"title":"%{item_name}ã®ã¦ã¼ã¹ã±ã¼ã¹"},"items":{"already_purchased":"ãã®ã¢ã¤ãã ã¯ãã§ã«è³¼å
¥æ¸ã¿ã§ãã","filters":{"attributes":"屿§","free":"ç¡æ","max_value":"$ + 500","min_value":"$ 2","reset":"ãã£ã«ã¿ããªã»ãã"},"footer":{"next":"次","per_page":"1ãã¼ã¸ãããï¼","previous":"å"},"geometry_type_forbidden":"ã¸ãªã¡ããªã¿ã¤ãã¯ç¦æ¢ããã¦ãã¾ãï¼","last_card":{"button_text":"ã«ã¹ã¿ã 3Dã¢ãã«ããªã¯ã¨ã¹ã","text":"ãæ¢ãã®ãã®ãè¦ã¤ããã¾ããã§ãããï¼"},"migrations":{"errors":{"invalid_owner":"æ°ããææè
ã¯ã¢ã¤ãã ãå¼ãç¶ããã¨ãã§ãã¾ããã","unpublished_items":"ãã¹ã¦ã®ã¢ã¤ãã ãå
¬éããå¿
è¦ãããã¾ãã"}},"new_price_applied":"æ°ããä¾¡æ ¼ããã¹ã¦ã®ã¢ã¤ãã ã«æ£å¸¸ã«é©ç¨ããã¾ããã","new_price_applied_to_selected_items":"æ°ããä¾¡æ ¼ã鏿ãããã¢ã¤ãã ã«æ£å¸¸ã«é©ç¨ããã¾ããã","new_prices_to_filtered_models":"æ°ããä¾¡æ ¼ããã¹ã¦ã®ãã£ã«ã¿æ¸ã¿ã¢ã¤ãã ã«æ£å¸¸ã«é©ç¨ããã¾ããã","order_processed":"注æãå¦çããã¾ããã","order_processing":"注æãå¦çä¸ã§ãã","something_went_wrong":"åé¡ãçºçãã¾ãã","title_error":"ã¿ã¤ãã«ã«éã©ãã³æåãå«ãããã¨ã¯ã§ãã¾ãã","uniq_user":"ãã®ã¢ã¤ãã ã®ã¦ã¼ã¹ã±ã¼ã¹ã¯ãã§ã«æåºããã¦ãã¾ã","upload_error":"ã¢ãããã¼ãã¨ã©ã¼ã","validate_license_for_zero_price":"ç¡æã¢ã¤ãã ã«ã¯ç¡å¹ã§ã","validate_minimum_price":"ä¾¡æ ¼ã®ãªãã¡ã¼ã¯å
ã®ä¾¡æ ¼ã®50ï¼
æªæºã«ãããã¨ã¯ã§ãã¾ãã","verify_printable_formats_error":"å°ãªãã¨ã1ã¤ã® .stlã.obj ã¾ã㯠.wrl ãã¡ã¤ã«ãã¢ãããã¼ããã¦ãã ããã","you_can_not_delete_models":"ã¢ãã«ãåé¤ãããã¨ã¯ã§ãã¾ãã"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projectsãªããåªç§ãª3Dããªã¼ã©ã³ãµã¼ãç°¡åã«æ¡ç¨ã§ããããããã¢ããªã³ã°èª²é¡ã解決ã§ãã¾ãã","heading_html":"æé«ã®ããªã¼ã©ã³ã¹ãã©ãããã©ã¼ã ã§ \u003cstrong\u003e3Dã¢ããªã³ã°æ¡ä»¶\u003c/strong\u003e ãæåããã¾ããã"},"sections":{"call_to_action":{"description":"ããã¸ã§ã¯ããç¡æã§æç¨¿ãã¦ã3Dããã¸ã§ã¯ãã§æ¬¡ã®ã¢ããªã³ã°èª²é¡ãç°¡åã«è§£æ±ºã§ãããã¨ã宿ã","title":"仿¥æé«ã®3D人æãæ¡ç¨ï¼"},"freelancer_selection":{"title":"次ã®3Dããã¸ã§ã¯ããæåã«å°ã","widest_selection":{"description":"å°ãªãæ°ã§æºè¶³ããªãã§ãã ããã4ä¸
16518人ã®ããªã¼ã©ã³ã¹3Dãã¶ã¤ãã¼ãæããCGTraderã¯ãã¢ãã©ã¼ãã¢ãã¡ã¼ã¿ã¼ããªã¬ã¼ã3Dããªã³ãã®ãããªã©ãæè½ãªå°éå®¶ã¨ã¤ãªããããã®æå¤§ã®ãã©ãããã©ã¼ã ã§ãã","title":"æãå¹
åºã3Dããªã¼ã©ã³ãµã¼"}},"how_it_works":{"steps":{"describe":{"description":"å¿
è¦ãªãã®ãæãã¦ãã ãããç°¡åãªãã©ã¼ã ã«å
¥åããç»åã追å ãã¦ãæ°åã§ããªã¼ã©ã³ã¹åéãå
¬éã","title":"ããã¸ã§ã¯ãã説æ"},"pay":{"description":"CGTraderã«å®å
¨ã«äºç®ãåæãããããªã¼ã©ã³ãµã¼ã«éå§æºåãã§ãããã¨ãç¥ããã¾ãããã£ãããæ·»ä»å
±æãé²æç¢ºèªãå°ç¨ã¯ã¼ã¯ã¹ãã¼ã¹ã§ä¾¿å©ã«è¡ããæçµçµæã«æºè¶³ãããæ¯æããè§£æ¾ã","title":"çµæã«æ¯æã"},"select":{"bullets":["è³æ ¼ã®ãããã¶ã¤ãã¼ããã®è¦ç©ãããåä¿¡ãã¬ã¤ã§ç´æ¥åãåã","ãã¶ã¤ãã¼ã¨ãªã¢ã«ã¿ã¤ã ã§ãã£ãã","éå»ã®ããã¸ã§ã¯ããé²è¦§","3Dã¹ãã«ãè©ä¾¡ãã½ããããã©ã¼ãããã®å¥½ã¿ã«åºã¥ãã¦æ¤ç´¢ããã£ã«ã¿ããããªã¼ã©ã³ãµã¼ãæå¾
ãããã¨ãã§ãã¾ã"],"title":"æé©ãªããªã¼ã©ã³ãµã¼ã鏿"}},"title":"3ã¤ã®ã¹ãããã§ä»äºãå®äº"},"payment_quality":{"description":"CGTraderã¯ãããªã¼ã©ã³ã¹ãµã¼ãã¹ãè¦ä»¶ãæºãããæéå
ã«ç´åããããã¨ãä¿è¨¼ãã¾ããQAãã¼ã ã¯ãã¤ã§ã対å¿å¯è½ã§ãã","title":"å質ä¿è¨¼"},"secure_payments":{"description":"ã¨ã¹ã¯ãã¼ãµã¼ãã¹ã«ãããè³éã¯ä¿è·ãããæçµçµæã«æºè¶³ããã¨ãã«ã®ã¿æ¯æãã¾ãã","title":"å®å
¨ãªæ¯æã"},"workspace_convenience":{"description":"ã¿ãããã¼ã«ãåãæ¿ããç
©ããããå¿ãã¾ããããå°ç¨ã¯ã¼ã¯ã¹ãã¼ã¹ã§ãè¤æ°ããã¸ã§ã¯ããè«æ±æ¸ãä¼è©±ããã¡ã¤ã«å
±æãªã©ã䏿¬ç®¡çã§ãã¾ãã","title":"ã·ã³ã°ã«ã¹ã¯ãªã¼ã³ã®å©ä¾¿æ§"}},"shared":{"post_project_cta":"ããã¸ã§ã¯ããæç¨¿"}}
16518,"navigation":{"find_jobs_cta":"3Dã®ä»äºãæ¢ã","hire_freelancers_cta":"3Dããªã¼ã©ã³ãµã¼ãéã","how_it_works":"ä»çµã¿","why_projects":"ãªã3Dããã¸ã§ã¯ããªã®ã"}},"agreed_to_terms_of_use":"ç¶è¡ããã«ã¯ã3D Projects ã®å©ç¨è¦ç´ã«åæããå¿
è¦ãããã¾ãã","budget_error_message":"ãé«ããã¾ã","check_designer_uniqueness_error":"ãã¶ã¤ãã¼ã¯ä¸åº¦ããæå¾
ã§ãã¾ãã","check_ownership_error":"æå¾
è
ã¯ãã®ããã¸ã§ã¯ãã®ææè
ã§ã¯ããã¾ãã","check_status_error":"ãã¶ã¤ãã¼ã¯æ¿èªãããããã¸ã§ã¯ãã«ã®ã¿æå¾
ã§ãã¾ãã","deadline_error_message":"ç· ãåãã¯æªæ¥ã®æ¥ä»ã§ãªããã°ãªãã¾ãã","discount_code_error":"ç³ã訳ããã¾ããããå²å¼ã³ã¼ããåå¨ããªããæå¹æéãåãã¦ãã¾ãã","email_subject":"3Dããã¸ã§ã¯ãã®æ©ä¼: %{subject}","error_check_application_uniqueness":"å¿åã¯1åã®ã¿å¯è½ã§ã","error_check_applier":"èªåèªèº«ã®3Dããã¸ã§ã¯ãã«å¿åãããã¨ã¯ã§ãã¾ãã","error_check_job_availability":"ã¦ã¼ã¶ã¼ã¯å¿åã許å¯ããã¦ãã¾ãã","error_check_job_status":"ããã¸ã§ã¯ãã®å¿åã¯æ°ãã審æ»ããã»ã¹ãå®äºããã¾ã§ä¿çããã¦ãã¾ããé常3å¶æ¥æ¥ä»¥å
ã«å®äºãã¾ãããçè§£ãããã¨ããããã¾ãï¼","modeling_request_failed":"ã¢ããªã³ã°ãªã¯ã¨ã¹ãã«å¤±æãã¾ããï¼","offer_has_been_sent":"ãããã¨ããããã¾ãããªãã¡ã¼ãéä¿¡ããã¾ããï¼","offer_is_closed":"ãªãã¡ã¼ã¯çµäºãã¾ããã","payment_successful":"æ¯æããæ£å¸¸ã«å®äºãã¾ããã","payment_under_review":"æ¯æãã¯å¯©æ»ä¸ã§ãã","share_with_yourself_error":"èªåèªèº«ã¨ãHire Meããã³ãã¬ã¼ããå
±æãããã¨ã¯ã§ãã¾ãã","system_messages":{"buyer_cancels_job":"ããã¸ã§ã¯ãã¯ãã£ã³ã»ã«ããã%{archive_url} ã¿ãã«ç§»åããã¾ããã","buyer_edits_hire_me_template":"ããã¸ã§ã¯ãã®è©³ç´°ãã¯ã©ã¤ã¢ã³ãã«ãã£ã¦æ´æ°ããã¾ããã","buyer_edits_job_details":"ããã¸ã§ã¯ãã®è©³ç´°ãæ´æ°ããã¾ããã","buyer_marks_job_as_finished":"ããã¸ã§ã¯ãã¯å®äºã¨ãã¦ãã¼ã¯ããã%{archive_url} ã¿ãã«ç§»åããã¾ããã","buyer_marks_job_as_finished_with_resell":"ã¯ã©ã¤ã¢ã³ããããã¸ã§ã¯ããå®äºã¨ãã¦ãã¼ã¯ããçµæãCGTraderã§è²©å£²ãããã¨ã許å¯ãã¾ããã使ããã¢ãã«ãå¿
ã\u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003eã¢ãããã¼ã\u003c/a\u003e\u003c/b\u003eãã¦ãã ããï¼","buyer_negotiates":"ã¯ã©ã¤ã¢ã³ããããªãã®ä¾¡æ ¼ãªãã¡ã¼ã交æ¸ãã¾ããã","buyer_pays_for_the_job":"ããã¸ã§ã¯ãã¯åæãããã%{in_progress_url} ã¿ãã«ç§»åããã¾ããã","designer_accepts_changes":"ãã¶ã¤ãã¼ãæ´æ°ããã詳細ã確èªãã¾ããã","designer_accepts_offer":"ãã¶ã¤ãã¼ãããªãã®ãªãã¡ã¼ãåãå
¥ãã¾ããã","designer_edits_offer":"ãã¶ã¤ãã¼ããªãã¡ã¼ãç·¨éãã¾ããã","designer_negotiates":"ãã¶ã¤ãã¼ãããªãã®ãªãã¡ã¼ã交æ¸ãã¾ããã","designer_withdraws_offer":"ãã¶ã¤ãã¼ããªãã¡ã¼ãæ¤åãã¾ããã","job_expires":"ããã¸ã§ã¯ãã¯æéåãã¨ãªãã%{archive_url} ã¿ãã«ç§»åããã¾ããã"},"template_error":"ã¸ã§ãã使ããã¾ããã§ããï¼","user_not_exists":"ãã®ã¦ã¼ã¶ã¼åã®ã¦ã¼ã¶ã¼ã¯åå¨ãã¾ããã","want_that_job":"ãã®ä»äºã欲ããï¼"},"kodama":{"invalid_request":"ç¡å¹ãªãªã¯ã¨ã¹ãã§ãï¼"},"landing":{"consent_not_saved":"åæãä¿åããã¾ããã§ãã","failure_notification":"API ã¢ã¯ã»ã¹ãªã¯ã¨ã¹ãã®å¿
é é
ç®ã¯ãã¹ã¦æå¹ã§ããå¿
è¦ãããã¾ãã","success_notification":"ãªã¯ã¨ã¹ããããã¨ããããã¾ããè¿æ¥ä¸ã«ãé£çµ¡ãããã¾ãã"},"layout":{"chunk_load_notice":"ãã¼ã¸ã®èªã¿è¾¼ã¿ä¸ã«åé¡ãçºçãã¾ããããã¼ã¸ãæ´æ°ãã¦ãã ããã","cookies_policy":{"accept":"åãå
¥ãã¾ã","learn_more":"ãã£ã¨è©³ããç¥ã","text":"å¼ç¤¾ã®ã¦ã§ããµã¤ãã使ç¨ããã¯ããã¼ã¯/ãã¤ã¬ã¯ããã¼ã±ãã£ã³ã°ã³ãã¥ãã±ã¼ã·ã§ã³ã¨çµ±è¨è¨ªåè
ã®ãã¼ã¿ã¨ãã©ãã¯ã¨ã®å¯¾è©±ãåéããå½ç¤¾ã®ã¦ã§ããµã¤ããæ¹åããããªãã®ãã©ã¦ã¸ã³ã°ä½é¨ãåä¸ããã¾ãããããã«ã¢ã¯ã»ã¹ãããã¨ãã§ããã¯ããã¼ãå½¼ããåéãããã¼ã¿ãããã³ããªãã®æ¨©å©ã«ã¤ãã¦ã®è©³ç´°ã¯ãå½ç¤¾ã®ã¯ããã¼ã®ãç¥ãããã覧ãã ããã"},"translations_notice":{"cta":"åãæ¿ããEnglish","text":"ããã«ã¡ã¯! CGTraderã翻訳ãã¦ãã¾ã. 翻訳ã¯é²è¡ä¸ã§ãããä¸é¨ã®ã»ã¯ã·ã§ã³ã¯æ¥æ¬èªã§å©ç¨ã§ããªãå ´åãããã¾ã."}},"model":{"already_purchased":"ãã®è£½åã¯ãã§ã«è³¼å
¥æ¸ã¿ã§ãã\u003ca href='/profile/cart/purchased'\u003eã·ã§ããã³ã°ã«ã¼ã\u003c/a\u003eãããã¦ã³ãã¼ãã§ãã¾ããå¿
è¦ã§ããã°ãããä¸åº¦è³¼å
¥ã§ãã¾ãã","animated":"ã¢ãã¡ã¼ã·ã§ã³ä»ã","artist_profile":"ã¢ã¼ãã£ã¹ããããã£ã¼ã«","author":"ä½è
","author_get_your_payment":"ä½è
ã¯ããªãã®æ¯æãã®100%ãåãåãã¾ããCGTraderã¯ã¢ã¼ãã£ã¹ããæå¤§éã®åçãå¾ãããããã«ããé«å質ã®ã³ã³ãã³ã販売ã奨å±ãã¾ãã","author_products":"\u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e ã®ãã®ä»ã®è£½å","authorised_seller":"CGTraderèªå®è²©å£²è
","authority":"権é","breadcrumb":{"3d_models":"3Dã¢ãã«","home":"ãã¼ã "}
16518,"bulk_download":{"download_all":"ãã¹ã¦ã®ãã¡ã¤ã«ããã¦ã³ãã¼ã","files_included":{"one":"%{count} åã®ãã¡ã¤ã«ãå«ã","other":"%{count} åã®ãã¡ã¤ã«ãå«ã"},"too_large":"ãã®ã¢ãã«ã¯å¤§ããããããã1ã¤ã®ã¢ã¼ã«ã¤ãã¨ãã¦ãã¦ã³ãã¼ãã§ãã¾ããï¼%{limit}è¶
ï¼ããã¡ã¤ã«ãåå¥ã«ãã¦ã³ãã¼ããã¦ãã ããã"},"buy":"è³¼å
¥","cannot_download":"%{experience_needed}以ä¸ã®è©å¤ãã¤ã³ããããã¦ã¼ã¶ã¼ã®ã¿ãã%{models}以ä¸ã®ç¡æã¢ãã«ããã¦ã³ãã¼ãã§ãã¾ããã¬ãã«ã¨è©å¤ã«ã¤ãã¦ã®è©³ç´°ã¯\u003ca href='%{reputation_url}' target='_blank'\u003eãã¡ã\u003c/a\u003eãã覧ãã ããã","collection":"3Dããã¯","contact_author":"ä½è
ã«é£çµ¡","description":"説æ","download":"ãã¦ã³ãã¼ã","download_limit_exceeded":"1æ¥ã®ãã¦ã³ãã¼ãå¶éãè¶
ãã¾ãããææ¥ããä¸åº¦ã試ããã ããããã®å¶éã¯éå»12ãæä»¥å
ã«è³¼å
¥ãè¡ã£ãã¦ã¼ã¶ã¼ã«ã¯é©ç¨ããã¾ããã","download_modal":{"chat_with_us":"ãã£ããã§åãåããã","contact_support":"ãã£ãããããåãåãããã ããã","download_file":"%{name} ããã¦ã³ãã¼ã","empty":"ãã¡ã¤ã«ãè¦ã¤ããã¾ããã§ãã","generic_error":"åé¡ãçºçãã¾ãããããä¸åº¦ã試ããã ãã","link_error":"ç³ã訳ããã¾ãããããã¦ã³ãã¼ããªã³ã¯ã«åé¡ãããããã§ãã","pbr_ready":"PBR対å¿","preparing":"ãã¦ã³ãã¼ããæºåãã¦ãã¾ã...","title":"ãã¡ã¤ã«ããã¦ã³ãã¼ã"},"format_downloads":"3Dã½ããã¦ã§ã¢å½¢å¼ã®ãã¦ã³ãã¼ã","game_ready":"ã²ã¼ã 対å¿ï¼ãã¼ããªï¼","geometry":"ã¸ãªã¡ããª","license":"ã©ã¤ã»ã³ã¹","make_offer":"ãªãã¡ã¼ãåºã","materials":"ãããªã¢ã«","messages":{"no_files":"ã¢ãããã¼ãããããã¡ã¤ã«ã¯ããã¾ãã","no_rating":"ãã®ã¢ãã«ã«ã¯ã¾ã è©ä¾¡ãããã¾ãã"},"model_details":"3Dã¢ãã«ã®è©³ç´°","pbr_textures":"PBRãã¯ã¹ãã£","plugin_used":"使ç¨ãã©ã°ã¤ã³","polygons":"ããªã´ã³","price":"ä¾¡æ ¼","print_ready":"3Dããªã³ã対å¿","product_id":"製åID","product_support":"製åãµãã¼ã","product_type":"製åã¿ã¤ã","published":"å
¬éæ¥","rated":{"error":"ãã®ã¢ãã«ã¯ãã§ã«è©ä¾¡æ¸ã¿ã§ã","success":"è©ä¾¡ããã ããããã¨ããããã¾ã"},"rating":"3Dã¢ãã«ã®è©ä¾¡","ratings":{"desc":{"negative":"ãã®3Dã¢ãã«ãè³¼å
¥ããã¦ã¼ã¶ã¼ã¯æå¾
ãããä½å質ã ã¨è©ä¾¡ãã¦ãã¾ã","positive":"ãã®3Dã¢ãã«ãè³¼å
¥ããã¦ã¼ã¶ã¼ã¯é«å質ã ã¨è©ä¾¡ãã¦ãã¾ã"},"negative":"ä½è©ä¾¡","positive":"é«è©ä¾¡"},"recently_viewed_models":"æè¿é²è¦§ããã¢ãã«","renderer":"ã¬ã³ãã©ã¼","report":"å ±åãã","rigged":"ãªã®ã³ã°æ¸ã¿","scripts-plugins":"ã¹ã¯ãªããã¨ãã©ã°ã¤ã³","similar_models":"é¡ä¼¼ã¢ãã«","statistics":"çµ±è¨","subscription":{"limit_reached":"ãã®è«æ±æéã®ãã¦ã³ãã¼ãä¸éã«éãã¾ããã","limit_reached_detailed":"仿ã®ãã¦ã³ãã¼ãä¸é%{limit}ä»¶ã«éãã¾ãããå¶éã¯%{reset_date}ã«ãªã»ããããã¾ãã ä»ããããã«ã¢ãã«ããã¦ã³ãã¼ãããã«ã¯ãåå¥ã«è³¼å
¥ã§ãã¾ãã","limit_reached_detailed_no_date":"仿ã®ãã¦ã³ãã¼ãä¸é%{limit}ä»¶ã«éãã¾ããã ä»ããããã«ã¢ãã«ããã¦ã³ãã¼ãããã«ã¯ãåå¥ã«è³¼å
¥ã§ãã¾ãã"},"tags":"ã¿ã°","textures":"ãã¯ã¹ãã£","title":"%{item_title} 3Dã¢ãã«","unwrapped_uvs":"å±éãããUV","uv_mapping":"UVãããã³ã°","vat_notice":"ãã¹ã¦ã®ä¾¡æ ¼ã¯VATï¼ä»å 価å¤ç¨ï¼æãã§ã","version":"ãã¼ã¸ã§ã³","vertices":"é ç¹","vr":"VRã¢ãã«"},"models":{"error":{"cannot_be_blank":" ã空ã«ãããã¨ã¯ã§ãã¾ããã"}},"navigation":{"3d-models":{"3d-printing":"3Dããªã³ããã¡ã¤ã«","discounts":"å²å¼","find_designers":"é©ä»»ã®ãã¶ã¤ãã¼ãæ¢ã","free":"ç¡æã®3Dã¢ãã«","pbr":"PBR","scanned_3d-models":"ã¹ãã£ã³ãã3Dã¢ãã«","scripts_apps":"ã¹ã¯ãªããã»ã¢ããª","show-all":"ãã
16518¹ã¦è¡¨ç¤º","textures":"CGãã¯ã¹ãã£","title":"3Dã¢ãã«","vr_low-poly":"VR /ãã¼ããª"},"already_added_message":"ãã§ã«ã«ã¼ãã«è¿½å ããã¦ãã¾ã","already_purchased_message":"ããªãã¯ãã§ã«ãã®ã¢ã¤ãã ãè³¼å
¥ãã¦ãã¾ãã","aria":{"account":"ã¢ã«ã¦ã³ã","cart":"ã«ã¼ã","close_menu":"ã¡ãã¥ã¼ãéãã","logo":"CGTrader - 3Dã¢ãã« / 3Dãã¶ã¤ãã¼","messages":"ã¡ãã»ã¼ã¸","notifications":"éç¥","open_menu":"ã¡ãã¥ã¼ãéã","search":"æ¤ç´¢","search_by_image":"ç»åã§æ¤ç´¢"},"budgets":{"below_10":"$10æªæº","collections":"ããã¯","free":"ç¡æ","more_than_20":"$20以ä¸","more_than_50":"$50以ä¸","sale":"ã»ã¼ã«ä¸","subscription":"ãµãã¹ã¯ãªãã·ã§ã³"},"cart_limit_reached":"ã«ã¼ãå
ã®ååæ°ã500ä»¶ã®å¶éã«éãã¾ããããè²·ãç©ãç¶ããã«ã¯ãç¾å¨ã®æ³¨æãå®äºãã追å ã®ã¢ã¤ãã ã®ããã«æ°ããæ³¨æãéå§ãã¦ãã ããã","cart_widget":{"continue_shopping":"è²·ãç©ãç¶ãã","discount":"伿¥ã®ã¯ã¼ãã³ã¨å²å¼ï¼","discount_applied":"é©ç¨ãããå²å¼ï¼","final":"æçµä¾¡æ ¼ï¼","have":"ã¢ã¤ãã æ°","items":"ãã·ã§ããã³ã°ã«ã¼ãã«å
¥ã£ã¦ãã¾ãã","left_to_unlock_discounts":"å²å¼ãã¢ã³ããã¯ããã«ã¯ãã¨{{leftToUnlock}}","potential_discount":"å²å¼ã®å¯è½æ§ï¼","proceed":"ãã§ãã¯ã¢ã¦ãã«é²ã","recently_viewed_empty_text":"æ¢ç´¢ãå§ããã¨ãæè¿è¦ãã¢ã¤ãã ãããã«è¡¨ç¤ºããã¾ãã","recently_viewed_empty_title":"ã¾ã ä½ãããã¾ãã","recently_viewed_tab":"æè¿è¦ãã¢ã¤ãã ","remainer":"CGTraderãã¤ã³ããæå¹ã«ããã«ã¯ã追å ã§ï¼","sale_discounts":"é©ç¨ãããå²å¼ï¼","sale_time_left":"ã»ã¼ã«çµäºã¾ã§","sale_tooltip":"ã»ã¼ã«ãã£ã³ãã¼ã³ã®å²å¼ã¯ãã«ã¼ãã${{threshold}}以ä¸ã«éããå ´åã«ã®ã¿é©ç¨ããã¾ãã","sale_tooltip_text":"ãã®ååã¯ã»ã¼ã«ä¸ã§ãããå²å¼ã¯ã«ã¼ãã®å°è¨ã${{threshold}}以ä¸ã«éããã¨ãã«ã®ã¿é©ç¨ããã¾ãã","text":"ã·ã§ããã³ã°ã«ã¼ãã¯ç©ºã§ãã","title":"ã·ã§ããã³ã°ã«ã¼ã","total":"åè¨ï¼","used":"使ç¨ã¯ã¬ã¸ããï¼","view":"ã«ã¼ãã®ä¸èº«ãè¦ã","wishlist_empty_text":"æ¢ç´¢ãå§ãã¦ããæ°ã«å
¥ããä¿åãã¾ããã â ããã«è¡¨ç¤ºããã¾ãã","wishlist_empty_title":"ã¦ã£ãã·ã¥ãªã¹ãã¯ç©ºã§ã","wishlist_tab":"ã¦ã£ãã·ã¥ãªã¹ã"},"community":{"awards":"ãã¶ã¤ãã¼è³ ð","blog":"ããã°","challenges":"課é¡","community_ratings":"ã³ãã¥ããã£è©ä¾¡","designers":"3Dãã¶ã¤ãã¼","digital_art":"ãã¸ã¿ã«ã¢ã¼ãã³ã³ã","forum":"ãã©ã¼ã©ã ","galleries":"ã®ã£ã©ãªã¼","invite":"å人ãæå¾
","printlist":"3Då°å·ãªã¹ã","sell_3d-models":"3Dã¢ãã«ã販売","title":"ã³ãã¥ããã£","tutorials":"ãã¥ã¼ããªã¢ã«"},"conversations_widget":{"conversations":"ä¼è©±","messages":{"loading":"åä¿¡ãã¬ã¤ãèªã¿è¾¼ãã§ãã¾ã"},"types":{"cgtrader_support":"CGTraderãµãã¼ã","file_conversion_request":"ãã¡ã¤ã«å¤æè¦æ±","job_application":"3Dããã¸ã§ã¯ã","model_feedback":"製åãã£ã¼ãããã¯","model_support":"ã¢ãã«ã®ãµãã¼ã","offer":"è¦ç©ãã","personal":"ãã©ã¤ãã¼ãã»ã¡ãã»ã¼ã¸","promotions":"ããã¢ã¼ã·ã§ã³"}},"create_ai":{"community_gallery":"ã³ãã¥ããã£ã®ã£ã©ãªã¼","free_trial":"ç¡æãã©ã¤ã¢ã«","generate_3d_model":"3Dã¢ãã«ãçæ","generation":{"dismiss":"éç¥ãéãã","error_title":"çæã«é¢ããåé¡","generating_title":"3Dã¢ãã«ãçæãã¦ãã¾ã","open_model":"ã¢ãã«ãéã","ready_title":"3Dã¢ãã«ã宿ãã¾ããï¼"}},"create_with_ai":"AIã§ä½æ","credits_guest_widget":{"create":"ä»ããã¢ã«ã¦ã³ãã使ï¼","discount":"å¤å¼ã","for":"ã®","get":"ããã¦ãããã","learn_more":"CGTraderã»ãã¤ã¤ã«ãã£ã»ã¯ã¬ã¸ããã®è©³ç´°ã«ã¤ãã¦ã¯ããã¡ããã覧ãã ãã ","link":"ãã¡ã","purchase":"ååè³¼å
¥ç¹å
¸ï¼","sign-up":"ãµã¤ã³ã¢ãã","text_below_1":"è³¼å
¥æã«ã¯ã¬ã¸ããã使ç¨ãããã¨ãã§ãã¾ã\"","text_below_2":"\"ãã¼ã¯ãããã¢ãã«ã«ç½²åããä¾¡æ ¼ã®30ï¼
å²å¼ã¾ã§ã«ãã¼ã"},"credits_user_widget":{"condition_1":"CGTraderãã¤ã³ãã¯ã\u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e ã®ãã¼ã¯ãä»ããã¢ãã«ã®è³¼å
¥ã«ä½¿ç¨ã§ããä¾¡æ ¼ããæå¤§30%ã®å²å¼ãæä¾ãã¾ãã","condition_2":"ãã¤ã³ãã¯ãã«ã¼ãã®åè¨éé¡ã\u003cstrong\u003e$%{minimum}\u003c/strong\u003e以ä¸ã®å ´åã«ã®ã¿ä½¿ç¨ã§ãã¾ãã","condition_3":"ã»ã¼ã«ãããã¢ã¼ã·ã§ã³ä¸ã¯ããã¤ã³ãã使ç¨ã§ãã¾ããã","condition_4":"ãã¤ã³ãã«ã¯æå¹æéããããã¨ã«æ³¨æãã¦ãã ããããã¤ã³ãã¯\u003cstrong\u003e%{days}\u003c/strong\u003eæ¥å¾ã«æéåãã«ãªãã¾ãã","earn_rate":"ã¯ã¬ã¸ããç²å¾ç","first_text_1":"ååç¹å
¸ã¨ãã¦ãè³¼å
¥æã«ã¯ã¬ã¸ãããå©ç¨ã§ãã¾ã\"","first_text_2":" \"ãã¼ã¯ãããã¢ãã«ã¨ãã®ä¾¡æ ¼ã®æå¤§30ï¼
å²å¼ãåå¾ã§ãã¾ããã¯ã¬ã¸ããã¯ãã«ã¼ãã®åè¨éé¡ããã«ä»¥ä¸ã®å ´åã«ã®ã¿ä½¿ç¨ã§ãã¾ãã","important":"éè¦ï¼","learn_more":"ãã£ã¨è©³ããç¥ã","lifetime_spending":"çæ¶¯æ¯åºï¼","list_item":"CGTraderã§ç涯æ¯åºãå¢å ããããã¨ã§ãã¯ã¬ã¸ããç²å¾çãä¸ããã¾ãã","message":"ã¯ã¬ã¸ããã¯ã»ã¼ã«ãã£ã³ãã¼ã³ã®éã«å©ç¨ãããã¨ã¯ã§ãã¾ãããããã¤ã¤ãªãã£ã®ã¬ãã«ãä¸ããæ¬¡ã®è³¼å
¥ç¨ã«ã¯ã¬ã¸ãããç²å¾ãããã¨ãã§ãã¾ãã","more_credits":"ã©ãããã°ãããå¤ãã®ã¯ã¬ã¸ãããç²å¾ã§ãã¾ããï¼","next_level":"次ã®ã¬ãã«ï¼","notice":"注æ: CGTraderãã¤ã³ãã¯ç¾å¨ã®ã»ã¼ã«ä¸ã«ã¯ä½¿ç¨ã§ãã¾ããããã»ã¼ã«çµäºå¾ã«åã³å©ç¨å¯è½ã«ãªãã¾ããããã¾ã§ã®éããå¾ãª3Dã¢ãã«ããã²ãã§ãã¯ãã¦ãã ãã \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003eãã¡ã\u003c/a\u003eã","par_1":"ææCGTraderã¯ã¬ã¸ããã¯","par_2":"ã§ãã","par_2_variation":" ã»ã¼ã«ãå©ç¨ã§ããªãå ´åã«ä½¿ç¨ã§ãããã¤ã³ãã","regular_text_1":"è³¼å
¥æã«ã¯ã¬ã¸ãããå©ç¨ã§ãã¾ã \"","regular_text_2":" \"ãã¼ã¯ãããã¢ãã«ã«ç½²åãããã®ä¾¡æ ¼ã®æå¤§30ï¼
å²å¼ãã¾ãã","title":"CGTraderã®ãã¤ã¤ãªãã£å²å¼"},"enterprise":{"management":"3Dè³ç£ç®¡ç","title":"3Dã³ã³ãã³ãå¶ä½"},"hire_a_freelancer":"ããªã¼ã©ã³ãµã¼ãéã","item_add_message":"ã«ã¼ãã«è¿½å ããã¾ãã","item_restricted_message":"ãã¶ã¤ãã¼ã®å½ (RU/BY) ã«å¯¾ããå¶è£ã®ããããã®ååã¯è³¼å
¥ã§ãã¾ããã","navbar":{"actions":{"new":"æ°ç","top_selling":"売ãç","trending":"ãã¬ã³ã"},"budgets":{"below_10":"$10æªæº","free":"ç¡æ","more_than_20":"$20以ä¸","more_than_50":"$50以ä¸","sale":"ã»ã¼ã«ä¸","up_to_10":"$10ã¾ã§"}},"projects":{"3d_customs":"ã«ã¹ã¿ã 3D","3d_printing":"3Dããªã³ã","about":"3Dããã¸ã§ã¯ãã«ã¤ãã¦","browse":"ããã¸ã§ã¯ããé²è¦§","buyer_perspective":"3Dãã¶ã¤ãã¼ãéã","for_designers":"ãã¶ã¤ãã¼åã","my_projects":"ãã¤ããã¸ã§ã¯ã","seller_perspective":"3Dããã¸ã§ã¯ããããªã¼ã©ã³ãµã¼ã«ä¾é ¼ãã","start":"ããã¸ã§ã¯ããéå§","work":"CGTraderã¨ä¸ç·ã«åã"},"sell_3d-models":"3Dã¢ãã«ã販売","sellers_hub":"販売è
ãã","subscription_includes_item_message":"ãã®
16518ååã¯ãã§ã«ããªãã®ãµãã¹ã¯ãªãã·ã§ã³ã«å«ã¾ãã¦ãã¾ãã","tooltips":{"cart":"ã·ã§ããã³ã°ã«ã¼ã","conversations":"ä¼è©±å±¥æ´","discounts":"CGTraderã®ãã¤ã¤ãªãã£å²å¼","notifications":"éç¥","publisher":"åºç社"},"user":{"ban_notification":"ãã®ã¦ã¼ã¶ã¼ã¢ã«ã¦ã³ãã¯åæ¢ããã¦ãã¾ãã詳細ã«ã¤ãã¦ã¯ãµãã¼ãã«ãåãåãããã ããã","cannot_refer_yourself":"èªåèªèº«ãç´¹ä»ãããã¨ã¯ã§ãã¾ãã","email_confirmation":"ã¡ã¼ã«ã¢ãã¬ã¹ã確èªããã¾ããã","email_reconfirmation":"ã¯ãã§ã«ç¢ºèªããã¦ãã¾ãããµã¤ã³ã¤ã³ãã¦ãã ãã","ends_at":"çµäºæ¥æ: %{date}","handle_error_tfa_code_missmatch":"å
¥åãããã»ãã¥ãªãã£ã³ã¼ããæ£ããããã¾ãããããä¸åº¦ã試ããã ããã","handle_error_tfa_code_missmatch_last":"ã»ãã¥ãªãã£ã³ã¼ãã®æå¹æéãåãã¦ãã¾ããç¶è¡ããã«ã¯ãã¡ã¼ã«ãåéä¿¡ãã¦æ°ããã³ã¼ããå
¥åãã¦ãã ããã","handle_error_tfa_default":"åé¡ãçºçãã¾ãããå¾ã§ããä¸åº¦ã試ããã ããã","handle_error_tfa_expired":"ã»ãã¥ãªãã£ã³ã¼ãã®æå¹æéãåãã¦ãã¾ãã","hundred_percent_royalties_popover":"ããªãã¯ä¸æçãª100%åçãã£ã³ãã¼ã³ã«åå ãã¦ãã¾ã: æ°ããã¢ãã«ã®è²©å£²åçã¯ãã£ã³ãã¼ã³çµäºã¾ã§å
¨ã¦ããªãã«æ¯æããã¾ã","invalid_email_message":"ç¶è¡ããã«ã¯æå¹ãªã¡ã¼ã«ã¢ãã¬ã¹ãå
¥åãã¦ãã ããã","login":"ãã°ã¤ã³","meta_description":"%{username} ã®CGTrader 3Dãã¶ã¤ãã¼ãããã£ã¼ã«ããã¼ããã©ãªãªãå©ç¨å¯è½ãª3Dã¢ãã«ãã覧ãã ãããæ¥çãããã®ã¢ããªã³ã°ã¢ã¼ãã£ã¹ãã«ããæé«ã®3Dã¢ãã«ããã§ãã¯ã","meta_title_suffix":"3Dãã¶ã¤ãã¼","not_valid_birthday":"èªçæ¥ãç¡å¹ã§ãã","offline":"ãªãã©ã¤ã³","online":"ãªã³ã©ã¤ã³","page_title":"ãã¶ã¤ãã¼ãããã£ã¼ã«","rate_models_limit":"æ¬æ¥ã¯ãã以ä¸ã¢ãã«ãè©ä¾¡ã§ãã¾ããã","semantic_description":"ãã¶ã¤ãã¼ã®3Dã¢ãã«ãä½åããã¼ããã©ãªãªãã覧ãã ãããCGTraderã§å½¼ã®ä½åããã§ãã¯","semantic_title":"ãã¶ã¤ãã¼ãããã£ã¼ã«","session_failure":"ã¦ã¼ã¶ã¼åï¼ã¡ã¼ã«ã¢ãã¬ã¹ã¾ãã¯ãã¹ã¯ã¼ããééã£ã¦ãã¾ã","session_password_expired":"ã¢ã«ã¦ã³ãã®éã¢ã¯ãã£ãã«ãããã¹ã¯ã¼ãã®æå¹æéãåãã¾ãããéä¿¡ãããã¡ã¼ã«ã®ãªã³ã¯ãããã¹ã¯ã¼ãããªã»ãããã¦ãã ããã","session_two_fa_failure":"ã³ã¼ãèªè¨¼ã«å¤±æãã¾ãã","session_unconfirmed":"ããªãã®ã¡ã¼ã«ã¢ãã¬ã¹ã¯ã¾ã 確èªããã¦ãã¾ããã","token_not_recognized":"ãã¼ã¯ã³ãèªèããã¾ããã§ãã","twitter_shareable_text":"ãã©ãã¼ãã価å¤ã®ãã#3dartist","username_error":"ã¹ãã¼ã¹ãéã©ãã³æåãå«ãããã¨ã¯ã§ãã¾ãã"},"user_menu":{"buyer":{"freelancers":"ããªã¼ã©ã³ãµã¼ãæ¢ã","purchases":"èªåã®è³¼å
¥å","sell":"3Dã¢ãã«ã販売","wishlist":"3Dã¢ãã«æ¬²ãããã®ãªã¹ã"},"dashboard":"管çããã·ã¥ãã¼ã","logout":"ãã°ã¢ã¦ã","public_profile":"å
¬éãããã£ã¼ã«","seller":{"analytics":"è§£æ","find_new_projects":"æ°ãã3Dããã¸ã§ã¯ããæ¢ã","freelance":"ããªã¼ã©ã³ã¹3Dããã¸ã§ã¯ã","freelance_cgtrader":"CGTraderã§ããªã¼ã©ã³ã¹","models":"èªåã®ã¢ãã«","publish_project":"ããã¸ã§ã¯ããå
¬é","publishing":"åºç","sales":"èªåã®è²©å£²","subscription":"ãµãã¹ã¯ãªãã·ã§ã³","wishlist":"3Dã¢ãã«æ¬²ãããã®ãªã¹ã"},"settings":"è¨å®"}},"owly":{"failed_set_pending":"ä¿çä¸ã«è¨å®ã§ãã¾ããã§ããã","failed_to_approve":"æ¿èªã«å¤±æãã¾ããã","failed_to_suspend":"䏿忢ã«å¤±æãã¾ããã","failed_to_update_license":"ã©ã¤ã»ã³ã¹ã®æ´æ°ã«å¤±æãã¾ããã","failed_to_update_status":"æ¿èªã¹ãã¼ã¿ã¹ã®æ´æ°ã«å¤±æãã¾ããã"}
16518,"print_models":{"browse_all_makes":"ãã¹ã¦ã®3Dã¡ã¤ã¯ãè¦ã","browse_all_models":"ãã¹ã¦ã®ã¢ãã«ãé²è¦§","description":"ã²ã¼ã ãã¢ã¼ããå®¶åºããã¸ã§ã¯ããªã©ã«ä½¿ãã人æ°ã®3Dããªã³ã対å¿ã¢ãã«ãSTLãã¡ã¤ã«ãçºè¦ã","makes_description":"ã³ãã¥ããã£ã«ãã£ã¦ã¢ãããã¼ããããææ°ã®3Dã¡ã¤ã¯ãæ¢ãã â 3Dã¢ãã«ãç¾å®ä¸çã§ã©ã®ããã«è¦ãããã示ãå®ä¾ã§ãã","makes_title":"æ°ãã3Dã¡ã¤ã¯","new_description":"ã³ã¬ã¯ã·ã§ã³ã«è¿½å ãããææ°ã®3Dããªã³ãããã§ãã¯ãã¾ããããæ¬¡ã®ããã¸ã§ã¯ãã«ããã«ãã¦ã³ãã¼ããã¦å°å·ã§ããæ°ãããã¶ã¤ã³ã§ãã","new_title":"æ°ãã3Dããªã³ãã¢ãã«","title":"人æ°ã®3Dããªã³ãã¢ãã«"},"profile":{"account_settings":{"account":{"email":"ã¡ã¼ã«ã¢ãã¬ã¹","submit":"ä¿å","title":"ãããã£ã¼ã«","update":{"updated":"ãããã£ã¼ã«ãæ´æ°ããã¾ãã"},"username":"ã¦ã¼ã¶ã¼å"},"email_settings":{"descriptions":{"ai_studio_notifications":"CGTrader AI ã®çæã«é¢ããéç¥ï¼ã¾ã éãã¦ããªãã¢ãã«ã®æºåãå®äºããå ´åãå«ãï¼","communication":"ä»ã®CGTraderã¦ã¼ã¶ã¼ã¨ã®ã³ãã¥ãã±ã¼ã·ã§ã³ã«é¢ããæ
å ±ï¼å人ã¡ãã»ã¼ã¸ãæ°ããä¾¡æ ¼ã¨ã«ã¹ã¿ã ã¸ã§ããªãã¡ã¼ããã£ã¼ãããã¯ã製åãµãã¼ããªã¯ã¨ã¹ããå«ãï¼","news":"CGTrader製åãæ°æ©è½ã®çºè¡¨ãã³ãã¥ããã£ãã¥ã¼ã¹ã«é¢ããæ
å ±","onboarding_and_edu":"ãªã³ãã¼ãã£ã³ã°ããã»ã¹ã¨CGTraderãæå¤§éã«æ´»ç¨ããããã®ãã³ãã«é¢ããæ
å ±","push_notifications":"éè¦ãªã¢ã«ã¦ã³ãã¢ã¯ãã£ããã£ã¨æ´æ°ã«é¢ããéç¥","sales_and_offers":"ç¹å¥ãªãã¡ã¼ã3Dã¢ãã«ã»ã¼ã«ãCGTraderãã¼ãã¹ã¯ã¬ã¸ããã«é¢ããæ
å ±","seller_sold_item":"販売ãã3Dã¢ãã«ã¨åãåã£ãæ¯æãã«é¢ããæ
å ±"},"privacy_policy_html":"詳細ã«ã¤ãã¦ã¯ã\u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003eãã©ã¤ãã·ã¼ããªã·ã¼\u003c/a\u003eãã覧ãã ããã ","titles":{"ai_studio_notifications":"CGTrader AI ã®éç¥","communication":"ã³ãã¥ãã±ã¼ã·ã§ã³ï¼å人ã¡ãã»ã¼ã¸ã3Dã¢ãã«ã®ãã£ã¼ãããã¯ãã³ãã¥ããã£æ´»åããªãã¡ã¼ï¼","news":"3Dãã¥ã¼ã¹ / CGTraderã®æ´æ°","onboarding_and_edu":"ãªã³ãã¼ãã£ã³ã°ã¨æè²","push_notifications":"éè¦ãªã¢ã«ã¦ã³ãã¢ã¯ãã£ããã£ã¨æ´æ°ã«é¢ããéç¥","sales_and_offers":"ã»ã¼ã«ã¨ç¹å¥ãªãã¡ã¼","seller_sold_item":"売ä¸ã¨æ¯æãæ
å ±"},"tracking_attributes":{"ai_studio_notifications":"CGTrader AI ã®éç¥","communication":"ã³ãã¥ãã±ã¼ã·ã§ã³","news":"3Dãã¥ã¼ã¹ / CGTraderã®æ´æ°","onboarding_and_edu":"ãªã³ãã¼ãã£ã³ã°ã¨æè²","sales_and_offers":"ã»ã¼ã«ã¨ç¹å¥ãªãã¡ã¼","seller_sold_item":"売ä¸ã¨æ¯æãæ
å ±"},"update":{"updated":"ã¡ã¼ã«ãæ£å¸¸ã«æ´æ°ããã¾ããã"}},"gdpr_success_notification":{"opt_in":"ãããã¨ããããã¾ãï¼ ã¡ã¼ã«ã®åè³¼èªã«æåãã¾ããã","opt_out":"ãã¥ã¼ã¹ã¬ã¿ã¼ã®è³¼èªãè§£é¤ãã¾ããããã®è¨å®ã¯ããã¤ã§ããããã£ã¼ã«è¨å®ãã夿´ã§ãã¾ãã\n"},"location_tooltip_text":"\u003cdiv\u003eãã®ãã§ãã¯ããã¯ã¹ããªã³ã«ããã¨ããããã£ã¼ã«ãã¼ã¸ã«ä½ç½®æ
å ±ã表示ã§ãã¾ãã\u003c/div\u003e \u003cdiv\u003eãã ããã³ã³ãã©ã¤ã¢ã³ã¹ä¸ã®çç±ã«ããããããã®å ´åã§ããããªãã販売è
ã§ããã°è³¼å
¥è
ã«ãè³¼å
¥è
ã§ããã°è²©å£²è
ã«ä½ç½®æ
å ±ã表示ããããã¨ã«æ³¨æãã¦ãã ããã\u003c/div\u003e","moneybookers":{"account":"Skrillã¢ã«ã¦ã³ã"},"password":{"current_password":"ç¾å¨ã®ãã¹ã¯ã¼ã","new_password":"æ°ãããã¹ã¯ã¼ã","submit":"ãã¹ã¯ã¼ãã夿´","title":"ãã¹ã¯ã¼ã","updated":"ãã¹ã¯ã¼ããæ£å¸¸ã«æ´æ°ããã¾ãããæ°ãããã¹ã¯ã¼ãã§ãã°ã¤ã³ã§ãã¾ãã","verify_password":"ãã¹ã¯ã¼ãã®ç¢ºèª"},"paypal":{"account":"PayPalã¢ã«ã¦ã³ã","submit":"ä¿å","title":"PayPalè¨å®","update":{"updated":"PayPalè¨å®ãæ´æ°ããã¾ãã"}}
16518,"personal_info":{"areas_of_expertise":"å°éåé","country":"å½","description":"èªå·±ç´¹ä»","full_name":"æ°å","languages":"è¨èª","preffered_tools":"使ç¨ãã¼ã«","submit":"ä¿å","title":"å人ããã³å°éæ
å ±","update":{"updated":"æ
å ±ãæ£å¸¸ã«æ´æ°ããã¾ãã"},"website":"ã¦ã§ããµã¤ã"},"personalization":{"no_muted_title":"ãã¥ã¼ãããããã¶ã¤ãã¼ã¯ãã¾ãã","title":"ãã¥ã¼ãããããã¶ã¤ãã¼","tooltip":"ãªã¹ãããããã¶ã¤ãã¼ã®3Dã¢ãã«ã¯æ¤ç´¢çµæããé¤å¤ããã¾ãã","unmute_designer":{"confirm":"æ¬å½ã«è§£é¤ãã¾ããï¼"}},"professional_info":{"allow_private_job_requests":"è³¼å
¥è
ã¯ã«ã¹ã¿ã 3Dã¸ã§ããªã¯ã¨ã¹ããéä¿¡ã§ããããã«ãªãã¾ãã","buyer_engagement_program_html":"CGTraderãã¤ã³ãã§ã¢ãã«ãè³¼å
¥ã§ããããã«ãã¦ãããå¤ãã®é¡§å®¢ãå¼ãä»ãã¾ãããã\u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003e詳細ã¯ãã¡ã\u003c/a\u003e\n","pbr_program":"夿ããããã¡ã¤ã«ããã¦ã³ãã¼ããããå ´åã®ã¿ãä½ãåççãé©ç¨ããã¾ãã","pbr_program_agreement":"%{date}ã«24ãæéã®PBRããã°ã©ã ã«åå ãããã¨ã«åæãã¾ããã詳細ã«ã¤ãã¦ã¯å©ç¨è¦ç´ãã覧ãã ãããã質åãããå ´åã¯ããµãã¼ãã«ãåãåãããã ããã","product_analytics_participation_html":"\u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eAnalytics\u003c/a\u003e ã«åå ãããã®å©ç¨è¦ç´ã«åæãã¾ãã\n","product_analytics_participation_tooltip_html":"Analyticsã«åå ããAnalyticså©ç¨è¦ç´ (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003eãªã³ã¯\u003c/a\u003e) ã«%{accepted_at}ã«åæãã¾ãããåå ãçµäºãããå ´åã¯ãCGTraderãµãã¼ãã«ãåãåãããã ããã\n"},"security":{"allow_mfa":"ã¢ã«ã¦ã³ããä¿è·ããããã«2段éèªè¨¼ãæå¹ã«ãã","use_authenticator_app":"2段éèªè¨¼ã«èªè¨¼ã¢ããªã使ç¨ãã","use_authenticator_app_tooltip":"QRã³ã¼ããèªè¨¼ã¢ããªï¼Google Authenticator / Authyï¼ã§ã¹ãã£ã³ãã¦ãèªè¨¼ã³ã¼ããçæãã¾ãã","use_email":"2段éèªè¨¼ã«ã¡ã¼ã«ã使ç¨ãã"},"sidebar":{"general_settigns":"ä¸è¬è¨å®","member_since":"ç»é²æ¥","paypal":"PayPal","title":"ã¢ã«ã¦ã³ãæ
å ±"},"title":"ãã¤ã¢ã«ã¦ã³ã"},"conversations":{"conversations":"ä¼è©±","messages":{"loading":"ãã¼ãã®åä¿¡ãã¬ã¤"},"types":{"cgtrader_support":"CGTraderãµãã¼ã","file_conversion_request":"ãã¡ã¤ã«å¤æè¦æ±","job_application":"3Dããã¸ã§ã¯ã","model_feedback":"製åãã£ã¼ãããã¯","model_support":"ã¢ãã«ã®ãµãã¼ã","offer":"è¦ç©ãã","personal":"ãã©ã¤ãã¼ãã»ã¡ãã»ã¼ã¸","promotions":"ããã¢ã¼ã·ã§ã³"}},"meta":{"description":"CGTraderã§%{username}ã«ããé«å質ãª3Dã¢ãã«ããã§ãã¯ãã²ã¼ã ãVR/ARããã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³åãã®ã¦ãã¼ã¯ãªç´ æãé²è¦§ã§ãã¾ãã","title":"3Dã¢ãã«ãã¶ã¤ãã¼ï¼%{username}"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"è¨å®ãæ£å¸¸ã«æ´æ°ããã¾ããã"},"publishing":{"banned_error":"ã¹ãã ã³ã³ãã³ããæç¨¿ãããããããªãã®ã¢ã«ã¦ã³ãã¯ç¦æ¢ããã¾ããããããééãã ã¨æãããå ´åã¯ã[email protected] ã«ãåãåãããã ããã","files_not_finalized":"1ã¤ä»¥ä¸ã®ãã¡ã¤ã«ã®ã¢ãããã¼ããå®äºãã¦ããªããããå
¬éã§ãã¾ãããåé¤ãã¦ãããããä¸åº¦ã¢ãããã¼ããã¦ããå
¬éãã¦ãã ããã","spam_suspect":"ããªãã®ã¢ã«ã¦ã³ãã¯ãã®ã¢ãã«ãå
¬éããæ¨©éãããã¾ããããããééãã ã¨æãããå ´åã¯ã[email protected] ã«ãåãåãããã ããã"},"rating":{"anonymous_buyer":"å¿åã®è³¼å
¥è
","errors":{"not_verified_buyer":"è³¼å
¥ã確èªãããè³¼å
¥è
ã®ã¿ã¬ãã¥ã¼ãæ®ããã¨ãã§ãã¾ã"}},"routes":{"discover":"hakken","search":"search"},"sale_off":{"no_overlapping_campaigns":"ãã£ã³ãã¼ã³ã®æ¥ä»ãæ¢åã®ã»ã¼ã«ãã£ã³ãã¼ã³ã¨éè¤ãã¦ãã¾ãã","parse_discount_rules_text":"è¡ #{index} ã«å¿
é ã® 'discount:' ãããã¾ãã"},"search":{"not_found":"æ¤ç´¢ãµãã¹ã¯ãªãã·ã§ã³ãè¦ã¤ããã¾ãã","subscription_created":"æ¤ç´¢ãµãã¹ã¯ãªãã·ã§ã³ã使ããã¾ãã","successfully_unsubscribed":"æ¤ç´¢ãµãã¹ã¯ãªãã·ã§ã³ãæ£å¸¸ã«è§£é¤ãã¾ãã"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"flash":{"active_subscription":"ãã§ã«æå¹ãªãµãã¹ã¯ãªãã·ã§ã³ããæã¡ã§ãã","premium_upgrade_unavailable":"Premium ã¸ã®ã¢ããã°ã¬ã¼ãã¯ä¸æçã«ãå©ç¨ããã ãã¾ããããã°ãããã¦ããããä¸åº¦ã試ããã ããã","update_payment_method":"ãµãã¹ã¯ãªãã·ã§ã³ã®ãæ¯æãã«åé¡ãããã¾ããæ°ãããµãã¹ã¯ãªãã·ã§ã³ãè³¼å
¥ãã代ããã«ããæ¯æãæ¹æ³ãæ´æ°ãã¦ãã ããã"},"payment_form":{"current_price":"%{price}","features":{"first":"æ%{downloads}ã¢ã»ãã â ã¢ãã«ã®ãã¦ã³ãã¼ãã¾ãã¯AIã§çæ","second":"%{models_count}以ä¸ã®å¿
é 3Dã¢ãã«ã«å³æã¢ã¯ã»ã¹","third":"ãã¤ã¤ãªãã£ããªã¼ãAIãªã"},"from_price_label":"ãã","original_price":24.99,"per_model_label":"1ã¢ãã«ããã","plan_name":"CGTrader Essentials Subscription â å¹´éãã©ã³ãæ¯æè«æ±","premium":{"features":{"first":"æ%{downloads}ã¢ã»ãã â ã¢ãã«ã®ãã¦ã³ãã¼ãã¾ãã¯AIã§çæ","fourth":"ãã¤ã¤ãªãã£ããªã¼ãAIãªã","second":"%{models_count}以ä¸ã®ã¢ã¯ã»ã¹å¯è½ãªå
¨ã¢ãã«ã«å³æã¢ã¯ã»ã¹","third":"Essentialsã«å«ã¾ããªããã仿§ã®ã¢ãã«"},"plan_name":"CGTrader Premium Subscription â å¹´éãã©ã³ãæ¯æè«æ±"},"price_unit":"/æ","vat_amount":"%{vat_amount}"}},"tag":{"description":{"bottle":"ç§å¦è
ãã¡ã¯ãã¯ã¤ã³ã®ããã«ã®æ¥ãããªãã®ããã«æªãããã§ã¯ãªãããããã¯ã¦ã¤ã¹ãã¼ããã¼ãã³ã®ãããªå¼·ã飲ã¿ç©ã«æ¥ãã¨ããç§ãã¡ã¯æ¬å½ã«ç§ãã¡ã®ã¢ã«ã³ã¼ã«æåéãè¦ãªããã°ãªããªãã¨è¨ãã¾ããæããã«ãæ°´ã®ãããããã«ããããã¼ã«ãã¯ã¹ã¦ã§ã¤ã¯ã¼ã©ã¼ã§ã·ã£ã³ãã³ã®ã°ã©ã¹ããé·å¯¿å½ã¨ãã¼ã«ã®çæ´»ã®å¯è½æ§ãèããã«ã¯ãåççãªç ç²ã®ããã«è¦ããã ãããããã«ï¼
16518ãªãªã¼ããªã¤ã«ã®ã·ã£ã³ãã¼ããï¼3Dã¢ãã«ã®ãã¹ã¦ã®ç¨®é¡ã®ã¯ã¤ã³ã©ãã¯ã¨ã³ã«ã¯æ æãã®ãããªã¢ã«ã³ã¼ã«é¢é£ã®ãªãã¸ã§ã¯ãã«è³ãã¾ã§ãã®ã«ãã´ãªã«ã¯ãç³ãåºããã«3Dã¢ãã«ã®å¹
åºã鏿ããã","brain":"è³ã¯äººéã®ä½å
ã§æå¤§ãã¤æãè¤éãªå¨å®ã®ä¸ã¤ã§ãããã®è¤éãªæ§é ã¨æ©è½ã®ããã«ãè³ã®è§£åå¦ãé常ã«è¤éã§ããããããç§å¦è
ãã¡ã¯æ°ãé ããªãç§å¯ãæ´ãã人éã®è³ã®ã¢ã¼ããã¯ãã£ã«æ·±ãæãã¾ãã 3Dãã¶ã¤ã³ã«é¢é£ããç¾å®çãã¤è©³ç´°ãªè³ã®åºãç¯å²åºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ããä»ã®ãã£ã¼ã«ãã®ãããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ãã3Dã¢ãã«ããã¦ã³ãã¼ãã§ãã¾ãã","building":"ç¾ä»£ã®å»ºç¯å®¶ããã¤ã³ã¹ãã¬ã¼ã·ã§ã³ãåããã¨ããä¸ççã«æåãªå»ºç¯ç©ã®ããã¤ãã¯ããããå½¼ãã¯æªæ¥ããã®ãã¸ã§ã³ã®ããã«è¦ãããã¨ã«ç«¯ãã«ãããã¦ããã¨ããã¯ä¸æã§ããããã¦ãç§ãã¡ã¯ãã å¤è£
é¨åãæå³ãããã®ã§ã¯ããã¾ãã...æè½ã§ã¯æ¨æºã®å»ºç©ã®å»ºè¨ã¯é¢ä¿ãªããããã¯ãªãã£ã¹ãé½å¸é¨ã®å»ºç©ã®ãã©ããã®é©æ°çãªã¤ã³ããªã¢ãã¶ã¤ã³ã¨æ¯ãã®ããããªå»ºç¯ã®ä½æã«ãªãã¾ãã 3Dã¢ãã«ãæ§ç¯ããç§ãã¡ã®é¸æã¯ããã¦ã³ãã¼ãã®æºåãã§ãã¦ããã¨æ§ã
ãªåéã«å¿ç¨ãããã¨ãã§ãã¾ã - 3Dã¢ãã¡ã¼ã·ã§ã³ãã°ã©ãã£ãã¯ãã¶ã¤ã³ãåºåã3Dã²ã¼ã ãã¦ã§ãã","camera":"åçã¨æ®å½±ã¯ç¾å¨ãè¥è
ã®éã§æã人æ°ã®ããè·æ¥åéã®ä¸ã¤ã§ããããããã®ã«ã¡ã©ã§èª°ããã¢ã¼ãã£ã¹ããåçå®¶ã§ããæºå¸¯é»è©±ã®ã«ã¡ã©ã®å質ã¯å¹´ã
åä¸ãã¦ãæã
ã¯ã人ã
ã¯ãã¹ã¦ã®ã¹ãããã§åçãæ®ãã¨ã¹ãã«ãç·¨éããæ°éçºã®ã¤ã¡ã¼ã¸ãæã£ã¦ãã人ã¯ãæ¬å½ã«ç¥ã£ã¦ããåç
§ãã¦ãã ããã人çã¯3Dã¢ãã«ã使ç¨ããã¨ãã¬ã³ãºã®åããå´ã«ããã¨ãã«å°ãéã£ã¦è¦ããããã®ã¯å¤¢ä¸ãªãããã«ãã¾ããã...詳細ã«ã¡ã©ã®åºãç¯å²ããã¦ã³ãã¼ãã¯ãã°ã©ãã£ãã¯ãã¶ã¤ãã¼ãã¢ãã¡ã¼ã·ã§ã³ãã²ã¼ã éçºè
ã使ç¨ããããã«æä¾ããã¦ãã¾ããå°éå®¶ã¯ãä»ã®3Dé¢é£ã®åéã§æ´»èºãã¾ãã","car":"ãããã®é常ã«è©³ç´°ãã¤é常ã«ãªã¢ã«ãª3Dã®è»ã®ã¢ãã«ãè¦ãã¨ãããªãã¯ã»ã¨ãã©ã¨ã³ã¸ã³ã®è½é³ãèããã¨ãã§ãã¾ãï¼ããªãã¯ã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ãã¢ãã¡ã¼ã·ã§ã³ãä»ã®3D-é¢é£åéã«åãçµãã§ããå ´åã¯è»ä¸¡ã®åºãç¯å²ã¯ã3Dã¢ãã«ã¯ãããªãã®äººçã¯ãããªã«ç°¡åã«ä½ããã¨ãã§ãã¾ãã","cell":"ç§å¦è
ãã¡ã¯ã人éã®ä½ã¯50åãã2åå
åã®ç´°èã«å«ã¾ãã¦ããã¨æ¨å®ãã¦ãã¾ããæ¤ç©ãåç©ããç´°èãæã£ã¦ãã¾ããç§ãã¡ã¯ãç§ãã¡ãã«ãã¼ã«è¡æ¶²ãã¦ã¤ã«ã¹ããã³DNAãã骨é«ããã³ç´°èå£ã«ãã¹ã¦ãæã£ã¦ãããã¨ããããªãã¯ããã®çç©ã®ãã®ã¨ãã¢ã«ãããããç´°èã®3Dã¢ãã«ã®åºãç¯å²ã§ã¯ããã¾ãããç¥çµã-ã©ããã³ã°ãã¨...ã§ã¯ãªãã§ããï¼","chair":"ç§ãã¡ã¯ã許å¯ããã常ã«å½¼ãã¯ç§ãã¡ã®å®¶åºããªãã£ã¹ã¤ã³ããªã¢ã«è¿½å ãããã¨ãã§ãã¾ãã©ã®ãããã®é
åæ°ã¥ããªãããã«æ¤
åã«åº§ã£ã¦ãã ãããè°é·ã¯ãå®éã«ã¯ã©ã®å®¶åºã§å®¶å
·ã®ä¸å¿çä½åã®ä¸ã¤ã§ããåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ãã3Dã²ã¼ã ã« - ããã§ã¯ãé«å質ã¨ç®ãå¼ããã¶ã¤ã³ã®æ¤
åæ§ã
ãªåéã§é©ç¨ãããã¨ãã§ãã3Dã¢ãã«ãè¦ã¤ãããã¨ãã§ãã¾ãã","city":"é½å¸çæ´»ã¯ãåå¿ã²ã¼ã ã§ããï¼ä¸æµ·ãããã¥ã¼ã¨ã¼ã¯ã¸ã®æ©ãå
¬åãå¯ã¬ã¼ã¹ã¿ã¯ã·ã¼ã§ç ´è£éããè¿ä»£çãªå»ºç©ãå®ç§ã«ä»ç«ã¦äºåæã§æ©è¡è
ã...ï¼ï¼ãã³ããã¿ã³ï¼ã¯ããã³ãã³ãããªã¸ - ãã¹ã¦ã®é½å¸ã¯ããã®ãæã£ã¦ãã¾ãèªåã®éæ³ãåºåãã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ãã¢ãã¡ã¼ã·ã§ã³ã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ãã²ã¼ã - ããªãã¯ãã£ã¼ã«ãã®æ°ã§ä½¿ç¨ãããã¨ãã§ãã詳細ãªé½å¸3Dã¢ãã«ã®ãã®è±ããªé¸æãã鏿ãããã¨ãã§ãã¾ããé½å¸çæ´»ãæ¢æ¤ã","dragon":"ãã©ã´ã³ã¯ããããããã¡ã³ã¿ã¸ã¼ã®ä¸çã«ä½ãã§æã人æ°ã®ããçãç©ã§ããããã¯ãä¼èª¬ã¨ãªã£ã¦ãããã¨ãæ§ã
ãªæåãã¢ãã¡ã¼ã·ã§ã³ãæ ç»ãæ¸ç±ã®ããã«å¤ãã®ç¥è©±ã«ç»å ´ãã¾ãããããã¯æãæ´çªããã³ã¸ã§ã³ã«ãã®ä¸æè°ãªé
åã追å ããã¨ããã¯ç¹ã«ãã²ã¼ã éçºè
ã«æããã¦ãã¾ããç¾å®çãªã®åºãç¯å²ãããã¦ã³ãã¼ãå¯è½ãªåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ãããã³3Dãã¶ã¤ã³ã«é¢é£ããä»ã®ãã£ã¼ã«ãããããããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ãããã©ã´ã³ã®3Dã¢ãã«ãè£
åãã¾ããã","earth":"Googleãããã§æè¿è¿½å ãããå°çã®ãã¥ã¼ã®è©³ç´°ã¬ãã«ã¯ã人ã
ã®æ°ã«è¡æãä¸ãã¾ãããããªãã®å®¶ãé¢ãããã¨ãªããé½å¸ãé ãããéãçºè¦ããæµ·ãå±±ãç æ¼ - ããªãã¯ãå
¨ä½ã®ææãæ¢ç´¢ãããã¨ãã§ãã¾ããããã¯æ¯ãªãå°çãåã«çµé¨ãã¦ããªãããã¤ãã®ä¿¡ããããªãã»ã©ã®ãã®ã§ãã 3Dãã¶ã¤ã³ã«é¢é£ãããªã¢ã«ãªå°çã®é¸æåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ããä»ã®ãã£ã¼ã«ãã®ãããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ãã3Dã¢ãã«ããã¦ã³ãã¼ãã§ãã¾ãã","engine":"ä¸é¨ã®äººã
ã¯ãåã«ãããä½ãé³ãèããã¨ã«ãã£ã¦ã¨ã³ã¸ã³ã«ååãä»ãããã¨ãã§ãã¾ããããã¯æ¬å½ã«ç´ æ´ãããã§ããããããããããã¯ã¸ã§ããã¨ã³ã¸ã³ãè»ã®ã¨ã³ã¸ã³ã ãã©ããã®ãå½¼ãã¯æã
ãããã»ã©é »ç¹ã«ä½¿ç¨ãããã¨ãé常ã«è¤éãªæ©æ¢°ã ããããã«ã¤ãã¦ã¯ããã¾ãã«ãå¤ãã®æéæèãè²»ãããã¨ã¯ããã¾ããã ï¼ãããåãã¦åæ¢ããã¾ã§ï¼ã®ã¢ã¼ã¿ã¯ãã¢ã¼ã¿ã§ãããã®ã«ãã´ãªã«ã¯ãã¨ã³ã¸ã³ã3Dã¢ãã«ã®ç°ãªã種é¡ã®ç¯å²ãæã£ã¦ãããæã
ã¯ããªããå¿
è¦ãªãã®ãè¦ã¤ããã¨ç¢ºä¿¡ãã¦ããã®ã§ãããã¯ã¾ãããããã©ãã·ãªã³ãã¼ãªã©ã®ã¨ã³ã¸ã³é¨åãå«ãã§ãã¾ãã","female":"ããã¯ãç·æ§ã¨å¥³æ§ã®è³ã®éã«ææãªå·®ããããã¨ãããã¯å
¨ãç°ãªãæ¹æ³ã§å¹³åç·ã¨å¥³æ¯ãèããæè§¦ã¨å¿çãããã¨ãæ£å¸¸ã§ãããã¨ããã®ææ®µåè«ã¾ãããããããããã¯è§£åå¦ã«ã¤ãã¦ã®ãã¹ã¦ã§ã¯ããã¾ããã女æ§ã®é
åã®
16518åã¯å¦å®ã§ããªãåå ã¨ãªããããªæã®ç©èªãæ ç»ãã²ã¼ã ã¯ä»ã¾ã§ã«ãå¼·ã女ã®åã®æåãªãã§ãããå¼ã£å¼µã£ã¦ãã¾ããããã¼ã3Dã¢ãã«ãã女æ§ã®å¼å¸å¨ç³»ã¸ - ç¾å®çãªå¥³æ§ã®3Dã¢ãã«ã®è±å¯ãªé¸æã¯ããªããå¿
è¦ãªãã¹ã¦ãæä¾ãããã¨ãã§ãã¾ãã","hand":"æã
ã¯é常ã«å¤ãã®ãã®ã®ããã«ç§ãã¡ã®æã使ãçç±ã¯ãå½¼ãã®ç°å¸¸ãªè§£åå¦ã§ãã親æã¯ãåç¬ã®9ã¤ã®å¥ã
ã®çèã«ãã£ã¦å¶å¾¡ããã¾ããããã¯ä¿¡ããããã§ãããåæã®æã¯ã仿¥ã©ããªæãããã¨ãã¾ããã¯ã ã£ã - ããã¤ãã®ç¨®ã¯ã7æ¬ã®æãæã£ã¦ãã¾ããã人éã®ä½ã¯ã大å¹
ã«é²åãã¦ãã¾ãããæã
ã¯ä»æ¥ãããè¦ãããã«è
ãæã¯ããã®åæã®ãã¼ã¸ã§ã³ã®ãããªãã®ãè¦ãã¾ãããç¾å®çãªã®åºãç¯å²ãã3Dãã¶ã¤ã³ã«é¢é£ããåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ããä»ã®ãã£ã¼ã«ãã®ãããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ãã3Dã¢ãã«ããã¦ã³ãã¼ãã§ããã®æãè£
åãã¾ããã","head":"人éã®è§£åå¦ã§ã¯ããããã¯ã人ä½ã®ä¸é¨ã«ããã¾ãããã¼é¢ç½ããç®ãè³ãé¼»ãåãããã®ã©ã¤ã³ããã¦ãã ãã - ç§ãã¡ã¯ã対称ããªã¢ã«ãªãããæè¬ï¼é常ã«å¤ãã®ç°ãªãå½¢ç¶ããã³ãµã¤ãºãããã«ããããããï¼ã®ã§ã3Dã®äººéã®é é¨ã®ã¢ããªã³ã°ã¯ãè¤éãªå°ãã証æãããã¨ãã§ãã¾ããé¡ã¯ææãªé¨åã§ãããã¡ããã©ãããæ¥½ããã§ããã®ã¯å¤±ç¤¼å¹³éã ãããç§ãã¡ã®é¸æã¯ç¾å®çãªç·æ§ã女æ§ãåä¾ãããªã¼ããã¿ã¼ã¨ããããã³ã¾ãã¯ãã¦ã³ãã¼ãããæºåãã§ãã¦ãããã ã»ã¯ã«ã¼ãºã¨ã¹ã«ã¼ã¬ããã»ã¨ãã³ã½ã³ã®é ã®ãããªæå人ã®ããã«ãç©èªã®ãã£ã©ã¯ã¿ã¼ãå
å«ããã","helmet":"ããªãã®é é¨ãä¿è·ãããã¨ã¯ãé³ã®ã¢ã¤ãã¢ã§ãã®ã§ãå¿
ããå®å
¨è¡çãæåã«æ¥ããã¨ãè¦ãã¦ããã¦ãã ãããä¸ä¸ã®é¨å£«ãããããã³ã¯ãããã«ã¯ã¢ã¤ã¢ã³ãã³æ©èãã«ã¡ãããèªè»¢è»ããã«ãã¼ã®ãããªã®ã§ã宿çãªã¹ã¼ãã¼ãã¼ãã¼ã¯ããµããè¦ã¦å¿é
ãã¦ã¯ããã¾ãããããªãã¯ãã°ã©ãã£ãã¯ãã¶ã¤ã³ã3Dã¢ãã¡ã¼ã·ã§ã³ã3Dã²ã¼ã ããã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã®åéã§ä½æ¥ãã¦ããå ´åã¯ããã¦ã³ãã¼ãã®ããã«å©ç¨å¯è½ã§ãããã«ã¡ããã®3Dã¢ãã«ã®ãã®ã³ã¬ã¯ã·ã§ã³ã¯æç¨ã§ãããã¨ãåããã ããã","house":"ããã¯ç·ã®å®¶ã¯å½¼ã®åã§ãããã¨ãå¤ãçå®ã ããããã¯ãã®å®ç§ãªå®¶ã建ã¦ãããçæ³ã®ãã³ã·ã§ã³ãè²·ãã«æ¥ãã¨ããæã
ã¯ããã®ä¸ã«ç§ãã¡ã®é ã失ãå¾åããããã幸ããªãã¨ã«ãã¢ã¼ããã¯ãã£ã®è©³ç´°ãå
é¨ã¨å¤é¨ããã®ãã¹ã¦ãç¶²ç¾
å®¶3Dã¢ãã«ã®ãã®åºãã¹ãã¯ãã«ã¯ãå®¶å
·ã«ãããªãã¯ãã®çã¿ãåãããããã«è¿ä»£çãª3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã使ããã®ã«å½¹ç«ã¡ã¾ãã","human":"ããªãã¯äººéã®è§£åå¦ãæ¢ç´¢ãéå§ããã¨ããããªãã¯ã人ã
ãããã¯æ¯ãåããããªè¤éãã¤è¤éãªæ©æ¢°ã§ãããã¨ãèªèãã¦ãã¾ãããã¹ã¦ã®èº«ä½ã®é¨åãçèãé¢ç¯ãèå¨ã骨ã®çµã¿åãããã1ã¤ã®ã·ã¹ãã ã«æ¥ç¶ãããä½ãå¤ç«ãã¦åãã¾ããï¼ãããã®è¶
ãªã¢ã«ãª3D人éã¢ãã«ã使ç¨ããã¨ãããããè§åº¦ããè§£åå¦çæ§é ã調ã¹ããã¨ãã§ãã¾ãã","lamp":"ããªãã®å®¶ã®å¨ããè¦ã¦ãããªããææãã¦ãããã¨ãã©ã³ãã®ç¨®é¡ãã«ã¦ã³ãããå ´åãããªãã¯é©ããããã¨ã§ãããï¼èªæ¸ããã¼ãã«ãå£ã天äºããã¹ã¯ãä¸èã©ã³ã...ããã¯ããªãã®é ã®ã¹ãã³ãä½ãã®ã«ååã§ãï¼ã¬ãããªã¹ã¿ã¤ãªãã·ã¥ãªæªæ¥ã¸ã®è´
æ²¢ãªè¿ä»£çãªã©ã³ããã - å½¼ãã¯æ¥ããã¨ã®ã¹ã¿ã¤ã«ã¯è¨ãã¾ã§ãããã¾ãããé²è¦§ããã³ãã¦ã³ãã¼ãã¯ãã°ã©ãã£ãã¯ãã¶ã¤ã³ã3Dè¦è¦åã¾ãã¯ä»»æã®ä»ã®3D-é¢é£åéã§ä½¿ç¨ããã®ã§ããã®ã«ãã´ãªã§ã¯ãæã
ã¯ãã©ã³ã3Dã¢ãã«ã®ãã¹ã¦ã®ç¨®é¡ãæã£ã¦ãã¾ãã","light":"é»çã¯ç´ æ´ãããã¢ã¤ãã¢ã®è±¡å¾´ã§ããçç±ããªããçåã«æã£ããã¨ãããã¾ããï¼ç¢ºãã«ãæããã®ã¢ã¤ãã¢ãå¿ã®ã¢ã¼ããã¯ãã£ãåçºãããã¨ãã§ãã¾ãããããã¯ããã§ã¯ããã¾ãããè¡è·¯ç¯ãã·ã£ã³ããªã¢ãã©ã³ãã®ä»ã®ã¿ã¤ãã¯ããã®å ´æãåããã£ã³ã¹ããªã
16518ã ãããããªãã¯å¤©äºãè¦ä¸ããã¨...ããªãã¯ééã£ãé·ã·ã¹ãã ãåè¦ãã¦ããã®ã§ã天æã®ã¢ã¤ãã¢ã¯ãããã¯ãããããããªãããªãã«å½ãããªã建ç¯å
ã®ããã¤ãã®ç¨®é¡ã§é«å質ãªå
ã®ç§éã®é¸æãåè¦æ¬¡åã®å ´åããªãã¯å»ºç¯ãã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã3Dã¢ãã¡ã¼ã·ã§ã³ããã¶ã¤ã³ã®åéã§åãå ´åã®3Dã¢ãã«ã¯ã便å©ãªãã¨ã証æãã¾ãã","machine":"ç¡ã³ã¼ãã¼ããªã便å©ãªæ´æ¿¯æ´æ¿¯ãéãã®è§ã«ãã£ãã·ã¥ãã¤ã³ããç¡ã¸ã æéãç¡é«å¤èªå販売æ©...ããã¯é³ããã¯ãããã¾ããæ¼ãä¸ããï¼ãã¹ã¦ã®ãã·ã³ãçªç¶åä½ã忢ããªãå ´åã«ã¯æ³åï¼ç§ãã¡ã¯ããããããã¯æåéãä¸çã®å転ã忢ãããã¨ããããã®å®¶é»è£½åãé»åã¬ã¸ã§ããã«ä½¿ç¨ããã¦ãã¾ãï¼å¹¸ããªãã¨ã«ãæ©é¢éããã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ãåºåã3Dã¢ãã¡ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ãã§ã®ä½æ¥ãã¶ã¤ãã¼ã«æç¨ã§ãããã¨ãåããã ããçºé»æ©ã®è©³ç´°ãªæ©æ¢°ã®3Dã¢ãã«ã®ã«ãã¼ã®ãã¹ã¦ã®ç§ãã¡ã®é¸æã","man":"ç·3Dã¢ãã«ã®è¨å¤§ãªã³ã¬ã¯ã·ã§ã³ã¯ããã¦ã³ãã¼ããããã¨ãã§ãã¾ããã¿ããªã®å¾ã®ãã¨ãå®ç§ãªç·ãé¤ã㦠- ç·ãåç´ãªç·ãé£ã¶ç·ãå¹³åç·ã«åº§ã£ã¦ãç§ãã¡ã¯ãã¹ã¦ãæã£ã¦ãã¾ããå½¼ã¯éã®æåã ã¨ãç§ãã¡ã¯ããã®ã¢ããããããããã¨ãæãããããã¯ç¥è©±ã§ãããããããªã...ã§ãããã人éã¯å®ç§ã§ã¯ãªããç´ æ´ããããã¨ãçã¾ãã¦ãã¾ãã","robot":"R2D2ã¯ãããããä¸çã§æãæåãªããããã§ãããããã¯ç¢ºãã«ä¸ã¤ã ãã§ã¯ããã¾ããã人éã®ããããã¸ã®ããã¡ãã®ç£æ¥ãããæã
ã¯ç´ æ´ãããã¨å°ãå¿é
ã§ããããããã®æ©æ¢°çãªãã·ã³ã®ã¾ãã¾ãåºã鏿è¢ãåç
§ãã¦ãã ãããããã¯ãã³ã³ãã¥ã¼ã¿ãæè¡ãããããã人éã«ãã¾ãã«ã大ããªå½±é¿ãä¸ãã¦ããã¨ä¸»å¼µãã人ã
ãçè§£ãããã¨ã¯ããã¾ãã«ãé£ãããã¨ã§ã¯ããã¾ãããç¾å®çãªã®åºãç¯å²ãã3Dãã¶ã¤ã³ã«é¢é£ããåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ããä»ã®ãã£ã¼ã«ãã®ãããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ãã3Dã¢ãã«ããã¦ã³ãã¼ãã§ãããããããè£
åãã¾ããã","ship":"è¹ã¯å¼·åãªè¹ã§ããããã¹ã¦ã®ãµã¤ãºãè²ãå½¢ã§æ¥ã¾ããå½¼ãã¯ã貨ç©è¹ãè»è¦ã客è¹ã¨ãã¦åé¡ãããã¨ãã§ãããããã¯ãã¹ã¦æ·±æµ·æµ·åã§åä½ãã¾ããããªããä¹ãç©é
ãã®ä¸å¿«æãçµé¨ãã¦ããå ´åãããã¯è¼¸éã®ã好ããªææ®µã§ã¯ãªããããããªãããå¤ãã®äººã
ã¯é常ã«ä¸åã§æ¥½ããã¨ãã¦ãã¼ãæ
è¡ãèãã¦ãã¾ããè¹ã®3Dã¢ãã«ã®ç§éã®é¸æã¯ããã¦ã³ãã¼ãã®æºåãã§ãã¦ããã¨ããæãè¦æ±ã®å³ããè¹é·ã®åºæºãæºããã¦ãã¾ãã","skeleton":"人éã®éª¨æ ¼ã¾ãã¯éª¨æ ¼ç³»ï¼è§£åå¦ï¼ã¯ãåºçæã«270åã®éª¨ã§æ§æãããæ¬ä½ã®å
é¨ãã¬ã¼ã ã¯ã¼ã¯ã§ããããã¯ãããã£æ§é ãä¿è·ãéåãæä¾ããæãè¤éãªéª¨æ ¼ç³»ã®ä¸ã¤ã§ããè±å¯ãªé¸æã¯ãè§£åå¦çã«æ£ããç¾å®çãª3Dã¢ãã¡ã¼ã·ã§ã³ãã°ã©ãã£ãã¯ãã¶ã¤ã³ãåºåã3Dã²ã¼ã ãã¦ã§ãã§ã®ä½¿ç¨ã«æé©ã§ã3Dã¢ãã«ã¹ã±ã«ãã³ã¹ã±ã¼ã«ãã¦ã³ãã¼ãã§ãã¾ãã","skull":"æå¤ã®æãå®å
¨ãªãéºä¼çã«ç¡å·ã®ããã®é è骨ãè¶
ãã40ã¡ã¼ãã«æµ·é¢ä¸çµ¶æ»
åç©ã®å¤æ§å²ã¾çºè¦ããã¾ãããããã¯æ°ä¸çã§è¦ã¤ãã£ãæå¤ã®éª¨æ ¼ã®ä¸ã¤ã§ãããããã¯ã¾ãã身ä½ã®ä¸»è¦ãªéª¨ãæ¯ã®å®å
¨ãªé èã¨ã»ããã®ãã¹ã¦ãå«ã¾ãã¦ãã¾ãã人éã®é èéª¨ã¯æè¿ããã¡ãã·ã§ã³ã¨ãã¶ã¤ã³ã®ãã®ã¨ãªã£ã¦ããããããªããå®éã«ãããããã¤ãã®èããä¸ããã¨ããå½¼ã種é¡ã¡ã¤ã¯ã®ç§ãã¡ã®ãã¹ã¦ã®ã°ã©ãã£ãã¯ãã¶ã¤ã³ã«ä½¿ç¨ãããé è骨ã®3Dã¢ãã«ã®è§£åå¦ããªã¼ã¯ã®ãããªè¡¨æ
...ãã®ã«ãã´ãªã®æä¾åºãç¯å²ã3Dã¢ãã¡ã¼ã·ã§ã³ã3Dã²ã¼ã ãåºåã","sofa":"é«ç´ã¾ãã¯ã·ã³ãã«ãã¢ãã³ã¾ãã¯ã¢ã³ãã£ã¼ã¯ãé©ãã·ã³ãã«ãªãã¶ã¤ã³ï¼ã©ã®ããã«ããªãã®ã½ãã¡ã好ãã§ããï¼æã
ãæã£ã¦ããã½ãã¡3Dã¢ãã«ã®ç¯å²ã¯ãææªã®å®ç§ä¸»ç¾©è
ãæºè¶³ããã¾ããããªãã¯ããã«ã¤ãã¦èããããã«åæ¢ããã¨ããã¶ã¤ã³ãé¸ã¶ã¨ãããªãã¯åµé çã§ãªããã°ãªããªãã®ã§ãã½ãã¡ã¯ããã¹ã¦ã®ãªãã³ã°ã«ã¼ã ã®ä¸å¿ã§ããã¾ãï¼","table":"ææ°ã®å®¶å
·ã®å¾åã¯ç¾ä»£ããã¡ãã·ã§ããã«ãªãã¼ãã«ã鏿ããã¨ããã¾ãã«ãã¹ãã¬ã¹ã«ãªã£ã¦ãã¦ããããã«å¤æ§ã§ããããã«ã¯ãããªãã®ãããããªãç¥ãã®ããã®ç°¡åãªå¤é£ã®ãã¼ãã«ãæã£ã¦ããæéã«ããããã«ä½¿ç¨ããããã¯ååã ã£ããã仿¥ - ãã¼ãã«ã¯ãæã¾ãã¯å°ãªãã¨ãç®ãå¼ãã¤ã³ããªã¢ã®ã¢ã¯ã»ã³ãã§ããã¨èãããã¾ãããã®é¸æã¯ãããªãã®ãã¹ã¦ã®æ°ã¾ããã«å¿ããããã«ããã¼ãã«ã®3Dã¢ãã«ã®åºå¤§ãªç¯å²ãæä¾ãã¾ãã","tower":"ãã¹ã¦ã®é½å¸ã¯ã誰ããæ¬å½ã«èªãã«æãã®ã ã¨ããç¹æ®ãªã¿ã¯ã¼ãããã¾ããä¸äººã§ãã¹ã¦ã®è¿ä»£çãªé«å±¤ãã«ãæªæ¥çãªå»ºç©ã観å
客ãæå¿ã¨ããé½å¸æ¯è¦³ãèããã¦ãã¨ããã§ã«å¡ãããµãã¿ã¯ã¼ãã¾ãã¯ãã³ãã³ã®ã¿ã¯ã¼ããªãã¸ãèãã¦ã¿ã¦ãã ãããããã¯é½å¸ãæ°´ã黿°ã®å¡ã®å·¥æ¥é¨åã«æ¥ãã¨ããããã誰ããé¢ãã¦å½¼ãã®ç®ãåããå¾åããã...ããããæã
ã¯é¢ä¿ãªããå¤ä»£ã®ç£æ¥ãè¿ä»£çãªããã¹ã¦ã®å»ºç¯ã®åµé ã«æè¬ããªããã¨ãå¦ã¶å¿
è¦ãããã¾ãã詳細ã¿ã¯ã¼ã®ç¯å²3Dã¢ãã«ããã¦ã³ãã¼ãã§ããåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ãããã³3Dãã¶ã¤ã³ã«é¢é£ããä»ã®ãã£ã¼ã«ãã®ãããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ãã¾ãã","tree":"ããªãã«ã¯ãããã¤ãã®æ¨ãã¨ãã¾ããã¯ãªæ¤ç©ãæ¤ãããã¨ã使å½ã«ãã¦ããå ´åã¯ãé©åãªå ´æã«æ¥ã¦ãã¾ãããã®ã«ãã´ãªã®ç³ãåºèªåã®ããã¸ã§ã¯ãã«ããã¤ãã®ç·ã追å ããããã«åªåãã¦ããCGã¢ã¼ãã£ã¹ãã建ç¯å®¶ãã«ç°¡åã«ä½¿ç¨ã§ãããé常ã«ãªã¢ã«ãª3D樹æ¨ã¢ãã«ã®ç¯å²ãããªãã¯è¯ãå質ãé«ãè©ä¾¡ããå ´åãæã
ã¯ããªãã®åºæºãæºããã¦ãã¾ã3Dããªã¼ã®ãã©ã³ãã¢ãã«ã®ãã®é¸æç¢ºä¿¡ãã¦ãã¾ãï¼","truck":"ãã©ãã¯ãé転ããã¨ãé½å¸ã®äº¤éæ¸
16518æ»ãéãã¦ããªãã®æ¹æ³ãè¦ã¤ããå¿
è¦ãããå ´åã¯ç¹ã«ã大å¤ãªä»äºã§ããããããããããã¯æ¶é²è»ããã¿åéè»ãé£åã®ãã©ãã¯ãä¸è¬çãªãã®ã ãã©ããã®ãããã¯ãããã®å·¨å¤§ãªè»ãæç¸¦ããããã«å大ãªã¹ãã«ãè¦ãã¾ããç§ãã¡ã¯ãç¾å®çãªãé«å質ã®ãã©ãã¯ã®ãã®é¸æ3Dã¢ãã«ã¯ã3Dã¢ãã¡ã¼ã·ã§ã³ãã°ã©ãã£ãã¯ãã¶ã¤ã³ãåºåããã®ä»ã®3Dé¢é£åéã§ã®ä½¿ç¨ã«æé©ã§ãããã¨ã確信ãã¦ãã¾ãã","tv":"æçããã¬ã¼ã¤ã¼ã¨ã¹ãã¼ã«ã¼ã¨ãã¬ãããªãã³ã°ã«ã¼ã ï¼ã¨ããå¯å®¤ï¼ã®çã§ããä»ããã¹ã¦ã®ç«æ´¾ãªå®¶ã®ç®çã ã£ãæãããã¾ãããè¿å¹´ã§ã¯ãã¬ãã¯ãææ°æè¡ã«è¿½ãã¤ãã¾ããããã®çµæãæã
ã¯ãã¹ãã¼ã3Dãã¬ãããã©ãããã©ãºãã¹ã¯ãªã¼ã³ãä¸ã®æ°æ©è½ãã¿ããã¹ã¯ãªã¼ã³ã®ãã¶ã¤ã³ãæã£ã¦ãã¾ãã䏿è°ãã¬ããå¸å ´ããæ ç»ãããã·ã¥ããã¾ãããåºåã3Dãã¸ã¥ã¢ã©ã¤ã¼ã¼ã·ã§ã³ã3Dã²ã¼ã ãã¦ã§ãããã³3Dãã¶ã¤ã³ã«é¢é£ããä»ã®ãã£ã¼ã«ãã®ãããªã³ã³ãã¥ã¼ã¿ã°ã©ãã£ãã¯ã¹ã¢ããªã±ã¼ã·ã§ã³ã®ããã®æºåãã§ãã¦ããç¾å®çãªã詳細ãªãã¬ãã®3Dã¢ãã«ã®åºãç¯å²ããã¦ã³ãã¼ãã§ãã¾ãã"}},"tag_promotion":{"days_left_error":"1ãã30ã®éã§ãªããã°ãªãã¾ãã","no_other_pending_promotions_for_same_item_tag":"ãã§ã«ä¿çä¸ã®ããã¢ã¼ã·ã§ã³ãããã¾ã"},"tooltips":{"buyer_loyalty_program_current_level_html":"ç¾å¨ãããªãã¯CGTraderã«%{total_price_paid}ãè²»ããã¦ããã¨ãããªãã®ã¯ã¬ã¸ããã¬ã¼ãã稼ã%{buyer_loyalty_rate} ã§ãã \u003cBR/\u003eããã¯ããªããããããã®è³¼å
¥ããã¯ã¬ã¸ããã®%{buyer_loyalty_rate}ãåå¾ãããã¨ãæå³ãã¾ãã\n","buyer_loyalty_program_html":"ããã¯ãããªããæ°ããã¯ã¬ã¸ããã¨ãã¦ãè³¼å
¥ããåå¾ããã¾ãã©ã®ãããã®å²åã§ãã \u003cBR/\u003eããã¯CGTraderã®å¢å ã§ããªãã®ç涯æ¯åºã¨ãã¦30%ã¾ã§å¢å ãã¾ãã \u003cBR/\u003eç¾å¨ãããªãã®ä¿¡ç¨ãå¾ãçã¯%{buyer_loyalty_rate}ã§ãã\n","buyer_loyalty_program_next_level_html":"次ã®ã¬ãã«%{next_lvl_expensesã¯}%{next_lvl_expenses_rate}ã«çã稼ãããªãã®ã¯ã¬ã¸ãããå¢å ãã¾ãã \u003cBR/\u003eããªãã¯$%{left_until_next_lvlã¯}ããæ¬¡ã®ã¬ãã«ã«å°éããããã«è³¼å
¥ããå¿
è¦ãããã¾ãã\n"},"trending_headers":{"models":"ä»ã®äººæ°ã®3Dã¢ãã«ãè¦ã","print":"ä»ã®äººæ°ã®3Dããªã³ãã¢ãã«ãè¦ã"},"tutorial":{"destroy":"ãã¥ã¼ããªã¢ã«ãæ£å¸¸ã«åé¤ããã¾ããã","submit_for_review_error":"å¿
é é
ç®ããã¹ã¦å
¥åãã¦ãã ããã","submitted":"ãã¥ã¼ããªã¢ã«ã®ãæç¨¿ãããã¨ããããã¾ãã審æ»å¾ãéããªãå
¬éããã¾ãã"}},"pt":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"Adulto ou conteúdo violento","ai_generated":"Conteúdo gerado por IA","copyright":"violação de direitos autorais"}}},"errors":{"messages":{"embedded_script":"Este arquivo não é compatÃvel e não pode ser enviado. Tente outro arquivo."}}},"api":{"profile":{"actions":{"contact":"Contato","follow":"Seguir","follow_tooltip":"Comece a seguir este designer para receber atualizações sobre o conteúdo dele e filtrar seus favoritos nos resultados de busca.","hide":"Ocultar","hire_me":"Contrate-me","invite_client":"Iniciar um projeto","mute_tooltip":"Oculte os modelos deste designer nos resultados de busca.","take_over":"Assumir","unfollow":"Deixar de seguir","unhide":"Mostrar","view_all_models":"Ver todos os modelos do designer"},"private_project_review":"Projeto privado"}},"browser":{"3d_models":"modelos 3D","3d_print":"3D impressão","active_filters":{"polygons":"%{range} polÃgonos"},"adult_content":"Mostrar Idade +","animated":"Animado","breadcrumb":{"browse_by_type":"Navegar por tipo","collection":"packs 3D","free":"livre","free_models":"Modelos livre 3D","free_print_models":"Modelos de impressão livre 3D","low_poly":"baixo poli","low_poly_models":"VR / AR / baixa-poli 3D Modelos","low_poly_print_models":"Modelos 3D de impressão Low-Poly","model_3d":"modelo 3D","model_3dp":"modelo de impressão 3D","models":"Modelos 3D","models_3d":"modelos 3D","models_3dp":"modelos de impressão 3D","models_variant_0":"Modelos 3D","models_variant_1":"Ativos 3D","models_variant_2":"Modelos VR","models_variant_3":"Modelos CG","models_variant_4":"Loja de modelos 3D","models_variant_5":"Objetos 3D","print_models":"Arquivos de impressão 3D","print_models_variant_0":"Modelos para impressão 3D","print_models_variant_1":"Modelos de impressora 3D","print_models_variant_10":"Modelos 3D para impressão","print_models_variant_11":"Modelos 3D para imprimir","print_models_variant_12":"Arquivos 3D para impressão","print_models_variant_13":"Modelos para impressora 3D","print_models_variant_14":"Modelos para impressão 3D","print_models_variant_15":"Modelos de impressão 3D","print_models_variant_16":"Arquivos 3D imprimÃveis","print_models_variant_2":"Modelos 3D para impressão","print_models_variant_3":"Modelos de impressão 3D","print_models_variant_4":"Arquivos para impressão 3D","print_models_variant_5":"Arquivos para impressão 3D","print_models_variant_6":"Arquivos de impressora 3D","print_models_variant_7":"Modelos 3D imprimÃveis","print_models_variant_8":"Modelos 3D para imprimir","print_models_variant_9":"Modelos 3D impressos"},"buyer_engagement_program":"descontos","categories":"categorias","category":{"meta":{"3d_models":"%{count} %{category} 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download de %{count} %{category} modelos de impressão 3D prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais.%{page}","animated_3d_models":"%{count} %{category} animado 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Download de %{count} %{category} gratuitos 3D modelos, disponÃveis em MAX, OBJ, FBX, 3DS, formatos de arquivo C4D, pronto para VR / AR, animação, jogos e outros projetos em 3D.%{page}","free_3d_print_models":"Download de %{count} %{category} modelos de impressão 3D gratuitos prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais.%{page}","lowpoly_3d_models":"Baixar %{count} VR / AR / low-poly %{category} modelos 3D pronto para realidade virtual, jogos e outros aplicativos em tempo real, disponÃveis em FBX, OBJ, MAX, 3DS, formatos de arquivo C4D.%{page}","rigged_3d_models":"%{count} %{category} fraudada 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"collection":"pack 3D","discounts":"descontos","ext":{"meta":{"3d_models":"Baixar %{count} %{ext} arquivos - %{software_name} modelos 3D pronto para VR / AR, design 3D, animação, jogos e em tempo real aplicativos%{page}","3d_print_models":"Download de %{count} %{ext} arquivos - %{software_name} modelos de impressão 3D prontos para o VR / AR, design 3D, animação, jogos e em tempo real aplicativos%{page}."}}
16518,"filter":"Filtro","filter_button":"aplicar filtros","filters":{"adult_content_only":"Apenas conteúdo adulto","cgt_standard_only":"Padrão CGT","collections_only":"Apenas pacotes","content_filters":"Filtros de conteúdo","designer":"Designer","exclude_3d_print":"Excluir impressão 3D","exclude_adult_content":"Excluir conteúdo adulto","exclude_ai_generated":"Excluir conteúdo gerado por IA","exclude_editorial_license":"Excluir licença editorial","exclude_free":"Excluir grátis","file_format":"Formatos de arquivo","following":"Seguindo","free":"Grátis","has_marmoset":"Possui visualizador 3D","has_video":"Com vÃdeo","include_ai_generated":"Incluir conteúdo gerado por IA","label":"filtros","poly_count":"Contagem de polÃgonos","print_ready":"Impressão 3D","stl_files":"Arquivos STL","subscription":"Assinatura","type":"Tipo"},"formats":"formatos","free":"Livre","free_models":"Mostrar modelos gratuitas apenas","free_to_premium":{"main":"modelos 3D de %{category}","postfix":"na lista premium.","prefix":"Você precisa de algo especial? Você pode encontrar melhor qualidade"},"gallery":{"preview":"pré-visualização"},"game_ready":"jogo pronto","high_poly":"De alta poli","items_page_title":"Modelos 3D","license":{"exclude_branded":"Excluir Branded","exclude_editorial":"Excluir Editorial","prompt":"Licença","tooltip_more":"Consulte Mais informação","tooltip_text":" Não mostrar modelos que podem ser usados ââapenas em não-comercial ou educacional.","tooltip_title":"Excluir Editorial:"},"low-poly":"Baixa-poli","low_poly":"Baixa-poli","meta":{"3d_models":"%{count} modelos 3D, disponÃvel para download no MAX, OBJ, FBX, MB e outros formatos de arquivo, pronto para VR / AR, animação, jogos e outros projetos em 3D.%{page}","3d_print_models":"Visualize arquivos de impressão 3D de todas as categorias no CGTrader. Refine, classifique e filtre objetos de impressão 3D profissionais para atender à s suas necessidades e recursos da impressora.","animated_3d_models":"modelos animados para uso em jogos, filmes e outros projetos. Estes modelos vêm pré-embalados com alguns movimentos e ações especÃficas. Estes ajudam a poupar tempo e recursos valiosos durante o processo de desenvolvimento ou criação de protótipos. Escolha PBR texturizada modelos para se certificar de que eles muito bem em todas as condições de iluminação.\n","free_3d_models":"Baixar %{count} gratuitos modelos 3D, disponÃvel em MAX, OBJ, FBX, 3DS, formatos de arquivo C4D, pronto para VR / AR, animação, jogos e outros projetos em 3D.%{page}","free_3d_print_models":"Download de %{count} modelos de impressão 3D gratuitos prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais. %{page}","lowpoly_3d_models":"modelos poli baixos para download. Esses modelos têm um menor número de polÃgonos e exigem menos poder de computação. modelos de baixo-poli são mais utilizados em aplicações como VR, AR, jogos, especialmente jogos móveis. Escolha de nossa coleção de modelos manipuladas e animados para o melhor desempenho em seus aplicativos.\n","metaverse":"Digite o metaverso com a nossa coleção de modelos 3D altos e baixos manipulados, animados e disponÃveis qualquer formato de arquivo.","omniverse":"Crie seu mundo virtual com nossos modelos 3D prontos para omniverse. Escolha entre os modelos animados, manipulados e PBR com alta e baixa contagem de polÃgonos.","page_prefix":"Página %{page_number} com","pbr_3d_models":"Fisicamente render base, ou PBR, indica a modelos que são fundidas com precisão e de forma consistente em todas as condições de iluminação, devido à texturização fluxos de trabalho usado no processo. Os desenvolvedores podem facilmente usar esses modelos em todos os principais motores de renderização.\n","rigged_3d_models":"Precisa modelos móveis? Confira nossa coleção de fraudada 3D modelos, que são o seu go-to escolha quando você precisa de um personagem ou objeto para executar únicas, movimentos especÃficos. Fraudada 3D modelos estão disponÃveis em Autodesk 3ds max (.max), Maya (.ma), Softimage (.xsi), Cinema4D (.c4d) e muitos outros formatos de arquivo.\n","snap-ar":"Com nossos modelos 3D, você pode participar de milhões de Snapchatters usando o Snap AR para criar experiências divertidas de realidade aumentada.","spark-ar":"Ilumine seu Facebook e Instagram com uma variedade de modelos Spark AR 3D que são manipulados, animados e prontos para uso.","stream_3d_print_models":"Navegar através de uma variedade de fluxo 3D categorias modelo de impressão para descobrir algumas das mais extraordinárias 3D projetos imprimÃveis de profissionais 3D criadores.","textures":"%{count} ativos e materiais de texturas 3D disponÃveis para download em vários formatos, incluindo .tga .sbsar .jpeg .png .tiff e outros. %{página}","tiktok":"Torne seus efeitos de vÃdeo mais impressionantes com os modelos Tiktok 3D. Nossa biblioteca pode atender a todas as suas necessidades criativas e é constantemente atualizada.","unity":"Encontre modelos 3D para o seu projeto de unidade em qualquer formato de arquivo e qualquer contagem de poli. Tudo o que você precisa para criar um ambiente virtual exclusivo.","unreal":"Crie visualizações impressionantes com modelos 3D compatÃveis com motores irreais em qualquer formato de arquivo. Nossa biblioteca possui modelos de baixo e alto poli de todas as categorias."},"optimized":"Baixa-poli / PBR","pbr":"PBR","per_page":"Por página","polygons_options":{"custom"
16518:"intervalo personalizado","gt_250k":"250k +","lt_5k":"Até 5k","more_than_250000":"250K+","prompt":"contagem de polÃgonos","range_0_5000":"Até 5K","range_100000_250000":"100 - 250K","range_10000_50000":"10 - 50K","range_100k_250k":"100k para 250k","range_10k_50k":"10k para 50k","range_50000_100000":"50 - 100K","range_5000_10000":"5 - 10K","range_50k_100k":"50k para 100k","range_5k_10k":"5k a 10k"},"price":"Preço: $%{from}-%{to}","price_range":"Preço","print_ready":"3D imprimir pronto","printable":"Impressão 3D","reset_button":"filtros de reposição","rigged":"fraudada","sale_off":"Em promoção","search_placeholder":"Procure palavras-chave","show_all_formats":"Mostrar todos os formatos","simulation_ready":"Pronto para simulação","sort_by":"Ordenar por","sort_by_options":{"best_match":"Melhor partida","highest_price":"Preço mais alto","lowest_price":"preço mais baixo","newest":"O mais novo","oldest":"mais velho","sales":"Mais vendido","trending":"Tendência"},"subcategory":{"meta":{"3d_models":"%{count} %{category} 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download de %{count} %{category} modelos de impressão 3D prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais.%{page}","animated_3d_models":"%{count} %{category} animado 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Download de %{count} %{category} gratuitos 3D modelos, disponÃveis em MAX, OBJ, FBX, 3DS, formatos de arquivo C4D, pronto para VR / AR, animação, jogos e outros projetos em 3D.%{page}","free_3d_print_models":"Download de %{count} %{category} modelos de impressão 3D gratuitos prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais.%{page}","lowpoly_3d_models":"Baixar VR / AR / Low poly %{tag} modelos 3D pronto para Realidade Virtual, jogos e outros aplicativos em tempo real, disponÃvel em FBX, OBJ, MAX, 3DS, formatos de arquivo C4D.%{page}","rigged_3d_models":"%{count} %{category} fraudada 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"subtitle":{"aircraft":"Modelos %{count} aeronaves 3D estão disponÃveis para download em nosso mercado. CG %{airplanes_link} se encaixam em simulações, visualizações, anúncios e vÃdeos. %{drone_link} corpos e partes irá deliciar os fãs de pequenos veÃculos voadores. E os %{rigged_link} modelos estão prontos para serem importados para motores de jogo e ser usadas para animação ou projetos VR / AR. Voando jogos, simuladores e vÃdeos de ambos CG regular e tipos de baixo poli pode ser preenchido com modelos 3D na maioria dos formatos populares, incluindo FBX, OBJ, MAX, 3DS, C4D.","animals":"%{count} de animais CG 3D -%{cats_link}, %{horses_link}, %{bears_link}, %{rhinos_link}, %{eagles_link}, %{lions_link}, fictÃcio %{dragons_link} e muito mais - estão disponÃveis aqui para download. A coleção de fauna 3D irá satisfazer as necessidades de anúncios ou cenas estáticas. Temos também %{rigged_link} modelos para jogos, animação, produção de vÃdeo e VR / projetos AR. Use filtros para encontrar fraudada, animado, low-poly ou livres 3D modelos disponÃveis na maioria dos formatos de arquivo aceitos pela indústria, incluindo FBX, OBJ, MAX, 3DS, C4D, e outros.","animated":"Explore modelos 3D totalmente animados de %{tag} para acelerar seu fluxo de trabalho e dar vida instantaneamente aos seus projetos.\n","architectural":"%{count} de arquitectura modelos 3D disponÃveis para download contém elementos e detalhes de arquitetura, construção e projeto de engenharia. Para comprar ou baixar um modelo 3D livre, navegar pelas categorias acima. Você pode usar modelos para animação ou jogos - alguns deles são manipuladas e low poly para servir VR / necessidades do projeto AR. modelos 3D estão disponÃveis em formatos de arquivo como FBX, OBJ, MAX, 3DS, C4D.","car":"Modelos %{count} carro 3D estão disponÃveis para download. versões de baixo poly de que será atrae
16518nte para os designers de jogos ou VR / AR aplicações desenvolvedores, outros - para cineastas, animadores ou anunciantes. De carros clássicos e antigos para o Racing e conceito que foi visto em filmes, há uma grande variedade de modelos de automóveis 3D em praticamente qualquer formato (FBX, OBJ, MAX, 3DS, C4D, etc.) você pode precisar. Use animados e gratuitos 3D modelos de protótipo e tempo de desenvolvimento encurtar.","character":"%{count} caracteres 3D modelos estão disponÃveis para download, assim navegar nesta categoria você vai encontrar modelos 3D de %{human_link}, pessoas, figuras mÃticas, sci-fi %{robots_link}, vestuário e outras coisas relacionadas com caracteres. Do %{heart_link} e %{hand_link} para detalhado realista %{male_link} ou %{female_link} modelos. Um número de modelos são manipuladas e pode ser facilmente adicionado ao seu jogo, VR / projeto AR, vÃdeo ou animação. Ambos os modelos de baixo poli alta poli e pode ser encontrado em vários formatos, incluindo FBX, OBJ, MAX, 3DS, C4d.","custom":"Aqui você pode comprar ou baixar livre %{tag} modelos 3D. %{tag_heading_subtitle}","electronics":"%{count} eletrônica 3D modelos disponÃvel para download. Esta é uma categoria para arquitetos, decoradores, designers de nÃveis, fabricantes de cena e outros criativos. modelos 3D de %{smartphones_link}, %{laptops_link}, %{cameras_link}, %{tvs_link} e mais irá ajudar a capturar com precisão a obsessão da vida moderna com dispositivos e tecnologia. Existem modelos 3D disponÃveis em formatos de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D. Grátis download ou comprar modelos premium e uso de animação, jogos e projetos VR / AR.","exterior":"%{count} de arquitectura exteriores modelos 3D disponÃveis para faixa de transferência a partir fachadas, edifÃcios urbanos, objetos paisagem, casas residenciais para construções industriais, edifÃcios de infra-estrutura e %{city_link} modelos em escala completa. Para comprar ou baixar um modelo 3D livre, navegar pelas categorias acima. Use filtros para encontrar fraudada, animado, low-poly, livre modelos 3D ou classificar por formato necessário, incluindo FBX, OBJ, MAX, 3DS, C4D. Alguns dos ativos são low-poly e poderia ajudá-lo a completar o ambiente em seu jogo ou aplicação VR / AR.","food":"%{count} modelos de alimento 3D estão disponÃveis para download..Food serve bem para criar cenas realistas da vida doméstica. 3D frutas, legumes, bebidas e refeições são todos aqui para anúncios completos para restaurantes, aplicações AR para uma alimentação mais saudável, e visualizações arquitetos e designers de interiores estão trabalhando. Se você está olhando para 3D %{pizza_link} e %{ketchup_link} modelos ou um modelo 3D de um casamento %{cake_link}, eles estão aqui. Um número de versões de baixa-poli estão disponÃveis para aqueles em jogo, desenvolvimento VR / AR. modelos 3D podem ser encontrados em FBX, OBJ, MAX, 3DS, formatos C4D.","formats":"Estão %{found_items_count} modelos 3D prontos para download no formato arquivo %{required_software_title} no\nO mercado. Sinta-se livre para navegar na coleção e não se esqueça de usar os outros filtros de busca para encontrar\nPBR, manipuladas, modelos 3D imprimÃveis animado ou para seus projetos. Se você é um desenvolvedor de jogos uso do filtro âPoly contagemâ\npara modelos 3D vista de baixo-poli que precisam de energia menos computacional para processar. A maioria dos activos 3D em CGTrader são\ndisponÃvel em vários formatos de arquivo, e se um modelo que você quer não estiver disponÃvel no formato arquivo %{required_software_title},\nvocê pode sempre pedir uma conversão de arquivos, selecionando âsolicitação de arquivo livre conversão de formatoâ na página do produto. Você pode\nTambém visite a nossa página 3D Jobs e postar um pedido de conversão modelo, modelos personalizados e quaisquer outros serviços de modelagem você\npode precisar.\n","free_general":"Modelos livre 3D disponÃveis para download a partir de %{link_1} para %{link_2} ativos 3D. DisponÃvel em vários formatos de arquivo, incluindo MAX, OBJ, FBX, 3DS, STL, C4D, mistura, MA, MB. Encontre profissional %{link_3} para quaisquer projetos de design 3D como a realidade virtual (VR), realidade aumentada (AR), jogos, %{link_4} visualização 3D ou animação.","free_no_tag":"%{model_count} free 3D %{tag} modelos prontos para a impressão 3D. Baixar %{tag} modelos de impressão 3D livres, formatos de arquivo disponÃveis, incluindo STL, OBJ, 3DM, 3DS, MAX. modelos 3D está pronto para ser usado com o FDM, SLA, SLS e outros tipos de impressoras 3D.","free_printable":"%{model_count} modelos 3D gratuitos pronto para impressão 3D. Download gratuito ou olhar para os modelos de impressão Premium 3D. formatos de arquivo disponÃveis, incluindo STL, OBJ, WRL. modelos 3D está pronto para ser usado com o FDM, SLA, SLS e outros tipos de impressoras 3D.","free_tag":"Grátis 3D %{tag} modelos disponÃveis para download. DisponÃvel em vários formatos de arquivo, incluindo MAX, OBJ, FBX, 3DS, STL, C4D, mistura, MA, MB. Encontre profissional %{tag_link} para quaisquer projetos de design 3D como a realidade virtual (VR), realidade aumentada (AR), jogos, visualização 3D ou animação.","furniture":"%{count} mobiliário modelos 3D disponÃveis para download incluem mesas, cadeiras, sofás, camas e outros móveis em uma variedade de texturas (madeira, metal, etc.) e estilos (%{retro_link},%{modern_link}, etc. ). Esta categoria é para qualquer um envolvido com arquitetura e design de interiores, bem como anunciantes e animadores. ativos em tempo real pode ajudar jogos e aplicativos VR / AR desenvolvedores para projetos completos. Use filtros para encontrar fraudada, animado, low-poly ou livres 3D modelos. DisponÃvel em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.","general":"modelos em 3D para design digital CG e obras de arte","high_poly":"Comprar ou baixar Animated Professional 3D modelos prontos para serem utilizados em projetos de computação gráfica, produção de filmes e vÃdeo, animação, visualizações e outros. Ativos estão disponÃveis para download em vários formatos aceitos pela indústria, incluindo MAX, OBJ, FBX, 3DS, UE4 e outros. Se você está em busca de ativos 3D de alta qualidade poli, temos uma biblioteca de arte digital lÃder para todas as suas necessidades.\n","household":"Modelos %{count} 3D doméstica disponÃveis para download pode ser usado para dar detalhes aos quartos. Você pode querer colocar um jogo de jantar na mesa, tem sal e pimenta recipientes para interior cozinha completa, ou colocar algum %{lights_link} e %{flowers_link} perto da cama para criar sensação de luxo. Se você é um designer de interiores, animador,
16518VR / aplicação AR ou jogo criador, esta categoria é para você. Use filtros para encontrar fraudada, animado, low-poly ou livres 3D modelos. DisponÃvel em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.","industrial":"%{count} modelos 3D industriais disponÃveis para download - materiais de construção, %{engineering_link} ferramentas, máquinas e %{containers_link} - irá fornecer ambos os detalhes e interativos, manipuladas elementos para criar ambientes animados. Esta é uma categoria perfeita para simulações / VR / AR ou desenvolvedores %{construction_link} nÃvel do site no jogo. Os modelos 3D servirá profissionais da construção visualizações precisas que trabalham com software variados como modelos em formatos como FBX, OBJ, MAX, 3DS, C4D estão disponÃveis.","interior":"%{count} modelos 3D interior estão disponÃveis para download e incluir elementos e detalhes usados ââna arquitetura, construção e engenharia, design de interiores. Para comprar prémio ou baixar um modelo 3D livre, navegar pelas categorias listadas acima. Você pode usar modelos para animação ou jogos - alguns deles são manipuladas, animado e low poly. DisponÃvel em uma variedade de formatos de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.","low_poly":"%{count} low poly 3D %{tag} modelos estão disponÃveis para download. Estes modelos conter um número significativamente menor de polÃgonos e, portanto, requerem menos energia para tornar computação. Modelos que têm menos polÃgonos são mais usados ââem aplicações em tempo real que requerem processamento rápido, como a realidade virtual (VR), realidade aumentada (AR), realidade mista (MR), a realidade cruz (XR) e jogos, especialmente jogos móveis. Escolha de nossa coleção de modelos manipuladas e animados para facilmente usá-los em suas aplicações em tempo real. Obter 3D ativos para ambientes, escolher adereços, objetos ou comprar completas modelo 3D coleções, pacotes e pacotes com tudo sua necessidade jogo poder. Economize tempo e custos de desenvolvimento, experiências protótipos fazem uso ou 3D modelos como espaços reservados em seu projeto. Para encontrar modelos que tornam previsÃvel em vários motores, use o filtro PBR ao lado da barra de pesquisa.\n","military":"%{count} militares 3D modelos de armas, braços, %{swords_link} e artilharia moderna e histórica usadas pelas forças militares e de defesa pessoal estão disponÃveis para download. Você pode usar modelos para jogos ou conteúdo de VR / AR - alguns deles são polÃgonos otimizado e pronto para ser adicionado a um motor de jogo. modelos manipuladas e animadas pode facilitar ainda mais o seu trabalho. Você certamente vai encontrar ativos relevantes, pois há muitos modelos 3D disponÃveis em qualquer formato de arquivo que você pode precisar (FBX, OBJ, MAX, 3DS, C4D, etc.).","not_custom":"%{found_items_count} 3D %{tag} modelos disponÃveis para download. %{tag} modelos 3D estão prontos para a animação, jogos e projetos VR / AR. Use filtros para encontrar fraudada, animado, low-poly ou livres 3D modelos. DisponÃvel em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D","optimized":"Modelos que têm menos polÃgonos são mais usados ââem aplicações em tempo real que requerem processamento rápido, como a realidade virtual (VR), realidade aumentada (AR), realidade mista (MR), a realidade cruz (XR) e jogos, especialmente jogos móveis. Escolha de nossa coleção de modelos manipuladas e animados para facilmente usá-los em suas aplicações em tempo real. Obter 3D ativos para ambientes, escolher adereços, objetos ou comprar completas modelo 3D coleções, pacotes e pacotes com tudo sua necessidade jogo poder. Economize tempo e custos de desenvolvimento, experiências protótipos fazem uso ou 3D modelos como espaços reservados em seu projeto. Fisicamente renderização baseada, ou PBR, denota modelos que são prestados com precisão e de forma consistente em todas as condições de iluminação devido à texturização fluxos de trabalho utilizada no processo de criação.\n","pbr":"Fisicamente renderização baseada, ou PBR, denota modelos que são prestados com precisão e de forma consistente em todas as condições de iluminação devido à texturização fluxos de trabalho utilizada no processo de criação. Reflexividade, rugosidade da superfÃcie e a coloração, em conjunto com o princÃpio da conservação de energia e as vantagens da função de distribuição de reflectância bidireccional (BRDF), forneça o melhor padrão para qualquer objectos 3D que pode ser processado em quaisquer condições de iluminação. modelo A PBR 3D nunca vai refletir mais luz que atinge a sua superfÃcie. texturas PBR estão disponÃveis em todos os formatos de arquivo padrão. CGTrader também oferece conversão modelo 3D para PBR para alguns modelos. modelos de uso da PBR em todos os principais motores de renderização, como Unity, motor Unreal, Marmoset Toolbag 3 e outros, que suportam renderização baseada fisicamente.\n","plant":"%{count} planta 3D modelos disponÃveis para download contêm flora organismos que crescem como plantas domésticas e na natureza, como flores, %{trees_link}, grama, trepadeiras, hortaliças, ervas, plantas perenes, mudas, brotos, arbustos, deslizamentos, brotos, videiras, plantas daninhas. Para comprar prémio ou baixar um modelo 3D livre, navegar pelas categorias acima para encontrar o melhor ajuste entre os modelos disponÃveis. Utilização filtros para encontrar manipuladas, animado, baixa-poli (para utilização em jogos e VR / aplicações AR) modelos, ou para filtrar os formatos requeridos (em modelos FBX, OBJ, MAX, 3DS, C4d e mais estão disponÃveis).","printable":"Professional 3D imprimir modelos adequados para todas as suas necessidades de impressão, se você deseja imprimi-los em casa usando um FDM desktop, ou com uma impressora 3D SLS industrial. Nossa coleção de modelos 3D prontos para impressão são agrupados em nove categorias, incluindo esculturas artÃsticas, arte matemática, artigos de moda, acessórios gadgets e muitos outros objetos. modelos de impressão estão disponÃveis em todos os formatos de arquivo padrão da indústria, incluindo OBJ, STL, e WRL. Melhorar a sua vida diária, hábitos de trabalho, dispositivos ou simplesmente imprimir e recolher personagens em miniatura, decorações, figuras geométricas alucinantes bonitos e encontrar 3D caracteres imprimÃveis para o seu jogo de tabuleiro.\n","printable_merged_tag":"Aqui você encontra %{tag} arquivos de impressão 3D (STL, OBJ, FBX e muitos outros) prontos para impressão. Compre e baixe modelos 3D gratuitos, transmita e imprima com sua impressora 3D.","printable_tag":"Aqui você pode encontrar arquivos de impressão 3D %{tag} (STL, OBJ, FBX e muitos outros) prontos para impressão. Compre e baixe modelos 3D, transmita e imprima com sua impressora 3D ou compre um produto impresso em 3D â nós o imprimiremos em 3D e enviaremos para sua casa.","rigged":"Navegue por modelos 3D rigged de %{tag} prontos para animação, ideais para desenvolvimento de jogos e pipelines de produção.\n","scanned":"%{count} digitalizados 3D modelos estão disponÃveis para compra ou download gratuito. 3D digitalizados modelos estão prontos para a animação, jogos e projetos VR / AR. Você pode encontrar modelos 3D de objetos encontrados na natureza, como pedras e superfÃcies naturais, humanos e outros objetos da vida real aqui ... e não pode ficar mais realista do que isso. Use filtros para encontrar fraudada, animado, low-poly ou livres 3D modelos. DisponÃvel em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.","science":"%{count} ciência 3D modelos disponÃvel para download nesta faixa de categoria da medicina, biologia, fÃsica, campos de quÃmica e outros objetos do mundo real relacionados à ciência e tecnologia: equipamentos de laboratório, os corpos microscópicos e mundo subatômico. Não procure mais, %{cell_link}, %{skull_link} e %{skeleton_link} 3D modelos podem ser encontrados aqui! Para comprar ou baixar um livre 3D ativos, navegar pelas categorias acima. Você pode usar modelos manipuladas para animação ou de baixa poli queridos para jogos e projetos VR / AR. Ambos os modelos 3D gratuitos e premium pode ser encontrado em um número de formatos de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.","scripts_plugins":"%{count} Scripts 3D / Plugins estão disponÃveis para download. Scripts 3D / Plugins pode ser adicionado a diversos softwares e usado para fazer o seu pipeline de trabalho de forma mais eficiente. Filtrar por formatos de encontrar ferramentas de montagem seu software preferido.\n","space":"%{count} modelos espaço 3D estão disponÃveis para download no CGTrader. O espaço é uma categoria cheia de low poly, modelos de jogo-
16518pronto de sci-fi %{spaceships_link}. Há também %{asteroids_link}, planetas (incluindo Lua e Marte, a colonização de simulação) e espaço realista %{shuttles_link} para os mais cientificamente inclinado. Os modelos pode definitivamente ser usado em VR jogos espaço simulador, aplicações AR e animações para demonstrar ao mundo exterior do planeta %{earth_link}. Filtros estão aqui para ajudá-lo a encontrar bens manipuladas, animado, baixos-poli ou modelos em formatos especÃficos, incluindo FBX, OBJ, MAX, 3DS, C4D.","sports":"%{count} esportes 3D modelos disponÃveis equipamentos juntos ninho que é usado para atividades recreativas, entretenimento, exercÃcio, lazer, passatempo prazeroso, divertido, bem como jogos, brinquedos para crianças e uma gama completa de instrumentos musicais. Para comprar ou baixar um modelo 3D livre em qualquer formato de arquivo necessário, incluindo FBX, OBJ, MAX, 3DS, C4D, navegar pelas categorias acima. Você pode usar modelos para animação, jogos, projetos VR / AR - muitas delas são manipuladas, low-poly ou já animado.","test":{"airplane":"Entusiastas da aviação, escutem, nunca foi tão fácil para obter o modelo de avião impresso 3D perfeito para o seu jogo de tabuleiro ou coleção modelo. Pesquisar modelos de avião de impressão %{model_count} 3D e encontrar um modelo que você só precisa ter na prateleira. Descubra verdadeiro modelos de avião ou aqueles confeccionados. Procurar modelos mais recentes ou algo que a contagem de volta da época dos irmãos Wright. à também um presente perfeito para qualquer criança que sonha ser piloto quando crescer. Compra e download de um modelo de impressão 3D, imprimi-lo por si mesmo ou enviar o modelo para um dos nossos fornecedores de serviços de impressão 3D para tê-lo impresso e enviado para você em nenhum momento!\n","anatomy":"%{model_count} modelos 3D anatomia disponÃveis para download em nosso mercado. Explorar a anatomia humana com elevada - osso poli, músculo, modelos de órgãos. Perfeito para qualquer projeto educacional ou cientÃfico. Use modelos 3D de impressão para melhorar a experiência de educação. Criar animações fantásticas e jogos de vÃdeo com o nosso\n vasta biblioteca de modelos manipuladas. Use nosso sistema de filtragem avançada para encontrar facilmente low poly, animado, PBR,\n modelos manipuladas ou qualquer coisa que se adapte à s suas necessidades melhor. Escolha entre uma grande quantidade de formatos de arquivo, incluindo o\n a maioria das mais populares como FBX, OBJ, MAX, 3DS, C4D.\n","castle":"Seu próprio surpreendente 3D impresso castelo é um clique de distância! Pesquisar vários modelos castelo 3D pronto para impressão 3D. Criar uma fortaleza original da fantasia para a sua sessão de D \u0026 D ou qualquer outro jogo de RPG de mesa medieval. Estas fortificações medievais são um dom incrÃvel para qualquer entusiasta de jogo de tabuleiro ou uma grande adição à sua própria coleção. Encontre o modelo perfeito 3D para a pintura amadores ou uma parte de um brinquedo tipo para as crianças. Compra e download seu projeto castelo 3D escolhido, imprimi-lo com sua própria impressora, ou enviar o modelo para um dos nossos fornecedores de serviços de impressão 3D para tê-lo impresso e enviado a você.\n","dice":"Sorte não vai ficar sem com 3D impresso dados! Se você quiser dados do jogo autêntico para a sua noite de jogo de tabuleiro, não procure mais. Aqui você pode escolher entre %{model_count} gratuitos modelos dados 3D prontos para impressão 3D. Quando o jogo acabou, usar essas belas modelos como acessório. Download gratuito modelos 3D dados imprimÃveis, formatos de arquivos disponÃveis, incluindo STL, OBJ, 3DM, 3DS, MAX. modelos Nossa 3D está pronto para ser usado com FDM, SLA, SLS e outros tipos de impressoras 3D. Fazer o seu jogo um pouco mais interessante e obter seus dados impressos em 3D!\n","drone":"3D imprimir e construir seu próprio robô ou encontrar as peças para substituição. 3D impresso drones são fáceis de montar e reparação após um pouso forçado. Descubra um modelo com a câmera posição de montagem perfeita ou pedido de alterações mÃnimas. Perfeito para divertidas actividades de lazer, fotografia aérea, videografia ou mapeamento. Encontrar e comprar um modelo de robô 3D design único que se encaixa todas as suas necessidades. Imprimi-lo por si mesmo ou enviar o modelo para um dos nossos fornecedores de serviços de impressão 3D para tê-lo impresso e enviado para você em nenhum momento! Obtenha seu próprio robô impresso em 3D e percorrer os céus ampla azuis!\n","pokemon":"Pikachu, eu escolho você! Escolha a partir de um monte de monstros de bolso pronto para impressão 3D. Ãtimo para expandir a sua coleção pokemon impresso 3D. Pesquisar e tropeçar em cima os melhores modelos pokemon, mais detalhados para o seu próximo jogo de mesa com os amigos. Compra e download seu pokemon 3D, imprimi-lo com sua própria impressora 3D, ou enviar o modelo para um dos nossos fornecedores de serviços de impressão 3D para tê-lo impresso e enviado a você. Afinal, esta é uma das coisas mais legais para impressão 3D!\n","ring":"Jóias impresso 3D é o novo preto na indústria, assim como os anéis impressos em 3D! Pesquisar uma enorme quantidade de modelos anel de impressão 3D gratuitos %{model_count}. Navegar através de projetos originais e encontrar algo feito a
16518penas para você. Não consigo encontrar nada para si mesmo na loja? Ou talvez você quer um acessório exatamente como o seu personagem favorito filme tem? Escolha entre uma grande quantidade de formatos de arquivo, incluindo STL, OBJ, 3DM, 3DS, MAX. modelos 3D está pronto para ser usado com FDM, SLA, SLS e outros tipos de impressoras 3D, então navegar através de nossa seleção e tentar em seu novo anel favorito.\n","shoes":"Grandes marcas estão a bordo com o 3D impresso sapatos e agora você pode compartilhar a experiência bem. Procurar e localize livres imprimÃveis design dos calçados - de tênis para saltos da moda, há uma série de modelos de ready-to-print apenas esperando por você para experimentá-los. Faça o perfeito resultado, selecionando materiais, ajustando suavidade e tamanho. Escolha a partir de 146 modelos gratuitas sapato 3D e transferi-los em formatos de arquivo disponÃveis, incluindo STL, OBJ, 3DM, 3DS, MAX. Designs está pronto para ser usado com FDM, SLA, SLS e outros tipos de impressoras 3D. Obter seus sapatos impressos 3D hoje!\n","textures":"Pesquisar uma grande quantidade de %{model_count} CG texturas disponÃveis para download, incluindo materiais bem-feitas. Navegue pela categoria e encontrar tecido sem costura, madeira, metal, plástico, texturas tijolo para ajudar a terminar o seu projeto mais rápido. Usar nossa busca avançada para encontrar texturas manipuladas e animados para o jogo ou criação de vÃdeo. Nossos materiais estão disponÃveis para download em vários formatos, incluindo TGA, SBSAR, JPG, PNG, TIFF e outros, então não perca tempo e encontrar texturas CG ready-to-use para quase todo o imaginável projeto.\n"},"various":"%{count} vários modelos 3D que não facilmente encontrar o seu lugar em outras categorias estão disponÃveis para download. %{rocks_link}, %{clouds_link}, %{logos_link}, %{cigarette_link} e outros modelos não-categorizadas em 3D que você pode precisar para completar o seu jogo, animação ou projeto VR / AR está aqui. Use filtros para encontrar fraudada, animado, low-poly ou livres 3D modelos, ou resolver por formatos disponÃveis, tais como FBX, OBJ, MAX, 3DS, C4D.","vehicle":"%{count} veÃculo 3D modelos disponÃveis para download incluem caminhões, %{ambulances_link}, ônibus, %{bikes_link} e moto - esta categoria é para as pessoas que querem suas ruas da cidade para ser preenchido com veÃculos se realista ou sci-fi. Aqueles que fazem jogos de simulação ou aplicações VR / AR, criativos na produção de vÃdeo ou até mesmo criando cartazes será mais provável encontrar formatos de arquivos mais populares, como FBX, OBJ, MAX, 3DS, C4D utilizável. Outros veÃculos de transporte terrestre como trem ou modelos %{tractor_link} 3D também podem ser encontradas nesta vasta coleção. Use filtros para encontrar fraudada, animado, low-poly ou livre modelos 3D mais rápido.","watercraft":"%{count} watercraft 3D modelos disponÃveis para download incluem %{boats_link}, %{yachts_link}, %{ships_link} e outros veÃculos de água vai de todos os tipos. Os manipuladas 3D modelos de baixo-poli fará bem em jogos de vÃdeo, VR / projetos AR, bem como animações, enquanto os modelos CG está aqui para as suas cenas e outras aplicações onde a fidelidade visual é mais importante do que polycount. Os modelos estão disponÃveis em qualquer formato de arquivo, incluindo, mas não limitado a FBX, OBJ, MAX, 3DS, C4D."},"tag":{"meta":{"3d_merged_premium":"Baixe %{count} modelos 3D %{tag} gratuitos e premium, disponÃveis nos formatos de arquivo MAX, OBJ, FBX, 3DS e C4D, prontos para VR/AR, animação, jogos e outros projetos 3D.","3d_merged_premium_print":"Baixe %{count} %{tag} arquivos de impressão 3D gratuitos e premium prontos para FDM, SLA, SLS e outras impressoras 3D, formatos disponÃveis STL, OBJ, 3DM e muito mais.","3d_models":"%{count} %{tag} 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"Download de %{count} %{tag} modelos de impressão 3D prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais.%{page}","animated_3d_models":"%{count} %{tag} animado 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"Download de %{count} %{tag} gratuitos 3D modelos, disponÃveis em MAX, OBJ, FBX, 3DS, formatos de arquivo C4D, pronto para VR / AR, animação, jogos e outros projetos em 3D.%{page}","free_3d_print_models":"Download de %{count} %{tag} modelos de impressão 3D gratuitos prontos para FDM, SLA, SLS e outros 3D impressoras, formatos disponÃveis STL, OBJ, 3DM e muito mais.%{page}","lowpoly_3d_models":"Baixar %{count} VR / AR / low-poly %{tag} modelos 3D pronto para Realidade Virtual, jogos e outros aplicativos em tempo real, disponÃvel em FBX, OBJ, MAX, 3DS, formatos de arquivo C4D.%{page}","rigged_3d_models":"%{count} %{tag} fraudada 3D modelos disponÃveis para download em qualquer formato de arquivo, incluindo FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"title":{"download":"| baixar","files":"arquivos 3D","formats":"%{required_extension_title} %{product_type_title} - download %{required_software_title} de formato de arquivo 3D ativos","free":"Modelos 3D grátis","free_printing":"Impressão livre modelos 3D","free_tag":"Livre %{selected_tag} modelos 3D","general":"%{selected_filter} 3D Models","high_poly":"%{selected_filter} Modelos 3D","low_poly":"%{selected_filter} 3D Modelos","newest_cg":"Novos e Ãltimos Modelos 3D","newest_print":"Novos e Ãltimos Modelos de Impressão 3D","page_prefix":"Página %{page_number} de ","pbr":"PBR 3D modelos","printing":"Impressão 3D %{selected_filter} Modelos","sales_cg":"Modelos 3D Mais Vendidos","sales_print":"Modelos de Impressão 3D Mais Vendidos","tag_heading":{"cg":"Livre %{tag} Modelos de impressão 3D","filter":"%{selected_filter} %{tag} 3D Modelos","general":" %{tag} Modelos 3D","merged_premium_print_tag":"Arquivos de impressão %{selected_tag} gratuitos e premium","merged_premium_tag":"Modelos 3D %{selected_tag} gratuitos e premium","printable":"%{tag} Arquivos e modelos de impressão 3D"},"trending_cg":"Modelos 3D em Tendência","trending_print":"Modelos de Impressão 3D em Tendência"}},"cart":{"request_invoice_failed":"Opa. Algo deu errado.","request_invoice_successful":"Solicitação de fatura enviada com sucesso.","shareable_cart_created":"Carrinho compartilhado com sucesso.","shareable_cart_failed":"Opa. Algo deu errado.","subscription_covered_items_removed":"Removido do seu carrinho: %{titles}. Já incluÃdo na sua assinatura.","subscription_covered_order_refused":"Sua assinatura agora inclui %{titles}, portanto não efetuamos a cobrança. Baixe pela sua assinatura."},"categories":{"cg":{"header_title_html":"Comprar \u003cstrong\u003emodelos 3D\u003c/strong\u003e profissionais","text":"Encontre exatamente o conteúdo 3D certo para suas necessidades, incluindo AR/VR,\njogos, publicidade, entretenimento e outros\n"},"head-title":{"cg":"Modelos Comprar Professional 3D","cg-models":{"sort-by":{"newest":"Novos Modelos 3D","top-selling":"Modelos 3D Mais Vendidos","trending":"Modelos 3D em Tendência"}},"print":"Compre arquivos profissionais de impressão 3D","print-models":{"sort-by":{"newest":"Novos Modelos de Impressão 3D","top-selling":"Modelos de Impressão 3D Mais Vendidos","trending":"Itens de Impressão 3D Mais Populares"}}
16518,"product-type":{"plural":{"capital":{"cg":"Modelos 3D","cg-merge-premium":"Modelos 3D â downloads gratuitos e premium","print":"Arquivos e Modelos de Impressão 3D","print-merge-premium":"%{tag} arquivos de impressão 3D - modelos STL gratuitos e premium"},"lower":{"cg":"3d modelos","print":"arquivos e modelos de impressão 3D"}},"singular":{"capital":{"cg":"Modelo 3D","print":"Modelo 3D Printing"},"lower":{"cg":"modelo 3d","print":"modelo de impressão 3D"}}}},"index":{"browse_all":"Navegar por todos os modelos","info-section__description_1_html":"Compre ou baixe gratuitamente modelos 3D profissionais prontos para serem usados em projetos CG, produção de filmes e vÃdeos, animação, visualizações, jogos, VR/AR e outros. Os recursos estão disponÃveis em muitos \u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eformatos aceitos pela indústria\u003c/a\u003e, incluindo MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB e outros. Se você procura assets high poly ou em tempo real, temos uma biblioteca lÃder de arte digital para todas as suas necessidades.\n","info-section__description_1_printable_html":"Arquivos, impressões e modelos 3D profissionais prontos para serem impressos em casa com impressoras 3D FDM de mesa ou SLS industriais, disponÃveis em muitos formatos industriais, incluindo OBJ, \u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003e, WRL. Se você é um entusiasta de impressão 3D, maker, educador ou uma empresa que cria protótipos por meio de impressão 3D, nossas decorações para casa, acessórios de gadgets modernos, peças de moda chamativas, joias únicas, peças mecânicas e uma variedade de miniaturas certamente lhe darão um impulso de inspiração.","info-section__heading_1_html":"Explorar \u003cstrong\u003ecategorias\u003c/strong\u003e de modelos 3D","info-section__heading_1_printable_html":"Explorar Modelo 3D Printing \u003cstrong\u003e Categorias \u003c/strong\u003e","info-section__heading_2_html":"\u003cstrong\u003eMarketplace\u003c/strong\u003e de modelos 3D","info-section__heading_2_printable_html":"O que \u003cstrong\u003emais\u003c/strong\u003e?"},"marketplace":{"3d-printing":{"link_text":"Navegar por modelos de impressão 3D","text":"Encontre modelos 3D para impressão em sua impressora 3D.","title":"Modelos de impressão 3D"},"blender_text":"Descubra milhares de modelos 3D Blender disponÃveis no formato blend.","browse":"Navegar","cinema-4d_text":"Descubra milhares de modelos Cinema 4D de alta qualidade disponÃveis no formato c4d.","discounted":{"link_text":"Procurar desconto modelos 3D","text":"Compre modelos 3D profissionais com um desconto.","title":"Descontados modelos 3D"},"low-poly":{"link_text":"Navegar por modelos 3D low poly","text":"Modelos 3D low poly prontos para videogames e aplicações VR \u0026 AR em tempo real.","title":"Modelos 3D low poly"},"pbr":{"link_text":"Navegar por modelos 3D PBR","text":"Modelos 3D baseados em renderização fÃsica.","title":"Modelo 3D PBR"},"scripts_apps":{"link_text":"Navegar por todos","text":"Scripts e plugins 3D para tornar seu pipeline de modelagem 3D mais eficiente.","title":"Scripts e Apps"},"sketchup_text":"Navegue pela vasta seleção de modelos 3D Sketchup para seus designs arquitetônicos, interiores e de videogame.","textures":{"link_text":"Navegar por texturas","text":"Texturas prontas para uso para economizar tempo na preparação de seus modelos 3D.","title":"Texturas"},"zbrush_text":"Encontre assets 3D em formato ZTL para seus projetos de escultura digital, modelagem 3D, texturização e pintura."},"more":{"designers":{"link_text":"Navegar pela lista de designers 3D","text":"Navegue por milhares de portfólios de designers 3D e encontre exatamente o que você\nprecisa para sua aplicação.\n","title":"Encontre os melhores designers 3D"},"projects":{"link_text":"Saiba mais sobre projetos 3D","text":"Contrate artistas 3D freelancers qualificados e resolva todos os seus desafios de\nmodelagem personalizada.\n","title":"Projetos 3D CGTrader"},"visualization":{"link_text":"Saiba mais","text":"Transforme seus produtos em modelos 3D fotorrealistas para e-commerce e outras\naplicações empresariais.\n","title":"Visualização 3D para e-Commerce"}},"navbar":{"aircraft":"Aeronave","animal":"Animais","animals":"Animais","architectural":"Arquitetônico","art":"Arte","car":"Carro","character":"Personagem","exterior":"Exterior","fashion":"Moda","food":"Comida","furniture":"MobÃlia","gadgets":"Aparelhos","games-toys":"Jogos e Brinquedos","hobby-diy":"Hobby \u0026 DIY","house":"Casa","household":"Casa","industrial":"Industrial","interior":"Interior","jewelry":"Joalheria","military":"Militares","miniatures":"Miniatures","plant":"Plantar","science":"Ciência","space":"Espaço","vehicle":"VeÃculo","watercraft":"Embarcação"},"print_models":{"subtitle":"Encontre exatamente o conteúdo de impressão 3D certo para suas necessidades","title_html":"Comprar \u003cstrong\u003emodelos 3D profissionais para impressão\u003c/strong\u003e"},"profile":{"collection":"packs 3D","free":"Modelos 3D grátis","high_poly":"Modelos High-Poly 3D","optimized":"Low-Poly / Modelos Pbr 3D","printable":"Modelos De Impressão 3D"},"seo":{"cg":{"aircraft":"Esta categoria abrange aeronaves 3D. Os aviões CG se encaixam em simulações,\nvisualizações, anúncios e vÃdeos. Corpos e peças de drones vão agradar os fãs de\npequenos veÃculos aéreos. E os modelos rigged estão prontos para serem importados em\nmotores de jogo.\n","animals":"A coleção de fauna 3D â gatos, cavalos, ursos, rinocerontes, águias, leões e mais â\npode ser encontrada aqui. Os animais CG satisfazem as necessidades de anúncios ou cenas\nestáticas. Também temos modelos de animais rigged para jogos.\n","architectural":"Escadas, lareiras, modelos 3D, bem como decorações como quadros, travesseiros ou\nlâmpadas, podem ser encontrados na extensa biblioteca de modelos arquitetônicos detalhados.\nInteriores e exteriores podem ser usados para construir cozinhas digitais, quartos, salas\nde castelo ou masmorras, seja você arquiteto, engenheiro ou desenvolvedor independente.\n","car":"A c
16518ategoria Carros contém modelos 3D de automóveis, cujas versões low poly atraem\ndesigners de jogos, outras cineastas ou publicitários. De carros clássicos a carros de\ncorrida e conceito, há uma grande variedade de modelos 3D de automóveis.\n","character":"Nesta categoria você encontrará modelos 3D de humanos, pessoas, ficção cientÃfica,\nroupas e outros. De coração e mão a modelos realistas detalhados masculinos ou\nfemininos. Vários modelos são rigged e podem ser facilmente adicionados ao seu jogo ou\nanimação.\n","electronics":"Electronics é uma categoria para arquitetos, decoradores, designers de nÃveis, fabricantes de cena e outros criativos. modelos 3D de { \"slug\": \"smartphones\", \"title\": \"smartphones\"}, { \"slug\": \"laptop\", \"title\": \"laptops\"}, { \"slug\": \"câmera\", \"tÃtulo \": 'câmeras'}, {\"slug\": 'tV', 'title': 'TVS'} e muito mais vai ajudar a capturar com precisão a obsessão da vida moderna com dispositivos e tecnologia.\n","engineering-parts":"Janelas, encanamentos, deslizantes mecanismos das portas e outros pedaços que são necessários para projectos de CAD e até mesmo planos de DIY se enquadram nesta categoria. Isto é onde você pode encontrar modelos 3D de fabricantes globais como Anver, Dynatec e FCi.\n","exterior":"Navegue por exteriores arquitetônicos de fachadas, edifÃcios urbanos até objetos de\npaisagem, casas residenciais, construções industriais e modelos completos de cidades 3D.\nAlguns assets são low poly e podem ajudá-lo a completar seu jogo ou aplicativo VR/AR.\n","food":"A comida ajuda a criar cenas realistas da vida doméstica. Frutas, vegetais, bebidas e\nrefeições 3D estão todos aqui. Anúncios para restaurantes, aplicativos AR para alimentação\nmais saudável. Se você estava procurando um modelo de pizza 3D ou bolo de casamento, eles\nestão aqui.\n","furniture":"Mesas, cadeiras, sofás, camas 3D em uma variedade de texturas (madeira, metal, etc.)\ne estilos (retrô, moderno, etc.) estão disponÃveis. Esta categoria é destinada a todos os\nenvolvidos com arquitetura, design de interiores e publicidade.\n","furniture-set":"Se você precisa de olhar tanto cadeira antiga e sofá olhando, ou conjunto completo de utensÃlios de cozinha, este é um lugar para ser como categoria conjuntos de coleta de modelos de mobiliário 3D a partir de cozinha e sala de estar para o escritório e sala de jantar conjuntos de mobiliário salão. Isso ajuda os interiores ou design de nÃvel quartos de construção especialista com elementos correspondentes.\n","household":"Modelos 3D de itens domésticos são usados para dar detalhes aos cômodos. Você pode colocar\num conjunto de jantar 3D na mesa ou recipientes de sal e pimenta para completar a cozinha,\ntalvez adicionar luzes e flores perto da cama para criar um ambiente luxuoso.\n","industrial":"Materiais de construção, ferramentas de engenharia, máquinas e contêineres que\nfornecem detalhes ambientais e elementos interativos rigged. Perfeito para\ndesenvolvedores de jogos de simulação ou pessoas que constroem nÃveis de canteiros de obras.\n","interior":"Esta categoria contém elementos 3D realistas e detalhes de arquitetura, construção\ne design de interiores. Você pode usar esses modelos 3D para animações ou jogos â\nalguns são rigged e low poly.\n","military":"Nesta categoria você pode comprar modelos 3D de armas, armaduras, espadas e artilharia â\nmodernas e históricas â usadas por forças militares e para autodefesa. Você pode usar os\nmodelos em jogos â alguns são otimizados em polÃgonos e prontos para motores de jogo.\n","plant":"Esta categoria contém modelos 3D de organismos de flora, como flores, árvores, grama,\ntrepadeiras, vegetação, ervas, perenes, mudas, brotos, arbustos, estacas, rebentos,\nvideiras e ervas daninhas. Para comprar ou baixar gratuitamente um modelo 3D, navegue\npelas categorias abaixo.\n","scanned":"Modeladores criar esses modelos utilizando tecnologias 3D digitalização como RealSense. Ãrvore tocos, estátuas, mesmo machos e fêmeas são populares aqui. O produto está pronto para ser usado em cenas e animações, oferecendo nÃveis inigualáveis ââde realismo.\n","scie
16518nce":"Esta categoria contém 3D modelos relacionados com a medicina, biologia, fÃsica, quÃmica e tecnologia, tais como equipamento de laboratório, corpos microscópicos e mundo subatômico. Não procure mais, { \"slug\": \"célula\"}, { \"slug\": \"crânio\"} e { \"slug\": \"esqueleto\"} 3D modelos podem ser encontrados aqui.\n","scripts-plugins":"Scripts e plug-ins fornecem atalhos de software. Renderização, modelagem, texturização - tudo isso pode ser facilitado usando plug-ins que vêm para todos os tipos de software, como Maya e V-Ray.\n","space":"O espaço é uma categoria cheia de modelos low poly, prontos para jogos, de naves espaciais\nsci-fi, asteroides, planetas (incluindo a Terra e ônibus espaciais realistas para os mais\ncientÃficos). Modelos 3D de espaço são úteis para jogos simuladores de espaço VR.\n","sport-hobby":"Esta categoria encompases tudo o que está relacionado com { \"slug\": \"campo\"} eventos, esportes e hobbies em geral. De { \"slug\": \"football\"} e pistas de esqui para { \"slug\": \"guitarra\"} e { \"slug\": \"piano\"}, estes são úteis 3D modelos para anúncios, cenas e animação. versões de baixa-poli estão lá para jogos de vÃdeo de esportes.\n","textures":"Navegue por uma biblioteca de materiais 3D lindamente feitos e encontre as texturas prontas\npara uso mais adequadas para preparar modelos prontos para jogos ou fotorrealistas, atualizar\nsua biblioteca de ativos e melhorar seus trabalhos 3D.\n","various":"Estes são os modelos 3D que não facilmente se encaixam em outras categorias, por isso criamos um que iria ace
16518itá-los todos. { \"title\": \"Rocks\", \"slug\": \"rochas\"}, { \"slug\": \"nuvens\"}, { \"title\": \"logos\", \"slug\": \"logo\"}, { \"tÃtulo\" : \"guarda-chuvas\", \"slug\": \"guarda-chuva\"} e outros modelos não-categorizadas em 3D estão aqui.\n","vehicle":"Caminhões, ambulâncias, ônibus, trens, tratores, bicicletas e motocicletas â esta\ncategoria é para as pessoas que querem suas ruas da cidade cheias de veÃculos realistas e\nsci-fi, e para aqueles que fazem jogos de simulação ou cartazes.\n","watercraft":"Embarcações cobrem barcos, iates, navios e outros veÃculos aquáticos. Os modelos 3D rigged\nfuncionam bem em videogames e animações, enquanto os modelos CG servem para cenas ou outras\naplicações onde a fidelidade visual é mais importante que a contagem de polÃgonos.\n"},"forwarded":{"cg":{"aircraft":"Esta categoria abrange aeronaves 3D. CG { \"slug\": \"airplane\", \"title\": \"aviões\"} vai caber em simulações, visualizações, anúncios e vÃdeos. { \"slug\": \"drone\", \"title\": \"Drone\"} corpos e partes irá deliciar os fãs de pequenos veÃculos voadores. E o { \"slug\": \"aircraft\", \"title\": \"fraudada modelos\", \"active_filter\": \"rigged\"} está pronto para ser importado para motores de jogo.\n","animals":"A coleção de fauna 3D - { \"slug\": \"cat\", \"title\": \"gatos\"}, { \"slug\": \"horse\", \"title\": \"cavalos\"}, { \"slug\": \"bear\" , \"title\": \"ursos\"}, { \"slug\": \"rhino\", \"title\": \"rinocerontes\"}, { \"slug\": \"eagle\", \"title\": \"águias\"}, { \"slug\": \"lion\", \"title\": \"leões\"} e muito mais - pode ser encontrada aqui. Os animais CG 3D irá satisfazer as necessidades de anúncios ou cenas estáticas. Temos também { \"slug\": \"animal\", \"title\": \"fraudada animal\", \"active_filter\": \"rigged\"} modelos para jogos.\n","architectural":"{ \"slug\": \"stairs\", \"title\": \"Escada\"}, { \"slug\": \"fireplace\", \"title\": \"lareira\"}, modelos 3D, bem como decorações como { \"slug\": \"frame\", \"title\": \"frame\"}, { \"slug\": \"pillow\", \"title\": \"travesseiro\"} ou { \"slug\": \"lamp\", \"title\": \"lâmpada\"} podem ser encontrados na extensa categoria detalhe do carro de arquitetura contém automóvel 3D modelos, { \"slug\": \"car\", \"title\": \"poli baixa\", \"active_filter\": \"low_poly\"} biblioteca modelo. Interior e exterior pode ser usado para construir as duas cozinhas digitais e quartos, bem como salas de castelos e masmorras se você é um arquiteto, engenheiro ou desenvolvedor de jogos indie.\n","car":"Categoria de carro contém automóvel 3D modelos, versões baixo poli \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e low-poly \u003c/a\u003e de que será atraente para os designers de jogos, outros - para cineastas ou anunciantes. De carros clássicos para corrida e pista de carros para aqueles conceito, há uma grande variedade de modelos de automóveis 3D.\n","character":"Nesta categoria você vai encontrar modelos 3D de { \"slug\": \"human\", \"title\": \"humano\"}, as pessoas, sci-fi, roupas e outros. De { \"slug\": \"heart\", \"title\": \"coração\"} e { \"slug\": \"hand\", \"title\": \"mão\"} para detalhada realista { \"slug\": \"male\", \"title\": \"macho\"} ou { \"slug\": \"female\", \"title\": \"feminino\"} modelos. Um número de modelos são manipuladas e pode ser facilmente adicionado ao seu jogo ou animação.\n","electronics":"Electronics é uma categoria para arquitetos, decoradores, designers de nÃveis, fabricantes de cena e outros criativos. modelos 3D de { \"slug\": \"smartphone\", \"title\": \"smartphones\"}, { \"slug\": \"laptop\", \"title\": \"laptops\"}, { \"slug\": \"camera\", \"title\": \"câmeras\"}, {\"slug\": \"tV\", \"title\": \"TVS\"} e muito mais vai ajudar a capturar com precisão a obsessão da vida moderna com dispositivos e tecnologia.\n","engineering-parts":"Janelas, encanamentos, deslizantes mecanismos das portas e outros pedaços que são necessários para projectos de CAD e até mesmo planos de DIY se enquadram nesta categoria. Isto é onde você pode encontrar modelos 3D de fabricantes globais como Anver, Dynatec e FCi.\n","exterior":"Exteriores arquitectónicas navegar a partir de fachadas, edifÃcios urbanos para objetos paisagem, casas residenciais, construções industriais, e em grande escala 3D { \"slug\": \"city\", \"title\": \"Cidade\"} modelos. Alguns dos ativos são baixos poli e poderia ajudá-lo a completar o seu jogo ou aplicativo VR / AR.\n","food":"Food ajuda a criar cenas realistas da vida doméstica. 3D frutas, legumes, bebidas e refeições estão todos aqui. Anúncios para restaurantes, aplicações AR para uma alimentação mais saudável. Se você estava procurando 3D { \"slug\": \"pizza\", \"title\": \"pizza\"} ou um casamento { \"slug\": \"cake\", \"title\": \"bolo\"} modelo, eles estão aqui.\n","furniture":"Mesas 3D, cadeiras, sofás, camas em uma variedade de texturas (madeira, metal, etc.) e estilos ({ \"slug\": \"retro\", \"title\": \"retro\"}, { \"slug\": \"modern\", \"title\": \"modernas\"}, etc.) estão on- mão. Esta categoria é para qualquer um envolvido com arquitetura e design de interiores, bem como anunciantes.\n","furniture-set":"Se você precisa de olhar tanto cadeira antiga e sofá olhando, ou conjunto completo de utensÃlios de cozinha, este é um lugar para ser como categoria conjuntos de coleta de modelos de mobiliário 3D a partir de cozinha e sala de estar para o escritório e sala de jantar conjuntos de mobiliário salão. Isso ajuda os interiores ou design de nÃvel quartos de construção especialista com elementos correspondentes.\
16518n","household":"Modelos item doméstico 3D são usadas para dar detalhes aos quartos. Você pode colocar um jogo de jantar 3D sobre a mesa, ou ter sal e pimenta recipientes para interior cozinha completa, talvez colocar alguma { \"slug\": \"light\", \"title\": \"luzes\"} e { \"slug\": \"flowers\", \"title\": \"flores\"} perto da cama para criar sensação de luxo.\n","industrial":"Materiais de construção, { \"slug\": \"engineering\", \"title\": \"engenharia\"} ferramentas, máquinas e { \"slug\": \"container\", \"title\": \"containers\"} que fornecem ambos os detalhes ambientais e interativos, manipuladas elementos. Isto é perfeito para desenvolvedores de jogos de simulação ou pessoas construindo { \"slug\": \"construction\", \"title\": \"construção\"} nÃvel jardim.\n","interior":"Esta categoria contém realistas 3D elementos e detalhes de arquitetura, construção e engenharia de design de interiores. Você pode usar esses modelos 3D para animação ou jogos - alguns deles são manipuladas e low poly.\n","military":"Nesta categoria você pode comprar 3D modelos de armas, braços, { \"title\": \"espadas\", \"slug\": \"sword\"} e artilharia moderna e histórico usado por forças militares e de defesa pessoal. Você pode usar modelos para jogos - alguns deles são polÃgonos otimizados e prontos para motores de jogo.\n","plant":"Esta categoria contém 3D modelos de flora organismos, tais como flores, { \"slug\": \"tree\", \"title\": \"árvores\"}, grama, trepadeiras, hortaliças, ervas, plantas perenes, mudas, brotos, arbustos, deslizamentos, couve, videiras, planta daninha. Para comprar ou baixar um modelo 3D livre, navegar pelas categorias abaixo.\n","scanned":"Modeladores criar esses modelos utilizando tecnologias 3D digitalização como RealSense. Ãrvore tocos, estátuas, mesmo machos e fêmeas são populares aqui. O produto está pronto para ser usado em cenas e animações, oferecendo nÃveis inigualáveis ââde realismo.\n","science":"Esta categoria contém 3D modelos relacionados com a medicina, biologia, fÃsica, quÃmica e tecnologia, tais como equipamento de laboratório, corpos microscópicos e mundo subatômico. Não procure mais, { \"slug\": \"cell\", \"title\": \"célula\"}, { \"slug\": \"skull\", \"title\": \"crânio\"} e { \"slug\": \"skeleton\", \"title\": \"esqueleto\"} 3D modelos podem ser encontrados aqui.\n","scripts-plugins":"Scripts e plug-ins fornecem atalhos de software. Renderização, modelagem, texturização - tudo isso pode ser facilitado usando plug-ins que vêm para todos os tipos de software, como Maya e V-Ray.\n","space":"O espaço é uma categoria cheia de low poly, modelos de jogo-pronto de sci-fi { \"slug\": \"spaceship\", \"title\": \"naves espaciais\"}, { \"slug\": \"asteroid\", \"title\": \"asteróides \"}, planetas (incluindo {\"slug\": \"earth\", \"title\": \"terra\"} e espaço realista {\"slug\": \"shuttle\", \"title\": \" shuttles\"} para os mais cientificamente inclinado 3D modelos espaciais são úteis para VR jogos espaço simulador.\n","sport-hobby":"Esta categoria encompases tudo o que está relacionado com { \"slug\": \"field\", \"title\": \"campo\"} eventos, esportes e hobbies em geral. De { \"slug\": \"football\", \"title\": \"football\"} e pistas de esqui para { \"slug\": \"guitar\", \"title\": \"guitarra\"} e { \"slug\": \"piano\", \"title\": \"piano\"}, estes são úteis 3D modelos para anúncios, cenas e animação. versões de baixa-poli estão lá para jogos de vÃdeo de esportes.\n","textures":"Navegar através de uma biblioteca de materiais 3D lindamente feitas e encontrar os melhores, texturas prontas para uso adequados à preparação \u003ca href=\"%{link_to_low_poly_items_url}\"\u003ejogo pronto\u003c/a\u003e ou modelos fotorrealistas, atualizar sua biblioteca de ativos e melhorar suas obras 3D.\n","various":"Estes são os modelos 3D que não facilmente se encaixam em outras categorias, por isso criamos um que iria ace
16518itá-los todos. { \"title\": \"Pedras\", \"slug\": \"rocks\"}, { \"slug\": \"clouds\", \"title\": \"nuvens\"}, { \"title\": \"logos\", \"slug\": \"logo\"}, { \"title\" : \"guarda-chuvas\", \"slug\": \"umbrella\"} e outros modelos não-categorizadas em 3D estão aqui.\n","vehicle":"Caminhões, { \"title\": \"ambulâncias\", \"slug\": \"ambulance\"}, ônibus, trens, tratores, { \"title\": \"bicicletas\", \"slug\": \"bike\"} e motocicletas - esta categoria é para as pessoas que querem suas ruas da cidade para ser preenchido com veÃculos realistas e sci-fi, e para aqueles que fazem jogos de simulação ou formatação cartazes.\n","watercraft":"Coberturas de embarcações { \"title\": \"barcos\", \"slug\": \"boat\"}, { \"title\": \"iates\", \"slug\": \"yacht\"}, { \"title\": \"navios\", \"slug\": \"ship\"} e outros veÃculos aquáticos. O fraudada modelos 3D vai fazer bem em jogos de vÃdeo, animação, enquanto os modelos CG estão lá para suas cenas ou outras aplicações onde a fidelidade visual é mais importante do que polycount.\n"},"printable":{"art":"Este é o lugar onde as artÃsticas impressões 3D ir. Procurando por design extravagante escultura recriar obras clássicas e estátuas de personalidades históricas, ou inspirando estatuetas, talvez até mesmo logotipos 3D imprimÃveis? Essa é a categoria.\n","fashion":"Coisas bonitas e elegantes que você pode usar são encontrados nesta categoria. Veja se você pode encontrar qualquer uso para a idade espaço fantasia { \"slug\": \"footwear\", \"title\": \"calçado\"}, óculos de novidade e cosplay { \"slug\": \"accessories\", \"title\": \"acessórios\"} encontrada aqui.\n","gadgets":"Todos os { \"title\": \"iPhone\", \"slug\": \"iphone\"}, { \"title\": \"iPad\", \"slug\": \"ipad\"} (e outros dispositivos inteligentes) casos podem ser encontrados na categoria gadget. De simples 3D add-ons para partes complexas e âhacksâ para seus itens, esta é a categoria para os criativos, e os amantes da tecnologia.\n","games-toys":"Jogos e brinquedos é a categoria que abrange impressão alienÃgenas ou monstros miniaturas 3D, minúsculo { \"title\": \"tanques\", \"slug\": \"tank\"}, funky { \"slug\": \"chess\", \"title\": \"xadrez\"} peças, capacetes personagem do filme, passatempo parafernália e acessórios. Esta é a categoria-para ir para todas as coisas geeky.\n","hobby-diy":"Se você é o nosso próximo grande inventor e quer construir seu projeto de DIY ou obter algumas peças de reposição para o seu { \"slug\": \"drone\", \"title\": \"zangão\"}, este é o lugar para estar. Além disso, possui um monte de coisas para as pessoas que querem fazer as suas próprias figuras ou réplicas de armas de plástico.\n","house":"Todos os tipos de bugigangas pode ser encontrada aqui. { \"title\": \"Lâmpadas\", \"slug\": \"lamp\"}, artÃstico { \"title\": \"taças\", \"slug\": \"bowl\"}, e todos os tipos de { \"title\": \"titulares\", \"slug\": \"holder\"} se você não consegue encontrar um local adequado para o seu telefone, manter a ordem de palitos, pilha de penas ou jóias em sua mesa.\n","jewelry":"A jóia é onde você vá para obter pulseiras e pingentes ou anéis com diamantes. Embora as impressoras 3D não são bons o suficiente para fazer os diamantes - ainda - você pode ainda imprimir um anel metálico como uma base para o seu TI anel proposta geek.\n","miniatures":"3D impressão { \"title\": \"caracteres\", \"slug\": \"character\"}, pessoas famosas, { \"title\": \"marcos\", \"slug\": \"landmark\"}, animais, { \"title\": \"Macho\",\"slug\": \"male\"}, { \"slug\": \"female\", \"title\": \"feminino\"}, { \"title\": \"monstros\", \"slug\": \"monster\"}, { \"title\": \"alienÃgenas\",\"slug\": \"alien\"} - está tudo aqui. Se você estiver imprimindo veÃculos utilitários para colocar em sua mesa ou criar miniaturas para seus jogos de mesa, é a sua categoria.\n","science":"O que pode ser classificada como ciência? Bem, modelos de esqueleto { \"slug\": \"bones\", \"title\": \"ossos\"}, os médicos { \"slug\": \"tools\", \"title\": \"ferramentas\"} e astrofÃsica relacionadas com 3D modelos imprimÃveis que podem ser usados ââem muitos processos de estudo.\n"}},"printable":{"art":"Este é o lugar onde as artÃsticas impressões 3D ir. Procurando por design extravagante escultura recriar obras clássicas e estátuas de personalidades históricas, ou inspirando estatuetas, talvez até mesmo logotipos 3D imprimÃveis? Essa é a categoria.\n","fashion":"Coisas bonitas e elegantes que você pode usar são encontrados nesta categoria. Veja se você pode encontrar qualquer uso para a idade espaço fantasia { \"slug\": \"calçado\"}, óculos de novidade e cosplay { \"slug\": \"acessórios\"} encontrada aqui.\n","gadgets":"Todos os { \"title\": \"iPhone\", \"slug\": \"iphone\"}, { \"title\": \"iPad\", \"slug\": \"ipad\"} (e outros dispositivos inteligentes) casos podem ser encontrados na categoria gadget. De simples 3D add-ons para partes complexas e âhacksâ para seus itens, esta é a categoria para os criativos, e os amantes da tecnologia.\n","games-toys":"Jogos e brinquedos é a categoria que abrange impressão alienÃgenas ou monstros miniaturas 3D, minúsculo { \"title\": \"tanques\", \"slug\": \"tanque\"}, funky { \"slug\": \"xadrez\"} peças, capacetes personagem do filme, passatempo parafernália e acessórios. Esta é a categoria-para ir para todas as coisas geeky.\n","hobby-diy":"Se você é o nosso próximo grande inventor e quer construir seu projeto de DIY ou obter algumas peças de reposição para o seu { \"slug\": \"zangão\"}, este é o lugar para estar. Além disso, possui um monte de coisas para as pessoas que querem fazer as suas próprias figuras ou réplicas de armas de plástico.\n","house":"Todos os tipos de bugigangas pode ser encontrada aqui. { \"title\": \"Lâmpadas\", \"slug\": \"lâmpada\"}, artÃstico { \"title\": \"taças\", \"slug\": \"tigela\"}, e todos os tipos de { \"title\": \"titulares\", \"slug\": \"titular\"} se você não consegue encontrar um local adequado para o seu telefone, manter a ordem de palitos, pilha de penas ou jóias em sua mesa.\n","jewelry":"A jóia é onde você vá para obter pulseiras e pingentes ou anéis com diamantes. Embora as impressoras 3D não são bons o suficiente para fazer os diamantes - ainda - você pode ainda imprimir um anel metálico como uma base para o seu TI anel proposta geek.\n","miniatures":"3D impressão { \"title\": \"caracteres\", \"slug\": \"caráter\"}, pessoas famosas, { \"title\": \"marcos\", \"slug\": \"marco\"}, animais, { \"title\": \"Male \",\"slug\": \"macho\"}, { \"slug\": \"feminino\"}, { \"title\": \"monstros\", \"slug\": \"monstro\"}, { \"title\": \"alienÃgenas\",\"slug\": \"alien\"} - está tudo aqui. Se você estiver imprimindo veÃculos utilitários para colocar em sua mesa ou criar miniaturas para seus jogos de mesa, é a sua categoria.\n","scie
16518nce":"O que pode ser classificada como ciência? Bem, modelos de esqueleto { \"slug\": \"ossos\"}, os médicos { \"slug\": \"ferramentas\"} e astrofÃsica relacionadas com 3D modelos imprimÃveis que podem ser usados ââem muitos processos de estudo.\n"},"titles":{"aircraft":"Modelos 3D de aeronaves","animals":"Modelos 3D de animais","architectural":"Modelos 3D arquitetônicos","car":"Modelos 3D de carros","character":"Modelos 3D de personagens","exterior":"Modelos 3D de exteriores","food":"Modelos 3D de comida","furniture":"Modelos 3D de móveis","household":"Modelos 3D domésticos","industrial":"Modelos 3D industriais","interior":"Modelos 3D de interiores","military":"Modelos 3D militares","plant":"Modelos 3D de plantas","space":"Modelos 3D do espaço","textures":"Modelos 3D de texturas CG","vehicle":"Modelos 3D de veÃculos","watercraft":"Modelos 3D de embarcações"}},"title":{"cg":" Modelos 3D","print":" Arquivos de impressão 3D"}},"competition":{"digital-art-competition":{"categories":{"page_description":"Participar do Concurso de Arte Digital CGTrader através da apresentação de seus trabalhos para a ilustração do personagem, Character Concept Design, Ilustração Meio Ambiente, Meio Ambiente conceito de design, objeto de design e objeto categorias conceito de design. Se você tem vários grandes obras que atendam à s diferentes categorias, não hesite em enviá-los para as categorias correspondentes. Selecione uma categoria para ver os prêmios para essa categoria."}}},"conversations":{"action_button_confirmation":"Você realmente deseja reabrir esta solicitação?","reply_posted":"A resposta foi publicada.","with_yourself":"não pode ser o mesmo que o remetente."},"date":{"month_names":[null,"Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"]},"devise":{"failure":{"too_many_requests":"Você já solicitou um e-mail para redefinir a senha. Por favor, aguarde alguns minutos antes de tentar novamente."}},"disabled_cookies_modal":{"button":"Cancelar","text_1":"Você não será capaz explorar milhões de grandes modelos 3D, adicioná-los ao carrinho ou Buy.","text_2":"Se você quiser experimentar CGTrader totalmente, sugerimos ativar os cookies neste site.","title":"Parece que você tem cookies do seu navegador desativada"},"emails":{"error_notification":"Assinatura não encontrada.","success_subscribed_notification":"Você se inscreveu com sucesso.","success_unsubscribed_notification":"Você cancelou a assinatura com sucesso."},"errors":{"messages":{"invalid_vat":"O NIF %{country_adjective} não é válido."}},"file_size_validator":{"errors":{"invalid_carrierwave":"Era esperado um objeto CarrierWave::Uploader::Base","invalid_key":":%{key} deve ser um número inteiro não negativo","range_format":":in e :within devem ser um intervalo (Range)","range_unspecified":"Intervalo não especificado. Especifique a opção :within, :maximum, :minimum ou :is."}},"file_type":{"default_error":"Nenhum caminho para o arquivo fornecido."},"footer":{"bottom-row":{"privacy":"Privacidade","terms-link":"Termos e Condições"},"links":{"buyLinks":[{"text":"Comprar modelos 3D","link":"/pt/3d-modelos"},{"text":"Para empresas","link":"/discover/business-account"},{"text":"Conjuntos de dados 3D gratuitos","link":"/discover/datasets"},{"text":"Contratar designer 3D","link":"/3d-modeling-jobs"},{"text":"Modelos 3D gratuitos","link":"/pt/livre-3d-modelos"},{"text":"Modelos 3D para impressão gratuitos","link":"/pt/livre-3d-impressao-modelos"}],"communityLinks":[{"text":"Comunidade","link":""},{"text":"Melhores designers","link":"/designers"},{"text":"Desafios","link":"/challenges"},{"text":"Fórum","link":"/forum"}],"companyLinks":[{"text":"Empresa","link":"/discover/about-us"},{"text":"Blogue","link":"/blog"},{"text":"Carreiras","link":"/pages/careers"},{"text":"Centro de ajuda","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"Vender modelos 3D","link":"/discover/sell-3d-models"},{"text":"Aumente suas vendas","link":"/discover/sell-more"},{"text":"Insights do mercado 3D","link":"/discover/3d-market-trends"},{"text":"Principais pesquisas de modelos 3D","link":"/discover/3d-models-top-searches"},{"text":"Principais pesquisas de impressão 3D","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"Se inscrever","button-disabled":"Subscrito","header":"Assine a nossa notÃcia:","placeholder":"Digite seu e-mail","terms-link":"Termos de uso","text":"Ao subscrever você confirma que leu e aceitou o nosso"}},"general":{"description":"CGTrader é um mercado online onde 3D artistas e designers podem comprar, vender ou compartilhar modelos 3D. Foi fundada e está sendo desenvolvido por uma equipe de designers 3D e engenheiros. Nosso objetivo é democratizar o mercado de ações 3D e mudar a maneira de vender os modelos 3D online. Ao permitir que autores ganhar royalties máximo, nós nos esforçamos para aumentar a sua motivação e aumentar a qualidade dos modelos 3D.","navigation":{"buy_3d_models":"Modelos Comprar 3D","sell_3d_models":"Vender modelos 3D"},"search_placeholder":"Pesquisar em mais de 2 milhões de modelos","site-search__field":"Pesquise entre %{model_count}
16518 modelos 3D","site_title":"3D loja Modelo","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"Deixe a IA realizar os seus sonhos","subtitle":"Converta um prompt ou uma imagem de referência num modelo 3D pronto para produção, depois refine, retexturize e exporte-o no formato de que necessita."},"faq":{"heading":"Perguntas Frequentes","items":{"commercial":{"answer":"A utilização comercial do seu modelo 3D de %{object} está disponÃvel com um plano pago do CGTrader AI. Por favor reveja os Termos e Condições da CGTrader para as condições de licença aplicáveis aos modelos gerados por IA.","question":"Posso usar o modelo de %{object} gerado para fins comerciais?"},"formats":{"answer":"Os modelos 3D de %{object} estão disponÃveis em formato GLB, FBX, OBJ, STL ou USDZ.","question":"Em que formato de ficheiro posso obter o meu modelo de %{object}?"},"no_skills":{"answer":"Não são necessários conhecimentos de modelação 3D. Toda a modelação é feita através do gerador de modelos de %{object}. O sistema trata da geometria, proporções e estrutura quando introduz o seu prompt ou carrega uma imagem. Mesmo os principiantes podem criar um modelo 3D completo de %{object} em minutos.","question":"à necessário conhecimento de modelação 3D para usar um gerador de modelos de %{object}?"},"what_is":{"answer":"O gerador de modelos 3D de %{object} da CGTrader, uma ferramenta baseada em IA, cria um modelo tridimensional de %{object} a partir de instruções escritas ou imagens de referência. Analisa a sua ideia e cria um modelo descarregável para design, prototipagem e visualização. As nossas subscrições pagas oferecem limites mensais mais elevados.","question":"O que é um gerador de modelos 3D de %{object}?"},"why_cgtrader":{"answer":"Os utilizadores podem confiar na CGTrader para uma experiência fluida, tempos de processamento rápidos e resultados 3D de alta qualidade. Esta ferramenta é adequada tanto para profissionais como para principiantes que procuram uma solução fiável para criar modelos 3D de %{object}.","question":"Por que usar o gerador de %{object} com IA da CGTrader?"}}},"h1":"Gerador de modelos 3D de %{object} com IA","hero_alt":"Gerador de modelos 3D de %{object} com IA","hero_height":617,"hero_width":1080,"how_to":{"heading":"Gerar %{object} a partir de imagens ou prompts de texto","paragraphs":["à muito fácil desenhar um modelo tridimensional de %{object}. Na barra lateral esquerda, no canto superior esquerdo, clique no botão para carregar a sua imagem de %{object} e criar um modelo 3D. Os utilizadores também podem introduzir um prompt no campo «Descreva o que pretende criar» na parte inferior. O CGTrader AI melhora o seu prompt automaticamente, pelo que uma descrição curta é suficiente para começar.","A barra lateral direita dá-lhe um bom controlo do seu modelo 3D de %{object}. Escolha definições como o tipo de malha, material, orientação de prompt e formato de ficheiro. Também pode utilizar texturização para personalizar o seu modelo de %{object}. Após introduzir as suas instruções de texto ou imagem, clique em «Gerar». A ferramenta processará a sua entrada em alguns minutos, dependendo da carga do sistema, material, tipo de malha, formas, valores de seed e qualidade."],"steps":["Escreva a sua descrição de texto e/ou anexe uma imagem de referência para melhorar a precisão final do seu modelo 3D de %{object}.","Selecione um dos nossos predefinidos, ou escolha um motor de IA, adicione um número personalizado de polÃgonos e selecione o tipo de material para o seu modelo 3D de %{object}.","Clique em Gerar para criar um modelo 3D de %{object} a partir do seu prompt e/ou imagem de referência.","Descarregue o seu modelo 3D de %{object} criado em diferentes formatos (GLB, FBX, OBJ, STL ou USDZ)."]},"intro":"Está à procura de uma forma simples e rápida de criar um modelo 3D de %{object} de alta qualidade em minutos? O nosso avançado gerador de modelos 3D de %{object}, CGTrader AI, pode transformar comandos escritos ou imagens de referência em modelos totalmente funcionais. Funciona nos principais motores de geração 3D, incluindo Meshy, Hunyuan e Tripo3D. Isto ajuda na modelação rápida de modelos 3D tanto para principiantes como para especialistas em design, para visualização, experimentação e prototipagem. Suporta texto para 3D e imagem para 3D, e é compatÃvel com impressoras 3D. Pode carregar uma imagem em formato JPG ou PNG, ou escrever uma descrição em texto. O CGTrader AI trata dos passos seguintes por si.","meta_description":"Gerador de modelos 3D de %{object} com IA da CGTrader âï¸ Crie modelos 3D de %{object} detalhados a partir de texto ou imagens. Comece gratuitamente.","primary_cta":"Começar a gerar gratuitamente","title":"Gerador de modelos 3D de %{object} com IA (grátis) | CGTrader"}}},"rules":{"errors":{"front_view_required":"à necessária uma imagem da vista frontal."}}},"home":{"index":{"3D-projects":{"info-section__cta":"Saber mais","info-section__description":"Onde as pessoas com emocionantes 3D Projects atender os designers 3D talentosos","info-section__heading_html":"\u003cStrong\u003e Projetos em 3D \u003c/strong\u003e Freelance Hub"},"categories-conatainer":{"browse_all":"Navegar por todos os modelos","browse_all_tooltip":"Consultar todos os modelos 3D","discounts":"descontos"},"cgdream":{"cta":"Comece de graça!","heading_html":"\u003cstrong\u003eExplore CGDream,\u003c/strong\u003e\u003c/br\u003e onde a IA encontra os modelos 3D.","text_html":"\u003cstrong\u003e CGDReam \u003c/strong\u003e é uma aplicação de ponta que aproveita o poder dos modelos generativos de IA e 3D para produzir imagens 2D impressionantes. \u003cstrong\u003e Sua jornada criativa começa agora. \u003c/strong\u003e"},"community":{"info-section__cta":"Junte-se à comunidade","info-section__heading_html":"Junte CGTrader \u003cstrong\u003e Comunidade \u003c/strong\u003e","info-section__icon-list_1":{"de
16518scription":"Apresente seu melhor torna, obter feedback e reconhecimento","heading":"galerias"},"info-section__icon-list_2":{"description":"Aprender novas habilidades e ensinar os outros","heading":"tutoriais"},"info-section__icon-list_3":{"description":"Encontrar tutoriais e discutir outros assuntos relacionados 3D","heading":"Fórum"}},"covid":{"timer-strip__item":"Liberar recursos para impressão em 3D para COVID-19 Proteção","timer-strip__item--button":"Pesquisar modelos 3D"},"enterprise":{"info-section__cta":"Saber mais","info-section__heading_html":"Serviços 3D para o \u003cstrong\u003e Empresa \u003c/strong\u003e","info-section__icon-list_1":"Nós podemos fazer a implementação AR para você","info-section__icon-list_2":"Mais conversões de vendas, menos devoluções de produtos","info-section__icon-list_3":"Qualidade assegurada com QA rigorosa"},"header":"Modelos 3D para impressão e computação gráfica VR / AR, 3D","marketplace":{"info-section__description":"Escolha a partir de %{models_count} 3D modelos para aplicações como jogos, AR / VR, publicidade, animação, filmes e impressão 3D","info-section__heading_html":"Modelo 3D \u003cstrong\u003e mercado \u003c/strong\u003e","info-section__image-list_1":{"description":"Comprar profissionais modelos 3D para seu projeto","heading":"Modelos 3D"},"info-section__image-list_2":{"description":"Modelos de baixo poli PBR 3D pronto para jogos de vÃdeo, VR \u0026 AR aplicações em tempo real","heading":"Baixa-poli Modelos PBR 3D"},"info-section__image-list_3":{"description":"Encontrar 3D imprimir desenhos para a impressora 3D","heading":"Impressão 3D Models"},"view_all":"Ver todos"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"Transforme uma imagem em um modelo 3D","title":"Imagem para 3D"},"text_to_3d":{"description":"Descreva sua ideia para criar um modelo 3D","title":"Texto para 3D"}},"ai_section_title":"Criar com IA","aria_label":"Sugestões de pesquisa","columns":{"cg":{"search_label":"Pesquisar em Modelos 3D","title":"Modelos 3D"},"print":{"search_label":"Pesquisar em Impressão 3D","title":"Modelos para impressão 3D"}}},"sell":{"info-section__heading_html":"\u003cstrong\u003e Vender \u003c/strong\u003e seus modelos 3D e encontrar freelance projectos","info-section__icon-list_1":{"description":"Vender seus modelos 3D e ganhe até 85% de royalties","link":"Vender modelos 3D\u003e"},"info-section__icon-list_2":{"description":"Trabalho com os clientes corporativos","link":"Obter Qualificado\u003e"},"info-section__icon-list_3":{"description":"Terceirizar suas habilidades e obter até 95% de royalties","link":"Navegar 3D Modeling Jobs\u003e"},"info-section__icon-list_4":{"description":"Construa o seu portfólio e ser visÃvel","link":"Navegar 3D Designers\u003e"}},"seo":{"description":"Explore mais de 2 milhões de modelos 3D online para projetos de impressão, jogos, VR/AR e design. Baixe, personalize ou contrate especialistas 3D - tudo no CGTrader.","title":"CGTrader - Modelos 3D e Marketplace de Impressão 3D"}}},"homepage":{"budget_counter":{"range_0_10":"Menos de $10","range_10_20":"$10 - $20","range_20_15000":"Mais de $20"},"quotes":{"quote_0":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Abaixe comissões retiradas dos meios vendedores preços melhores para os compradores. Confira e comparar os preços em CGTrader e as outras lojas."},"quote_1":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"A vantagem mais marcante CGTrader é sistema de ativação de taxa fixa que nos dá retornos elevados. Você não está tendo um percentual de comissão de nossas vendas. Após a venda, recebemos a 100% do preço. Só se quisermos continuar a vender esse produto, que pode voltar a ativá-lo novamente, pagando US $ 5. solução elegante."},"quote_10":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"O sistema de activação de taxa fixa é engenhoso. Fiquei me perguntando por que ninguém tinha pensado nisso antes. Após a venda, pagar uma pequena taxa para ativar um produto e é isso. O vendedor está em pleno controle."},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Há duas coisas que mais gosto sobre CGTrader. Primeiro, não há escondido que significa nada aqui. Você não precisa ter cuidado com CGTrader. Em segundo lugar, esta loja é pelos artistas e para os artistas. Eles compreendê-lo melhor. Algo está incomodando você aqui? ... informá-los e eles vão ter certeza de que você se sinta confortável aqui."},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"sistema de ativação de taxa fixa é a melhor! (Pelo menos eu não encontrei nada melhor do que isso). à muito realista e justo para os vendedores. Eles não se importam o quanto de lucro você faz, basta pagar o aluguel fixo. MAS se você não fazer nenhuma venda, você não tem que pagar o aluguel também. O comércio justo CG está aqui!"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"CGTrader atrai clientes até mesmo de paÃses em desenvolvimento, porque os preços são mais baratos do que em outras lojas. Ao mesmo tempo, os autores podem ganhar mais, porque não existe tal coisa como altas taxas de comissão. à uma maneira certa de valorizar o trabalho de artistas 3D."},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"A interface intuitiva do editor e ferramentas inovadoras como recomendação tag e formas de descrição flexÃveis faz com que o processo de publicação fácil e rápido."},"quote_15":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"abordagem de venda 3D de CGTrader é diferente e não tem nada em comum com outras lojas que eu costumava vender. Pagar uma baixa taxa de 5 $ após a venda é uma grande idéia e permita-me oferecer preços mais baixos aqui. Cliente e artista são beneficiados com esta forma de trabalhar."},"quote_16":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"O sistema de carregamento é fácil e clara. à bom saber que por trás do projeto são pessoas com anos de experiência em matéria gráficos de computador. Sempre que eu tinh
16518a um problema, a equipe CGTrader fixas rapidamente."},"quote_17":{"author":{"name":"Javier Almazor","username":"jvr3D"},"text":"CGTrader me permite ligar meu perfil com a minha página pessoal. Os clientes podem entrar em contato comigo, se eles não estão certos sobre uma caracterÃstica de um item que eles querem comprar ou apenas quer uma modificação do mesmo. à como possuir uma loja 3D pessoal em um grande mercado!"},"quote_2":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Temos tido uma grande e responsivo apoio da equipe CGTrader. A equipe gentilmente se ofereceu para fazer a publicação de todos os modelos para nós, o que é uma grande ajuda para os vendedores profissionais."},"quote_3":{"author":{"name":"Juan Carlos Jiménez","username":"CGShape"},"text":"Nesta plataforma, podemos oferecer preços muito melhores para nossos clientes. Por exemplo todos os nossos produtos estão com preços 20% mais baixos do que em qualquer outro lugar e ainda obter mais lucros em comparação com outras lojas!"},"quote_4":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"Este é o melhor sistema para a data. Todas as outras lojas online 3D dar uma% de nossos lucros. Este foi o recurso que pegou nosso interesse em CGTrader desde o inÃcio. Clientes, compra on CGTrader, sabemos que a maior parte de seu dinheiro ir para o autor, que no final vai colocar mais e melhores modelos se os seus lucros melhorar."},"quote_5":{"author":{"name":"Jesús Pedrosa Vidal","username":"NoneCG"},"text":"CGTrader é a loja online 3D que tornou mais rápido crescimento de vendas e lucro para nós. O sistema de ativação de taxa fixa é o melhor que você pode encontrar, como ele recompensa os criadores de conteúdo em vez de intermediários."},"quote_6":{"author":{"name":"RiÄardas Marozas","username":"pumper"},"text":"Quando recebi US $ 160 para a minha conta Paypal, não sei o que está acontecendo como se nunca tivesse acontecido antes, mas depois pensei que poderia ser uma venda CGTrader e eu estava certo. Vendido o mesmo pacote em Turbosquid no mês passado por US $ 189, mas depois de 40% taxa de royalties e imposto de 30%, tudo o que tenho foi de US $ 52,92 - centavos em comparação com $ 160 de CGTrader. Além disso, o cliente pagamos US $ 29 menos - agora que é um bom negócio."},"quote_7":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"No começo eu estava cético sobre como um bom negócio para os vendedores que não é a norma para grandes 3D online lojas. Quando eu aprendi sobre o sistema de ativação de taxa fixa, fiquei impressionado com a forma tão criativa de vender ativos digitais. Sell, em seguida, ativar, pagando uma taxa de US $ 5. Tudo faz sentido para mim. Fiz upload de alguns para experimentar e realmente, quando eu tenho a minha primeira venda, que foi de 100% a realeza!"},"quote_8":{"author":{"name":"Threed Ken","username":"3DKen"}
16518,"text":"Eu estava tão acostumado a muitos outros sites que cobram entre 30% - 60% de comissão até que eu descobri CGTrader. Como um vendedor, eu definitivamente como a alta porcentagem de royalties retornos."},"quote_9":{"author":{"name":"Threed Ken","username":"3DKen"},"text":"A experiência vendedor é fantástico. submissão do produto é uma brisa. E sim, o sistema me permitiu salvar um rascunho da minha submissão produto a cada etapa do caminho."}}},"hyperwallet":{"failed_payment_agreement":"Algo inesperado aconteceu","success_notification":"O acordo de pagamento foi atualizado com sucesso.","success_payment_agreement":"O acordo de pagamento foi enviado com sucesso."},"item-search-filters":{"3d-models-url":"3d-modelos","3d-print-models-url":"3d-impressao-modelos","dedicated-search-page-url":{"animated":"/animado-","free":"/livre-","low_poly":"/de-baixo-poli-","pbr":"/pbr-","rigged":"/fraudada-"}},"item_use_case":{"not_valid":"Arquivo inválido","pundit":{"not_authorized":"Você não está autorizado a executar esta ação."},"title":"Caso de uso para %{item_name}"},"items":{"already_purchased":"Você já comprou este item.","filters":{"attributes":"Atributos","free":"Livre","max_value":"$ 500 +","min_value":"$ 2","reset":"filtros de reposição"},"footer":{"next":"Próximo","per_page":"Por página:","previous":"Anterior"},"geometry_type_forbidden":"Tipo de geometria proibido!","last_card":{"button_text":"Pedir um modelo personalizado 3D","text":"Não foi possÃvel encontrar o que você está procurando?"},"migrations":{"errors":{"invalid_owner":"O novo proprietário não pode assumir os itens.","unpublished_items":"Todos os itens devem ser publicados."}},"new_price_applied":"Os novos preços foram aplicados com sucesso a todos os itens.","new_price_applied_to_selected_items":"Os novos preços foram aplicados com sucesso aos itens selecionados.","new_prices_to_filtered_models":"Os novos preços foram aplicados com sucesso a todos os itens filtrados.","order_processed":"Pedido processado.","order_processing":"Processando pedido.","something_went_wrong":"Algo deu errado","title_error":"O tÃtulo não deve conter sÃmbolos não latinos","uniq_user":"já enviou um caso de uso para este item","upload_error":"Erro de upload.","validate_license_for_zero_price":"não é válido para item gratuito","validate_minimum_price":"As ofertas de preço não devem ser inferiores a 50% do preço original","verify_printable_formats_error":"Por favor, envie pelo menos um arquivo .stl, .obj ou .wrl.","you_can_not_delete_models":"Você não pode excluir modelos"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"O 3D Projects facilita a contratação de artistas 3D freelancers de qualidade e ajuda você a resolver todos os desafios de modelagem.","heading_html":"Conheça a melhor plataforma de freelancers para seus \u003cstrong\u003etrabalhos de modelagem 3D\u003c/strong\u003e"},"sections":{"call_to_action":{"description":"Publique seu projeto gratuitamente e veja como é fácil resolver seu próximo desafio de modelagem com Projetos 3D.","title":"Contrate os melhores talentos 3D hoje mesmo!"},"freelancer_selection":{"title":"Faça do seu próximo projeto 3D um sucesso","widest_selection":{"description":"Não se contente com menos. Com 40.000 designers 3D freelancers, a CGTrader é a maior plataforma para conectar você com especialistas qualificados: modeladores, animadores, riggers, profissionais de impressão 3D e muito mais.","title":"A maior seleção de freelancers 3D"}},"how_it_works":{"steps":{"describe":{"description":"Diga-nos o que você precisa. Use nosso formulário simples, adicione imagens e publique sua oferta freelance em minutos.","title":"Descreva seu projeto"},"pay":{"description":"Pague o orçamento antecipadamente com segurança à CGTrader e informe seu freelancer que você está pronto para começar. Converse, compartilhe anexos e acompanhe o progresso do projeto convenientemente no seu espaço de trabalho. Libere o pagamento quando estiver satisfeito com o resultado final.","title":"Pague pelo resultado"},"select":{"bullets":["Receba orçamentos de designers qualificados diretamente na sua caixa de entrada","Converse em tempo real com os designers","Navegue pelos projetos anteriores deles","Você também pode pesquisar, filtrar e convidar freelancers de acordo com habilidades 3D, avaliações e preferências de softw
16518are ou formato"],"title":"Selecione o melhor freelancer"}},"title":"Conclua seu trabalho em 3 etapas simples"},"payment_quality":{"description":"A CGTrader garante que os serviços freelancers atenderão aos seus requisitos e serão entregues no prazo. Nossa equipe de QA está disponÃvel sempre que necessário.","title":"Qualidade garantida"},"secure_payments":{"description":"Nosso serviço de custódia garante que seus fundos estejam protegidos e que você só pague quando estiver satisfeito com o resultado final.","title":"Pagamentos seguros"},"workspace_convenience":{"description":"Esqueça a frustração de alternar entre abas e diferentes ferramentas. Com o espaço de trabalho dedicado, você pode gerenciar tudo em um só lugar: múltiplos projetos, faturas, conversas, compartilhamento de arquivos e muito mais.","title":"Conveniência em uma única tela"}},"shared":{"post_project_cta":"Publicar um projeto"}},"navigation":{"find_jobs_cta":"Encontrar trabalhos 3D","hire_freelancers_cta":"Contratar freelancers 3D","how_it_works":"Como funciona","why_projects":"Por que Projetos 3D"}},"agreed_to_terms_of_use":"Você deve concordar com os Termos e Condições do 3D Projects para continuar.","budget_error_message":"é muito alto","check_designer_uniqueness_error":"O designer só pode ser convidado uma vez","check_ownership_error":"O convidador não é o proprietário do projeto","check_status_error":"Designers só podem ser convidados para projetos aprovados.","deadline_error_message":"O prazo deve estar no futuro","discount_code_error":"Desculpe, o código de desconto não existe ou expirou.","email_subject":"Oportunidade de projeto 3D: %{subject}","error_check_application_uniqueness":"Você só pode se candidatar uma vez","error_check_applier":"Você não pode se candidatar ao seu próprio projeto 3D","error_check_job_availability":"Usuário não autorizado a se candidatar","error_check_job_status":"As candidaturas a projetos estão suspensas até a conclusão do nosso novo processo de moderação, geralmente em até 3 dias úteis. Agradecemos sua compreensão!","modeling_request_failed":"Falha na solicitação de modelagem!","offer_has_been_sent":"Obrigado, sua oferta foi enviada!","offer_is_closed":"A oferta está encerrada.","payment_successful":"Pagamento realizado com sucesso.","payment_under_review":"O pagamento está em revisão.","share_with_yourself_error":"Não é permitido compartilhar modelos de Contrate-me consigo mesmo","system_messages":{"buyer_cancels_job":"O projeto foi cancelado e movido para a aba %{archive_url}.","buyer_edits_hire_me_template":"Os detalhes do projeto foram atualizados pelo cliente.","buyer_edits_job_details":"Os detalhes do projeto foram atualizados.","buyer_marks_job_as_finished":"O projeto foi marcado como concluÃdo e movido para a aba %{archive_url}.","buyer_marks_job_as_finished_with_resell":"O cliente marcou o projeto como concluÃdo e permitiu que você vendesse os resultados no CGTrader. Certifique-se de \u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003eenviar\u003c/a\u003e\u003c/b\u003e o modelo criado!","buyer_negotiates":"O cliente negociou sua oferta de preço.","buyer_pays_for_the_job":"O projeto foi pré-pago e movido para a aba %{in_progress_url}.","designer_accepts_changes":"O designer revisou os detalhes atualizados.","designer_accepts_offer":"O designer aceitou sua oferta.","designer_edits_offer":"O designer editou sua oferta.","designer_negotiates":"O designer negociou sua oferta.","designer_withdraws_offer":"O designer retirou sua oferta.","job_expires":"O projeto expirou e foi movido para a aba %{archive_url}."},"template_error":"Nenhum projeto foi criado!","user_not_exists":"Usuário com esse nome de usuário não existe.","want_that_job":"Eu quero este trabalho!"},"kodama":{"invalid_request":"Solicitação inválida!"},"landing":{"consent_not_saved":"O consentimento não foi salvo","failure_notification":"Todos os campos obrigatórios da solicitação de acesso à API devem ser válidos.","success_notification":"Obrigado pela sua solicitação. Entraremos em contato em breve."},"layout":{"chunk_load_notice":"Algo deu errado ao carregar esta página. Por favor, atualize-a.","cookies_policy":{"accept":"Aceitar","learn_more":"Saber mais","text":"Nossos utilizações do website cookies para coletar dados de visitantes estatÃstica e interação pista com comunicação de marketing direto / melhorar o nosso website e melhorar a sua experiência de navegação. Por favor, consulte o nosso Aviso de cookie para obter mais informações sobre cookies, dados que eles coletam, que podem acessá-los, e os seus direitos."},"translations_notice":{"cta":"Troque para English","text":"Olá! Estamos traduzindo CGTrader. As traduções estão em andamento e algumas seções podem não estar disponÃveis em português."}},"model":{"already_purchased":"Você já comprou este produto. Você pode baixá-lo no seu \u003ca href='/profile/cart/purchased'\u003ecarrinho de compras\u003c/a\u003e. Se desejar, pode comprá-lo novamente.","animated":"Animado","artist_profile":"Perfil do artista","author":"Autor","author_get_your_payment":"O autor receberá 100% do seu pagamento. A CGTrader permite que os artistas maximizem seus ganhos e sejam incentivados a vender conteúdo de alta qualidade.","author_products":"Mais produtos de \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e","authorised_seller":"Vendedor autorizado da CGTrader","authority":"Autoridade","breadcrumb":{"3d_models":"Modelos 3D","home":"InÃcio"},"bulk_download":{"download_all":"Baixar todos os arquivos","files_included":{"one":"%{count} arquivo incluÃdo","other":"%{count} arquivos incluÃdos"},"too_large":"Este modelo é grande demais para ser baixado como um único arquivo (mais de %{limit}). Por favor, baixe os arquivos individualmente."},"buy":"Comprar","cannot_download":"Apenas usuários com %{experience_needed} pontos de reputação podem baixar mais de %{models} modelos gratuitos. Saiba mais sobre nÃveis e reputação \u003ca href='%{reputation_url}' target='_blank'\u003eaqui\u003c/a\u003e.","collection":"pack 3D","contact_author":"Contatar o autor","description":"Descrição","download":"Baixar","download_limit_exceeded":"Você excedeu seu limite diário de downloads. Por favor, tente novamente amanhã. Esse limite não se aplica a usuários que fizeram uma compra nos últimos 12 meses.","download_modal":{"chat_with_us":"Fale conosco","contact_support":"Entre em contato conosco pelo chat.","download_file":"Baixar %{name}","empty":"Nenhum arquivo encontrado","generic_error":"Algo deu errado, por favor tente novamente","link_error":"Pedimos desculpas, mas parece haver um pequeno problema com o seu link de download.","pbr_ready":"CompatÃvel com PBR","preparing":"Preparando seu download...","title":"Baixar arquivos"}
16518,"format_downloads":"Downloads de formato de software 3D","game_ready":"Pronto para jogos (lowpoly)","geometry":"Geometria","license":"Licença","make_offer":"Fazer oferta","materials":"Materiais","messages":{"no_files":"Nenhum arquivo enviado","no_rating":"Ainda não há avaliações disponÃveis para este modelo"},"model_details":"Detalhes do modelo 3D","pbr_textures":"Texturas PBR","plugin_used":"Plugin usado","polygons":"PolÃgonos","price":"Preço","print_ready":"Pronto para impressão 3D","product_id":"ID do produto","product_support":"Suporte do produto","product_type":"Tipo de produto","published":"Publicado em","rated":{"error":"Você já avaliou este modelo","success":"Obrigado por avaliar este modelo"},"rating":"Avaliação do modelo 3D","ratings":{"desc":{"negative":"Usuários que compraram este modelo 3D acham que tem qualidade inferior à esperada","positive":"Usuários que compraram este modelo 3D acham que é de boa qualidade"},"negative":"negativo","positive":"positivo"},"recently_viewed_models":"Modelos visualizados recentemente","renderer":"Renderizador","report":"Denunciar","rigged":"Rigado","scripts-plugins":"Scripts e Plugins","similar_models":"Modelos semelhantes","statistics":"EstatÃsticas","subscription":{"limit_reached":"Você atingiu o limite de downloads para este perÃodo de cobrança.","limit_reached_detailed":"Você atingiu seu limite de %{limit} downloads deste mês. Seu limite é redefinido em %{reset_date}. Para baixar mais modelos agora, você pode comprá-los individualmente.","limit_reached_detailed_no_date":"Você atingiu seu limite de %{limit} downloads deste mês. Para baixar mais modelos agora, você pode comprá-los individualmente."},"tags":"Tags","textures":"Texturas","title":"%{item_title} modelo 3D","unwrapped_uvs":"UVs desdobradas","uv_mapping":"Mapeamento UV","vat_notice":"Todos os preços são exclusivos de IVA","version":"Versão","vertices":"Vértices","vr":"Modelos VR"},"models":{"error":{"cannot_be_blank":" não pode estar em branco."}},"navigation":{"3d-models":{"3d-printing":"Arquivos de impressão 3D","discounts":"Descontos","find_designers":"Encontrar melhores designers","free":"Modelos livre 3D","pbr":"PBR","scanned_3d-models":"Modelos digitalizados 3D","scripts_apps":"Scripts e Aplicativos","show-all":"Mostre tudo","textures":"Texturas","title":"Modelos 3D","vr_low-poly":"VR / Baixa-poli"},"already_added_message":"Já foi adicionado ao carrinho","already_purchased_message":"Você já comprou este item.","aria":{"account":"Conta","cart":"Carrinho","close_menu":"Fechar menu","logo":"CGTrader - Modelos 3D / Designers 3D","messages":"Mensagens","notifications":"Notificações","open_menu":"Abrir menu","search":"Buscar","search_by_image":"Buscar por imagem"},"budgets":{"below_10":"Abaixo de $10","collections":"Pacotes","free":"Grátis","more_than_20":"Mais de $20","more_than_50":"Mais de $50","sale":"Em Oferta","subscription":"Assinatura"},"cart_limit_reached":"Você atingiu o limite de 500 itens no seu carrinho. Para continuar comprando, por favor, complete seu pedido atual e inicie um novo para qualquer item adicional.","cart_widget":{"continue_shopping":"Continuar comprando","discount":"Desconto com cupom empresa: ","discount_applied":"Descontos aplicados:","final":"Preço final: ","have":"Você tem ","items":" itens no seu carrinho de compras.","left_to_unlock_discounts":"Faltam {{leftToUnlock}} para desbloquear descontos","potential_discount":"Desconto potencial:","proceed":"Fazer o check-out","recently_viewed_empty_text":"Comece a explorar e seus itens vistos recentemente aparecerão aqui.","recently_viewed_empty_title":"Nada aqui ainda","recently_viewed_tab":"Vistos recentemente","remainer":"Para ativar os pontos de CGTrader, adicione: ","sale_discounts":"Descontos aplicados: ","sale_time_left":"Tempo restante para a venda","sale_tooltip":"Os descontos das nossas campanhas de promoção só são aplicados quando o seu carrinho atinge ${{threshold}} ou mais.","sale_tooltip_text":"Este item está em promoção, mas o desconto só será aplicad
16518o quando o subtotal do seu carrinho atingir ${{threshold}} ou mais.","text":"Seu carrinho de compras está vazio.","title":"Carrinho de compras","total":"Total: ","used":"Créditos utilizados: ","view":" Ver carrinho","wishlist_empty_text":"Comece a explorar e salve seus favoritos para mais tarde â eles aparecerão aqui.","wishlist_empty_title":"Sua lista de desejos está vazia","wishlist_tab":"Lista de desejos"},"community":{"awards":"Prêmios de Designers ð","blog":"Blog","challenges":"Desafios","community_ratings":"Classificações da comunidade","designers":"Designers 3D","digital_art":"Concurso de Arte Digital","forum":"Fórum","galleries":"Galerias","invite":"Convidar um amigo","printlist":"3D imprimeLista","sell_3d-models":"Vender modelos 3D","title":"Comunidade","tutorials":"Tutoriais"},"conversations_widget":{"conversations":"conversações","messages":{"loading":"Carregando caixa de entrada"},"types":{"cgtrader_support":"Suporte CGTrader","file_conversion_request":"pedido de conversão de arquivos","job_application":"Projeto 3D","model_feedback":"Product feedback","model_support":"Suporte modelo","offer":"Oferta de preço","personal":"Mensagem pessoal","promotions":"promoções"}},"create_ai":{"community_gallery":"Galeria da comunidade","free_trial":"Teste gratuito","generate_3d_model":"Gerar modelo 3D","generation":{"dismiss":"Dispensar notificação","error_title":"Problema na geração","generating_title":"Seu modelo 3D está sendo gerado","open_model":"Abrir modelo","ready_title":"Seu modelo 3D está pronto!"}},"create_with_ai":"Criar com IA","credits_guest_widget":{"create":"Crie uma conta agora!","discount":" desconto","for":" Para o seu ","get":" e chegar até a ","learn_more":"Saiba mais sobre créditos Fidelidade CGTrader ","link":"aqui","purchase":"primeira compra!","sign-up":"inscrever-se","text_below_1":"Os créditos podem ser usados ââna compra \"","text_below_2":"\"Assinar modelos marcados e cobrir até 30% de desconto do preço."},"credits_user_widget":{"condition_1":"Os pontos CGTrader podem ser aplicados na compra de modelos marcados com o sÃmbolo \u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e, proporcionando até 30% de desconto no preço.","condition_2":"Os pontos só podem ser usados se o valor total do seu carrinho for de \u003cstrong\u003e$%{minimum}\u003c/strong\u003e ou mais.","condition_3":"Durante promoções ou vendas ativas, os pontos não podem ser usados.","condition_4":"Lembre-se de que os pontos têm uma data de validade - seus pontos expirarão em \u003cstrong\u003e%{days}\u003c/strong\u003e dias.","earn_rate":"Crédito ganhar taxa ","first_text_1":"Considere isso como um presente para sua primeira compra - você pode usar créditos ao comprar \"","first_text_2":" \"Os modelos marcados e obter até 30% de desconto de seu preço. Credits só podem ser utilizados se o valor total de seu carrinho for igual ou superior a US","important":"IMPORTANTE:","learn_more":"Saber mais","lifetime_spending":"Gastos Lifetime: ","list_item":"Ao aumentar seus gastos vida na CGTrader, o seu crédito ganhar aumentos da taxa também.","message":" Os créditos não podem ser usados ââdurante as campanhas venda, mas você ainda pode aumentar seu nÃvel de royalties e recolher mais créditos para a sua próxima compra.","more_credits":"Como faço para obter mais créditos?","next_level":"Próximo nÃvel: ","notice":"AVISO: Os pontos CGTrader não podem ser usados durante a venda em andamento, mas estarão disponÃveis novamente assim que a venda terminar. Enquanto isso, confira ótimas ofertas em modelos 3D \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003eaqui\u003c/a\u003e","par_1":"Você tem ","par_2":" créditos CGTrader.","par_2_variation":" em pontos que você pode gastar quando nenhuma promoção estiver disponÃvel.","regular_text_1":"Os créditos podem ser usados ââna compra \"","regular_text_2":" \"Assinar modelos marcados e cobrir até 30% de desconto de seu preço.","title":"CGTrader desconto de fidelidade"},"enterprise":{"management":"Gerenciamento de ativos 3D","title":"Produção de Conteúdo 3D"},"hire_a_freelancer":"Contratar freelancer","item_add_message":"Com sucesso, foi adicionado ao carrinho","item_restricted_message":"Este item não pode ser comprado devido a sanções impostas ao paÃs do designer (RU/BY).","navbar":{"actions":{"new":"Novos","top_selling":"Mais vendidos","trending":"Em alta"},"budgets":{"below_10":"Abaixo de $10","free":"Grátis","more_than_20":"Mais de $20","more_than_50":"Mais de $50","sale":"Em Oferta","up_to_10":"Até $10"}},"projects":{"3d_customs":"3D personalizado","3d_printing":"Impressão 3D","about":"Sobre Projetos 3D","browse":"Procurar Projetos","buyer_perspective":"Contratar designers 3D","for_designers":"Para designers","my_projects":"Meus projetos","seller_perspective":"Projetos 3D Freelance","start":"Iniciar Um Projeto","work":"Trabalho Com Cgtrader"},"sell_3d-models":"Vender modelos 3D","sellers_hub":"Central do vendedor","subscription_includes_item_message":"Este item já está incluÃdo na sua assinatura.","tooltips":{"cart":"Carrinho de compras","conversations":"Minhas conversas","discounts":"CGTrader desconto de fidelidade","notifications":"Notificações","publisher":"Editor"},"user":{"ban_notification":"Esta conta de usuário está suspensa. Entre em contato com nosso suporte para obter uma explicação.","cannot_refer_yourself":"você não pode se indicar a si mesmo","email_confirmation":"Seu endereço de e-mail foi verificado.","email_reconfirmation":"já foi confirmado, por favor tente fazer login","ends_at":"Termina em: %{date}","handle_error_tfa_code_missmatch":"O código de segurança que você digitou está incorreto. Por favor, tente novamente.","handle_error_tfa_code_missmatch_last":"Seu código de segurança expirou. Se quiser continuar, clique em reenviar e-mail e insira o
16518novo código fornecido.","handle_error_tfa_default":"Algo deu errado, por favor tente novamente mais tarde.","handle_error_tfa_expired":"Seu código de segurança expirou.","hundred_percent_royalties_popover":"Você está participando de uma campanha temporária de 100% de ganhos: toda a receita das vendas de novos modelos será sua até o final da campanha","invalid_email_message":"Por favor, insira um endereço de e-mail válido para continuar.","login":"Conecte-se","meta_description":"Confira o perfil de designer 3D %{username} na CGTrader, seu portfólio e modelos 3D disponÃveis. Descubra os melhores modelos 3D dos principais artistas de modelagem da indústria.","meta_title_suffix":"Designer 3D","not_valid_birthday":"A data de nascimento não é válida.","offline":"Offline","online":"Online","page_title":"Perfil do designer","rate_models_limit":"Você não pode avaliar mais modelos hoje.","semantic_description":"Modelos 3D, obras e portfólio do designer. Confira suas criações na CGTrader","semantic_title":"Perfil do designer","session_failure":"Nome de usuário/e-mail ou senha incorretos","session_password_expired":"Sua senha expirou devido à inatividade. Redefina sua senha pelo link enviado ao seu e-mail.","session_two_fa_failure":"Falha na verificação do código","session_unconfirmed":"Seu endereço de e-mail ainda não foi confirmado.","token_not_recognized":"O token não foi reconhecido","twitter_shareable_text":"Um #3dartist que vale a pena seguir","username_error":"não deve conter espaços ou sÃmbolos não latinos"},"user_menu":{"buyer":{"freelancers":"Encontrar Freelancers","purchases":"Minhas compras","sell":"Vender modelos 3D","wishlist":"Modelo 3D Lista de Desejos"},"dashboard":"Admin dashboard","logout":"Sair","public_profile":"Perfil público","seller":{"analytics":"AnalÃtica","find_new_projects":"Encontrar novos projetos 3D","freelance":"Projetos 3D Freelance","freelance_cgtrader":"Freelance com CGTrader","models":"Meus modelos","publish_project":"Publicar um projeto","publishing":"Editor","sales":"Minhas vendas","subscription":"Assinatura","wishlist":"Modelo 3D Lista de Desejos"},"settings":"Configurações"}},"owly":{"failed_set_pending":"Falha ao definir como pendente.","failed_to_approve":"Falha ao aprovar.","failed_to_suspend":"Falha ao suspender.","failed_to_update_license":"Falha ao atualizar a licença.","failed_to_update_status":"Falha ao atualizar o status de aprovação."},"print_models":{"browse_all_makes":"Navegar por todos os Criações 3D","browse_all_models":"Navegar por todos os modelos","description":"Descubra modelos 3D prontos para impressão, assets imprimÃveis e arquivos STL para jogos, arte, projetos domésticos e muito mais.","makes_description":"Explore as mais recentes Criações 3D enviadas pela comunidade â exemplos reais que mostram como os modelos 3D ficam no mundo fÃsico.","makes_title":"Novas Criações 3D","new_description":"Confira as impressões 3D mais recentes adicionadas à nossa coleção â designs frescos prontos para baixar e imprimir em seu próximo projeto.","new_title":"Novos modelos 3D para impressão","title":"Modelos 3D de impressão em alta"},"profile":{"account_settings":{"account":{"email":"E-mail","submit":"Salvar","title":"Perfil","update":{"updated":"Perfil atualizado"},"username":"Nome de Usuário"},"email_settings":{"descriptions":{"ai_studio_notifications":"Notificações sobre suas gerações do CGTrader AI, incluindo quando um modelo que você ainda não abriu está pronto","communication":"Informações sobre sua comunicação com outros usuários da CGTrader, incluindo mensagens pessoais, novas ofertas de preço e trabalhos personalizados, feedback e solicitações de suporte a produtos","news":"Informações sobre produtos CGTrader, anúncios de novos recursos e notÃcias da comunidade","onboarding_and_edu":"Informações sobre seu processo de integração e dicas para ajudá-lo a aproveitar ao máximo a CGTrader","push_notifications":"Notificações sobre atividades e atualizações importantes da conta","sales_and_offers":"Informações sobre ofertas especiais, vendas de modelos 3D e créditos bônus CGTrader","seller_sold_item":"Informações sobre seus modelos 3D vendidos e pagamentos recebidos"},"privacy_policy_html":"Por favor, leia nossa \u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003ePolÃtica de Privacidade\u003c/a\u003e para mais informações. ","t
16518itles":{"ai_studio_notifications":"Notificações do CGTrader AI","communication":"Comunicação (Mensagens pessoais, feedback de modelos 3D, atividade da comunidade, ofertas)","news":"NotÃcias 3D / Atualizações CGTrader","onboarding_and_edu":"Onboarding \u0026 Educação","push_notifications":"Notificações Push","sales_and_offers":"Vendas \u0026 ofertas especiais","seller_sold_item":"Informações de Vendas \u0026 Pagamentos"},"tracking_attributes":{"ai_studio_notifications":"Notificações do CGTrader AI","communication":"Comunicação","news":"NotÃcias 3D / Atualizações CGTrader","onboarding_and_edu":"Onboarding \u0026 Educação","sales_and_offers":"Vendas \u0026 ofertas especiais","seller_sold_item":"Informações de Vendas \u0026 Pagamentos"},"update":{"updated":"Seu e-mail foi atualizado com sucesso."}},"gdpr_success_notification":{"opt_in":"Obrigado! Você se re-inscreveu com sucesso em nossos e-mails.","opt_out":"Você cancelou a inscrição de nossos boletins com sucesso. Você pode alterar esta preferência a qualquer momento visitando as configurações do seu perfil.\n"},"location_tooltip_text":"\u003cdiv\u003eEsta caixa de seleção permite mostrar a localização na página de Perfil.\u003c/div\u003e \u003cdiv\u003eObserve que, em qualquer caso, por razões de conformidade, sua localização será mostrada aos seus compradores (se você for um vendedor) e aos vendedores de quem você comprou.\u003c/div\u003e","moneybookers":{"account":"Conta Skrill"},"password":{"current_password":"Senha atual","new_password":"Nova senha","submit":"Alterar Senha","title":"Senha","updated":"Sua senha foi atualizada com sucesso. Agora você pode usar sua nova senha para fazer login.","verify_password":"Verificar senha"},"paypal":{"account":"Conta do PayPal","submit":"Salvar","title":"Configurações do PayPal","update":{"updated":"Suas configurações do PayPal foram atualizadas"}},"personal_info":{"areas_of_expertise":"Ãreas de Especialização","country":"PaÃs","description":"Algumas frases sobre você","full_name":"Nome completo","languages":"Idiomas","preffered_tools":"Ferramentas Preferidas","submit":"Salvar","title":"Informações pessoais e profissionais","update":{"updated":"Suas informações foram atualizadas com sucesso"},"website":"Website"},"personalization":{"no_muted_title":"Nenhum designer silenciado","title":"Designers Silenciados","tooltip":"Os modelos 3D dos designers listados são excluÃdos dos seus resultados de pesquisa.","unmute_designer":{"confirm":"Você tem certeza?"}},"professional_info":{"allow_private_job_requests":"Os compradores poderão enviar solicitações de trabalho 3D personalizadas para você.","buyer_engagement_program_html":"Atraia mais clientes permitindo que eles comprem seus modelos com CGTrader Points. \u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003eMais informações\u003c/a\u003e\n","pbr_program":"A taxa de ganho mais baixa é aplicada apenas quando o arquivo convertido é baixado","pbr_program_agreement":"Você concordou em participar do programa PBR por 24 meses em %{date}. Veja os Termos \u0026 Condições para mais detalhes. Por favor, entre em contato com nosso suporte caso tenha dúvidas.","product_analytics_participation_html":"Eu participo de \u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eAnalytics\u003c/a\u003e e concordo com seus Termos e Condições\n","product_analytics_participation_tooltip_html":"Você concordou em participar do Analytics e aceitou os Termos e Condições do Analytics (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003elink\u003c/a\u003e) em %{accepted_at}. Se você deseja encerrar sua participação, entre em contato com o suporte da CGTrader\n"},"security":{"allow_mfa":"Ative a verificação em 2 etapas para proteger sua conta","use_authenticator_app":"Use um aplicativo autenticador para a verificação em 2 etapas","use_authenticator_app_tooltip":"Digitalize o código QR com seu aplicativo autenticador (Google Authenticator / Authy) para gerar códigos de verificação.","use_email":"Use e-mail para a verificação em 2 etapas"},"sidebar":{"general_settigns":"Configurações Gerais","member_since":"Membro Desde","paypal":"PayPal","title":"Informações da Conta"},"title":"Minha Conta"},"conversations":{"conversations":"conversações","messages":{"loading":"Carregando caixa de entrada"},"types":{"cgtrader_support":"Suporte CGTrader","file_conversion_request":"pedido de conversão de arquivos","job_application":"Projeto 3D","model_feedback":"Product feedback","model_support":"Suporte modelo","offer":"Oferta de preço","personal":"Mensagem pessoal","promotions":"promoções"}},"meta":{"description":"Explore modelos 3D de alta qualidade de %{username} no CGTrader. Navegue por ativos exclusivos para jogos, VR/AR e visualização.","title":"Designer de modelos 3D: %{username}"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"Suas configurações foram atualizadas com sucesso."},"publishing":{"banned_error":"A sua conta foi banida por publicar conteúdo spam. Se acredita que isto é um erro, por favor contacte [email protected].","files_not_finalized":"Um ou mais ficheiros não terminaram de carregar e não podem ser publicados. Remova-os e carregue-os novamente antes de publicar.","spam_suspect":"A sua conta não está autorizada a publicar este modelo. Se acredita que isto é um erro, por favor contacte [email protected]."},"rating":{"anonymous_buyer":"Comprador Anônimo","errors":{"not_verified_buyer":"Apenas compradores verificados podem deixar uma avaliação"}},"routes":{"3d-models":"3d-modelos","3d-print-models":"3d-impressão-modelos","animated-3d-models":"animado-3d-modelos","controllers":{"three_d_studio":{"3d-models":"3d-models","images":"images"}},"discover":"descobrir","free-3d-models":"livre-3d-modelos","free-3d-print-models":"livre-3d-impressão-modelos","low-poly-3d-models":"de-baixo-poli-3d-modelos","pbr-3d-models":"pbr-3d-modelos","pbr-textures":"pbr-textures","rigged-3d-models":"fraudada-3d-modelos","search":"search"},"sale_off":{"no_overlapping_campaigns":"As datas da campanha se sobrepõem a outra campanha de venda existente.","parse_discount_rules_text":"A linha #{index} não contém o parâmetro obrigatório 'discount:'"},"search":{"not_found":"Assinatura de pesquisa não encontrada","subscription_created":"Assinatura de pesquisa criada","successfully_unsubscribed":"Você cancelou a assinatura de pesquisa com sucesso"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"flash":{"active_subscription":"Você já tem uma assinatura ativa.","premium_upgrade_unavailable":"A atualização para Premium está temporariamente indisponÃvel. Tente novamente mais tarde.","update_payment_method":"Sua assinatura tem um problema de pagamento. Atualize sua forma de pagamento em vez de comprar uma nova assinatura."},"payment_form":{"current_price":"%{price}","features":{"first":"%{downloads} recursos / mês â baixe modelos ou gere com IA","second":"Acesso instantâneo a mais de %{models_count} modelos 3D essenciais","third":"Livre de royalties, sem IA"},"from_price_label":"a partir de","original_price":24.99,"per_model_label":"por modelo","plan_name":"Assinatura CGTrader Essentials â plano anual, cobrado mensalmente","premium":{"features":{"first":"%{downloads} recursos / mês â baixe modelos ou gere com IA","fourth":"Livre de royalties, sem IA","second":"Acesso instantâneo a mais de %{models_count} modelos acessÃveis no total","third":"Modelos de nÃvel profissional não incluÃdos no Essentials"},"plan_name":"Assinatura CGTrader Premium â plano anual, cobrado mensalmente"},"price_unit":"/mês","vat_amount":"%{vat_amount}"}},"tag":{"description":{"bottle":"Os cientistas dizem que garrafa de vinho por dia não é ruim para você, mas quando se trata de bebidas mais fortes, como uÃsque ou bourbon, devemos realmente prestar atenção a nossa ingestão de álcool. Obviamente, uma taça de champanhe no refrigerador da maneira do bar parece que uma garrafa plástica de água, mas pensar sobre a possibilidade de viver uma vida mais longa e cerveja vai parecer um sacrifÃcio razoável. Esta categoria oferece uma vasta selecção de garrafa 3D modelos, que variam a partir de objectos relacionados com o álcool como cremalheiras do vinho e saca-rolhas para todos os tipos de garrafa modelos em 3D (a partir de champô para o azeite).","brain":"O cérebro é um dos órgãos maiores e mais complexas do corpo humano. Devido à sua estrutura e função complexa, a anatomia do cérebro também é muito complexo. No entanto, os cientistas aprofundar a arquitetura do cérebro humano, descobrindo segredos incompreensÃvel. Uma vasta gama de realistas e detalhados modelos 3D do cérebro que estão prontos para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D está disponÃvel para download.","building":"Não está claro onde arquitetos modernos se inspiram, mas alguns dos edifÃcios famosos do mundo são tão de vanguarda que eles se parecem com visões do futuro. E não me refiro apenas a parte exterior ... Em mãos capazes de Construção padrão se torna uma criação arquitetônica de tirar o fôlego com um inovador design interior, independentemente de se tratar de um escritório ou um edifÃcio urbano. Nossa selecção de construção de modelos 3D está pronto para download e pode ser aplicado em vários campos - animação 3D, design gráfico, publicidade, jogos 3D ou web.","camera":"Fotografia e filmagem é atualmente um dos mais campos de carreira populares entre os jovens, mas nem todo mundo com uma câmera profissional é um artista ou um fotógrafo. Com a qualidade de câmeras de telefones melhorando ano a ano, vemos pessoas tirar fotografias em cada passo e aqueles que têm a imagem recém-desenvolvida editar habilidades são verdadeiramente célebre. A vida parece um pouco diferente quando você está do outro lado da lente, mas não vamos deixar levar ... Uma vasta gama de câmera detalhada 3D modelos está disponÃvel para download para ser usado por designers gráficos, animação e desenvolvedores de jogos e profissionais que trabalham em outros campos relacionados com o 3D.","car":"Olhando para estes modelos muito detalhados e altamente realistas carro 3D, você pode quase ouvir o ronco do motor! Uma vasta gama de veÃculo 3D modelos pode tornar sua vida muito mais fácil, se você está lidando com computação gráfica, animação ou qualquer outro campo relacionado 3D.","cell":"Os cientistas estimam que o corpo humano contém entre 5 bilhões para 200 milhões de trilhões de células. Plantas e animais têm células também. Não quero aborrecê-lo com este material biologia, mas a vasta gama de modelos 3D de células que temos cobre tudo, desde o sangue, vÃrus e DNA de medula óssea e paredes celulares. Não é isso ... desesperador?","chair":"Tomamos sentados em cadeiras para concedido e nem sempre perceber o quanto charme eles podem adicionar à nossa casa ou escritório interior. Cadeira é realmente uma das peças centrais de móveis em todo o agregado familiar. Aqui você pode encontrar modelos 3D cadeira design apelativo que podem ser aplicados em vários campos de alta qualidade e - de publicidade e visualização 3D para jogos 3D.","city":"A vida da cidade é um jogo excêntrico: ruas repleta de táxis corrida, edifÃcios modernos, pedestres no escritório veste perfeitamente adaptados, dormindo pontes e parques ... de Xangai, para Nova Iorque (! Manhattan), a Londres ou Paris - cada cidade tem o seu própria magia. Você pode escolher a partir desta rica seleção de modelos em 3D da cidade detalhado que pode ser usado em um número de campos - publicidade, computação gráfica, animação, visualização 3D ou jogos. Explore a vida urbana.","dragon":"Dragão é provavelmente a criatura mais popular viver no mundo da fantasia. Ele tem destaque em tantos mitos de culturas diversas, animações, filmes e livros que se tornou lendária. à especialmente amado por desenvolvedores de jogos, como acrescenta o charme mágico para cavernas escuras e masmorras. Uma vasta gama de realista, equipou modelos dragão 3D que estão prontos para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D está disponÃvel para download.","earth":"O nÃvel de detalhe na vista de terra recentemente adicionados em mapas do Google chocou um número de pessoas. Você pode explorar todo o planeta - oceanos, montanhas e desertos, descobrir as cidades e estradas escondidas, sem sair de sua casa. Isso é algumas coisas incrÃveis Mãe Terra não tenha experimentado antes. Uma seleção de modelos 3D terra realistas que estão prontos para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D está disponÃvel para download.","engine":"Algumas pessoas são capazes de citar o motor simplesmente ouvir o som que faz, e que é verdadeiramente surpreendente. Independentemente de se tratar de um motor a jato ou um motor de carro, eles estão extremamente máquinas complicado que usamos com tanta frequência, mas não gastar muito tempo pensando sobre isso. Um motor é um motor (até que ele pára de funcionar). Esta categoria tem uma gama de diferentes tipos de motor 3D modelos, e também inclui peças de motor como hélice ou cilindro, por isso estamos confiantes de que você vai encontrar o que você precisa.","female":"Não é brincadeira que existem diferenças significativas entre o cérebro masculino e feminino, o que significa que é normal que um homem e uma mulher se comportam média, sentir e responder de maneiras completamente diferentes. Mas não é tudo sobre a anatomia. Sem história de amor, filme ou jogo de sempre puxou-lo sem um caráter forte menina, causa o poder de charme senhora é inegável. Uma rica selecção de realistas 3D modelos femininos pode oferecer-lhe tudo o que precisa - a partir de modelos 3D de nudez para as vias respiratórias feminino.","hand":"A razão que nós usamos nossas mãos para muitas coisas é a sua extraordinária anatomia. O polegar sozinho é controlado por nove músculos separados. à difÃcil de acreditar, mas os primeiros mãos eram mais exótico do que qualquer mão hoje - algumas espécies tinha sete dedos. O corpo humano evoluiu significativamente. Um braço ou uma mão como a vemos hoje parece em nada com suas primeiras versões. Uma vasta gama de realista, manipuladas mão modelos 3D que estão prontos para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D está disponÃvel para download.","head":"Na anatomia humana, a cabeça é a porção superior do corpo humano. Modelando uma cabeça humana 3D pode provar um pouco complicado, porque (ainda que há tantas formas e tamanhos diferentes) nós apreciamos, cabeças de apar
16518ência realista simétricas - há engraçados olhos, orelhas, nariz, lábios ou linha da mandÃbula, por favor. Rosto é uma área sensÃvel e que seria apenas a planÃcie rude para se divertir com isso. Nossa selecção engloba masculino realista, fêmea, criança e personagens da história até mesmo como Harry Potter e Batman ou celebridades como Tom Cruise e Scarlett Johansson cabeças que estão prontos para download.","helmet":"Lembre-se sempre que a saúde e a segurança vem em primeiro lugar, para proteger a sua cabeça é uma boa idéia. cavaleiros medievais, Daft Punk e até mesmo os capacetes desgaste Ironman, super-heróis tão regulares como os ciclistas ou os construtores não deve se preocupar sobre olhar uncool. Esta coleção de capacete 3D modelos que está disponÃvel para download será útil se você estiver trabalhando nas áreas de design gráfico, animação 3D, jogos 3D ou visualização.","house":"à uma verdade antiga que a casa de um homem é seu castelo, mas quando se trata de construir a casa perfeita ou comprar um apartamento ideal, nós tendemos a perder a cabeça sobre ele. Felizmente, este amplo espectro de modelos de casa em 3D que engloba tudo, desde detalhes arquitetônicos, interior e exterior, para móveis, irá ajudá-lo a criar modernos 3D visualizações para aliviar essa dor.","human":"Quando você começar a explorar a anatomia humana, você percebe que as pessoas são tão intrincada e máquinas complexas que leva o seu fôlego. Cada combinação parte do corpo, músculos, articulações, órgão ou osso está conectado em um único sistema, nada funciona isoladamente! Estes super-realistas modelos humanos 3D permitirá que você examinar as estruturas anatômicas de cada ângulo.","lamp":"Se você olhar em torno de sua casa e contar os tipos de lâmpadas que você possui, você ficará surpreso: leitura, mesa, parede, teto, mesa, tripé lâmpadas ... à o suficiente para fazer girar a cabeça! para não mencionar os estilos que eles vêm em - de lâmpadas modernas extravagantes para retro ou futurista elegante. Nesta categoria temos todos os tipos de lâmpada 3D modelos, assim navegar e baixar para usar em design gráfico, 3D visualizações ou qualquer outro campo relacionadas com 3D.","light":"Alguma vez você já se perguntou por que uma lâmpada é o sÃmbolo de uma idéia brilhante? Certamente, uma idéia brilhante pode iluminar a arquitetura da mente, mas não é isso. Uma luz de rua, um lustre ou qualquer outro tipo de lâmpada não teria a menor chance de tomar esse ponto. Se da próxima vez quando você olha para o teto e olhar para algum tipo de luz de arquitetura a idéia de gênio não bater em você, pode ser porque você está olhando para um sistema de iluminação errado ... Nossa selecção de luz de alta qualidade modelos 3D vai provar útil se você trabalhar nas áreas de arquitetura, computação gráfica, animação 3D ou design.","machine":"Imagine se todas as máquinas de repente parou de funcionar: no café, sem lavar roupa conveniente, há dinheiro pontos em uma esquina da rua, sem tempo de ginásio, não superfaturada máquinas de venda automática ... soa deprimente, não é? Estamos tão acostumados a esses eletrodomésticos e aparelhos eletrônicos que seria, literalmente, parar o giro mundo! Felizmente, a nossa selecção de máquina detalhado 3D modelos cobre tudo, desde metralhadoras a produtores de electricidade que serão úteis para os designers que trabalham com computação gráfica, publicidade, animação 3D, jogos 3D ou web.","man":"Uma vasta coleção de modelos 3D homem está disponÃvel para download. Homem de assento, homem simples, o homem voar ou homem médio, nós temos tudo - exceto que o homem perfeito que todos está atrás. Ele é um personagem suspeito e nós odiamos para trazer isto, mas pode ser um mito ... Mas hey, os seres humanos nascem para ser incrÃvel, não perfeito.","robot":"R2D2 é provavelmente o robô mais famoso do mundo, mas certamente não é o único. De industrial de brinquedo para robôs humanos, vemos uma escolha cada vez mais amplo dessas máquinas mecânicas, que é ao mesmo tempo maravilhoso e um pouco preocupante. Não é muito difÃcil entender as pessoas que insistem que os computadores, tecnologia, robôs estão fazendo um impacto muito significativo sobre os seres humanos. Uma vasta gama de realista, manipuladas robô modelos 3D que estão prontos para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D está disponÃvel para download.","ship":"Os navios são vasos poderosos e vêm em todos os tamanhos, cores e formas. Eles podem ser classificados como navios de carga, navios de guerra ou navios de passageiros, mas todos eles operam em águas de profundidade. Se você tem experimentado o desconforto da doença de movimento, pode não ser um de seus meios favoritos de transporte, mas muitas pessoas consideram passeios de barco como bastante elegante e agradável. Nossa selecção de modelos 3D navio está pronto para download e irá cumprir as normas de até mesmo o capitão mais exigente.","skeleton":"O esqueleto humano ou sistema esquelético (anatomia) é a estrutura interna do corpo que é composto por 270 ossos no nascimento. Ele proporciona a estrutura do corpo, e a protecção e o movimento é um dos mais complexos sistemas esquelético. Uma rica selecção de anatomicamente correto, realista e escalado esqueleto modelos 3D que são perfeitos para uso em animação 3D, design gráfico, publicidade, jogos 3D e web está disponÃvel para download.","skull":"O mais antigo mais completo crânio humano, geneticamente intacto foi descoberto rodeado por uma variedade de animais extintos mais de 40 metros abaixo do nÃvel do mar. à um dos esqueletos mais antigos encontrados no Novo Mundo e também inclui todos os principais ossos do corpo e um crânio intacto e conjunto de dentes. crânios humanos tornaram-se recentemente uma coisa na moda e design, mas quando você realmente dar-lhe algum pensamento, que tipo de make-nos a todos olhar como aberrações anatomia ... Esta categoria oferece uma ampla gama de modelos de crânio em 3D para ser usado em design gráfico , animação 3D, jogos 3D ou publicidade.","sofa":"Luxo ou simples, moderno ou antigo, couro ou design minimalista? Como você gosta do seu sofá? A gama de modelos sofá 3D que temos irá satisfazer até mesmo o pior perfeccionista. Quando você parar para pensar nisso, sofá é o centro de cada sala de estar, por isso você deve ser criativo ao escolher o design!","table":"As mais recentes tendências de mobiliário são tão diversos que escolher, uma mesa moda moderno está se tornando muito estressante. Costumava haver um tempo em que você tinha uma mesa de jantar simples para as suas festas modestas e isso era suficiente, mas hoje - a tabela é suposto ser uma declaração ou pelo menos um sotaque interior atraente. Esta seleção dá-lhe uma vasta gama de modelos de mesa 3D para atender a todos os caprichos.","tower":"Cada cidade tem uma torre especial que todo mundo é realmente motivo de orgulho. Pense torre Eiffel ou Torre de Pisa, ou torre da ponte de Londres, muito menos todos os modernos arranha-céus, prédios futuristas e da paisagem urbana que os turistas admiram. No entanto, quando se trata de peças industriais da cidade, água ou torres elétricas, todos tendem a voltar seus olhos para longe ... Mas devemos aprender a apreciar cada criação arquitectónica, não importa antiga, industrial ou moderno. A gama de modelos 3D torre detalhada estão disponÃveis para download e pronto para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D.","tree":"Se você está em uma missão para plantar algumas árvores ou plantas exóticas, você veio ao lugar certo. Esta categoria oferece uma gama de utilização fácil, muito realistas modelos de árvore 3D para artistas e arquitetos CG, que estão se esforçando para adicionar algumas hortaliças para os seus projectos. Se você aprecia boa qualidade, estamos confiantes de que essa seleção de modelos de planta árvore 3D vai atender à s suas normas!","truck":"Dirigindo um caminhão é uma tarefa difÃcil, especialmente se você precisa encontrar o seu caminho através de um congestionamento de tráfego da cidade. Independentemente de se tratar de um caminhão de bombeiros, caminhão de lixo, caminhão do alimento ou um genérico, é preciso uma grande habilidade de manobrar estes veÃculos gigantes. Estamos confiantes de que esta seleção de realistas, caminhão de alta qualidade 3D modelos são perfeitos para uso em animação 3D, design gráfico, publicidade ou qualquer outro campo 3D-relacionadas.","tv":"Costumava haver um momento em que lareira era a peça central de cada lar respeitável, agora aparelho de TV com jogadores e alto-falantes é o rei da sala de estar (e até mesmo o quarto). Nos últimos anos, a televisão tem pego com as mais recentes tecnologias. Como resultado, temos telas de TV 3D inteligente, planas e de plasma, milhões de novas funções e design touchscreen. Sem televisão maravilha está empurrando cinema fora do mercado. Uma vasta gama de, detalhados modelos realistas TV 3D que estão prontos para aplicações de computação gráfica como a publicidade, a visualização 3D, jogos 3D, web e qualquer outro domÃnio relacionado com o desenho em 3D está disponÃvel para download."}},"tag_promotion":{"days_left_error":"deve estar entre 1 e 30","no_other_pending_promotions_for_same_item_tag":"já possui uma promoção pendente"},"tooltips":{"buyer_loyalty_program_current_level_html":"Atualmente você gastou %{total_price_paid} no CGTrader e seu crédito ganhar taxa é de %{buyer_loyalty_rate}. \u003cbr/\u003e Isso significa que você terá %{buyer_loyalty_rate} dos créditos de cada compra.\n","buyer_loyalty_program_html":"Esta é a porcentagem de quanto você vai começar a partir de suas compras como novos créditos. \u003cbr/\u003e Ela vai aumentar até 30% de seus gastos de vida no aumento CGTrader. \u003cbr/\u003e Atualmente seu crédito ganhar taxa é de %{buyer_loyalty_rate}.\n","buyer_loyalty_program_next_level_html":"Próximo nÃvel %{next_lvl_expenses} irá aumentar o seu crédito ganhar taxa de até %{next_lvl_expenses_rate}. \u003cbr/\u003e você precisa comprar por US $ %{left_until_next_lvl} mais para chegar próximo nÃvel.\n"},"trending_headers":{"models":"Confira outros modelos 3D em alta","print":"Confira outros modelos 3D para impressão em alta"},"tutorial":{"destroy":"O tutorial foi excluÃdo com sucesso.","submit_for_review_error":"Por favor, preencha todos os campos obrigatórios.","submitted":"Obrigado por enviar seu tutorial. Ele será revisado e publicado em breve."},"valvat":{"country_adjectives":{"at":"austrÃaco","be":"belga","bg":"búlgaro","cy":"cipriota","cz":"checo","de":"alemão","dk":"dinamarquês","ee":"estónio","es":"espanhol","eu":"europeu","fi":"finlandês","fr":"francês","gb":"britânico","gr":"grego","hu":"húngaro","ie":"irlandês","it":"italiano","lt":"lituano","lu":"luxemburguês","lv":"letão","mt":"maltês","nl":"holandês","pl":"polaco","pt":"português","ro":"romeno","se":"sueco","si":"esloveno","sk":"eslovaco"}}},"ru":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"ÐзÑоÑлÑй или наÑилиÑ","ai_generated":"ÐонÑенÑ, ÑгенеÑиÑованнÑй ÐÐ","copyright":"ÐаÑÑÑение авÑоÑÑкого пÑава"}}},"errors":{"full_messages":{"format":"%{attribute} %{message}"},"messages":{"accepted":"нÑжно подÑвеÑдиÑÑ","blank":"не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÑÑÑм","confirmation":"не ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñо знаÑением Ð¿Ð¾Ð»Ñ %{attribute}","embedded_script":"ÐÑÐ¾Ñ Ñайл не поддеÑживаеÑÑÑ Ð¸ не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð·Ð°Ð³ÑÑжен. ÐопÑобÑйÑе дÑÑгой Ñайл.","empty":"не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÑÑÑм","equal_to":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð·Ð½Ð°Ñение, Ñавное %{count}","even":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ ÑеÑное знаÑение","exclusion":"Ð¸Ð¼ÐµÐµÑ Ð·Ð°ÑезеÑвиÑованное знаÑение","greater_than":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð·Ð½Ð°Ñение болÑÑе %{count}","greater_than_or_equal_to":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð·Ð½Ð°Ñение не менÑÑе %{count}","inclusion":"Ð¸Ð¼ÐµÐµÑ Ð½ÐµÐ¿ÑедÑÑмоÑÑенное знаÑение","invali
16518d":"Ð¸Ð¼ÐµÐµÑ Ð½ÐµÐ²ÐµÑное знаÑение","less_than":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð·Ð½Ð°Ñение менÑÑе %{count}","less_than_or_equal_to":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð·Ð½Ð°Ñение не болÑÑе %{count}","not_a_number":"не ÑвлÑеÑÑÑ ÑиÑлом","odd":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð½ÐµÑеÑное знаÑение","record_invalid":"Ðозникли оÑибки: %{errors}","restrict_dependent_destroy":{"has_many":"Ðевозможно ÑдалиÑÑ Ð·Ð°Ð¿Ð¸ÑÑ, Ñак как ÑÑÑеÑÑвÑÑÑ Ð·Ð°Ð²Ð¸ÑимоÑÑи: %{record}","has_one":"Ðевозможно ÑдалиÑÑ Ð·Ð°Ð¿Ð¸ÑÑ, Ñак как ÑÑÑеÑÑвÑÐµÑ Ð·Ð°Ð²Ð¸ÑимоÑÑÑ: %{record}"},"taken":"Ñже ÑÑÑеÑÑвÑеÑ","too_long":{"few":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимвола)","many":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимволов)","one":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимвол)","other":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимвола)"},"too_short":{"few":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимволов)","many":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимволов)","one":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимвола)","other":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимвола)"},"wrong_length":{"few":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимвола)","many":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимволов)","one":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимвол)","other":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимвола)"}},"models":null,"template":{"body":"ÐÑÐ¾Ð±Ð»ÐµÐ¼Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ»Ð¸ Ñо ÑледÑÑÑими полÑми:","header":{"few":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибок","many":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибок","one":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибки","other":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибки"}}}},"api":{"profile":{"actions":{"contact":"СвÑзаÑÑÑÑ","follow":"ÐодиÑаÑÑÑÑ","follow_tooltip":"Start following this designer to get updates about his content and easily filter favorite designers in Search results","hide":"СкÑÑÑÑ","hire_me":"ÐанÑÑÑ Ð¼ÐµÐ½Ñ","invite_client":"ÐаÑаÑÑ Ð¿ÑоекÑ","mute_tooltip":"Hide this designerâs models in the Search results","take_over":"Take over","unfollow":"ÐÑпиÑаÑÑÑÑ","unhide":"ÐоказаÑÑ","view_all_models":"View all Designer's Models"},"private_project_review":"Private Project"}},"browser":{"3d_models":"3д модели","3d_print":"3д-пеÑаÑÑ","active_filters":{"polygons":"%{range} полигонов"},"adult_content":"ÐоказаÑÑ ÐºÐ¾Ð½ÑÐµÐ½Ñ Ð´Ð»Ñ Ð²Ð·ÑоÑлÑÑ
","animated":"ÐнимиÑованнÑе","breadcrumb":{"browse_by_type":"ÐÑоÑмоÑÑ Ð¿Ð¾ ÑипÑ","collection":"3D-паки","free":"Ñвободно","free_models":"ÐеÑплаÑнÑе 3д модели","free_print_models":"Free 3д модели пеÑаÑи","low_poly":"низкополигоналÑнаÑ","low_poly_models":"VR / AR / низкополигоналÑÐ½Ð°Ñ 3д-модели","low_poly_print_models":"ÐизкополигоналÑнÑе ÑÐ°Ð¹Ð»Ñ 3д-пеÑаÑи","model_3d":"3д модели","model_3dp":"3д Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¿ÐµÑаÑи","models":"3д модели","models_3d":"3д модели","models_3dp":"Ðодели 3д пеÑаÑи","models_variant_0":"3D-модели","models_variant_1":"3D-аÑÑеÑÑ","models_variant_2":"VR-модели","models_variant_3":"CG-модели","models_variant_4":"ÐагаÐ
16518·Ð¸Ð½ 3D-моделей","models_variant_5":"3D-обÑекÑÑ","print_models":"Ð¤Ð°Ð¹Ð»Ñ 3д-пеÑаÑи","print_models_variant_0":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи","print_models_variant_1":"Ðодели Ð´Ð»Ñ 3D-пÑинÑеÑа","print_models_variant_10":"3D-модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","print_models_variant_11":"3D-модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","print_models_variant_12":"3D-ÑÐ°Ð¹Ð»Ñ Ð´Ð»Ñ Ð¿ÐµÑаÑи","print_models_variant_13":"Ðодели Ð´Ð»Ñ 3D-пÑинÑеÑа","print_models_variant_14":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи","print_models_variant_15":"Ðодели 3D-пеÑаÑи","print_models_variant_16":"ÐеÑаÑаемÑе 3D-ÑайлÑ","print_models_variant_2":"3D-модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","print_models_variant_3":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи","print_models_variant_4":"Ð¤Ð°Ð¹Ð»Ñ Ð´Ð»Ñ 3D-пеÑаÑи","print_models_variant_5":"Ð¤Ð°Ð¹Ð»Ñ Ð´Ð»Ñ 3D-пеÑаÑи","print_models_variant_6":"Ð¤Ð°Ð¹Ð»Ñ Ð´Ð»Ñ 3D-пÑинÑеÑа","print_models_variant_7":"ÐеÑаÑаемÑе 3D-модели","print_models_variant_8":"3D-модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","print_models_variant_9":"РаÑпеÑаÑаннÑе 3D-модели"},"buyer_engagement_program":"Скидки","categories":"ÐаÑегоÑии","category":{"meta":{"3d_models":"%{count} %{category} 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайла, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"СкаÑаÑÑ %{count} %{category} 3д модели пеÑаÑи, доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² STL, OBJ и дÑÑгие ÑоÑмаÑÑ Ñайлов, гоÑовÑÑ
к пеÑаÑи Ñ FDM, SLS и дÑÑгиÑ
3д пÑинÑеÑов.%{page}","animated_3d_models":"%{count} %{category} анимиÑованнÑе 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"СкаÑаÑÑ %{count} %{category} беÑплаÑнÑе 3д модели, доÑÑÑпнÑе в MAX, OBJ, FBX, 3DS, ÑоÑмаÑÑ Ñайлов C4D, гоÑовÑе к VR / AR, анимаÑии, Ð¸Ð³Ñ Ð¸ дÑÑгиÑ
3д-пÑоекÑов.%{page}","free_3d_print_models":"СкаÑаÑÑ %{count} %{category} беÑплаÑнÑе 3д модели пеÑаÑи гоÑовÑе Ð´Ð»Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
3д пÑинÑеÑÑ, доÑÑÑпнÑе ÑоÑмаÑÑ STL, OBJ, 3дM и многое дÑÑгое.%{page}","lowpoly_3d_models":"СкаÑаÑÑ %{count} VR / AR / низкополигоналÑÐ½Ð°Ñ %{category} 3д моделей, гоÑовÑÑ
к виÑÑÑалÑной ÑеалÑноÑÑи, Ð¸Ð³Ñ Ð¸ дÑÑгиÑ
пÑиложений ÑеалÑного вÑемени, имеÑÑиÑ
ÑÑ Ð² FBX, OBJ, MAX, 3DS, ÑоÑмаÑÑ Ñайлов C4D.%{page}","rigged_3d_models":"%{count} %{category} ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"collection":"3D-пак","discounts":"Скидки","ext":{"meta":{"3d_models":"СкаÑайÑе %{rounded_count} 3D моделей в ÑоÑмаÑе %{format_upper}: %{format_lower} модели ÑкаÑаÑÑ Ð±ÐµÑплаÑно или кÑпиÑÑ.","3d_print_models":"СкаÑаÑÑ %{count} %{ext} Ñайлов - %{software_name} 3д модели пеÑаÑи гоÑовÑе Ð´Ð»Ñ VR / AR, 3д дизайн, анимаÑиÑ, игÑÑ Ð¸ в Ñежиме ÑеалÑного вÑемени пÑиложений%{page}."}},"filter":"ФилÑÑÑ","filter_button":"ÐÑимениÑÑ ÑилÑÑÑÑ","filters":{"adult_content_only":"ТолÑко конÑÐµÐ½Ñ Ð´Ð»Ñ Ð²Ð·ÑоÑлÑÑ
","cgt_standard_only":"CGT Standard","collections_only":"ТолÑко набоÑÑ","content_filters":"ФилÑÑÑÑ ÐºÐ¾Ð½ÑенÑа","designer":"ÐизайнеÑ","exclude_3d_print":"ÐÑклÑÑиÑÑ 3D-пеÑаÑÑ","exclude_adult_content":"ÐÑклÑÑиÑÑ ÐºÐ¾Ð½ÑÐµÐ½Ñ Ð´Ð»Ñ Ð²Ð·ÑоÑлÑÑ
","exclude_ai_generated":"ÐÑклÑÑиÑÑ ÐºÐ¾Ð½ÑенÑ, ÑозданнÑй ÐÐ","exclude_editorial_license":"ÐÑклÑÑиÑÑ ÑедакÑионнÑе лиÑензии","exclude_free":"ÐÑклÑÑиÑÑ Ð±ÐµÑплаÑнÑе","file_format":"ФоÑмаÑÑ Ñайлов","following":"ÐодпиÑки","free":"ÐеÑплаÑно","has_marmoset":"С 3D-вÑÑвеÑом","has_video":"С видео","include_ai_generated":"ÐклÑÑаÑÑ ÐºÐ¾Ð½ÑенÑ, ÑозданнÑй ÐÐ","label":"ФилÑÑÑÑ","poly_count":"ÐолиÑеÑÑво полигонов","print_ready":"3д-пеÑаÑи","stl_files":"Ð¤Ð°Ð¹Ð»Ñ STL","subscription":"ÐодпиÑка","type":"Тип"},"formats":"ФоÑмаÑÑ","free":"ÐеÑплаÑно","free_models":"ÐоказаÑÑ ÑолÑко беÑплаÑнÑе модели","free_to_premium":{"main":"3D-модели %{category}","postfix":"в пÑемиÑм-лиÑÑинге.","prefix":"Ðам нÑжно ÑÑо-Ñо оÑобенное? ÐÑ Ð¼Ð¾Ð¶ÐµÑе найÑи лÑÑÑее каÑеÑÑво"},"gallery":{"preview":"пÑевÑÑ"},"game_ready":"ÐоÑовÑе Ð´Ð»Ñ Ð¸Ð³ÑовÑÑ
движков","high_poly":"ÐÑÑокополигоналÑнÑе","items_page_title":"3д модели","license":{"exclude_branded":"ÐÑклÑÑиÑÑ Ð±ÑендиÑованнÑе","exclude_editorial":"ÐÑклÑÑиÑÑ ÑедакÑионнÑе","prompt":"ÐиÑензиÑ","tooltip_more":"ЧиÑаÑÑ Ð´Ð°Ð»ÐµÐµ","tooltip_text":"Ðе показÑваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸, коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ ÑолÑко в некоммеÑÑеÑкиÑ
, обÑазоваÑелÑнÑÑ
ÑелÑÑ
.","tooltip_title":"ÐÑклÑÑиÑÑ ÑедакÑионнÑе:"},"low-poly":"ÐизкополигоналÑнÑе","low_poly":"ÐизкополигоналÑнÑе","meta":{"3d_models":"СкаÑайÑе или кÑпиÑе %{rounded_count} пÑоÑеÑÑионалÑнÑÑ
3D моделей. ÐеÑплаÑнÑе и плаÑнÑе 3д модели Ð´Ð»Ñ Ð¸Ð³Ñ, кино, VFX, AR/VR и 3D пеÑаÑи. FBX, OBJ, BLEND, GLB.","3d_print_models":"СкаÑайÑе %{rounded_count} моделей Ð´Ð»Ñ 3д пÑинÑеÑа. ÐеÑплаÑнÑе и плаÑнÑе STL модели Ð´Ð»Ñ 3D пеÑаÑи: ÑигÑÑки, миниаÑÑÑÑ, декоÑ, запÑаÑÑи.","animated_3d_models":"СкаÑайÑе %{rounded_count} 3D моделей Ñ Ð°Ð½Ð¸Ð¼Ð°Ñией. ÐоÑовÑе анимиÑованнÑе пеÑÑонажи и обÑекÑÑ Ð² FBX, BLEND, GLB.","free_3d_models":"СкаÑайÑе %{rounded_count} беÑплаÑнÑÑ
3D моделей. 3д модели беÑплаÑно в ÑоÑмаÑаÑ
FBX, OBJ, BLEND, GLB Ð´Ð»Ñ Ð²Ð°ÑиÑ
пÑоекÑов.","free_3d_print_models":"%{rounded_count} беÑплаÑнÑÑ
3д моделей Ð´Ð»Ñ Ð¿ÐµÑаÑи. СкаÑайÑе STL ÑÐ°Ð¹Ð»Ñ Ð´Ð»Ñ 3D пÑинÑеÑа беÑплаÑно: ÑигÑÑки, игÑÑÑки, полезнÑе веÑи.","lowpoly_3d_models":"СкаÑайÑе %{rounded_count} низкополигоналÑнÑÑ
(low poly) 3D моделей Ð´Ð»Ñ Ð¸Ð³Ñ, AR/VR и ÑендеÑа в ÑеалÑном вÑемени.","metaverse":"ÐведиÑе Metaverse Ñ Ð½Ð°Ñей коллекÑией вÑÑокиÑ
и низкополи-3D-моделей, ÑÑалÑÑиÑиÑиÑованнÑÑ
, анимиÑованнÑÑ
и доÑÑÑпнÑÑ
в лÑбом ÑоÑмаÑе Ñайлов.","omniverse":"СоздайÑе Ñвой виÑÑÑалÑнÑй Ð¼Ð¸Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð½Ð°ÑиÑ
3D-моделей, гоÑовÑÑ
к вÑемÑ,. ÐÑбеÑиÑе из анимиÑованнÑÑ
, ÑÑалÑÑиÑиÑиÑованнÑÑ
и моделей PBR Ñ Ð²ÑÑоким и низким Ð
16518ºÐ¾Ð»Ð¸ÑеÑÑвом многоÑголÑника.","page_prefix":"Page %{page_number} Ñ","pbr_3d_models":"СкаÑайÑе %{rounded_count} 3D моделей Ñ PBR ÑекÑÑÑÑами Ð´Ð»Ñ Unity, Unreal и движков ÑеалÑного вÑемени.","rigged_3d_models":"СкаÑайÑе %{rounded_count} 3D моделей Ñ Ñигом (ÑкелеÑом), гоÑовÑÑ
к анимаÑии в Blender, Maya, 3ds Max, Unity и Unreal.","snap-ar":"С наÑими 3D -моделÑми Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑиÑоединиÑÑÑÑ Ðº Ð¼Ð¸Ð»Ð»Ð¸Ð¾Ð½Ñ Snapchatters, иÑполÑзÑÑ Snap AR, ÑÑÐ¾Ð±Ñ ÑоздаÑÑ Ð²ÐµÑелÑй опÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð½Ð¾Ð¹ ÑеалÑноÑÑи.","spark-ar":"ÐÑвеÑиÑе Ñвой Facebook и Instagram Ñ ÑазлиÑнÑми моделÑми Spark AR 3D, коÑоÑÑе ÑÑалÑÑиÑиÑиÑованÑ, анимиÑÐ¾Ð²Ð°Ð½Ñ Ð¸ гоÑÐ¾Ð²Ñ Ðº иÑполÑзованиÑ.","stream_3d_print_models":"ÐÑоÑмоÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑазлиÑнÑÑ
каÑегоÑий поÑока 3д пеÑаÑÑ Ð¼Ð¾Ð´ÐµÐ»ÐµÐ¹ обнаÑÑжиÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе из ÑамÑÑ
необÑÑнÑÑ
3д пеÑаÑнÑÑ
пÑоекÑов Ð¾Ñ Ð¿ÑоÑеÑÑионалÑнÑÑ
3д ÑоздаÑелей.","textures":"% {count} ТекÑÑÑÑÑ 3д акÑÐ¸Ð²Ñ Ð¸ маÑеÑиалÑ, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
, вклÑÑÐ°Ñ .tga .sbsar .jpeg .png .tiff и дÑÑгие. %{page}","tiktok":"СделайÑе ваÑи видео -ÑÑÑекÑÑ Ð±Ð¾Ð»ÐµÐµ впеÑаÑлÑÑÑими Ñ Ð¼Ð¾Ð´ÐµÐ»Ñми Tiktok 3D. ÐаÑа библиоÑека Ð¼Ð¾Ð¶ÐµÑ ÑдовлеÑвоÑиÑÑ Ð²Ñе ваÑи ÑвоÑÑеÑкие поÑÑебноÑÑи и поÑÑоÑнно обновлÑеÑÑÑ.","unity":"ÐайдиÑе 3D -модели Ð´Ð»Ñ Ð²Ð°Ñего пÑоекÑа Unity в лÑбом ÑоÑмаÑе Ñайлов и лÑбого колиÑеÑÑва поли. ÐÑе, ÑÑо вам нÑжно Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑникалÑной виÑÑÑалÑной ÑÑедÑ.","unreal":"СоздайÑе впеÑаÑлÑÑÑие визÑализаÑии Ñ Ð½ÐµÑеалÑнÑми двигаÑелÑми, ÑовмеÑÑимÑми Ñ 3D -моделÑми в лÑбом ÑоÑмаÑе Ñайла. ÐаÑа библиоÑека Ð¸Ð¼ÐµÐµÑ Ð½Ð¸Ð·ÐºÐ¸Ðµ и вÑÑокополиÑиÑеÑкие модели из каждой каÑегоÑии."},"optimized":"ÐизкополигоналÑнÑе/PBR","page_title":{"animated_3d_models":"ÐнимиÑованнÑе 3D модели â беÑплаÑно и пÑемиÑм","format_page":"%{format_upper} 3D модели â ÑкаÑаÑÑ %{format_lower} ÑÐ°Ð¹Ð»Ñ Ð±ÐµÑплаÑно","free_3d_models":"ÐеÑплаÑнÑе 3D модели â ÑкаÑаÑÑ","free_3d_print_models":"ÐеÑплаÑнÑе модели Ð´Ð»Ñ 3D пÑинÑеÑа â ÑкаÑаÑÑ STL","lowpoly_3d_models":"Low Poly 3D модели â беÑплаÑно и пÑемиÑм","pbr_3d_models":"PBR 3D модели â беÑплаÑно и пÑемиÑм","rigged_3d_models":"Rigged 3D модели (Ñ Ñигом) â беÑплаÑно и пÑемиÑм","software_page":"3D модели Ð´Ð»Ñ %{software} â ÑкаÑаÑÑ %{ext_file}","tag":{"3d_merged_premium":"%{tag_cap} â 3D модели ÑкаÑаÑÑ Ð±ÐµÑплаÑно и пÑемиÑм","3d_merged_premium_print":"%{tag_cap} Ð´Ð»Ñ 3D пÑинÑеÑа â STL модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","3d_models":"%{tag_cap} â 3D модели ÑкаÑаÑÑ Ð±ÐµÑплаÑно и пÑемиÑм","3d_print_models":"%{tag_cap} Ð´Ð»Ñ 3D пÑинÑеÑа â STL модели Ð´Ð»Ñ Ð¿ÐµÑаÑи"}},"pbr":"PBR","per_page":"ÐолиÑеÑÑво на ÑÑÑаниÑе","polygons_options":{"custom":"ÐолÑзоваÑелÑÑкий диапазон","gt_250k":"250к+","lt_5k":"Ðо 5к","prompt":"ÐолиÑеÑÑво полигонов","range_0_5000":"Ðо 5Ð","range_100k_250k":"100к-250к","range_10k_50k":"10к-50к","range_50k_100k":"50к-100к","range_5k_10k":"5к-10к"},"price":"Цена: $%{from}-%{to}","price_range":"Цена","print_ready":"ÐоÑовÑе к 3д-пеÑаÑи","printable":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи","reset_button":"СбÑоÑиÑÑ ÑилÑÑÑÑ","rigged":"Риги","rounded_count":{"delimiter":" ","exact":"%{n}","million":"%{n}
16518 млн","separator":",","thousand":"%{n}+"},"sale_off":"Со Ñкидкой","search_placeholder":"ÐлÑÑевÑе Ñлова Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка","show_all_formats":"ÐоказаÑÑ Ð²Ñе ÑоÑмаÑÑ","simulation_ready":"ÐоÑово Ð´Ð»Ñ ÑимÑлÑÑии","software":{"meta":{"3d_models":"СкаÑайÑе %{rounded_count} 3D моделей Ð´Ð»Ñ %{software}. ÐеÑплаÑнÑе и плаÑнÑе %{ext_file} ÑайлÑ, гоÑовÑе к импоÑÑÑ."}},"sort_by":"СоÑÑиÑоваÑÑ Ð¿Ð¾","sort_by_options":{"best_match":"ÐÑÑÑее Ñовпадение","highest_price":"Ðолее вÑÑÐ¾ÐºÐ°Ñ Ñена","lowest_price":"Ðолее Ð½Ð¸Ð·ÐºÐ°Ñ Ñена","newest":"СамÑе новÑе","oldest":"СамÑе ÑÑаÑÑе","sales":"ÐÑÑÑие пÑодажи","trending":"ТÑендÑ"},"subcategory":{"meta":{"3d_models":"%{count} %{category} 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайла, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.%{page}","3d_print_models":"СкаÑаÑÑ %{count} %{category} 3д модели пеÑаÑи, доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² STL, OBJ и дÑÑгие ÑоÑмаÑÑ Ñайлов, гоÑовÑÑ
к пеÑаÑи Ñ FDM, SLS и дÑÑгиÑ
3д пÑинÑеÑов.%{page}","animated_3d_models":"%{count} %{category} анимиÑованнÑе 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"СкаÑаÑÑ %{count} %{category} беÑплаÑнÑе 3д модели, доÑÑÑпнÑе в MAX, OBJ, FBX, 3DS, ÑоÑмаÑÑ Ñайлов C4D, гоÑовÑе к VR / AR, анимаÑии, Ð¸Ð³Ñ Ð¸ дÑÑгиÑ
3д-пÑоекÑов.%{page}","free_3d_print_models":"СкаÑаÑÑ %{count} %{category} беÑплаÑнÑе 3д модели пеÑаÑи гоÑовÑе Ð´Ð»Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
3д пÑинÑеÑÑ, доÑÑÑпнÑе ÑоÑмаÑÑ STL, OBJ, 3дM и многое дÑÑгое.%{page}","lowpoly_3d_models":"СкаÑаÑÑ VR / AR / низкополигоналÑÐ½Ð°Ñ %{tag} 3д моделей, гоÑовÑÑ
к виÑÑÑалÑной ÑеалÑноÑÑи, Ð¸Ð³Ñ Ð¸ дÑÑгиÑ
пÑиложений ÑеалÑного вÑемени, доÑÑÑÐ¿Ð½Ñ Ð² FBX, OBJ, MAX, 3DS, ÑоÑмаÑÑ Ñайлов C4D.%{page}","rigged_3d_models":"%{count} %{category} ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"subtitle":{"aircraft":"%{count} ÑамолеÑа 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð½Ð° наÑем ÑÑнке. CG %{airplanes_link} впиÑеÑÑÑ Ð² ÑимÑлÑÑии, визÑализаÑии, ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ видео. %{drone_link} оÑÐ³Ð°Ð½Ñ Ð¸ ÑаÑÑи бÑдÑÑ ÑадоваÑÑ Ð¿Ð¾ÐºÐ»Ð¾Ð½Ð½Ð¸ÐºÐ¾Ð² кÑоÑеÑнÑÑ
леÑаÑелÑнÑÑ
аппаÑаÑов. Ð %{rigged_link} Ð¼Ð¾Ð´ÐµÐ»Ñ Ð³Ð¾Ñова к Ð²Ð²Ð¾Ð·Ñ Ð² игÑовÑе движки и иÑполÑзоваÑÑ Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии или пÑоекÑов VR / AR. ÐеÑаÑÑие игÑÑ, ÑимÑлÑÑоÑÑ Ð¸ видео как обÑÑного CG и низкий поли Ñипов могÑÑ Ð±ÑÑÑ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ñ Ñ 3д-моделÑми в болÑÑинÑÑве попÑлÑÑнÑÑ
ÑоÑмаÑов, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.","animals":"%{count} из CG 3д живоÑнÑÑ
-%{cats_link}, %{horses_link}, %{bears_link}, %{rhinos_link}, %{eagles_link}, %{lions_link}, вÑмÑÑленнÑй %{dragons_link} и болÑÑе - можно поÑмоÑÑеÑÑ Ð·Ð´ÐµÑÑ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки. ÐоллекÑÐ¸Ñ 3д ÑаÑÐ½Ñ Ð±ÑÐ´ÐµÑ ÑдовлеÑвоÑÑÑÑ Ð¿Ð¾ÑÑебноÑÑи ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸Ð»Ð¸ ÑÑаÑиÑеÑкиÑ
ÑÑен. ÐÑ Ñакже имеем %{rigged_link} модели Ð´Ð»Ñ Ð¸Ð³Ñ, анимаÑии, видео-пÑодÑкÑии и VR / AR пÑоекÑов. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑй, низкополигоналÑнÑе или беÑплаÑнÑе 3д модели, доÑÑÑпной в болÑÑинÑÑве оÑÑаÑлевÑÑ
обÑепÑинÑÑÑÑ
ÑоÑмаÑов Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D, и дÑÑгиÑ
.","animated":"СкаÑайÑе %{rounded_count} анимиÑованнÑÑ
3D моделей Ñ Ð³Ð¾ÑовÑми движениÑми â пеÑÑонажи, живоÑнÑе и обÑекÑÑ Ð´Ð»Ñ Ð¸Ð³Ñ, кино и ÑеалÑного вÑемени.","architectural":"%{count} аÑÑ
иÑекÑÑÑнÑÑ
3д моделей , доÑÑÑпнÑÑ
Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки ÑодеÑÐ¶Ð¸Ñ ÑлеменÑÑ Ð¸ деÑали аÑÑ
иÑекÑÑÑÑ, ÑÑÑоиÑелÑÑÑва и инженеÑного пÑоекÑиÑованиÑ. ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¸Ð»Ð¸ ÑкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели, пÑоÑмаÑÑиваÑÑ ÐºÐ°ÑегоÑии вÑÑе. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии или Ð¸Ð³Ñ - некоÑоÑÑе из ниÑ
ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¸ низкополигоналÑнÑÑ
ÑлÑжиÑÑ VR / AR поÑÑебноÑÑи пÑоекÑа. 3д модели доÑÑÑÐ¿Ð½Ñ Ð² ÑоÑмаÑаÑ
, ÑакиÑ
как FBX, OBJ, MAX, 3DS, C4D.","car":"%{count} авÑÐ¾Ð¼Ð¾Ð±Ð¸Ð»Ñ 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑиваниÑ. ÐизкополигоналÑнÑÑ
веÑÑии, коÑоÑÑе бÑдÑÑ Ð¿ÑивлекаÑелÑÐ½Ñ Ð´Ð»Ñ Ð¸Ð³ÑовÑÑ
дизайнеÑов и ÑазÑабоÑÑиков VR / AR пÑиложений, дÑÑгие - кинемаÑогÑаÑиÑÑÑ, анимаÑоÑов и ÑекламодаÑелей. ÐÑ ÐºÐ»Ð°ÑÑиÑеÑкиÑ
и анÑикваÑнÑÑ
авÑомобилей на гоноÑнÑе и конÑепÑÐ¸Ñ Ð¸Ð· ниÑ
видели в ÑилÑмаÑ
, еÑÑÑ Ð±Ð¾Ð»ÑÑое ÑазнообÑазие моделей 3д авÑо в пÑакÑиÑеÑки лÑбом ÑоÑмаÑе (FBX, OBJ, MAX, 3DS, C4D и Ñ.д.), вам могÑÑ Ð¿Ð¾Ð½Ð°Ð´Ð¾Ð±Ð¸ÑÑÑÑ. ÐÑполÑзÑйÑе анимиÑованнÑе и беÑплаÑнÑе 3д модели Ð´Ð»Ñ Ð¿ÑоÑоÑипа и ÑокÑаÑиÑÑ Ð²ÑÐµÐ¼Ñ ÑазÑабоÑки.","character":"%{count} Ñимволов 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки, поÑÑÐ¾Ð¼Ñ Ð¿ÑоÑмаÑÑиваÑÑ ÑÑÑ ÐºÐ°ÑегоÑÐ¸Ñ Ð²Ñ Ð½Ð°Ð¹Ð´ÐµÑе 3д модели %{human_link}, лÑди, миÑиÑеÑкие ÑигÑÑÑ, наÑÑно-ÑанÑаÑÑиÑеÑкие %{robots_link}, Ð¾Ð´ÐµÐ¶Ð´Ñ Ð¸ дÑÑгие веÑи, ÑвÑзаннÑе Ñ Ñимволами. С %{heart_link} и %{hand_link} к деÑалÑÐ½Ð¾Ð¼Ñ ÑеалиÑÑиÑеÑкой %{male_link} или %{female_link}. Ð Ñд моделей ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¸ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð»ÐµÐ³ÐºÐ¾ добавлен к ваÑей игÑе, VR / пÑÐ¾ÐµÐºÑ AR, видео или анимаÑиÑ. Ðба вÑÑокиÑ
и низкое поли модели поли могÑÑ Ð±ÑÑÑ Ð½Ð°Ð¹Ð´ÐµÐ½Ñ Ð² ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.","custom"
16518:"ÐдеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе кÑпиÑÑ Ð¸Ð»Ð¸ ÑкаÑаÑÑ Ð±ÐµÑплаÑно %{tag} 3д-модели. %{tag_heading_subtitle}","electronics":"%{count} ÑлекÑÑоника 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑиваниÑ. ÐÑо каÑегоÑÐ¸Ñ Ð´Ð»Ñ Ð°ÑÑ
иÑекÑоÑов, декоÑаÑоÑов, дизайнеÑов ÑÑовней, ÑÑководиÑелей ÑÑÐµÐ½Ñ Ð¸ дÑÑгиÑ
обÑÑвлений. 3д модели %{smartphones_link}, %{laptops_link}, %{cameras_link}, %{tvs_link} и болÑÑе Ð¿Ð¾Ð¼Ð¾Ð¶ÐµÑ ÑоÑно заÑ
ваÑиÑÑ Ð¾Ð´ÐµÑжимоÑÑÑ ÑовÑеменной жизни Ñ ÑÑÑÑойÑÑвами и ÑеÑ
нологиÑми. ÐÑÑÑ 3д модели доÑÑÑÐ¿Ð½Ñ Ð² ÑоÑмаÑаÑ
Ñайлов, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D. СкаÑаÑÑ Ð±ÐµÑплаÑно или кÑпиÑÑ Ð¿ÑемиÑм-Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¸ иÑполÑзоваÑÑ Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии, Ð¸Ð³Ñ Ð¸ пÑоекÑов VR / AR.","exterior":"%{count} аÑÑ
иÑекÑÑÑнÑÑ
внеÑниÑ
3д-модели, доÑÑÑпнÑÑ
Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки диапазона Ð¾Ñ ÑаÑадов, гоÑодÑкиÑ
зданий, ландÑаÑÑнÑÑ
обÑекÑов, жилÑÑ
домов до пÑомÑÑленнÑÑ
ÑооÑÑжений, инÑÑаÑÑÑÑкÑÑÑÑ Ð·Ð´Ð°Ð½Ð¸Ð¹ и%моделей полномаÑÑÑабного %{city_link}. ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¸Ð»Ð¸ ÑкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели, пÑоÑмаÑÑиваÑÑ ÐºÐ°ÑегоÑии вÑÑе. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑе, низкополигоналÑнаÑ, беÑплаÑно 3д модели или ÑоÑÑиÑоваÑÑ Ð¿Ð¾ ÑоÑмаÑÑ Ð½ÐµÐ¾Ð±Ñ
одимо, в Ñом ÑиÑле и FBX, OBJ, MAX, 3DS, C4D. ÐекоÑоÑÑе из акÑивов низкополигоналÑнÑе и могÑÑ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð²Ð°Ð¼ завеÑÑиÑÑ Ð¾ÐºÑÑжение в ваÑей игÑе или пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ VR / AR.","food":"%{count} еда 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ download..Food Ñ
оÑоÑо ÑлÑÐ¶Ð¸Ñ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑеалиÑÑиÑнÑÑ
ÑÑен домаÑней жизни. 3д ÑÑÑкÑÑ, овоÑи, напиÑки и пиÑание вÑе здеÑÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»Ð½Ñе ÑÐµÐºÐ»Ð°Ð¼Ñ Ð´Ð»Ñ ÑеÑÑоÑанов, AR-пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð·Ð´Ð¾Ñового пиÑаниÑ, и визÑализаÑии аÑÑ
иÑекÑоÑÑ Ð¸ дизайнеÑÑ Ð¸Ð½ÑеÑÑеÑов ÑабоÑаÑÑ. ÐÑли Ð²Ñ Ð¸ÑеÑе 3д %{pizza_link} и %{ketchup_link} или 3д Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¾Ð±ÑÑÑалÑного %{cake_link}, они здеÑÑ. Ð Ñд низкополигоналÑнÑÑ
веÑÑий доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑеÑ
, в игÑе, ÑазвиÑие VR / AR. 3д модели можно найÑи в FBX, OBJ, MAX, 3DS, ÑоÑмаÑÑ C4D.","formats":"СкаÑайÑе %{rounded_count} 3D моделей в ÑоÑмаÑе %{format_upper} â беÑплаÑно и пÑемиÑм. ÐÑе ÑÐ°Ð¹Ð»Ñ Ð½Ð° ÑÑой ÑÑÑаниÑе доÑÑÑÐ¿Ð½Ñ Ð² наÑивном %{format_upper}, без конвеÑÑаÑии.","free_general":"СкаÑайÑе %{rounded_count} беÑплаÑнÑÑ
3D моделей Ð´Ð»Ñ Ð»Ð¸ÑнÑÑ
и коммеÑÑеÑкиÑ
пÑоекÑов. 3д модели беÑплаÑно и без ÑкÑÑÑÑÑ
плаÑежей â в FBX, OBJ, BLEND и GLB.","free_no_tag":"%{model_count} беÑплаÑно 3д моделей гоÑова к 3д пеÑаÑи. СкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели пеÑаÑи, доÑÑÑпнÑÑ
ÑоÑмаÑов Ñайлов, вклÑÑÐ°Ñ STL, OBJ, 3дM, 3DS, MAX. 3д модели гоÑÐ¾Ð²Ñ Ðº иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
Ñипов 3д пÑинÑеÑов.","free_printable":"СкаÑайÑе %{rounded_count} беÑплаÑнÑÑ
моделей Ð´Ð»Ñ 3D пÑинÑеÑа: 3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи беÑплаÑно, пÑовеÑеннÑе ÑообÑеÑÑвом â ÑигÑÑки, игÑÑÑки, Ð´ÐµÐºÐ¾Ñ Ð¸ пÑакÑиÑнÑе веÑи.","free_tag":"беÑплаÑно 3д %{tag} моделей, доÑÑÑпнÑÑ
Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки. ÐоÑÑÑпнÑе в ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
, вклÑÑÐ°Ñ MAX, OBJ, FBX, 3DS, STL, C4D, Blend, MA, MB. ÐайÑи пÑоÑеÑÑионалÑнÑÑ %{tag_link} Ð´Ð»Ñ Ð»ÑбÑÑ
пÑоекÑов 3д-пÑоекÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ°Ðº виÑÑÑалÑной ÑеалÑноÑÑи (VR), дополненной ÑеалÑноÑÑи (AR), игÑÑ, 3д визÑализаÑии или анимаÑии.","furniture":"%{count} Ð¼ÐµÐ±ÐµÐ»Ñ 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð²ÐºÐ»ÑÑаÑÑ ÑÑолÑ, ÑÑÑлÑÑ, диванÑ, кÑоваÑи и дÑÑÐ³Ð°Ñ Ð¼ÐµÐ±ÐµÐ»Ñ Ð² ÑазлиÑнÑÑ
ÑекÑÑÑÑ (деÑево, меÑалл и Ñ.д.) и ÑÑили (%{retro_link}, %{modern_link} и Ñ.д. ). ÐÑа каÑегоÑÐ¸Ñ Ð¿ÑедназнаÑена Ð´Ð»Ñ Ð²ÑеÑ
, кÑо занимаеÑÑÑ Ñ Ð°ÑÑ
иÑекÑÑÑой и дизайном инÑеÑÑеÑа, а Ñакже ÑекламодаÑелей и анимаÑоÑов. Ð Ñежиме ÑеалÑного вÑемени акÑÐ¸Ð²Ñ Ð¼Ð¾Ð³ÑÑ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð¸Ð³ÑÑ Ð¸ пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ VR / AR ÑазÑабоÑÑиков комплекÑнÑÑ
пÑоекÑов. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑе, низкополигоналÑнÑе или беÑплаÑнÑе 3д моделей . ÐоÑÑÑпен в лÑбом ÑоÑмаÑе Ñайла, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.","general":"СкаÑайÑе или кÑпиÑе %{rounded_count} пÑоÑеÑÑионалÑнÑÑ
3D моделей: 3д модели и аÑÑеÑÑ Ð´Ð»Ñ Ð¸Ð³Ñ, кино, VFX, AR/VR и 3D пеÑаÑи. ÐеÑплаÑно и пÑемиÑм, в ÑоÑмаÑаÑ
FBX, OBJ, BLEND, GLB и еÑÑ 100+.","high_poly":"ÐÑпиÑÑ Ð¸Ð»Ð¸ ÑкаÑаÑÑ ÐнимиÑованнÑе ÐÑоÑеÑÑионалÑнÑе 3д модели гоÑÐ¾Ð²Ñ Ðº иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² пÑоекÑаÑ
CG, кино- и видеопÑоизводÑÑва, анимаÑии, визÑализаÑии и дÑÑгие. ÐкÑÐ¸Ð²Ñ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки во многиÑ
оÑÑаÑлевÑÑ
пÑинимаÑÑÑÑ ÑоÑмаÑÑ, вклÑÑÐ°Ñ MAX, OBJ, FBX, 3DS, UE4 и дÑÑгие. ÐÑли Ð²Ñ Ð½Ð°Ñ
одиÑеÑÑ Ð² поиÑкаÑ
вÑÑокого каÑеÑÑва поли 3д акÑивов, Ð¼Ñ Ð¸Ð¼ÐµÐµÐ¼ ведÑÑий ÑиÑÑовое иÑкÑÑÑÑво библиоÑеки Ð´Ð»Ñ Ð²ÑеÑ
ваÑиÑ
поÑÑебноÑÑей.\n","household":"%{count} бÑÑовÑÑ
3д моделÑ, доÑÑÑÐ¿Ð½Ð°Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ÑполÑзована, ÑÑÐ¾Ð±Ñ Ð´Ð°ÑÑ Ð¿Ð¾Ð´ÑобнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð² номеÑа. ÐÑ Ð¼Ð¾Ð¶ÐµÑе поÑÑавиÑÑ Ð½Ð°Ð±Ð¾Ñ Ð¿Ð¾ÑÑÐ´Ñ Ð½Ð° ÑÑоле, еÑÑÑ Ð¿ÐµÑÐµÑ Ð¸ ÑÐ¾Ð»Ñ ÐºÐ¾Ð½ÑейнеÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð³Ð¾ инÑеÑÑеÑа кÑÑ
ни, или поÑÑавиÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе %{lights_link} и %{flowers_link} возле кÑоваÑи, ÑÑÐ¾Ð±Ñ ÑоздаÑÑ Ð¾ÑÑÑение ÑоÑкоÑи. ÐÑли Ð²Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑ Ð¸Ð½ÑеÑÑеÑа, анимаÑоÑ, VR / AR пÑиложение или ÑоздаÑÐµÐ»Ñ Ð¸Ð³ÑÑ, ÑÑа каÑегоÑÐ¸Ñ Ð´Ð»Ñ Ð²Ð°Ñ. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑе, низкополигоналÑнÑе или беÑплаÑнÑе 3д моделей . ÐоÑÑÑпен в лÑбом ÑоÑмаÑе Ñайла, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.","industrial":"%{count} пÑомÑÑленнÑе модели 3д доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ - ÑÑÑоиÑелÑнÑÑ
маÑеÑиалов, %{engineering_link} инÑÑÑÑменÑов, маÑин и %{containers_link} - обеÑпеÑÐ¸Ñ ÐºÐ°Ðº деÑали и инÑеÑакÑивнÑе, ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ ÑлеменÑÑ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¶Ð¸Ð²Ð¾Ð¹ ÑÑедÑ. ÐÑо идеалÑÐ½Ð°Ñ ÐºÐ°ÑегоÑÐ¸Ñ Ð´Ð»Ñ Ð¼Ð¾Ð´ÐµÐ»Ð¸ÑÐ¾Ð²Ð°Ð½Ð¸Ñ / VR / AR или ÑазÑабоÑÑиков, ÑоздаÑÑим %{construction_link} ÑÑÐ¾Ð²Ð½Ñ ÑайÑа в игÑе. 3д модели бÑÐ´ÐµÑ ÑлÑжиÑÑ Ð¿ÑоÑеÑÑионалам ÑÑÑоÑÑ ÑоÑнÑе визÑализаÑии, ÑабоÑаÑÑие Ñ ÑазлиÑнÑм пÑогÑаммнÑм обеÑпеÑением, как модели в ÑакиÑ
ÑоÑмаÑаÑ
, Ð
16518ºÐ°Ðº FBX, OBJ, MAX, 3DS, C4D доÑÑÑпнÑ.","interior":"%{count} инÑеÑÑÐµÑ 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки и вклÑÑаÑÑ Ð² ÑÐµÐ±Ñ ÑлеменÑÑ Ð¸ деÑали, иÑполÑзÑемÑе в аÑÑ
иÑекÑÑÑе, ÑÑÑоиÑелÑÑÑве и маÑиноÑÑÑоении, дизайн инÑеÑÑеÑа. ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¿ÑемиÑм или ÑкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели, пÑоÑмаÑÑиваÑÑ ÐºÐ°ÑегоÑии, пеÑеÑиÑленнÑе вÑÑе. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии или Ð¸Ð³Ñ - некоÑоÑÑе из ниÑ
ÑÑалÑÑиÑиÑиÑованÑ, анимаÑионнÑе и низкополигоналÑнÑе. ÐоÑÑÑпнÑе в ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.","low_poly":"СкаÑайÑе %{rounded_count} low poly 3D моделей â лÑгкие низкополигоналÑнÑе аÑÑеÑÑ Ð´Ð»Ñ Ð¸Ð³Ñ, AR/VR и мобилÑнÑÑ
пÑоекÑов.","military":"%{count} военнÑе 3д Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¾ÑÑжиÑ, оÑÑжие, %{swords_link} и аÑÑиллеÑии как ÑовÑеменнÑÑ
и иÑÑоÑиÑеÑкиÑ
, иÑполÑзÑÐµÐ¼Ð°Ñ Ð²Ð¾Ð¾ÑÑженнÑми Ñилами и ÑамообоÑона доÑÑÑпен Ð´Ð»Ñ ÑкаÑиваниÑ. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ Ð¸Ð³Ñ Ð¸Ð»Ð¸ конÑенÑа VR / AR - некоÑоÑÑе из ниÑ
ÑвлÑÑÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ÑголÑниками ÐпÑимизиÑованнÑе и гоÑовÑе бÑÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð² игÑовой движок. ÐÑнаÑеннÑе и анимиÑованнÑе модели могÑÑ Ð¾Ð±Ð»ÐµÐ³ÑиÑÑ Ð²Ð°ÑÑ ÑабоÑÑ Ð´Ð°Ð»ÑÑе. ÐÑ Ð½Ð°Ð²ÐµÑнÑка найдеÑе ÑооÑвеÑÑÑвÑÑÑие акÑивÑ, поÑколÑÐºÑ ÐµÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ 3д моделей, доÑÑÑпнÑÑ
в лÑбом ÑоÑмаÑе Ñайл, вам могÑÑ Ð¿Ð¾Ð½Ð°Ð´Ð¾Ð±Ð¸ÑÑÑÑ (FBX, OBJ, MAX, 3DS, C4D и Ñ.д.).","not_custom":"ÐеÑплаÑнÑе и плаÑнÑе 3D модели в каÑегоÑии %{tag_low} - ÑеалиÑÑиÑнÑе и ÑÑилизованнÑе, в FBX, OBJ, BLEND и GLB.","optimized":"Ðодели, коÑоÑÑе имеÑÑ Ð¼ÐµÐ½ÑÑе многоÑголÑников лÑÑÑе вÑего иÑполÑзоваÑÑ Ð² ÑеалÑнÑÑ
пÑиложениÑÑ
, коÑоÑÑе ÑÑебÑÑÑ Ð²Ñемени бÑÑÑÑой обÑабоÑки, как виÑÑÑалÑÐ½Ð°Ñ ÑеалÑноÑÑÑ (VR), Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð½Ð°Ñ ÑеалÑноÑÑÑ (AR), ÑмеÑÐ°Ð½Ð½Ð°Ñ ÑеалÑноÑÑÑ (MR), пеÑекÑеÑÑÐ½Ð°Ñ ÑеалÑноÑÑÑ (XR) и игÑÑ, оÑобенно игÑÑ Ð´Ð»Ñ Ð¼Ð¾Ð±Ð¸Ð»ÑнÑÑ
ÑелеÑонов. ÐÑбеÑиÑе из наÑей коллекÑии ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¸ анимиÑованнÑе модели легко иÑполÑзоваÑÑ Ð¸Ñ
в пÑиложениÑÑ
ÑеалÑного вÑемени. ÐолÑÑиÑÑ 3д акÑивов Ð´Ð»Ñ ÑÑед, подобÑаÑÑ ÑеквизиÑ, обÑекÑÑ Ð¸Ð»Ð¸ кÑпиÑÑ Ð¿Ð¾Ð»Ð½Ñе 3д модели коллекÑии, пакеÑÑ Ð¸ пакеÑÑ Ñо вÑеми ваÑей игÑой Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð½Ð°Ð´Ð¾Ð±Ð¸ÑÑÑÑ. СоÑ
ÑаниÑÑ Ð²ÑÐµÐ¼Ñ ÑазÑабоÑки и заÑÑаÑÑ, Ð´ÐµÐ»Ð°Ñ Ð¾Ð¿ÑÑ Ð¿ÑоÑоÑипов или иÑполÑзование 3д моделей как заполниÑели в ваÑем пÑоекÑе. ФизиÑеÑки ÑендеÑинг, или PBR, обознаÑÐ°ÐµÑ Ð¼Ð¾Ð´ÐµÐ»Ñ, коÑоÑÑе оказÑÐ²Ð°ÐµÐ¼Ð°Ñ ÑоÑно и поÑледоваÑелÑно в лÑбÑÑ
ÑÑловиÑÑ
оÑвеÑÐµÐ½Ð¸Ñ Ð±Ð»Ð°Ð³Ð¾Ð´Ð°ÑÑ ÑекÑÑÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÑабоÑиÑ
пÑоÑеÑÑов, иÑполÑзÑемой в пÑоÑеÑÑе ÑозданиÑ.\n","pbr":"СкаÑайÑе %{rounded_count} 3D моделей Ñ PBR ÑекÑÑÑÑами (ÑизиÑеÑки коÑÑекÑнÑй ÑендеÑинг) â ÑеалиÑÑиÑнÑе маÑеÑÐ¸Ð°Ð»Ñ Ð´Ð»Ñ Unity, Unreal и дÑÑгиÑ
движков ÑеалÑного вÑемени.","plant":"%{count} завод 3д моделÑ, доÑÑÑÐ¿Ð½Ð°Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ ÑодеÑÐ¶Ð¸Ñ ÑÐ»Ð¾Ñ Ð¾ÑганизмÑ, коÑоÑÑе ÑаÑÑÑÑ Ð² домаÑниÑ
ÑаÑÑÐµÐ½Ð¸Ñ Ð¸ в пÑиÑоде, Ñакие как ÑвеÑÑ, %{trees_link}, ÑÑавÑ, лианÑ, зеленÑ, ÑÑавÑ, многолеÑники, ÑаженÑÑ, побеги, кÑÑÑаÑники, пÑомаÑ
и, капÑÑÑа, виногÑад, ÑоÑнÑки. ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¿ÑемиÑм или ÑкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели, пÑоÑмаÑÑиваÑÑ ÐºÐ°ÑегоÑии вÑÑе, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи наиболее подÑ
одÑÑий ваÑÐ¸Ð°Ð½Ñ ÑÑеди доÑÑÑпнÑÑ
моделей. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑй, низкополигоналÑнÑе (Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² игÑаÑ
и VR / AR-пÑиложении) модели, или оÑÑилÑÑÑоваÑÑ Ð½ÐµÐ¾Ð±Ñ
одимÑе ÑоÑмаÑÑ (модели FBX, OBJ, MAX, 3DS, C4D и более доÑÑÑпнÑ).","printable":"СкаÑайÑе %{rounded_count} моделей Ð´Ð»Ñ 3D пÑинÑеÑа: 3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи в STL, пÑовеÑеннÑе Ð´Ð»Ñ FDM и ÑоÑополимеÑнÑÑ
пÑинÑеÑов. ФигÑÑки, миниаÑÑÑÑ, декоÑ, полезнÑе веÑи и запÑаÑÑи.","printable_merged_tag":"СкаÑайÑе %{rounded_count} моделей «%{tag_low}» Ð´Ð»Ñ 3D пеÑаÑи: STL ÑÐ°Ð¹Ð»Ñ Ð±ÐµÑплаÑно и пÑемиÑм, Ð´Ð»Ñ FDM и ÑоÑополимеÑнÑÑ
пÑинÑеÑов.","printable_tag":"СкаÑайÑе %{rounded_count} моделей «%{tag_low}» Ð´Ð»Ñ 3D пеÑаÑи: STL ÑÐ°Ð¹Ð»Ñ Ð±ÐµÑплаÑно и пÑемиÑм, Ð´Ð»Ñ FDM и ÑоÑополимеÑнÑÑ
пÑинÑеÑов.","rigged":"СкаÑайÑе %{rounded_count} rigged 3D моделей â пеÑÑонажи, живоÑнÑе и ÑÑÑеÑÑва Ñо ÑкелеÑом (Ñигом), гоÑовÑе к анимаÑии в Blender, Maya, 3ds Max, Unity и Unreal.","scanned":"%{count} оÑÑканиÑованнÑе 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð¿ÑиобÑеÑÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ беÑплаÑного ÑкаÑиваниÑ. 3д модели ÐÑÑканиÑованнÑе гоÑÐ¾Ð²Ñ Ðº анимаÑии, Ð¸Ð³Ñ Ð¸ пÑоекÑов VR / AR. ÐÑ Ð¼Ð¾Ð¶ÐµÑе найÑи 3д модели обÑекÑов, вÑÑÑеÑаÑÑиÑ
ÑÑ Ð² пÑиÑоде, Ñакие как камни и пÑиÑоднÑе повеÑÑ
ноÑÑи, лÑди и дÑÑгие обÑекÑÑ ÑеалÑной жизни здеÑÑ ... и он не Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð»ÑÑиÑÑ ÐºÐ°ÐºÑÑ-либо более ÑеалиÑÑиÑен, Ñем ÑÑо. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑе, низкополигоналÑнÑе или беÑплаÑнÑе 3д моделей . ÐоÑÑÑпен в лÑбом ÑоÑмаÑе Ñайла, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.","science":"%{count} наÑка 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² ÑÑой каÑегоÑии диапазоне Ð¾Ñ Ð¼ÐµÐ´Ð¸ÑинÑ, биологии, Ñизики, Ñ
имии и дÑÑгиÑ
облаÑÑÑÑ
обÑекÑов ÑеалÑного миÑа, ÑвÑзаннÑÑ
Ñ Ð½Ð°Ñкой и ÑеÑ
никой: лабоÑаÑоÑное обоÑÑдование, микÑоÑкопиÑеÑкиÑ
Ñел и ÑÑбаÑомном миÑе. ÐÐµÑ Ð½ÐµÐ¾Ð±Ñ
одимоÑÑи иÑкаÑÑ Ð´Ð°Ð»ÑÑе, %{cell_link}, %{skull_link}
16518 и %{skeleton_link} 3д модели можно найÑи здеÑÑ! ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¸Ð»Ð¸ же ÑкаÑаÑÑ Ð±ÐµÑплаÑнÑй 3д акÑивов, пÑоÑмаÑÑиваÑÑ ÐºÐ°ÑегоÑии вÑÑе. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии или низкополигоналÑнÑми из ниÑ
Ð´Ð»Ñ Ð¸Ð³Ñ Ð¸ пÑоекÑов VR / AR. Ðба ÑвободнÑÑ
и пÑемиÑм 3д-модели можно найÑи в ÑÑде ÑоÑмаÑов Ñайлов, вклÑÑÐ°Ñ FBX, OBJ, MAX, 3DS, C4D.","scripts_plugins":"%{count} 3д ÑкÑипÑÑ / Ð¿Ð»Ð°Ð³Ð¸Ð½Ñ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки. 3д ÑкÑипÑÑ / Ð¿Ð»Ð°Ð³Ð¸Ð½Ñ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ðº ÑазлиÑÐ½Ð¾Ð¼Ñ Ð¿ÑогÑÐ°Ð¼Ð¼Ð½Ð¾Ð¼Ñ Ð¾Ð±ÐµÑпеÑÐµÐ½Ð¸Ñ Ð¸ иÑполÑзоваÑÑ Ð±Ð¾Ð»ÐµÐµ ÑÑÑекÑивно ÑделаÑÑ Ð²Ð°ÑÑ ÑабоÑÑ ÑÑÑбопÑовод. ФилÑÑÑ Ð¿Ð¾ ÑоÑмаÑам, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи инÑÑÑÑменÑÑ Ð¤Ð¸Ñ Ð¿ÑедпоÑиÑаемого пÑогÑаммного обеÑпеÑениÑ.\n","software_page":"СкаÑайÑе %{rounded_count} 3D моделей Ð´Ð»Ñ %{software} â беÑплаÑно и пÑемиÑм. ÐаÑивнÑе %{ext_file} ÑÐ°Ð¹Ð»Ñ Ð¾ÑкÑÑваÑÑÑÑ ÑÑазÑ; оÑÑалÑнÑе ÑоÑмаÑÑ Ð»ÐµÐ³ÐºÐ¾ импоÑÑиÑÑÑÑÑÑ.","space":"%{count} пÑоÑÑÑанÑÑво 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð½Ð° CGTrader. ÐÑоÑÑÑанÑÑво каÑегоÑÐ¸Ñ Ð¿Ð¾Ð»Ð½Ð° низкополигоналÑного, игÑовÑе гоÑовÑе модели наÑÑно-ÑанÑаÑÑиÑеÑком %{spaceships_link}. ÐÑÑÑ Ñакже %{asteroids_link}, Ð¿Ð»Ð°Ð½ÐµÑ (вклÑÑÐ°Ñ ÐÑÐ½Ñ Ð¸ ÐаÑÑ, Ð´Ð»Ñ Ð¸Ð¼Ð¸ÑаÑии колонизаÑии) и ÑеалиÑÑиÑеÑкое пÑоÑÑÑанÑÑво %{shuttles_link} Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ наÑÑно наклонена. Ðодели, безÑÑловно, могÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð² VR коÑмиÑеÑкий ÑимÑлÑÑÐ¾Ñ Ð¸Ð³ÑÑ, AR-пÑиложений и анимаÑии, ÑÑÐ¾Ð±Ñ Ð¿ÑодемонÑÑÑиÑоваÑÑ Ð¼Ð¸ÑÑ Ð·Ð° пÑеделами планеÑÑ %{earth_link}. ФилÑÑÑÑ Ð·Ð´ÐµÑÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð²Ð°Ð¼ найÑи ÑÑалÑÑиÑиÑиÑовано, анимиÑованнÑе, низкополигоналÑнÑе акÑÐ¸Ð²Ñ Ð¸Ð»Ð¸ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð² опÑеделеннÑÑ
ÑоÑмаÑаÑ
, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D. ","sports":"%{count} ÑпоÑÑ 3д модели доÑÑÑпно вмеÑÑе обоÑÑдование гнезда, коÑоÑое иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð°ÐºÑивного оÑдÑÑ
а, ÑазвлеÑений, ÑизиÑеÑкиÑ
ÑпÑажнений, оÑдÑÑ
а, пÑиÑÑного вÑемÑпÑепÑовождениÑ, забавÑ, а Ñакже игÑÑ, деÑÑкие игÑÑÑки и полнÑй ÑпекÑÑ Ð¼ÑзÑкалÑнÑÑ
инÑÑÑÑменÑов. ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¸Ð»Ð¸ ÑкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели в лÑбом ÑоÑмаÑе Ñайлов, необÑ
одимÑÑ
, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D, пÑоÑмаÑÑиваÑÑ ÐºÐ°ÑегоÑии вÑÑе. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии, игÑ, пÑоекÑов VR / AR - много из ниÑ
ÑÑалÑÑиÑиÑиÑованÑ, низкополигоналÑнÑÑ
или анимиÑованнÑÑ
Ñже.","test":{"airplane":"ÐÑбиÑели авиаÑии, ÑлÑÑайÑе, ÑÑо никогда не бÑло Ñак легко полÑÑиÑÑ Ð¸Ð´ÐµÐ°Ð»ÑнÑй 3д напеÑаÑаннÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ ÑамолеÑа Ð´Ð»Ñ Ð½Ð°ÑÑолÑной игÑÑ Ð¸Ð»Ð¸ коллекÑии модели. ÐоиÑк по моделей %{model_count} 3д пеÑаÑи ÑÐ°Ð¼Ð¾Ð»ÐµÑ Ð¸ найÑи моделÑ, вам пÑоÑÑо необÑ
одимо имеÑÑ Ð½Ð° ÑÑой полке. модели ÑеалÑного ÑамолеÑа Discover или вÑдÑманнÑе из ниÑ
. ÐоиÑк новейÑиÑ
конÑÑÑÑкÑий или ÑÑо-Ñо, ÑÑо ÑаÑÑÑиÑÑÐ²Ð°ÐµÑ Ð¾Ð±ÑаÑно Ð¾Ñ Ð²Ñемени бÑаÑÑев РайÑ. ÐÑо Ñакже пÑекÑаÑнÑй подаÑок Ð´Ð»Ñ Ð»Ñбого Ñебенка, коÑоÑÑй меÑÑÐ°ÐµÑ ÑÑаÑÑ Ð¿Ð¸Ð»Ð¾Ñом, когда он вÑÑаÑÑеÑ. ÐокÑпка и загÑÑзка модели пеÑаÑи 3д, ÑаÑпеÑаÑаÑÑ ÐµÐ³Ð¾ ÑамоÑÑоÑÑелÑно или пÑедÑÑавиÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ из наÑиÑ
поÑÑавÑиков ÑÑлÑг пеÑаÑи 3д, ÑÑÐ¾Ð±Ñ Ð¾Ð
16518½ напеÑаÑан и оÑпÑавлен к вам в кÑаÑÑайÑие ÑÑоки!\n","anatomy":"%{model_count} Ð¼Ð¾Ð´ÐµÐ»Ñ 3д анаÑомиÑ, доÑÑÑÐ¿Ð½Ð°Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð½Ð° наÑем ÑÑнке. ÐÑÑледÑйÑе анаÑомии Ñеловека Ñ Ð²ÑÑоким - поли коÑÑи, мÑÑÑÑ, модели оÑганов. ÐдеалÑно подÑ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ Ð»Ñбого обÑазоваÑелÑного или наÑÑного пÑоекÑа. ÐÑполÑзÑйÑе Ð´Ð»Ñ Ð¿ÐµÑаÑи 3д модели Ð´Ð»Ñ ÑлÑÑÑÐµÐ½Ð¸Ñ Ð¾Ð¿ÑÑа обÑазованиÑ. СоздавайÑе поÑÑÑÑаÑÑие анимаÑии и видео-игÑÑ Ñ Ð½Ð°Ñим\n обÑиÑÐ½Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñека ÑалÑÑиÑиÑиÑованнÑÑ
моделей. ÐÑполÑзÑйÑе наÑÑ ÑÑовеÑÑенÑÑвованнÑÑ ÑиÑÑÐµÐ¼Ñ ÑилÑÑÑаÑии легко найÑи низкополигоналÑнÑй, анимиÑованнÑй, PBR,\n ÑÑалÑÑиÑиÑиÑованнÑе модели или ÑÑо-нибÑдÑ, ÑÑо ÑооÑвеÑÑÑвÑÐµÑ Ð²Ð°Ñим поÑÑебноÑÑÑм. ÐÑбеÑиÑе из болÑÑой Ñделки ÑоÑмаÑов Ñайлов, вклÑÑаÑ\n ÑамÑе попÑлÑÑнÑе из ниÑ
, как FBX, OBJ, MAX, 3DS, C4D.\n","castle":"ÐÐ°Ñ ÑобÑÑвеннÑй ÑдивиÑелÑнÑй 3д пеÑаÑаÑÑÑÑ Ð·Ð°Ð¼Ð¾Ðº на ÑаÑÑÑоÑнии одного клика! ÐоиÑк ÑазлиÑнÑÑ
моделей 3д замок гоÑов к 3д пеÑаÑи. Создание ÑникалÑной ÑанÑазии кÑепоÑÑи Ð´Ð»Ñ Ð²Ð°Ñего D \u0026 D ÑеÑÑии или лÑбой дÑÑгой наÑÑолÑной игÑÑ ÑÑедневекового Ñпга. ÐÑи ÑÑедневековÑе кÑепоÑÑи ÑдивиÑелÑнÑй подаÑок Ð´Ð»Ñ Ð»Ñбой наÑÑолÑной игÑÑ ÑнÑÑзиаÑÑов или пÑекÑаÑнÑм дополнением к ваÑей ÑобÑÑвенной коллекÑии. ÐайÑи идеалÑнÑй 3д модели Ð´Ð»Ñ ÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð»ÑбиÑелей или единÑÑвеннÑй в Ñвоем Ñоде игÑÑÑка Ð´Ð»Ñ Ð´ÐµÑей. ÐокÑпка и загÑÑзиÑÑ Ð²ÑбÑаннÑй дизайн 3д замка, ÑаÑпеÑаÑайÑе его Ñ Ð²Ð°Ñим ÑобÑÑвеннÑм пÑинÑеÑом или пÑедÑÑавиÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ из наÑиÑ
поÑÑавÑиков ÑÑлÑг пеÑаÑи 3д, ÑÑÐ¾Ð±Ñ Ð¾Ð½ напеÑаÑан и оÑпÑавлен к вам.\n","dice":"УдаÑа не бÑÐ´ÐµÑ ÑабоÑаÑÑ Ñ 3д пеÑаÑнÑÑ
коÑÑи! ÐÑли Ð²Ñ Ð½Ðµ Ñ
оÑиÑе аÑÑенÑиÑнÑе игÑÑ Ð² коÑÑи Ð´Ð»Ñ Ð²Ð°Ñей наÑÑолÑной игÑÑ Ð½Ð¾ÑÑÑ, ÑмоÑÑеÑÑ Ð½Ðµ болÑÑе. ÐдеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе вÑбÑаÑÑ Ð¼ÐµÐ¶Ð´Ñ %{model_count} ÑвободнÑÑ
3д коÑÑи моделей, гоÑовÑÑ
Ð´Ð»Ñ 3д пеÑаÑи. Ðогда игÑа законÑена, иÑполÑзоваÑÑ ÑÑи кÑаÑивÑе модели в каÑеÑÑве акÑеÑÑÑаÑа. СкаÑаÑÑ Ð±ÐµÑплаÑно 3д Ð´Ð»Ñ Ð¿ÐµÑаÑи модели коÑÑи, ÑоÑмаÑÑ Ñайлов доÑÑÑÐ¿Ð½Ñ Ð² Ñом ÑиÑле STL, OBJ, 3дM, 3DS, MAX. ÐаÑи 3д модели гоÑÐ¾Ð²Ñ Ðº иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
Ñипов 3д пÑинÑеÑов. СделайÑе ваÑÑ Ð¸Ð³ÑÑ Ð±Ð¾Ð»ÐµÐµ инÑеÑеÑной и полÑÑиÑÑ 3д пеÑаÑнÑÑ
коÑÑи!\n","drone":"3д пеÑаÑÑ Ð¸ поÑÑÑоиÑÑ Ñвой ÑобÑÑвеннÑй беÑпилоÑнÑй или найÑи ÑаÑÑи Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ. 3д пеÑаÑнÑÑ
ÑÑÑÑни легко ÑобÑаÑÑ Ð¸ ÑÐµÐ¼Ð¾Ð½Ñ Ð¿Ð¾Ñле аваÑийной поÑадки. ÐÑкÑойÑе Ð´Ð»Ñ ÑÐµÐ±Ñ Ð¼Ð¾Ð´ÐµÐ»Ñ Ñ Ð¸Ð´ÐµÐ°Ð»Ñной монÑажной позиÑией камеÑÑ Ð¸Ð»Ð¸ запÑоÑом минималÑнÑÑ
изменений. ÐдеалÑно подÑ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ Ð°ÐºÑивного оÑдÑÑ
а забавнÑми, аÑÑоÑоÑоÑÑемки, видеогÑаÑии или оÑобÑажениÑ. ÐайÑи и пÑиобÑеÑÑи ÑникалÑнÑй дизайн 3д беÑпилоÑнÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ, коÑоÑÐ°Ñ Ð¿Ð¾Ð´Ñ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ Ð²ÑеÑ
ваÑиÑ
поÑÑебноÑÑей. РаÑпеÑаÑайÑе его ÑамоÑÑоÑÑелÑно или пÑедÑÑавиÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ из наÑиÑ
поÑÑавÑиков ÑÑлÑг пеÑаÑи 3д, ÑÑÐ¾Ð±Ñ Ð¾Ð
16518½ напеÑаÑан и оÑпÑавлен к вам в кÑаÑÑайÑие ÑÑоки! ÐолÑÑиÑе Ð²Ð°Ñ ÑобÑÑвеннÑй 3д пеÑаÑного дÑон и бÑодÑÑ Ð¿Ð¾ ÑиÑÐ¾ÐºÐ¾Ð¼Ñ Ð³Ð¾Ð»ÑÐ±Ð¾Ð¼Ñ Ð½ÐµÐ±Ñ!\n","pokemon":"ÐикаÑÑ, Ñ Ð²ÑбиÑÐ°Ñ ÑебÑ! ÐÑбеÑиÑе из нагÑÑзок каÑманнÑÑ
монÑÑÑов, гоÑовÑÑ
Ð´Ð»Ñ 3д пеÑаÑи. Ðеликий ÑаÑÑиÑиÑÑ Ñвой 3д пеÑаÑное покемон коллекÑии. ÐоиÑк и наÑкнÑÑÑÑÑ Ð½Ð° ÑамÑÑ
лÑÑÑиÑ
, ÑамÑÑ
подÑобнÑÑ
покемон конÑÑÑÑкÑий Ð´Ð»Ñ Ð²Ð°Ñей ÑледÑÑÑей наÑÑолÑной игÑÑ Ñ Ð´ÑÑзÑÑми. ÐокÑпка и загÑÑзиÑÑ 3д покемон, ÑаÑпеÑаÑайÑе его Ñ ÑобÑÑвеннÑм 3д пÑинÑеÑом, или пÑедÑÑавиÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ из наÑиÑ
поÑÑавÑиков ÑÑлÑг пеÑаÑи 3д, ÑÑÐ¾Ð±Ñ Ð¾Ð½ напеÑаÑан и оÑпÑавлен к вам. РконÑе конÑов, ÑÑо одна из ÑамÑÑ
кÑÑÑÑÑ
веÑей Ð´Ð»Ñ 3д пеÑаÑи!\n","ring":"3д напеÑаÑÐ°Ð½Ñ ÑвелиÑнÑе Ð¸Ð·Ð´ÐµÐ»Ð¸Ñ Ð½Ð¾Ð²Ñй ÑеÑнÑй в пÑомÑÑленноÑÑи, как и 3д пеÑаÑнÑе колÑÑа! ÐоиÑк огÑомного колиÑеÑÑва %{model_count} ÑвободнÑÑ
3д моделей Ð´Ð»Ñ Ð¿ÐµÑаÑи колÑÑа. ÐÑоÑмоÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑникалÑнÑÑ
дизайнов и найÑи ÑÑо-Ñо Ñделал Ð´Ð»Ñ Ð²Ð°Ñ. Ðе Ð¼Ð¾Ð³Ñ Ð½Ð°Ð¹Ñи ÑÑо-нибÑÐ´Ñ Ð´Ð»Ñ ÑÐµÐ±Ñ Ð² магазине? Ðли, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ, Ð²Ñ Ñ
оÑиÑе акÑеÑÑÑÐ°Ñ ÑоÑно, как один Ð²Ð°Ñ Ð»ÑбимÑй пеÑÑонаж ÑилÑма еÑÑÑ? ÐÑбеÑиÑе из болÑÑой Ñделки ÑоÑмаÑов Ñайлов, вклÑÑÐ°Ñ STL, OBJ, 3дM, 3DS, MAX. 3д модели гоÑÐ¾Ð²Ñ Ðº иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
Ñипов 3д пÑинÑеÑов, поÑÑÐ¾Ð¼Ñ Ð¿ÑоÑмаÑÑиваÑÑ Ð½Ð°Ñ Ð²ÑÐ±Ð¾Ñ Ð¸ попÑобоваÑÑ Ð½Ð° новом лÑбимом колÑÑе.\n","shoes":"ÐолÑÑие бÑÐµÐ½Ð´Ñ Ð½Ð° боÑÑÑ Ñ 3д пеÑаÑнÑÑ
обÑÐ²Ñ Ð¸ ÑепеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе поделиÑÑÑÑ Ð¾Ð¿ÑÑом, а Ñакже. ÐÐ±Ð·Ð¾Ñ Ð¸ найÑи беÑплаÑнÑÑ Ð¿ÐµÑаÑнÑе конÑÑÑÑкÑии обÑви - Ð¾Ñ ÐºÑоÑÑовок до моднÑÑ
каблÑков еÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ гоÑовÑÑ
к пеÑаÑи моделей пÑоÑÑо ждем ваÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¿ÑобоваÑÑ Ð¸Ñ
. СделайÑе иÑоговÑй ÑовеÑÑеннÑм пÑÑем вÑбоÑа маÑеÑиалов, ÑегÑлиÑÑÑ Ð¼ÑгкоÑÑÑ Ð¸ ÑазмеÑ. ÐÑбеÑиÑе один из 146 беÑплаÑнÑÑ
3д моделей обÑви и загÑÑзиÑÑ Ð¸Ñ
в доÑÑÑпнÑÑ
ÑоÑмаÑаÑ
Ñайлов, вклÑÑÐ°Ñ STL, OBJ, 3дM, 3DS, MAX. ÐонÑÑÑÑкÑии гоÑÐ¾Ð²Ñ Ðº иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
Ñипов 3д пÑинÑеÑов. ÐолÑÑиÑе ваÑи 3д пеÑаÑной обÑÐ²Ñ ÑегоднÑ!\n","textures":"ÐоиÑк по огÑÐ¾Ð¼Ð½Ð¾Ð¼Ñ ÐºÐ¾Ð»Ð¸ÑеÑÑÐ²Ñ %{model_count} CG ÑекÑÑÑÑÑ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки, вклÑÑÐ°Ñ ÐºÑаÑиво ÑделаннÑе маÑеÑиалÑ. ÐÑоÑмоÑÑиÑе каtagоÑии и найÑи беÑÑовнÑÑ ÑканÑ, деÑево, меÑалл, плаÑÑик, киÑÐ¿Ð¸Ñ ÑекÑÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð·Ð°ÐºÐ¾Ð½ÑиÑÑ Ð²Ð°Ñ Ð¿ÑÐ¾ÐµÐºÑ Ð±ÑÑÑÑее. ÐÑполÑзÑйÑе ÑаÑÑиÑеннÑй поиÑк, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованнÑе и анимиÑованнÑе ÑекÑÑÑÑÑ Ð´Ð»Ñ Ð¸Ð³ÑÑ Ð¸Ð»Ð¸ видео ÑозданиÑ. ÐаÑи маÑеÑÐ¸Ð°Ð»Ñ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
, вклÑÑÐ°Ñ TGA, SBSAR, JPG, PNG, TIFF и дÑÑгие, Ñак ÑÑо не ÑеÑÑйÑе вÑемени и найÑи гоÑовÑе к иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑекÑÑÑÑ CG пÑакÑиÑеÑки Ð´Ð»Ñ Ð»Ñбого пÑоекÑа можно Ñебе пÑедÑÑавиÑÑ.\n"},"various":"%{count} ÑазлиÑнÑе 3д-модели, коÑоÑÑе не легко найÑи Ñвое меÑÑо в дÑÑгиÑ
каÑегоÑиÑÑ
доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки. %{rocks_link}, %{clouds_link}, %{logos_link}, %{cigarette_link} и дÑÑгие не клаÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ 3д модели, коÑоÑÑе вÑ, возможно, поÑÑебÑеÑÑÑ, ÑÑÐ¾Ð±Ñ Ð·Ð°Ð²ÐµÑÑиÑÑ Ð¸Ð³ÑÑ, анимаÑÐ¸Ñ Ð¸Ð»Ð¸ пÑÐ¾ÐµÐºÑ VR / AR здеÑÑ. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑованÑ, анимиÑованнÑй, низкополигоналÑнÑе или беÑплаÑно 3д модели, или пеÑебиÑаÑÑ Ð´Ð¾ÑÑÑпнÑми ÑоÑмаÑами, Ñакие как FBX, OBJ, MAX, 3DS, C4D.","vehicle":"%{count} авÑÐ¾Ð¼Ð¾Ð±Ð¸Ð»Ñ 3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð²ÐºÐ»ÑÑаÑÑ ÑÑанÑпоÑÑ, %{ambulances_link}, авÑобÑÑÑ, %{bikes_link} и Moto - ÑÑо каÑегоÑÐ¸Ñ Ð´Ð»Ñ Ð»Ñдей, коÑоÑÑе Ñ
оÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¸Ñ
гоÑодÑкие ÑлиÑÑ Ð±Ñли Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ñ Ñ ÑÑанÑпоÑÑнÑми ÑÑедÑÑвами, Ñвл
16518ÑеÑÑÑ Ð»Ð¸ ÑеалиÑÑиÑной или наÑÑно-ÑанÑаÑÑиÑеÑкой. Те, ÑÑо Ð´ÐµÐ»Ð°ÐµÑ Ð¸Ð¼Ð¸ÑаÑионнÑе игÑÑ Ð¸Ð»Ð¸ VR / AR-пÑиложений, обÑÑвлений в пÑоизводÑÑве видео или даже ÑазÑабоÑки плакаÑов, ÑкоÑее вÑего, найÑи наиболее попÑлÑÑнÑе ÑоÑмаÑÑ Ñайлов, Ñакие как FBX, OBJ, MAX, 3DS, C4D годнÑм к ÑпоÑÑеблениÑ. ÐÑÑгие земли ÑÑанÑпоÑÑнÑе ÑÑедÑÑва, Ñакие как поезд или %{tractor_link} 3д Ð¼Ð¾Ð´ÐµÐ»Ñ Ñакже можно найÑи в ÑÑой обÑиÑной коллекÑии. ÐÑполÑзÑйÑе ÑилÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¹Ñи ÑÑалÑÑиÑиÑиÑовано, анимиÑованнÑе, низкополигоналÑнÑÑ Ð¸Ð»Ð¸ беÑплаÑнÑй 3д модели бÑÑÑÑее.","watercraft":"%{count} ÐÐÐÐЫР3д модели доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð²ÐºÐ»ÑÑаÑÑ %{boats_link}, %{yachts_link}, %{ships_link} и дÑÑгие воднÑе ÑÑанÑпоÑÑнÑе ÑÑедÑÑва ÑобиÑаÑÑÑÑ Ð²ÑеÑ
видов. ÐÑнаÑенное 3д Ð¼Ð¾Ð´ÐµÐ»Ñ Ð½Ð¸Ð·ÐºÐ¾Ð¿Ð¾Ð»Ð¸Ð³Ð¾Ð½Ð°Ð»Ñной пÑеÑÑÐ¿ÐµÐµÑ Ð² видеоигÑаÑ
, VR / AR пÑоекÑаÑ
, а Ñакже анимаÑии, в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº модели CG здеÑÑ Ð´Ð»Ñ ÑÑен и дÑÑгиÑ
пÑименений, где визÑалÑÐ½Ð°Ñ ÑоÑноÑÑÑ Ð²Ð°Ð¶Ð½ÐµÐµ Polycount. Ðодели доÑÑÑÐ¿Ð½Ñ Ð² лÑбом ÑоÑмаÑе Ñайла, вклÑÑаÑ, но не огÑаниÑиваÑÑÑ FBX, OBJ, MAX, 3DS, C4D."},"tag":{"meta":{"3d_merged_premium":"СкаÑайÑе %{rounded_count} 3D моделей в каÑегоÑии %{tag_low} беÑплаÑно и пÑемиÑм. Ð ÑоÑмаÑаÑ
FBX, OBJ, BLEND, GLB â Ð´Ð»Ñ Ð¸Ð³Ñ, кино, AR/VR и 3D пеÑаÑи.","3d_merged_premium_print":"СкаÑайÑе %{rounded_count} STL моделей «%{tag_low}» Ð´Ð»Ñ 3D пÑинÑеÑа, беÑплаÑно и пÑемиÑм â пÑовеÑено Ð´Ð»Ñ FDM и ÑоÑополимеÑной пеÑаÑи.","3d_models":"СкаÑайÑе %{rounded_count} 3D моделей в каÑегоÑии %{tag_low} беÑплаÑно и пÑемиÑм. Ð ÑоÑмаÑаÑ
FBX, OBJ, BLEND, GLB â Ð´Ð»Ñ Ð¸Ð³Ñ, кино, AR/VR и 3D пеÑаÑи.","3d_print_models":"СкаÑайÑе %{rounded_count} STL моделей «%{tag_low}» Ð´Ð»Ñ 3D пÑинÑеÑа, беÑплаÑно и пÑемиÑм â пÑовеÑено Ð´Ð»Ñ FDM и ÑоÑополимеÑной пеÑаÑи.","animated_3d_models":"%{count} %{tag} анимиÑованнÑе 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.%{page}","free_3d_models":"СкаÑаÑÑ %{count} %{tag} беÑплаÑно 3д модели, доÑÑÑпнÑе в MAX, OBJ, FBX, 3DS, ÑоÑмаÑÑ Ñайлов C4D, гоÑовÑе к VR / AR, анимаÑии, Ð¸Ð³Ñ Ð¸ дÑÑгиÑ
3д-пÑоекÑов.%{page}","free_3d_print_models":"СкаÑаÑÑ %{count} %{tag} беÑплаÑно 3д модели пеÑаÑи гоÑовÑе Ð´Ð»Ñ FDM, ÐÐС, SLS и дÑÑгиÑ
3д пÑинÑеÑÑ, доÑÑÑпнÑе ÑоÑмаÑÑ STL, OBJ, 3дM и многое дÑÑгое.%{page}","lowpoly_3d_models":"СкаÑаÑÑ %{count} VR / AR / низкополигоналÑÐ½Ð°Ñ %{tag} 3д моделей, гоÑовÑÑ
к виÑÑÑалÑной ÑеалÑноÑÑи, Ð¸Ð³Ñ Ð¸ дÑÑгиÑ
пÑиложений ÑеалÑного вÑемени, доÑÑÑÐ¿Ð½Ñ Ð² FBX, OBJ, MAX, 3DS, ÑоÑмаÑÑ Ñайлов C4D.%{page}","rigged_3d_models":"%{count} %{tag} ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ 3д модели, доÑÑÑпнÑе Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð² лÑбом ÑоÑмаÑе Ñайлов, в Ñом ÑиÑле FBX, OBJ, MAX, 3DS, C4D.%{page}"}},"title":{"download":"| ÑкаÑаÑÑ","files":"3д ÑайлÑ","formats":"%{format_upper} 3D модели","free":"ÐеÑплаÑнÑе 3D модели","free_printing":"ÐеÑплаÑнÑе модели Ð´Ð»Ñ 3D пÑинÑеÑа","free_tag":"ÐеÑплаÑнÑе %{selected_tag} 3д модели","general":"ÐÑоÑеÑÑионалÑнÑе 3D модели","high_poly":"%{selected_filter} 3д модели.","landing":{"animated_3d_models":"ÐнимиÑованнÑе 3D модели","lowpoly_3d_models":"ÐизкополигоналÑнÑе 3D модели","pbr_3d_models":"PBR 3D модели","rigged_3d_models":"Rigged 3D модели"},"low_poly":"%{selected_filter} 3д модели","newest_cg":"ÐовÑе и поÑледние 3д модели","newest_print":"ÐовÑе и поÑледние 3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","page_prefix":"Page %{page_number} ","pbr":"PBR 3д модели","printing":"Ðодели Ð´Ð»Ñ 3D пÑинÑеÑа","sales_cg":"СамÑе пÑодаваемÑе 3д модели","sales_print":"СамÑе пÑодаваемÑе 3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","software_page":"3D модели Ð´Ð»Ñ %{software}","tag_heading":{"cg":"ÐеÑплаÑнÑе %{tag} 3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","filter":"%{selected_filter} %{tag} 3д модели","general":"%{tag_cap}: %{rounded_count} 3D моделей","merged_premium_print_tag":"%{tag_cap}: модели Ð´Ð»Ñ 3D пÑинÑеÑа","merged_premium_tag":"%{tag_cap}: %{rounded_count} 3D моделей","printable":"%{tag_cap}: модели Ð´Ð»Ñ 3D пÑинÑеÑа"},"trending_cg":"ТÑендовÑе 3д модели","trending_print":"ТÑендовÑе 3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи"}},"cart":{"request_invoice_failed":"УпÑ. ЧÑо-Ñо поÑло Ð
16518½Ðµ Ñак.","request_invoice_successful":"ÐапÑÐ¾Ñ Ð½Ð° ÑÑÑÑ ÑÑпеÑно оÑпÑавлен.","shareable_cart_created":"ÐоÑзина ÑÑпеÑно поделена.","shareable_cart_failed":"УпÑ. ЧÑо-Ñо поÑло не Ñак.","subscription_covered_items_removed":"Удалено из коÑзинÑ: %{titles}. Уже вклÑÑено в ваÑÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑкÑ.","subscription_covered_order_refused":"ТепеÑÑ %{titles} вÑ
Ð¾Ð´Ð¸Ñ Ð² ваÑÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑкÑ, поÑÑÐ¾Ð¼Ñ Ð¾Ð¿Ð»Ð°Ñа не бÑла ÑпиÑана. СкаÑайÑе ÑеÑез подпиÑкÑ."},"categories":{"cg":{"header_title_html":"ÐÑоÑеÑÑионалÑнÑе 3D модели","text":"ÐайдиÑе нÑжнÑй 3D-конÑÐµÐ½Ñ Ð¸Ð¼ÐµÐ½Ð½Ð¾ под ваÑи задаÑи, вклÑÑÐ°Ñ AR/VR, игÑÑ, ÑекламÑ, ÑазвлеÑÐµÐ½Ð¸Ñ Ð¸ дÑÑгое."},"head-title":{"cg":"3D модели â ÑкаÑаÑÑ Ð±ÐµÑплаÑно или кÑпиÑÑ","cg-models":{"sort-by":{"newest":"ÐовÑе 3D-модели","top-selling":"СамÑе пÑодаваемÑе 3D-модели","trending":"ÐопÑлÑÑнÑе 3D-модели"}},"print":"Ðодели Ð´Ð»Ñ 3D пÑинÑеÑа â 3D модели Ð´Ð»Ñ Ð¿ÐµÑаÑи","print-models":{"sort-by":{"newest":"ÐовÑе модели Ð´Ð»Ñ 3D-пеÑаÑи","top-selling":"СамÑе пÑодаваемÑе модели Ð´Ð»Ñ 3D-пеÑаÑи","trending":"СамÑе попÑлÑÑнÑе модели Ð´Ð»Ñ 3D-пеÑаÑи"}},"product-type":{"plural":{"capital":{"cg":"3д модели","cg-merge-premium":"3D-модели â беÑплаÑнÑе и пÑемиÑм-загÑÑзки","print":"Ð¤Ð°Ð¹Ð»Ñ Ð¸ Ðодели Ð´Ð»Ñ 3D-ÐеÑаÑи","print-merge-premium":"%{tag} Ð¤Ð°Ð¹Ð»Ñ Ð´Ð»Ñ 3D-пеÑаÑи â беÑплаÑнÑе и пÑемиÑм-модели STL"},"lower":{"cg":"3д модели","print":"ÑÐ°Ð¹Ð»Ñ Ð¸ модели Ð´Ð»Ñ 3D-пеÑаÑи"}},"singular":{"capital":{"cg":"3д моделÑ","print":"ÐÐ¾Ð´ÐµÐ»Ñ Ð´Ð»Ñ 3д-пеÑаÑи"},"lower":{"cg":"3д моделÑ","print":"ÐÐ¾Ð´ÐµÐ»Ñ Ð´Ð»Ñ 3д-пеÑаÑи"}}}},"index":{"browse_all":"ÐÑоÑмоÑÑеÑÑ Ð²Ñе модели","info-section__description_1_html":"ÐокÑпайÑе или беÑплаÑно ÑкаÑивайÑе пÑоÑеÑÑионалÑнÑе 3D-модели Ð´Ð»Ñ CG-пÑоекÑов, видеопÑоизводÑÑва, анимаÑии, визÑализаÑий, игÑ, VR/AR и дÑÑгиÑ
нÑжд. Ð¤Ð°Ð¹Ð»Ñ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки в \u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eпопÑлÑÑнÑÑ
ÑоÑмаÑаÑ
\u003c/a\u003e: MAX, OBJ, FBX, 3DS, STL, C4D, BLEND, MA, MB и дÑÑгиÑ
. ÐÑли Ð²Ñ Ð¸ÑеÑе вÑÑокополигоналÑнÑе или real-time 3D-аÑÑеÑÑ â Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð¿ÐµÑÐµÐ´Ð¾Ð²Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñека ÑиÑÑового иÑÑкÑÑÑва под лÑбÑе задаÑи.","info-section__description_1_printable_html":"ÐÑоÑеÑÑионалÑнÑе 3D-ÑайлÑ, модели и оÑпеÑаÑки, гоÑовÑе Ð´Ð»Ñ Ð¿ÐµÑаÑи дома на наÑÑолÑнÑÑ
FDM или пÑомÑÑленнÑÑ
SLS 3D-пÑинÑеÑаÑ
, доÑÑÑÐ¿Ð½Ñ Ð² ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
, вклÑÑÐ°Ñ OBJ, \u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003e, WRL. ÐÑли Ð²Ñ Ð»ÑбиÑÐµÐ»Ñ 3D-пеÑаÑи, маÑÑеÑ, педагог или компаниÑ, занимаÑÑаÑÑÑ Ð¿ÑоÑоÑипиÑованием Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ 3D-пеÑаÑи, наÑи пÑедмеÑÑ Ð´ÐµÐºÐ¾Ñа Ð´Ð»Ñ Ð´Ð¾Ð¼Ð°, ÑÑилÑнÑе акÑеÑÑÑаÑÑ Ð´Ð»Ñ Ð³Ð°Ð´Ð¶ÐµÑов, ÑÑкие моднÑе изделиÑ, ÑникалÑнÑе ÑкÑаÑениÑ, меÑ
аниÑеÑкие деÑали и ÑазнообÑазие миниаÑÑÑ Ð¾Ð±ÑзаÑелÑно вдоÑ
новÑÑ Ð²Ð°Ñ.","info-section__heading_1_html":"ÐÑÑледÑйÑе \u003cstrong\u003eкаÑегоÑии\u003c/strong\u003e 3D-моделей","info-section__heading_1_printable_html":"ÐоÑмоÑÑеÑÑ \u003cstrong\u003eкаÑегоÑии\u003c/strong\u003e моделей Ð´Ð»Ñ 3д-пеÑаÑи","info-section__heading_2_html":"\u003cstrong\u003eÐаÑкеÑплейÑ\u003c/strong\u003e 3д моделей","info-section__heading_2_printable_html":"Ð ÑÑо \u003cstrong\u003eеÑÑ\u003c/strong\u003e?"},"marketplace":{"3d-printing":{"link_text":"ÐоказаÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ 3D-пеÑаÑи","text":"ÐайдиÑе 3D-модели Ð´Ð»Ñ Ñвоего 3D-пÑинÑеÑа.","title":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи"},"blender_text":"ÐÑкÑойÑе ÑÑÑÑÑи 3D-моделей Blender в ÑоÑмаÑе .blend.","browse":"ÐоказаÑÑ","cinema-4d_text":"ÐÑкÑойÑе ÑÑÑÑÑи вÑÑококаÑеÑÑвеннÑÑ
моделей Cinema 4D в ÑоÑмаÑе .c4d.","discounted":{"link_text":"ÐоÑмоÑÑеÑÑ 3д модели Ñо Ñкидкой","text":"ÐÑпиÑÑ Ð¿ÑоÑеÑÑионалÑнÑе 3д модели Ñо Ñкидкой.","title":"3д модели Ñо Ñкидкой"},"low-poly":{"link_text":"ÐоказаÑÑ low-poly 3D-модели","text":"Low-poly 3D-модели Ð´Ð»Ñ Ð²Ð¸Ð´ÐµÐ¾Ð¸Ð³Ñ, VR и AR-пÑиложений в ÑеалÑном вÑемени.","title":"Low-poly 3D-модели"},"pbr":{"link_text":"ÐоказаÑÑ PBR 3D-модели","text":"3D-модели Ñ ÑизиÑеÑки коÑÑекÑнÑм ÑендеÑингом.","title":"PBR 3D-модели"},"scripts_apps":{"link_text":"ÐоказаÑÑ Ð²Ñе","text":"СкÑипÑÑ Ð¸ Ð¿Ð»Ð°Ð³Ð¸Ð½Ñ Ð´Ð»Ñ Ð¿Ð¾Ð²ÑÑÐµÐ½Ð¸Ñ ÑÑÑекÑивноÑÑи 3D-пайплайна.","title":"СкÑипÑÑ Ð¸ пÑиложениÑ"},"sketchup_text":"ÐзÑÑиÑе огÑомнÑй вÑÐ±Ð¾Ñ Ð¼Ð¾Ð´ÐµÐ»ÐµÐ¹ Sketchup Ð´Ð»Ñ Ð°ÑÑ
иÑекÑÑÑÑ, инÑеÑÑеÑов и дизайна видеоигÑ.","textures":{"link_text":"ÐоказаÑÑ ÑекÑÑÑÑÑ","text":"ÐоÑовÑе ÑекÑÑÑÑÑ Ð´Ð»Ñ ÑÑкоÑÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´Ð³Ð¾Ñовки ваÑиÑ
3D-моделей.","title":"ТекÑÑÑÑÑ"},"zbrush_text":"ÐайдиÑе 3D-модели в ÑоÑмаÑе ZTL Ð´Ð»Ñ ÑиÑÑовой лепки, моделиÑованиÑ, ÑекÑÑÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸ покÑаÑки."},"meta-description":{"cg":"СкаÑайÑе или кÑпиÑе %{rounded_count} пÑоÑеÑÑионалÑнÑÑ
3D моделей. ÐеÑплаÑнÑе и плаÑнÑе 3д модели Ð´Ð»Ñ Ð¸Ð³Ñ, кино, VFX, AR/VR и 3D пеÑаÑи. FBX, OBJ, BLEND, GLB.","print":"СкаÑайÑе %{rounded_count} моделей Ð´Ð»Ñ 3д пÑинÑеÑа. ÐеÑплаÑнÑе и плаÑнÑе STL модели Ð´Ð»Ñ 3D пеÑаÑи: ÑигÑÑки, миниаÑÑÑÑ, декоÑ, запÑаÑÑи."},"more":{"designers":{"link_text":"ÐоказаÑÑ ÑпиÑок 3D-дизайнеÑов","text":"ÐÑбиÑайÑе из мÐ
16518½Ð¾Ð¶ÐµÑÑва поÑÑÑолио 3D-дизайнеÑов и найдиÑе именно Ñо, ÑÑо нÑжно Ð´Ð»Ñ Ð²Ð°Ñего пÑоекÑа.","title":"ÐайдиÑе лÑÑÑиÑ
3D-дизайнеÑов"},"projects":{"link_text":"УзнаÑÑ Ð±Ð¾Ð»ÑÑе о 3D-пÑоекÑаÑ
","text":"ÐаймиÑе опÑÑнÑÑ
3D-ÑÑиланÑеÑов и ÑеÑиÑе лÑбÑе задаÑи по 3D-моделиÑованиÑ.","title":"3D-пÑоекÑÑ Ð½Ð° CGTrader "},"visualization":{"link_text":"УзнаÑÑ Ð±Ð¾Ð»ÑÑе","text":"ÐÑевÑаÑиÑе Ñвои ÑоваÑÑ Ð² ÑоÑоÑеалиÑÑиÑнÑе 3D-модели Ð´Ð»Ñ e-commerce и дÑÑгиÑ
задаÑ.","title":"3D-визÑализаÑÐ¸Ñ Ð´Ð»Ñ e-Commerce"}},"navbar":{"aircraft":"ÐвиаÑиÑ","animal":"ÐивоÑнÑе","animals":"ÐивоÑнÑе","architectural":"ÐÑÑ
иÑекÑÑÑнÑе","art":"ÐÑкÑÑÑÑво","car":"ÐвÑомобилÑ","character":"ÐеÑÑонаж","exterior":"ÐкÑÑеÑÑеÑ","fashion":"Ðода","food":"Ðда","furniture":"ÐебелÑ","gadgets":"ÐаджеÑÑ","games-toys":"ÐгÑÑ Ð¸ игÑÑÑки","hobby-diy":"Хобби и DIY","house":"Ðом","household":"ÐомаÑнее Ñ
озÑйÑÑво","industrial":"ÐÑомÑÑленнÑе","interior":"ÐнÑеÑÑеÑ","jewelry":"ЮвелиÑнÑе изделиÑ","military":"ÐооÑÑженнÑе ÑилÑ","miniatures":"ÐиниаÑÑÑÑ","plant":"РаÑÑениÑ","science":"ÐаÑка","space":"ÐоÑмоÑ","vehicle":"ТÑанÑпоÑÑное ÑÑедÑÑво","watercraft":"ÐоднÑй ÑÑанÑпоÑÑ"},"print_models":{"hero_title_html":"Ðодели Ð´Ð»Ñ 3D пÑинÑеÑа","subtitle":"ÐайÑи ÑоÑно подÑ
одÑÑий конÑÐµÐ½Ñ Ð´Ð»Ñ 3д-пеÑаÑи под ваÑи ÑÑебованиÑ","title_html":"ÐÑпиÑÑ Ð¿ÑоÑеÑÑионалÑнÑе \u003cstrong\u003e3д модели Ð´Ð»Ñ Ð¿ÐµÑаÑи\u003c/strong\u003e"},"profile":{"collection":"3D-паки","free":"ÐеÑплаÑнÑе 3D модели","high_poly":"ÐÑÑокополигоналÑнÑе 3D модели","optimized":"ÐизкополигоналÑнÑе/PBR 3D модели","printable":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи"},"seo":{"cg":{"aircraft":"ÐÑа каtagоÑÐ¸Ñ Ð¾Ñ
ваÑÑÐ²Ð°ÐµÑ 3д ÑамолеÑов. CG { \"slug\": \"СамолеÑ\", \"title\": \"ÑамолеÑÑ\"} бÑÐ´ÐµÑ Ð²Ð¿Ð¸ÑÑваÑÑÑÑ Ð² ÑимÑлÑÑии, визÑализаÑиÑ, ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ видео. { \"slug\": \"дÑон\", \"title\": \"ÐÑон\"} оÑÐ³Ð°Ð½Ñ Ð¸ ÑаÑÑи бÑдÑÑ ÑадоваÑÑ Ð¿Ð¾ÐºÐ»Ð¾Ð½Ð½Ð¸ÐºÐ¾Ð² кÑоÑеÑнÑÑ
леÑаÑелÑнÑÑ
аппаÑаÑов. Ð { \"slug\": \"СамолеÑ\", \"title\": \"ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¼Ð¾Ð´ÐµÐ»Ð¸\", \"active_filter\": \"ÑÑалÑÑиÑиÑиÑовано\"} гоÑÐ¾Ð²Ñ Ð±ÑÑÑ Ð¸Ð¼Ð¿Ð¾ÑÑиÑовано в игÑовÑе ÑиÑÑемÑ.\n","animals":"ÐоллекÑÐ¸Ñ 3д ÑаÑÐ½Ñ - { \"slug\": \"коÑÑ\", \"title\": \"ÐоÑÑ\"}, { \"slug\": \"лоÑадÑ\", \"title\": \"лоÑадей\"}, { \"slug\": \"медведÑ\" , \"title\": \"медведи\"}, { \"slug\": \"ноÑоÑог\", \"title\": \"ноÑоÑоги\"}, { \"slug\": \"оÑел\", \"title\": \"оÑлÑ\"}, { \"slug\" : \"лев\", \"title\": \"лÑвÑ\"} и болÑÑе - можно найÑи здеÑÑ. Ð CG 3д живоÑнÑе бÑдÑÑ ÑдовлеÑвоÑÑÑÑ Ð¿Ð¾ÑÑебноÑÑи ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸Ð»Ð¸ ÑÑаÑиÑеÑкиÑ
ÑÑен. ÐÑ Ñакже имеем { \"slug\": \"живоÑное\", \"title\": \"анимиÑÐ¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¶Ð¸Ð²Ð¾Ñное\", \"active_filter\": \"ÑÑалÑÑиÑиÑиÑовано\"} Ð¼Ð¾Ð´ÐµÐ»Ñ Ð´Ð»Ñ Ð¸Ð³Ñ.\n","architectural":"{ \"slug\": \"леÑÑниÑа\", \"title\": \"ÐеÑÑниÑа\" }, { \"slug\": \"камин\"}, 3д модели, а Ñакже ÑкÑаÑениÑ, как { \"slug\": \"кадÑ\"}, { \"slug\": \"подÑÑкÑ\"}, или { \"slug\": \"лампа\"} можно найÑи в обÑиÑной аÑÑ
иÑекÑÑÑной каtagоÑии деÑали авÑÐ¾Ð¼Ð¾Ð±Ð¸Ð»Ñ ÑодеÑÐ¶Ð¸Ñ Ð°Ð²ÑомобилÑнÑе 3д модели, { \"slug\": \"маÑина\", \"title\": \"низкополигоналÑное\", \"active_filter \": \"low_poly\"} Ð¼Ð¾Ð´ÐµÐ»Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñеки. ÐнÑеÑÑÐµÑ Ð¸ ÑкÑÑеÑÑÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ÑполÑзован Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ°Ðº ÑиÑÑовÑе, кÑÑ
ни и ÑпалÑни, а Ñакже замок номеÑа и подземелий ли Ð²Ñ Ð°ÑÑ
иÑекÑоÑ, Ð¸Ð½Ð¶ÐµÐ½ÐµÑ Ð¸Ð»Ð¸ инди-ÑазÑабоÑÑик компÑÑÑеÑнÑÑ
игÑ.\n","car":"ÐаtagоÑÐ¸Ñ Ð°Ð²Ñомобилей ÑодеÑÐ¶Ð¸Ñ Ð°Ð²ÑомобилÑнÑÑ 3д модели, \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e низкополигоналÑной \u003c/a\u003e веÑÑии, коÑоÑÑе бÑÐ´ÐµÑ Ð¿ÑивлекаÑелÑна Ð´Ð»Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑов игÑÑ, дÑÑгой - кинемаÑогÑаÑиÑÑÑ Ð¸Ð»Ð¸ ÑекламодаÑелей. ÐÑ ÐºÐ»Ð°ÑÑиÑеÑкиÑ
авÑомобилей до гоноÑнÑÑ
авÑомобилей и пÑÑевÑÑ
к конÑепÑии ÑеÑ
, ÑÑо еÑÑÑ Ð±Ð¾Ð»ÑÑое ÑазнообÑазие моделей 3д авÑо.\n","character":"Ð ÑÑой каtagоÑии Ð²Ñ Ð½Ð°Ð¹Ð´ÐµÑе 3д модели { \"slug\": \"Ñеловека\"}, лÑди, наÑÑной ÑанÑаÑÑики, Ð¾Ð´ÐµÐ¶Ð´Ñ Ð¸ дÑÑгиÑ
. С { \"slug\": \"ÑеÑдÑе\"} и { \"slug\": \"ÑÑка\"} деÑалÑÐ½Ð¾Ð¼Ñ ÑеалиÑÑиÑеÑкой { \"slug\": \"мÑжÑкой\"} или { \"slug\": \"женÑкий\"} моделей. Ð Ñд моделей ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¸ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð»ÐµÐ³ÐºÐ¾ добавлен к ваÑей игÑе или анимаÑии.\n","electronics":"ÐлекÑÑоника каtagоÑÐ¸Ñ Ð´Ð»Ñ Ð°ÑÑ
иÑекÑоÑов, декоÑаÑоÑов, дизайнеÑов ÑÑовней, ÑÑководиÑелей ÑÑÐµÐ½Ñ Ð¸ дÑÑгиÑ
обÑÑвлений. 3д Ð¼Ð¾Ð´ÐµÐ»Ñ { \"slug\": \"ÑмаÑÑÑон\", \"названиÑ\": \"ÑмаÑÑÑонÑ\"}, { \"slug\": \"ноÑÑбÑк\", \"title\": \"ноÑÑбÑки\"}, { \"slug\": \"камеÑа\", \"title\":\"камеÑа\"}, {\"slug\":\"ТÐ\",\"title\":\"ÑелевизоÑÑ\"} и многим дÑÑгим Ð¿Ð¾Ð¼Ð¾Ð¶ÐµÑ ÑоÑно заÑ
ваÑиÑÑ Ð¾Ð´ÐµÑжимоÑÑÑ ÑовÑеменной жизни Ñ ÑÑÑÑойÑÑвами и ÑеÑ
нологиÑми.\n","engineering-parts":"Ðкна, ÑÑÑбопÑоводÑ, ÑаздвижнÑе меÑ
Ð°Ð½Ð¸Ð·Ð¼Ñ Ð´Ð²ÐµÑи и дÑÑгие биÑÑ, коÑоÑÑе необÑ
Ð¾Ð´Ð¸Ð¼Ñ Ð´Ð»Ñ CAD пÑоекÑов и даже DIY Ð¿Ð»Ð°Ð½Ñ Ð¿Ð¾Ð´Ð¿Ð°Ð´Ð°ÑÑ Ð¿Ð¾Ð´ ÑÑÑ ÐºÐ°tagоÑиÑ. ÐдеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи 3д модели Ð¾Ñ Ð¼Ð¸ÑовÑÑ
пÑоизводиÑелей, ÑакиÑ
как ÐнвеÑ, Dynatec и FCi.\n","exterior":"ÐÐ±Ð·Ð¾Ñ Ð°ÑÑ
иÑекÑÑÑнÑÑ
ÑкÑÑеÑÑеÑÑ Ð¾Ñ ÑаÑадов, гоÑодÑкие Ð·Ð´Ð°Ð½Ð¸Ñ Ð´Ð¾ ландÑаÑÑнÑÑ
обÑекÑов, жилÑÑ
домов, пÑомÑÑленнÑÑ
ÑооÑÑжений и полномаÑÑÑабной 3д { \"slug\": \"гоÑод\"} моделей. ÐекоÑоÑÑе из акÑивов низкополигоналÑнÑе и могÑÑ Ð¿Ð¾Ð¼Ð¾ÑÑ Ð²Ð°Ð¼ завеÑÑиÑÑ Ð¸Ð³ÑÑ Ð¸Ð»Ð¸ пÑиложение VR / AR.\n","food":"Ðда Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ ÑоздаваÑÑ ÑеалиÑÑиÑнÑе ÑÑÐµÐ½Ñ Ð´Ð¾Ð¼Ð°Ñней жизни. 3д ÑÑÑкÑÑ, овоÑи, напиÑки и пиÑание вÑе здеÑÑ. ÐбÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑеÑÑоÑанов, AR пÑиложений Ð´Ð»Ñ Ð·Ð´Ð¾Ñового пиÑаниÑ. ÐÑли Ð²Ñ Ð¸Ñкали 3д { \"slug\": \"пиÑÑа\"} или ÑвадебнÑÑ { \"slug\": \"ÑоÑÑ\"} моделÑ, они здеÑÑ.\n","furniture":"3д ÑÑолÑ, ÑÑÑлÑÑ, диванÑ, кÑоваÑи в ÑазлиÑнÑÑ
ÑекÑÑÑÑ (деÑево, меÑалл и Ñ.д.) и ÑÑилей ({ \"slug\": \"ÑеÑÑо\"}, { \"slug\": \"ÑовÑеменнÑÑ
\"} и Ñ.д.), на- ÑÑка. ÐÑа каtagоÑÐ¸Ñ Ð¿ÑедназнаÑена Ð´Ð»Ñ Ð²ÑеÑ
, кÑо занимаеÑÑÑ Ñ Ð°ÑÑ
иÑекÑÑÑой и дизайном инÑеÑÑеÑа, а Ñакже ÑекламодаÑелей.\n","furniture-set":"ÐÑли вам нÑжно, Ñак глÑÐ´Ñ Ð°Ð½ÑикваÑнÑй ÑÑÑл и диван, глÑдÑ, или полнÑй Ð½Ð°Ð±Ð¾Ñ ÐºÑÑ
онной поÑÑдÑ, ÑÑо Ð¸Ð¼ÐµÐµÑ Ð¼ÐµÑÑо бÑÑÑ Ð² ÑÑой каtagоÑии ÑобиÑаÑÑ Ð½Ð°Ð±Ð¾ÑÑ 3д моделей мебели из кÑÑ
ни и гоÑÑиной в оÑÐ¸Ñ Ð¸ ÑÑоловой гаÑниÑÑÑов. ÐÑо Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ Ð¸Ð½ÑеÑÑеÑÑ Ð¸Ð»Ð¸ Ð´Ð¸Ð·Ð°Ð¹Ð½Ñ ÑÑÐ¾Ð²Ð½Ñ ÑпеÑиалиÑÑа ÑбоÑка номеÑÑ Ñ ÑооÑвеÑÑÑвÑÑÑими ÑлеменÑами.\n","household":"ÐÑÑÐ¾Ð²Ð°Ñ Ð¿ÑÐ½ÐºÑ 3д модели иÑполÑзÑÑÑÑÑ, ÑÑÐ¾Ð±Ñ Ð´Ð°ÑÑ Ð¿Ð¾Ð´ÑобнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð² номеÑа. ÐÑ Ð¼Ð¾Ð¶ÐµÑе поÑÑавиÑÑ Ð¾Ð±ÐµÐ´ÐµÐ½Ð½Ñй Ð½Ð°Ð±Ð¾Ñ 3д на ÑÑоле, или пеÑÐµÑ Ð¸ ÑÐ¾Ð»Ñ ÐºÐ¾Ð½ÑейнеÑÑ Ð¿Ð¾Ð»Ð½Ð¾Ð³Ð¾ инÑеÑÑеÑа кÑÑ
ни, Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑавиÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе { \"slug\": \"ÑвеÑ\", \"title\": \"огни\"} и { \"slug\": \"ÑвеÑÑ\"} возле кÑоваÑи, ÑÑÐ¾Ð±Ñ ÑоздаÑÑ Ð¾ÑÑÑение ÑоÑкоÑи.\n","industrial":"СÑÑоиÑелÑнÑе маÑеÑиалÑ, { \"slug\": \"инжиниÑинг\"} инÑÑÑÑменÑÑ, маÑина и { \"slug\": \"конÑейнеÑ\", \"title\": \"конÑейнеÑÑ\"}, коÑоÑÑе обеÑпеÑиваÑÑ ÐºÐ°Ðº ÑкологиÑеÑкие даннÑе и инÑеÑакÑивнÑе, ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ ÑлеменÑÑ. ÐÑо идеалÑно подÑ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ ÑазÑабоÑÑиков моделиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð³ÑÑ Ð¸Ð»Ð¸ лÑдей, ÑÑÑоÑÑиÑ
{ \"slug\": \"ÑÑÑоиÑелÑÑÑво\"} ÑÑÐ¾Ð²Ð½Ñ Ð´Ð²Ð¾Ñа.\n","interior":"ÐÑа каtagоÑÐ¸Ñ ÑодеÑÐ¶Ð¸Ñ ÑеалиÑÑиÑнÑе 3д ÑлеменÑÑ Ð¸ деÑали аÑÑ
иÑекÑÑÑÑ, ÑÑÑоиÑелÑÑÑва и инженеÑного дизайна инÑеÑÑеÑа. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ ÑÑи 3д модели Ð´Ð»Ñ Ð°Ð½Ð¸Ð¼Ð°Ñии или Ð¸Ð³Ñ - некоÑоÑÑе из ниÑ
ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð¸ низкополигоналÑнÑе.\n","military":"Ð ÑÑой каtagоÑии Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе кÑпиÑÑ 3д модели оÑÑжиÑ, оÑÑжие, { \"title\": \"меÑи\", \"slug\": \"меÑ\"} и аÑÑиллеÑии как ÑовÑеменнÑе и иÑÑоÑиÑеÑкиÑ
иÑполÑзÑеÑÑÑ Ð²Ð¾Ð¾ÑÑженнÑми Ñилами и ÑамообоÑоной. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ð´Ð»Ñ Ð¸Ð³Ñ - некоÑоÑÑе из ниÑ
ÑвлÑÑÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ÑголÑниками ÐпÑимизиÑованнÑе и гоÑовÑе Ð´Ð»Ñ Ð¸Ð³ÑовÑÑ
движков.\n","plant":"ÐÑа каtagоÑÐ¸Ñ ÑодеÑÐ¶Ð¸Ñ 3д модели ÑаÑÑений оÑганизмов, Ñакие как ÑвеÑÑ, { \"slug\": \"деÑево\", \"title\": \"деÑева\"}, ÑÑава, лианÑ, зеленÑ, ÑÑавÑ, многолеÑники, ÑаженÑÑ, побеги, кÑÑÑаÑники, пÑомаÑ
и, ÑаÑÑадÑ, лозÑ, ÑоÑнÑки. ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ ÐºÑпиÑÑ Ð¸Ð»Ð¸ ÑкаÑаÑÑ Ð±ÐµÑплаÑно 3д модели, пÑоÑмаÑÑиваÑÑ ÐºÐ°tagоÑии ниже.\n","scanned":"ÐоделÑеÑÑ ÑоздаÑÑ ÑÑи модели Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ 3д ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÑеÑ
нологий, ÑакиÑ
как RealSense. Ðни, ÑÑаÑÑи, даже мÑжÑÐ¸Ð½Ñ Ð¸ женÑÐ¸Ð½Ñ Ð¿Ð¾Ð»ÑзÑÑÑÑÑ Ð¿Ð¾slugÑноÑÑÑÑ Ð·Ð´ÐµÑÑ. ÐÑодÑÐºÑ Ð³Ð¾Ñов к иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² ÑÑенаÑ
и анимаÑии, пÑÐµÐ´Ð»Ð°Ð³Ð°Ñ Ð½ÐµÐ¿ÑевзойденнÑй ÑÑÐ¾Ð²ÐµÐ½Ñ Ñеализма.\n","scie
16518nce":"ÐÑа каtagоÑÐ¸Ñ ÑодеÑÐ¶Ð¸Ñ 3д модели, оÑноÑÑÑиеÑÑ Ðº медиÑине, биологии, Ñизике, Ñ
имии и ÑеÑ
нологии, Ñакие как лабоÑаÑоÑное обоÑÑдование, микÑоÑкопиÑеÑкиÑ
Ñел и ÑÑбаÑомном миÑе. ÐÐµÑ Ð½ÐµÐ¾Ð±Ñ
одимоÑÑи иÑкаÑÑ Ð´Ð°Ð»ÑÑе, { \"slug\": \"ÑÑейки\"}, { \"slug\": \"ÑеÑеп\"} и { \"slug\": \"ÑкелеÑ\"} 3д-модели можно найÑи здеÑÑ.\n","scripts-plugins":"СÑенаÑии и Ð¿Ð»Ð°Ð³Ð¸Ð½Ñ Ð¾Ð±ÐµÑпеÑиваÑÑ Ð²Ð°Ð¼ ÑÑлÑки пÑогÑамм. ÐоделиÑование, ÑендеÑинг, ÑекÑÑÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ - вÑе ÑÑо можно ÑделаÑÑ Ð¿ÑоÑе Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¿Ð»Ð°Ð³Ð¸Ð½Ð¾Ð², коÑоÑÑе пÑиÑ
одÑÑ Ð´Ð»Ñ Ð²ÑеÑ
видов пÑогÑаммного обеÑпеÑениÑ, как Maya и V-Ray.\n","space":"ÐÑоÑÑÑанÑÑво каtagоÑÐ¸Ñ Ð¿Ð¾Ð»Ð½Ð° низкополигоналÑного, игÑовÑе гоÑовÑе модели ÑанÑаÑÑики { \"slug\": \"коÑмиÑеÑкий коÑаблÑ\", \"ÑиÑÑл\": \"коÑмиÑеÑкие коÑабли\"}, { \"slug\": \"аÑÑеÑоид\", \"ÑиÑÑл\": \"аÑÑеÑÐ¾Ð¸Ð´Ñ \"}, планеÑÑ (в Ñом ÑиÑле {\"slug\":\"землей\",\"title\":\"земли\"} и ÑеалиÑÑиÑеÑкого пÑоÑÑÑанÑÑва {\"slug\":\"Ñелнока\",\"title\":\" Ñелноки\"} Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ Ñ Ð½Ð°ÑÑной ÑоÑки зÑÐµÐ½Ð¸Ñ Ð½Ð°ÐºÐ»Ð¾Ð½ÐµÐ½Ð° 3д коÑмиÑеÑкие модели Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ Ð´Ð»Ñ VR пÑоÑÑÑанÑÑва ÑимÑлÑÑоÑов.\n","sport-hobby":"ÐÑа каtagоÑÐ¸Ñ Ð¾Ñ
ваÑÑ- ниÑего, ÑÑо ÑвÑзано Ñ { \"slug\": \"поле\"} ÑобÑÑиÑ, ÑпоÑÑ Ð¸ Ñ
обби в Ñелом. С { \"slug\": \"ÑÑÑбол\"} и лÑжнÑе ÑÐºÐ»Ð¾Ð½Ñ Ð´Ð¾ { \"slug\": \"гиÑаÑÑ\"} и { \"slug\": \"ÑоÑÑепиано\"}, ÑÑи полезнÑе 3д модели Ð´Ð»Ñ ÑекламÑ, ÑÑен и анимаÑии. ÐизкополигоналÑнÑÑ
веÑÑии еÑÑÑ Ð´Ð»Ñ ÑпоÑÑа видеоигÑ.\n","textures":"ÐÑоÑмоÑÑ ÑеÑез библиоÑÐµÐºÑ ÐºÑаÑиво ÑделаннÑе 3д маÑеÑиалов и найÑи ÑамÑе подÑ
одÑÑие, гоÑовÑе к иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑекÑÑÑÑ Ð¿Ð¾Ð´Ð³Ð¾ÑовиÑÑ \u003ca href=\"%{link_to_low_poly_items_url}\"\u003e игÑÑ Ð³Ð¾Ñова \u003c/a\u003e или ÑоÑоÑеалиÑÑиÑнÑе модели, обновиÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑÐµÐºÑ Ð°ÐºÑивов , а Ñакже ÑлÑÑÑиÑÑ Ñвои 3д ÑабоÑÑ.\n","various":"ÐÑо 3д-модели, коÑоÑÑе не легко впиÑÑваÑÑÑÑ Ð² дÑÑгие каtagоÑии, поÑÑÐ¾Ð¼Ñ Ð¼Ñ Ñоздали один, коÑоÑÑй пÑинÑл Ð±Ñ Ð¸Ñ
вÑеÑ
. { \"title\": \"Rocks\", \"slug\": \"камни\"}, { \"slug\": \"облака\"}, { \"title\": \"логоÑипÑ\", \"slug\": \"логоÑип\"}, { \"title\" : \"зонÑики\", \"slug\": \"зонÑик\"} и дÑÑгие не клаÑÑиÑиÑиÑован 3д Ð¼Ð¾Ð´ÐµÐ»Ñ Ð·Ð´ÐµÑÑ.\n","vehicle":"ÐÑÑзовÑе авÑомобили, { \"title\": \"ÑкоÑÐ°Ñ Ð¿Ð¾Ð¼Ð¾ÑÑ\", \"slug\": \"ÑкоÑой помоÑи\"}, авÑобÑÑÑ, поезда, ÑÑакÑоÑÑ, { \"title\": \"велоÑипедÑ\", \"slug\": \"велоÑипед\"} и моÑоÑиклов - ÑÑо каtagоÑÐ¸Ñ Ð´Ð»Ñ Ð»Ñди, коÑоÑÑе Ñ
оÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¸Ñ
гоÑодÑкие ÑлиÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ñ ÑеалиÑÑиÑнÑми и Ð
16518½Ð°ÑÑно-ÑанÑаÑÑиÑеÑкими ÑÑанÑпоÑÑнÑми ÑÑедÑÑвами, а Ñакже Ð´Ð»Ñ ÑеÑ
, кÑо Ð´ÐµÐ»Ð°ÐµÑ Ð¸Ð¼Ð¸ÑаÑионнÑе игÑÑ Ð¸Ð»Ð¸ ÑоÑмаÑиÑование плакаÑÑ.\n","watercraft":"СÑдовÑе покÑÑÑÐ¸Ñ { \"title\": \"лодка\", \"slug\": \"лодка\"}, { \"title\": \"ÑÑ
Ñа\", \"slug\": \"ÑÑ
Ñа\"}, { \"title\": \"коÑабли\", \"slug\" : \"коÑаблÑ\"} и дÑÑгие воднÑе ÑÑанÑпоÑÑнÑе ÑÑедÑÑва. СÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ 3д модели бÑдÑÑ Ð´ÐµÐ»Ð°ÑÑ Ñ
оÑоÑо в видеоигÑаÑ
, анимаÑии в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº модели CG еÑÑÑ Ð´Ð»Ñ Ð²Ð°ÑиÑ
ÑÑен или дÑÑгиÑ
пÑиложений, где визÑалÑÐ½Ð°Ñ ÑоÑноÑÑÑ Ð²Ð°Ð¶Ð½ÐµÐµ Polycount.\n"},"forwarded":{"cg":{"aircraft":"ÐÑа каÑегоÑÐ¸Ñ Ð²ÐºÐ»ÑÑÐ°ÐµÑ 3D-модели авиаÑии. СамолÑÑÑ Ð¿Ð¾Ð´Ð¾Ð¹Ð´ÑÑ Ð´Ð»Ñ ÑимÑлÑÑий, визÑализаÑий, ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ видео. ÐÑÐ¾Ð½Ñ Ð¸ ÑаÑÑи к ним поÑадÑÑÑ ÑанаÑов миниаÑÑÑной воздÑÑной ÑеÑ
ники. Также еÑÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ Ñ Ñиггом, гоÑовÑе Ð´Ð»Ñ Ð¸Ð³ÑовÑÑ
движков.","animals":"ÐдеÑÑ Ð²Ñ Ð½Ð°Ð¹Ð´ÑÑе 3D-модели ÑаÑнÑ: коÑек, лоÑадей, медведей, ноÑоÑогов, оÑлов, лÑвов и дÑÑгиÑ
. ÐодÑ
одÑÑ Ð´Ð»Ñ ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ ÑÑен. ÐдеÑÑ Ð²Ñ Ñакже найдеÑе модели живоÑнÑÑ
Ñ Ñиггом, гоÑовÑе Ð´Ð»Ñ Ð¸Ð³ÑовÑÑ
движков.","architectural":"ÐеÑÑниÑÑ, ÐºÐ°Ð¼Ð¸Ð½Ñ Ð¸ дÑÑгие 3D-модели, а Ñакже декоÑаÑивнÑе ÑлеменÑÑ â Ñамки, подÑÑки, Ð»Ð°Ð¼Ð¿Ñ â доÑÑÑÐ¿Ð½Ñ Ð² обÑиÑной библиоÑеке аÑÑ
иÑекÑÑÑнÑÑ
деÑалей. ÐнÑеÑÑеÑнÑе и ÑкÑÑеÑÑеÑнÑе модели подойдÑÑ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑиÑÑовÑÑ
кÑÑ
онÑ, Ñпален, замковÑÑ
залов или подземелий â бÑÐ´Ñ Ð²Ñ Ð°ÑÑ
иÑекÑоÑом, инженеÑом или инди-ÑазÑабоÑÑиком игÑ.","car":"ÐаÑегоÑÐ¸Ñ Ð²ÐºÐ»ÑÑÐ°ÐµÑ 3D-модели авÑомобилей, вклÑÑÐ°Ñ Ð½Ð¸Ð·ÐºÐ¾Ð¿Ð¾Ð»Ð¸Ð³Ð¾Ð½Ð°Ð»ÑнÑе. ÐодÑ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ Ð¸Ð³Ñ, ÑилÑмов и ÑÐµÐºÐ»Ð°Ð¼Ñ â Ð¾Ñ ÐºÐ»Ð°ÑÑики до гоноÑнÑÑ
и конÑепÑов. ÐдеÑÑ Ð²Ñ ÑможеÑе найÑи болÑÑое ÑазнообÑазие авÑомобилÑнÑÑ
3D-моделей!","character":"ÐдеÑÑ Ð²Ñ Ð½Ð°Ð¹Ð´ÑÑе 3Ð ÑÑой каÑегоÑии пÑедÑÑÐ°Ð²Ð»ÐµÐ½Ñ 3D-модели лÑдей, пеÑÑонажей, ÑлеменÑов наÑÑной ÑанÑаÑÑики, Ð¾Ð´ÐµÐ¶Ð´Ñ Ð¸ многого дÑÑгого. ÐÑ ÑеÑдÑа и ÑÑки до деÑализиÑованнÑÑ
ÑеалиÑÑиÑнÑÑ
мÑжÑкиÑ
и женÑкиÑ
моделей. ÐклÑÑÐ°Ñ Ð²ÐµÑÑии Ñ Ñиггом коÑоÑÑе Ñ Ð»ÐµÐ³ÐºÐ¾ÑÑÑÑ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð² ваÑей игÑе или анимаÑии.","electronics":"ÐлекÑÑоника - каÑегоÑÐ¸Ñ Ð´Ð»Ñ Ð°ÑÑ
иÑекÑоÑов, декоÑаÑоÑов, дизайнеÑов, ÑÑководиÑелей ÑÑÐµÐ½Ñ Ð¸ дÑÑгиÑ
ÑпеÑиалÑноÑÑей. 3д модели { \"slug\": \"smartphone\", \"title\": \"ÑмаÑÑÑонÑ\"}, { \"slug\": \"laptop\", \"title\": \"ноÑÑбÑки\"}, { \"slug\": \"camera\", \"title\":\"камеÑа\"}, {\"slug\": \"tv\",\"title\":\"ÑелевизоÑÑ\"} и многие дÑÑгие помогÑÑ ÑоÑно показаÑÑ Ð¾Ð´ÐµÑжимоÑÑÑ ÑовÑеменной жизни ÑÑÑÑойÑÑвами и ÑеÑ
нологиÑми.\n","engineering-parts":"Ðод ÑÑÑ ÐºÐ°ÑегоÑÐ¸Ñ Ð¿Ð¾Ð¿Ð°Ð´Ð°ÑÑ Ð¾ÐºÐ½Ð°, ÑÑÑбопÑоводÑ, меÑ
Ð°Ð½Ð¸Ð·Ð¼Ñ ÑаздвижнÑÑ
двеÑей и дÑÑгие деÑали, необÑ
одимÑе Ð´Ð»Ñ CAD-пÑоекÑов и даже пÑоекÑов DIY. ÐдеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи 3д-модели Ð¾Ñ Ð¼Ð¸ÑовÑÑ
пÑоизводиÑелей, ÑакиÑ
как ANVER, Dynatec и FCi.","exterior":"ÐзнакомÑÑеÑÑ Ñ Ð°ÑÑ
иÑекÑÑÑнÑми ÑкÑÑеÑÑеÑами â Ð¾Ñ ÑаÑадов и гоÑодÑкиÑ
зданий до ландÑаÑÑнÑÑ
обÑекÑов, жилÑÑ
домов, пÑомÑÑленнÑÑ
поÑÑÑоек и полноÑеннÑÑ
3D-моделей гоÑодов. ÐекоÑоÑÑе аÑÑеÑÑ Ð¸Ð¼ÐµÑÑ Ð½Ð¸Ð·ÐºÐ¾Ðµ ÑиÑло полигонов и оÑлиÑно подойдÑÑ Ð´Ð»Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð¸Ñ Ð²Ð°Ñего игÑового или VR/AR-пÑоекÑа.","food":"Ðда Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ ÑоздаваÑÑ ÑеалиÑÑиÑнÑе ÑÑÐµÐ½Ñ Ð¿Ð¾Ð²Ñедневной жизни. ÐдеÑÑ Ð²Ñ Ð½Ð°Ð¹Ð´ÑÑе 3D-модели ÑÑÑкÑов, овоÑей, напиÑков и гоÑовÑÑ
блÑд. РеÑÑÑÑÑ Ð¿Ð¾Ð´Ð¾Ð¹Ð´ÑÑ Ð´Ð»Ñ ÑеÑÑоÑанной ÑекламÑ, AR-пÑиложений, поÑвÑÑÑннÑÑ
здоÑÐ¾Ð²Ð¾Ð¼Ñ Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ Ð¸ Ð
16518½Ðµ ÑолÑко. ХоÑиÑе 3D-пиÑÑÑ Ð¸Ð»Ð¸ ÑвадебнÑй ÑоÑÑ? ÐÑÑ ÑÑо â здеÑÑ.","furniture":"3д ÑÑолÑ, ÑÑÑлÑÑ, диванÑ, кÑоваÑи ÑазлиÑнÑÑ
ÑекÑÑÑÑ (деÑево, меÑалл и Ñ.д.) и ÑÑилей ({ \"slug\": \"retro\", \"title\": \"ÑеÑÑо\"}, { \"slug\": \"modern\", \"title\": \"ÑовÑеменнÑй\"} и Ñ.д.) под ÑÑкой. ÐÑа каÑегоÑÐ¸Ñ Ð¿ÑедназнаÑена Ð´Ð»Ñ Ð²ÑеÑ
, кÑо занимаеÑÑÑ Ð°ÑÑ
иÑекÑÑÑой и дизайном инÑеÑÑеÑа, а Ñакже Ð´Ð»Ñ ÑекламодаÑелей.\n","furniture-set":"ÐÑли вам нÑжно одинаково вÑглÑдÑÑее анÑикваÑное кÑеÑло и диван или полнÑй Ð½Ð°Ð±Ð¾Ñ ÐºÑÑ
онной ÑÑваÑи, ÑÑо Ñо меÑÑо, где Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ÑÑо вÑÑ Ð½Ð°Ð¹Ñи, поÑколÑÐºÑ ÑÑа каÑегоÑÐ¸Ñ ÑобиÑÐ°ÐµÑ Ð½Ð°Ð±Ð¾ÑÑ 3д-моделей мебели Ð¾Ñ ÐºÑÑ
ни и гоÑÑиной до оÑиÑнÑÑ
и обеденнÑÑ
набоÑов мебели. ÐÑо Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ ÑпеÑиалиÑÑÑ Ð¿Ð¾ Ð´Ð¸Ð·Ð°Ð¹Ð½Ñ Ð¸Ð½ÑеÑÑеÑа или ÑпеÑиалиÑÑÑ Ð´ÑÑгого ÑÑÐ¾Ð²Ð½Ñ Ð¿Ð¾ÑÑÑоиÑÑ ÐºÐ¾Ð¼Ð½Ð°ÑÑ Ñ ÑооÑвеÑÑÑвÑÑÑими ÑлеменÑами.","household":"3D-модели пÑедмеÑов бÑÑа помогаÑÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÑÑÑ Ð´ÐµÑализаÑÐ¸Ñ Ð² инÑеÑÑеÑ. ÐÑ Ð¼Ð¾Ð¶ÐµÑе поÑÑавиÑÑ ÑеÑвиз на ÑÑол, добавиÑÑ Ð±Ð°Ð½Ð¾Ñки Ñ ÑолÑÑ Ð¸ пеÑÑем на кÑÑ
не или ÑазмеÑÑиÑÑ ÑвеÑилÑники и ÑвеÑÑ Ñ ÐºÑоваÑи, ÑÑÐ¾Ð±Ñ ÑоздаÑÑ Ð¾ÑÑÑение ÑÑÑа и ÑоÑкоÑи.","industrial":"СÑÑоиÑелÑнÑе маÑеÑиалÑ, инженеÑнÑе инÑÑÑÑменÑÑ, ÑеÑ
ника и конÑейнеÑÑ â вÑÑ ÑÑо добавлÑÐµÑ ÐºÐ°Ðº визÑалÑнÑе деÑали, Ñак и инÑеÑакÑивнÑе, ÑиггиÑованнÑе ÑлеменÑÑ. ÐдеалÑно подÑ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ ÑазÑабоÑÑиков ÑимÑлÑÑоÑов и ÑеÑ
, кÑо ÑоздаÑÑ ÑÑовни Ñо ÑÑÑоиÑелÑнÑми плоÑадками.","interior":"Ð ÑÑой каÑегоÑии ÑобÑÐ°Ð½Ñ ÑеалиÑÑиÑнÑе 3D-ÑлеменÑÑ Ð¸ деÑали аÑÑ
иÑекÑÑÑÑ, ÑÑÑоиÑелÑÑÑва и инженеÑного дизайна инÑеÑÑеÑов. ÐÑи модели можно иÑполÑзоваÑÑ Ð² анимаÑии или игÑаÑ
â некоÑоÑÑе из ниÑ
Ñ Ñиггоми опÑимизиÑÐ¾Ð²Ð°Ð½Ñ Ð¿Ð¾ полигонам.","military":"Ð ÑÑой каÑегоÑии Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑиобÑеÑÑи 3D-модели оÑÑжиÑ, меÑей, аÑÑиллеÑии и дÑÑгого вооÑÑÐ¶ÐµÐ½Ð¸Ñ â как ÑовÑеменного, Ñак и иÑÑоÑиÑеÑкого, иÑполÑзовавÑегоÑÑ Ð°ÑмиÑми или Ð´Ð»Ñ ÑамообоÑонÑ. Ðодели можно иÑполÑзоваÑÑ Ð² игÑаÑ
â многие из ниÑ
опÑимизиÑÐ¾Ð²Ð°Ð½Ñ Ð¿Ð¾ полигонам и гоÑÐ¾Ð²Ñ Ð´Ð»Ñ Ð¸Ð³ÑовÑÑ
движков.","plant":"ÐклÑÑÐ°ÐµÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ ÑлоÑÑ: ÑвеÑÑ, деÑевÑÑ, ÑÑава, кÑÑÑÑ, лианÑ, побеги и многое дÑÑгое. ÐÑ Ð¼Ð¾Ð¶ÐµÑе кÑпиÑÑ Ð¸Ð»Ð¸ беÑплаÑно ÑкаÑаÑÑ 3D-моделÑ.","scanned":"ÐизайнеÑÑ ÑоздаÑÑ ÑÑи модели Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑеÑ
нологий 3д ÑканиÑованиÑ, ÑакиÑ
как RealSense. Ðни, ÑÑаÑÑи, даже мÑжÑÐ¸Ð½Ñ Ð¸ женÑÐ¸Ð½Ñ Ð·Ð´ÐµÑÑ Ð¿Ð¾Ð»ÑзÑÑÑÑÑ Ð¿Ð¾Ð¿ÑлÑÑноÑÑÑÑ. ÐÑодÑÐºÑ Ð³Ð¾Ñов к иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² ÑÑенаÑ
и анимаÑии, пÑÐµÐ´Ð»Ð°Ð³Ð°Ñ Ð½ÐµÐ¿ÑевзойденнÑй ÑÑÐ¾Ð²ÐµÐ½Ñ Ñеализма.\n","science":"ÐÑа каÑегоÑÐ¸Ñ ÑодеÑÐ¶Ð¸Ñ 3д-модели, ÑвÑзаннÑе Ñ Ð¼ÐµÐ´Ð¸Ñиной, биологией, Ñизикой, Ñ
имией и ÑеÑ
нологиÑми, Ñакими как лабоÑаÑоÑное обоÑÑдование, микÑоÑкопиÑеÑкие Ñела и ÑÑбаÑомнÑй миÑ. ÐолÑÑе не иÑиÑе, {\"slug\": \"cell\"}, {\"slug\": \"skull\"} и {\"slug\": \"skeleton\"} 3д-модели можно найÑи здеÑÑ.","scripts-plugins":"СкÑипÑÑ Ð¸ Ð¿Ð»Ð°Ð³Ð¸Ð½Ñ Ð¾Ð±ÐµÑпеÑиваÑÑ Ð²Ð°Ñ Ð¿ÑогÑаммнÑми гоÑÑÑими клавиÑами. ÐоделиÑование, ÑендеÑинг, ÑекÑÑÑÑиÑование - вÑе ÑÑо можно ÑпÑоÑÑиÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¿Ð»Ð°Ð³Ð¸Ð½Ð¾Ð², коÑоÑÑе поÑÑавлÑÑÑÑÑ Ð´Ð»Ñ Ð²ÑеÑ
видов пÑогÑаммного обеÑпеÑениÑ, ÑакиÑ
как Maya и V-Ray.","space":"ÐоÑÐ¼Ð¾Ñ â ÑÑо каÑегоÑиÑ, Ð¿Ð¾Ð»Ð½Ð°Ñ Ð½Ð¸Ð·ÐºÐ¾Ð¿Ð¾Ð»Ð¸Ð³Ð¾Ð½Ð°Ð»ÑнÑÑ
, гоÑовÑÑ
к иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² игÑаÑ
3D моделей наÑÑно-ÑанÑаÑÑиÑеÑкиÑ
коÑмиÑеÑкиÑ
коÑаблей, аÑÑеÑоидов, Ð¿Ð»Ð°Ð½ÐµÑ (вклÑÑÐ°Ñ ÐÐµÐ¼Ð»Ñ Ð¸ ÑеалиÑÑиÑнÑе коÑмиÑеÑкие Ñелноки Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ наÑÑного пÑименениÑ). Также Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² коÑмиÑеÑкиÑ
ÑимÑлÑÑоÑаÑ
виÑÑÑалÑной ÑеалÑноÑÑи.","sport-hobby":"ÐÑа каÑегоÑÐ¸Ñ Ð¾Ñ
ваÑÑÐ²Ð°ÐµÑ Ð²Ñе, ÑÑо ÑвÑзано Ñ { \"slug\": \"field\",\"title\": \"поле\"} ÑобÑÑиÑми, ÑпоÑÑом и Ñ
обби в Ñелом. ÐÑ { \"slug\": \"football\",\"title\": \"ÑÑÑбол\"} и лÑжнÑÑ
Ñклонов до { \"slug\": \"guitar\",\"title\": \"гиÑаÑÑ\"} и { \"slug\": \"piano\",\"title\": \"ÑоÑÑепиано\"}, ÑÑо полезнÑе 3д модели Ð´Ð»Ñ ÑекламÑ, ÑÑен и анимаÑии. ÐизкополигоналÑнÑе веÑÑии еÑÑÑ Ð´Ð»Ñ ÑпоÑÑа и видеоигÑ.\n","textures":"ÐÑоÑмаÑÑивайÑе библиоÑÐµÐºÑ ÑÑаÑелÑно пÑоÑабоÑаннÑÑ
3D-маÑеÑиалов и наÑ
одиÑе гоÑовÑе к иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑекÑÑÑÑÑ, идеалÑно подÑ
одÑÑие Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð³ÑовÑÑ
или ÑоÑоÑеалиÑÑиÑнÑÑ
моделей, ÑаÑÑиÑÐµÐ½Ð¸Ñ Ð²Ð°Ñей библиоÑеки аÑÑеÑов и ÑлÑÑÑÐµÐ½Ð¸Ñ 3D-пÑоекÑов.","various":"ÐÑо 3д модели, коÑоÑÑе не Ñак легко впиÑÑваÑÑÑÑ Ð² дÑÑгие каÑегоÑии, поÑÑÐ¾Ð¼Ñ Ð¼Ñ Ñоздали однÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð³ÑÑппиÑоваÑÑ Ð¸Ñ
вÑе. { \"title\": \"ÐоÑнÑе поÑодÑ\", \"slug\": \"rocks\"}
16518, { \"slug\": \"clouds\",\"title\": \"облака\"}, { \"title\": \"логоÑипÑ\", \"slug\": \"logo\"}, { \"title\" : \"зонÑики\", \"slug\": \"umbrella\"} и дÑÑгие не каÑегоÑизиÑованнÑе 3д модели Ð²Ñ Ð½Ð°Ð¹Ð´ÐµÑе здеÑÑ.\n","vehicle":"ÐÑÑзовики, маÑÐ¸Ð½Ñ ÑкоÑой помоÑи, авÑобÑÑÑ, поезда, ÑÑакÑоÑÑ, велоÑÐ¸Ð¿ÐµÐ´Ñ Ð¸ моÑоÑÐ¸ÐºÐ»Ñ â ÑÑа каÑегоÑÐ¸Ñ Ð´Ð»Ñ ÑеÑ
, кÑо Ñ
оÑÐµÑ Ð½Ð°Ð¿Ð¾Ð»Ð½Ð¸ÑÑ Ð³Ð¾ÑодÑкие ÑлиÑÑ ÑеалиÑÑиÑнÑм или ÑанÑаÑÑиÑеÑким ÑÑанÑпоÑÑом, а Ñакже Ð´Ð»Ñ ÑазÑабоÑÑиков ÑимÑлÑÑоÑов и ÑоздаÑелей поÑÑеÑов.","watercraft":"ÐаÑегоÑÐ¸Ñ Â«ÐоднÑй ÑÑанÑпоÑÑ» вклÑÑÐ°ÐµÑ Ð»Ð¾Ð´ÐºÐ¸, ÑÑ
ÑÑ, коÑабли и дÑÑгие плаваÑелÑнÑе ÑÑедÑÑва. РиггиÑованнÑе 3D-модели оÑлиÑно подойдÑÑ Ð´Ð»Ñ Ð²Ð¸Ð´ÐµÐ¾Ð¸Ð³Ñ Ð¸ анимаÑии, а CG-модели â Ð´Ð»Ñ ÑÑен и пÑоекÑов, где визÑалÑÐ½Ð°Ñ Ð´Ð¾ÑÑовеÑноÑÑÑ Ð²Ð°Ð¶Ð½ÐµÐµ колиÑеÑÑва полигонов."},"printable":{"art":"ÐдеÑÑ Ð½Ð°Ñ
одÑÑÑÑ Ñ
ÑдожеÑÑвеннÑе 3д-пÑинÑÑ. ÐÑиÑе необÑÑнÑй ÑкÑлÑпÑÑÑнÑй дизайн, воÑÑоздаÑÑий клаÑÑиÑеÑкие пÑÐ¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ ÑÑаÑÑи иÑÑоÑиÑеÑкиÑ
лиÑноÑÑей, или вдоÑ
новлÑÑÑие ÑÑаÑÑÑÑки, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ, даже логоÑÐ¸Ð¿Ñ Ð´Ð»Ñ 3д-пеÑаÑи? ÐÑо и еÑÑÑ Ð´Ð°Ð½Ð½Ð°Ñ ÐºÐ°ÑегоÑиÑ.","fashion":"ÐÑаÑивÑе и ÑÑилÑнÑе веÑи, коÑоÑÑе Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ноÑиÑÑ, Ð²Ñ Ð½Ð°Ð¹Ð´ÐµÑе в ÑÑой каÑегоÑии. ÐоÑмоÑÑиÑе, можеÑе ли Ð²Ñ Ð½Ð°Ð¹Ñи какое-либо пÑименение Ð´Ð»Ñ ÑанÑазийной коÑмиÑеÑкой {\"slug\": \"footwear\",\"title\": \"обÑви\"}, инноваÑионнÑÑ
оÑков и коÑÐ¿Ð»ÐµÑ {\"slug\": \"accessories\",\"title\": \"акÑеÑÑÑаÑов\"}, и иÑиÑе здеÑÑ.\n","gadgets":"ÐÑе { \"title\": \"iPhone\", \"slug\": \"iphone\"}, { \"title\": \"IPad\", \"slug\": \"ipad\"} (и дÑÑгие инÑеллекÑÑалÑнÑе ÑÑÑÑойÑÑва) гаджеÑÑ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð½Ð°Ð¹Ð´ÐµÐ½Ñ Ð² каÑегоÑии гаджеÑов. ÐÑ Ð¿ÑоÑÑого 3д Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð´Ð¾ ÑложнÑÑ
деÑалей и \"Ñ
аков\" Ð´Ð»Ñ Ð²Ð°ÑиÑ
веÑей, ÑÑо каÑегоÑÐ¸Ñ Ð´Ð»Ñ ÑвоÑÑеÑкиÑ
лÑдей и лÑбиÑелей ÑеÑ
ники.\n","games-toys":"ÐгÑÑ Ð¸ игÑÑÑки - ÑÑо каÑегоÑиÑ, оÑ
ваÑÑваÑÑÐ°Ñ Ð¿ÐµÑаÑнÑе 3д ÐÐРили миниаÑÑÑÑ Ð¼Ð¾Ð½ÑÑÑов, кÑоÑеÑнÑе { \"title\": \"Ñанки\", \"slug\": \"tank\"}, пÑиколÑнÑе{ \"slug\": \"chess\",\"title\": \"ÑаÑ
маÑÑ\"}, ÑÐ»ÐµÐ¼Ñ ÐºÐ¸Ð½Ð¾Ð³ÐµÑоев, пÑинадлежноÑÑи и акÑеÑÑÑаÑÑ Ð´Ð»Ñ Ñ
обби. ÐÑо каÑегоÑÐ¸Ñ Ð¿Ð¾Ð´Ñ
Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ Ð²ÑеÑ
веÑей Ð´Ð»Ñ Ð³Ð¸ÐºÐ¾Ð².\n","hobby-diy":"ÐÑли Ð²Ñ Ð½Ð°Ñ ÑледÑÑÑий великий изобÑеÑаÑÐµÐ»Ñ Ð¸ Ñ
оÑиÑе ÑоздаÑÑ Ñвой DIY пÑÐ¾ÐµÐºÑ Ð¸Ð»Ð¸ полÑÑиÑÑ ÐºÐ°ÐºÐ¸Ðµ-Ñо запаÑнÑе ÑаÑÑи Ð´Ð»Ñ { \"slug\": \"drone\",\"title\": \"дÑонов\"}, ÑÑа каÑегоÑÐ¸Ñ Ð´Ð»Ñ Ð²Ð°Ñ. ÐÑоме Ñого, она Ð¸Ð¼ÐµÐµÑ Ð¼Ð½Ð¾Ð³Ð¾ веÑей Ð´Ð»Ñ Ð»Ñдей, коÑоÑÑе Ñ
оÑÑÑ ÑделаÑÑ Ñвои ÑобÑÑвеннÑе ÑигÑÑки или плаÑÑиковÑе Ñеплики пÑÑек.\n","house":"Ð
16518Ñе Ð²Ð¸Ð´Ñ Ð±ÐµÐ·Ð´ÐµÐ»ÑÑек можно найÑи здеÑÑ. { \"title\": \"Ðампа\", \"slug\": \"lamp\"}, Ñ
ÑдожеÑÑÐ²ÐµÐ½Ð½Ð°Ñ { \"title\": \"ÑаÑа\", \"slug\": \"bowl\"} и вÑе Ð²Ð¸Ð´Ñ { \"title\": \"деÑжаÑели\", \"slug\": \"holder\"}, еÑли Ð²Ñ Ð½Ðµ можеÑе найÑи пÑавилÑное меÑÑо Ð´Ð»Ñ Ð²Ð°Ñего ÑелеÑона, ÑоÑ
ÑаниÑÑ Ð¿Ð¾ÑÑдок в зÑбоÑиÑÑкаÑ
, кÑÑе ÑÑÑек или ÑкÑаÑений на ваÑем ÑÑоле.\n","jewelry":"ЮвелиÑнÑе Ð¸Ð·Ð´ÐµÐ»Ð¸Ñ - ÑÑо Ñа каÑегоÑиÑ, где можно кÑпиÑÑ Ð±ÑаÑлеÑÑ, кÑÐ»Ð¾Ð½Ñ Ð¸Ð»Ð¸ колÑÑа Ñ Ð±ÑиллианÑами. ХоÑÑ 3д - пÑинÑеÑÑ Ð½ÐµÐ´Ð¾ÑÑаÑоÑно Ñ
оÑоÑи Ð´Ð»Ñ Ð¸Ð·Ð³Ð¾ÑÐ¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð±ÑиллианÑов - пока Ð²Ñ Ð²Ñе еÑе можеÑе ÑаÑпеÑаÑаÑÑ Ð¼ÐµÑаллиÑеÑкое колÑÑо в каÑеÑÑве оÑÐ½Ð¾Ð²Ñ Ð´Ð»Ñ Ð²Ð°Ñего IT гиковÑкого колÑÑа Ð´Ð»Ñ Ð¿ÑедложениÑ.","miniatures":"3д пеÑаÑнÑе { \"title\": \"пеÑÑонажи\", \"slug\": \"character\"}, извеÑÑнÑе лÑди, { \"title\": \"доÑÑопÑимеÑаÑелÑноÑÑи\", \"slug\": \"landmark\"}, живоÑнÑе, { \"title\": \"ÐÑжÑина \", \"slug\": \"male\"}, { \"slug\": \"female\",\"title\": \"женÑина\"}, { \"title\": \"монÑÑÑÑ\", \"slug\": \"monster\"}, { \"title\": \"инопланеÑÑне\",\"slug\": \"alien\"} - вÑе ÑÑо здеÑÑ. ÐÑли Ð²Ñ Ð¿ÐµÑаÑаеÑе коммÑналÑнÑе ÑÑанÑпоÑÑнÑе ÑÑедÑÑва, ÑÑÐ¾Ð±Ñ Ð¿Ð¾ÑÑавиÑÑ Ð½Ð° ÑÑол или ÑоздаÑÑ Ð¼Ð¸Ð½Ð¸Ð°ÑÑÑÑ Ð´Ð»Ñ Ð½Ð°ÑÑолÑнÑÑ
игÑ, ÑÑо ваÑа каÑегоÑиÑ.\n","science":"ЧÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÐºÐ»Ð°ÑÑиÑиÑиÑовано как наÑка? ÐÑ, Ð¼Ð¾Ð´ÐµÐ»Ñ ÑкелеÑа { \"slug\": \"bones\",\"title\": \"коÑÑÑ\"}, { \"slug\": \"tools\", \"title\": \"ÐнÑÑÑÑменÑÑ\"} и ÑвÑзаннÑе Ñ Ð°ÑÑÑоÑизикой 3д-пеÑаÑнÑе модели, коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð²Ð¾ многиÑ
иÑÑледоваÑелÑÑкиÑ
пÑоÑеÑÑаÑ
.\n"}},"printable":{"art":"ÐÑо меÑÑо, где Ñ
ÑдожеÑÑвеннÑе 3д пеÑаÑÑ Ð¸Ð´Ñи. ÐлÑÐ´Ñ Ð½Ð° дизайн ÑанÑазии ÑкÑлÑпÑÑÑÑ Ð²Ð¾ÑÑоздание клаÑÑиÑеÑкиÑ
пÑоизведений и ÑÑаÑÑй иÑÑоÑиÑеÑкиÑ
лиÑноÑÑей, или вдоÑ
новлÑÑÑие ÑигÑÑки, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ, даже 3д-пеÑаÑаемÑе логоÑипÑ? То еÑÑÑ ÐºÐ°tagоÑиÑ.\n","fashion":"ÐÑаÑивÑе и ÑÑилÑнÑе веÑи, коÑоÑÑе Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ноÑиÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ найÑи в ÑÑой каtagоÑии. СмоÑÑиÑе, еÑли Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи лÑбое иÑполÑзование Ð´Ð»Ñ ÑанÑазии коÑмиÑеÑкой ÑÑÑ {\"slug\": \"обÑвÑ\"}, новизна оÑков и коÑÐ¿Ð»ÐµÑ {\"slug\": \"акÑеÑÑÑаÑÑ\"} найÑи здеÑÑ.\n","gadgets":"ÐÑе { \"title\": \"iPhone\", \"slug\": \"iphone\"}, { \"title\": \"IPad\", \"slug\": \"Ipad\"} (и дÑÑгие инÑеллекÑÑалÑнÑе ÑÑÑÑойÑÑва) ÑлÑÑаи могÑÑ Ð±ÑÑÑ Ð½Ð°Ð¹Ð´ÐµÐ½Ñ Ð² каtagоÑии гаджеÑов. ÐÑ Ð¿ÑоÑÑого 3д дополнений в ÑложнÑе деÑали и \"Ñ
аки\" Ð´Ð»Ñ Ð²Ð°ÑиÑ
веÑей, ÑÑо каtagоÑÐ¸Ñ Ð´Ð»Ñ Ð¾Ð±ÑÑвлений и лÑбиÑели ÑеÑ
ники.\n","games-toys":"ÐгÑÑ Ð¸ игÑÑÑки ÑÑо каtagоÑиÑ, оÑ
ваÑÑваÑÑÐ°Ñ Ð¿ÐµÑаÑÐ°ÐµÐ¼Ð°Ñ 3д ÑÑжеÑодной или монÑÑÑ Ð¼Ð¸Ð½Ð¸Ð°ÑÑÑÑ, кÑоÑеÑнÑе { \"title\": \"Ñанки\", \"slug\": \"Ñанк\"}, Ñанк { \"slug\": \"ÑаÑ
маÑÑ\"} ÑÑÑки, ÑимволÑнÑе кино ÑлемÑ, Ñ
обби пÑинадлежноÑÑи и акÑеÑÑÑаÑÑ. ÐÑо каtagоÑÐ¸Ñ Ðº Ñ
Ð¾Ð´Ñ Ð´Ð»Ñ Ð²ÑеÑ
веÑей вÑзÑваÑÑиÑ
.\n","hobby-diy":"ÐÑли Ð²Ñ Ð½Ð°Ñ ÑледÑÑÑий великий изобÑеÑаÑÐµÐ»Ñ Ð¸ Ñ
оÑиÑе поÑÑÑоиÑÑ Ñвой DIY пÑÐ¾ÐµÐºÑ Ð¸Ð»Ð¸ полÑÑиÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе запаÑнÑе ÑаÑÑи Ð´Ð»Ñ { \"slug\": \"дÑонов\"}, ÑÑо меÑÑо бÑÑÑ. ÐÑоме Ñого, он Ð¸Ð¼ÐµÐµÑ Ð¼Ð½Ð¾Ð³Ð¾ веÑей Ð´Ð»Ñ Ð»Ñдей, коÑоÑÑе Ñ
оÑÑÑ ÑделаÑÑ Ñвои ÑобÑÑвеннÑе ÑигÑÑки или плаÑÑиковÑе пÑÑки Ñеплики.\n","house":"Ð
16518Ñе Ð²Ð¸Ð´Ñ Ð±ÐµÐ·Ð´ÐµÐ»ÑÑек можно найÑи здеÑÑ. { \"title\": \"Ðампа\", \"slug\": \"лампа\"}, Ñ
ÑдожеÑÑвеннÑй { \"title\": \"ÑаÑа\", \"slug\": \"ÑаÑа\"}, и вÑе Ð²Ð¸Ð´Ñ { \"title\": \"деÑжаÑели\", \"slug\": \"деÑжаÑелÑ\"} ли Ð²Ñ Ð½Ðµ можеÑе найÑи пÑавилÑное меÑÑо Ð´Ð»Ñ Ð²Ð°Ñего ÑелеÑона, ÑоÑ
ÑаниÑÑ Ð¿Ð¾ÑÑдок зÑбоÑиÑÑки, кÑÑа ÑÑÑек или ÑкÑаÑений на ваÑем ÑÑоле.\n","jewelry":"ЮвелиÑнÑе изделиÑ, где Ð²Ñ Ð¸Ð´ÐµÑе, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð±ÑаÑлеÑÑ Ð¸ подвеÑÐºÑ Ð¸Ð»Ð¸ колÑÑо Ñ Ð±ÑиллианÑами. Ð Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº 3д пÑинÑеÑÑ Ð½Ðµ доÑÑаÑоÑно Ñ
оÑоÑи, ÑÑÐ¾Ð±Ñ ÑделаÑÑ Ð°Ð»Ð¼Ð°Ð·Ñ - еÑе - Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ÑаÑпеÑаÑаÑÑ Ð¼ÐµÑаллиÑеÑкое колÑÑо в каÑеÑÑве оÑÐ½Ð¾Ð²Ñ Ð´Ð»Ñ Ð²Ð°Ñего ÐТ-вÑÑодка пÑедложение колÑÑа.\n","miniatures":"3д веÑÑÐ¸Ñ Ð´Ð»Ñ Ð¿ÐµÑаÑи { \"title\": \"ÑимволÑ\", \"slug\": \"Ñимволов\"}, извеÑÑнÑе лÑди, { \"title\": \"доÑÑопÑимеÑаÑелÑноÑÑи\", \"slug\": \"знаковÑе\"}, живоÑнÑе, { \"title\": \"ÐÑжÑина \", \"slug\": \"мÑжÑкаÑ\"}, { \"slug\": \"женÑкаÑ\"}, { \"title\": \"монÑÑÑÑ\", \"slug\": \"монÑÑÑ\"}, { \"title\": \"инопланеÑÑне\",\"slug\" :\"иноÑÑÑанеÑ\"} - вÑе ÑÑо здеÑÑ. ÐÑли Ð²Ñ Ð¿ÐµÑаÑаеÑе коммÑналÑнÑе ÑÑанÑпоÑÑнÑе ÑÑедÑÑва, ÑÑÐ¾Ð±Ñ Ð¿Ð¾ÑÑавиÑÑ Ð½Ð° ÑÑол или Ñоздание миниаÑÑÑ Ð´Ð»Ñ Ð½Ð°ÑÑолÑнÑÑ
игÑ, ÑÑо ваÑа каtagоÑиÑ.\n","science":"ЧÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÐºÐ»Ð°ÑÑиÑиÑиÑован как наÑка? ÐÑ, Ð¼Ð¾Ð´ÐµÐ»Ñ ÑкелеÑа { \"slug\": \"коÑÑÑ\"}, { \"slug\": \"ÐнÑÑÑÑменÑÑ\"} и аÑÑÑоÑизики, ÑвÑÐ·Ð°Ð½Ð½Ð°Ñ Ñ 3д моделей Ð´Ð»Ñ Ð¿ÐµÑаÑи, коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð²Ð¾ многиÑ
пÑоÑеÑÑаÑ
обÑÑениÑ.\n"},"titles":{"aircraft":"3D-модели авиаÑии","animal":"3D-модели живоÑнÑÑ
","animals":"3D-модели живоÑнÑÑ
","architectural":"ÐÑÑ
иÑекÑÑÑнÑе 3D-модели","car":"3D-модели авÑомобилей","character":"3D-модели пеÑÑонажей","exterior":"3D-модели ÑкÑÑеÑÑеÑов","food":"3D-модели едÑ","furniture":"3D-модели мебели","household":"ÐÑÑовÑе 3D-модели","industrial":"ÐÑомÑÑленнÑе 3D-модели","interior":"3D-модели инÑеÑÑеÑов","military":"ÐоеннÑе 3D-модели","plant":"3D-модели ÑаÑÑений","space":"ÐоÑмиÑеÑкие 3D-модели","textures":"ТекÑÑÑÑÑ","vehicle":"ТÑанÑпоÑÑнÑе 3D-модели","watercraft":"3D-модели водного ÑÑанÑпоÑÑа"}},"title":{"cg":"3д модели","print":"Ð¤Ð°Ð¹Ð»Ñ Ð´Ð»Ñ 3D-пеÑаÑи"}}
16518,"competition":{"digital-art-competition":{"categories":{"page_description":"ÐÑинÑÑÑ ÑÑаÑÑие в ÐонкÑÑÑе CGTrader Digital Art, пÑедÑÑавив Ñвои ÑабоÑÑ Character ÐллÑÑÑÑаÑиÑ, Ñ
аÑакÑÐµÑ ÐºÐ¾Ð½ÑепÑии дизайна, окÑÑжаÑÑей ÑÑÐµÐ´Ñ ÐллÑÑÑÑаÑиÑ, ÐкÑÑжаÑÑÐ°Ñ ÑÑеда ÐонÑепÑÐ¸Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½Ð°, обÑекÑов дизайна и обÑекÑов каtagоÑии Concept Design. ÐÑли Ñ Ð²Ð°Ñ ÐµÑÑÑ Ð½ÐµÑколÑко болÑÑиÑ
ÑабоÑ, коÑоÑÑе подÑ
одÑÑ Ð´Ð»Ñ ÑазлиÑнÑÑ
каtagоÑий, не ÑÑеÑнÑйÑеÑÑ Ð¿ÑедÑÑавиÑÑ Ð¸Ñ
в ÑооÑвеÑÑÑвÑÑÑие каtagоÑии. ÐÑбеÑиÑе каtagоÑиÑ, ÑÑÐ¾Ð±Ñ ÑвидеÑÑ Ð¿ÑÐ¸Ð·Ñ Ð´Ð»Ñ ÑÑой каtagоÑии."}}},"conversations":{"action_button_confirmation":"ÐÑ Ð´ÐµÐ¹ÑÑвиÑелÑно Ñ
оÑиÑе Ñнова оÑкÑÑÑÑ ÑÑÐ¾Ñ Ð·Ð°Ð¿ÑоÑ?","reply_posted":"ÐÑÐ²ÐµÑ Ð±Ñл опÑбликован.","with_yourself":"не Ð¼Ð¾Ð¶ÐµÑ ÑовпадаÑÑ Ñ Ð¾ÑпÑавиÑелем."},"date":{"abbr_day_names":{},"abbr_month_names":{},"common_abbr_day_names":["ÐÑ","Ðн","ÐÑ","СÑ","ЧÑ","ÐÑ","Сб"],"common_abbr_month_names":[null,"Ñнв.","ÑевÑ.","маÑÑа","апÑ.","маÑ","иÑнÑ","иÑлÑ","авг.","ÑенÑ.","окÑ.","ноÑб.","дек."],"common_day_names":["воÑкÑеÑенÑе","понеделÑник","вÑоÑник","ÑÑеда","ÑеÑвеÑг","пÑÑниÑа","ÑÑббоÑа"],"common_month_names":[null,"ÑнваÑÑ","ÑевÑалÑ","маÑÑа","апÑелÑ","маÑ","иÑнÑ","иÑлÑ","авгÑÑÑа","ÑенÑÑбÑÑ","окÑÑбÑÑ","ноÑбÑÑ","декабÑÑ"],"day_names":{},"formats":{"default":"%d.%m.%Y","long":"%d %B %Y","short":"%d %b"},"month_names":[null,"ЯнваÑÑ","ФевÑалÑ","ÐаÑÑ","ÐпÑелÑ","Ðай","ÐÑнÑ","ÐÑлÑ","ÐвгÑÑÑ","СенÑÑбÑÑ","ÐкÑÑбÑÑ","ÐоÑбÑÑ","ÐекабÑÑ"],"order":["day","month","year"],"standalone_abbr_day_names":["вÑ","пн","вÑ","ÑÑ","ÑÑ","пÑ","Ñб"],"standalone_abbr_month_names":[null,"Ñнв.","ÑевÑ.","маÑÑ","апÑ.","май","иÑнÑ","иÑлÑ","авг.","ÑенÑ.","окÑ.","ноÑб.","дек."],"standalone_day_names":["ÐоÑкÑеÑенÑе","ÐонеделÑник","ÐÑоÑник","СÑеда","ЧеÑвеÑг","ÐÑÑниÑа","СÑббоÑа"],"standalone_month_names":[null,"ЯнваÑÑ","ФевÑалÑ","ÐаÑÑ","ÐпÑелÑ","Ðай","ÐÑнÑ","ÐÑлÑ","ÐвгÑÑÑ","СенÑÑбÑÑ","ÐкÑÑбÑÑ","ÐоÑбÑÑ","ÐекабÑÑ"]},"datetime":{"distance_in_words":{"about_x_hours":{"few":"около %{count} ÑаÑов","many":"около %{count} ÑаÑов","one":"около %{count} ÑаÑа","other":"около %{count} ÑаÑов"},"about_x_months":{"few":"около %{count} меÑÑÑев","many":"около %{count} меÑÑÑев","one":"около %{count} меÑÑÑа","other":"около %{count} меÑÑÑев"},"about_x_years":{"few":"около %{count} леÑ","many":"около %{count} леÑ","one":"около %{count} года","other":"около %{count} леÑ"},"almost_x_years":{"few":"поÑÑи %{count} года","many":"поÑÑи %{count} леÑ","one":"поÑÑи %{count} год","other":"поÑÑи %{count} леÑ"},"half_a_minute":"менÑÑе минÑÑÑ","less_than_x_minutes":{"few":"менÑÑе %{count} минÑÑ","many":"менÑÑе %{count} минÑÑ","one":"менÑÑе %{count} минÑÑÑ","other":"менÑÑе %{count} минÑÑ"},"less_than_x_seconds":{"few":"менÑÑе %{count} ÑекÑнд","many":"менÑÑе %{count} ÑекÑнд","one":"менÑÑе %{count} ÑекÑндÑ","other":"менÑÑе %{count} ÑекÑнд"},"over_x_years":{"few":"болÑÑе %{count} леÑ","many":"болÑÑе %{count} леÑ","one":"болÑÑе %{count} года","other":"болÑÑе %{count} леÑ"},"x_days":{"few":"%{count} днÑ","many":"%{count} дней","one":"%{count} денÑ","other":"%{count} дней"},"x_minutes":{"few":"%{count} минÑÑÑ","many":"%{count} минÑÑ","one":"%{count} минÑÑа","other":"%{count} минÑÑ"},"x_months":{"few":"%{count} меÑÑÑа","many":"%{count} меÑÑÑев","one":"%{count} меÑÑÑ","other":"%{count} меÑÑÑев"},"x_seconds":{"few":"%{count} ÑекÑндÑ","many":"%{count} ÑекÑнд","one":"%{count} ÑекÑнда","other":"%{count} ÑекÑнд"},"x_years":{"few":"%{count} года","many":"%{count} леÑ","one":"%{count} год","other":"%{count} леÑ"}},"prompts":{"day":"ÐенÑ","hour":"ЧаÑов","minute":"ÐинÑÑ","month":"ÐеÑÑÑ","second":"СекÑнд","year":"Ðод"}}
16518,"design_partnership":{"benefits":{"benefits_arr":[{"title":"ÐаÑинайÑе ÑабоÑаÑÑ ÑейÑаÑ","info":"Ðе нÑжно иÑкаÑÑ ÐºÐ»Ð¸ÐµÐ½Ñа â ÑабоÑайÑе над ÑоÑнÑми доÑÑÑпнÑÑ
Ð·Ð°Ð´Ð°Ñ Ð¿Ð¾ моделиÑованиÑ, коÑоÑÑе ÑооÑвеÑÑÑвÑÑÑ Ð²Ð°Ñим инÑеÑеÑам и ÑинанÑовÑм ожиданиÑм.","icon":"rabbit-fast"},{"title":"Ðибкое ÑабоÑее вÑемÑ","info":"ÐодÑ
Ð¾Ð´Ð¸Ñ Ð¸ Ð´Ð»Ñ Ñов и Ð´Ð»Ñ Ð¶Ð°Ð²Ð¾Ñонков - Ð²Ñ ÐµÐ´Ð¸Ð½ÑÑвеннÑй, кÑо вÑбиÑÐ°ÐµÑ ÑколÑко поÑабоÑаÑÑ.","icon":"clock"},{"title":"РабоÑайÑе комÑоÑÑно на домÑ","info":"ÐÑе ÑÑиланÑ-задаÑи могÑÑ Ð±ÑÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ñ Ð´Ð¾Ð¼Ð° на ваÑем домаÑнем компÑÑÑеÑе или в лÑбом дÑÑгом меÑÑа, где Ð²Ñ Ð¿ÑедпоÑиÑаеÑе ÑабоÑаÑÑ.","icon":"couch"},{"title":"ÐолÑÑайÑе наÑÑоÑÑие денÑги","info":"ÐаÑабаÑÑвайÑе наÑÑоÑÑие денÑги. ÐеÑеÑиÑÐ»ÐµÐ½Ð¸Ñ ÑеÑез Paypal, Payoneer, Webmoney или пÑÑмо на Ð²Ð°Ñ Ð±Ð°Ð½ÐºÐ¾Ð²Ñкий ÑÑеÑ.","icon":"money-check-alt"},{"title":"ÐÑÐ´ÐµÐ»ÐµÐ½Ð½Ð°Ñ 3D поддеÑжка","info":"ÐаÑа вÑÐ´ÐµÐ»ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° гоÑова поделиÑÑÑÑ 3D ноÑ-Ñ
аÑ, оÑвеÑиÑÑ Ð½Ð° ÑеÑ
ниÑеÑкие вопÑоÑÑ Ð¸ помоÑÑ Ð²Ð°Ð¼ вÑполниÑÑ Ð·Ð°Ð´Ð°ÑÑ.","icon":"user-friends"},{"title":"РабоÑайÑе Ñ Ñоп заказÑиками","info":"СоздавайÑе полÑзоваÑелÑÑкие модели Ð´Ð»Ñ Ð³Ð»Ð¾Ð±Ð°Ð»Ñного бизнеÑа (вклÑÑÐ°Ñ ÐºÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ð¸ из ÑпиÑка Fortune 500).","icon":"hands-helping"}],"section_title":"ЧÑо в ÑÑом Ð´Ð»Ñ Ð²Ð°Ñ?"},"cta_button":"ÐÑиÑоеденÑйÑеÑÑ Ðº Wildcat ÑегоднÑ","explanation_steps":{"section_title":"ÐÑиÑоединÑйÑеÑÑ ÑегоднÑ","step_1":{"info":"СоздайÑе аккаÑÐ½Ñ Ð² CGTrader, еÑли Ñ Ð²Ð°Ñ ÐµÐ³Ð¾ еÑе неÑ. Ðак ÑолÑко войдеÑе в ÑиÑÑемÑ, пÑедоÑÑавÑÑе пÑимеÑÑ ÐаÑиÑ
ÑÐ°Ð±Ð¾Ñ Ð¸Ð»Ð¸ пÑойдиÑе неболÑÑой ÑеÑÑ. ÐÑли ÐаÑиÑ
навÑки подойдÑÑ, ÐÑ Ð¿Ð¾Ð»ÑÑиÑе полнÑй доÑÑÑп к наÑим оплаÑиваемÑм задаÑам.","title":"ÐÑиÑоединÑйÑеÑÑ"},"step_2":{"info":"ÐолÑÑили подÑвеÑждение? ÐÐµÐ¼ÐµÐ´Ð»Ñ Ð¿ÑоÑмоÑÑиÑе доÑÑÑпнÑе задаÑи по 3D моделиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð² наÑей ÑиÑÑеме Wildcat, ÑабоÑайÑе над ÑемÑ, коÑоÑÑе Ðам понÑавÑÑÑÑ Ð±Ð¾Ð»ÐµÐµ вÑего либо возвÑаÑайÑеÑÑ Ð·Ð° дÑÑгими задаÑи попозже.","title":"ÐаÑинайÑе"},"step_3":{"info":"ÐÑбеÑиÑе пÑедпоÑиÑаемÑй меÑод оплаÑÑ Ð¸ полÑÑайÑе Ñвой заÑабоÑок на ÑÑиланÑе еженеделÑно или ежемеÑÑÑно.","title":"ÐолÑÑайÑе оплаÑÑ"}},"header":{"benefits":[{"text":"ÐаÑабаÑÑвайÑе до $200 за каждÑÑ Ð¸Ð·Ð³Ð¾ÑовленнÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ"},{"text":"ÐÑбиÑайÑе задаÑи ÑоглаÑно ÐаÑим пÑедпоÑÑениÑм, никакиÑ
ÑоÑгов"},{"text":"ÐаÑлаждайÑеÑÑ Ð±Ð¾Ð½ÑÑами множиÑÐµÐ»Ñ Ð¿ÑибÑли и ÑоповÑми Ñенами"},{"text":"ÐоÑÑоÑннÑй поÑок ÑабоÑÑ Ð¸ доÑ
ода"}],"page_title":"ФÑÐ¸Ð»Ð°Ð½Ñ Ð¿Ð»Ð°ÑÑоÑма без ÑоÑгов Ð´Ð»Ñ 3D дизайнеÑов","subtitle":"ÐÑиÑоеденÑйÑеÑÑ Ðº ÑкÑклÑÐ·Ð¸Ð²Ð½Ð¾Ð¼Ñ ÑообÑеÑÑÐ²Ñ 3D дизайнеÑов и полÑÑиÑе доÑÑÑп к ÑоÑнÑм кÑÑиÑованÑÑ
заданий по моделиÑованиÑ. РабоÑайÑе в лÑбом меÑÑе, в лÑбое вÑемÑ!","switcher_html":"\u003ca href='/freelance-with-us'\u003eEN\u003c/a\u003e\n\u003cspan class='u-mr10 u-ml10'\u003e|\u003c/span\u003e\n\u003ca href='/ru/Zarabatyvayte-s-CGTrader' class='is-active'\u003eRU\u003c/a\u003e\n"},"help_section":{"contact_btn":"СвÑзаÑÑÑÑ Ñ Ð½Ð°Ð¼Ð¸","help_center_btn":"ÐоÑеÑиÑе ÑенÑÑ Ð¿Ð¾Ð¼Ð¾Ñи","section_title":"ÐÑÑÑ Ð²Ð¾Ð¿ÑоÑÑ?"},"meta":{"description":"ÐолÑÑиÑе доÑÑÑп к ÑоÑнÑм Ð·Ð°Ð´Ð°Ñ Ð¿Ð¾ 3д-моделиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸ заÑабаÑÑвайÑе денÑги в Ñдобном Ñежиме.","title":"ÐаÑабаÑÑвайÑе Ñ CGTrader"},"positions":{"open_positions":[{"type":"pbr","title":"PBR (низкополигоналÑное) моделиÑование","info_html":"\u003cp\u003eÐоÑÑÑпно 3D-дизайнеÑам, имеÑÑим опÑÑ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ PBR моделей.\u003c/p\u003e\n\u003cp\u003e\n \u003cspan class=\"text-semibold\"\u003eТÑÐµÐ±Ð¾Ð²Ð°Ð½Ð¸Ñ Ðº пÑогÑÐ°Ð¼Ð¼Ð½Ð¾Ð¼Ñ Ð¾Ð±ÐµÑпеÑениÑ: оÑÑÑÑÑÑвÑÑÑ\u003c/span\u003e \u003cbr /\u003e\n ФоÑÐ¼Ð°Ñ Ð´Ð¾ÑÑавки: \u003cspan class=\"text-semibold\"\u003e.fbx\u003c/span\u003e\n\u003c/p\u003e\n","badge":"Ð ÑÑенде!"},{"type":"archviz","title":"AÑÑ
. виз. (вÑÑокополигоналÑное) моделиÑование","info_html":"\u003cp\u003eÐоÑÑÑпно 3D-дизайнеÑам, имеÑÑим опÑÑ 3D моделиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸ ÑекÑÑÑÑиÑованиÑ.\u003c/p\u003e\n\u003cp\u003e\n ТÑÐµÐ±Ð¾Ð²Ð°Ð½Ð¸Ñ Ðº пÑогÑÐ°Ð¼Ð¼Ð½Ð¾Ð¼Ñ Ð¾Ð±ÐµÑпеÑениÑ: \u003cspan class=\"text-semibold\"\u003e3ds Max 2020\u003c/span\u003e (дÑÑгие веÑÑии\n допÑÑкаÑÑÑÑ, но не ÑекомендÑÑÑÑÑ) \u003cbr /\u003e\n РендеÑеÑ: \u003cspan class=\"text-semibold\"\u003eV-ray Next, обновление 3.2\u003c/span\u003e (дÑÑгие веÑÑии\n допÑÑкаÑÑÑÑ, но не ÑекомендÑÑÑÑÑ)\n\u003c/p\u003e\n","badge":""}],"section_title":"ÐоÑÑÑпнÑе задаÑи на даннÑй моменÑ"}},"devise":{"failure":{"too_many_requests":"ÐÑ Ñже запÑаÑивали пиÑÑмо Ð´Ð»Ñ ÑбÑоÑа паÑолÑ. ÐожалÑйÑÑа, подождиÑе неÑколÑко минÑÑ, пÑежде Ñем попÑобоваÑÑ Ñнова."}},"disabled_cookies_modal":{"button":"оÑмениÑÑ","text_1":"ÐÑ Ð½Ðµ ÑможеÑе иÑÑледоваÑÑ Ð¼Ð¸Ð»Ð»Ð¸Ð¾Ð½Ñ Ð±Ð¾Ð»ÑÑиÑ
3D моделей, добавиÑÑ Ð¸Ñ
в коÑзин
16518Ñ Ð¸Ð»Ð¸ ÐÑпиÑÑ.","text_2":"ÐÑли Ð²Ñ Ñ
оÑиÑе, ÑÑÐ¾Ð±Ñ Ð² полной меÑе иÑпÑÑаÑÑ CGTrader, Ð¼Ñ ÑекомендÑем позволÑÑ ÐºÑк на ÑÑом ÑайÑе.","title":"ÐажеÑÑÑ, Ð²Ñ Ð¾ÑклÑÑили кÑки ваÑего бÑаÑзеÑа"},"emails":{"error_notification":"ÐодпиÑка не найдена.","success_subscribed_notification":"ÐÑ ÑÑпеÑно подпиÑалиÑÑ.","success_unsubscribed_notification":"ÐÑ ÑÑпеÑно оÑпиÑалиÑÑ."},"errors":{"format":"%{attribute} %{message}","messages":{"accepted":"нÑжно подÑвеÑдиÑÑ","blank":"не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÑÑÑм","confirmation":"не ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñо знаÑением Ð¿Ð¾Ð»Ñ %{attribute}","empty":"не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÑÑÑм","equal_to":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð·Ð½Ð°Ñение, Ñавное %{count}","even":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ ÑеÑное знаÑение","exclusion":"Ð¸Ð¼ÐµÐµÑ Ð·Ð°ÑезеÑвиÑованное знаÑение","greater_than":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°Ñение болÑÑе %{count}","greater_than_or_equal_to":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°Ñение не менÑÑе %{count}","in":"должно бÑÑÑ Ð² диапазоне %{count}","inclusion":"Ð¸Ð¼ÐµÐµÑ Ð½ÐµÐ¿ÑедÑÑмоÑÑенное знаÑение","invalid":"Ð¸Ð¼ÐµÐµÑ Ð½ÐµÐ²ÐµÑное знаÑение","less_than":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°Ñение менÑÑе %{count}","less_than_or_equal_to":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð·Ð½Ð°Ñение не болÑÑе %{count}","model_invalid":"Ðозникли оÑибки: %{errors}","not_a_number":"не ÑвлÑеÑÑÑ ÑиÑлом","not_an_integer":"не ÑвлÑеÑÑÑ ÑелÑм ÑиÑлом","odd":"Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ Ð»Ð¸ÑÑ Ð½ÐµÑеÑное знаÑение","other_than":"должно оÑлиÑаÑÑÑÑ Ð¾Ñ %{count}","present":"нÑжно оÑÑавиÑÑ Ð¿ÑÑÑÑм","record_invalid":"Ðозникли оÑибки: %{errors}","required":"не Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑÑÑÑÑвоваÑÑ","taken":"Ñже ÑÑÑеÑÑвÑеÑ","too_long":{"few":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимвола)","many":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимволов)","one":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимвол)","other":"ÑлиÑком болÑÑой Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð»ÑÑе Ñем %{count} Ñимвола)"},"too_short":{"few":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимволов)","many":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимволов)","one":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимвола)","other":"недоÑÑаÑоÑной Ð´Ð»Ð¸Ð½Ñ (не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼ÐµÐ½ÑÑе %{count} Ñимвола)"},"wrong_length":{"few":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимвола)","many":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимволов)","one":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимвол)","other":"невеÑной Ð´Ð»Ð¸Ð½Ñ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð´Ð»Ð¸Ð½Ð¾Ð¹ Ñовно %{count} Ñимвола)"}},"template":{"body":"ÐÑÐ¾Ð±Ð»ÐµÐ¼Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ»Ð¸ Ñо ÑледÑÑÑими полÑми:","header":{"few":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибок","many":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибок","one":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибки","other":"%{model}: ÑоÑ
Ñанение не ÑдалоÑÑ Ð¸Ð·-за %{count} оÑибки"}}},"file_size_validator":{"errors":{"invalid_carrierwave":"ÐжидалÑÑ Ð¾Ð±ÑÐµÐºÑ CarrierWave::Uploader::Base","invali
16518d_key":":%{key} должно бÑÑÑ Ð½ÐµÐ¾ÑÑиÑаÑелÑнÑм ÑелÑм ÑиÑлом","range_format":":in и :within Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð¾Ð¼ (Range)","range_unspecified":"Ðиапазон не Ñказан. УкажиÑе паÑамеÑÑ :within, :maximum, :minimum или :is."}},"file_type":{"default_error":"ÐÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð½Ðµ Ñказан."},"footer":{"bottom-row":{"privacy":"ÐолиÑика конÑиденÑиалÑноÑÑи","terms-link":"ÐÑавила и ÑÑловиÑ"},"links":{"buyLinks":[{"text":"ÐÑпиÑÑ 3D-модели","link":"/ru/3d-modeli"},{"text":"ÐÐ»Ñ Ð±Ð¸Ð·Ð½ÐµÑа","link":"/discover/business-account"},{"text":"ÐеÑплаÑнÑе 3D-даÑаÑеÑÑ","link":"/discover/datasets"},{"text":"ÐанÑÑÑ 3D-дизайнеÑа","link":"/3d-modeling-jobs"},{"text":"ÐеÑплаÑнÑе 3D-модели","link":"/ru/besplatnye-3d-modeli"},{"text":"ÐеÑплаÑнÑе модели Ð´Ð»Ñ 3D-пеÑаÑи","link":"/ru/besplatnye-3d-pechat-modeli"}],"communityLinks":[{"text":"СообÑеÑÑво","link":""},{"text":"ÐÑÑÑие дизайнеÑÑ","link":"/designers"},{"text":"Челленджи","link":"/challenges"},{"text":"ФоÑÑм","link":"/forum"}],"companyLinks":[{"text":"ÐомпаниÑ","link":"/discover/about-us"},{"text":"Ðлог","link":"/blog"},{"text":"ÐаканÑии","link":"/pages/careers"},{"text":"ЦенÑÑ Ð¿Ð¾Ð´Ð´ÐµÑжки","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"ÐÑодаÑÑ 3D-модели","link":"/discover/sell-3d-models"},{"text":"УвелиÑÑÑе пÑодажи","link":"/discover/sell-more"},{"text":"ÐÐ±Ð·Ð¾Ñ ÑÑнка 3D","link":"/discover/3d-market-trends"},{"text":"Топ поиÑков 3D-моделей","link":"/discover/3d-models-top-searches"},{"text":"Топ поиÑков Ð´Ð»Ñ 3D-пеÑаÑи","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"ÐодпиÑаÑÑÑÑ","button-disabled":"ÐодпиÑка оÑоÑмлена","header":"ÐодпиÑаÑÑÑÑ Ð½Ð° новоÑÑи:","placeholder":"ÐведиÑе адÑÐµÑ ÑлекÑÑонной поÑÑÑ","terms-link":"УÑÐ»Ð¾Ð²Ð¸Ñ Ð¿Ð¾Ð»ÑзованиÑ","text":"ÐодпиÑавÑиÑÑ, Ð²Ñ Ð¿Ð¾Ð´ÑвеÑждаеÑе, ÑÑо пÑоÑиÑали и пÑинимаеÑе наÑи"}},"general":{"description":"CGTrader пÑедÑÑавлÑÐµÑ Ñобой инÑеÑнеÑ-ÑÑнок, где 3D-Ñ
Ñдожники и дизайнеÑÑ Ð¼Ð¾Ð³ÑÑ ÐºÑпиÑÑ, пÑодаÑÑ Ð¸Ð»Ð¸ поделиÑÑÑÑ 3д-модели. Ðн бÑл оÑнован и ÑазÑабаÑÑваеÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ 3D-дизайнеÑов и инженеÑов. ÐаÑа ÑÐµÐ»Ñ ÑоÑÑÐ¾Ð¸Ñ Ð² Ñом, ÑÑÐ¾Ð±Ñ Ð´ÐµÐ¼Ð¾ÐºÑаÑизиÑоваÑÑ 3D ÑондовÑй ÑÑнок и измениÑÑ ÑпоÑоб, коÑоÑÑм Ð¼Ñ Ð¿ÑодаваÑÑ 3д модели онлайн. ÐозволÑÑ Ð°Ð²ÑоÑÑ Ð¿Ð¾Ð»ÑÑаÑÑ Ð¼Ð°ÐºÑималÑнÑе гоноÑаÑÑ, Ð¼Ñ ÑÑÑемимÑÑ Ð¿Ð¾Ð²ÑÑиÑÑ Ð¸Ñ
моÑиваÑÐ¸Ñ Ð¸ повÑÑиÑÑ ÐºÐ°ÑеÑÑво 3д-модели.","navigation":{"buy_3d_models":"ÐÑпиÑÑ 3д модели","sell_3d_models":"ÐÑодаÑÑ 3д модели"},"search_placeholder":"ÐоиÑк ÑÑеди более Ñем 2 миллионов 3D-моделей","site-search__field":"ÐоиÑк ÑÑеди %{model_count} 3D-моделей","site_title":"3д модели магазина","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"ÐÑÑÑÑ ÐРвоплоÑÐ¸Ñ Ð²Ð°Ñи меÑÑÑ","subtitle":"ÐÑевÑаÑиÑе подÑÐºÐ°Ð·ÐºÑ Ð¸Ð»Ð¸ ÑеÑеÑенÑное изобÑажение в гоÑовÑÑ Ðº пÑоизводÑÑÐ²Ñ 3D-моделÑ, заÑем доÑабоÑайÑе, пеÑеÑекÑÑÑÑиÑÑйÑе и ÑкÑпоÑÑиÑÑйÑе ÐµÑ Ð² нÑжном ÑоÑмаÑе."},"faq":{"heading":"ЧаÑÑо задаваемÑе вопÑоÑÑ","items":{"commercial":{"answer":"ÐоммеÑÑеÑкое иÑполÑзование ваÑей 3D-модели %{object} доÑÑÑпно на плаÑном плане CGTrader AI. ÐзнакомÑÑеÑÑ Ñ Ð£ÑловиÑми иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ CGTrader Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð¸Ð½ÑоÑмаÑии о лиÑензионнÑÑ
ÑÑловиÑÑ
Ð´Ð»Ñ ÐÐ-ÑгенеÑиÑованнÑÑ
моделей.","question":"Ðожно ли иÑполÑзоваÑÑ ÑгенеÑиÑованнÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} в коммеÑÑеÑкиÑ
ÑелÑÑ
?"},"formats":{"answer":"3D-модели %{object} доÑÑÑÐ¿Ð½Ñ Ð² ÑоÑмаÑаÑ
GLB, FBX, OBJ, STL или USDZ.","question":"Ркаком ÑоÑмаÑе Ñайла Ñ Ð¿Ð¾Ð»ÑÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ %{object}?"},"no_skills":{"answer":"ÐÐ½Ð°Ð½Ð¸Ñ 3D-моделиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð½Ðµ ÑÑебÑÑÑÑÑ. ÐÑÑ ÑабоÑа вÑполнÑеÑÑÑ ÑеÑез генеÑаÑÐ¾Ñ Ð¼Ð¾Ð´ÐµÐ»ÐµÐ¹ %{object}. СиÑÑема ÑамоÑÑоÑÑелÑно обÑабаÑÑÐ²Ð°ÐµÑ Ð³ÐµÐ¾Ð¼ÐµÑÑиÑ, пÑопоÑÑии и ÑÑÑÑкÑÑÑÑ Ð¿Ð¾ ваÑÐµÐ¼Ñ Ð·Ð°Ð¿ÑоÑÑ Ð¸Ð»Ð¸ загÑÑÐ¶ÐµÐ½Ð½Ð¾Ð¼Ñ Ð¸Ð·Ð¾Ð±ÑажениÑ. Ðаже новиÑки могÑÑ ÑоздаÑÑ Ð¿Ð¾Ð»Ð½Ð¾ÑеннÑÑ 3D-Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} за неÑколÑко минÑÑ.","question":"ÐÑÐ¶Ð½Ñ Ð»Ð¸ Ð·Ð½Ð°Ð½Ð¸Ñ 3D-моделиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð³ÐµÐ½ÐµÑаÑоÑа моделей %{object}?"},"what_is":{"answer":"ÐенеÑаÑÐ¾Ñ 3D-моделей CGTrader %{object}, оÑнованнÑй на ÐÐ, ÑоздаÑÑ ÑÑÑÑ
меÑнÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} из ÑекÑÑовÑÑ
инÑÑÑÑкÑий или ÑеÑеÑенÑнÑÑ
изобÑажений. Ðн анализиÑÑÐµÑ Ð²Ð°ÑÑ Ð¸Ð´ÐµÑ Ð¸ ÑоздаÑÑ Ð·Ð°Ð³ÑÑжаемÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð´Ð»Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½Ð°, пÑоÑоÑипиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¸ визÑализаÑии. ÐаÑи плаÑнÑе подпиÑки пÑедлагаÑÑ Ð±Ð¾Ð»ÐµÐµ вÑÑокие ежемеÑÑÑнÑе лимиÑÑ.","question":"ЧÑо Ñакое генеÑаÑÐ¾Ñ 3D-моделей %{object}?"},"why_cgtrader":{"answer":"CGTrader обеÑпеÑÐ¸Ð²Ð°ÐµÑ Ð¿Ð»Ð°Ð²Ð½Ñй опÑÑ ÑабоÑÑ, бÑÑÑÑÑÑ Ð¾Ð±ÑабоÑÐºÑ Ð¸ вÑÑококаÑеÑÑвеннÑе 3D-ÑезÑлÑÑаÑÑ. ÐÑÐ¾Ñ Ð¸Ð½ÑÑÑÑÐ¼ÐµÐ½Ñ Ð¿Ð¾Ð´Ñ
Ð¾Ð´Ð¸Ñ ÐºÐ°Ðº Ð´Ð»Ñ Ð¿ÑоÑеÑÑионалов, Ñак и Ð´Ð»Ñ Ð½Ð°ÑинаÑÑиÑ
, коÑоÑÑе иÑÑÑ Ð½Ð°Ð´Ñжное ÑеÑение Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ 3D-моделей %{object}.","question":"ÐоÑÐµÐ¼Ñ ÑÑÐ¾Ð¸Ñ Ð¸ÑполÑзоваÑÑ ÐÐ-генеÑаÑÐ¾Ñ %{object} Ð¾Ñ CGTrader?"}}},"h1":"ÐÐ-генеÑаÑÐ¾Ñ 3D-моделей %{object}","hero_alt":"ÐÐ-генеÑаÑÐ¾Ñ 3D-моделей %{object}","hero_height":617,"hero_width":1080,"how_to":{"heading":"ÐенеÑаÑÐ¸Ñ %{object} из изобÑажений или ÑекÑÑовÑÑ
подÑказок","paragraphs":["СоздаÑÑ ÑÑÑÑ
меÑнÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} оÑÐµÐ½Ñ Ð¿ÑоÑÑо. Ðа левой панели в веÑÑ
нем левом ÑÐ³Ð»Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñе кнопкÑ, ÑÑÐ¾Ð±Ñ Ð·Ð°Ð³ÑÑзиÑÑ Ð¸Ð·Ð¾Ð±Ñажение %{object} и ÑоздаÑÑ 3D-моделÑ. Также можно ввеÑÑи подÑÐºÐ°Ð·ÐºÑ Ð² поле «ÐпиÑиÑе, ÑÑо Ð²Ñ Ñ
оÑиÑе ÑоздаÑÑ» внизÑ. CGTrader AI авÑомаÑиÑеÑки ÑÑоÑнÑÐµÑ Ð²Ð°ÑÑ Ð¿Ð¾Ð´ÑказкÑ, поÑÑÐ¾Ð¼Ñ Ð´Ð¾ÑÑаÑоÑно кÑаÑкого опиÑаниÑ.","ÐÑÐ°Ð²Ð°Ñ Ð¿Ð°Ð½ÐµÐ»Ñ Ð´Ð°ÑÑ ÑиÑокие возможноÑÑи ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ 3D-моделÑÑ %{object}. ÐÑбеÑиÑе паÑамеÑÑÑ: Ñип ÑеÑки, маÑеÑиал, ÑпÑавление подÑказками и ÑоÑÐ¼Ð°Ñ Ñайла. Ðожно Ñакже наÑÑÑоиÑÑ ÑекÑÑÑÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ %{object}. ÐоÑле ввода ÑекÑÑовÑÑ
инÑÑÑÑкÑий или изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñе «ÐенеÑиÑоваÑÑ». ÐнÑÑÑÑÐ¼ÐµÐ½Ñ Ð¾Ð±ÑабоÑÐ°ÐµÑ Ð²Ð°Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð·Ð° неÑколÑко минÑÑ Ð² завиÑимоÑÑи Ð¾Ñ Ð½Ð°Ð³ÑÑзки ÑиÑÑемÑ, маÑеÑиала, Ñипа ÑеÑки, ÑоÑм, знаÑений seed и каÑеÑÑва."],"steps":["ÐведиÑе ÑекÑÑовое опиÑание и/или пÑикÑепиÑе ÑеÑеÑенÑное изобÑажение Ð´Ð»Ñ Ð¿Ð¾Ð²ÑÑÐµÐ½Ð¸Ñ ÑоÑноÑÑи ваÑей 3D-модели %{object}.","ÐÑбеÑиÑе один из наÑиÑ
пÑеÑеÑов или вÑбеÑиÑе движок ÐÐ, задайÑе колиÑеÑÑво полигонов и вÑбеÑиÑе Ñип маÑеÑиала Ð´Ð»Ñ 3D-модели %{object}.","ÐажмиÑе «ÐенеÑиÑоваÑÑ», ÑÑÐ¾Ð±Ñ ÑоздаÑÑ 3D-Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} по ваÑей подÑказке и/или ÑеÑеÑенÑÐ½Ð¾Ð¼Ñ Ð¸Ð·Ð¾Ð±ÑажениÑ.","СкаÑайÑе ÑозданнÑÑ 3D-Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} в ÑазлиÑнÑÑ
ÑоÑмаÑаÑ
(GLB, FBX, OBJ, STL или USDZ)."]},"intro":"ÐÑеÑе пÑоÑÑой и бÑÑÑÑÑй ÑпоÑоб ÑоздаÑÑ Ð²ÑÑококаÑеÑÑвеннÑÑ 3D-Ð¼Ð¾Ð´ÐµÐ»Ñ %{object} за неÑколÑко минÑÑ? ÐÐ°Ñ Ð¿ÐµÑедовой генеÑаÑÐ¾Ñ 3D-моделей %{object}, CGTrader AI, пÑеобÑазÑÐµÑ ÑекÑÑовÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð¸Ð»Ð¸ ÑеÑеÑенÑнÑе изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð² полноÑÑÑÑ Ð³Ð¾ÑовÑе модели. Ðн ÑабоÑÐ°ÐµÑ Ð½Ð° ведÑÑиÑ
движкаÑ
генеÑаÑии 3D: Meshy, Hunyuan и Tripo3D. ÐÑо Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ Ð±ÑÑÑÑо ÑоздаваÑÑ 3D-модели как наÑинаÑÑим, Ñак и опÑÑнÑм ÑпеÑиалиÑÑам в облаÑÑи дизайна Ð´Ð»Ñ Ð²Ð¸Ð·ÑализаÑии, ÑкÑпеÑименÑов и пÑоÑоÑипиÑованиÑ. ÐоддеÑживаеÑÑÑ Ð¿ÑеобÑазование ÑекÑÑа в 3D и изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð² 3D, ÑовмеÑÑимо Ñ 3D-пÑинÑеÑами. ÐагÑÑзиÑе изобÑажение в ÑоÑмаÑе JPG или PNG или введиÑе опиÑание ÑекÑÑом â CGTrader AI ÑÐ´ÐµÐ»Ð°ÐµÑ Ð²ÑÑ Ð¾ÑÑалÑное.","meta_description":"ÐÐ-генеÑаÑÐ¾Ñ 3D-моделей %{object} Ð¾Ñ CGTrader âï¸ Ð¡Ð¾Ð·Ð´Ð°Ð²Ð°Ð¹Ñе деÑализиÑованнÑе 3D-модели %{object} по ÑекÑÑÑ Ð¸Ð»Ð¸ изобÑажениÑ. ÐаÑниÑе беÑплаÑно.","primary_cta":"ÐаÑаÑÑ Ð³ÐµÐ½ÐµÑаÑÐ¸Ñ Ð±ÐµÑплаÑно","title":"ÐÐ-генеÑаÑÐ¾Ñ 3D-моделей %{object} (беÑплаÑно) | CGTrader"}}},"rules":{"errors":{"front_view_required":"ТÑебÑеÑÑÑ Ð¸Ð·Ð¾Ð±Ñажение вида ÑпеÑеди."}}},"helpers":{"select":{"prompt":"ÐÑбеÑиÑе: "},"submit":{"create":"СоздаÑÑ %{model}","submit":"СоÑ
ÑаниÑÑ %{model}","update":"СоÑ
ÑаниÑÑ %{model}"}},"home":{"index":{"3D-projects":{"info-section__cta":"УÑиÑÑ Ð±Ð¾Ð»ÑÑе","info-section__description":"Там, где лÑди Ñ Ð·Ð°Ñ
ваÑÑваÑÑими 3д пÑоекÑами оÑвеÑаÑÑ ÑаланÑливÑм 3д дизайнеÑ","info-section__heading_html":"\u003cstrong\u003e 3д пÑоекÑÑ \u003c/strong\u003e ФÑÐ¸Ð»Ð°Ð½Ñ Ð¥Ð°Ð±"},"categories-conatainer":{"browse_all":"ÐÑоÑмоÑÑеÑÑ Ð²Ñе модели","browse_all_tooltip":"ÐÑоÑмоÑÑеÑÑ Ð²Ñе 3д модели","discounts":"Скидки"},"cgdream":{"cta":"ÐаÑниÑе беÑплаÑно!","heading_html":"\u003cstrong\u003eÐÑÑледÑйÑе CGDream,\u003c/strong\u003e\u003c/br\u003e где ÐРвÑÑÑеÑаеÑÑÑ Ñ 3D-моделÑми.","text_html":"\u003cstrong\u003e CGDream \u003c/strong\u003e-ÑÑо пеÑедовое пÑиложение, коÑоÑое иÑполÑзÑÐµÑ Ð¼Ð¾ÑноÑÑÑ Ð³ÐµÐ½ÐµÑаÑивнÑÑ
моделей ÐРи 3D Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ð¾ÑÑÑÑаÑÑиÑ
2D-изобÑажений. \u003cstrong\u003e ваÑе ÑвоÑÑеÑкое пÑÑеÑеÑÑвие наÑинаеÑÑÑ ÑейÑаÑ. \u003c/strong\u003e"},"community":{"info-section__cta":"ÐÑиÑоединиÑÑÑÑ Ðº ÑообÑеÑÑвÑ","info-section__heading_html":"РегиÑÑÑаÑÐ¸Ñ CGTrader \u003cstrong\u003e ÐÑновной \u003c/strong\u003e","info-section__icon-list_1":{"de
16518scription":"ÐиÑÑина Ð²Ð°Ñ Ð»ÑÑÑий делаеÑ, полÑÑиÑÑ Ð¾Ð±ÑаÑнÑÑ ÑвÑÐ·Ñ Ð¸ пÑизнание","heading":"галеÑеи"},"info-section__icon-list_2":{"description":"УÑиÑе новÑе навÑки и наÑÑиÑÑ Ð´ÑÑгиÑ
","heading":"УÑебники"},"info-section__icon-list_3":{"description":"ÐайÑи ÑÑебнÑе поÑÐ¾Ð±Ð¸Ñ Ð¸ обÑÑдиÑÑ Ð´ÑÑгие ÑвÑзаннÑе Ñ 3д вопÑоÑов","heading":"ФоÑÑм"}},"covid":{"timer-strip__item":"ÐеÑплаÑнÑе 3д ÑеÑÑÑÑÑ Ð¿ÐµÑаÑи Ð´Ð»Ñ COVID-19 ÐаÑиÑа","timer-strip__item--button":"ÐÑоÑмоÑÑ 3д модели"},"enterprise":{"info-section__cta":"УÑиÑÑ Ð±Ð¾Ð»ÑÑе","info-section__heading_html":"3д УÑлÑги Ð´Ð»Ñ \u003cstrong\u003e ÐÑедпÑиÑÑие \u003c/strong\u003e","info-section__icon-list_1":"ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ ÑделаÑÑ ÑеализаÑÐ¸Ñ AR Ð´Ð»Ñ Ð²Ð°Ñ","info-section__icon-list_2":"ÐолÑÑе конвеÑÑий пÑодаж, менÑÑе пÑодÑÐºÑ Ð²Ð¾Ð·Ð²ÑаÑаеÑÑÑ","info-section__icon-list_3":"ÐаÑеÑÑво обеÑпеÑиваеÑÑÑ ÑÑÑогим QA"},"header":"3д модели Ð´Ð»Ñ VR / AR, 3д пеÑаÑи и компÑÑÑеÑной гÑаÑики","marketplace":{"info-section__description":"ÐÑбеÑиÑе из %{models_count} 3д модели Ð´Ð»Ñ Ð¿Ñиложений, ÑакиÑ
как игÑовÑе, AR / VR, ÑекламÑ, анимаÑии, ÑилÑмов и 3д пеÑаÑи","info-section__heading_html":"3д Ð¼Ð¾Ð´ÐµÐ»Ñ \u003cstrong\u003e ТоÑÐ³Ð¾Ð²Ð°Ñ Ð¿Ð»Ð¾Ñадка \u003c/strong\u003e","info-section__image-list_1":{"description":"ÐÑпиÑÑ Ð¿ÑоÑеÑÑионалÑнÑе 3д модели Ð´Ð»Ñ Ð²Ð°Ñего пÑоекÑа","heading":"3д модели"},"info-section__image-list_2":{"description":"ÐизкополигоналÑнÑÑ
PBR 3д ÐÐ¾Ð´ÐµÐ»Ñ Ð³Ð¾Ñова к видеоигÑам, VR \u0026 AR пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² Ñежиме ÑеалÑного вÑемени","heading":"ÐизкополигоналÑнÑÑ
PBR 3д модели"},"info-section__image-list_3":{"description":"ÐайÑи 3д пеÑаÑÑ Ðизайн Ð´Ð»Ñ 3д пÑинÑеÑов","heading":"3д пеÑаÑÑ Ð¼Ð¾Ð´ÐµÐ»ÐµÐ¹"},"view_all":"ÐÑоÑмоÑÑеÑÑ Ð²Ñе"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"ÐÑевÑаÑиÑе изобÑажение в 3D-моделÑ","title":"ÐзобÑажение в 3D"},"text_to_3d":{"description":"ÐпиÑиÑе ÑÐ²Ð¾Ñ Ð¸Ð´ÐµÑ, ÑÑÐ¾Ð±Ñ ÑоздаÑÑ 3D-моделÑ","title":"ТекÑÑ Ð² 3D"}},"ai_section_title":"СоздаÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÐÐ","aria_label":"ÐоиÑковÑе подÑказки","columns":{"cg":{"search_label":"ÐÑкаÑÑ Ð² 3D-моделÑÑ
","title":"3D-модели"},"print":{"search_label":"ÐÑкаÑÑ Ð² 3D-пеÑаÑи","title":"Ðодели Ð´Ð»Ñ 3D-пеÑаÑи"}}},"sell":{"info-section__heading_html":"\u003cstrong\u003e ÐÑодам \u003c/strong\u003e 3д модели и пÑоекÑÑ ÐайÑи ÐнеÑÑаÑнÑй","info-section__icon-list_1":{"description":"ÐÑодаÑÑ 3д модели и заÑабоÑаÑÑ Ð´Ð¾ 85% ÑоÑлÑи","link":"ÐÑодаÑÑ 3д модели"},"info-section__icon-list_2":{"description":"РабоÑа Ñ ÐºÐ¾ÑпоÑаÑивнÑми клиенÑами","link":"ÐолÑÑиÑÑ ÐвалиÑиÑиÑованнÑе"},"info-section__icon-list_3":{"description":"ÐÑоизведиÑе Ñвои навÑки и полÑÑиÑÑ Ð´Ð¾ 95% ÑоÑлÑи","link":"ÐÑоÑмоÑÑ 3д моделиÑование РабоÑа"},"info-section__icon-list_4":{"description":"СоздайÑе Ñвой поÑÑÑÐµÐ»Ñ Ð¸ бÑÑÑ Ð²Ð¸Ð´Ð¸Ð¼Ñм","link":"ÐÑоÑмоÑÑ 3д ÐонÑÑÑÑкÑоÑÑ"}},"seo":{"description":"ÐÑÑледÑйÑе более 2 миллионов 3D моделей онлайн Ð´Ð»Ñ Ð¿ÑоекÑов пеÑаÑи, игÑ, VR/AR и дизайна. СкаÑивайÑе, наÑÑÑаивайÑе или нанимайÑе 3D ÑкÑпеÑÑов - вÑÑ Ð½Ð° CGTrader.","title":"CGTrader - 3D-модели и маÑкеÑÐ¿Ð»ÐµÐ¹Ñ 3D-пеÑаÑи"}}},"homepage":{"budget_counter":{"range_0_10":"Ðо $10","range_10_20":"$10 - $20","range_20_15000":"Ðолее $20"},"quotes":{"quote_0":{"author":{"name":"Ð¥Ñан ÐаÑÐ»Ð¾Ñ Ð¥Ð¸Ð¼ÐµÐ½ÐµÑ","username":"CGShape"},"text":"ÐонизиÑÑ ÐºÐ¾Ð¼Ð¸ÑÑии, пÑинÑÑÑе Ð¾Ñ Ð¿ÑодавÑов ознаÑÐ°ÐµÑ Ð±Ð¾Ð»ÐµÐµ вÑÑокие ÑÐµÐ½Ñ Ð´Ð»Ñ Ð¿Ð¾ÐºÑпаÑелей. ÐÑовеÑÑÑе и ÑÑавниÑе ÑÐµÐ½Ñ Ð½Ð° CGTrader и дÑÑгие магазинÑ."},"quote_1":{"author":{"name":"Ð¥Ñан ÐаÑÐ»Ð¾Ñ Ð¥Ð¸Ð¼ÐµÐ½ÐµÑ","username":"CGShape"},"text":"Ðаиболее ÑÑкое пÑеимÑÑеÑÑво CGTrader плоÑко плаÑа ÑиÑÑема акÑиваÑии, коÑоÑÐ°Ñ Ð´Ð°ÐµÑ Ð½Ð°Ð¼ вÑÑокÑÑ Ð¾ÑдаÑÑ. ÐÑ Ð½Ðµ беÑеÑе комиÑÑÐ¸Ñ Ð¿ÑоÑÐµÐ½Ñ Ð½Ð°ÑиÑ
пÑодаж. ÐоÑле пÑодажи, Ð¼Ñ Ð¿Ð¾Ð»ÑÑаем 100% Ð¾Ñ ÑÑоимоÑÑи. ТолÑко еÑли Ð¼Ñ Ñ
оÑим пÑодолжаÑÑ Ð¿ÑодаваÑÑ ÑÑÐ¾Ñ Ð¿ÑодÑкÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ повÑоÑно акÑивиÑоваÑÑ ÐµÐ³Ð¾ еÑе Ñаз, заплаÑив $ 5. ÐлеганÑное ÑеÑение."},"quote_10":{"author":{"name":"ThreeD Ken","username":"3DKen"},"text":"ÐлоÑÐºÐ°Ñ ÑиÑÑема акÑиваÑии плаÑÑ Ð³ÐµÐ½Ð¸Ð°Ð»Ñна. Ðне бÑло инÑеÑеÑно, поÑÐµÐ¼Ñ Ð½Ð¸ÐºÑо не подÑмал об ÑÑом ÑанÑÑе. ÐоÑле пÑодажи, заплаÑиÑÑ Ð½ÐµÐ±Ð¾Ð»ÑÑÑÑ Ð¿Ð»Ð°ÑÑ, ÑÑÐ¾Ð±Ñ Ð°ÐºÑивиÑоваÑÑ Ð¿ÑодÑÐºÑ Ð¸ ÑÑо вÑе. ÐÑÐ¾Ð´Ð°Ð²ÐµÑ Ð½Ð°Ñ
одиÑÑÑ Ð² полном конÑÑоле."},"quote_11":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"ÐÑÑÑ Ð´Ð²Ðµ веÑи, коÑоÑÑе мне нÑавÑÑÑÑ Ð±Ð¾Ð»ÑÑе вÑего о CGTrader. Ðо-пеÑвÑÑ
неÑ, Ñам Ð½ÐµÑ ÑкÑÑÑÑй ÑмÑÑл ÑÑо-либо здеÑÑ. Ðам не нÑжно бÑÑÑ Ð¾ÑÑоÑожнÑм Ñ CGTrader. Ðо-вÑоÑÑÑ
, ÑÑÐ¾Ñ Ð¼Ð°Ð³Ð°Ð·Ð¸Ð½ Ñ
Ñдожниками и Ð´Ð»Ñ Ñ
Ñдожников. Ðни понимаÑÑ Ð²Ð°Ñ Ð»ÑÑÑе. ЧÑо-Ñо беÑÐ¿Ð¾ÐºÐ¾Ð¸Ñ Ð²Ð°Ñ Ð·Ð´ÐµÑÑ? ... пÑÑÑÑ Ð¾Ð½Ð¸ знаÑÑ, и они бÑдÑÑ ÑбедиÑÑÑÑ, ÑÑо Ð²Ñ ÑÑвÑÑвовали ÑÐµÐ±Ñ Ð·Ð´ÐµÑÑ ÐºÐ¾Ð¼ÑоÑÑно."},"quote_12":{"author":{"name":"Sid Naique","username":"sidnaique"},"text":"Ðини-плаÑа ÑиÑÑема акÑиваÑии ÑвлÑеÑÑÑ Ð»ÑÑÑим! (Ðо кÑайней меÑе, Ñ Ð½Ðµ вÑÑÑеÑал ниÑего лÑÑÑе, Ñем ÑÑо). Ðго оÑÐµÐ½Ñ ÑеалиÑÑиÑнÑй и ÑпÑаведливÑй по оÑноÑÐµÐ½Ð¸Ñ Ðº пÑодавÑам. Ðни не забоÑÑÑÑÑ, ÑколÑко пÑибÑли Ð²Ñ Ð´ÐµÐ»Ð°ÐµÑе, пÑоÑÑо плаÑиÑе ÑикÑиÑованнÑÑ Ð°ÑенднÑÑ Ð¿Ð»Ð°ÑÑ. ÐРеÑли Ð²Ñ Ð½Ðµ ÑделаеÑе какие-либо пÑодажи, Ð²Ñ Ð½Ðµ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿Ð»Ð°ÑиÑÑ Ð°ÑенднÑÑ Ð¿Ð»Ð°ÑÑ Ð»Ð¸Ð±Ð¾. ЯÑмаÑка CG ÑоÑговли здеÑÑ!"},"quote_13":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"CGTrader пÑÐ¸Ð²Ð»ÐµÐºÐ°ÐµÑ ÐºÐ»Ð¸ÐµÐ½Ñов даже из ÑазвиваÑÑиÑ
ÑÑ ÑÑÑан, поÑколÑÐºÑ ÑÐµÐ½Ñ Ð´ÐµÑевле, Ñем в дÑÑгиÑ
магазинаÑ
. Ð Ñо же вÑÐµÐ¼Ñ Ð°Ð²ÑоÑÑ Ð¼Ð¾Ð³ÑÑ Ð·Ð°ÑабоÑаÑÑ Ð±Ð¾Ð»ÑÑе, поÑÐ¾Ð¼Ñ ÑÑо Ð½ÐµÑ Ñакой веÑи, как вÑÑокие ÑÑавки комиÑÑионного вознагÑаждениÑ. ÐÑо пÑавилÑнÑй пÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¾ÑениÑÑ ÑабоÑÑ 3D Ñ
Ñдожников."},"quote_14":{"author":{"name":"Leandro Salerno","username":"leansaler"},"text":"ÐнÑÑиÑивнÑй инÑеÑÑÐµÐ¹Ñ Ð¸Ð·Ð´Ð°ÑÐµÐ»Ñ Ð¸ инноваÑионнÑÑ
инÑÑÑÑменÑов, Ñакие как ÑекомендаÑии tagов и гибкие опиÑÐ°Ð½Ð¸Ñ ÑоÑÐ¼Ñ Ð´ÐµÐ»Ð°ÐµÑ Ð¿ÑоÑеÑÑ Ð¿ÑбликаÑии легко и бÑÑÑÑо."},"quote_15":{"author":{"name":"ХавÑÐµÑ Almazor","username":"jvr3D"},"text":"ÐодÑ
од CGTrader о пÑодаже 3D оÑлиÑаеÑÑÑ, и не Ð¸Ð¼ÐµÐµÑ Ð½Ð¸Ñего обÑего Ñ Ð´ÑÑгими магазинами, коÑоÑÑе Ñ Ð¸ÑполÑзовал, ÑÑÐ¾Ð±Ñ Ð¿ÑодаÑÑ. ÐбÑаÑиÑе низкÑÑ Ð¿Ð»Ð°ÑÑ Ð² ÑазмеÑе 5 $ поÑле пÑодажи ÑÑо оÑлиÑÐ½Ð°Ñ Ð¸Ð´ÐµÑ, и позволÑÑе мне пÑедложиÑÑ ÑамÑе низкие ÑÐµÐ½Ñ Ð·Ð´ÐµÑÑ. Ðаказ
16518Ñик и иÑполниÑÐµÐ»Ñ Ð¿ÑиноÑÑÑ Ð¿Ð¾Ð»ÑÐ·Ñ ÑÑим ÑпоÑобом ÑабоÑÑ."},"quote_16":{"author":{"name":"ХавÑÐµÑ Almazor","username":"jvr3D"},"text":"СиÑÑема загÑÑзки пÑоÑÑа и понÑÑна. ÐÑо Ñ
оÑоÑо, ÑÑÐ¾Ð±Ñ Ð·Ð½Ð°ÑÑ, ÑÑо за ÑÑим пÑоекÑом лÑди Ñ Ð¼Ð½Ð¾Ð³Ð¾Ð»ÐµÑним опÑÑом в вопÑоÑаÑ
компÑÑÑеÑной гÑаÑики. РлÑбое вÑÐµÐ¼Ñ Ñ Ð¼ÐµÐ½Ñ Ð±Ñла пÑоблема, команда CGTrader ÑикÑиÑованной бÑÑÑÑо."},"quote_17":{"author":{"name":"ХавÑÐµÑ Almazor","username":"jvr3D"},"text":"CGTrader позволÑÐµÑ Ð¼Ð½Ðµ ÑвÑзаÑÑ Ñвой пÑоÑÐ¸Ð»Ñ Ñ Ð¼Ð¾ÐµÐ¹ лиÑной веб-ÑÑÑаниÑÑ. ÐлиенÑÑ Ð¼Ð¾Ð³ÑÑ ÑвÑзаÑÑÑÑ Ñо мной, еÑли они не ÑвеÑÐµÐ½Ñ Ð² Ñ
аÑакÑеÑиÑÑике пÑедмеÑа они Ñ
оÑÑÑ ÐºÑпиÑÑ Ð¸Ð»Ð¸ пÑоÑÑо Ñ
оÑиÑе его модиÑикаÑиÑ. ÐÑо как имеÑÑ Ð¿ÐµÑÑоналÑнÑй 3D-магазин в болÑÑом ÑÑнке!"},"quote_2":{"author":{"name":"Ð¥Ñан ÐаÑÐ»Ð¾Ñ Ð¥Ð¸Ð¼ÐµÐ½ÐµÑ","username":"CGShape"},"text":"ÐÑ Ð¿Ð¾Ð»ÑзовалиÑÑ Ð±Ð¾Ð»ÑÑой и оÑзÑвÑивой поддеÑжкой Ñо ÑÑоÑÐ¾Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CGTrader. ÐеÑÑонал лÑбезно пÑедложил ÑделаÑÑ Ð¿ÑбликаÑÐ¸Ñ Ð²ÑеÑ
моделей Ð´Ð»Ñ Ð½Ð°Ñ, коÑоÑÑй ÑвлÑеÑÑÑ Ð±Ð¾Ð»ÑÑим подÑпоÑÑем Ð´Ð»Ñ Ð¿ÑоÑеÑÑионалÑнÑÑ
пÑодавÑов."},"quote_3":{"author":{"name":"Ð¥Ñан ÐаÑÐ»Ð¾Ñ Ð¥Ð¸Ð¼ÐµÐ½ÐµÑ","username":"CGShape"},"text":"Ðа ÑÑой плаÑÑоÑме Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ пÑедложиÑÑ Ð³Ð¾Ñаздо более вÑгоднÑе ÑÐµÐ½Ñ Ð´Ð»Ñ Ð½Ð°ÑиÑ
клиенÑов. ÐапÑимеÑ, вÑе наÑи пÑодÑкÑÑ Ð¿Ð¾ Ñене на 20% ниже, Ñем где-либо еÑе, и Ð¼Ñ Ð¿Ð¾-пÑÐµÐ¶Ð½ÐµÐ¼Ñ Ð¿Ð¾Ð»ÑÑаÑÑ Ð±Ð¾Ð»ÑÑе пÑибÑли по ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ Ð´ÑÑгими магазинами!"},"quote_4":{"author":{"name":"ХеÑÑÑ ÐедÑоÑа Vidal","username":"NoneCG"},"text":"ÐÑо ÐУЧШÐРна ÑегоднÑÑний Ð´ÐµÐ½Ñ ÑиÑÑема. ÐÑе дÑÑгие инÑеÑнеÑ-Ð¼Ð°Ð³Ð°Ð·Ð¸Ð½Ñ 3D взÑÑÑ% Ð¾Ñ Ð½Ð°Ñей пÑибÑли. ÐÑо бÑла оÑобенноÑÑÑ, коÑоÑÐ°Ñ Ð¿Ñивлекла наÑе внимание в CGTrader Ñ Ñамого наÑала. ÐлиенÑÑ, покÑпка на CGTrader, знаеÑ, ÑÑо болÑÑÐ°Ñ ÑаÑÑÑ Ð¸Ñ
денÑги идÑÑ Ðº авÑоÑÑ, коÑоÑÑй в конÑе конÑов бÑÐ´ÐµÑ Ð´ÐµÐ»Ð°ÑÑ Ð±Ð¾Ð»ÑÑе и лÑÑÑе модели, еÑли иÑ
пÑибÑÐ»Ñ ÑлÑÑÑиÑÑ."},"quote_5":{"author":{"name":"ХеÑÑÑ ÐедÑоÑа Vidal","username":"NoneCG"},"text":"CGTrader ÑвлÑеÑÑÑ Ð¸Ð½ÑеÑнеÑ-магазин 3D, коÑоÑÑй Ñделал ÑамÑй бÑÑÑÑÑй ÑоÑÑ Ð¿Ñодаж и пÑибÑли Ð´Ð»Ñ Ð½Ð°Ñ. СиÑÑема акÑиваÑии плоÑко-плаÑа ÑвлÑеÑÑÑ Ð»ÑÑÑей Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи, как ÑÑо вознагÑÐ°Ð¶Ð´Ð°ÐµÑ ÑоздаÑÐµÐ»Ñ ÐºÐ¾Ð½ÑенÑа, а не поÑÑедники."},"quote_6":{"author":{"name":"RiÄardas Marozas","username":"ÑабоÑий наÑоÑÐ½Ð°Ñ ÑÑанÑиÑ"},"text":"Ðогда Ñ Ð¿Ð¾Ð»ÑÑил $ 160 на мой ÑÑÐµÑ Paypal, не знал, ÑÑо пÑоиÑÑ
одиÑ, как ÑÑо никогда не ÑлÑÑалоÑÑ ÑанÑÑе, но поÑом Ñ Ð¿Ð¾Ð´Ñмал, ÑÑо ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ñодажа CGTrader и Ñ Ð±Ñл пÑав. ÐÑодан ÑÐ¾Ñ Ð¶Ðµ Ð¿Ð°ÐºÐµÑ Ð½Ð° Turbosquid в пÑоÑлом меÑÑÑе за $ 189, но поÑле Ñого, как 40% ÑÑавка ÑоÑлÑи и 30% налога, вÑе, ÑÑо Ñ Ð¿Ð¾Ð»ÑÑил $ 52,92 - гÑоÑи по ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ $ 160 Ð¾Ñ CGTrader. ÐлÑÑ ÐºÐ»Ð¸ÐµÐ½Ñ Ð·Ð°Ð¿Ð»Ð°Ñил $ 29 менÑÑе - ÑепеÑÑ ÑÑо пÑавилÑное дело."},"quote_7":{"author":{"name":"ThreeD Ken","username":"3DKen"},"text":"СнаÑала Ñ ÑкепÑиÑеÑки оÑноÑилÑÑ Ðº Ñакой Ñ
оÑоÑей Ñделки Ð´Ð»Ñ Ð¿ÑодавÑов, коÑоÑÐ°Ñ Ð½Ðµ ÑвÐ
16518»ÑеÑÑÑ Ð½Ð¾Ñмой Ð´Ð»Ñ ÐºÑÑпнÑÑ
инÑеÑнеÑ-магазинов 3D. Ðогда Ñ Ñзнал о ÑиÑÑеме акÑиваÑии плоÑко-плаÑе, Ñ Ð±Ñл поÑажен Ñаким ÑвоÑÑеÑким ÑпоÑобом пÑодажи ÑиÑÑовÑÑ
акÑивов. ÐÑодажа, заÑем акÑивиÑоваÑÑ, заплаÑив Ð²Ð·Ð½Ð¾Ñ Ð² ÑазмеÑе $ 5. ÐÑе ÑÑо Ð¸Ð¼ÐµÐµÑ ÑмÑÑл Ð´Ð»Ñ Ð¼ÐµÐ½Ñ. Я загÑÑзил неÑколÑко, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¿ÑобоваÑÑ Ð¸ дейÑÑвиÑелÑно, когда Ñ Ð¿Ð¾Ð»ÑÑил ÑÐ²Ð¾Ñ Ð¿ÐµÑвÑÑ Ð¿ÑодажÑ, ÑÑо 100% ÑоÑлÑи!"},"quote_8":{"author":{"name":"ThreeD Ken","username":"3DKen"},"text":"Я Ñак пÑивÑк многие дÑÑгие ÑайÑÑ, заÑÑд Ð¾Ñ 30% - 60% комиÑÑии, пока Ñ Ð½Ðµ обнаÑÑжил CGTrader. Ðак пÑодавеÑ, Ñ Ð¾Ð¿Ñеделенно как вÑÑокий пÑоÑÐµÐ½Ñ Ð¾ÑÑиÑлений пÑибÑли."},"quote_9":{"author":{"name":"ThreeD Ken","username":"3DKen"},"text":"ÐпÑÑ Ð¿ÑÐ¾Ð´Ð°Ð²ÐµÑ ÑвлÑеÑÑÑ ÑанÑаÑÑиÑеÑким. ÐÑедÑÑавление пÑодÑкÑа ÑвлÑеÑÑÑ Ð²ÐµÑеÑ. Рда, ÑиÑÑема позволила мне ÑоÑ
ÑаниÑÑ ÑеÑновик моего пÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿ÑодÑкÑа на каждом ÑÑапе пÑÑи."}}},"hyperwallet":{"failed_payment_agreement":"ÐÑоизоÑла непÑÐµÐ´Ð²Ð¸Ð´ÐµÐ½Ð½Ð°Ñ Ð¾Ñибка","success_notification":"ÐлаÑÑжное ÑоглаÑение бÑло ÑÑпеÑно обновлено.","success_payment_agreement":"ÐлаÑÑжное ÑоглаÑение бÑло ÑÑпеÑно оÑпÑавлено."},"i18n":{"plural":{"rule":{}},"transliterate":{"rule":{}}},"item-search-filters":{"3d-models-url":"3d-modeli","3d-print-models-url":"3d-pechat-modeli","dedicated-search-page-url":{"animated":"/animirovannaya-","free":"/besplatnye-","low_poly":"/nizkopoligonalnyy-","pbr":"/pbr-","rigged":"/sfalsifitsirovano-"}},"item_use_case":{"not_valid":"ÐедопÑÑÑимÑй Ñайл","pundit":{"not_authorized":"У Ð²Ð°Ñ Ð½ÐµÑ Ð¿Ñав Ð´Ð»Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑÑого дейÑÑвиÑ."},"title":"СлÑÑай иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ %{item_name}"},"items":{"already_purchased":"ÐÑ Ñже пÑиобÑели ÑÑÐ¾Ñ ÑоваÑ.","filters":{"attributes":"ÐÑÑибÑÑÑ","free":"ÐеÑплаÑно","max_value":"$ 500 +","min_value":"$ 2","reset":"СбÑоÑиÑÑ ÑилÑÑÑÑ"},"footer":{"next":"СледÑÑÑаÑ","per_page":"ÐолиÑеÑÑво на ÑÑÑаниÑе:","previous":"ÐÑедÑдÑÑаÑ"},"geometry_type_forbidden":"Geometry type forbidden!","last_card":{"button_text":"ÐаказаÑÑ Ð¿Ð¾Ð»ÑзоваÑелÑÑкÑÑ 3д моделÑ","text":"Ðе ÑдалоÑÑ Ð½Ð°Ð¹Ñи Ñо, ÑÑо Ð²Ñ Ð¸ÑеÑе?"},"migrations":{"errors":{"invalid_owner":"ÐовÑй Ð²Ð»Ð°Ð´ÐµÐ»ÐµÑ Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑинÑÑÑ Ð¿ÑедмеÑÑ.","unpublished_items":"ÐÑе пÑедмеÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð¾Ð¿ÑбликованÑ."}},"new_price_applied":"ÐовÑе ÑÐµÐ½Ñ Ð±Ñли ÑÑпеÑно пÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ñ ÐºÐ¾ вÑем ÑоваÑам.","new_price_applied_to_selected_items":"ÐовÑе ÑÐµÐ½Ñ Ð±Ñли ÑÑпеÑно пÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ñ Ðº вÑбÑаннÑм ÑоваÑам.","new_prices_to_filtered_models":"ÐовÑе ÑÐµÐ½Ñ Ð±Ñли ÑÑпеÑно пÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ñ ÐºÐ¾ вÑем оÑÑилÑÑÑованнÑм ÑоваÑам.","order_processed":"Ðаказ обÑабоÑан.","order_processing":"Ðаказ обÑабаÑÑваеÑÑÑ.","something_went_wrong":"ЧÑо-Ñо поÑло не Ñак","title_error":"Title should not contain non-latin symbols","uniq_user":"Ñже оÑпÑавил ваÑÐ¸Ð°Ð½Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð»Ñ ÑÑого ÑоваÑа","upload_error":"ÐÑибка загÑÑзки.","validate_license_for_zero_price":"is not valid for free item","validate_minimum_price":"ÐÑедложение по Ñене не должно бÑÑÑ Ð½Ð¸Ð¶Ðµ минималÑнÑÑ
50% Ð¾Ñ Ð¸ÑÑ
одной ÑенÑ","verify_printable_formats_error":"ÐожалÑйÑÑа, загÑÑзиÑе Ñ
оÑÑ Ð±Ñ Ð¾Ð´Ð¸Ð½ Ñайл в ÑоÑмаÑе .stl, .obj или .wrl.","you_can_not_delete_models":"ÐÑ Ð½Ðµ можеÑе ÑдалиÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projects ÑпÑоÑÐ°ÐµÑ Ð½Ð°Ð¹Ð¼ квалиÑиÑиÑованнÑÑ
3D-ÑÑиланÑеÑов и Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ ÑеÑиÑÑ Ð²Ñе задаÑи моделиÑованиÑ.","heading_html":"ÐознакомÑÑеÑÑ Ñ Ð»ÑÑÑей плаÑÑоÑмой Ð´Ð»Ñ ÑÑиланÑеÑов Ð´Ð»Ñ Ð²Ð°ÑиÑ
\u003cstrong\u003e3D-Ð·Ð°Ð´Ð°Ñ Ð¿Ð¾ моделиÑованиÑ\u003c/strong\u003e"},"sections":{"call_to_action":{"description":"ÐпÑбликÑйÑе Ñвой пÑÐ¾ÐµÐºÑ Ð±ÐµÑплаÑно и ÑбедиÑеÑÑ, как легко ÑеÑиÑÑ ÑледÑÑÑÑÑ Ð·Ð°Ð´Ð°ÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸ÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ 3D-пÑоекÑов.","title":"Ð
16518аймиÑе лÑÑÑиÑ
ÑпеÑиалиÑÑов по 3D Ñже ÑегоднÑ!"},"freelancer_selection":{"title":"СделайÑе Ñвой ÑледÑÑÑий 3D-пÑÐ¾ÐµÐºÑ ÑÑпеÑнÑм","widest_selection":{"description":"Ðе ÑоглаÑайÑеÑÑ Ð½Ð° менÑÑее. ÐдеÑÑ ÑабоÑаÑÑ 40 000 ÑÑиланÑ-3D-дизайнеÑов. CGTrader â кÑÑпнейÑÐ°Ñ Ð¿Ð»Ð°ÑÑоÑма, коÑоÑÐ°Ñ Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ Ð²Ð°Ð¼ найÑи квалиÑиÑиÑованнÑÑ
ÑпеÑиалиÑÑов: моделлеÑов, анимаÑоÑов, ÑиггеÑов, ÑкÑпеÑÑов по 3D-пеÑаÑи и вÑеÑ
, кÑо Ð¼ÐµÐ¶Ð´Ñ Ð½Ð¸Ð¼Ð¸.","title":"СамÑй ÑиÑокий вÑÐ±Ð¾Ñ 3D-ÑÑиланÑеÑов"}},"how_it_works":{"steps":{"describe":{"description":"РаÑÑкажиÑе нам, ÑÑо вам нÑжно. ÐÑполÑзÑйÑе пÑоÑÑÑÑ ÑоÑмÑ, добавÑÑе изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¸ опÑбликÑйÑе ÑÐ²Ð¾Ñ ÑÑиланÑ-пÑедложение за неÑколÑко минÑÑ.","title":"ÐпиÑиÑе Ñвой пÑоекÑ"},"pay":{"description":"ÐезопаÑно внеÑиÑе пÑедоплаÑÑ Ð² CGTrader и дайÑе знаÑÑ ÑÑиланÑеÑÑ, ÑÑо Ð²Ñ Ð³Ð¾ÑÐ¾Ð²Ñ Ð½Ð°ÑаÑÑ. ÐбÑайÑеÑÑ, делиÑеÑÑ Ñайлами и оÑÑлеживайÑе Ñ
од пÑоекÑа в Ñдобном ÑабоÑем пÑоÑÑÑанÑÑве. ÐеÑеведиÑе оплаÑÑ ÑолÑко Ñогда, когда бÑдеÑе доволÑÐ½Ñ Ð¸ÑоговÑм ÑезÑлÑÑаÑом.","title":"ÐплаÑиÑе ÑезÑлÑÑаÑ"},"select":{"bullets":["ÐолÑÑайÑе пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ ÐºÐ²Ð°Ð»Ð¸ÑиÑиÑованнÑÑ
дизайнеÑов пÑÑмо на ÑÐ²Ð¾Ñ Ð¿Ð¾ÑÑÑ","ÐбÑайÑеÑÑ Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑами в ÑеалÑном вÑемени","ÐÑоÑмаÑÑивайÑе иÑ
пÑедÑдÑÑие пÑоекÑÑ","ÐÑ Ñакже можеÑе иÑкаÑÑ, ÑилÑÑÑоваÑÑ Ð¸ пÑиглаÑаÑÑ ÑÑиланÑеÑов по иÑ
3D-навÑкам, ÑейÑингÑ, а Ñакже по иÑполÑзÑÐµÐ¼Ð¾Ð¼Ñ ÐРили ÑоÑмаÑам"],"title":"ÐÑбеÑиÑе лÑÑÑего ÑÑиланÑеÑа"}},"title":"ÐÑполниÑе ÑÐ²Ð¾Ñ Ð·Ð°Ð´Ð°ÑÑ Ð² 3 пÑоÑÑÑÑ
Ñага"},"payment_quality":{"description":"CGTrader гаÑанÑиÑÑеÑ, ÑÑо ÑÑлÑги ÑÑиланÑеÑов бÑдÑÑ ÑооÑвеÑÑÑвоваÑÑ Ð²Ð°Ñим ÑÑебованиÑм и бÑдÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ñ Ð² ÑÑок. ÐаÑа команда конÑÑÐ¾Ð»Ñ ÐºÐ°ÑеÑÑва вÑегда доÑÑÑпна, когда она вам нÑжна.","title":"ÐаÑанÑÐ¸Ñ ÐºÐ°ÑеÑÑва"},"secure_payments":{"description":"ÐаÑа ÑÑкÑоÑ-ÑиÑÑема гаÑанÑиÑÑÐµÑ Ð·Ð°ÑиÑÑ Ð²Ð°ÑиÑ
ÑÑедÑÑв, и Ð²Ñ Ð¿Ð»Ð°ÑиÑе ÑолÑко Ñогда, когда доволÑÐ½Ñ ÐºÐ¾Ð½ÐµÑнÑм ÑезÑлÑÑаÑом.","title":"ÐезопаÑнÑе плаÑежи"},"workspace_convenience":{"description":"ÐабÑдÑÑе о неÑдобÑÑве поÑÑоÑнного пеÑеклÑÑÐµÐ½Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ°Ð¼Ð¸ и ÑазнÑми инÑÑÑÑменÑами. С помоÑÑÑ Ð²Ñделенного ÑабоÑего пÑоÑÑÑанÑÑва Ð²Ñ ÑможеÑе легко ÑпÑавлÑÑÑ Ð²Ñем в одном меÑÑе: неÑколÑкими пÑоекÑами, ÑÑеÑами, пеÑепиÑкой, обменом Ñайлами и многим дÑÑгим.","title":"УдобÑÑво единого ÑкÑана"}},"shared":{"post_project_cta":"ÐпÑбликоваÑÑ Ð¿ÑоекÑ"}},"navigation":{"find_jobs_cta":"ÐайÑи 3D-ваканÑии","hire_freelancers_cta":"ÐаймиÑе 3D-ÑÑиланÑеÑов","how_it_works":"Ðак ÑÑо ÑабоÑаеÑ","why_projects":"ÐоÑÐµÐ¼Ñ 3D-пÑоекÑÑ"}},"agreed_to_terms_of_use":"ÐÑ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑоглаÑиÑÑÑÑ Ñ Ð£ÑловиÑми и положениÑми 3D Projects, ÑÑÐ¾Ð±Ñ Ð¿ÑодолжиÑÑ.","budget_error_message":"ÑлиÑком вÑÑок","check_designer_uniqueness_error":"ÐизайнеÑа можно пÑиглаÑиÑÑ ÑолÑко один Ñаз","check_ownership_error":"ÐÑиглаÑаÑÑий не ÑвÐ
16518»ÑеÑÑÑ Ð²Ð»Ð°Ð´ÐµÐ»ÑÑем пÑоекÑа","check_status_error":"ÐизайнеÑов можно пÑиглаÑаÑÑ ÑолÑко в одобÑеннÑе пÑоекÑÑ.","deadline_error_message":"ÐÑайний ÑÑок должен бÑÑÑ Ð² бÑдÑÑем","discount_code_error":"ÐзвиниÑе, код Ñкидки не ÑÑÑеÑÑвÑÐµÑ Ð¸Ð»Ð¸ ÑÑок его дейÑÑÐ²Ð¸Ñ Ð¸ÑÑÑк.","email_subject":"ÐозможноÑÑÑ 3D пÑоекÑа: %{subject}","error_check_application_uniqueness":"ÐÑ Ð¼Ð¾Ð¶ÐµÑе подаÑÑ Ð·Ð°ÑÐ²ÐºÑ ÑолÑко один Ñаз","error_check_applier":"ÐÑ Ð½Ðµ можеÑе подаÑÑ Ð·Ð°ÑÐ²ÐºÑ Ð½Ð° Ñвой ÑобÑÑвеннÑй 3D пÑоекÑ","error_check_job_availability":"ÐолÑзоваÑÐµÐ»Ñ Ð½Ðµ Ð¸Ð¼ÐµÐµÑ Ð¿Ñава подаваÑÑ Ð·Ð°ÑвкÑ","error_check_job_status":"ÐодаÑа заÑвок на пÑоекÑÑ Ð¿ÑиоÑÑановлена до завеÑÑÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ пÑоÑеÑÑа модеÑаÑии, обÑÑно в ÑеÑение 3 ÑабоÑиÑ
дней. СпаÑибо за понимание!","modeling_request_failed":"ÐапÑÐ¾Ñ Ð½Ð° моделиÑование не вÑполнен!","offer_has_been_sent":"СпаÑибо, ваÑе пÑедложение бÑло оÑпÑавлено!","offer_is_closed":"ÐÑедложение закÑÑÑо.","payment_successful":"ÐплаÑа ÑÑпеÑно пÑоизведена.","payment_under_review":"ÐлаÑÑж наÑ
одиÑÑÑ Ð½Ð° пÑовеÑке.","share_with_yourself_error":"ÐелÑÐ·Ñ Ð´ÐµÐ»Ð¸ÑÑÑÑ Ñаблонами «ÐанÑÑÑ Ð¼ÐµÐ½Ñ» Ñ Ñамим Ñобой","system_messages":{"buyer_cancels_job":"ÐÑÐ¾ÐµÐºÑ Ð±Ñл оÑменÑн и пеÑемеÑÑн во Ð²ÐºÐ»Ð°Ð´ÐºÑ %{archive_url}.","buyer_edits_hire_me_template":"ÐеÑали пÑоекÑа бÑли Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ñ ÐºÐ»Ð¸ÐµÐ½Ñом.","buyer_edits_job_details":"ÐеÑали пÑоекÑа бÑли обновленÑ.","buyer_marks_job_as_finished":"ÐÑÐ¾ÐµÐºÑ Ð±Ñл оÑмеÑен как завеÑÑÑннÑй и пеÑемеÑÑн во Ð²ÐºÐ»Ð°Ð´ÐºÑ %{archive_url}.","buyer_marks_job_as_finished_with_resell":"ÐÐ»Ð¸ÐµÐ½Ñ Ð¾ÑмеÑил пÑÐ¾ÐµÐºÑ ÐºÐ°Ðº завеÑÑÑннÑй и ÑазÑеÑил вам пÑодаваÑÑ ÑезÑлÑÑаÑÑ Ð½Ð° CGTrader. Ðе забÑдÑÑе \u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003eзагÑÑзиÑÑ\u003c/a\u003e\u003c/b\u003e ÑозданнÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ!","buyer_negotiates":"ÐÐ»Ð¸ÐµÐ½Ñ Ð¾Ð±ÑÑдил ваÑе Ñеновое пÑедложение.","buyer_pays_for_the_job":"ÐÑÐ¾ÐµÐºÑ Ð±Ñл пÑедоплаÑен и пеÑемеÑÑн во Ð²ÐºÐ»Ð°Ð´ÐºÑ %{in_progress_url}.","designer_accepts_changes":"ÐÐ¸Ð·Ð°Ð¹Ð½ÐµÑ Ð¿ÑовеÑил обновлÑннÑе деÑали.","designer_accepts_offer":"ÐÐ¸Ð·Ð°Ð¹Ð½ÐµÑ Ð¿ÑинÑл ваÑе пÑедложение.","designer_edits_offer":"ÐÐ¸Ð·Ð°Ð¹Ð½ÐµÑ Ð¾ÑÑедакÑиÑовал ÑÐ²Ð¾Ñ Ð¿Ñедложение.","designer_negotiates":"ÐÐ¸Ð·Ð°Ð¹Ð½ÐµÑ Ð¾Ð±ÑÑдил ваÑе пÑедложение.","designer_withdraws_offer":"ÐÐ¸Ð·Ð°Ð¹Ð½ÐµÑ Ð¾Ñозвал ÑÐ²Ð¾Ñ Ð¿Ñедложение.","job_expires":"СÑок дейÑÑÐ²Ð¸Ñ Ð¿ÑоекÑа иÑÑÑк, и он бÑл пеÑемеÑÑн во Ð²ÐºÐ»Ð°Ð´ÐºÑ %{archive_url}."},"template_error":"ÐÑоекÑÑ Ð½Ðµ бÑли ÑозданÑ!","user_not_exists":"ÐолÑзоваÑÐµÐ»Ñ Ñ Ñаким именем не ÑÑÑеÑÑвÑеÑ.","want_that_job":"Я Ñ
оÑÑ ÑÑÑ ÑабоÑÑ!"},"kodama":{"invalid_request":"ÐевеÑнÑй запÑоÑ!"},"landing":{"consent_not_saved":"СоглаÑие не бÑло ÑоÑ
Ñанено","failure_notification":"ÐÑе обÑзаÑелÑнÑе Ð¿Ð¾Ð»Ñ Ð·Ð°Ð¿ÑоÑа на доÑÑÑп к API Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ñ ÐºÐ¾ÑÑекÑно.","success_notification":"СпаÑибо за Ð²Ð°Ñ Ð·Ð°Ð¿ÑоÑ. ÐÑ ÑвÑжемÑÑ Ñ Ð²Ð°Ð¼Ð¸ в ближайÑее вÑемÑ."},"layout":{"chunk_load_notice":"ÐÑи загÑÑзке ÑÑÑаниÑÑ Ð¿ÑоизоÑла оÑибка. ÐожалÑйÑÑа, обновиÑе ÑÑÑаниÑÑ.","cookies_policy":{"accept":"пÑинимаÑÑ","learn_more":"ÐÑÑÑиÑÑ Ð±Ð¾Ð»ÑÑе","text":"ÐÐ°Ñ ÑÐ°Ð¹Ñ Ð¸ÑполÑзÑÐµÑ ÐºÑки-ÑÐ°Ð¹Ð»Ñ Ð´Ð»Ñ ÑбоÑа ÑÑаÑиÑÑиÑеÑкиÑ
даннÑÑ
Ð´Ð»Ñ Ð¿Ð¾ÑеÑиÑелей и взаимодейÑÑвие доÑожки Ñ Ð¿ÑÑмой маÑкеÑинговой коммÑникаÑией / ÑлÑÑÑиÑÑ Ð½Ð°Ñ ÑÐ°Ð¹Ñ Ð¸ ÑлÑÑÑиÑÑ Ñвой опÑÑ Ð¿ÑоÑмоÑÑа. ÐожалÑйÑÑа, ÑмоÑÑиÑе наÑи Cookie ÐÑимеÑание ÐÐ»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑной инÑоÑмаÑии о пеÑенÑе, даннÑе, коÑоÑÑе они ÑобиÑаÑÑ, коÑоÑÑе могÑÑ Ð¿Ð¾Ð»ÑÑиÑÑ Ð´Ð¾ÑÑÑп к ним, и ваÑим пÑавам."},"translations_notice":{"cta":"ÐеÑеклÑÑиÑÑÑÑ Ð½Ð° English","text":"ÐдÑавÑÑвÑйÑе! ÐÑ Ð¿ÐµÑеводим CGTrader. ÐÐ´ÐµÑ Ð¿ÐµÑевод, и некоÑоÑÑе ÑÐ°Ð·Ð´ÐµÐ»Ñ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð½ÐµÐ´Ð¾ÑÑÑÐ¿Ð½Ñ Ð½Ð° ÑÑÑÑком ÑзÑке."}},"model":{"already_purchased":"ÐÑ Ñже кÑпили ÑÑÐ¾Ñ Ð¿ÑодÑкÑ. ÐÑ Ð¼Ð¾Ð¶ÐµÑе ÑкаÑаÑÑ ÐµÐ³Ð¾ из \u003ca href='/profile/cart/purchased'\u003eкоÑзин
16518Ñ Ð¿Ð¾ÐºÑпок\u003c/a\u003e. ÐÑли Ñ
оÑиÑе, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе кÑпиÑÑ ÐµÐ³Ð¾ Ñнова.","animated":"ÐнимиÑованнÑй","artist_profile":"ÐÑоÑÐ¸Ð»Ñ Ñ
Ñдожника","author":"ÐвÑоÑ","author_get_your_payment":"ÐвÑÐ¾Ñ Ð¿Ð¾Ð»ÑÑÐ¸Ñ 100% ваÑей оплаÑÑ. CGTrader позволÑÐµÑ Ñ
Ñдожникам полÑÑаÑÑ Ð¼Ð°ÐºÑималÑнÑй доÑ
од и моÑивиÑÑÐµÑ Ð¿ÑодаваÑÑ Ð²ÑÑококаÑеÑÑвеннÑй конÑенÑ.","author_products":"ÐÑÑгие пÑодÑкÑÑ Ð¾Ñ \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e","authorised_seller":"ÐвÑоÑизованнÑй пÑÐ¾Ð´Ð°Ð²ÐµÑ CGTrader","authority":"ÐвÑоÑиÑеÑ","breadcrumb":{"3d_models":"3D модели","home":"ÐлавнаÑ"},"bulk_download":{"download_all":"СкаÑаÑÑ Ð²Ñе ÑайлÑ","files_included":{"one":"ÐклÑÑÑн %{count} Ñайл","other":"ÐклÑÑено Ñайлов: %{count}"},"too_large":"ÐÑа Ð¼Ð¾Ð´ÐµÐ»Ñ ÑлиÑком велика Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки одним аÑÑ
ивом (более %{limit}). ÐожалÑйÑÑа, ÑкаÑайÑе ÑÐ°Ð¹Ð»Ñ Ð¿Ð¾ оÑделÑноÑÑи."},"buy":"ÐÑпиÑÑ","cannot_download":"ТолÑко полÑзоваÑели Ñ ÑепÑÑаÑией %{experience_needed} могÑÑ ÑкаÑиваÑÑ Ð±Ð¾Ð»ÐµÐµ %{models} беÑплаÑнÑÑ
моделей. УзнайÑе болÑÑе об ÑÑовнÑÑ
и ÑепÑÑаÑии, \u003ca href='%{reputation_url}' target='_blank'\u003eнажав здеÑÑ\u003c/a\u003e.","collection":"3D-пак","contact_author":"СвÑзаÑÑÑÑ Ñ Ð°Ð²ÑоÑом","description":"ÐпиÑание","download":"СкаÑаÑÑ","download_limit_exceeded":"ÐÑ Ð¿ÑевÑÑили Ñвой дневной Ð»Ð¸Ð¼Ð¸Ñ Ð·Ð°Ð³ÑÑзок. ÐопÑобÑйÑе Ñнова завÑÑа. ÐÑÐ¾Ñ Ð»Ð¸Ð¼Ð¸Ñ Ð½Ðµ ÑаÑпÑоÑÑÑанÑеÑÑÑ Ð½Ð° полÑзоваÑелей, ÑовеÑÑивÑиÑ
покÑÐ¿ÐºÑ Ð·Ð° поÑледние 12 меÑÑÑев.","download_modal":{"chat_with_us":"ÐапиÑаÑÑ Ð² ÑаÑ","contact_support":"ÐожалÑйÑÑа, ÑвÑжиÑеÑÑ Ñ Ð½Ð°Ð¼Ð¸ ÑеÑез ÑаÑ.","download_file":"СкаÑаÑÑ %{name}","empty":"Ð¤Ð°Ð¹Ð»Ñ Ð½Ðµ найденÑ","generic_error":"ЧÑо-Ñо поÑло не Ñак, попÑобÑйÑе еÑÑ Ñаз","link_error":"ÐÑиноÑим извинениÑ, но Ñ Ð²Ð°Ñей ÑÑÑлкой Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ»Ð° неболÑÑÐ°Ñ Ð¿Ñоблема.","pbr_ready":"ÐоддеÑжка PBR","preparing":"ÐодгоÑовка загÑÑзки...","title":"СкаÑаÑÑ ÑайлÑ"},"format_downloads":"ÐагÑÑзки 3D-ÑоÑмаÑов","game_ready":"ÐоÑово Ð´Ð»Ñ Ð¸Ð³Ñ (lowpoly)","geometry":"ÐеомеÑÑиÑ","license":"ÐиÑензиÑ","low_poly":"ÐизкополигоналÑнÑе","make_offer":"СделаÑÑ Ð¿Ñедложение","materials":"ÐаÑеÑиалÑ","messages":{"no_files":"ÐÐµÑ Ð·Ð°Ð³ÑÑженнÑÑ
Ñайлов","no_rating":"РейÑинг Ð´Ð»Ñ ÑÑой модели пока оÑÑÑÑÑÑвÑеÑ"},"model_details":"ÐеÑали 3D модели","pbr_textures":"PBR-ÑекÑÑÑÑÑ","plugin_used":"ÐÑполÑзÑемÑй плагин","polygons":"ÐолигонÑ","price":"Цена","print_ready":"ÐоÑово Ð´Ð»Ñ 3D-пеÑаÑи","product_id":"ÐденÑиÑикаÑÐ¾Ñ Ð¿ÑодÑкÑа","product_support":"ÐоддеÑжка пÑодÑкÑа","product_type":"Тип пÑодÑкÑа","published":"ÐпÑбликовано","rated":{"error":"ÐÑ Ñже оÑенили ÑÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ","success":"СпаÑибо за ваÑÑ Ð¾ÑÐµÐ½ÐºÑ ÑÑой модели"},"rating":"РейÑинг 3D модели","ratings":{"desc":{"negative":"ÐолÑзоваÑели, кÑпивÑие ÑÑÑ 3D моделÑ, ÑÑиÑаÑÑ ÐµÑ Ð½Ð¸Ð¶Ðµ ожидаемого каÑеÑÑва","positive":"ÐолÑзоваÑели, кÑпивÑие ÑÑÑ 3D моделÑ, ÑÑиÑаÑÑ ÐµÑ ÐºÐ°ÑеÑÑвенной"},"negative":"оÑÑиÑаÑелÑнÑй","positive":"положиÑелÑнÑй"},"recently_viewed_models":"Ðедавно пÑоÑмоÑÑеннÑе модели","renderer":"РендеÑеÑ","report":"ÐожаловаÑÑÑÑ","rigged":"С Ñиггингом","scanned":"СканиÑованнÑе","scripts-plugins":"СкÑипÑÑ Ð¸ плагинÑ","similar_models":"ÐоÑ
ожие модели","statistics":"СÑаÑиÑÑика","subscription":{"limit_reached":"ÐÑ Ð´Ð¾ÑÑигли лимиÑа загÑÑзок за ÑÑÐ¾Ñ ÑаÑÑеÑнÑй пеÑиод.","limit_reached_detailed":"ÐÑ Ð´Ð¾ÑÑигли лимиÑа в %{limit} загÑÑзок в ÑÑом меÑÑÑе. ÐÐ°Ñ Ð»Ð¸Ð¼Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð¸ÑÑÑ %{reset_date}. ЧÑÐ¾Ð±Ñ ÑкаÑаÑÑ Ð±Ð¾Ð»ÑÑе моделей ÑейÑаÑ, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑиобÑеÑÑи иÑ
по оÑделÑноÑÑи.","limit_reached_detailed_no_date":"ÐÑ Ð´Ð¾ÑÑигли лимиÑа в %{limit} загÑÑзок в ÑÑом меÑÑÑе. ЧÑÐ¾Ð±Ñ ÑкаÑаÑÑ Ð±Ð¾Ð»ÑÑе моделей ÑейÑаÑ, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑиобÑеÑÑи иÑ
по оÑделÑноÑÑи."},"tags":"Теги","textures":"ТекÑÑÑÑÑ","title":"%{item_title} 3D моделÑ","unwrapped_uvs":"РазвеÑнÑÑÑе UV","uv_mapping":"UV-ÑазвеÑÑка","vat_notice":"ÐÑе ÑÐµÐ½Ñ ÑÐºÐ°Ð·Ð°Ð½Ñ Ð±ÐµÐ· ÐÐС","version":"ÐеÑÑиÑ","vertices":"ÐеÑÑинÑ","vr":"VR модели"},"models":{"error":{"cannot_be_blank":" не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÑÑÑм."}},"navigation":{"3d-models":{"3d-printing":"Ðодели Ð´Ð»Ñ 3д пеÑаÑи","discounts":"Скидки","find_designers":"ÐайÑи лÑÑÑиÑ
дизайнеÑов","free":"ÐеÑплаÑнÑе 3д модели","pbr":"PBR 3д модели","scanned_3d-models":"СканиÑованнÑе 3д модели","scripts_apps":"СкÑипÑÑ Ð¸ пÑиложениÑ","show-all":"ÐоказаÑÑ Ð²Ñе","textures":"CG ÑекÑÑÑÑÑ","title":"3д модели","vr_low-poly":"ÐизкополигоналÑнÑе 3д модели"},"already_added_message":"Ñже бÑл добавлен в коÑзин
16518Ñ","already_purchased_message":"ÐÑ Ñже пÑиобÑели ÑÑÐ¾Ñ ÑоваÑ.","aria":{"account":"ÐккаÑнÑ","cart":"ÐоÑзина","close_menu":"ÐакÑÑÑÑ Ð¼ÐµÐ½Ñ","logo":"CGTrader - 3D-модели / 3D-дизайнеÑÑ","messages":"СообÑениÑ","notifications":"УведомлениÑ","open_menu":"ÐÑкÑÑÑÑ Ð¼ÐµÐ½Ñ","search":"ÐоиÑк","search_by_image":"ÐоиÑк по изобÑажениÑ"},"budgets":{"below_10":"Ðо $10","collections":"ÐабоÑÑ","free":"ÐеÑплаÑно","more_than_20":"Ðолее $20","more_than_50":"Ðолее $50","sale":"РпÑодаже","subscription":"ÐодпиÑка"},"cart_limit_reached":"ÐÑ Ð´Ð¾ÑÑигли пÑедела в 500 ÑоваÑов в ваÑей коÑзине. ЧÑÐ¾Ð±Ñ Ð¿ÑодолжиÑÑ Ð¿Ð¾ÐºÑпки, пожалÑйÑÑа, завеÑÑиÑе ÑекÑÑий заказ и наÑниÑе новÑй Ð´Ð»Ñ Ð»ÑбÑÑ
дополниÑелÑнÑÑ
ÑоваÑов.","cart_widget":{"continue_shopping":"ÐÑодолжиÑÑ Ð¿Ð¾ÐºÑпки","discount":"Скидка Ñ ÐºÐ¾ÑпоÑаÑивнÑм кÑпоном:","discount_applied":"ÐÑимененнÑе Ñкидки:","final":"ÐконÑаÑелÑÐ½Ð°Ñ Ñена:","have":"У ваÑ","items":"наименований в ваÑей коÑзине.","left_to_unlock_discounts":"ÐÑÑалоÑÑ {{leftToUnlock}} ÑÑÐ¾Ð±Ñ ÑазблокиÑоваÑÑ Ñкидки","potential_discount":"ÐÐ¾Ð·Ð¼Ð¾Ð¶Ð½Ð°Ñ Ñкидка:","proceed":"ÐеÑейÑи к оÑоÑÐ¼Ð»ÐµÐ½Ð¸Ñ Ð·Ð°ÐºÐ°Ð·Ð°","recently_viewed_empty_text":"ÐаÑниÑе иÑÑледоваÑÑ Ð¸ ваÑи недавно пÑоÑмоÑÑеннÑе ÑоваÑÑ Ð¿Ð¾ÑвÑÑÑÑ Ð·Ð´ÐµÑÑ.","recently_viewed_empty_title":"ÐдеÑÑ Ð¿Ð¾ÐºÐ° ниÑего неÑ","recently_viewed_tab":"Ðедавно пÑоÑмоÑÑеннÑе","remainer":"ЧÑÐ¾Ð±Ñ Ð°ÐºÑивиÑоваÑÑ CGTrader, добавÑÑе: ","sale_discounts":"ÐÑимененнÑе Ñкидки: ","sale_time_left":"ÐÑÑалоÑÑ Ð²Ñемени на ÑаÑпÑодажÑ","sale_tooltip":"Скидки Ð¾Ñ Ð½Ð°ÑиÑ
ÑаÑпÑодажнÑÑ
кампаний пÑименÑÑÑÑÑ ÑолÑко когда ваÑа коÑзина доÑÑÐ¸Ð³Ð°ÐµÑ ${{threshold}} или более.","sale_tooltip_text":"ÐÑÐ¾Ñ ÑÐ¾Ð²Ð°Ñ Ð½Ð° ÑаÑпÑодаже, но Ñкидка бÑÐ´ÐµÑ Ð¿Ñименена ÑолÑко когда обÑÐ°Ñ ÑÑоимоÑÑÑ Ð²Ð°Ñей коÑÐ·Ð¸Ð½Ñ Ð´Ð¾ÑÑÐ¸Ð³Ð°ÐµÑ ${{threshold}} или более.","text":"ÐаÑа коÑзина пÑÑÑа.","title":"ÐоÑзина покÑпаÑелÑ","total":"ÐбÑее колиÑеÑÑво:","used":"ÐÑполÑзовано кÑедиÑов:","view":"ÐоÑмоÑÑеÑÑ ÐºÐ¾ÑзинÑ","wishlist_empty_text":"ÐаÑниÑе иÑÑледоваÑÑ Ð¸ ÑоÑ
ÑаниÑе Ñвои лÑбимÑе наÑ
одки Ð´Ð»Ñ Ð±ÑдÑÑего â они поÑвÑÑÑÑ Ð·Ð´ÐµÑÑ.","wishlist_empty_title":"ÐÐ°Ñ ÑпиÑок желаний пÑÑÑ","wishlist_tab":"СпиÑок желаний"},"community":{"awards":"ÐагÑÐ°Ð´Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑов ð","blog":"Ðлог","challenges":"ÐадаÑи","community_ratings":"РейÑинги ÑообÑеÑÑва","designers":"3D дизайнеÑÑ","digital_art":"ÐонкÑÑÑ ÑиÑÑового иÑкÑÑÑÑва","forum":"ФоÑÑм","galleries":"ÐалеÑеи","invite":"ÐÑиглаÑиÑÑ Ð´ÑÑга","printlist":"СпиÑок 3д-пеÑаÑи","sell_3d-models":"ÐÑодаÑÑ 3д модели","title":"СообÑеÑÑво","tutorials":"УÑебнÑе поÑобиÑ"},"conversations_widget":{"conversations":"Ðиалоги","messages":{"loading":"ÐагÑÑзка вÑ
одÑÑиÑ
ÑообÑений"},"types":{"cgtrader_support":"CGTrader ÐоддеÑжка","file_conversion_request":"ÐапÑÐ¾Ñ Ð¿ÑеобÑÐ°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñайлов","job_application":"3д пÑоекÑ","model_feedback":"ÐбÑаÑÐ½Ð°Ñ ÑвÑÐ·Ñ Ð¿Ð¾ пÑодÑкÑÑ","model_support":"ÐоддеÑжка по модели","offer":"ÐÑедложение ÑенÑ","personal":"ÐиÑное ÑообÑение","promotions":"ÐкÑии"}},"create_ai":{"community_gallery":"ÐалеÑÐµÑ ÑообÑеÑÑва","free_trial":"ÐеÑплаÑнÑй пеÑиод","generate_3d_model":"СгенеÑиÑоваÑÑ 3D-моделÑ","generation":{"dismiss":"ÐакÑÑÑÑ Ñведомление","error_title":"ÐÑоблема генеÑаÑии","generating_title":"ÐаÑа 3D-Ð¼Ð¾Ð´ÐµÐ»Ñ Ð³ÐµÐ½ÐµÑиÑÑеÑÑÑ","open_model":"ÐÑкÑÑÑÑ Ð¼Ð¾Ð´ÐµÐ»Ñ","ready_title":"ÐаÑа 3D-Ð¼Ð¾Ð´ÐµÐ»Ñ Ð³Ð¾Ñова!"}},"create_with_ai":"СоздаÑÑ Ñ ÐÐ","credits_guest_widget":{"create":"СоздайÑе аккаÑÐ½Ñ ÑейÑаÑ!","discount":"Ñкидка","for":"на ваÑÑ","get":"и полÑÑи","learn_more":"УзнайÑе болÑÑе о кÑедиÑаÑ
лоÑлÑноÑÑи CGTrader","link":"здеÑÑ","purchase":"пеÑвÑÑ Ð¿Ð¾ÐºÑпкÑ!","sign-up":"РегиÑÑÑиÑÑйÑÑ","text_below_1":"ÐÑедиÑÑ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð¿Ñи покÑпке \"","text_below_2":"\"оÑмеÑеннÑÑ
моделей и покÑÑваÑÑ Ð´Ð¾ 30% Ñкидки Ð¾Ñ ÑенÑ."},"credits_user_widget":{"condition_1":"ÐÐ°Ð»Ð»Ñ CGTrader можно иÑполÑзоваÑÑ Ð´Ð»Ñ Ð¿Ð¾ÐºÑпки моделей, оÑмеÑеннÑÑ
знаÑком \u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003e, пÑедоÑÑавлÑÑ ÑÐºÐ¸Ð´ÐºÑ Ð´Ð¾ 30% Ð¾Ñ Ð¸Ñ
ÑенÑ.","condition_2":"ÐÐ°Ð»Ð»Ñ Ð¼Ð¾Ð¶Ð½Ð¾ иÑполÑзоваÑÑ ÑолÑко еÑли обÑÐ°Ñ ÑÑоимоÑÑÑ Ð²Ð°Ñей коÑзин
16518Ñ ÑоÑÑавлÑÐµÑ \u003cstrong\u003e$%{minimum}\u003c/strong\u003e или болÑÑе.","condition_3":"Ðо вÑÐµÐ¼Ñ Ð°ÐºÑивнÑÑ
ÑаÑпÑодаж или акÑий Ð±Ð°Ð»Ð»Ñ Ð¸ÑполÑзоваÑÑ Ð½ÐµÐ»ÑзÑ.","condition_4":"ÐмейÑе в видÑ, ÑÑо Ñ Ð±Ð°Ð»Ð»Ð¾Ð² еÑÑÑ ÑÑок дейÑÑÐ²Ð¸Ñ - ваÑи Ð±Ð°Ð»Ð»Ñ Ð¸ÑÑекÑÑ ÑеÑез \u003cstrong\u003e%{days}\u003c/strong\u003e дней.","earn_rate":"ÐолиÑеÑÑво заÑабоÑаннÑÑ
кÑедиÑов:","first_text_1":"СÑиÑайÑе ÑÑо подаÑком за ваÑÑ Ð¿ÐµÑвÑÑ Ð¿Ð¾ÐºÑÐ¿ÐºÑ - Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ ÐºÑедиÑÑ Ð¿Ñи покÑпке \"","first_text_2":"\"оÑмеÑеннÑÑ
моделей и полÑÑиÑÑ Ð´Ð¾ 30% Ñкидки Ð¾Ñ ÑенÑ. ÐÑедиÑÑ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ ÑолÑко, еÑли обÑÐ°Ñ ÑÑоимоÑÑÑ Ð²Ð°Ñей коÑÐ·Ð¸Ð½Ñ Ñавна или болÑÑе, Ñем","important":"ÐÐÐÐÐ:","learn_more":"УзнаÑÑ Ð±Ð¾Ð»ÑÑе","lifetime_spending":"ÐолгоÑÑоÑнÑе ÑаÑÑ
одÑ:","list_item":"УвелиÑÐ¸Ð²Ð°Ñ Ð²Ð°Ñи долгоÑÑоÑнÑе ÑаÑÑ
Ð¾Ð´Ñ Ð½Ð° CGTrader, ваÑа кÑедиÑÐ½Ð°Ñ ÑÑавка Ñакже ÑвелиÑиваеÑÑÑ.","message":"ÐÑедиÑÑ Ð½Ðµ могÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð²Ð¾ вÑÐµÐ¼Ñ ÑаÑпÑодажи, но Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе повÑÑиÑÑ Ñвой ÑÑÐ¾Ð²ÐµÐ½Ñ Ð»Ð¸Ñензии и ÑобиÑаÑÑ Ð±Ð¾Ð»ÑÑе кÑедиÑов Ð´Ð»Ñ Ð²Ð°Ñей ÑледÑÑÑей покÑпки.","more_credits":"Ðак Ñ Ð¼Ð¾Ð³Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð±Ð¾Ð»ÑÑе кÑедиÑов?","next_level":"СледÑÑÑий ÑÑовенÑ:","notice":"ÐÐÐÐÐÐÐÐ: ÐÐ°Ð»Ð»Ñ CGTrader нелÑÐ·Ñ Ð¸ÑполÑзоваÑÑ Ð²Ð¾ вÑÐµÐ¼Ñ ÑекÑÑей ÑаÑпÑодажи, но они Ñнова ÑÑанÑÑ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð¿Ð¾Ñле ÐµÑ Ð·Ð°Ð²ÐµÑÑениÑ. Рпока поÑмоÑÑиÑе оÑлиÑнÑе пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ð° 3D-модели \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003eздеÑÑ\u003c/a\u003e.","par_1":"У ваÑ","par_2":"CGTrader кÑедиÑов.","par_2_variation":" в баллаÑ
, коÑоÑÑе Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе поÑÑаÑиÑÑ, еÑли ÑаÑпÑодажа невозможна.","regular_text_1":"ÐÑедиÑÑ Ð¼Ð¾Ð³ÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð¿Ñи покÑпке \"","regular_text_2":"\"оÑмеÑеннÑÑ
моделей и покÑÑваÑÑ Ð´Ð¾ 30% Ñкидки Ð¾Ñ ÑенÑ.","title":"ÐÑогÑамма лоÑлÑноÑÑи CGTrader"},"enterprise":{"management":"3D ÑпÑавление акÑивами","title":"ÐÑоизводÑÑво 3D-конÑенÑа"},"hire_a_freelancer":"ÐанÑÑÑ ÑÑиланÑеÑа","item_add_message":"ÑÑпеÑно добавлен в коÑзинÑ","item_restricted_message":"ÐÑÐ¾Ñ ÑÐ¾Ð²Ð°Ñ Ð½ÐµÐ»ÑÐ·Ñ ÐºÑпиÑÑ Ð¸Ð·-за ÑанкÑий, наложеннÑÑ
на ÑÑÑÐ°Ð½Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑа (RU/BY).","navbar":{"actions":{"new":"ÐовÑе","top_selling":"ÐидеÑÑ Ð¿Ñодаж","trending":"Ð ÑÑенде"},"budgets":{"below_10":"Ðо $10","free":"ÐеÑплаÑно","more_than_20":"Ðолее $20","more_than_50":"Ðолее $50","sale":"РпÑодаже","up_to_10":"Ðо $10"}},"projects":{"3d_customs":"ÐндивидÑалÑное 3D","3d_printing":"3D пеÑаÑÑ","about":"Ð 3д пÑоекÑаÑ
","browse":"ÐоÑмоÑÑеÑÑ Ð¿ÑоекÑÑ","buyer_perspective":"ÐанÑÑÑ 3д дизайнеÑов","for_designers":"ÐÐ»Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑов","my_projects":"Ðои пÑоекÑÑ","seller_perspective":"ФÑÐ¸Ð»Ð°Ð½Ñ 3д пÑоекÑÑ","start":"ÐаÑаÑÑ Ð¿ÑоекÑ","work":"РабоÑа Ñ Cgtrader"},"sell_3d-models":"ÐÑодаÑÑ 3д модели","sellers_hub":"ЦенÑÑ Ð¿ÑодавÑа","subscription_includes_item_message":"ÐÑÐ¾Ñ ÑÐ¾Ð²Ð°Ñ Ñже вклÑÑен в ваÑÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑкÑ.","tooltips":{"cart":"ÐоÑзина покÑпаÑелÑ","conversations":"Ðои ÑообÑениÑ","discounts":"ÐÑогÑамма лоÑлÑноÑÑи CGTrader","notifications":"УведомлениÑ","publisher":"ÐздаÑелÑ"},"user":{"ban_notification":"ÐÑа ÑÑеÑÐ½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñована. ÐожалÑйÑÑа, ÑвÑжиÑеÑÑ Ñ Ð½Ð°Ñей поддеÑжкой Ð´Ð»Ñ ÑазÑÑÑнений.","cannot_refer_yourself":"нелÑÐ·Ñ Ð¿ÑиглаÑиÑÑ Ñамого ÑебÑ","email_confirmation":"ÐÐ°Ñ Ð°Ð´ÑÐµÑ ÑлекÑÑонной поÑÑÑ Ð±Ñл подÑвеÑждÑн.","email_reconfirmation":"Ñже бÑл подÑвеÑждÑн, пожалÑйÑÑа, попÑобÑйÑе войÑи","ends_at":"ÐконÑание: %{date}","handle_error_tfa_code_missmatch":"ÐведÑннÑй вами код безопаÑноÑÑи невеÑен. ÐожалÑйÑÑа, попÑобÑйÑе Ñнова.","handle_error_tfa_code_missmatch_last":"СÑок дейÑÑÐ²Ð¸Ñ Ð²Ð°Ñего кода безопаÑноÑÑи иÑÑÑк. ЧÑÐ¾Ð±Ñ Ð¿ÑодолжиÑÑ, нажмиÑе «ÐÑпÑавиÑÑ Ð¿Ð¸ÑÑмо повÑоÑно» и введиÑе новÑй полÑÑеннÑй код.","handle_error_tfa_default":"ЧÑо-Ñо поÑло Ð
16518½Ðµ Ñак, пожалÑйÑÑа, попÑобÑйÑе позже.","handle_error_tfa_expired":"СÑок дейÑÑÐ²Ð¸Ñ Ð²Ð°Ñего кода безопаÑноÑÑи иÑÑÑк.","hundred_percent_royalties_popover":"ÐÑ ÑÑаÑÑвÑеÑе во вÑеменной кампании 100% заÑабоÑка: вÑе доÑ
Ð¾Ð´Ñ Ð¾Ñ Ð¿Ñодаж новÑÑ
моделей бÑдÑÑ Ð¸Ð´Ñи вам до оконÑÐ°Ð½Ð¸Ñ ÐºÐ°Ð¼Ð¿Ð°Ð½Ð¸Ð¸","invalid_email_message":"ÐожалÑйÑÑа, введиÑе дейÑÑвиÑелÑнÑй адÑÐµÑ ÑлекÑÑонной поÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¿ÑодолжиÑÑ.","login":"ÐвÑоÑизоваÑÑÑÑ","meta_description":"ÐоÑмоÑÑиÑе пÑоÑÐ¸Ð»Ñ 3D дизайнеÑа %{username} на CGTrader, его поÑÑÑолио и доÑÑÑпнÑе 3D модели. ÐзнакомÑÑеÑÑ Ñ Ð»ÑÑÑими 3D моделÑми Ð¾Ñ Ð²ÐµÐ´ÑÑиÑ
Ñ
Ñдожников индÑÑÑÑии.","meta_title_suffix":"3D дизайнеÑ","not_valid_birthday":"ÐÐµÐ½Ñ ÑÐ¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ð½ÐµÐ´ÐµÐ¹ÑÑвиÑелен.","offline":"Ðе в ÑеÑи","online":"Ð ÑеÑи","page_title":"ÐÑоÑÐ¸Ð»Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑа","rate_models_limit":"Ð¡ÐµÐ³Ð¾Ð´Ð½Ñ Ð²Ñ Ð±Ð¾Ð»ÑÑе не можеÑе оÑениваÑÑ Ð¼Ð¾Ð´ÐµÐ»Ð¸.","semantic_description":"3D модели, ÑабоÑÑ Ð¸ поÑÑÑолио дизайнеÑа. ÐзнакомÑÑеÑÑ Ñ ÐµÐ³Ð¾ ÑвоÑÑеÑÑвом на CGTrader","semantic_title":"ÐÑоÑÐ¸Ð»Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑа","session_failure":"Ð£ÐºÐ°Ð·Ð°Ð½Ñ Ð½ÐµÐ²ÐµÑное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑзоваÑелÑ/ÑлекÑÑÐ¾Ð½Ð½Ð°Ñ Ð¿Ð¾ÑÑа или паÑолÑ","session_password_expired":"ÐÐ°Ñ Ð¿Ð°ÑÐ¾Ð»Ñ Ð¸ÑÑÑк из-за бездейÑÑвиÑ. ÐожалÑйÑÑа, ÑбÑоÑÑÑе паÑÐ¾Ð»Ñ ÑеÑез ÑÑÑлкÑ, оÑпÑавленнÑÑ Ð²Ð°Ð¼ по ÑлекÑÑонной поÑÑе.","session_two_fa_failure":"ÐÑибка пÑовеÑки кода","session_unconfirmed":"ÐÐ°Ñ Ð°Ð´ÑÐµÑ ÑлекÑÑонной поÑÑÑ ÐµÑÑ Ð½Ðµ подÑвеÑждÑн.","token_not_recognized":"Токен не бÑл ÑаÑпознан","twitter_shareable_text":"#3dartist, за коÑоÑÑм ÑÑÐ¾Ð¸Ñ ÑледиÑÑ","username_error":"не должно ÑодеÑжаÑÑ Ð¿Ñобелов или нелаÑинÑкиÑ
Ñимволов"},"user_menu":{"buyer":{"freelancers":"ÐайÑи ÑÑиланÑеÑов","purchases":"Ðои покÑпки","sell":"ÐÑодаÑÑ 3д модели","wishlist":"СпиÑок желаний 3д моделей"},"dashboard":"ÐÐ°Ð½ÐµÐ»Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸ÑÑÑаÑоÑа","logout":"ÐÑйÑи","public_profile":"ÐÑблиÑнÑй пÑоÑилÑ","seller":{"analytics":"ÐналиÑика","find_new_projects":"ÐайÑи новÑе 3D пÑоекÑÑ","freelance":"ФÑÐ¸Ð»Ð°Ð½Ñ 3д пÑоекÑÑ","freelance_cgtrader":"ФÑÐ¸Ð»Ð°Ð½Ñ Ñ CGTrader","models":"Ðои модели","publish_project":"ÐпÑбликоваÑÑ Ð¿ÑоекÑ","publishing":"ÐздаÑелÑÑкий","sales":"Ðои пÑодажи","subscription":"ÐодпиÑка","wishlist":"СпиÑок желаний 3д моделей"},"settings":"ÐаÑÑÑойки"}},"number":{"currency":{"format":{"delimiter":" ","format":"%n %u","negative_format":"-%n %u","precision":2,"separator":",","significant":false,"strip_insignificant_zeros":false,"unit":"ÑÑб."}},"format":{"delimiter":" ","precision":3,"round_mode":"default","separator":",","significant":false,"strip_insignificant_zeros":false},"human":{"decimal_units":{"format":"%n %u","units":{"billion":{"few":"миллиаÑдов","many":"миллиаÑдов","one":"миллиаÑд","other":"миллиаÑдов"},"million":{"few":"миллионов","many":"миллионов","one":"миллион","other":"миллионов"},"quadrillion":{"few":"квадÑиллионов","many":"квадÑиллионов","one":"квадÑиллион","other":"квадÑиллионов"},"thousand":{"few":"ÑÑÑÑÑ","many":"ÑÑÑÑÑ","one":"ÑÑÑÑÑа","other":"ÑÑÑÑÑ"},"trillion":{"few":"ÑÑиллионов","many":"ÑÑиллионов","one":"ÑÑиллион","other":"ÑÑиллионов"},"unit":""}},"format":{"delimiter":"","precision":1,"significant":false,"strip_insignificant_zeros":false},"storage_units":{"format":"%n %u","units":{"byte":{"few":"байÑа","many":"байÑ","one":"байÑ","other":"байÑа"},"eb":"ÐÐ","gb":"ÐÐ","kb":"ÐÐ","mb":"ÐÐ","pb":"ÐÐ","tb":"ТÐ"}}},"percentage":{"format":{"delimiter":"","format":"%n%"}},"precision":{"format":{"delimiter":""}}}
16518,"owly":{"failed_set_pending":"Ðе ÑдалоÑÑ ÑÑÑановиÑÑ ÑÑаÑÑÑ Â«Ð² ожидании».","failed_to_approve":"Ðе ÑдалоÑÑ Ð¾Ð´Ð¾Ð±ÑиÑÑ.","failed_to_suspend":"Ðе ÑдалоÑÑ Ð¿ÑиоÑÑановиÑÑ.","failed_to_update_license":"Ðе ÑдалоÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð¸ÑÑ Ð»Ð¸ÑензиÑ.","failed_to_update_status":"Ðе ÑдалоÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð¸ÑÑ ÑÑаÑÑÑ Ð¾Ð´Ð¾Ð±ÑениÑ."},"print_models":{"browse_all_makes":"СмоÑÑеÑÑ Ð²Ñе пÑимеÑÑ 3D-пеÑаÑи","browse_all_models":"СмоÑÑеÑÑ Ð²Ñе модели","description":"ÐÑкÑойÑе Ð´Ð»Ñ ÑÐµÐ±Ñ Ð¿Ð¾Ð¿ÑлÑÑнÑе модели, гоÑовÑе к 3D-пеÑаÑи: игÑовÑе, Ñ
ÑдожеÑÑвеннÑе, Ð´Ð»Ñ Ð´Ð¾Ð¼Ð° и многое дÑÑгое.","makes_description":"ÐзÑÑиÑе поÑледние пÑимеÑÑ 3D-пеÑаÑи, загÑÑженнÑе ÑообÑеÑÑвом - ÑеалÑнÑе напеÑаÑаннÑе обÑазÑÑ, показÑваÑÑие, как 3D-модели вÑглÑдÑÑ Ð² ÑизиÑеÑком миÑе.","makes_title":"ÐовÑе пÑимеÑÑ 3D-пеÑаÑи","new_description":"ÐзнакомÑÑеÑÑ Ñ Ð½Ð¾Ð²Ñми моделÑми в наÑей коллекÑии â Ñвежие дизайнÑ, гоÑовÑе к загÑÑзке и пеÑаÑи Ð´Ð»Ñ Ð²Ð°Ñего ÑледÑÑÑего пÑоекÑа.","new_title":"ÐовÑе модели Ð´Ð»Ñ 3D-пеÑаÑи","title":"ÐопÑлÑÑнÑе модели Ð´Ð»Ñ 3D-пеÑаÑи"},"profile":{"account_settings":{"account":{"email":"ÐлекÑÑÐ¾Ð½Ð½Ð°Ñ Ð¿Ð¾ÑÑа","submit":"СоÑ
ÑаниÑÑ","title":"ÐÑоÑилÑ","update":{"updated":"ÐÑоÑÐ¸Ð»Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½"},"username":"ÐÐ¼Ñ Ð¿Ð¾Ð»ÑзоваÑелÑ"},"email_settings":{"descriptions":{"ai_studio_notifications":"Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ ваÑиÑ
генеÑаÑиÑÑ
CGTrader AI, в Ñом ÑиÑле когда гоÑова моделÑ, коÑоÑÑÑ Ð²Ñ ÐµÑÑ Ð½Ðµ оÑкÑÑвали","communication":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ ваÑем обÑении Ñ Ð´ÑÑгими полÑзоваÑелÑми CGTrader, вклÑÑÐ°Ñ Ð»Ð¸ÑнÑе ÑообÑениÑ, новÑе пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ Ñенам и индивидÑалÑнÑм заказам, оÑзÑÐ²Ñ Ð¸ запÑоÑÑ Ð½Ð° поддеÑÐ¶ÐºÑ Ð¿ÑодÑкÑов","news":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ пÑодÑкÑаÑ
CGTrader, обÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð¾ новÑÑ
ÑÑнкÑиÑÑ
и новоÑÑи ÑообÑеÑÑва","onboarding_and_edu":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ пÑоÑеÑÑе Ð²Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ ÑовеÑÑ, коÑоÑÑе помогÑÑ Ð²Ð°Ð¼ макÑималÑно ÑÑÑекÑивно иÑполÑзоваÑÑ CGTrader","push_notifications":"Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ важной акÑивноÑÑи и обновлениÑÑ
аккаÑнÑа","sales_and_offers":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ ÑпеÑиалÑнÑÑ
пÑедложениÑÑ
, ÑаÑпÑодажаÑ
3D-моделей и бонÑÑнÑÑ
кÑедиÑаÑ
CGTrader","seller_sold_item":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ пÑоданнÑÑ
вами 3D-моделÑÑ
и полÑÑеннÑÑ
плаÑежаÑ
"},"privacy_policy_html":"ÐожалÑйÑÑа, ознакомÑÑеÑÑ Ñ Ð½Ð°Ñей \u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003eÐолиÑикой конÑиденÑиалÑноÑÑи\u003c/a\u003e Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑной инÑоÑмаÑии. ","titles":{"ai_studio_notifications":"Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ CGTrader AI","communication":"ÐбÑение (ÐиÑнÑе ÑообÑениÑ, оÑзÑÐ²Ñ Ð¾ 3D-моделÑÑ
, акÑивноÑÑÑ ÑообÑеÑÑва, пÑедложениÑ)","news":"ÐовоÑÑи 3D / Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ CGTrader","onboarding_and_edu":"Ðведение и обÑÑение","push_notifications":"Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ важной акÑивноÑÑи и обновлениÑÑ
аккаÑнÑа","sales_and_offers":"ÐÑодажи и ÑпеÑиалÑнÑе пÑедложениÑ","seller_sold_item":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ пÑодажаÑ
и плаÑежаÑ
"},"tracking_attributes":{"ai_studio_notifications":"Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ CGTrader AI","communication":"ÐбÑение","news":"ÐовоÑÑи 3D / Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ CGTrader","onboarding_and_edu":"Ðведение и обÑÑение","sales_and_offers":"ÐÑодажи и ÑпеÑиалÑнÑе пÑедложениÑ","seller_sold_item":"ÐнÑоÑмаÑÐ¸Ñ Ð¾ пÑодажаÑ
и плаÑежаÑ
"},"update":{"updated":"ÐаÑа ÑлекÑÑÐ¾Ð½Ð½Ð°Ñ Ð¿Ð¾ÑÑа бÑла ÑÑпеÑно обновлена."}},"gdpr_success_notification":{"opt_in":"СпаÑибо! ÐÑ ÑÑпеÑно подпиÑалиÑÑ Ð½Ð° наÑи ÑлекÑÑоннÑе пиÑÑма.","opt_out":"ÐÑ ÑÑпеÑно оÑпиÑалиÑÑ Ð¾Ñ Ð½Ð°ÑиÑ
новоÑÑнÑÑ
ÑаÑÑÑлок. ÐÑ Ð¼Ð¾Ð¶ÐµÑе измениÑÑ ÑÑо пÑедпоÑÑение в лÑбое вÑемÑ, поÑеÑив наÑÑÑойки ваÑего пÑоÑилÑ.\n"},"location_tooltip_text":"\u003cdiv\u003eÐÑÐ¾Ñ Ñлажок позволÑÐµÑ Ð¾ÑобÑажаÑÑ Ð¼ÐµÑÑоположение на ÑÑÑаниÑе пÑоÑилÑ.\u003c/div\u003e \u003cdiv\u003eÐбÑаÑиÑе внимание, ÑÑо в лÑбом ÑлÑÑае, по пÑиÑинам ÑоблÑÐ´ÐµÐ½Ð¸Ñ ÑÑебований, ваÑе меÑÑоположение бÑÐ´ÐµÑ Ð¾ÑобÑажаÑÑÑÑ Ð²Ð°Ñим покÑпаÑелÑм (еÑли Ð²Ñ Ð¿ÑодавеÑ) и пÑодавÑам, Ñ ÐºÐ¾ÑоÑÑÑ
Ð²Ñ Ð¿Ð¾ÐºÑпали.\u003c/div\u003e","moneybookers":{"account":"ÐккаÑÐ½Ñ Skrill"},"password":{"current_password":"ТекÑÑий паÑолÑ","new_password":"ÐовÑй паÑолÑ","submit":"ÐзмениÑÑ Ð¿Ð°ÑолÑ","title":"ÐаÑолÑ","updated":"ÐÐ°Ñ Ð¿Ð°ÑÐ¾Ð»Ñ Ð±Ñл ÑÑпеÑно обновлен. ТепеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе иÑполÑзоваÑÑ Ð½Ð¾Ð²Ñй паÑÐ¾Ð»Ñ Ð´Ð»Ñ Ð²Ñ
ода.","verify_password":"ÐодÑвеÑдиÑе паÑолÑ"},"paypal":{"account":"ÐккаÑÐ½Ñ PayPal","submit":"СоÑ
ÑаниÑÑ","title":"Ð
16518аÑÑÑойки PayPal","update":{"updated":"ÐаÑÑÑойки PayPal бÑли обновленÑ"}},"personal_info":{"areas_of_expertise":"ÐблаÑÑи ÑкÑпеÑÑизÑ","country":"СÑÑана","description":"ÐеÑколÑко пÑедложений о Ñебе","full_name":"Ðолное имÑ","languages":"ЯзÑки","preffered_tools":"ÐÑедпоÑиÑаемÑе инÑÑÑÑменÑÑ","submit":"СоÑ
ÑаниÑÑ","title":"ÐиÑÐ½Ð°Ñ Ð¸ пÑоÑеÑÑионалÑÐ½Ð°Ñ Ð¸Ð½ÑоÑмаÑиÑ","update":{"updated":"ÐаÑа инÑоÑмаÑÐ¸Ñ Ð±Ñла ÑÑпеÑно обновлена"},"website":"Ðеб-ÑайÑ"},"personalization":{"no_muted_title":"ÐÐµÑ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸ÑованнÑÑ
дизайнеÑов","title":"ÐаблокиÑованнÑе дизайнеÑÑ","tooltip":"3D-модели пеÑеÑиÑленнÑÑ
дизайнеÑов иÑклÑÑÐµÐ½Ñ Ð¸Ð· ваÑиÑ
ÑезÑлÑÑаÑов поиÑка.","unmute_designer":{"confirm":"ÐÑ ÑвеÑенÑ?"}},"professional_info":{"allow_private_job_requests":"ÐокÑпаÑели ÑмогÑÑ Ð¾ÑпÑавлÑÑÑ Ð²Ð°Ð¼ индивидÑалÑнÑе запÑоÑÑ Ð½Ð° 3D-ÑабоÑÑ.","buyer_engagement_program_html":"ÐÑивлекайÑе болÑÑе клиенÑов, позволÑÑ Ð¸Ð¼ покÑпаÑÑ Ð²Ð°Ñи модели Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ CGTrader Points. \u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003eÐодÑобнее\u003c/a\u003e\n","pbr_program":"Ðолее Ð½Ð¸Ð·ÐºÐ°Ñ ÑÑавка заÑабоÑка пÑименÑеÑÑÑ ÑолÑко пÑи загÑÑзке пÑеобÑазованного Ñайла","pbr_program_agreement":"ÐÑ ÑоглаÑилиÑÑ ÑÑаÑÑвоваÑÑ Ð² пÑогÑамме PBR на 24 меÑÑÑа Ñ %{date}. ÐодÑобнее Ñм. УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ ÐоложениÑ. ÐÑли Ñ Ð²Ð°Ñ ÐµÑÑÑ Ð²Ð¾Ð¿ÑоÑÑ, ÑвÑжиÑеÑÑ Ñ Ð½Ð°Ñей поддеÑжкой.","product_analytics_participation_html":"Я ÑÑаÑÑвÑÑ Ð² \u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eÐналиÑике\u003c/a\u003e и ÑоглаÑаÑÑÑ Ñ Ð¸Ñ
УÑловиÑми и ÐоложениÑми\n","product_analytics_participation_tooltip_html":"ÐÑ ÑоглаÑилиÑÑ ÑÑаÑÑвоваÑÑ Ð² ÐналиÑике и пÑинÑли УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ ÐÐ¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐналиÑики (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003eÑÑÑлка\u003c/a\u003e) %{accepted_at}. ÐÑли Ð²Ñ Ñ
оÑиÑе пÑекÑаÑиÑÑ ÑÑаÑÑие, пожалÑйÑÑа, ÑвÑжиÑеÑÑ Ñ Ð¿Ð¾Ð´Ð´ÐµÑжкой CGTrader\n"},"security":{"allow_mfa":"ÐклÑÑиÑе двÑÑ
ÑÑапнÑÑ Ð¿ÑовеÑÐºÑ Ð´Ð»Ñ Ð·Ð°ÑиÑÑ Ñвоего аккаÑнÑа","use_authenticator_app":"ÐÑполÑзоваÑÑ Ð¿Ñиложение-аÑÑенÑиÑикаÑÐ¾Ñ Ð´Ð»Ñ Ð´Ð²ÑÑ
ÑÑапной пÑовеÑки","use_authenticator_app_tooltip":"ÐÑÑканиÑÑйÑе QR-код Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð²Ð°Ñего пÑиложениÑ-аÑÑенÑиÑикаÑоÑа (Google Authenticator / Authy) Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑаÑии кодов пÑовеÑки.","use_email":"ÐÑполÑзоваÑÑ ÑлекÑÑоннÑÑ Ð¿Ð¾ÑÑÑ Ð´Ð»Ñ Ð´Ð²ÑÑ
ÑÑапной пÑовеÑки"},"sidebar":{"general_settigns":"ÐбÑие наÑÑÑойки","member_since":"УÑаÑÑник Ñ","paypal":"PayPal","title":"ÐнÑоÑмаÑÐ¸Ñ Ð¾Ð± аккаÑнÑе"},"title":"Ðой аккаÑнÑ"},"conversations":{"conversations":"Ðиалоги","messages":{"loading":"ÐагÑÑзка ÐÑ
одÑÑие"},"types":{"cgtrader_support":"CGTrader ÐоддеÑжка","file_conversion_request":"запÑÐ¾Ñ Ð¿ÑеобÑÐ°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñайлов","job_application":"3D пÑоекÑ","model_feedback":"ÐÑодÑÐºÑ ÐбÑаÑÐ½Ð°Ñ ÑвÑзÑ","model_support":"ÐÐ¾Ð´ÐµÐ»Ñ Ð¿Ð¾Ð´Ð´ÐµÑжки","offer":"ÐÑедложение ÑенÑ","personal":"ÐиÑное ÑообÑение","promotions":"ÐкÑии"}},"meta":{"description":"ÐзнакомÑÑеÑÑ Ñ Ð²ÑÑококаÑеÑÑвеннÑми 3DâмоделÑми Ð¾Ñ %{username} на CGTrader. ÐÑоÑмаÑÑивайÑе ÑникалÑнÑе ÑеÑÑÑÑÑ Ð´Ð»Ñ Ð¸Ð³Ñ, VR/AR и визÑализаÑии.","title":"СоздаÑÐµÐ»Ñ 3Dâмоделей: %{username}"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"ÐаÑи наÑÑÑойки бÑли ÑÑпеÑно обновленÑ."},"publishing":{"banned_error":"ÐÐ°Ñ Ð°ÐºÐºÐ°ÑÐ½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñован за пÑбликаÑÐ¸Ñ Ñпам-конÑенÑа. ÐÑли Ð²Ñ ÑÑиÑаеÑе, ÑÑо ÑÑо оÑибка, пожалÑйÑÑа, ÑвÑжиÑеÑÑ Ñ supp
16518[email protected].","files_not_finalized":"Ðдин или неÑколÑко Ñайлов не бÑли загÑÑÐ¶ÐµÐ½Ñ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ Ð¸ не могÑÑ Ð±ÑÑÑ Ð¾Ð¿ÑбликованÑ. УдалиÑе иÑ
и загÑÑзиÑе Ñнова пеÑед пÑбликаÑией.","spam_suspect":"ÐÐ°Ñ Ð°ÐºÐºÐ°ÑÐ½Ñ Ð½Ðµ авÑоÑизован Ð´Ð»Ñ Ð¿ÑбликаÑии ÑÑой модели. ÐÑли Ð²Ñ ÑÑиÑаеÑе, ÑÑо ÑÑо оÑибка, пожалÑйÑÑа, ÑвÑжиÑеÑÑ Ñ [email protected]."},"rating":{"anonymous_buyer":"ÐнонимнÑй ÐокÑпаÑелÑ","errors":{"not_verified_buyer":"ТолÑко пÑовеÑеннÑе покÑпаÑели могÑÑ Ð¾ÑÑавиÑÑ Ð¾ÑзÑв"}},"routes":{"3d-models":"3d-модели","3d-print-models":"3d-пеÑаÑÑ-модели","animated-3d-models":"анимиÑованнаÑ-3d-модели","controllers":{"three_d_studio":{"3d-models":"3d-models","images":"images"}},"discover":"otkrytie","free-3d-models":"беÑплаÑнÑе-3d-модели","free-3d-print-models":"беÑплаÑнÑе-3d-пеÑаÑÑ-модели","freelance-with-us":"ÐаÑабаÑÑвайÑе-Ñ-CGTrader","low-poly-3d-models":"низкополигоналÑнÑй-3d-модели","pbr-3d-models":"pbr-3d-модели","pbr-textures":"pbr-textures","rigged-3d-models":"ÑÑалÑÑиÑиÑиÑовано-3d-модели","search":"search"},"sale_off":{"no_overlapping_campaigns":"ÐаÑÑ ÐºÐ°Ð¼Ð¿Ð°Ð½Ð¸Ð¸ пеÑеÑекаÑÑÑÑ Ñ Ð´ÑÑгой ÑÑÑеÑÑвÑÑÑей акÑией ÑаÑпÑодажи.","parse_discount_rules_text":"СÑÑока #{index} не ÑодеÑÐ¶Ð¸Ñ Ð¾Ð±ÑзаÑелÑного паÑамеÑÑа 'discount:'"},"search":{"not_found":"ÐодпиÑка на поиÑк не найдена","subscription_created":"ÐодпиÑка на поиÑк Ñоздана","successfully_unsubscribed":"ÐÑ ÑÑпеÑно оÑпиÑалиÑÑ Ð¾Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñки на поиÑк"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."},"subscriptions":{"flash":{"active_subscription":"У Ð²Ð°Ñ Ñже еÑÑÑ Ð°ÐºÑÐ¸Ð²Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñка.","premium_upgrade_unavailable":"ÐеÑеÑ
од на Premium вÑеменно недоÑÑÑпен. ÐожалÑйÑÑа, попÑобÑйÑе позже.","update_payment_method":"С оплаÑой ваÑей подпиÑки возникла пÑоблема. ÐожалÑйÑÑа, обновиÑе ÑпоÑоб оплаÑÑ Ð²Ð¼ÐµÑÑо покÑпки новой подпиÑки."},"payment_form":{"current_price":"%{price}","features":{"first":"%{downloads} аÑÑеÑов / меÑÑÑ â ÑкаÑивайÑе модели или генеÑиÑÑйÑе Ñ ÐÐ","second":"ÐгновеннÑй доÑÑÑп к %{models_count}+ клÑÑевÑм 3D-моделÑм","third":"Ðез оÑÑиÑлений, без ÐÐ"},"from_price_label":"оÑ","original_price":24.99,"per_model_label":"за моделÑ","plan_name":"ÐодпиÑка CGTrader Essentials â годовой план, ежемеÑÑÑÐ½Ð°Ñ Ð¾Ð¿Ð»Ð°Ñа","premium":{"features":{"first":"%{downloads} аÑÑеÑов / меÑÑÑ â ÑкаÑивайÑе модели или генеÑиÑÑйÑе Ñ ÐÐ","fourth":"Ðез оÑÑиÑлений, без ÐÐ","second":"ÐгновеннÑй доÑÑÑп к %{models_count}+ моделÑм в обÑем доÑÑÑпе","third":"Ðодели пÑоÑеÑÑионалÑного ÑÑовнÑ, не вÑ
одÑÑие в Essentials"},"plan_name":"ÐодпиÑка CGTrader Premium â годовой план, ежемеÑÑÑÐ½Ð°Ñ Ð¾Ð¿Ð»Ð°Ñа"},"price_unit":"/меÑÑÑ","vat_amount":"%{vat_amount}"}},"support":{"array":{"last_word_connector":" и ","sentence_connector":"и","skip_last_comma":true,"two_words_connector":" и ","words_connector":", "},"select":{"prompt":"ÐÑбеÑиÑе: "}},"tag":{"description":{"bottle":"УÑенÑе говоÑÑÑ, ÑÑо бÑÑÑлка вина в Ð´ÐµÐ½Ñ Ð½Ðµ плоÑ
а Ð´Ð»Ñ Ð²Ð°Ñ, но когда дело доÑ
Ð¾Ð´Ð¸Ñ Ð´Ð¾ более ÑилÑнÑÑ
напиÑков, как виÑки или бÑÑбон, Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑеалÑно ÑмоÑÑеÑÑ Ð½Ð°Ñе поÑÑебление алкоголÑ. ÐÑевидно, бокал ÑампанÑкого в баÑе внеÑноÑÑÑ ÐºÑÑÑе, Ñем плаÑÑÐ¸ÐºÐ¾Ð²Ð°Ñ Ð±ÑÑÑлка водÑ, но дÑмаÑÑ Ð¾ возможноÑÑи жиÑÑ Ð´Ð¾Ð»ÑÑе и пиво бÑÐ´ÐµÑ ÐºÐ°Ð·Ð°ÑÑÑÑ ÑазÑмной жеÑÑвой. ÐÑа каÑегоÑÐ¸Ñ Ð¿ÑÐµÐ´Ð»Ð°Ð³Ð°ÐµÑ ÑиÑокий вÑÐ±Ð¾Ñ Ð±ÑÑÑлок 3D моделей, наÑÐ¸Ð½Ð°Ñ Ð¾Ñ ÑвÑзаннÑÑ
Ñ Ð°Ð»ÐºÐ¾Ð³Ð¾Ð»ÐµÐ¼ обÑекÑов, ÑакиÑ
как виннÑе ÑкаÑÑ Ð¸ ÑÑопоÑÑ Ð´Ð»Ñ Ð²ÑеÑ
Ñипов бÑÑÑлки 3D моделей (Ð¾Ñ ÑампÑÐ½Ñ Ð´Ð¾ оливкового маÑла).","brain":"Ðозг ÑвлÑеÑÑÑ Ð¾Ð´Ð½Ð¸Ð¼ из ÑамÑÑ
кÑÑпнÑÑ
и ÑложнÑÑ
оÑганов в оÑганизме Ñеловека. Ðз-за ÑÐ²Ð¾Ñ ÑложнÑÑ ÑÑÑÑкÑÑÑÑ Ð¸ ÑÑнкÑиÑ, анаÑÐ¾Ð¼Ð¸Ñ Ð³Ð¾Ð»Ð¾Ð²Ð½Ð¾Ð³Ð¾ мозга Ñакже оÑÐµÐ½Ñ Ñложна. Тем не менее, ÑÑенÑе ÑглÑбимÑÑ Ð² аÑÑ
иÑекÑÑÑÑ ÑеловеÑеÑкого мозга, ÑаÑкÑÑÐ²Ð°Ñ Ð¾ÑеломлÑÑÑие ÑайнÑ. ШиÑокий ÑпекÑÑ ÑеалиÑÑиÑнÑÑ
и подÑобнÑе мозга 3D-моделей, коÑоÑÑе гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑной гÑаÑики пÑиложений, ÑакиÑ
как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑ, веб и лÑбой дÑÑгой облаÑÑи, ÑвÑзанной Ñ 3D дизайн доÑÑÑпен Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки.","building":"ÐеÑÑно, где ÑовÑеменнÑе аÑÑ
иÑекÑоÑÑ Ð±ÐµÑÑÑ Ñвое вдоÑ
новение из, но некоÑоÑÑе из вÑемиÑно извеÑÑнÑÑ
зданий наÑÑолÑко пеÑедний кÑай, ÑÑо они поÑ
ожи на Ð²Ð¸Ð´ÐµÐ½Ð¸Ñ Ð¸Ð· бÑдÑÑего. Ð Ð¼Ñ Ð½Ðµ пÑоÑÑо ознаÑÐ°ÐµÑ Ð²Ð½ÐµÑнÑÑ ÑаÑÑÑ ... Ð ÑмелÑÑ
ÑÑкаÑ
ÑÑандаÑÑное домоÑÑÑоение ÑÑановиÑÑÑ Ð·Ð°Ñ
ваÑÑваÑÑий аÑÑ
иÑекÑÑÑное ÑвоÑение Ñ Ð¸Ð½Ð½Ð¾Ð²Ð°ÑионнÑм дизайном инÑеÑÑеÑа, незавиÑимо Ð¾Ñ Ñого, Ñвл
16518ÑеÑÑÑ Ð»Ð¸ ÑÑо оÑÐ¸Ñ Ð¸Ð»Ð¸ здание гоÑодÑкой. ÐÐ°Ñ Ð²ÑÐ±Ð¾Ñ Ð¿Ð¾ÑÑÑÐ¾ÐµÐ½Ð¸Ñ 3D моделей гоÑов Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки и Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ñименен в ÑазлиÑнÑÑ
облаÑÑÑÑ
- 3D анимаÑии, гÑаÑиÑеÑкий дизайн, Ñеклама, 3D игÑÑ Ð¸Ð»Ð¸ веб.","camera":"ФоÑогÑаÑÐ¸Ñ Ð¸ киноÑÑемка в наÑÑоÑÑее вÑÐµÐ¼Ñ Ð¾Ð´Ð¸Ð½ из ÑамÑÑ
попÑлÑÑнÑÑ
полой каÑÑеÑÑ ÑÑеди молодÑÑ
лÑдей, но не вÑе Ñ Ð¿ÑоÑеÑÑионалÑной камеÑой, Ñ
Ñдожник или ÑоÑогÑаÑ. С каÑеÑÑвом ÑелеÑоннÑÑ
камеÑ, ÑлÑÑÑаÑÑиÑ
из года в год, Ð¼Ñ Ð²Ð¸Ð´Ð¸Ð¼ лÑдей, ÑоÑогÑаÑиÑоваÑÑ Ð½Ð° каждом ÑагÑ, и ÑеÑ
, кÑо Ð¸Ð¼ÐµÐµÑ Ð½Ð°Ð²Ñки ÑедакÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð½Ð¾Ð²Ñ Ð¿ÑоÑвленное изобÑажение дейÑÑвиÑелÑно знамениÑÑй. ÐÐ¸Ð·Ð½Ñ Ð´ÐµÐ¹ÑÑвиÑелÑно вÑглÑÐ´Ð¸Ñ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ по-дÑÑгомÑ, когда Ð²Ñ Ð½Ð°Ñ
одиÑеÑÑ Ð½Ð° дÑÑгой ÑÑоÑоне линзÑ, но давайÑе не ÑвлекайÑеÑÑ ... ШиÑокий ÑпекÑÑ Ð´ÐµÑалÑной камеÑÑ 3D моделей доÑÑÑпен Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð³ÑаÑиÑеÑкиÑ
дизайнеÑов, анимаÑией и ÑазÑабоÑÑики Ð¸Ð³Ñ Ð¸ ÑпеÑиалиÑÑÑ, ÑабоÑаÑÑие в дÑÑгиÑ
3D-ÑмежнÑÑ
облаÑÑÑÑ
.","car":"ÐлÑÐ´Ñ Ð½Ð° ÑÑи оÑÐµÐ½Ñ Ð¿Ð¾Ð´Ñобно и оÑÐµÐ½Ñ ÑеалиÑÑиÑнÑÑ
3D моделей авÑомобилей, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе поÑÑи ÑÑлÑÑаÑÑ Ñев двигаÑелÑ! ШиÑокий вÑÐ±Ð¾Ñ Ð°Ð²ÑÐ¾Ð¼Ð¾Ð±Ð¸Ð»Ñ 3D модели могÑÑ ÑделаÑÑ Ð²Ð°ÑÑ Ð¶Ð¸Ð·Ð½Ñ Ð½Ð°Ð¼Ð½Ð¾Ð³Ð¾ пÑоÑе, еÑли Ð²Ñ Ð±Ð¾ÑеÑеÑÑ Ñ ÐºÐ¾Ð¼Ð¿ÑÑÑеÑной гÑаÑикой, анимаÑией или лÑбой дÑÑгой 3D-ÑвÑзанной облаÑÑÑÑ.","cell":"УÑенÑе подÑÑиÑали, ÑÑо ÑеловеÑеÑкое Ñело ÑодеÑÐ¶Ð¸Ñ Ð¾Ñ 5 млÑд до 200 миллионов ÑÑиллионов клеÑок. РаÑÑÐµÐ½Ð¸Ñ Ð¸ живоÑнÑе клеÑки, Ñоже. ÐÑ Ð½Ðµ Ñ
оÑим ÑÑомлÑÑÑ Ð²Ð°Ñ Ñ ÑÑим биологии веÑи, но ÑиÑокий ÑпекÑÑ ÐºÐ»ÐµÑоÑнÑÑ
3D моделей, коÑоÑÑе Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð¾Ñ
ваÑÑÐ²Ð°ÐµÑ Ð²Ñе, Ð¾Ñ ÐºÑови, виÑÑÑов и ÐÐРв коÑÑном мозге и клеÑоÑнÑÑ
ÑÑенок. Разве ÑÑо не ... неÑвÑ?","chair":"ÐÑ Ð¿Ñинимаем, ÑÐ¸Ð´Ñ Ð² кÑеÑлаÑ
как Ñамо Ñобой ÑазÑмеÑÑееÑÑ Ð¸ не вÑегда замеÑаÑÑ, как много обаÑÐ½Ð¸Ñ Ð¾Ð½Ð¸ могÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ Ðº наÑÐµÐ¼Ñ Ð´Ð¾Ð¼Ñ Ð¸Ð»Ð¸ оÑиÑного инÑеÑÑеÑа. ÐÑедÑедаÑÐµÐ»Ñ ÑакÑиÑеÑки ÑвлÑеÑÑÑ Ð¾Ð´Ð½Ð¸Ð¼ из ÑенÑÑалÑнÑÑ
пÑедмеÑов мебели в лÑбом доме. ÐдеÑÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи вÑÑокое каÑеÑÑво и пÑивлекаÑелÑнÑй дизайн кÑеÑла 3д-модели, коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¿ÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ñ Ð² ÑазлиÑнÑÑ
облаÑÑÑÑ
- Ð¾Ñ ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ 3D визÑализаÑии в 3D-игÑаÑ
.","city":"ÐоÑодÑÐºÐ°Ñ Ð¶Ð¸Ð·Ð½Ñ ÑкÑÑенÑÑиÑÐ½Ð°Ñ Ð¸Ð³Ñа: ÑлиÑÑ ÑаÑпиÑаÑÑ Ð³Ð¾Ð½Ð¾ÑнÑе ÑакÑи, ÑовÑеменнÑе зданиÑми, пеÑеÑ
одÑ, идеалÑно ÑооÑвеÑÑÑвÑÑÑей оÑиÑнÑÑ Ð¾Ð´ÐµÐ¶Ð´Ñ, ÑпалÑнÑе моÑÑÑ Ð¸ паÑки ... Ðз ШанÑ
аÑ, ÐÑÑ-ÐоÑк (! Manhattan), в Ðондон или ÐаÑиж, - каждÑй гоÑод Ð¸Ð¼ÐµÐµÑ Ñвой ÑобÑÑÐ²ÐµÐ½Ð½Ð°Ñ Ð¼Ð°Ð³Ð¸Ñ. ÐÑ Ð¼Ð¾Ð¶ÐµÑе вÑбÑаÑÑ Ð¸Ð· ÑÑого богаÑого вÑбоÑа деÑалÑнÑÑ
гоÑодÑкиÑ
3D моделей, коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ñ Ð² ÑÑде облаÑÑей - ÑекламÑ, компÑÑÑеÑной гÑаÑики, анимаÑии, 3D визÑализаÑии или игÑ. ÐÑÑледÑйÑе гоÑодÑкÑÑ Ð¶Ð¸Ð·Ð½Ñ.","dragon":"ÐÑакон ÑвлÑеÑÑÑ, веÑоÑÑно, ÑамÑм попÑлÑÑнÑм ÑÑÑеÑÑво Ð¶Ð¸Ð²ÐµÑ Ð² миÑе ÑанÑазий. Ðн показал во многиÑ
миÑаÑ
ÑазлиÑнÑÑ
кÑлÑÑÑÑ, анимаÑии, ÑилÑмов и книг, коÑоÑÑе она ÑÑала легендой. ÐÑо оÑобенно лÑбÑÑ ÑазÑабоÑÑиков игÑ, как ÑÑо добавлÑеÑ, ÑÑо магиÑеÑкое оÑаÑование ÑемнÑÑ
пеÑÐµÑ Ð¸ подземелий. ШиÑокий ÑпекÑÑ ÑеалиÑÑиÑнÑÑ
, ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ Ð´Ñакона 3д-модели, коÑоÑÑе гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑной гÑаÑики пÑиложений, ÑакиÑ
как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑ, веб и лÑбой дÑÑгой облаÑÑи, ÑвÑзанной Ñ 3D дизайн доÑÑÑпен Ð´Ð»Ñ ÑкаÑиваниÑ.","earth":"УÑÐ¾Ð²ÐµÐ½Ñ Ð´ÐµÑализаÑии в недавно добавленном зÑении земли в Google каÑÑаÑ
поÑÑÑÑ ÑÑд лÑдей. ÐÑ Ð¼Ð¾Ð¶ÐµÑе иÑÑледоваÑÑ Ð²ÑÑ Ð¿Ð»Ð°Ð½ÐµÑÑ - океанÑ, гоÑÑ Ð¸ пÑÑÑÑни, гоÑода и обнаÑÑжиÑÑ ÑкÑÑÑÑе доÑоги, не вÑÑ
Ð¾Ð´Ñ Ð¸Ð· дома. ÐÐ¾Ñ Ð½ÐµÐºÐ¾ÑоÑÑе невеÑоÑÑнÑе веÑи ÐаÑÑ-ÐÐµÐ¼Ð»Ñ Ð½Ðµ иÑпÑÑÑвала ÑанÑÑе. ÐодбоÑка ÑеалиÑÑиÑнÑÑ
земнÑÑ
3D-моделей, коÑоÑÑе гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑной гÑаÑики пÑиложений, ÑакиÑ
как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑ, веб и лÑбой дÑÑгой облаÑÑи, ÑвÑзанной Ñ 3D дизайн доÑÑÑпен Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки.","engine":"ÐекоÑоÑÑе лÑди могÑÑ Ð½Ð°Ð·Ð²Ð°ÑÑ Ð´Ð²Ð¸Ð³Ð°ÑелÑ, пÑоÑÑо ÑлÑÑÐ°Ñ Ð·Ð²Ñк он делаеÑ, и ÑÑо дейÑÑвиÑелÑно ÑдивиÑелÑно. ÐезавиÑимо Ð¾Ñ Ñого, Ñвл
16518ÑеÑÑÑ Ð»Ð¸ ÑÑо ÑеакÑивнÑй двигаÑÐµÐ»Ñ Ð¸Ð»Ð¸ двигаÑÐµÐ»Ñ Ð°Ð²ÑомобилÑ, они оÑÐµÐ½Ñ ÑложнÑе маÑинÑ, коÑоÑÑе Ð¼Ñ Ð¸ÑполÑзÑем Ñак ÑаÑÑо, но не ÑÑаÑиÑÑ ÑлиÑком много вÑемени, дÑÐ¼Ð°Ñ Ð¾Ð± ÑÑом. ÐвигаÑÐµÐ»Ñ ÑвлÑеÑÑÑ Ð´Ð²Ð¸Ð³Ð°Ñелем (пока он не пеÑеÑÑÐ°Ð½ÐµÑ ÑабоÑаÑÑ). ÐÑа каÑегоÑÐ¸Ñ Ð¸Ð¼ÐµÐµÑ ÑелÑй ÑÑд ÑазлиÑнÑÑ
Ñипов двигаÑелей 3D-моделей, а Ñакже вклÑÑÐ°ÐµÑ Ð² ÑÐµÐ±Ñ Ð´ÐµÑÐ°Ð»Ñ Ð´Ð²Ð¸Ð³Ð°ÑелÑ, как пÑÐ¾Ð¿ÐµÐ»Ð»ÐµÑ Ð¸Ð»Ð¸ ÑилиндÑ, поÑÑÐ¾Ð¼Ñ Ð¼Ñ ÑвеÑенÑ, ÑÑо Ð²Ñ Ð½Ð°Ð¹Ð´ÐµÑе Ñо, ÑÑо вам нÑжно.","female":"ÐÑо не ÑÑÑка, ÑÑо ÑÑÑеÑÑвÑÑÑ Ð·Ð½Ð°ÑиÑелÑнÑе ÑазлиÑÐ¸Ñ Ð¼ÐµÐ¶Ð´Ñ Ð¼ÑжÑким и женÑким мозгом, а ÑÑо знаÑиÑ, ÑÑо ÑÑо ноÑмалÑно, ÑÑо ÑÑедний мÑжÑина и женÑина ведÑÑ ÑебÑ, ÑÑвÑÑвоваÑÑ Ð¸ ÑеагиÑоваÑÑ ÑовеÑÑенно по-ÑазномÑ. Ðо ÑÑо еÑе не вÑе об анаÑомии. ÐÐµÑ Ð¸ÑÑоÑÐ¸Ñ Ð»Ñбви, ÑилÑм или игÑа никогда не ÑнÑл его без ÑилÑной девÑÑки Ñ
аÑакÑеÑа, поÑÐ¾Ð¼Ñ ÑÑо Ñила леди ÑаÑм неоÑпоÑимо. ÐогаÑÑй вÑÐ±Ð¾Ñ ÑеалиÑÑиÑнÑÑ
женÑкиÑ
3D моделей Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑедложиÑÑ Ð²Ð°Ð¼ вÑе, ÑÑо вам нÑжно - Ð¾Ñ Ð¾Ð±Ð½Ð°Ð¶ÐµÐ½Ð½ÑÑ
3D моделей Ð´Ð»Ñ Ð¶ÐµÐ½Ñкой дÑÑ
аÑелÑной ÑиÑÑемÑ.","hand":"ÐоÑÑÐ¾Ð¼Ñ Ð¼Ñ Ð¸ÑполÑзÑем наÑи ÑÑки Ñак мÐ
16518½Ð¾Ð³Ð¾ веÑей, иÑ
необÑÐºÐ½Ð¾Ð²ÐµÐ½Ð½Ð°Ñ Ð°Ð½Ð°ÑомиÑ. Ðдин ÑолÑко болÑÑой Ð¿Ð°Ð»ÐµÑ Ð½Ð°Ñ
одиÑÑÑ Ð¿Ð¾Ð´ конÑÑолем девÑÑи оÑделÑнÑÑ
мÑÑÑ. ТÑÑдно повеÑиÑÑ, но пеÑвÑе ÑÑки бÑли более ÑкзоÑиÑеÑкими, Ñем лÑÐ±Ð°Ñ ÑÑоÑона ÑÐµÐ³Ð¾Ð´Ð½Ñ - некоÑоÑÑе Ð²Ð¸Ð´Ñ Ð±Ñли ÑÐµÐ¼Ñ Ð¿Ð°Ð»ÑÑев. ЧеловеÑеÑкое Ñело знаÑиÑелÑно изменилоÑÑ. Ð Ñка или ÑÑка, как Ð¼Ñ Ð²Ð¸Ð´Ð¸Ð¼ ÑÑо ÑÐµÐ³Ð¾Ð´Ð½Ñ Ð²ÑглÑÐ´Ð¸Ñ Ð»ÑÑÑе, Ñем его Ñанние веÑÑии. ШиÑокий ÑпекÑÑ ÑеалиÑÑиÑнÑÑ
, ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ ÑÑÑнÑе 3д-модели, коÑоÑÑе гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑной гÑаÑики пÑиложений, ÑакиÑ
как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑ, веб и лÑбой дÑÑгой облаÑÑи, ÑвÑзанной Ñ 3D дизайн доÑÑÑпен Ð´Ð»Ñ ÑкаÑиваниÑ.","head":"РанаÑомии Ñеловека, голова веÑÑ
нÑÑ ÑаÑÑÑ Ñела Ñеловека. ÐоделиÑование ÑеловеÑеÑкой Ð³Ð¾Ð»Ð¾Ð²Ñ 3D Ð¼Ð¾Ð¶ÐµÑ Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ ÑложнÑм, поÑÐ¾Ð¼Ñ ÑÑо (неÑмоÑÑÑ Ð½Ð° Ñо, ÑÑо еÑÑÑ Ð¾ÑÐµÐ½Ñ Ð¼Ð½Ð¾Ð³Ð¾ ÑазлиÑнÑÑ
ÑоÑм и ÑазмеÑов), Ð¼Ñ Ð¾Ñениваем ÑиммеÑÑиÑнÑе, ÑеалиÑÑиÑно вÑглÑдÑÑие Ð³Ð¾Ð»Ð¾Ð²Ñ - не ÑмеÑнÑе глаза, ÑÑи, ноÑ, гÑÐ±Ñ Ð¸Ð»Ð¸ линии ÑелÑÑÑи, пожалÑйÑÑа. ÐиÑо ÑвлÑеÑÑÑ ÑÑвÑÑвиÑелÑной облаÑÑÑÑ, и ÑÑо бÑÐ´ÐµÑ Ð¿ÑоÑÑо обÑÑÐ½Ð°Ñ Ð³ÑÑбÑм, ÑÑÐ¾Ð±Ñ Ð²ÐµÑело пÑовеÑÑи вÑÐµÐ¼Ñ Ñ ÑÑим. ÐÐ°Ñ Ð²ÑÐ±Ð¾Ñ Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð² ÑÐµÐ±Ñ ÑеалиÑÑиÑнÑй мÑжÑина, женÑина, Ñебенок и даже пеÑÑонаж ÑаÑÑказа, как ÐаÑÑи ÐоÑÑÐµÑ Ð¸ ÐÑÑмен или знамениÑоÑÑÑ, как Том ÐÑÑз и СкаÑлеÑÑ ÐоÑ
анÑÑон ÑÑководиÑели, коÑоÑÑе гоÑÐ¾Ð²Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки.","helmet":"ÐÑегда помниÑе, ÑÑо пÑиÑ
Ð¾Ð´Ð¸Ñ Ð·Ð´Ð¾ÑовÑе и безопаÑноÑÑÑ Ð¿ÐµÑвого, поÑÑÐ¾Ð¼Ñ Ð·Ð°ÑиÑа ваÑа голова здÑÐ°Ð²Ð°Ñ Ð¸Ð´ÐµÑ. СÑедневековÑе ÑÑÑаÑи, Daft Punk и даже Ironman ноÑиÑÑ ÑлемÑ, Ñак как обÑÑнÑе ÑÑпеÑгеÑой велоÑипедиÑÑÑ Ð¸Ð»Ð¸ ÑÑÑоиÑели не Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÐµÑпокоиÑÑÑÑ Ð¾ поиÑке ÑаÑпÑÑенÑ. ÐÑа коллекÑÐ¸Ñ Ñлемов 3D моделей, коÑоÑÑе доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки окажеÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñм, еÑли Ð²Ñ ÑабоÑаеÑе в облаÑÑи гÑаÑиÑеÑкого дизайна, 3D-анимаÑии, 3D-игÑÑ Ð¸Ð»Ð¸ визÑализаÑии.","house":"ÐÑо ÑÑаÑÐ°Ñ Ð¸ÑÑина, ÑÑо дом Ñеловека еÑÑÑ Ñвой замок, но когда дело доÑ
Ð¾Ð´Ð¸Ñ Ð´Ð¾ ÑÑÑоиÑелÑÑÑва, ÑÑо идеалÑнÑй дом или кÑпиÑÑ Ð¸Ð´ÐµÐ°Ð»ÑнÑÑ ÐºÐ²Ð°ÑÑиÑÑ, мÑ, как пÑавило, ÑеÑÑÑÑ Ð³Ð¾Ð»Ð¾Ð²Ð° над ним. Ð ÑÑаÑÑÑÑ, ÑÑÐ¾Ñ ÑиÑокий ÑпекÑÑ Ð´Ð¾Ð¼ 3D моделей, коÑоÑÑе вклÑÑаÑÑ Ð² ÑÐµÐ±Ñ Ð²Ñе, наÑÐ¸Ð½Ð°Ñ Ð¾Ñ Ð°ÑÑ
иÑекÑÑÑнÑÑ
деÑалей инÑеÑÑеÑа и ÑкÑÑеÑÑеÑа, мебелÑ, Ð¿Ð¾Ð¼Ð¾Ð¶ÐµÑ ÑоздаÑÑ ÑовÑеменнÑÑ 3D визÑализаÑии, ÑÑÐ¾Ð±Ñ Ð¾Ð±Ð»ÐµÐ³ÑиÑÑ ÑÑÑ Ð±Ð¾Ð»Ñ.","human":"Ðогда Ð²Ñ Ð½Ð°ÑинаеÑе изÑÑаÑÑ Ð°Ð½Ð°ÑÐ¾Ð¼Ð¸Ñ Ñеловека, Ð²Ñ Ð¿Ð¾Ð½Ð¸Ð¼Ð°ÐµÑе, ÑÑо лÑди, Ñакие запÑÑаннÑе и ÑложнÑе маÑинÑ, ÑÑо заÑ
ваÑÑÐ²Ð°ÐµÑ Ð´ÑÑ
. ÐÐ°Ð¶Ð´Ð°Ñ ÑаÑÑÑ Ñела, мÑÑÑ, ÑÑÑÑавов, оÑганов или коÑÑей ÑоÑеÑание ÑоединÑеÑÑÑ Ð² Ð¾Ð´Ð½Ñ ÑиÑÑемÑ, ниÑего не ÑабоÑÐ°ÐµÑ Ð² изолÑÑии! ÐÑа ÑÑÐ¿ÐµÑ ÑеалиÑÑиÑнÑе 3D Ð¼Ð¾Ð´ÐµÐ»Ñ Ñеловека Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ Ð¸ÑÑледоваÑÑ Ð°Ð½Ð°ÑомиÑеÑкие ÑÑÑÑкÑÑÑÑ Ñ Ð»ÑбÑм Ñглом.","lamp":"ÐÑли Ð²Ñ Ð¿Ð¾ÑмоÑÑиÑе вокÑÑг ваÑего дома и подÑÑиÑÑваÑÑ ÑÐ¸Ð¿Ñ Ð»Ð°Ð¼Ð¿, коÑоÑÑми Ð²Ñ Ð²Ð»Ð°Ð´ÐµÐµÑе, Ð²Ñ Ð±ÑдеÑе ÑдивленÑ: ÑÑение, наÑÑолÑнÑе, наÑÑеннÑе, поÑолоÑнÑе, пиÑÑменнÑй ÑÑол, ÑÑаÑив Ð»Ð°Ð¼Ð¿Ñ ... ÐÑо доÑÑаÑоÑно, ÑÑÐ¾Ð±Ñ ÑделаÑÑ Ð²Ð°ÑÑ Ð³Ð¾Ð»Ð¾Ð²Ñ Ñпина! Ðе говоÑÑ Ñже о Ñом, ÑÑо ÑÑили они пÑиÑ
одÑÑ - Ð¾Ñ ÑкÑÑÑаваганÑнÑÑ
ÑовÑеменнÑÑ
ламп в ÑÑиле ÑеÑÑо или ÑÑилÑнÑй Ñ
16518ÑÑÑÑиÑÑиÑеÑкий. Ð ÑÑой каÑегоÑии Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð²Ñе Ð²Ð¸Ð´Ñ Ð»Ð°Ð¼Ð¿ 3D моделей, Ñак ÑÑо пÑоÑмаÑÑиваÑÑ Ð¸ загÑÑжаÑÑ Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² облаÑÑи гÑаÑиÑеÑкого дизайна, 3D визÑализаÑии или лÑбой дÑÑгой 3D-ÑвÑзанной облаÑÑи.","light":"ÐÑ ÐºÐ¾Ð³Ð´Ð°-нибÑÐ´Ñ Ð·Ð°Ð´Ð°Ð²Ð°Ð»Ð¸ÑÑ Ð²Ð¾Ð¿ÑоÑом, поÑÐµÐ¼Ñ Ð»Ð°Ð¼Ð¿Ð¾Ñка ÑвлÑеÑÑÑ Ñимволом блеÑÑÑÑей идеей? ÐонеÑно, Ð¸Ð´ÐµÑ ÑÑÐºÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑоÑвеÑиÑÑ Ð°ÑÑ
иÑекÑÑÑÑ Ñма, но ÑÑо не Ñак. УлиÑнÑй ÑвеÑ, лÑÑÑÑа или лÑбой дÑÑгой Ñип Ð»Ð°Ð¼Ð¿Ñ Ð½Ð¸ÐºÐ¾Ð³Ð´Ð° не бÑÐ´ÐµÑ ÑÑоÑÑÑ ÑÐ°Ð½Ñ Ð·Ð°Ð½ÑÑÑ ÑÑо меÑÑо. ÐÑли в ÑледÑÑÑий Ñаз, когда Ð²Ñ Ð¿Ð¾ÑмоÑÑиÑе на поÑолок и ÑмоÑÑеÑÑ Ð½Ð° какой-Ñо аÑÑ
иÑекÑÑÑнÑй ÑÐ²ÐµÑ Ð¸Ð´ÐµÑ Ð³ÐµÐ½Ð¸Ð¹ не ÑдаÑил ваÑ, ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾ÑомÑ, ÑÑо Ð²Ñ ÑмоÑÑели на непÑавилÑнÑÑ ÑиÑÑÐµÐ¼Ñ Ð¼Ð¾Ð»Ð½Ð¸Ð¸ ... ÐÐ°Ñ Ð²ÑÐ±Ð¾Ñ Ð²ÑÑокого каÑеÑÑва ÑвеÑа 3D модели окажеÑÑÑ Ð¿Ð¾Ð´ ÑÑкой, еÑли Ð²Ñ ÑабоÑаеÑе в облаÑÑи аÑÑ
иÑекÑÑÑÑ, компÑÑÑеÑной гÑаÑики, 3D-анимаÑии и дизайна.","machine":"ÐÑедÑÑавÑÑе Ñебе, еÑли вÑе маÑÐ¸Ð½Ñ Ð²Ð´ÑÑг оÑÑановилиÑÑ Ð½Ðµ ÑабоÑаÑÑ: Ð½ÐµÑ ÐºÐ¾Ñе, Ð½ÐµÑ Ñдобной Ð´Ð»Ñ ÑÑиÑки, не ÐÐÐРна Ñгле ÑлиÑÑ, Ð½ÐµÑ Ð²Ñемени ÑÑенажеÑного зала, не завÑÑÐµÐ½Ñ Ð°Ð²ÑомаÑов ... ÐÑо звÑк ÑдÑÑÑаеÑ, не Ñак ли? ÐÑ Ñак пÑивÑкли к ÑÑим бÑÑовой ÑеÑ
ники и ÑлекÑÑоннÑÑ
ÑÑÑÑойÑÑв, ÑÑо бÑквалÑно оÑÑановиÑÑ Ð¼Ð¸Ñовой повоÑоÑ! Ð ÑÑаÑÑÑÑ, Ð½Ð°Ñ Ð²ÑÐ±Ð¾Ñ Ð¿Ð¾Ð´ÑобнÑе маÑÐ¸Ð½Ñ 3D моделей оÑ
ваÑÑÐ²Ð°ÐµÑ Ð²Ñе из пÑлемеÑов ÑлекÑÑогенеÑаÑоÑов, коÑоÑÑе окажÑÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñми Ð´Ð»Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½ÐµÑов, ÑабоÑаÑÑиÑ
Ñ ÐºÐ¾Ð¼Ð¿ÑÑÑеÑной гÑаÑикой, Ñекламой, 3D-анимаÑии, 3D-игÑÑ Ð¸Ð»Ð¸ ÐнÑеÑнеÑ.","man":"ÐбÑиÑнÑй Ð½Ð°Ð±Ð¾Ñ Ð¸ÑкÑÑÑÑвеннÑÑ
3D моделей доÑÑÑпен Ð´Ð»Ñ ÑкаÑиваниÑ. СидеÑÑ Ñеловек, пÑоÑÑой Ñеловек, леÑаÑÑий Ñеловек или ÑÑедний Ñеловек, Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð²Ñе - кÑоме Ñого, ÑÑо ÑовеÑÑеннÑй Ñеловек, ÑÑо вÑе поÑле. Ðн ÑÑÑклÑй Ñ
аÑакÑÐµÑ Ð¸ Ð¼Ñ Ð½ÐµÐ½Ð°Ð²Ð¸Ð´Ð¸Ð¼, ÑÑÐ¾Ð±Ñ Ð´Ð¾Ð²ÐµÑÑи ÑÑо, но ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼Ð¸Ñом ... Ðо Ñй, лÑди ÑожденÑ, ÑÑÐ¾Ð±Ñ Ð±ÑÑÑ ÑдивиÑелÑнÑм, не ÑвлÑеÑÑÑ ÑовеÑÑеннÑм.","robot":"R2D2, веÑоÑÑно, ÑамÑй извеÑÑнÑй ÑÐ¾Ð±Ð¾Ñ Ð² миÑе, но ÑÑо, конеÑно, не ÑолÑко один. ÐÑ Ð¸Ð½Ð´ÑÑÑÑиалÑного к игÑÑÑке ÑеловеÑеÑкиÑ
ÑобоÑов, Ð¼Ñ Ð²Ð¸Ð´Ð¸Ð¼ вÑе более ÑиÑокий вÑÐ±Ð¾Ñ ÑÑиÑ
меÑ
аниÑеÑкиÑ
маÑин, коÑоÑÑй ÑвлÑеÑÑÑ Ð¾Ð´Ð½Ð¾Ð²Ñеменно пÑекÑаÑнÑм и немного ÑÑевожнÑм. ÐÑо не Ñак Ñж ÑÑÑдно понÑÑÑ Ð»Ñдей, коÑоÑÑе наÑÑаиваÑÑ, ÑÑо компÑÑÑеÑÑ, ÑеÑ
нологии, ÑобоÑÑ Ð´ÐµÐ»Ð°ÑÑ ÑлиÑком знаÑиÑелÑное влиÑние на Ñеловека. ШиÑокий ÑпекÑÑ ÑеалиÑÑиÑнÑÑ
, ÑÑалÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ ÑобоÑов 3д-модели, коÑоÑÑе гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑной гÑаÑики пÑиложений, ÑакиÑ
как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑ, веб и лÑбой дÑÑгой облаÑÑи, ÑвÑзанной Ñ 3D дизайн доÑÑÑпен Ð´Ð»Ñ ÑкаÑиваниÑ.","ship":"СÑда Ñвл
16518ÑÑÑÑÑ Ð¼Ð¾ÑнÑми ÑÑда и бÑваÑÑ Ð²ÑеÑ
ÑазмеÑов, ÑвеÑов и ÑоÑм. Ðни могÑÑ Ð±ÑÑÑ ÐºÐ»Ð°ÑÑиÑиÑиÑÐ¾Ð²Ð°Ð½Ñ ÐºÐ°Ðº гÑÑзовÑÑ
ÑÑдов, военнÑÑ
коÑаблей и паÑÑажиÑÑкиÑ
ÑÑдов, но вÑе они ÑабоÑаÑÑ Ð² глÑбокиÑ
моÑÑкиÑ
водаÑ
. ÐÑли Ð²Ñ Ð¸ÑпÑÑали диÑкомÑоÑÑ Ð¾Ñ ÑкаÑиваниÑ, она не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²Ð°Ñи лÑбимÑе ÑÑанÑпоÑÑнÑе ÑÑедÑÑва, но многие лÑди ÑÑиÑаÑÑ Ð¼Ð¾ÑÑкие пÑогÑлки, как доволÑно ÑÑилÑнÑй и пÑиÑÑнÑй. ÐÐ°Ñ Ð²ÑÐ±Ð¾Ñ ÑÑдовÑÑ
3D моделей гоÑова Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки и бÑÐ´ÐµÑ ÑооÑвеÑÑÑвоваÑÑ ÑÑандаÑÑам даже Ñамого ÑÑебоваÑелÑного капиÑана.","skeleton":"Ð¡ÐºÐµÐ»ÐµÑ Ñеловека или ÑкелеÑÐ½Ð°Ñ ÑиÑÑема (анаÑомиÑ) ÑвлÑеÑÑÑ Ð²Ð½ÑÑÑенней ÑÑÑÑкÑÑÑой Ñела, коÑоÑÐ°Ñ ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· 270 коÑÑей пÑи Ñождении. Ðна обеÑпеÑÐ¸Ð²Ð°ÐµÑ ÑÑÑÑкÑÑÑÑ Ñела, заÑиÑÑ Ð¸ движение и ÑвлÑеÑÑÑ Ð¾Ð´Ð½Ð¸Ð¼ из ÑамÑÑ
ÑложнÑÑ
каÑкаÑнÑÑ
ÑиÑÑем. ÐогаÑÑй вÑÐ±Ð¾Ñ Ð°Ð½Ð°ÑомиÑеÑки пÑавилÑнÑй, ÑеалиÑÑиÑнÑй и маÑÑÑабиÑÑеÑÑÑ ÑÐºÐµÐ»ÐµÑ 3D-моделей, коÑоÑÑе идеалÑно подÑ
одÑÑ Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² 3D-анимаÑии, гÑаÑиÑеÑкого дизайна, ÑекламÑ, 3D-Ð¸Ð³Ñ Ð¸ веб доÑÑÑпен Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки.","skull":"СÑаÑейÑий наиболее полнÑй, генеÑиÑеÑки неÑÑонÑÑÑй ÑеловеÑеÑкий ÑеÑеп бÑл обнаÑÑжен в окÑÑжении множеÑÑва вÑмеÑÑиÑ
живоÑнÑÑ
более Ñем на 40 меÑÑов ниже ÑÑÐ¾Ð²Ð½Ñ Ð¼Ð¾ÑÑ. ÐÑо один из ÑамÑÑ
ÑÑаÑÑÑ
ÑкелеÑов, найденнÑÑ
в Ðовом СвеÑе, и ÑÑо Ñакже вклÑÑÐ°ÐµÑ Ð² ÑÐµÐ±Ñ Ð²Ñе оÑновнÑе коÑÑи Ñела и неповÑежденного ÑеÑепа и Ð½Ð°Ð±Ð¾Ñ Ð·Ñбов. ЧеловеÑеÑкие ÑеÑепа в поÑледнее вÑÐµÐ¼Ñ ÑÑали веÑÑÑ Ð² моде и дизайне, но когда Ð²Ñ Ð½Ð° Ñамом деле даÑÑ ÐµÐ¼Ñ Ð½ÐµÐºÐ¾ÑоÑÑе мÑÑли, они вÑоде делаÑÑ Ð½Ð°Ñ Ð²Ñе поÑ
ожи по анаÑомии ÑÑодам ... ÐÑа каÑегоÑÐ¸Ñ Ð¿ÑÐµÐ´Ð»Ð°Ð³Ð°ÐµÑ ÑиÑокий ÑпекÑÑ ÑеÑеп 3D моделей Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² гÑаÑиÑеÑком дизайне , 3D-анимаÑиÑ, 3D-игÑÑ Ð¸Ð»Ð¸ ÑекламÑ.","sofa":"РоÑкоÑÑ Ð¸Ð»Ð¸ пÑоÑÑой, ÑовÑеменнÑй или анÑиÑнÑй, кожа или минималиÑÑÑкий дизайн? Ðак вам нÑавиÑÑÑ Ð²Ð°Ñ Ð´Ð¸Ð²Ð°Ð½? Ðиапазон диван 3D моделей, коÑоÑÑе Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑдовлеÑвоÑиÑÑ Ð´Ð°Ð¶Ðµ ÑамÑй Ñ
ÑдÑий пеÑÑекÑиониÑÑ. Ðогда Ð²Ñ Ð·Ð°Ð´ÑмаеÑеÑÑ Ð¾Ð± ÑÑом, диван ÑвлÑеÑÑÑ ÑенÑÑом каждой гоÑÑиной, Ñак ÑÑо Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑвоÑÑеÑкими пÑи вÑбоÑе дизайна!","table":"ÐовейÑие мебелÑнÑе ÑенденÑии наÑÑолÑко ÑазнообÑазнÑ, ÑÑо вÑÐ±Ð¾Ñ ÑовÑеменнÑй, моднÑй ÑÑол ÑÑановиÑÑÑ ÑлиÑком напÑÑженнÑм. Там ÑанÑÑе бÑло вÑемÑ, когда Ñ Ð²Ð°Ñ Ð±Ñл пÑоÑÑой обеденнÑй ÑÑол Ð´Ð»Ñ ÑкÑомнÑÑ
пÑаздников и ÑÑого бÑло доÑÑаÑоÑно, но ÑÐµÐ³Ð¾Ð´Ð½Ñ - ÑаблиÑа должна бÑÑÑ Ð·Ð°Ñвление или, по кÑайней меÑе, вÑделÑÑÑийÑÑ Ð¸Ð½ÑеÑÑÐµÑ Ð°ÐºÑенÑ. ÐÑÐ¾Ñ Ð²ÑÐ±Ð¾Ñ Ð´Ð°ÐµÑ ÑиÑокий ÑпекÑÑ Ð½Ð°ÑÑолÑнÑÑ
3D-моделей, ÑÑÐ¾Ð±Ñ ÑдовлеÑвоÑиÑÑ Ð»Ñбой капÑиз.","tower":"ÐаждÑй гоÑод Ð¸Ð¼ÐµÐµÑ ÑпеÑиалÑнÑÑ Ð±Ð°ÑнÑ, ÑÑо вÑе на Ñамом деле гоÑдиÑÑÑÑ. ÐодÑмайÑе ÐйÑелева баÑÐ½Ñ Ð¸Ð»Ð¸ ÐизанÑÐºÐ°Ñ Ð±Ð°ÑнÑ, или в Ðондоне ТаÑÑÑÑкий моÑÑ, не говоÑÑ Ñже вÑе ÑовÑеменнÑе небоÑкÑебÑ, ÑÑÑÑÑиÑÑиÑеÑкие Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸ гоÑодÑкой пейзаж, Ð
16518ºÐ¾ÑоÑÑй ÑÑÑиÑÑÑ Ð²Ð¾ÑÑ
иÑаÑÑÑÑ. Ðднако, когда ÑеÑÑ Ð¸Ð´ÐµÑ Ð¾ пÑомÑÑленнÑÑ
ÑайонаÑ
гоÑода, вода или ÑлекÑÑиÑеÑкие баÑни, вÑе ÑÑÑемÑÑÑÑ Ð¿ÑевÑаÑиÑÑ Ñвои глаза в ÑÑоÑÐ¾Ð½Ñ ... Ðо Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð½Ð°ÑÑиÑÑÑÑ Ð½Ðµ ÑениÑÑ ÐºÐ°Ð¶Ð´Ð¾Ðµ аÑÑ
иÑекÑÑÑное ÑвоÑение, незавиÑимо Ð¾Ñ Ñого, дÑевний, пÑомÑÑленнÑй или ÑовÑеменнÑй. ÐеÑалÑнÑе баÑни 3D моделей доÑÑÑÐ¿Ð½Ñ Ð´Ð»Ñ ÑкаÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¸ гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑнÑм гÑаÑикам пÑиложений, Ñаким как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑÑ, веб и лÑбой дÑÑгой облаÑÑÑ, ÑвÑзанной Ñ 3D-дизайном.","tree":"ÐÑли Ð²Ñ Ð½Ð°Ñ
одиÑеÑÑ Ð½Ð° миÑÑии, ÑÑÐ¾Ð±Ñ Ð¿Ð¾ÑадиÑÑ Ð´ÐµÑевÑÑ Ð¸Ð»Ð¸ ÑкзоÑиÑеÑкие ÑаÑÑениÑ, Ð²Ñ Ð¿ÑиÑли в нÑжное меÑÑо. ÐÑа каÑегоÑÐ¸Ñ Ð¿ÑÐµÐ´Ð»Ð°Ð³Ð°ÐµÑ ÑиÑокий вÑÐ±Ð¾Ñ Ð¿ÑоÑÑой в иÑполÑзовании, оÑÐµÐ½Ñ ÑеалиÑÑиÑнÑе 3D модели деÑевÑев к CG Ñ
Ñдожников и аÑÑ
иÑекÑоÑов, коÑоÑÑе ÑÑÑемÑÑÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ Ð·ÐµÐ»ÐµÐ½Ñ Ð² Ñвои пÑоекÑÑ. ÐÑли Ð²Ñ ÑениÑе Ñ
оÑоÑее каÑеÑÑво, Ð¼Ñ ÑвеÑенÑ, ÑÑо ÑÑÐ¾Ñ Ð²ÑÐ±Ð¾Ñ 3D моделей деÑевÑев ÑаÑÑений бÑÐ´ÐµÑ ÑооÑвеÑÑÑвоваÑÑ Ð²Ð°Ñим ÑÑандаÑÑам!","truck":"Ðождение гÑÑзовика ÑÑÑÐ´Ð½Ð°Ñ ÑабоÑа, оÑобенно еÑли вам нÑжно найÑи Ñвой пÑÑÑ ÑеÑез ваÑенÑем гоÑод движениÑ. ÐезавиÑимо Ð¾Ñ Ñого, ÑвлÑеÑÑÑ Ð»Ð¸ ÑÑо пожаÑнÑй, мÑÑоÑовоз, гÑÑзовик пиÑи или Ñодовой один, он пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð±Ð¾Ð»ÑÑое Ñмение маневÑиÑоваÑÑ ÑÑи гиганÑÑкие ÑÑанÑпоÑÑнÑе ÑÑедÑÑва. ÐÑ ÑвеÑенÑ, ÑÑо ÑÑÐ¾Ñ Ð²ÑÐ±Ð¾Ñ ÑеалиÑÑиÑнÑÑ
, вÑÑокое каÑеÑÑво гÑÑзовиков 3D модели идеалÑно подÑ
одÑÑ Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² 3D-анимаÑии, гÑаÑиÑеÑкого дизайна, ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸Ð»Ð¸ лÑбой дÑÑгой 3D-ÑвÑзанной облаÑÑи.","tv":"Там ÑанÑÑе бÑло вÑемÑ, когда камин бÑл ÑенÑÑалÑной каждого ÑеÑпекÑабелÑного дома, ÑепеÑÑ ÑÐµÐ»ÐµÐ²Ð¸Ð·Ð¾Ñ Ñ Ð¸Ð³Ñоками и динамиками коÑÐ¾Ð»Ñ Ð³Ð¾ÑÑиной (и даже ÑпалÑни). РпоÑледние Ð³Ð¾Ð´Ñ Ñелевидение догнали новейÑими ÑеÑ
нологиÑми. Ð ÑезÑлÑÑаÑе, Ñ Ð½Ð°Ñ ÐµÑÑÑ ÑмнÑе 3D-ÑелевизоÑ, плоÑкие и плазменнÑе ÑкÑанÑ, миллион новÑÑ
ÑÑнкÑий и дизайн ÑенÑоÑного ÑкÑана. Ðе ÑдивиÑелÑно, ÑÑо Ñелевидение не ÑÐ¾Ð»ÐºÐ°ÐµÑ ÐºÐ¸Ð
16518½Ð¾ из ÑÑнка. ШиÑокий ÑпекÑÑ ÑеалиÑÑиÑнÑÑ
, подÑобнÑÑ
моделей ÑелевизоÑов 3D, коÑоÑÑе гоÑÐ¾Ð²Ñ Ðº компÑÑÑеÑной гÑаÑики пÑиложений, ÑакиÑ
как Ñеклама, 3D визÑализаÑиÑ, 3D-игÑ, веб и лÑбой дÑÑгой облаÑÑи, ÑвÑзанной Ñ 3D дизайн доÑÑÑпен Ð´Ð»Ñ Ð·Ð°Ð³ÑÑзки."}},"tag_promotion":{"days_left_error":"должно бÑÑÑ Ð¾Ñ 1 до 30","no_other_pending_promotions_for_same_item_tag":"Ñже Ð¸Ð¼ÐµÐµÑ Ð¾Ð¶Ð¸Ð´Ð°ÑÑÑÑ Ð¿ÑомоакÑиÑ"},"time":{"am":"ÑÑÑа","formats":{"default":"%a, %d %b %Y, %H:%M:%S %z","long":"%d %B %Y, %H:%M","short":"%d %b, %H:%M"},"pm":"веÑеÑа"},"tooltips":{"buyer_loyalty_program_current_level_html":"РнаÑÑоÑÑее вÑÐµÐ¼Ñ Ð²Ñ Ð¿Ð¾ÑÑаÑили %{total_price_paid} на CGTrader и ваÑей кÑедиÑной заÑабоÑаÑÑ ÑкоÑоÑÑÑ ÑоÑÑавлÑÐµÑ %{buyer_loyalty_rate}. \u003cbr/\u003e ÐÑо ознаÑаеÑ, ÑÑо Ð²Ñ Ð¿Ð¾Ð»ÑÑиÑе %{buyer_loyalty_rate} кÑедиÑов Ð¾Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ покÑпки.\n","buyer_loyalty_program_html":"ÐÑо пÑоÑÐµÐ½Ñ Ð¾Ñ Ñого, ÑколÑко Ð²Ñ Ð¿Ð¾Ð»ÑÑиÑе Ð¾Ñ Ð²Ð°ÑиÑ
покÑпок в каÑеÑÑве новÑÑ
кÑедиÑов. \u003cbr/\u003e ÐÑо ÑвелиÑÐ¸Ñ Ð´Ð¾ 30% в каÑеÑÑве пожизненнÑÑ
ÑаÑÑ
одов на CGTrader ÑвелиÑении. \u003cbr/\u003e РнаÑÑоÑÑее вÑÐµÐ¼Ñ Ð²Ð°Ñа кÑедиÑÐ½Ð°Ñ ÑÑавка заÑабоÑаÑÑ %{buyer_loyalty_rate}.\n","buyer_loyalty_program_next_level_html":"СледÑÑÑий ÑÑÐ¾Ð²ÐµÐ½Ñ %{next_lvl_expenses} ÑвелиÑÐ¸Ñ Ð²Ð°Ñ ÐÑÐµÐ´Ð¸Ñ Ð·Ð°ÑабоÑаÑÑ ÑÑÐ°Ð²ÐºÑ Ð´Ð¾ %{next_lvl_expenses_rate}. \u003cbr/\u003e ÐÑ Ð´Ð¾Ð»Ð¶Ð½Ñ ÐºÑпиÑÑ Ð·Ð° $ %{left_until_next_lvl} болÑÑе, ÑÑÐ¾Ð±Ñ Ð´Ð¾ÑÑиÑÑ ÑледÑÑÑего ÑÑовнÑ.\n"},"trending_headers":{"models":"ÐоÑмоÑÑиÑе дÑÑгие попÑлÑÑнÑе 3D модели","print":"ÐоÑмоÑÑиÑе дÑÑгие попÑлÑÑнÑе 3D модели Ð´Ð»Ñ Ð¿ÐµÑаÑи"},"tutorial":{"destroy":"УÑок бÑл ÑÑпеÑно ÑдалÑн.","submit_for_review_error":"ÐожалÑйÑÑа, заполниÑе вÑе обÑзаÑелÑнÑе полÑ.","submitted":"СпаÑибо за оÑпÑÐ°Ð²ÐºÑ Ð²Ð°Ñего ÑÑока. Ðн бÑÐ´ÐµÑ Ð¿ÑовеÑен и вÑкоÑе опÑбликован."}},"zh-CN":{"activerecord":{"attributes":{"content_report":{"categories":{"adult":"æäººææ´åå
容","copyright":"ä¾µç¯çæ"}}},"errors":{"messages":{"embedded_script":"æ¤æä»¶ä¸åæ¯æï¼æ æ³ä¸ä¼ ã请å°è¯å
¶ä»æä»¶ã"}}},"api":{"profile":{"actions":{"contact":"èç³»","follow":"å
³æ³¨","follow_tooltip":"å
³æ³¨æ¤è®¾è®¡å¸ä»¥è·åå
¶å
å®¹æ´æ°ï¼å¹¶å¨æç´¢ç»æä¸è½»æ¾çéåç±ç设计å¸ã","hide":"éè","hire_me":"éä½£æ","invite_client":"å¯å¨é¡¹ç®","mute_tooltip":"å¨æç´¢ç»æä¸éèæ¤è®¾è®¡å¸ç模åã","take_over":"æ¥ç®¡","unfollow":"åæ¶å
³æ³¨","unhide":"æ¾ç¤º","view_all_models":"æ¥çææè®¾è®¡å¸ç模å"},"private_project_review":"ç§äººé¡¹ç®"}},"browser":{"3d_models":"3D模å","3d_print":"3Dæå°","active_filters":{"polygons":"%{range}å¤è¾¹å½¢"},"adult_content":"æ¾ç¤ºå¹´é¾+","animated":"å¨ç»","breadcrumb":{"browse_by_type":"æç±»åæµè§","collection":"3Dèµæºå
","free":"èªç±","free_models":"å
è´¹ç3D模å","free_print_models":"å
è´¹ç3Dæå°æ¨¡å","low_poly":"ä½å¤è¾¹å½¢","low_poly_models":"VR / AR /ä½å¤è¾¹å½¢ç3D模å","low_poly_print_models":"ä½å¤è¾¹å½¢ 3D æå°æ¨¡å","model_3d":"3D模å","model_3dp":"3Dæå°æ¨¡å","models":"3D模å","models_3d":"3D模å","models_3dp":"3Dæå°æ¨¡å","models_variant_0":"3D模å","models_variant_1":"3Dèµäº§","models_variant_2":"VR模å","models_variant_3":"CG模å","models_variant_4":"3D模åååº","models_variant_5":"3Dç©ä½","print_models":"3Dæå°æä»¶","print_models_variant_0":"3Dæå°æ¨¡å","print_models_variant_1":"3Dæå°æºæ¨¡å","print_models_variant_10":"ç¨äºæå°ç3D模å","print_models_variant_11":"å¯ä¾æå°ç3D模å","print_models_variant_12":"ç¨äºæå°ç3Dæä»¶","print_models_variant_13":"éç¨äº3Dæå°æºç模å","print_models_variant_14":"ç¨äº3Dæå°ç模å","print_models_variant_15":"3Dæå°ç模å","print_models_variant_16":"坿å°ç3Dæä»¶","print_models_variant_2":"ç¨äºæå°ç3D模å","print_models_variant_3":"3Dæå°æ¨¡å","print_models_variant_4":"3Dæå°æä»¶","print_models_variant_5":"3Dæå°æä»¶","print_models_variant_6":"3Dæå°æºæä»¶","print_models_variant_7":"坿å°3D模å","print_models_variant_8":"坿å°ç3D模å","print_models_variant_9":"å·²æå°ç3D模å"},"buyer_engagement_program":"ææ£","categories":"åç±»","category":{"meta":{"3d_models":"%{count} %{category}ç3D模åå¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D%{page}","3d_print_models":"ä¸è½½ %{count} %{category}3Dæå°æ¨¡åï¼å¯ä¾ä¸è½½çSTLï¼OBJçæ ¼å¼çæä»¶ï¼åå¤ä¸FDMï¼SLSç3Dæå°æºä¸æå°ã%{page}","animated_3d_models":"%{count} %{category}å¨ç»å¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D 3D模å%{page}","free_3d_models":"ä¸è½½ %{count} %{category}å
è´¹ç3D模åï¼å¨MAXï¼OBJï¼FBXï¼3DSï¼C4Dæä»¶æ ¼å¼æä¾ï¼åå¤VR / ARï¼å¨æ¼«ï¼æ¸¸æç3D项ç®ã%{page}","free_3d_print_models":"ä¸è½½ %{count} %{category}å
è´¹ç3Dæå°æ¨¡ååå¤FDMï¼SLAï¼SLSç3Dæå°æºï¼å¯ç¨çæ ¼å¼STLï¼OBJï¼3DMå¤ã%{page}","lowpoly_3d_models":"ä¸è½½ %{count} VR / AR /ä½å¤è¾¹å½¢%{category}ç3D模ååå¤èæç°å®ï¼æ¸¸æåå
¶ä»å®æ¶åºç¨ç¨åºï¼æä¾FBXï¼OBJï¼MAXï¼3DSï¼C4Dæä»¶æ ¼å¼%{page}","rigged_3d_models":"%{count} %{category}æçºµå¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D 3D模å%{page}"}},"collection":"3Dèµæºå
","discounts":"ææ£","ext":{"meta":{"3d_models":"ä¸è½½%{rounded_count}个%{format_upper}æ ¼å¼3D模åãå
è´¹ä¸ä»è´¹%{format_lower}æä»¶ã","3d_print_models":"ä¸è½½ %{count} %{ext}æä»¶ - %{software_name} 3Dæå°æ¨¡ååå¤VR / ARï¼3D设计ï¼å¨ç»ï¼æ¸¸æå宿¶åºç¨ç¨åº%{page}ã"}},"filter_button":"åºç¨è¿æ»¤å¨","filters":{"adult_content_only":"ä»
éæäººå
容","cgt_standard_only":"CGTæ å","collections_only":"ä»
éç»åå
","content_filters":"å
容çé","designer":"设计å¸","exclude_3d_print":"æé¤3Dæå°","exclude_adult_content":"æé¤æäººå
容","exclude_ai_generated":"æé¤AIçæå
容","exclude_editorial_license":"æé¤ç¼è¾è®¸å¯","exclude_free":"æé¤å
è´¹","file_format":"æä»¶æ ¼å¼","following":"å
³æ³¨ä¸","free":"å
è´¹","has_marmoset":"带æ3Dæ¥çå¨","has_video":"带æè§é¢","include_ai_generated":"å
å«AIçæå
容","label":"è¿æ»¤å¨","poly_count":"å¤è¾¹å½¢æ°é","print_ready":"3Dæå°","stl_files":"STL æä»¶","subscription":"订é
","type":"ç±»å"},"formats":"æ ¼å¼","free":"èªç±","free_models":"åªæ¾ç¤ºå
费模å¼","free_to_premium":{"main":"%{category} 3D模å","postfix":"å¨ä¼è´¨å表ä¸ã","prefix":"ä½ éè¦ç¹å«çä¸è¥¿åï¼ä½ å¯ä»¥æ¾å°æ´é«è´¨éç"},"gallery":{"preview":"é¢è§"},"game_ready":"游æåå¤","high_poly":"é«è","items_page_title":"3D模å","license":{"exclude_branded":"æé¤åç","exclude_editorial":"ç¼è¾æé¤","prompt":"æ§ç
§","tooltip_more":"é
读æ´å¤","tooltip_text":" ä¸è¦æ¾ç¤ºï¼åªè½å¨éåä¸ï¼æè²ç®çè使ç¨çæºåã","tooltip_title":"æé¤ç¼è¾è§ç¹ï¼"},"low-poly":"ä½è","low_poly":"ä½è","meta":{"3d_models":"ä¸è½½æè´ä¹°%{rounded_count}个ä¸ä¸3D模åãå
è´¹ä¸ä»è´¹3D模åï¼éç¨äºæ¸¸æãå½±è§ãVFXãAR/VRå3Dæå°ãæ¯æFBXãOBJãBLENDãGLBæ ¼å¼ã","3d_print_models":"ä¸è½½%{rounded_count}个3Dæå°æ¨¡åãå
è´¹ä¸ä»è´¹STLæä»¶ï¼æåãæ¨¡åãå®ç¨ä»¶çã","animated_3d_models":"ä¸è½½%{rounded_count}个带å¨ç»ç3D模åãFBXãBLENDãGLBæ ¼å¼ç游æå°±ç»ªè§è²ä¸ç©ä½ã","free_3d_models":"ä¸è½½%{rounded_count}个å
è´¹3D模åãå
è´¹3Dç´ æï¼æ¯æFBXãOBJãBLENDãGLBæ ¼å¼ï¼å¯ç¨äºæ¸¸æåCG项ç®ã","free_3d_print_models":"%{rounded_count}个å
è´¹3Dæå°æ¨¡åãå
è´¹ä¸è½½STLæä»¶ï¼éç¨äºåç±»3Dæå°æºã","lowpoly_3d_models":"ä¸è½½%{rounded_count}个ä½å¤è¾¹å½¢3D模åï¼éç¨äºæ¸¸æãAR/VRä¸å®æ¶æ¸²æã","metaverse":"è¾å
¥æä»¬çé«åä½poly 3Dåå·çæ¶éï¼å¹¶ä½¿ç¨ä»»ä½æä»¶æ ¼å¼ã","omniverse":"ä½¿ç¨æä»¬çOmniverse 3Dæ¨¡åæ¥æå»ºèæä¸çãä»å
·æé«åä½çå¤è¾¹å½¢è®¡æ°çå¨ç»ï¼æçºµåPBR模åä¸è¿è¡éæ©ã","page_prefix":"page %{page_number} with","pbr_3d_models":"ä¸è½½%{rounded_count}个带PBRè´´å¾ç3D模åï¼éç¨äºUnityãUnrealä¸å®æ¶æ¸²æå¼æã","rigged_3d_models":"ä¸è½½%{rounded_count}个已ç»å®éª¨éª¼ç3D模åï¼å¯ç´æ¥ç¨äºå¨ç»ãæ¯æBlenderãMayaã3ds Ma
16518xãUnityåUnrealã","snap-ar":"å婿们ç3Dåå·ï¼æ¨å¯ä»¥ä½¿ç¨Snap ARå å
¥æ°ç¾ä¸ä¸ªSnapchattersï¼ä»¥åé æè¶£çå¢å¼ºç°å®ä½éªã","spark-ar":"使ç¨åç§Spark AR 3Dåå·æ¥ä½¿æ¨çFacebookåInstagram亮起ï¼è¿äºæ¨¡å被æçºµï¼å¨ç»ååå¤ä½¿ç¨ã","stream_3d_print_models":"æµè§éè¿åç§æµç3Dæå°æ¨¡åç±»å«æ¥åç°ä¸äºä»ä¸ä¸ç3Då¶ä½è
æä¸å¯»å¸¸ç3Dæå°è®¾è®¡ã","textures":"%{count} 个纹ççä¸ç»´èµæºåææå¯ä¾ä¸è½½çåç§æ ¼å¼ï¼å
æ¬.TGA .sbsar .JPEG .PNG .TIFFçã %{页}","tiktok":"Tiktok 3Dåå·ä½¿æ¨çè§é¢æææ´ä»¤äººå°è±¡æ·±å»ãæä»¬çå¾ä¹¦é¦å¯ä»¥æ»¡è¶³æ¨çææåé æ§éæ±ï¼å¹¶ä¸ææ´æ°ã","unity":"ä»¥ä»»ä½æä»¶æ ¼å¼åä»»ä½polyè®¡æ°æ¥æ¾æ¨çUnity项ç®ç3D模åãå建ç¬ç¹çèæç¯å¢æéçä¸åã","unreal":"使ç¨ä»»ä½æä»¶æ ¼å¼å
¼å®¹ç3D模åå建令人å°è±¡æ·±å»çå¯è§åãæä»¬çå¾ä¹¦é¦é½ææ¥èªæ¯ä¸ªç±»å«ç使¨¡åã"},"optimized":"ä½å¤è¾¹å½¢/ PBR","page_title":{"animated_3d_models":"å¨ç»3D模å â å
è´¹ä¸ä»è´¹","format_page":"%{format_upper} 3D模å â %{format_lower}æä»¶ä¸è½½","free_3d_models":"å
è´¹3D模å â å
è´¹ä¸è½½","free_3d_print_models":"å
è´¹3Dæå°æ¨¡å â å
è´¹STLæä»¶ä¸è½½","lowpoly_3d_models":"ä½å¤è¾¹å½¢3D模åï¼Low Polyï¼ â å
è´¹ä¸ä»è´¹","pbr_3d_models":"PBR 3D模å â å
è´¹ä¸ä»è´¹","rigged_3d_models":"ç»å®éª¨éª¼3D模åï¼Riggedï¼ â å
è´¹ä¸ä»è´¹","software_page":"%{software} 3D模å â %{ext_file}ä¸è½½","tag":{"3d_merged_premium":"%{tag_cap}3D模å â å
è´¹ä¸è½½ä¸è´ä¹°","3d_merged_premium_print":"%{tag_cap}3Dæå°æ¨¡å â STLæä»¶","3d_models":"%{tag_cap}3D模å â å
è´¹ä¸è½½ä¸è´ä¹°","3d_print_models":"%{tag_cap}3Dæå°æ¨¡å â STLæä»¶"}},"pbr":"PBR","per_page":"æ¯é¡µ","polygons_options":{"custom":"èªå®ä¹èå´","gt_250k":"250K +","lt_5k":"é«è¾¾5K","more_than_250000":"250K以ä¸","prompt":"ä¿å©è®¡","range_0_5000":"æå¤5K","range_100000_250000":"100 - 250K","range_10000_50000":"10 - 50K","range_100k_250k":"100kååº250K","range_10k_50k":"10Kå°50K","range_50000_100000":"50 - 100K","range_5000_10000":"5 - 10K","range_50k_100k":"50Kå°100K","range_5k_10k":"5Kå°10K"},"price":"ä»·æ ¼ï¼$%{from}-%{to}","price_range":"ä»·é±","print_ready":"ä¸ç»´æå°å°±ç»ª","printable":"3Dæå°æ¨¡å","reset_button":"å¤ä½è¿æ»¤å¨","rigged":"éæ³æçºµç","rounded_count":{"delimiter":",","exact":"%{n}","separator":".","ten_thousand":"%{n}ä¸","thousand":"%{n}"},"sale_off":"ç¹ä»·ä¿é","search_placeholder":"æç´¢å
³é®è¯","show_all_formats":"æ¾ç¤ºæææ ¼å¼","simulation_ready":"仿ç就绪","software":{"meta":{"3d_models":"ä¸è½½%{rounded_count}个%{software}ç¨3D模åãå
è´¹ä¸ä»è´¹%{ext_file}æä»¶ï¼å¯ç´æ¥å¯¼å
¥ã"}},"sort_by":"æåºæ¹å¼","sort_by_options":{"best_match":"æä½³å¹é
","highest_price":"è¾é«çä»·æ ¼","lowest_price":"æ´ä½çä»·æ ¼","newest":"ææ°","oldest":"æèç","sales":"æç
é","trending":"è¶å¿"},"subcategory":{"meta":{"3d_models":"%{count} %{category}ç3D模åå¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D%{page}","3d_print_models":"ä¸è½½ %{count} %{category}3Dæå°æ¨¡åï¼å¯ä¾ä¸è½½çSTLï¼OBJçæ ¼å¼çæä»¶ï¼åå¤ä¸FDMï¼SLSç3Dæå°æºä¸æå°ã%{page}","animated_3d_models":"%{count} %{category}å¨ç»å¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D 3D模å%{page}","free_3d_models":"ä¸è½½ %{count} %{category}å
è´¹ç3D模åï¼å¨MAXï¼OBJï¼FBXï¼3DSï¼C4Dæä»¶æ ¼å¼æä¾ï¼åå¤VR / ARï¼å¨æ¼«ï¼æ¸¸æç3D项ç®ã%{page}","free_3d_print_models":"ä¸è½½ %{count} %{category}å
è´¹ç3Dæå°æ¨¡ååå¤FDMï¼SLAï¼SLSç3Dæå°æºï¼å¯ç¨çæ ¼å¼STLï¼OBJï¼3DMå¤ã%{page}","lowpoly_3d_models":"ä¸è½½VR / AR /ä½è%{tag}ç3D模ååå¤èæç°å®ï¼æ¸¸æåå
¶ä»å®æ¶åºç¨ç¨åºï¼æä¾FBXï¼OBJï¼MAXï¼3DSï¼C4Dæä»¶æ ¼å¼%{page}","rigged_3d_models":"%{count} %{category}æçºµå¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D 3D模å%{page}"}}
16518,"subtitle":{"aircraft":"%{count} ç®æºç3D模åå¯ä¾ä¸è½½æä»¬çå¸åºãCG %{airplanes_link} å°èå
¥æ¨¡æ,å¯è§å,广ååè§é¢ã%{drone_link} 车身åé¨ä»¶å°ä»¤ç»å°é£è½¦è¾ççè¿·ãå¹¶ä¸%{rigged_link}模ååå¤å°±ç»ª,è¦å¯¼å
¥å°æ¸¸æå¼æåç¨äºå¨ç»æVR / AR项ç®ãé£è¡æ¸¸æ,模æå¨å宿䏤ç§CGåä½èç±»åçå½±ç,å¯ä»¥å¨ææµè¡çæ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4Då
满3D模åã","animals":"CGä¸ç»´å¨ç© %{count} - %{cats_link} %{horses_link} %{bears_link} %{rhinos_link} %{eagles_link} %{lions_link},èæ %{dragons_link}çç - é½å¯ä»¥å¨è¿éä¸è½½ã 3Då¨ç©çéåå°æ»¡è¶³å¹¿åæéæåºæ¯çéæ±ãæä»¬ä¹æ%{rigged_link}æ¬¾çæ¸¸æ,å¨ç»,å½±è§å¶ä½åVR / AR项ç®ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½èæå¨å¤§å¤æ°è¡ä¸å
¬è®¤çæä»¶æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4D,åå
¶ä»äººæä¾å
è´¹ç3D模åã","animated":"ä¸è½½%{rounded_count}个带é¢ç½®å¨ç»ç3D模åï¼è§è²ãå¨ç©ä¸éå
·ï¼éç¨äºæ¸¸æãå½±è§ä¸å®æ¶é¡¹ç®ã","architectural":"å¯ä¾ä¸è½½å»ºçç3D模å %{count} 计æ°å
å«å
ç´ ä¸å»ºç,建çä¸å·¥ç¨è®¾è®¡çç»èãè´ä¹°æä¸è½½å
è´¹ç3D模å,æµè§ä¸è¿°çç±»å«ä¸ãæ¨å¯ä»¥ä½¿ç¨æ¨¡åå¨ç»ææ¸¸æ - å
¶ä¸ä¸äºæ¯æçºµåä½èæ
ä»»VR / AR项ç®çéè¦ã 3D模åæä»¶æ ¼å¼å¦FBX,OBJ,MAX,3DS,C4Då¯ç¨ã","car":"%{count} 个汽车3D模åå¯ä¾ä¸è½½ãå
¶ä¸ä½èççæ¬å°æ¯æ¸¸æè®¾è®¡è
æVR / ARåºç¨çå¼åè
,ä»äººçå¸å¼å - 以çµå½±å¶ä½,å¨ç»æå¹¿ååãä»ç»å
¸å¤è£è½¦å°èµè½¦åæ¦å¿µç人å¨çµå½±ä¸çå°ç,æåºæ¬ä¸ä»»ä½æ ¼å¼(FBX,OBJ,MAX,3DS,C4Dç),ä½ å¯è½éè¦ä¸ä¸ªä¼å¤§çåç§3D汽车模åã使ç¨å¨ç»åå
è´¹ç3D模å,ååå缩çå¼åæ¶é´ã","character":"%{count} 个å符ç3D模åå¯ä¾ä¸è½½,æä»¥è¿ä¸ç±»æµè§,ä½ ä¼åç°3D模å%{human_link},人ç©,ç¥è¯äººç©,ç§å¹»%{robots_link},æè£
åç¸å
³æåå
¶ä»çäºæ
ãä»%{heart_link}å%{hand_link}以ç»è´é¼ç%{male_link}æ%{female_link}车åãè®¸å¤æºåé½æçºµå¹¶å¯ä»¥å¾å®¹æå°æ·»å å°æ¨ç游æ,VR / AR项ç®,è§é¢æå¨ç»ãè¿ä¸¤ä¸ªé«èåä½å¤è¾¹å½¢æ¨¡åå¯ä»¥ä»¥å¤ç§æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4D被åç°ã","custom":"å¨è¿é,æ¨å¯ä»¥è´ä¹°æå
è´¹ä¸è½½%{tag}æ ç¾ç3D模åã %{tag_heading_subtitle}","electronics":"%{count} 个çµåå¯ä¾ä¸è½½ç3D模åãè¿æ¯å»ºçå¸,室å
设计å¸,å
³å¡è®¾è®¡å¸,ç°åºå¶å®è
åå
¶ä»å¹¿åç±»å«ã %ç3D模å%{smartphones_link},%{laptops_link},%{cameras_link},%{tvs_link},æ´æå©äºåç¡®å°ææç°ä»£çæ´»ä¸è®¾å¤åææ¯çç´è¿·ãææä»¶æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4Då¯ç¨ç3D模åãå
è´¹ä¸è½½æè´ä¹°é«æ¡£è½¦åå使ç¨å¨ç»,游æåVR / AR项ç®ã","exterior":"å¯ä»ç«é¢,åå¸å»ºç,æ¯è§å¯¹è±¡,ä½å®
产ä¸å»ºè®¾,åºç¡è®¾æ½å»ºè®¾ç建çç©å满éç¨%{city_link}模åä¸è½½èå´å»ºçå¤å¢3D模å %{count} 个ãè´ä¹°æä¸è½½å
è´¹ç3D模å,æµè§ä¸è¿°çç±»å«ä¸ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½å¤,å
è´¹ç3Dæ¨¡åææåºæ ¼å¼éè¦,å
æ¬FBX,OBJ,MAX,3DS,C4Dãæäºèµäº§æ¯ä½å¤è¾¹å½¢å¹¶ä¸å¯ä»¥å¸®å©ä½ å®æä½ çæ¸¸ææVR / ARåºç¨ç¨åºçç¯å¢ã","food":"%{count} 计æ°é£åç3D模åå¯ç¨äºdownload..Foodæä¾è¯å¥½æå¡,以æé å½å
çæ´»çé¼ççåºæ¯ã 3Dæ°´æ,è¬è,饮æåé¤ç¹é½å¨è¿éé¤é¦å®æ´ç广å,对äºå¥åº·ç饮é£ARåºç¨åå¯è§å建çå¸å室å
设计å¸çå·¥ä½ãæ è®ºæ¨æ¯å¨å¯»æ¾3D %{pizza_link}å%{ketchup_link}模åæçå©ç¤¼%{cake_link}3D模å,ä»ä»¬å¨è¿éãä¸äºä½å¤è¾¹å½¢ççæ¬æ¯ä¸ºé£äºå¨æ¸¸æä¸,VR / ARåå±ãä¸ç»´æ¨¡åå¯ä»¥å¨FBX,OBJ,MAX,3DS,C4Dæ ¼å¼è¢«åç°ã","formats":"ä¸è½½%{rounded_count}个%{format_upper}æ ¼å¼ç3D模åï¼å
è´¹ä¸ä»è´¹ãæ¬é¡µæææä»¶å为åç%{format_upper}ï¼æ é转æ¢ã","free_general":"ä¸è½½%{rounded_count}个å
è´¹3D模åï¼å
çç¨3Dç´ æï¼æ¯æFBXãOBJãBLENDåGLBæ ¼å¼ï¼éç¨äºä¸ªäººååä¸é¡¹ç®ã","free_no_tag":"%{model_count} å
è´¹ç3Dæ ç¾çæºååå¤ä¸ç»´æå°ãä¸è½½æ ç¾å
è´¹ç3Dæå°æ¨¡å,æä»¶æ ¼å¼æä¾,å
æ¬STL,OBJ,3DM,3DS,MAXã 3Dæ¨¡åæ¿ä¸FDM,SLA,SLSåå
¶ä»ç±»åç3Dæå°æºç使ç¨ã","free_printable":"å
è´¹ä¸è½½%{rounded_count}个3Dæå°æ¨¡åï¼ç¤¾åºéªè¯çå
è´¹STLæä»¶ââæåãæä»¶ãå®ç¨å°ç©çã","free_tag":"å
è´¹ç3D %{tag}æ ç¾çæºååå¤ä¸ç»´æå°ãä¸è½½ %{tag}æ ç¾å
è´¹ç3Dæå°æ¨¡å,æä»¶æ ¼å¼æä¾,å
æ¬STL,OBJ,3DM,3DS,MAXã 3Dæ¨¡åæ¿ä¸FDM,SLA,SLSåå
¶ä»ç±»åç3Dæå°æºç使ç¨ã","furniture":"å¯ä¾ä¸è½½ %{count} 计æ°å®¶å
·3D模åå
æ¬æ¡å,æ¤
å,æ²å,åºçå®¶å
·ä¸çåç§çº¹ç(æ¨æ,éå±ç)åæ ·å¼(%{retro_link},%{modern_link}ç)ãè¿ä¸ªç±»å«æ¯ä¸ºåä¸å»ºçå室å
设计,以å广ååå¨ç»å¶ä½äººã宿¶èµäº§å¯ä»¥å¸®å©æ¸¸æåVR / ARåºç¨å¼åå宿项ç®ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½èæå
è´¹ç3D模åãå¯å¨å
æ¬FBX,OBJ,MAX,3DS,C4Dä»»ä½æä»¶æ ¼å¼ã","general":"æµè§%{rounded_count}个ä¸ä¸3D模åï¼å
è´¹ä¸è½½æè´ä¹°ï¼éç¨äºæ¸¸æãå½±è§ãVFXãAR/VRä¸3Dæå°ãæ¯æFBXãOBJãBLENDãGLBç100å¤ç§æ ¼å¼ã","high_poly":"è´ä¹°æä¸è½½å¨ç»ä¸ä¸ç3D模ååå¤å¨CG项ç®,å½±è§å¶ä½,å¨ç»å¶ä½,å¯è§å,åå
¶ä»äººä½¿ç¨ãèµäº§å¯ä¾ä¸è½½å¨è®¸å¤è¡ä¸å
¬è®¤çæ ¼å¼,å
æ¬MAX,OBJ,FBX,3DS,UE4çãå¦æä½ å¨å¯»æ¾é«åè´¨çè3Dèµæºçæ¯,æä»¬æåç§éæ±çé¢å
çæ°åèºæ¯å¾ä¹¦é¦ã\n","household":"å¯ä¾ä¸è½½ %{count} 个家åº3D模åå¯ä»¥ç¨æ¥ç»ç»èçæ¿é´ãæ¨å¯è½å¸ææé¤å
·æ¾å¨æ¡åä¸,æè¡æ¤åçéè£
ç®±é½å
¨ç卿¿å
,ææ¾äº%{lights_link}å%{flowers_link}
16518åºè¾¹è¥é 豪åçæè§ãå¦æä½ æ¯ä¸ä½å®¤å
设计å¸,å¨ç»å¸,VR / ARåºç¨ç¨åºææ¸¸æçåé è
,è¿ä¸ªç±»å«æ¯ä¸ºæ¨ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½èæå
è´¹ç3D模åãå¯å¨å
æ¬FBX,OBJ,MAX,3DS,C4Dä»»ä½æä»¶æ ¼å¼ã","industrial":"%{count} 个工ä¸3D模åå¯ä¾ä¸è½½ - å»ºçææ,%{engineering_link}å·¥å
·,æºæ¢°å%{containers_link} - å°åæ¶æä¾è¯¦ç»ä¿¡æ¯åäºå¨,æçºµå
ç´ ,æé 活泼çç¯å¢ãè¿æ¯æ¨¡æ/ VR / ARæå¼å建设ä¸ç游æ%{construction_link}ç«ç¹çº§å«å®ç¾çç±»å«ã 3D模åå°æä¸ºä¸ä¸å»ºè®¾æä¸åç软件工ä½ä½ä¸ºæ ¼å¼å¦FBX,OBJ,MAX,3DS,C4D模åå¯ç²¾ç¡®çå¯è§åã","interior":"%{count} 个室å
3D模åå¯ä¾ä¸è½½,å
æ¬å»ºç,建çåå·¥ç¨,室å
设计使ç¨çå
ç´ åç»èãè´ä¹°æº¢ä»·æä¸è½½ä¸ä¸ªå
è´¹ç3D模å,æµè§ä¸é¢ååºçç±»å«ãæ¨å¯ä»¥ä½¿ç¨æ¨¡åå¨ç»ææ¸¸æ - å®ä»¬ä¸çä¸äºæçºµ,å¨ç»åä½èãå¯å¨å¤ç§æä»¶æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4Dã","low_poly":"ä¸è½½%{rounded_count}个ä½å¤è¾¹å½¢ï¼low polyï¼3D模åï¼è½»éãæ¸¸æå°±ç»ªï¼éç¨äºæ¸¸æãAR/VRåç§»å¨é¡¹ç®ã","military":"%{count} 个æ¦å¨,æ¦å¨,%{swords_link}åç«ç®ç°ä»£ååå²çåäº3D模åç±åéåèªå«ä½¿ç¨å¯ä¾ä¸è½½ãæ¨å¯ä»¥ä½¿ç¨åå·ä¸ºæ¸¸ææVR / ARå
容 - ä»ä»¬ä¸çä¸äºä¼å,å¹¶åå¤å°å
¶æ·»å å°æ¸¸æå¼æçå¤è¾¹å½¢ãæçºµåå¨ç»æ¨¡åå¯ä»¥è¿ä¸æ¥ç®åæ¨çå·¥ä½ãä½ ä¸å®ä¼æ¾å°ç¸å
³çèµäº§,å 为æä½ å¯è½éè¦(FBX,OBJ,MAX,3DS,C4Dç)çä»»ä½æä»¶æ ¼å¼æä¾ç3D模åã","not_custom":"ä¸è½½%{rounded_count}个%{tag_cap}3D模åï¼å
è´¹ä¸ä»è´¹ãåå®ä¸é£æ ¼åï¼æ¯æFBXãOBJãBLENDåGLBæ ¼å¼ã","optimized":"å
¶ä¸æè¾å°çå¤è¾¹å½¢æ¨¡åæ¯æå¥½ç,éè¦å¿«éå¤ç,å¦èæç°å®(VR),å¢å¼ºç°å®(AR),æ··åç°å®(MR),交åç°å®(XR)忏¸æ,å°¤å
¶æ¯ææºæ¸¸æç宿¶åºç¨ã仿们æçºµåå¨ç»æ¨¡åçéå,è½»æ¾å°å¨å®æ¶åºç¨ç¨åºä¸ä½¿ç¨å®ä»¬ãè·åä¸ç»´èµäº§ç¯å¢,æéå
·,ç©åæè
è´ä¹°å®æ´çä¸ç»´æ¨¡åéå,æåå
çä¸åä½ çæ¸¸æå¯è½éè¦ãèçå¼åæ¶é´åææ¬,å¶å®ååç»éªæä½¿ç¨3D模åä½ä¸ºæ¨ç项ç®å ä½ç¬¦ãåºäºç©ççæ¸²æ,æè
PBR,表示å
¶åç¡®ä¸è´å°åç°å¨ä»»ä½ç
§ææ¡ä»¶ä¸,ç±äºçº¹çåçæ¨¡å工使µå¨å建è¿ç¨ä¸ä½¿ç¨ã\n","pbr":"ä¸è½½%{rounded_count}个带PBRï¼åºäºç©ç渲æï¼è´´å¾ç3D模åï¼å¨ä»»ä½å
ç
§ä¸é½çå®ä¸è´çæè´¨ï¼éç¨äºUnityãUnrealç弿ã","plant":"å¯ä¾ä¸è½½%{计æ°}å·¥åç3D模åå
嫿é¿ä¸ºå½å
æ¤ç©åèªç¶æ¤ç©ææºä½,å¦è±å,%{trees_link},è,æç¼æ¤ç©,绿å,èæ¬,å¤å¹´çæ¤ç©,è,è½,çæ¨,å,è±è½,è¤è,æèãè´ä¹°æº¢ä»·æä¸è½½ä¸ä¸ªå
è´¹ç3D模å,æµè§çç±»å«ä¸é¢æ¾å°å¯ç¨ç模åä¹é´çæä½³å¹é
ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½è(ç¨äºæ¸¸æåVR / ARåºç¨ç¨åº)模å¼,æè¿æ»¤ææéçæ ¼å¼(å¨FBX,OBJ,MAX,3DS,C4D模ååæ´å¤å¯ç¨)ã","printable":"ä¸è½½%{rounded_count}个3Dæå°æ¨¡åï¼ç»ç¤¾åºæµè¯çå
è´¹ä¸ä»è´¹STLæä»¶ï¼éç¨äºFDMåå
åºåæå°æºãæåãæ¨¡åãå®ç¨ä»¶ä¸é¶ä»¶ã","printable_merged_tag":"ä¸è½½%{rounded_count}个%{tag_cap}3Dæå°æ¨¡åï¼å
è´¹ä¸ä»è´¹STLæä»¶ï¼FDMä¸å
åºåæå°æºåéç¨ã","printable_tag":"ä¸è½½%{rounded_count}个%{tag_cap}3Dæå°æ¨¡åï¼å
è´¹ä¸ä»è´¹STLæä»¶ï¼FDMä¸å
åºåæå°æºåéç¨ã","rigged":"ä¸è½½%{rounded_count}个riggedï¼å·²ç»å®éª¨éª¼ï¼3D模åï¼è§è²ãå¨ç©ä¸çç©ï¼éæ¶å¯å¶ä½å¨ç»ãæ¯æBlenderãMayaã3ds MaxãUnityåUnrealã","scanned":"%{count} ä¸ªæ«æ3D模åå¯ç¨äºè´ä¹°æå
è´¹ä¸è½½ã 3Dæ«ææ¨¡ååå¤å°±ç»ª,å¨ç»,游æåVR / AR项ç®ãä½ å¯ä»¥æ¾å°ç3D模å,å¦å²©ç³åèªç¶è¡¨é¢,人类åå
¶ä»å¨è¿éç°å®çæ´»ä¸ç©ä½å¨èªç¶çä¸åç°ç对象...å®ä¸è½å¾å°ä»»ä½æ¯è¿æ´ååå®é
ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½èæå
è´¹ç3D模åãå¯å¨å
æ¬FBX,OBJ,MAX,3DS,C4Dä»»ä½æä»¶æ ¼å¼ã","science":"%{count} 个ç§å¦å¯ä¾ä¸è½½,ä»å»å¦,çç©å¦,ç©çå¦,åå¦é¢ååå
¶ä»ç°å®ä¸çä¸è¿ä¸ç±»èå´å
ç3D模å对象ç¸å
³ç§æï¼å®éªå®¤è®¾å¤,æ¾å¾®ç»ç»åäºååä¸çãä¸è¦åè§æ,%{cell_link},%{skull_link} å %{skeleton_link} 3D模åå¯ä»¥å¨è¿éæ¾å°ï¼è´ä¹°æä¸è½½å
è´¹ç3Dèµäº§,æµè§ä¸è¿°çç±»å«ä¸ãæ¨å¯ä»¥ä½¿ç¨å¨ç»æå°èç人æçºµç模å为游æåVR / AR项ç®ãå
è´¹åä»è´¹ç3D模åå¯ä»¥å¨è®¸å¤æä»¶æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4D被åç°ã","scripts_plugins":"%{count} 个3Dèæ¬/æä»¶å¯ä¾ä¸è½½ã 3Dèæ¬/æä»¶å¯ä»¥æ·»å å°åç§è½¯ä»¶åç¨äºæ´ææå°ä½¿ä½ ç工使µæ°´çº¿ãéè¿æ ¼å¼è¿æ»¤å¨æ¥æ¥æ¾å·¥å
·é
ä»¶æ¨é¦éç软件ã\n","software_page":"ä¸è½½%{rounded_count}个%{software}
16518ç¨3D模åï¼åç%{ext_file}æä»¶å¯ç´æ¥æå¼ï¼å
¶ä»æ ¼å¼ä¹å¯è½»æ¾å¯¼å
¥ã","space":"%{count} 个空é´ç3D模åå¯ä¾ä¸è½½çCGTraderãç©ºé´æ¯ä¸ä¸ªå®æ´çä½è,ç§å¹»%{spaceships_link}游æåå¤ç车åç±»å«ã乿%{asteroids_link},è¡æ(å
æ¬æçåç«æ,ä»¥æ¨¡ææ®æ°å)åç°å®ç©ºé´%{shuttles_link}为æ´ç§å¦å°å¾æã该车åç»å¯¹å¯ä»¥å¨VRç©ºé´æ¨¡æå¨æ¸¸æ,ARåºç¨ç¨åºåå¨ç»æ¥æ¼ç¤ºè¿ä¸ªæç%{earth_link}以å¤çä¸çãè¿æ»¤å¨å¨è¿éä½ ä¼åç°æçºµ,å¨ç»,ä½å¤è¾¹å½¢èµäº§ææ¨¡åç¹å®æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4D帮å©ã","sports":"%{count} ç®è¿å¨ç3D模åå¯åµå¥å¨ä¸èµ·çè®¾å¤æ¯ç¨äºä¼é²æ´»å¨,娱ä¹,è¿å¨,ä¼é²,æå¿«çæ¶é£,ä¹è¶£ä»¥å游æ,å¿ç«¥ç©å
·åå
¨æ¹ä½çä¹å¨ãè´ä¹°æä¸è½½æéçä»»ä½æä»¶æ ¼å¼,å
æ¬FBX,OBJ,MAX,3DS,C4Dä¸ä¸ªå
è´¹ç3D模å,æµè§ä¸è¿°çç±»å«ä¸ãæ¨å¯ä»¥ä½¿ç¨æ¨¡åå¨ç»,游æ,VR / ARé¡¹ç® - ä»ä»¬å¾å¤é½æ¯ä¸æ¼å
«å,ä½èæå·²å¨ç»ã","test":{"airplane":"èªç©ºç±å¥½è
,å¬å¥½äº,å®ä»æ¥æ²¡æé£ä¹å®¹æå¾å°å®ç¾ç3Dæå°é£æºæ¨¡å为æ¨çæ£çæ¸¸æææ¨¡åéåãæç´¢%{model_count} 3Dæå°é£æºæ¨¡å,æ¾å°ä½ åªéè¦æä¸ä¸ªè´§æ¶ä¸ç模åãåç°çæ£ç飿ºæ¨¡åææé çãæç´¢ææ°è®¾è®¡ä»ä¹ææ¯æéè¦ç,ä»è±ç¹å
å¼çæ¶åè½åæ¥ãå®ä¹æ¯è°ç梦æ³,å½ä»é¿å¤§åæä¸ºä¸åé£è¡åçä»»ä½å©åä¸ä¸ªå®ç¾ç礼ç©ãè´ä¹°åä¸è½½ç3Dæå°æ¨¡å,èªè¡æå°ææäº¤æ¨¡å,以æä»¬ç3Dæå°æå¡æä¾åä¹ä¸,æå®æå°å¹¶è¿å°ä½ å¨ä»»ä½æ¶é´ï¼\n","anatomy":"%{model_count} 3Dè§£åæ¨¡åå¯ä¾ä¸è½½æä»¬çå¸åºãæ¢ç´¢å
·æè¾é«ç人ä½è§£å - è骨骼,èè,å¨å®æ¨¡åãéåä»»ä½æè²æç§å¦é¡¹ç®ã使ç¨å¯æå°ä¸ç»´æ¨¡å,以æé«æè²çç»éªãå建令人æå¹çå¨ç»åè§é¢æ¸¸æä¸æä»¬\n æçºµæ¨¡åç大éè书ãä½¿ç¨æä»¬å
è¿çè¿æ»¤ç³»ç»,å¯ä»¥è½»æ¾æ¾å°ä½è,å¨ç»,PBR,\n åæçºµç模åæä»»ä½é忍çéæ±æå¥½çãéæ©çæä»¶æ ¼å¼å¾å¤§,å
æ¬\n ææµè¡çåFBX,OBJ,MAX,3DS,C4Dã\n","castle":"å°å·åå ¡ä½ èªå·±çæäºº3Dæ¯ä¸ä¸ªç¹å»å³å¯ï¼æç´¢åç§3D模ååå ¡åå¤å¥½3Dæå°ã为æ¨çdï¼dä¼è¯æä»»ä½å
¶ä»ä¸ä¸çºªRPGæ¡é¢æ¸¸æç¬ç¹ç梦幻åå ¡ãè¿äºä¸ä¸çºªçå ¡åæ¯ä»»ä½æ£ç游æç±å¥½è
æè
ä¸ä¸ªä¼å¤§çé¤äºèªå·±çæ¶èä¸ä¸ªæäººç礼ç©ãæ¥æ¾ç»ç»ç±å¥½è
æå©å们çè¿ç§ç©å
·çä¸ä¸ªå®ç¾ç3D模åã订è´åä¸è½½ä½ æéæ©ç3Dåå ¡è®¾è®¡é£æ ¼,ç¨èªå·±çæå°æºæå°åºæ¥,ææäº¤æ¨¡å,以æä»¬ç3Dæå°æå¡æä¾åä¹ä¸,æå®çå°å·åè£
è¿ã\n","dice":"è¿æ°ä¸ä¼ç¨å®ç¨3Dæå°éª°åï¼å¦æä½ æ³ä¸ºä½ çæ£çæ¸¸æå¤æçå®ç游æéª°å,ççæ²¡äºãå¨è¿é,æ¨å¯ä»¥ %{model_count} å
è´¹ç3D模å骰ååå¤3Dæå°ä¹é´è¿è¡éæ©ã彿¯èµç»ææ¶,å°è¿äºç¾ä¸½ç模ç¹ä½ä¸ºéä»¶ãå
è´¹ä¸è½½ç3Dæå°æ¨¡å骰å,æä»¶æ ¼å¼æä¾,å
æ¬STL,OBJ,3DM,3DS,MAXãæä»¬ç3Dæ¨¡åæ¿ä¸FDM,SLA,SLSåå
¶ä»ç±»åç3Dæå°æºç使ç¨ãä½¿ä½ çæ¸¸ææ´æè¶£,è®©ä½ ç3Dæå°ç骰åï¼\n","drone":"3Dæå°,并建ç«èªå·±çæ äººæºææ¾å°é¶ä»¶è¿è¡æ´æ¢ã 3Då°å·æ äººé©¾é©¶é£æºå¾å®¹æè¿«éåç»è£
åç»´ä¿®ãåç°ä¸æå°çæ¹å¨å®ç¾çæåæºå®è£
ä½ç½®æè¦æ±ç模åãå®ç¾ç好ç©çä¼é²æ´»å¨,èªææå½±,å½åææ å°ãæ¥æ¾å¹¶è´ä¹°ä¸ä¸ªè®¾è®¡ç¬ç¹ç3D模å,æ äººé©¾é©¶é£æºéåæ¨çææéæ±ãèªè¡æå°ææäº¤æ¨¡åç»æä»¬çä¸ç»´æå°æå¡æä¾åä¹ä¸,æå®æå°å¹¶è¿å°ä½ å¨ä»»ä½æ¶é´ï¼è·åèªå·±ç3Dæå°æ 人æºå漫游广æ³çè天ï¼\n","pokemon":"ç®å¡ä¸,æéæ©äºä½ ï¼éæ©ä»å£è¢å¦æªåå¤3Dæå°çè´è·ã大æ©å±æ¨ç3Dæå°çç¥å¥å®è´æ¶èãæç´¢å卿好ç,æè¯¦ç»çå® ç©å°ç²¾çµè®¾è®¡ç»åä½ çä¸ä¸ä¸ªæ¡é¢æ¸¸æçæåã订è´åä¸è½½ä½ ç3Då® ç©å°ç²¾çµ,ç¨èªå·±çä¸ç»´æå°æºæå°åºæ¥,ææäº¤æ¨¡å,以æä»¬ç3Dæå°æå¡æä¾åä¹ä¸,æå®çå°å·åè£
è¿ãæ¯ç«,è¿æ¯æé
·çäºæ
3Dæå°ä¸ä¸ªï¼\n","ring":"3Dæå°ç 宿¯å¨åè¡ä¸ä¸æ°çé»è²,å 为æ¯3Dæå°çææï¼æå¯» %{model_count} å
è´¹ç3Dæå°æ¨¡åç¯ç巨大æ°é¢ãéè¿ç¬ç¹ç设计æµè§,æ¾å°åæä¸ºä½ åä»ä¹ãæ æ³æ¾å°å¨åºéèªå·±åä»»ä½äºæè
,ä¹è®¸ä½ æ³è¦ä¸ä¸ªéä»¶é
·ä¼¼ä¸ä¸ªä½ æå欢ççµå½±è§è²äºï¼éæ©çæä»¶æ ¼å¼å¾å¤§,å
æ¬STL,OBJ,3DM,3DS,MAXã 3Dæ¨¡åæ¿ä¸FDM,SLA,SLSåå
¶ä»ç±»åç3Dæå°æºç使ç¨,éè¿æä»¬çéæ©,以便æµè§åå°è¯æ°çæåæ¬¢çææã\n","shoes":"大åçæ¿è½½ç3Dæå°çéå,ç°å¨ä½ å¯ä»¥å享ç»éª,以åãæµè§å¹¶æ¾å°å
è´¹æå°éç设计 - ä»è¿å¨éå°é«è·éçæ¶å°ä¹æå¾å¤ç°æçæå°æ¨¡å¼,å¨çå¾
çä½ å»å°è¯å®ä»¬ãéè¿éæ©ææ,è°æ´æè½¯æ§åå°ºå¯¸ä½¿ç»æå®ç¾ãéæ©ä»146å
è´¹3Dé´æ¬¾åä¸è½½ä»ä»¬å¨å¯ç¨çæä»¶æ ¼å¼,å
æ¬STL,OBJ,3DM,3DS,MAXã设计æ¿ä¸FDM,SLA,SLSåå
¶ä»ç±»åç3Dæå°æºç使ç¨ã让æ¨ç3Dæå°çéåå§ï¼\n","textures":"ä¸æç´¢%äºå¤§é %{model_count} CG纹çå¯ä¾ä¸è½½,å
æ¬ç²¾ç¾çå¶ä½ææãæµè§ç±»å«,å¹¶æ¾å°æ ç¼ç»ç©,æ¨æ,éå±,塿,ç çº¹çæ¥å¸®å©å®ææ¨çé¡¹ç®æ´å¿«ãä½¿ç¨æä»¬çé«çº§æç´¢æ¾å°æ¸¸ææè§é¢åä½ä½å¼çåå¨ç»çº¹çãæä»¬çææå¯ä¾ä¸è½½çåç§æ ¼å¼,å
æ¬TGA,SBSAR,JPG,PNG,TIFFåå
¶ä»äºº,æä»¥ä¸è¦æµªè´¹æ¶é´,æ¾å°åå¤ä½¿ç¨çCGè´´å¾å 乿æé¡¹ç®å¯æ³èç¥ã\n"},"various":"%{count} 个ä¸åç3D模åä¸å®¹ææ¾å°èªå·±çä½ç½®å¨å
¶ä»ç±»å«å¯ä¾ä¸è½½ã %{rocks_link},%{clouds_link},%{logos_link},%{cigarette_link}åå
¶ä»éåç±»ç3D模å,ä½ å¯è½éè¦å®æä½ çæ¸¸æ,å¨ç»æVR / AR项ç®é½å¨è¿éã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½èæå
è´¹ç3D模å,æå¯ç¨çæ ¼å¼å¦FBX,OBJ,MAX,3DS,C4Dçæ¸
ã","vehicle":"å¯ä¾ä¸è½½ %{count} 车è¾3D模åå
æ¬å¡è½¦,%{ambulances_link},å
Œ
±æ±½è½¦%{bikes_link}åæ©æ - è¿ä¸ªç±»å«æ¯ä¸ºè°å¸æèªå·±çåå¸è¡éå
æ»¡è½¦è¾æ¯å¦ç°å®æç§å¹»ç人ãé£äºå¶ä½æ¨¡ææ¸¸ææVR / ARåºç¨,åæçè§é¢å¶ä½,çè³æµ·æ¥è®¾è®¡å¾å¯è½ä¼åç°ææµè¡çæä»¶æ ¼å¼,å¦FBX,OBJ,MAX,3DS,C4D使ç¨ãå
¶ä»éå°äº¤éå·¥å
·åç«è½¦æ%{tractor_link} 3D模åä¹å¯ä»¥è¿ä¸ªåºå¤§éå䏿¾å°ã使ç¨è¿æ»¤å¨æ¥æ¾æçºµ,å¨ç»,ä½èæå
è´¹ç3Dæ¨¡åæ´å¿«ã","watercraft":"%{count} 个è¹è¶å¯ä¾ä¸è½½ç3D模åå
å«%{boats_link},%{yachts_link},%{ships_link}ååç§å
¶ä»æ°´ä¸è¡é©¶è½¦è¾ãçè£
ä½å¤è¾¹å½¢ç模åå°å¨è§é¢æ¸¸æ,VR / AR项ç®ä»¥åå¨ç»åçå¾å¥½,èCG模åå¨è¿é为æ¨çåºæ¯åå
¶ä»åºç¨ä¸çè§è§ä¿çåº¦æ¯æ´éè¦ãæ¨¡åæ¯å
æ
16518¬ä»»ä½æä»¶æ ¼å¼æä¾,å
æ¬ä½ä¸éäºFBX,OBJ,MAX,3DS,C4Dã"},"tag":{"meta":{"3d_merged_premium":"ä¸è½½%{rounded_count}个%{tag_cap}3D模åï¼å
è´¹ä¸ä»è´¹ãæ¯æFBXãOBJãBLENDãGLBæ ¼å¼ï¼éç¨äºæ¸¸æãå½±è§ãAR/VRå3Dæå°ã","3d_merged_premium_print":"ä¸è½½%{rounded_count}个%{tag_cap}3Dæå°æ¨¡åãå
è´¹ä¸ä»è´¹STLæä»¶ï¼éç¨äºFDMåå
åºåæå°æºã","3d_models":"ä¸è½½%{rounded_count}个%{tag_cap}3D模åï¼å
è´¹ä¸ä»è´¹ãæ¯æFBXãOBJãBLENDãGLBæ ¼å¼ï¼éç¨äºæ¸¸æãå½±è§ãAR/VRå3Dæå°ã","3d_print_models":"ä¸è½½%{rounded_count}个%{tag_cap}3Dæå°æ¨¡åãå
è´¹ä¸ä»è´¹STLæä»¶ï¼éç¨äºFDMåå
åºåæå°æºã","animated_3d_models":" %{count} %{tag}å¨ç»å¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D 3D模å%{page}","free_3d_models":"ä¸è½½ %{count} %{tag}å
è´¹ç3D模åï¼å¨MAXï¼OBJï¼FBXï¼3DSï¼C4Dæä»¶æ ¼å¼æä¾ï¼åå¤VR / ARï¼å¨æ¼«ï¼æ¸¸æç3D项ç®ã%{page}","free_3d_print_models":"ä¸è½½ %{count} %{tag}å
è´¹ç3Dæå°æ¨¡ååå¤FDMï¼SLAï¼SLSç3Dæå°æºï¼å¯ç¨çæ ¼å¼STLï¼OBJï¼3DMå¤ã%{page}","lowpoly_3d_models":"ä¸è½½ %{count} VR / AR /ä½å¤è¾¹å½¢%{tag}ç3D模ååå¤èæç°å®ï¼æ¸¸æåå
¶ä»å®æ¶åºç¨ç¨åºï¼æä¾FBXï¼OBJï¼MAXï¼3DSï¼C4Dæä»¶æ ¼å¼%{page}","rigged_3d_models":"%{count} %{tag}çæçºµå¯ä¾ä¸è½½çä»»ä½æä»¶æ ¼å¼ï¼å
æ¬FBXï¼OBJï¼MAXï¼3DSï¼C4D 3D模å%{page}"}},"title":{"download":"|ä¸è½½","files":"3Dæä»¶","formats":"%{format_upper} 3D模å","free":"å
è´¹3D模å","free_printing":"å
è´¹3Dæå°æ¨¡å","free_tag":"å
è´¹ %{selected_tag} 3D模å","general":"è´ä¹°ä¸ä¸3D模å","high_poly":"%{selected_filter} 3D 模å","landing":{"animated_3d_models":"å¨ç»3D模å","lowpoly_3d_models":"ä½å¤è¾¹å½¢3D模å","pbr_3d_models":"PBR 3D模å","rigged_3d_models":"ç»å®éª¨éª¼3D模å"},"low_poly":"%{selected_filter} 3D 模å","newest_cg":"æ°çåææ°ç3D模å","newest_print":"æ°çåææ°ç3Dæå°æ¨¡å","page_prefix":"page %{page_number}","pbr":"åºäºç©ççæ¸²æ 3D 模å","printing":"3Dæå°æ¨¡å â STLæä»¶","sales_cg":"æç
éç3D模å","sales_print":"æç
éç3Dæå°æ¨¡å","software_page":"%{software} 3D模å","tag_heading":{"cg":"å
è´¹%{tag} 3D æå°æ¨¡å","filter":"%{selected_filter}%{tag} ç 3D 模å","general":"%{tag_cap}3D模å","merged_premium_print_tag":"%{tag_cap}3Dæå°æ¨¡å","merged_premium_tag":"%{tag_cap}3D模å","printable":"%{tag_cap}3Dæå°æ¨¡å"},"trending_cg":"è¶å¿3D模å","trending_print":"è¶å¿3Dæå°æ¨¡å"}},"cart":{"request_invoice_failed":"ååï¼åºéäºã","request_invoice_successful":"å票请æ±å·²æååéã","shareable_cart_created":"è´ç©è½¦å·²æåå享ã","shareable_cart_failed":"ååï¼åºéäºã","subscription_covered_items_removed":"å·²ä»è´ç©è½¦ä¸ç§»é¤ï¼%{titles}ãå·²å
å«å¨æ¨ç订é
ä¸ã","subscription_covered_order_refused":"æ¨ç订é
ç°å·²å
å« %{titles}ï¼å æ¤æä»¬æªåæ¨æ¶è´¹ã请éè¿è®¢é
ä¸è½½ã"},"categories":{"cg":{"header_title_html":"è´ä¹°ä¸ä¸3D模å","text":"æ¾å°å®å
¨ç¬¦åæ¨éæ±ç3Då
容ï¼å
æ¬AR/VRãæ¸¸æã广åã娱ä¹ç\n"},"head-title":{"cg":"3D模å â å
è´¹ä¸è½½ä¸è´ä¹°","cg-models":{"sort-by":{"newest":"ææ°3D模å","top-selling":"æç
é3D模å","trending":"çé¨3D模å"}},"print":"3Dæå°æ¨¡å â STLæä»¶ä¸è½½","print-models":{"sort-by":{"newest":"ææ°3Dæå°æ¨¡å","top-selling":"æç
é3Dæå°æ¨¡å","trending":"æçé¨3Dæå°é¡¹ç®"}},"product-type":{"plural":{"capital":{"cg":"3D模å","cg-merge-premium":"3D 模å â å
è´¹åä»è´¹ä¸è½½","print":"3Dæå°æä»¶å模å","print-merge-premium":"%{tag} 3D æå°æä»¶ - å
è´¹åé«çº§ STL 模å"},"lower":{"cg":"3D模å","print":"3Dæå°æä»¶å模å"}},"singular":{"capital":{"cg":"ä¸ç»´æ¨¡å","print":"3Dæå°æ¨¡å"},"lower":{"cg":"3D模å","print":"3Dæå°æ¨¡å"}}}},"index":{"browse_all":"æµè§æææ¨¡å","info-section__description_1_html":"è´ä¹°æå
è´¹ä¸è½½ä¸ä¸3D模åï¼å¯ç«å³ç¨äºCG项ç®ãå½±è§å¶ä½ãå¨ç»ãå¯è§åãæ¸¸æãVR/ARçãèµæºæä¾å¤ç§\u003ca href='https://www.cgtrader.com/blog/3d-file-formats' target='_blank' rel='noopener noreferrer'\u003eè¡ä¸è®¤å¯çæ ¼å¼\u003c/a\u003eï¼å
æ¬MAXãOBJãFBXã3DSãSTLãC4Dã
16518BLENDãMAãMBçã妿æ¨å¨å¯»æ¾é«å¤è¾¹å½¢æå®æ¶3Dèµæºï¼æä»¬æ¥æé¢å
çæ°åèºæ¯åºæ¥æ»¡è¶³æ¨çææéæ±ã\n","info-section__description_1_printable_html":"ä¸ä¸ç3Dæä»¶ãæå°ä»¶å模åï¼éç¨äºä½¿ç¨æ¡é¢FDMæå·¥ä¸çº§SLS 3Dæå°æºå¨å®¶ä¸æå°ï¼æ¯æå¤ç§è¡ä¸æ ¼å¼ï¼å
æ¬OBJã\u003ca href=\"https://www.cgtrader.com/3d-print-models/stl-files\"\u003eSTL\u003c/a\u003eãWRLãå¦ææ¨æ¯3Dæå°ç±å¥½è
ãå客ãæè²å·¥ä½è
æéè¿3Dæå°è¿è¡ååå¶ä½çä¼ä¸ï¼æä»¬çå®¶å±
è£
é¥°ãæ¶å°å°å·¥å
·é
ä»¶ãå¼äººæ³¨ç®çæ¶å°ååãç¬ç¹çç å®ãæºæ¢°é¨ä»¶ä»¥ååç§å¾®å模åï¼ä¸å®ä¼ç»æ¨å¸¦æ¥çµæã","info-section__heading_1_html":"æ¢ç´¢3D模å\u003cstrong\u003eç±»å«\u003c/strong\u003e","info-section__heading_1_printable_html":"æ¢ç´¢3Dæå°æ¨¡åç\u003cstrong\u003eç±»å«\u003c/strong\u003e","info-section__heading_2_html":"3D模å\u003cstrong\u003eå¸åº\u003c/strong\u003e","info-section__heading_2_printable_html":"è¿æ\u003cstrong\u003eä»ä¹ï¼\u003c/strong\u003e"},"marketplace":{"3d-printing":{"link_text":"æµè§3Dæå°æ¨¡å","text":"æ¥æ¾éç¨äºæ¨ç3Dæå°æºç3D模åã","title":"3Dæå°æ¨¡å"},"blender_text":"åç°æ°å个å¯ç¨äºblendæ ¼å¼çBlender 3D模åã","browse":"æµè§","cinema-4d_text":"åç°æ°å个é«è´¨éCinema 4D模åï¼å¯ç¨äºc4dæä»¶æ ¼å¼ã","discounted":{"link_text":"æµè§è´´ç°3D模å","text":"è´ä¹°ä¸ä¸ç3Dæ¨¡åææã","title":"ç¹ä»·3D模å"},"low-poly":{"link_text":"æµè§ä½å¤è¾¹å½¢3D模å","text":"ä½å¤è¾¹å½¢3D模åï¼éç¨äºè§é¢æ¸¸æãVRåAR宿¶åºç¨ã","title":"ä½å¤è¾¹å½¢3D模å"}
16518,"pbr":{"link_text":"æµè§PBR 3D模å","text":"åºäºç©ç渲æç3D模åã","title":"PBR 3D模å"},"scripts_apps":{"link_text":"æµè§å
¨é¨","text":"3Dèæ¬åæä»¶ï¼è®©æ¨ç3D建模æµç¨æ´é«æã","title":"èæ¬ä¸åºç¨"},"sketchup_text":"æµè§å¤§éSketchup 3D模åï¼éç¨äºå»ºçã室å
åè§é¢æ¸¸æè®¾è®¡ã","textures":{"link_text":"æµè§çº¹ç","text":"å³ç¨å纹çï¼å¸®æ¨èçåå¤3D模åçæ¶é´ã","title":"纹ç"},"zbrush_text":"æ¥æ¾ZTLæä»¶æ ¼å¼ç3Dèµæºï¼ç¨äºæ°åéå»ã3D建模ãè´´å¾åç»ç»é¡¹ç®ã"},"meta-description":{"cg":"ä¸è½½æè´ä¹°%{rounded_count}个ä¸ä¸3D模åãå
è´¹ä¸ä»è´¹3D模åï¼éç¨äºæ¸¸æãå½±è§ãVFXãAR/VRå3Dæå°ãæ¯æFBXãOBJãBLENDãGLBæ ¼å¼ã","print":"ä¸è½½%{rounded_count}个3Dæå°æ¨¡åãå
è´¹ä¸ä»è´¹STLæä»¶ï¼æåãæ¨¡åãå®ç¨ä»¶çã"},"more":{"designers":{"link_text":"æµè§3D设计å¸å表","text":"æµè§æ°å个3D设计å¸ä½åéï¼æ¾å°å®å
¨ç¬¦åæ¨éæ±çå
容ã","title":"å¯»æ¾æä½³3D设计å¸"},"projects":{"link_text":"äºè§£æ´å¤å
³äº3D项ç®","text":"éä½£ä¼è´¨3Dèªç±èºæ¯å®¶ï¼è§£å³æ¨ææçå®å¶å»ºæ¨¡ææã","title":"CGTrader 3D项ç®"},"visualization":{"link_text":"äºè§£æ´å¤","text":"å°æ¨ç产å转æ¢ä¸ºç
§ç级é¼çç3D模åï¼ç¨äºçµååå
¶ä»ä¸å¡åºç¨ã","title":"çµå3Då¯è§å"}},"navbar":{"aircraft":"飿º","animal":"å¨ç©","animals":"å¨ç©","architectural":"建çç","art":"èºæ¯","car":"汽车","character":"å符","exterior":"å¤è§","fashion":"æ¶å°","food":"é¤é¥®","furniture":"å®¶å
·","gadgets":"å°å·¥å
·","games-toys":"游æåç©å
·","hobby-diy":"å好DIY","house":"æ¿å±","household":"å®¶åº","industrial":"产ä¸","interior":"室å
","jewelry":"é¦é¥°","military":"åäº","miniatures":"è¢ç","plant":"å","science":"ç§å¦","space":"空é´","vehicle":"车è¾","watercraft":"è¹è¶"},"print_models":{"hero_title_html":"3Dæå°æ¨¡å â STLæä»¶","subtitle":"æ¾å°å®å
¨ç¬¦åæ¨éæ±ç3Dæå°å
容","title_html":"è´ä¹°ä¸ä¸ç\u003cstrong\u003e3Dæå°æ¨¡å\u003c/strong\u003e"},"profile":{"collection":"3Dèµæºå
","free":"å
è´¹ç3D模å","high_poly":"é«å¤è¾¹å½¢3D模å","optimized":"ä½å¤è¾¹å½¢/ Pbr 3D模å","printable":"3Dæå°æ¨¡å"},"seo":{"cg":{"aircraft":"è¯¥ç±»å«æ¶µç3D飿ºãCG飿ºéç¨äºæ¨¡æãå¯è§åã广ååè§é¢ãæ äººæºæºèº«åé¶ä»¶å°è®©å°åé£è¡å¨ç±å¥½è
满æãç»å®æ¨¡åå¯ç´æ¥å¯¼å
¥æ¸¸æå¼æã\n","animals":"æ¤å¤å¯æ¾å°3Då¨ç©åéââç«ã马ãçãççãé¹°ãç®åçãCGå¨ç©å¯æ»¡è¶³å¹¿åæéæåºæ¯çéæ±ã
16518æä»¬ä¹æç¨äºæ¸¸æçç»å®å¨ç©æ¨¡åã\n","architectural":"楼梯ãå£çã3D模å以åè£
饰åï¼å¦ç»æ¡ãæå¤´æç¯å
·ï¼å¯å¨åºå¤§ç建çç»è模ååºä¸æ¾å°ãå¯å©ç¨å®¤å
å¤æå»ºæ°å卿¿ãå§å®¤ãåå ¡æ¿é´æå°ç¢ï¼æ è®ºæ¨æ¯å»ºçå¸ãå·¥ç¨å¸è¿æ¯ç¬ç«æ¸¸æå¼åè
ã\n","car":"汽车类å«å
å«3D汽车模åï¼å
¶ä¸ä½å¤è¾¹å½¢çæ¬å¸å¼æ¸¸æè®¾è®¡å¸ï¼å
¶ä½åé忳影åå¶ä½äººæå¹¿ååãä»ç»å
¸æ±½è½¦å°èµè½¦ãæ¦å¿µè½¦ï¼åç±»3D汽车模ååºæå°½æã\n","character":"卿¤ç±»å«ä¸ï¼æ¨å°æ¾å°äººç±»ã人ç©ãç§å¹»ãæè£
ç3D模åãä»å¿èåæå°è¯¦ç»é¼ççç·å¥³æ¨¡åãè®¸å¤æ¨¡åå·²ç»å®ï¼å¯è½»æ¾æ·»å å°æ¨ç游ææå¨ç»ä¸ã\n","electronics":"çµåæ¯å»ºçå¸,室å
设计å¸,å
³å¡è®¾è®¡å¸,ç°åºå¶å®è
åå
¶ä»å¹¿åç±»å«ã { \"slug\": \"ç¬è®°æ¬çµè\", \"title\": \"ç¬è®°æ¬çµè\"},{ \"slug\": \"ç¸æº\",\"title\": \"æºè½ææº\"}, {\"slug\": \"æºè½ææº\", \"title\":\"ç¸æº\"},{\"slug\":\"TV\",\"title\":\"çµè§\"},æ´æå©äºåç¡®å°ææç°ä»£çæ´»ä¸è®¾å¤åææ¯çç´è¿·ã\n","engineering-parts":"çª,管é,æå¿
éçCAD项ç®,çè³DIYè®¡åæ¨æé¨æºå¶åå
¶ä»ä½å±äºè¿ä¸ç±»ãå¨è¿é,æ¨å¯ä»¥ä»å
¨çå¶é å,å¦ANVER,纳ç¹åFCIæ¾å°ç3D模åã\n","exterior":"æµè§å»ºçå¤è§ï¼ä»ç«é¢ãåå¸å»ºçå°æ¯è§å¯¹è±¡ãä½å®
ãå·¥ä¸å»ºç以åå
¨å°ºåº¦3Då叿¨¡åãä¸äºèµæºä¸ºä½å¤è¾¹å½¢ï¼å¯å¸®å©æ¨å®ææ¸¸ææVR/ARåºç¨ã\n","food":"é£ç©æå©äºè¥é å®¶åºçæ´»ççå®åºæ¯ã3Dæ°´æãè¬èã饮æåé¤ç¹é½å¨è¿éï¼å¯ç¨äºé¤å
广åæå¥åº·é¥®é£çARåºç¨ãæ è®ºæ¨æ¯å¨æ¾3Dæ«è¨è¿æ¯å©ç¤¼èç³æ¨¡åï¼è¿é齿ã\n","furniture":"3Dæ¡åãæ¤
åãæ²åãåºæä¾å¤ç§æè´¨ï¼æ¨æãéå±çï¼å飿 ¼ï¼å¤å¤ãç°ä»£çï¼ã该类å«éå建çã室å
设计å广åç¸å
³äººåã\n","furniture-set":"å¦æä½ éè¦çèµ·æ¥é½å·®ä¸å¤çå¤è£æ¤
ååæ²åç,æå
¨å¥å¨å
·,è¿æ¯ä»å¨æ¿å客å
å°åå
¬å®¤åé£å æå¥å®¶å
·è¿ä¸ç±»æ¶èä¸ç³»åç3D模åå®¶å
·çå°æ¹ãè¿æå©äºå¹é
çå
ç´ å
é¨æçº§è®¾è®¡ä¸å®¶æé çæ¿é´ã\n","household":"å®¶å±
3D模åç¨äºä¸ºæ¿é´å¢æ·»ç»èãæ¨å¯ä»¥å¨æ¡ä¸æ¾ç½®3Dé¤å
·å¥è£
ï¼æä½¿ç¨è¡æ¤åçç½æ¥å®å卿¿ï¼è¿å¯ä»¥å¨åºè¾¹æ¾ç½®ç¯å
åé²è±ä»¥è¥é 奢忰å´ã\n","industrial":"å»ºçææãå·¥ç¨å·¥å
·ãæºæ¢°åéè£
ç®±ï¼æ¢æä¾ç¯å¢ç»èï¼ä¹å
å«äº¤äºå¼ç»å®å
ç´ ãé常é忍¡ææ¸¸æå¼åè
æå¶ä½æ½å·¥åºæ¯ç人ã\n","interior":"æ¬ç±»å«å
å«å»ºçãæ½å·¥å室å
设计çé¼ç3Då
ç´ ä¸ç»èãæ¨å¯ä»¥å°è¿äº3D模åç¨äºå¨ç»ææ¸¸æï¼å
¶ä¸ä¸äºæ¯ç»å®çä¸ä¸ºä½å¤è¾¹å½¢ã\n","military":"卿¤ç±»å«ä¸ï¼æ¨å¯ä»¥è´ä¹°æ¦å¨ãçç²ãååç«ç®ç3D模åââå
æ¬ç°ä»£ååå²çæ¬ï¼ç¨äºåéæèªå«ã模åå¯ç¨äºæ¸¸æï¼å
¶ä¸ä¸äºå·²è¿è¡å¤è¾¹å½¢ä¼åå¹¶å¯ç´æ¥ç¨äºæ¸¸æå¼æã\n","plant":"æ¤ç±»å«å
嫿¤ç©ç±»3D模åï¼å¦è±ãæ ãèãè¤èã绿æ¤ãèè¯ãå¤å¹´çæ¤ç©ãå¹¼èãå«©è½ãçæ¨ãææãè½ãè¡èè¤ãæèãè¦è´ä¹°æå
è´¹ä¸è½½3D模åï¼è¯·æµè§ä»¥ä¸ç±»å«ã\n","scanned":"建模éè¿ä½¿ç¨ââ3Dæ«æææ¯,å¦RealSenseå建è¿äºæ¨¡åãæ æ¡©,éå,çè³ç·æ§å女æ§å¨è¿é忬¢è¿ãè¯¥äº§åæ¯åå¤å¨åºæ¯åå¨ç»ä¸ä½¿ç¨,æä¾äºç°å®ä¸»ä¹çæ ä¸ä¼¦æ¯çæ°´å¹³ã\n","scie
16518nce":"è¿ä¸ªç±»å«å
嫿¶åå»è¯,çç©,ç©ç,åå¦åææ¯ç3D模å,å¦å®éªå®¤è®¾å¤,æ¾å¾®ç»ç»åäºååä¸çãä¸è¦åè§æ,{\"slug\":\"ç»è\"},{\"slug\":\"骷é«
\"}å{\"slug\":\"骨æ¶\"} 3D模åå¯ä»¥å¨è¿éæ¾å°ã\n","scripts-plugins":"èæ¬åæä»¶ä¸ºæ¨æä¾è½¯ä»¶çå¿«æ·æ¹å¼ã建模,渲æ,纹ç - è¿äºé½å¯ä»¥éè¿æä»¶,æ¥åMayaåçV-Rayåç§è½¯ä»¶å徿´å®¹æã\n","space":"太空类å«å
满äºä½å¤è¾¹å½¢ã游æå°±ç»ªçç§å¹»é£è¹ãå°è¡æãè¡æï¼å
æ¬å°çå为ç§å¦ç±å¥½è
åå¤çé¼çèªå¤©é£æºï¼ã3D太空模å对VRå¤ªç©ºæ¨¡ææ¸¸æå¾æç¨ã\n","sport-hobby":"æ¤ç±»å«encompasesä»»ä½ä¸{\"slug\":\"ç°\"}ä¸è¬äºä»¶,ä½è²åç±å¥½ãä»{\"slug\":\"è¶³ç\"}åæ»éªæå¡{\"slug\":\"åä»\"}å{\"slug\":\"é¢ç´\"},è¿äºé½æ¯æç¨ç3D模åç广å,åºæ¯åå¨ç»ãä½å¤è¾¹å½¢çæ¬æä½è²è§é¢æ¸¸æã\n","textures":"æµè§ä¸ä¸ªç²¾ç¾å¶ä½ç3Dæè´¨åºï¼æ¾å°æåéçå³ç¨å纹çï¼ç¨äºå夿¸¸æå°±ç»ªæç
§ç级é¼ççæ¨¡åï¼å级æ¨çèµæºåºå¹¶æ¹è¿æ¨ç3Dä½åã\n","various":"è¿äºé½æ¯3D模åä¸å®¹æèå
¥å
¶ä»ç±»å«,æä»¥æä»¬å建äºä¸ä¸ªä¼æ¥åä»ä»¬ã { \"title\": \"岩ç³\", \"slug\": \"岩ç³\"},{ \"slug\": \"äº\"},{ \"title\": \"æ å¿\", \"slug\": \"æ å¿\"},{ \"title\":\"ä¼\",\"slug\":\"ä¿æ¤ä¼\"}åå
¶ä»éåç±»3D模åé½å¨è¿éã\n","vehicle":"å¡è½¦ãææ¤è½¦ãå
¬äº¤è½¦ãç«è½¦ãæææºãèªè¡è½¦åæ©æè½¦ââæ¬ç±»å«éåå¸æè®©åå¸è¡éå
满çå®ä¸ç§å¹»è½¦è¾ç人ï¼ä»¥åå¶ä½æ¨¡ææ¸¸æææµ·æ¥çç¨æ·ã\n","watercraft":"æ°´ä¸äº¤éå·¥å
፱Ȍnj
æ¬è¹åªã游èãè°è¹çãç»å®ç3D模åéåç¨äºè§é¢æ¸¸æåå¨ç»ï¼èCG模åéåç¨äºå¯¹è§è§é¼çåº¦è¦æ±æ´é«çåºæ¯æå
¶ä»åºç¨ã\n"},"forwarded":{"cg":{"aircraft":"æ¤ç±»å«å
æ¬3D飿ºã CG {\"slug\": \"aircraft\",\"title\":\"飿º\"}å°éç¨äºæ¨¡æ,å¯è§å,广ååè§é¢ã {\"slug\": \"drone\",\"title\":\"éè\"}æºæåé¨åå°æ»¡è¶³å¾®å°ç©ºä¸è¿è¾å·¥å
·ççè¿·ãå{\"slug\": \"aircraft\",\"title\":\"é æ¨¡å\",\"active_filter\":\"rigged\"}
16518åå¤å¯¼å
¥å°æ¸¸æå¼æã\n","animals":"3Då¨ç©çéå - {\"slug\": \"cat\",\"title\": \"ç«\"},{\"slug\": \"horse\",\"title\": \"马\"},{\"slug\": \"bear\",\"title\":\"ç\"},{\"slug\": \"rhino\",\"title\":\"çç\"},{\"slug\": \"eagle\",\"title\":\"é¹°\"},{\"slug\": \"lion\",\"title\":\"ç®å\"}å¤ - å¯ä»¥å¨è¿éæ¾å°ã该CG 3Då¨ç©å°æ»¡è¶³å¹¿åæéæåºæ¯çéæ±ãæä»¬ä¹æ{\"slug\": \"animal\",\"title\":\"é å¨ç©\",\"active_filter\":\"rigged\"}模åçæ¸¸æã\n","architectural":"{ \"slug\": \"stairs\", \"title\": \"楼梯\"},{ \"slug\": \"fireplace\", \"title\": \"å£ç\"},3D模å以åå{ \"slug\": \"frame\", \"title\": \"帧\"}è£
饰å,{ \"slug\": \"pillow\", \"title\": \"æ\"}æ{\"slug\": \"lamp\", \"title\": \"ç¯\"}å¯ä»¥å¨å¹¿éç建çç»è轿车类å«ä¸æ¾å°å
嫿±½è½¦3D模å,{\"slug\": \"car\",\"title\":\"ä½è\",\"active_filter\": \"low_poly\"}模ååºãå
é¨åå¤é¨å¯ç¨äºæ è®ºä½ æ¯ä¸å建çå¸,å·¥ç¨å¸æç¬ç«æ¸¸æå¼åå建ç«äºæ°åç卿¿åå§å®¤ä»¥åæ¿é´çåå ¡åå°ç¢ã\\n","car":"汽车类å«å
æ¬æ±½è½¦3D模å,å
¶ä¸\u003ca href=\"%{link_to_low_poly_items_url}\"\u003eä½è\u003c/A\u003eçæ¬å°æ¯æ¸¸æè®¾è®¡è
çå¸å¼å,å
¶ä»äºº - çµå½±å¶é åæå¹¿ååãä»èç·è½¦å°èµè½¦å轨éè½¦çæ¦å¿µç,æç§ç±»ç¹å¤ç3D汽车模åã\n","character":"å¨è¿ä¸ªç±»å«ä¸,ä½ ä¼åç°3D模å {\"slug\": \"human\", \"title\": \"人\"} ç,人,ç§å¹»,æè£
çãä» {\"slug\": \"heart\", \"title\": \"å¿è\"}å{\"slug\": \"hand\", \"title\":\"æ\"},以ç»è´é¼ç {\"slug\": \"male\", \"title\":\"ç·\"} æ {\"slug\": \"female\", \"title\":\"女\"} 模åãè®¸å¤æºåé½è¢«æçºµ,å¹¶ä¸å¯ä»¥å¾å®¹æå°æ·»å å°æ¨ç游ææå¨ç»ã\n","electronics":"çµåæ¯å»ºçå¸,室å
设计å¸,å
³å¡è®¾è®¡å¸,ç°åºå¶å®è
åå
¶ä»å¹¿åç±»å«ã { \"slug\": \"smartphone\", \"title\": \"ç¬è®°æ¬çµè\"},{ \"slug\": \"laptop\",\"title\": \"æºè½ææº\"}, {\"slug\": \"camera\", \"title\":\"ç¸æº\"},{\"slug\": \"tv\",\"title\":\"çµè§\"},æ´æå©äºåç¡®å°ææç°ä»£çæ´»ä¸è®¾å¤åææ¯çç´è¿·ã\n","engineering-parts":"çª,管é,æå¿
éçCAD项ç®,çè³DIYè®¡åæ¨æé¨æºå¶åå
¶ä»ä½å±äºè¿ä¸ç±»ãå¨è¿é,æ¨å¯ä»¥ä»å
¨çå¶é å,å¦ANVER,纳ç¹åFCIæ¾å°ç3D模åã\n","exterior":"ä»å¤å¢æµè§å»ºçå¤å¢,åå¸å»ºçæ¯è§å¯¹è±¡,ä½å®
,å·¥ä¸å»ºç,åæ»¡éç¨3D {\"slug\": \"city\", \"title\": \"å\"}模åãæäºèµäº§æ¯ä½èåå¯ä»¥å¸®å©ä½ å®æä½ çæ¸¸ææVR / ARåºç¨ã\n","food":"é£åæå©äºæé å½å
çæ´»çé¼ççåºæ¯ã 3Dæ°´æ,è¬è,饮æåé¤ç¹é½å¨è¿éã广åé¤é¦,为å¥åº·ç饮é£ARåºç¨ãæ è®ºæ¨æ£å¨å¯»æ¾3D {\"slug\": \"pizza\", \"title\":\"æ¯è¨\"}æå©ç¤¼{\"slug\": \"cake\", \"title\":\"èç³\"}模å,ä»ä»¬å¨è¿éã\n","furniture":"3Dæ¡å,æ¤
å,æ²å,å¨åç§æè´¨ï¼æ¨æ,éå±çï¼åæ ·å¼ï¼{\"slug\": \"retro\", \"title\":\"å¤å¤\"},{\"slug\": \"modern\", \"title\":\"ç°ä»£\"}çï¼çåºæ¯å¯¼éæãè¿ä¸ªç±»å«æ¯ä¸ºåä¸å»ºçå室å
设计,以å广å主ç人ã\n","furniture-set":"å¦æä½ éè¦çèµ·æ¥é½å·®ä¸å¤çå¤è£æ¤
ååæ²åç,æå
¨å¥å¨å
·,è¿æ¯ä»å¨æ¿å客å
å°åå
¬å®¤åé£å æå¥å®¶å
·è¿ä¸ç±»æ¶èä¸ç³»åç3D模åå®¶å
·çå°æ¹ãè¿æå©äºå¹é
çå
ç´ å
é¨æçº§è®¾è®¡ä¸å®¶æé çæ¿é´ã\n","household":"å®¶å±
ç¨å3Dæ¨¡åæ¯ç¨æ¥ç»ç»èçæ¿é´ãä½ å¯ä»¥æ3Dé¤å
·æ¾å¨æ¡ä¸,ææè¡æ¤åçç容å¨,以宿´ç卿¿å
,å¯è½æä¸äº{\"slug\": \"light\",\"title\":\"ç¯\"}å{\"slug\": \"flowers\", \"title\":\"è±\"}åºè¾¹è¥é 豪åçæè§ã\n","industrial":"å»ºçææ,{\"slug\": \"engineering\", \"title\":\"å·¥ç¨\"}
16518å·¥å
·,æºæ¢°{\"slug\": \"container\",\"title\":\"容å¨\"}åæ¶æä¾ç¯å¢ä¿¡æ¯åäºå¨,æçºµå
ç´ ãè¿æ¯å®ç¾çæ¨¡ææ¸¸æå¼ååæå»ºçç人{\"slug\": \"construction\", \"title\":\"建设\"}é¢åéçæ°´å¹³ã\n","interior":"è¿ä¸ªç±»å«å
å«é¼çç3Då
ç´ ä¸å»ºç,建çä¸å·¥ç¨å
é¨è®¾è®¡çç»èãæ¨å¯ä»¥ä½¿ç¨è¿äº3D模å,å¨ç»ææ¸¸æ - å
¶ä¸ä¸äºæ¯æçºµåä½èã\n","military":"å¨è¿ä¸ªç±»å«ä¸,ä½ å¯ä»¥ä¹°å°3D模åçæ¦å¨,æ¦å¨,{\"title\":\"å\",\"slug\": \"sword\"}ç±åéåèªå«ä½¿ç¨åç«ç®ç°ä»£ååå²ãæ¨å¯ä»¥ä½¿ç¨æ¨¡å游æ - ä»ä»¬ä¸çä¸äºä¼å,å¹¶å夿¸¸æå¼æçå¤è¾¹å½¢ã\n","plant":"è¿ä¸ªç±»å«å
å«3Dæ¨¡åæ¤ç©çç©,å¦è±å,{\"slug\": \"tree\",\"title\":\"æ \"},è,æç¼æ¤ç©,绿å,èæ¬,å¤å¹´çæ¤ç©,è,è½,çæ¨,å,è±è½,è¤è,æèãè´ä¹°æä¸è½½å
è´¹ç3D模å,æµè§ä»¥ä¸ç±»å«ã\n","scanned":"建模éè¿ä½¿ç¨ââ3Dæ«æææ¯,å¦RealSenseå建è¿äºæ¨¡åãæ æ¡©,éå,çè³ç·æ§å女æ§å¨è¿é忬¢è¿ãè¯¥äº§åæ¯åå¤å¨åºæ¯åå¨ç»ä¸ä½¿ç¨,æä¾äºç°å®ä¸»ä¹çæ ä¸ä¼¦æ¯çæ°´å¹³ã\n","scie
16518nce":"è¿ä¸ªç±»å«å
嫿¶åå»è¯,çç©,ç©ç,åå¦åææ¯ç3D模å,å¦å®éªå®¤è®¾å¤,æ¾å¾®ç»ç»åäºååä¸çãä¸è¦åè§æ,{\"slug\": \"cell\",\"title\":\"ç»è\"},{\"slug\": \"skull\",\"title\":\"骷é«
\"}å{\"slug\": \"skeleton\",\"title\":\"骨æ¶\"} 3D模åå¯ä»¥å¨è¿éæ¾å°ã\n","scripts-plugins":"èæ¬åæä»¶ä¸ºæ¨æä¾è½¯ä»¶çå¿«æ·æ¹å¼ã建模,渲æ,纹ç - è¿äºé½å¯ä»¥éè¿æä»¶,æ¥åMayaåçV-Rayåç§è½¯ä»¶å徿´å®¹æã\n","space":"ç©ºé´æ¯ä¸ä¸ªå®æ´çä½è,ç§å¹»{\"slug\": \"spaceship\",\"title\":\"é£è¹\"}游æåå¤ç车åç±»å«,{\"slug\": \"asteroid\",\"title\":\"å°è¡æ\"},è¡æï¼å
æ¬{\"slug\": \"earth\",\"title\":\"å°ç\"}åç°å®ç©ºé´{\"slug\": \"shuttle\",\"title\":\"èªå¤©é£æº\"}为æ´ç§å¦å°å¾æ3Dç©ºé´æ¨¡å对VRç©ºé´æ¨¡æå¨æ¸¸ææç¨ã\n","sport-hobby":"æ¤ç±»å«encompasesä»»ä½ä¸{\"slug\": \"field\",\"title\":\"ç°\"}ä¸è¬äºä»¶,ä½è²åç±å¥½ãä»{\"slug\": \"football\",\"title\":\"è¶³ç\"}åæ»éªæå¡{\"slug\": \"guitar\",\"title\":\"åä»\"}å{\"slug\": \"piano\",\"title\":\"é¢ç´\"},è¿äºé½æ¯æç¨ç3D模åç广å,åºæ¯åå¨ç»ãä½å¤è¾¹å½¢çæ¬æä½è²è§é¢æ¸¸æã\n","textures":"æµè§ç²¾ç¾å¶ä½ç3Dææåºï¼å¹¶æ¾å°æéåçï¼åå¤ä½¿ç¨ç纹çåå¤\u003ca href=\"%{link_to_low_poly_items_url}\"\u003e游æåå¤\u003c/a\u003eæé¼ççæ¨¡åï¼åçº§ä½ çèµäº§åºï¼å¹¶æé«æ¨ç3Dä½åã\n","various":"è¿äºé½æ¯3D模åä¸å®¹æèå
¥å
¶ä»ç±»å«,æä»¥æä»¬å建äºä¸ä¸ªä¼æ¥åä»ä»¬ã { \"title\": \"岩ç³\", \"slug\": \"rocks\"},{ \"slug\": \"clouds\",\"title\": \"äº\"},{ \"title\": \"æ å¿\", \"slug\": \"logo\"},{ \"title\":\"ä¼\",\"slug\": \"umbrella\"}åå
¶ä»éåç±»3D模åé½å¨è¿éã\n","vehicle":"å¡è½¦,{\"title\":\"ææ¤è½¦\",\"slug\": \"ambulance\"},å
Œ
±æ±½è½¦,ç«è½¦,æææº,{\"title\":\"èªè¡è½¦\",\"slug\": \"bike\"}åæ©æè½¦ - è¿ä¸ªç±»å«æ¯ä¸ºè°å¸æèªå·±çåå¸è¡éä¸ç人们å
满äºç°å®åç§å¹»è½¦è¾,并为é£äºå¶ä½æ¨¡ææ¸¸ææå¨æ ¼å¼åçæµ·æ¥ã\n","watercraft":"è¹è¶äºç{ \"title\": \"è¹\", \"slug\": \"ship\"},{ \"title\": \"游è\", \"slug\": \"yacht\"},{ \"title\": \"è¹\", \"slug\": \"ship\"}çæ°´ä¸äº¤éå·¥å
·ãçè£
ç3D模åå°å¨è§é¢æ¸¸æ,å¨ç»åçå¾å¥½,èCGæ¨¡åæ¯æä½ çåºæ¯æå
¶ä»åºç¨ä¸çè§è§ä¿ç度æ¯polycountæ´éè¦ã\n"},"printable":{"art":"è¿å°±æ¯èºæ¯çä¸ç»´æå°å»ã寻æ¾è±å¨çéå¡è®¾è®¡åç°åå²äººç©çç»å
¸ä½ååéå,æé¼è人å¿ä¿,çè³3Dæå°çæ å¿ï¼è¿æ¯ç±»å«ã\n","fashion":"ä½ å¯ä»¥ç©¿ä¸æ¼äº®åæ¶å°çä¸è¥¿,è¿ä¸ªç±»å«ä¸è¢«åç°ãççä½ è½ä¸è½æ¾å°ä»»ä½ä½¿ç¨è±å¼å¤ªç©ºæ¶ä»£{\"slug\": \"footwear\",\"title\":\"éç±»\"},æ°å¥ç¼é,è§è²æ®æ¼{\"slug\": \"accessories\",\"title\":\"é
ä»¶\"}å¨è¿éæ¾å°ã\n","gadgets":"ææ{ \"title\": \"iPhone\", \"slug\": \"iphone\"},{ \"title\": \"iPadç\", \"slug\": \"ipad\"}ï¼åå
¶ä»æºè½è®¾å¤ï¼çæ
åµä¸å¯ä»¥å¨å°å·¥å
·ç±»ä¸æ¾å°ãä»ç®åç3Déå ç»ä»¶å°å¤æçé¶ä»¶å\"é»å®¢\"为æ¨ç项ç®,è¿æ¯ä¸ºå¹¿åç´ æç±»å«åææ¯ç±å¥½è
ã\n","games-toys":"游æåç©å
·æ¯è¦çæå°3Då¤æäººææªç©å¾®ç¼©æ¨¡åç±»,å¾®å°{\"title\":\"å¦å
\",\"slug\": \"tank\"},æ¶é«¦{\"slug\": \"chess\",\"title\":\"å½é
象æ£\"}ç,çµå½±éç人ç©å¤´ç,ä¸ä½ç±å¥½ç¨å
·åé
ä»¶ãè¿æ¯å¯¹-GOç±»å«ä¸ææçä¸è¥¿ä¹¦ååã\n","hobby-diy":"å¦æä½ æ¯æä»¬çä¸ä¸ä¸ªä¼å¤§çåæå®¶,å¹¶å¸æå»ºç«èªå·±çDIYé¡¹ç®æå¾å°ä¸äºé¶é¨ä»¶ä¸ºæ¨{\"slug\": \"drone\",\"title\":\"æ 人驾驶\"},è¿æ¯è¦å»çå°æ¹ãæ¤å¤,å®çåè½è°æ³è¦è®©èªå·±çéåæå¡ææªå¤å¶åç人å¾å¤ä¸è¥¿ã\n","house":"å°æè®¾çåç§å¯ä»¥å¨è¿éæ¾å°ã {\"title\":\"ç¯\",\"slug\": \"lamp\"},èºæ¯{\"title\":\"ç¢\",\"slug\": \"bowl\"},以ååç±»{\"title\":\"ææäºº\", \"slug\": \"holder\"}æ¯å¦æ¾ä¸å°æ¨çææºå³ä¾§çç¹,ä¿æçç¾,å 卿¡ä¸çç¬æç å®ç顺åºã\n","jewelry":"ç 宿¯ä½ å»åªéè·å¾çæé¯ååå æé»ç³ææãè½ç¶3Dæå°æºé½ä¸å¤å¥½,使é»ç³ - ä½ - ä½ ä»ç¶å¯ä»¥æå°åºä¸ä¸ªéå±ç¯ä¸ºæ¨çITæªèææ¡ç¯çåºç¡ã\n","miniatures":"3Dæå°{ \"title\": \"人ç©\", \"slug\": \"character\"},å人,{ \"title\": \"å°æ \", \"slug\": \"landmark\"},å¨ç©,{ \"title\":\"ç·\",\"slug\": \"male\"}
16518,{ \"slug\": \"female\", \"title\": \"女\"},{ \"title\": \"æªç©\", \"slug\": \"monster\"},{ \"title\": \"å¤å½äºº\",\"slug\": \"alien\"} - è¿ä¸åé½å¨è¿éãæ è®ºæ¨æ¯æå°å¤åè½è½¦,æä½ ç表æä¸ºæ¨çæ¡é¢æ¸¸æä¸å¶ä½ç微缩模å,è¿æ¯ä½ çç±»å«ã\n","science":"æä»ä¹å¯ä»¥è¢«å½ç±»ä¸ºç§å¦ï¼é£ä¹,骨æ¶{\"slug\": \"bones\",\"title\":\"ç骨\"}ç车å,å»ç{\"slug\": \"tools\",\"title\":\"å·¥å
·\"}å天ä½ç©çå¦ç¸å
³3D,å¯ä»¥å¨è®¸å¤ç ç©¶è¿ç¨ä¸ä½¿ç¨çæå°æ¨¡å¼ã\n"}},"printable":{"art":"è¿å°±æ¯èºæ¯çä¸ç»´æå°å»ã寻æ¾è±å¨çéå¡è®¾è®¡åç°åå²äººç©çç»å
¸ä½ååéå,æé¼è人å¿ä¿,çè³3Dæå°çæ å¿ï¼è¿æ¯ç±»å«ã\n","fashion":"ä½ å¯ä»¥ç©¿ä¸æ¼äº®åæ¶å°çä¸è¥¿,è¿ä¸ªç±»å«ä¸è¢«åç°ãççä½ è½ä¸è½æ¾å°ä»»ä½ä½¿ç¨è±å¼å¤ªç©ºæ¶ä»£{\"slug\":\"éç±»\"},æ°å¥ç¼é,è§è²æ®æ¼{\"slug\":\"é
ä»¶\"}å¨è¿éæ¾å°ã\n","gadgets":"ææ{ \"title\": \"iPhone\", \"slug\": \"iphone\"},{ \"title\": \"iPadç\", \"slug\": \"iPadç\"}ï¼åå
¶ä»æºè½è®¾å¤ï¼çæ
åµä¸å¯ä»¥å¨å°å·¥å
·ç±»ä¸æ¾å°ãä»ç®åç3Déå ç»ä»¶å°å¤æçé¶ä»¶å\"é»å®¢\"为æ¨ç项ç®,è¿æ¯ä¸ºå¹¿åç´ æç±»å«åææ¯ç±å¥½è
ã\n","games-toys":"游æåç©å
·æ¯è¦çæå°3Då¤æäººææªç©å¾®ç¼©æ¨¡åç±»,å¾®å°{\"title\":\"å¦å
\",\"slug\":\"å¦å
\"},æ¶é«¦{\"slug\":\"å½é
象æ£\"}ç,çµå½±éç人ç©å¤´ç,ä¸ä½ç±å¥½ç¨å
·åé
ä»¶ãè¿æ¯å¯¹-GOç±»å«ä¸ææçä¸è¥¿ä¹¦ååã\n","hobby-diy":"å¦æä½ æ¯æä»¬çä¸ä¸ä¸ªä¼å¤§çåæå®¶,å¹¶å¸æå»ºç«èªå·±çDIYé¡¹ç®æå¾å°ä¸äºé¶é¨ä»¶ä¸ºæ¨{\"slug\":\"æ 人驾驶\"},è¿æ¯è¦å»çå°æ¹ãæ¤å¤,å®çåè½è°æ³è¦è®©èªå·±çéåæå¡ææªå¤å¶åç人å¾å¤ä¸è¥¿ã\n","house":"å°æè®¾çåç§å¯ä»¥å¨è¿éæ¾å°ã {\"title\":\"ç¯\",\"slug\":\"ç¯\"},èºæ¯{\"title\":\"ç¢\",\"slug\":\"ç¢\"},以ååç±»{\"title\":\"ææäºº\", \"slug\":\"ææäºº\"}æ¯å¦æ¾ä¸å°æ¨çææºå³ä¾§çç¹,ä¿æçç¾,å 卿¡ä¸çç¬æç å®ç顺åºã\n","jewelry":"ç 宿¯ä½ å»åªéè·å¾çæé¯ååå æé»ç³ææãè½ç¶3Dæå°æºé½ä¸å¤å¥½,使é»ç³ - ä½ - ä½ ä»ç¶å¯ä»¥æå°åºä¸ä¸ªéå±ç¯ä¸ºæ¨çITæªèææ¡ç¯çåºç¡ã\n","miniatures":"3Dæå°{ \"title\": \"人ç©\", \"slug\": \"å符\"},å人,{ \"title\": \"å°æ \", \"slug\": \"å°æ \"},å¨ç©,{ \"title\":\"ç·\",\"slug\": \"ç·æ§\"},{ \"slug\": \"女æ§\"},{ \"title\": \"æªç©\", \"slug\": \"æªç©\"},{ \"title\": \"å¤å½äºº\",\"slug\":\"å¤æäºº\"} - è¿ä¸åé½å¨è¿éãæ è®ºæ¨æ¯æå°å¤åè½è½¦,æä½ ç表æä¸ºæ¨çæ¡é¢æ¸¸æä¸å¶ä½ç微缩模å,è¿æ¯ä½ çç±»å«ã\n","science":"æä»ä¹å¯ä»¥è¢«å½ç±»ä¸ºç§å¦ï¼é£ä¹,骨æ¶{\"slug\":\"ç骨\"}ç车å,å»ç{\"slug\":\"å·¥å
·\"}å天ä½ç©çå¦ç¸å
³3D,å¯ä»¥å¨è®¸å¤ç ç©¶è¿ç¨ä¸ä½¿ç¨çæå°æ¨¡å¼ã\n"},"titles":{"aircraft":"飿º3D模å","animals":"å¨ç©3D模å","architectural":"建ç3D模å","car":"汽车3D模å","character":"人ç©3D模å","exterior":"å¤è§3D模å","food":"é£ç©3D模å","furniture":"å®¶å
·3D模å","household":"å®¶å±
3D模å","industrial":"å·¥ä¸3D模å","interior":"室å
3D模å","military":"åäº3D模å","plant":"æ¤ç©3D模å","space":"太空3D模å","textures":"CGè´´å¾3D模å","vehicle":"交éå·¥å
·3D模å","watercraft":"æ°´ä¸äº¤éå·¥å
·3D模å"}},"title":{"cg":" 3D模å","print":" 3Dæå°æä»¶"}}
16518,"competition":{"digital-art-competition":{"categories":{"page_description":"æäº¤æ¨çä½åè§è²æç»ï¼è§è²æ¦å¿µè®¾è®¡ï¼ç¯å¢æå¾ï¼ç¯å¢æ¦å¿µè®¾è®¡ï¼å¯¹è±¡è®¾è®¡å对象æ¦å¿µè®¾è®¡ç±»å«åå CGTraderæ°åèºæ¯å¤§èµãå¦ææ¨æéåä¸åç±»å«çå 个ä¼å¤§çä½åï¼éæå°å
¶æäº¤å°ç¸åºçç±»å«ãéæ©ä¸ä¸ªç±»å«ï¼ä»¥æ¥ç该类å«çå¥é¡¹ã"}}},"conversations":{"action_button_confirmation":"æ¨ç¡®å®è¦éæ°æå¼æ¤è¯·æ±åï¼","reply_posted":"åå¤å·²åå¸ã","with_yourself":"ä¸è½ä¸åéè
ç¸åã"},"date":{"month_names":[null,"䏿","äºæ","䏿","åæ","äºæ","å
æ","䏿","å
«æ","乿","åæ","å䏿","åäºæ"]},"devise":{"failure":{"too_many_requests":"æ¨å·²è¯·æ±åéå¯ç éç½®é®ä»¶ã请ç¨çå åéååè¯ã"}},"disabled_cookies_modal":{"button":"åæ¶","text_1":"æ¨å°æ æ³æµè§æ°ä»¥ç¾ä¸è®¡ç巨大çä¸ç»´æ¨¡åï¼å°å
¶æ·»å å°è´ç©è½¦æè´ä¹°ã","text_2":"å¦æä½ æ³å
åä½éªCGTraderï¼æä»¬é¼å±å¨è¿ä¸ªç½ç«ä¸å¯ç¨Cookieã","title":"çæ¥ä½ æä½ çæµè§å¨çcookieç¦ç¨"},"emails":{"error_notification":"æªæ¾å°è®¢é
ã","success_subscribed_notification":"æ¨å·²æå订é
ã","success_unsubscribed_notification":"æ¨å·²æåé订ã"},"file_size_validator":{"errors":{"invalid_carrierwave":"颿åºä¸º CarrierWave::Uploader::Base 对象","invalid_key":":%{key} å¿
é¡»æ¯éè´æ´æ°","range_format":":in å :within å¿
é¡»æ¯ä¸ä¸ªèå´ (Range)","range_unspecified":"æªæå®èå´ã请æå® :withinã:maximumã:minimum æ :is é项ã"}},"file_type":{"default_error":"æªæä¾æä»¶è·¯å¾ã"},"footer":{"bottom-row":{"privacy":"éç§","terms-link":"æ¡æ¬¾ä¸æ¡ä»¶"},"links":{"buyLinks":[{"text":"è´ä¹°3D模å","link":"/zh-cn/3d-models"},{"text":"ä¼ä¸ç","link":"/discover/business-account"},{"text":"å
è´¹3Dæ°æ®é","link":"/discover/datasets"},{"text":"è请3D设计å¸","link":"/3d-modeling-jobs"},{"text":"å
è´¹3D模å","link":"/zh-cn/free-3d-models"},{"text":"å
è´¹3Dæå°æ¨¡å","link":"/zh-cn/free-3d-print-models"}],"communityLinks":[{"text":"社åº","link":""},{"text":"ä¼ç§è®¾è®¡å¸","link":"/designers"},{"text":"ææèµ","link":"/challenges"},{"text":"论å","link":"/forum"}],"companyLinks":[{"text":"å
¬å¸","link":"/discover/about-us"},{"text":"å客","link":"/blog"},{"text":"èä¸","link":"/pages/careers"},{"text":"帮å©ä¸å¿","link":"https://help.cgtrader.com"}],"sellLinks":[{"text":"åºå®3D模å","link":"/discover/sell-3d-models"},{"text":"æåéé","link":"/discover/sell-more"},{"text":"3Då¸åºæ´å¯","link":"/discover/3d-market-trends"},{"text":"çé¨3D模åæç´¢","link":"/discover/3d-models-top-searches"},{"text":"çé¨3Dæå°æç´¢","link":"/discover/3d-print-models-top-searches"}]},"subscribe":{"button-active":"订é
","button-disabled":"已订é
","header":"订é
æä»¬çæ°é»ï¼","placeholder":"è¾å
¥æ¨ççµåé®ç®±","terms-link":"ä½¿ç¨æ¡æ¬¾","text":"éè¿è®¢é
æ¨ç¡®è®¤æ¨å·²ç»é
读并æ¥åæä»¬ç"}},"general":{"description":"CGTraderæ¯ä¸ä¸ªå¨çº¿å¸åºï¼3Dèºæ¯å®¶å设计å¸å¯ä»¥è´ä¹°ï¼åºå®æå
±äº«3D模åã宿ç«ï¼ç®åæ£å¨ç±ä¸ä¸ªå¢éç3D设计å¸åå·¥ç¨å¸å¼åçãæä»¬çç®æ æ¯æ°ä¸»å3Dè¡å¸åæ¹åæä»¬çå¨çº¿éå®ç3D模åçæ¹å¼ãå¯è®©ä½è
è·å¾æå¤§çç¹è®¸æä½¿ç¨è´¹ï¼æä»¬åªåæé«ä»ä»¬çç§¯ææ§ï¼å¹¶æé«3D模åçè´¨éã","navigation":{"buy_3d_models":"è´ä¹°3D模å","sell_3d_models":"åºå®3D模å"},"search_placeholder":"å¨è¶
è¿200ä¸ä¸ªæ¨¡åä¸æç´¢","site-search__field":"æç´¢%{model_count}个3D模å","site_title":"ä¸ç»´æ¨¡ååº","site_title_postfix":" | CGTrader"},"generator":{"landing_pages":{"three_d_model":{"defaults":{"closing_cta":{"heading":"让AIå®ç°æ¨ç梦æ³","subtitle":"å°æç¤ºè¯æåèå¾å转å为ç产就绪ç3D模åï¼ç¶åç»åãéæ°çº¹çå并以æ¨éè¦çæ ¼å¼å¯¼åºã"},"faq":{"heading":"常è§é®é¢","items":{"commercial":{"answer":"æ¨ç%{object}ä¸ç»´æ¨¡åçåä¸ä½¿ç¨å¯å¨CGTrader AIä»è´¹è®¡åä¸è·å¾ã请æ¥é
CGTraderæ¡æ¬¾ 忡件ï¼äºè§£éç¨äºAIçææ¨¡åçè®¸å¯æ¡æ¬¾ã","question":"æå¯ä»¥å°çæç%{object}模åç¨äºåä¸ç®çåï¼"},"formats":{"answer":"%{object}ç3D模åæä¾GLBãFBXãOBJãSTLæUSDZæ ¼å¼ã","question":"æå¯ä»¥ä»¥ä½ç§æä»¶æ ¼å¼è·å%{object}模åï¼"},"no_skills":{"answer":"æ éä»»ä½3D建模ç¥è¯ãææå»ºæ¨¡åéè¿%{object}模åçæå¨å®æã彿¨è¾å
¥æç¤ºè¯æä¸ä¼ å¾åæ¶ï¼ç³»ç»ä¼èªå¨å¤çå ä½å½¢ç¶ãæ¯ä¾åç»æãå³ä½¿æ¯åå¦è
ä¹è½å¨å åéå
åå»ºå®æ´ç %{object}ä¸ç»´æ¨¡åã","question":"使ç¨%{object}
16518模åçæå¨éè¦3D建模ç¥è¯åï¼"},"what_is":{"answer":"CGTrader %{object}ä¸ç»´æ¨¡åçæå¨æ¯ä¸æ¬¾åºäºAIçå·¥å
·ï¼å¯æ ¹æ®æåæä»¤æåèå¾åå建 %{object}ä¸ç»´æ¨¡åãå®åææ¨çæ³æ³ï¼ä¸ºè®¾è®¡ãååå¶ä½åå¯è§åçæå¯ä¸è½½æ¨¡åãæä»¬ç ä»è´¹è®¢é
æä¾æ´é«çæåº¦éé¢ã","question":"ä»ä¹æ¯%{object}ä¸ç»´æ¨¡åçæå¨ï¼"},"why_cgtrader":{"answer":"ç¨æ·å¯ä»¥ä¿¡èµCGTraderæä¾æµç
çä½éªãå¿«éçå¤çé度åé«è´¨éç3Dè¾åºã该工å
·éåä¸ ä¸äººå£«ååå¦è
ï¼ä¸ºå建%{object}ä¸ç»´æ¨¡åæä¾å¯é çè§£å³æ¹æ¡ã","question":"为ä»ä¹ä½¿ç¨CGTraderçAI %{object}çæå¨ï¼"}}},"h1":"AI %{object}ä¸ç»´æ¨¡åçæå¨","hero_alt":"AI %{object}ä¸ç»´æ¨¡åçæå¨","hero_height":617,"hero_width":1080,"how_to":{"heading":"ä»å¾åæææ¬æç¤ºçæ%{object}","paragraphs":["设计%{object}ä¸ç»´æ¨¡åé常ç®åãå¨å·¦ä¾§è¾¹æ çå·¦ä¸è§ï¼ç¹å»æé®ä¸ä¼ æ¨ç%{object}å¾å以 æå»º3D模åãç¨æ·ä¹å¯ä»¥å¨åºé¨ç\"æè¿°æ¨æ³å建çå
容\"åæ®µä¸è¾å
¥æç¤ºè¯ãCGTrader AIä¼ä¸º æ¨ä¼åæç¤ºè¯ï¼å æ¤ç®ççæè¿°å³å¯å¼å§ã","å³ä¾§è¾¹æ 让æ¨å¯¹%{object}ä¸ç»´æ¨¡åæ¥æè¯å¥½çæ§å¶ãéæ©ç½æ ¼ç±»åãæè´¨ãæç¤ºå¼å¯¼åæä»¶ æ ¼å¼çè®¾ç½®ãæ¨è¿å¯ä»¥éè¿çº¹çèªå®ä¹%{object}模åãè¾å
¥æå说ææå¾ååï¼ç¹å»\"çæ\"ã 该工å
·å°å¨å åéå
å¤çæ¨çè¾å
¥ï¼å
·ä½æ¶é´åå³äºç³»ç»è´è½½ãæè´¨ãç½æ ¼ç±»åãå½¢ç¶ãç§å å¼åè´¨éã"],"steps":["è¾å
¥æåæè¿°å¹¶/æéä¸åèå¾åï¼ä»¥æé«%{object}ä¸ç»´æ¨¡åçæç»ç²¾åº¦ã","éæ©æä»¬çé¢è®¾ä¹ä¸ï¼æéæ©AI弿ãèªå®ä¹å¤è¾¹å½¢æ°éï¼å¹¶ä¸ºæ¨ç%{object}ä¸ç»´æ¨¡åéæ©æè´¨ç±»åã","ç¹å»\"çæ\"ï¼ä»æ¨çæç¤ºè¯å/æåèå¾åå建%{object}ä¸ç»´æ¨¡åã","以ä¸åæ ¼å¼ï¼GLBãFBXãOBJãSTLæUSDZï¼ä¸è½½æ¨å建ç%{object}ä¸ç»´æ¨¡åã"]},"intro":"æ¨æ¯å¦å¨å¯»æ¾ä¸ç§ç®åå¿«æ·çæ¹å¼ï¼å¨å åéå
å建é«è´¨éç%{object}ä¸ç»´æ¨¡åï¼æä»¬å
è¿ç %{object}ä¸ç»´æ¨¡åçæå¨CGTrader AIå¯å°æåæä»¤æåèå¾å转å为å®å
¨å¯ç¨ç模åãå®åºäº å
æ¬MeshyãHunyuanåTripo3Då¨å
çé¢å
3Dçæå¼æè¿è¡ï¼å¸®å©è®¾è®¡åå¦è
åä¸å®¶å¿«éåå»ºç¨ äºå¯è§åãå®éªååå设计ç3D模åãæ¯æææ¬è½¬3Dåå¾å转3Dï¼å¹¶å
¼å®¹3Dæå°æºãæ¨å¯ä»¥ä¸ä¼ JPGæPNGæ ¼å¼çå¾åï¼ä¹å¯ä»¥ä»¥æåå½¢å¼è¾å
¥æè¿°ï¼CGTrader AIå°ä¸ºæ¨å®æåç»æ¥éª¤ã","meta_description":"CGTrader AI %{object} ä¸ç»´æ¨¡åçæå¨ âï¸ éè¿æåæå¾åçæç²¾ç»ç %{object} ä¸ç»´æ¨¡åãç«å³å
è´¹å¼å§ã","primary_cta":"å
è´¹å¼å§çæ","title":"AI %{object}ä¸ç»´æ¨¡åçæå¨ï¼å
è´¹ï¼| CGTrader"}}},"rules":{"errors":{"front_view_required":"éè¦æ£è§å¾å¾çã"}}},"home":{"index":{"3D-projects":{"info-section__cta":"äºè§£æ´å¤","info-section__description":"å¨è¿éï¼å¥½ç3D项ç®ä¼éå°ææåç3D设计å¸","info-section__heading_html":"\u003cstrong\u003e 3D项ç®\u003c/strong\u003eç¹çº¦ä¸å¿"},"categories-conatainer":{"browse_all":"æµè§æææ¨¡å","browse_all_tooltip":"æµè§ææ3D模å","discounts":"ææ£"},"cgdream":{"cta":"å
è´¹å
¥é¨ï¼","heading_html":"\u003cstrong\u003eæ¢ç´¢ CGDreamï¼\u003c/strong\u003e\u003c/br\u003e å¨è¿é AI ä¸ 3D 模åç¸éã","text_html":"\u003cstrong\u003e CGDream \u003c/strong\u003eæ¯ä¸ç§å°ç«¯åºç¨ï¼å®å©ç¨çæAIå3D模åçåè½æ¥äº§çæäººç2Då¾åã \u003cstrong\u003e æ¨çåææ
ç¨ç°å¨å¼å§ã\u003c/strong\u003e"},"community":{"info-section__cta":"å å
¥ç¤¾åº","info-section__heading_html":"å å
¥CGTraderç\u003cstrong\u003e社åº\u003c/strong\u003e","info-section__icon-list_1":{"description":"å±ç°æ¨çæä½³æ¸²æï¼å¹¶è·å¾åé¦å认å¯","heading":"ä½åé¦"},"info-section__icon-list_2":{"description":"å¦ä¹ æ°æè½å¹¶ææä»äºº","heading":"æç¨"},"info-section__icon-list_3":{"description":"æ¥æ¾æç¨å讨论å
¶ä»3Dç¸å
³äºå®","heading":"论å"}},"covid":{"timer-strip__item":"COVID-19鲿¤çå
è´¹3Dæå°èµæº","timer-strip__item--button":"æµè§3D模å"},"enterprise":{"info-section__cta":"äºè§£æ´å¤","info-section__heading_html":"\u003cstrong\u003eä¼ä¸\u003c/strong\u003eç3Dæå¡","info-section__icon-list_1":"æä»¬å¯ä»¥åçARå®ç°äºä½ ","info-section__icon-list_2":"æ´å¤çéå®è½¬åçï¼æ´å°ç产åéè´§","info-section__icon-list_3":"ä¸¥æ ¼çè´¨éä¿è¯"},"header":"è´ä¹°ä¸ä¸3D模å","marketplace":{"info-section__description":"ä»%{models_count}个3D模å䏿éï¼æ»¡è¶³æ¸¸æãVR/ARã广åãå¨ç»ãå½±è§å3Dæå°çä¸ååºç¨éæ±ã\n","info-section__heading_html":"3D模å\u003cstrong\u003eå¸åº\u003c/strong\u003e","info-section__image-list_1":{"de
16518scription":"为æ¨ç项ç®è´ä¹°ä¸ä¸ç3D模å","heading":"3D模å"},"info-section__image-list_2":{"description":"ä½å¤è¾¹å½¢PBR 3D模åï¼éç¨äºè§é¢æ¸¸æãVRåAR宿¶åºç¨","heading":"ä½å¤è¾¹å½¢PBR 3D模å"},"info-section__image-list_3":{"description":"为æ¨ç3Dæå°æºæ¥æ¾3Dæå°è®¾è®¡","heading":"3Dæå°æ¨¡å"},"view_all":"æµè§æææ¨¡å"},"search_dropdown":{"ai_cards":{"image_to_3d":{"description":"å°å¾å转æ¢ä¸º3D模å","title":"å¾å转3D"},"text_to_3d":{"description":"æè¿°æ¨çåæä»¥å建3D模å","title":"ææ¬è½¬3D"}},"ai_section_title":"ç¨AIå建","aria_label":"æç´¢å»ºè®®","columns":{"cg":{"search_label":"å¨3D模åä¸æç´¢","title":"3D模å"},"print":{"search_label":"å¨3Dæå°ä¸æç´¢","title":"3Dæå°æ¨¡å"}}},"sell":{"info-section__heading_html":"\u003cstrong\u003eéå®\u003c/strong\u003eæ¨ç3D模åï¼å¹¶å¯»æ¾ç¹çº¦é¡¹ç®","info-section__icon-list_1":{"description":"åºå®æ¨ç3D模åï¼å¹¶èµåé«è¾¾85%çç¹è®¸æä½¿ç¨è´¹","link":"åºå®3D模å"},"info-section__icon-list_2":{"description":"ä¸ä¼ä¸å®¢æ·åä½","link":"è·å¾èµæ ¼"},"info-section__icon-list_3":{"description":"å¤å
æ¨çæè½å¹¶è·å¾é«è¾¾95%çç¹è®¸æä½¿ç¨è´¹","link":"æµè§3D建模工ä½"},"info-section__icon-list_4":{"description":"æå»ºèªå·±çç»å并使å
¶å¯è§","link":"æµè§3D设计å¸"}},"seo":{"description":"æ¢ç´¢2,390,000个å¨çº¿3D模åï¼éç¨äºæå°ã游æãVR/ARå设计项ç®ãå¨CGTraderä¸ä¸è½½ãå®å¶æéä½£3Dä¸å®¶ã","title":"CGTrader - 3D模åå3Dæå°å¸åº"}}},"homepage":{"budget_counter":{"range_0_10":"10ç¾å
以ä¸","range_10_20":"10ç¾å
- 20ç¾å
","range_20_15000":"20ç¾å
以ä¸"},"quotes":{"quote_0":{"author":{"name":"è¡å®Â·å¡æ´æ¯Â·å¸é¨å°¼æ¯","username":"CGShape"},"text":"ä»é宿¹æ¶åçä½£éè¶ä½ï¼å¯¹è´ä¹°æ¹æ¥è¯´ä»·æ ¼å°±è¶å¥½ãæ¥çå¹¶æ¯è¾CGTraderåå
¶ä»ååºçä»·æ ¼ã"},"quote_1":{"author":{"name":"è¡å®Â·å¡æ´æ¯Â·å¸é¨å°¼æ¯","username":"CGShape"},"text":"CGTraderææ¾èçä¼å¿æ¯æä¾é«åæ¥çåºå®è´¹ç¨æ¿æ´»ç³»ç»ãä½ ä»¬ä¸ä¼å¯¹æä»¬çéå®é¢æ¶åä½£éãåºå®äº§ååï¼æä»¬å¯ä»¥å¾å°100%ä»·æ ¼çæ¶å
¥ãåªæå½æä»¬æ³ç»§ç»éå®è¯¥äº§åæ¶ï¼æä»¬æéè¦æ¯ä»5ç¾å
忬¡æ¿æ´»å®ãå®ç¾çè§£å³æ¹æ¡ã"},"quote_10":{"author":{"name":"Threedè¯","username":"3DKen"},"text":"åºå®æ¶è´¹æ¿æ´»ç³»ç»é常巧å¦ãææ³ç¥é为ä»ä¹ä»¥å没人æ³å°è¿ä¸ªãå¨éå®äº§åä¹åï¼éè¿æ¯ä»ä¸äºé±æ¥æ¿æ´»äº§åãè¿æ ·åå®¶å°±å¯ä»¥å®å
¨ææ§ã"},"quote_11":{"author":{"name":"å¸å¾·Â·èå
","username":"sidnaique"},"text":"CGTraderæä¸¤ä¸ªä¸è¥¿ææå欢ãé¦å
ï¼è¿é没æä»»ä½éèçä¸è¥¿ï¼ä½ ä¸éè¦å°å¿CGTraderã第äºï¼è¿å®¶ååºæ¯ç±èºæ¯å®¶åèºæ¯å®¶å¼çï¼ä»ä»¬æ´äºè§£ä½ ã妿æä»ä¹äºå°æ°çä½ ï¼é£å°±è®©ä»ä»¬ç¥éï¼ä»ä»¬ä¼ä¿è¯ä½ å¨è¿éæå°é常èéã"},"quote_12":{"author":{"name":"å¸å¾·Â·èå
","username":"sidnaique"},"text":"åºå®æ¶è´¹æ¿æ´»ç³»ç»æ¯æå¥½çï¼ï¼è³å°ææ²¡æéå°æ¯è¿æ´å¥½çï¼ãè¿å¯¹åæ¹æ¥è¯´æ¯é常ç°å®åå
¬å¹³çãä»ä»¬ä¸å¨ä¹ä½ èµå¤å°é±ï¼åªè¦ä»åºå®ç§éå°±è¡äºãä½å¦æä½ 没æä»»ä½éå®ï¼ä½ ä¹ä¸å¿
æ¯ä»ç§éãå
¬å¹³çCGè´¸æå°±å¨è¿éï¼"},"quote_13":{"author":{"name":"è±æå¾·ç½Â·è¨å诺","username":"leansaler"},"text":"CGTraderçè³å¸å¼äºåå±ä¸å½å®¶ç客æ·ï¼å ä¸ºä»·æ ¼æ¯å
¶ä»ååºä¾¿å®ãåæ¶ï¼ä½è
å¯ä»¥èµæ´å¤çé±ï¼å 为ä¸åå¨é«ä½£éççé®é¢ãè¿æ¯ä¸ä¸ªæ£ç¡®çæ¹å¼æ¥ä¸º3Dèºæ¯å®¶çå·¥ä½å®ä»·ã"},"quote_14":{"author":{"name":"è±æå¾·ç½Â·è¨å诺","username":"leansaler"},"text":"åå¸è
çç´è§çé¢ååæ°å·¥å
·ï¼å¦æ ç¾æ¨èåçµæ´»çæè¿°è¡¨æ ¼ï¼ä½¿åå¸è¿ç¨ç®åå¿«æ·ã"},"quote_15":{"author":{"name":"åç»´å°Â·é¿å°é©¬ä½å°","username":"jvr3D"},"text":"CGTraderéå®3Dçæ¹æ³ä¸åï¼ä¸æä»¥åå¨å
¶ä»ååºé宿²¡æä»»ä½ç¸åä¹å¤ãå¨åºå®äº§ååä»5ç¾å
æ¯ä¸ªå¥½çæ³æ³ï¼å¯ä»¥è®©æå¨è¿éæä¾æä½çä»·æ ¼ãè¿ç§å·¥ä½æ¹å¼ä½¿é¡¾å®¢åèºæ¯å®¶é½åçã"},"quote_16":{"author":{"name":"åç»´å°Â·é¿å°é©¬ä½å°","username":"jvr3D"},"text":"ä¸ä¼ ç³»ç»ç®åæäºãæå¾é«å
´äºè§£å°è¿ä¸ªé¡¹ç®çå¹åè¿ä½è
æ¯å¨è®¡ç®æºå¾å½¢æ¹é¢æå¤å¹´ç»éªç人ã任使¶å彿æé®é¢ï¼CGTraderå¢éé½ä¼å¾å¿«è§£å³ã"},"quote_17":{"author":{"name":"åç»´å°Â·é¿å°é©¬ä½å°","username":"jvr3D"},"text":"CGTraderå
许æå°æçä¸ªäººèµæé¾æ¥å°æç个人ç½é¡µã妿客æ·ä¸ç¡®å®è¦è´ä¹°çååçç¹æ§æåªæ¯æ³å¯¹ååè¿è¡ä¿®æ¹ï¼å°±å¯ä»¥ç´æ¥èç³»æãå°±åå¨ä¸ä¸ªå¤§å¸åºä¸æ¥æä¸å®¶ä¸ªäººç3Dååºï¼"},"quote_2":{"author":{"name":"è¡å®Â·å¡æ´æ¯Â·å¸é¨å°¼æ¯","username":"CGShape"},"text":"æä»¬å¾å°äºCGTraderå¢éç大忝æï¼å·¥ä½äººåå¾ä¹æä¸ºæä»¬æä¾æææ¨¡åãè¿å¯¹ä¸ä¸å家徿叮å©ã"},"quote_3":{"author":{"name":"è¡å®Â·å¡æ´æ¯Â·å¸é¨å°¼æ¯","username":"CGShape"},"text":"å¨è¿ä¸ªå¹³å°ä¸æä»¬å¯ä»¥ä¸ºå®¢æ·æä¾æ´å¥½çä»·æ ¼ãä¾å¦ï¼æä»¬ææäº§
16518åçä»·æ ¼é½æ¯å
¶ä»ä»»ä½å°æ¹ä½20%ï¼ä½æä»¬ä»ç¶å¯ä»¥è·å¾æ¯å
¶ä»ååºæ´å¤ç婿¶¦ï¼"},"quote_4":{"author":{"name":"èµ«èæ¯Â·ä½©å¾·ç½è¨ç»´è¾¾å°","username":"NoneCG"},"text":"è¿æ¯è¿ä»ä¸ºæ¢æå¥½çç³»ç»ãå
¶ä»ææçå¨çº¿3Dååºé½ä¼æ¿èµ°æä»¬çé¨å婿¶¦ãè¿ä¹æ¯æä»¬ä¸å¼å§å¯¹CGTraderæå
´è¶£çåå ãå¨CGTraderä¸çä¹°æ¹å®¢æ·ç¥éï¼ä»ä»¬æä»çé±å¤§é¨åç»å°äºäº§åçä½è
ãå½ä½è
们ç婿¶¦æé«äºï¼ä»ä»¬æç»ä¼å¶ä½åºæ´å¤æ´å¥½ç模åã"},"quote_5":{"author":{"name":"èµ«èæ¯Â·ä½©å¾·ç½è¨ç»´è¾¾å°","username":"NoneCG"},"text":"CGTraderæ¯ä¸å®¶å¨çº¿3Dååºï¼ä¸ºæä»¬å¸¦æ¥äºæå¿«çéå®å婿¶¦å¢é¿ãåºå®è´¹ç¨æ¿æ´»ç³»ç»æ¯ä½ è½æ¾å°çæå¥½ççç³»ç»ï¼å 为å®å¥å±å
容åä½è
è䏿¯ä¸é´åã"},"quote_6":{"author":{"name":"RiÄardasMarozas","username":"æ¶é²è½¦"},"text":"彿çPaypal叿·æ¶å°160ç¾å
ï¼æè¿ä¸ç¥éæ¯æä¹åäºï¼å 为ä¹å仿¥æ²¡åçè¿ãä½è½¬å¿µä¸æ³ï¼è¿å¯è½æ¯æå¨CGTraderçé宿¶å
¥ï¼åæ¥è¯ææççæµæ¯å¯¹çãä¸ä¸ªææå¨Turbosquidä¸ä»¥189ç¾å
çä»·æ ¼ååºäºåæ ·ç产åï¼ä½å¨äº¤äº40%ççç¨å30%çå
¶ä»ç¨ä¹åï¼æåªæ¿å°äº52.92ç¾å
ï¼èå¨CGTraderçæ¶å
¥æ¯160ç¾å
ãèä¸å®¢æ·è¿å°ä»äº29ç¾å
ï¼æä»¥ç°å¨ææ¯ä¸ä¸ªæ£å¸¸ççæã"},"quote_7":{"author":{"name":"Threedè¯","username":"3DKen"},"text":"èµ·åæå¯¹è¿æ ·ä¸ç¬å¥½ä¹°åææçæåº¦ï¼å 为è¿å¯¹äºå¤§åå¨çº¿3Dååºæ¥è¯´å¹¶ä¸æ£å¸¸ã彿äºè§£å°åºå®æ¶è´¹æ¿æ´»ç³»ç»æ¶ï¼æå¯¹è¿ç§é宿°åèµäº§çåææ¹å¼å°è±¡æ·±å»ã产ååºå®åï¼ç¶åæ¯ä»5ç¾å
çæ¿æ´»è´¹ç¨ãè¿å¯¹æå¤ªææä¹äºãæä¸ä¼ äºä¸äºä½åè¿è¡å°è¯ï¼ççï¼å½æååºç¬¬ä¸åæ¶ï¼ææ¿å°äºå
¨é¨ä»·æ ¼çæ¶å
¥ï¼"},"quote_8":{"author":{"name":"Threedè¯","username":"3DKen"},"text":"æä¹ æ¯äºå
¶ä»ç½ç«æ¶å30%-60%çä½£éï¼ç´å°æåç°äºCGTraderãä½ä¸ºä¸ä¸ªåå®¶ï¼æå¤ªåæ¬¢é«æ¯ä¾ççç¨åæ¥äºã"},"quote_9":{"author":{"name":"Threedè¯","username":"3DKen"},"text":"åå®¶çä½éªçç太æ£äºãæäº¤äº§åå¾å®¹æãèä¸ç³»ç»å
许æå¨æ¯ä¸ªé¶æ®µä¿å产åæäº¤çè稿ã"}}},"hyperwallet":{"failed_payment_agreement":"åçäºæå¤é误","success_notification":"æ¯ä»å议已æåæ´æ°ã","success_payment_agreement":"æ¯ä»å议已æåæäº¤ã"},"item-search-filters":{"3d-models-url":"3d-models","3d-print-models-url":"3d-print-models","dedicated-search-page-url":{"animated":"/animated-","free":"/free-","low_poly":"/low-poly-","pbr":"/pbr-","rigged":"/rigged-"}},"items":{"already_purchased":"æ¨å·²ç»è´ä¹°äºæ¤ååã","filters":{"attributes":"屿§","free":"èªç±","max_value":"$ 500+","min_value":"$ 2","reset":"å¤ä½è¿æ»¤å¨"},"footer":{"next":"ä¸ä¸ä¸ª","per_page":"æ¯é¡µï¼","previous":"以å"},"geometry_type_forbidden":"å ä½ç±»åè¢«ç¦æ¢ï¼","last_card":{"button_text":"è¦æ±èªè®¢ç3D模å","text":"æ¾ä¸å°ä½ å¨å¯»æ¾ä»ä¹ï¼"},"migrations":{"errors":{"invalid_owner":"æ°ææè
æ æ³æ¥ç®¡ç©åã","unpublished_items":"ææç©åå¿
é¡»åå¸ã"}},"new_price_applied":"æ°ä»·æ ¼å·²æååºç¨äºææååã","new_price_applied_to_selected_items":"æ°ä»·æ ¼å·²æååºç¨äºæéååã","new_prices_to_filtered_models":"æ°ä»·æ ¼å·²æååºç¨äºææçéçååã","order_processed":"订åå·²å¤çã","order_processing":"订åå¤çä¸ã","something_went_wrong":"åºç°é误","title_error":"æ é¢ä¸åºå
å«éæä¸ç¬¦å·","uniq_user":"å·²ç»ä¸ºè¯¥ååæäº¤äºä½¿ç¨æ¡ä¾","upload_error":"ä¸ä¼ é误ã","validate_license_for_zero_price":"对äºå
è´¹ååæ æ","validate_minimum_price":"åºä»·ä¸å¾ä½äºåä»·ç 50%","verify_printable_formats_error":"请è³å°ä¸ä¼ ä¸ä¸ª .stlã.obj æ .wrl æä»¶ã","you_can_not_delete_models":"æ¨ä¸è½å 餿¨¡å"},"jobs":{"about":{"hire_designers_page":{"hero":{"description":"3D Projects 让æ¨å³å¯éä½£ä¼è´¨ç 3D èªç±èä¸èºæ¯å®¶ï¼è§£å³ææå»ºæ¨¡é¾é¢ã","heading_html":"ä½éªæä½³èªç±èä¸å¹³å°ï¼è½»æ¾åºå¯¹æ¨ç\u003cstrong\u003e3D建模项ç®\u003c/strong\u003e"},"sections":{"call_to_action":{"description":"å
è´¹å叿¨ç项ç®ï¼ççéè¿3D项ç®è§£å³ä¸ä¸ä¸ªå»ºæ¨¡æææå¤å®¹æã","title":"ç«å³éä½£æä¼ç§ç3D人æï¼"},"freelancer_selection":{"title":"让æ¨çä¸ä¸ä¸ª3Dé¡¹ç®æå","widest_selection":{"description":"ä¸è¦æ»¡è¶³äºæ´å°ãCGTraderæ¥æ40,000åèªç±3D设计å¸ï¼æ¯ä¸ä¸ä¸äººæå¯¹æ¥çæå¤§å¹³å°ï¼å»ºæ¨¡å¸ãå¨ç»å¸ãç»å®å¸ã3Dæå°ä¸å®¶çã","title":"æå¹¿æ³ç3Dèªç±èä¸è
éæ©"}},"how_it_works":{"steps":{"describe":{"description":"åè¯æä»¬æ¨çéæ±ã
16518ä½¿ç¨æä»¬çç®åè¡¨æ ¼ï¼æ·»å å¾çï¼å¹¶å¨å åéå
åå¸èªç±èä¸éæ±ã","title":"æè¿°æ¨ç项ç®"},"pay":{"description":"å®å
¨å°å°é¢ç®é¢ä»ç»CGTraderï¼è®©æ¨çèªç±èä¸è
ç¥éæ¨å·²åå¤å¥½å¼å§ãéè¿ä¸ç¨å·¥ä½åºè天ãå
±äº«é件忥ç项ç®è¿åº¦ã对æç»ç»ææ»¡ææ¶éæ¾ä»æ¬¾ã","title":"ä¸ºç»æä»æ¬¾"},"select":{"bullets":["ç´æ¥å¨æ¶ä»¶ç®±æ¶å°åæ ¼è®¾è®¡å¸çæ¥ä»·","ä¸è®¾è®¡å¸å®æ¶è天","æµè§ä»ä»¬ä»¥åç项ç®","æ¨è¿å¯ä»¥æ ¹æ®3Dæè½ãè¯ååè½¯ä»¶ææ ¼å¼å好æç´¢ãçéå¹¶é请èªç±èä¸è
"],"title":"éæ©æä½³èªç±èä¸è
"}},"title":"ç¨3个ç®åæ¥éª¤å®æä»»å¡"},"payment_quality":{"description":"CGTraderç¡®ä¿èªç±è䏿å¡ç¬¦åæ¨çè¦æ±å¹¶ææ¶äº¤ä»ãæä»¬çQAå¢ééæ¶ä¸ºæ¨æä¾æ¯æã","title":"åè´¨ä¿è¯"},"secure_payments":{"description":"æä»¬çæç®¡æå¡æå³çæ¨çèµéåå°ä¿æ¤ï¼åªæå½æ¨å¯¹æç»ç»ææ»¡ææ¶æä»æ¬¾ã","title":"å®å
¨æ¯ä»"},"workspace_convenience":{"description":"å¿æå¨æ ç¾åå·¥å
·ä¹é´åæ¢ç麻ç¦ãéè¿ä¸ç¨å·¥ä½åºï¼æ¨å¯ä»¥å¨ä¸ä¸ªå°æ¹è½»æ¾ç®¡çææå
容ï¼å¤ä¸ªé¡¹ç®ãå票ã对è¯ãæä»¶å
±äº«çã","title":"åå±ä¾¿æ·"}},"shared":{"post_project_cta":"åå¸é¡¹ç®"}},"navigation":{"find_jobs_cta":"寻æ¾3Då·¥ä½","hire_freelancers_cta":"éä½£3Dèªç±èä¸è
","how_it_works":"å¦ä½è¿ä½","why_projects":"为ä»ä¹éæ©3D项ç®"}},"agreed_to_terms_of_use":"æ¨å¿
é¡»åæ 3D Projects çæ¡æ¬¾åæ¡ä»¶æè½ç»§ç»ã","budget_error_message":"太é«","check_designer_uniqueness_error":"设计å¸åªè½è¢«éè¯·ä¸æ¬¡","check_ownership_error":"é请è
并䏿¥æè¯¥é¡¹ç®","check_status_error":"设计å¸åªè½è¢«é请å°å·²æ¹åç项ç®ã","deadline_error_message":"æªæ¢æ¥æå¿
é¡»æ¯æªæ¥æ¶é´","discount_code_error":"æ±æï¼ææ£ç ä¸åå¨æå·²è¿æã","email_subject":"3Dé¡¹ç®æºä¼: %{subject}","error_check_application_uniqueness":"æ¨åªè½ç³è¯·ä¸æ¬¡","error_check_applier":"æ¨ä¸è½ç³è¯·èªå·±ç3D项ç®","error_check_job_availability":"ç¨æ·æ æç³è¯·","error_check_job_status":"项ç®ç³è¯·å·²æåï¼ç´å°æä»¬çæ°å®¡æ ¸æµç¨å®æï¼é常å¨3ä¸ªå·¥ä½æ¥å
ãæè°¢æ¨ççè§£ï¼","modeling_request_failed":"建模请æ±å¤±è´¥ï¼","offer_has_been_sent":"æè°¢æ¨ï¼æ¨çæ¥ä»·å·²åéï¼","offer_is_closed":"æ¥ä»·å·²å
³éã","payment_successful":"æ¯ä»æå宿ã","payment_under_review":"æ¯ä»æ£å¨å®¡æ ¸ä¸ã","share_with_yourself_error":"ä¸å
许ä¸èªå·±å享âéç¨æâæ¨¡æ¿","system_messages":{"buyer_cancels_job":"项ç®å·²åæ¶å¹¶ç§»è³ %{archive_url} æ ç¾é¡µã","buyer_edits_hire_me_template":"项ç®è¯¦æ
å·²ç±å®¢æ·æ´æ°ã","buyer_edits_job_details":"项ç®è¯¦æ
å·²æ´æ°ã","buyer_marks_job_as_finished":"项ç®å·²æ è®°ä¸ºå®æå¹¶ç§»è³ %{archive_url} æ ç¾é¡µã","buyer_marks_job_as_finished_with_resell":"客æ·å°é¡¹ç®æ è®°ä¸ºå®æï¼å¹¶å
许æ¨å¨CGTraderä¸åºå®ææã请å¡å¿
\u003cb\u003e\u003ca href=\"/profile/upload/model\"\u003eä¸ä¼ \u003c/a\u003e\u003c/b\u003eåå»ºçæ¨¡åï¼","buyer_negotiates":"客æ·ååäºæ¨çæ¥ä»·ã","buyer_pays_for_the_job":"项ç®å·²é¢ä»å¹¶ç§»è³ %{in_progress_url} æ ç¾é¡µã","designer_accepts_changes":"设计å¸å·²å®¡æ ¸æ´æ°ç详æ
ã","designer_accepts_offer":"è®¾è®¡å¸æ¥åäºæ¨çæ¥ä»·ã","designer_edits_offer":"设计å¸ä¿®æ¹äºä»çæ¥ä»·ã","designer_negotiates":"设计å¸ååäºæ¨çæ¥ä»·ã","designer_withdraws_offer":"è®¾è®¡å¸æ¤åäºä»çæ¥ä»·ã","job_expires":"项ç®å·²è¿æå¹¶ç§»è³ %{archive_url} æ ç¾é¡µã"},"template_error":"æªå建任ä½é¡¹ç®ï¼","user_not_exists":"使ç¨è¯¥ç¨æ·åçç¨æ·ä¸åå¨ã","want_that_job":"ææ³è¦è¿ä»½å·¥ä½ï¼"},"kodama":{"invalid_request":"æ æè¯·æ±ï¼"},"landing":{"consent_not_saved":"åææªä¿å","failure_notification":"ææå¿
å¡«ç API 访é®è¯·æ±å段é½å¿
é¡»ææã","success_notification":"æè°¢æ¨ç请æ±ãæä»¬ä¼å°½å¿«ä¸æ¨èç³»ã"},"layout":{"chunk_load_notice":"å è½½æ¤é¡µé¢æ¶åºç°é®é¢ï¼è¯·å·æ°é¡µé¢ã","cookies_policy":{"accept":"æ¥å","learn_more":"å¦å°æ´å¤","text":"æä»¬çç½ç«ä½¿ç¨Cookiesæ¥æ¶éç»è®¡è®¿é®è
æ°æ®å轨éçç¸äºä½ç¨ç´æ¥è¥éä¼ æ/æ¹è¿æä»¬çç½ç«ï¼å¹¶æ¹åæ¨çæµè§ä½éªã请åé
æä»¬çCookieéç¥æå
³Cookieçä¿¡æ¯ï¼ä»ä»¬æ¶éçæ°æ®ï¼è°å¯ä»¥è®¿é®å®ä»¬ï¼ä½ çæå©ã"},"translations_notice":{"cta":"åæ¢å° English","text":"ä½ å¥½! æä»¬æ£å
16518¨ç¿»è¯CGTrader. ä½ å¥½! æä»¬æ£å¨ç¿»è¯CGTrader. æ£å¨è¿è¡ç¿»è¯, æäºé¨åå¯è½æ²¡æä¸æ."}},"model":{"already_purchased":"æ¨å·²è´ä¹°æ¤äº§åãæ¨å¯ä»¥ä»\u003ca href='/profile/cart/purchased'\u003eè´ç©è½¦\u003c/a\u003eä¸è½½ã妿éè¦ï¼æ¨å¯ä»¥å次è´ä¹°ã","animated":"å¨ç»","artist_profile":"èºæ¯å®¶ç®ä»","author":"ä½è
","author_get_your_payment":"ä½è
å°è·å¾æ¨æ¯ä»éé¢ç100%ãCGTraderæ¯æèºæ¯å®¶èµåæé«æ¶å
¥ï¼å¹¶é¼å±éå®é«è´¨éå
容ã","author_products":"æ´å¤æ¥èª \u003ca href=\"%{author_url}\"\u003e%{username}\u003c/a\u003e ç产å","authorised_seller":"CGTrader认è¯åå®¶","authority":"æé","breadcrumb":{"3d_models":"3D模å","home":"é¦é¡µ"},"bulk_download":{"download_all":"ä¸è½½æææä»¶","files_included":{"one":"å
å« %{count} 个æä»¶","other":"å
å« %{count} 个æä»¶"},"too_large":"æ¤æ¨¡åè¿å¤§ï¼æ æ³ä½ä¸ºå个å缩å
ä¸è½½ï¼è¶
è¿ %{limit}ï¼ã请åç¬ä¸è½½å个æä»¶ã"},"buy":"è´ä¹°","cannot_download":"ä»
æ¥æ%{experience_needed}声æç§¯åçç¨æ·å¯ä»¥ä¸è½½è¶
è¿%{models}个å
费模åãäºè§£æ´å¤ç级å声æä¿¡æ¯ï¼è¯·\u003ca href='%{reputation_url}' target='_blank'\u003eç¹å»è¿é\u003c/a\u003eã","collection":"3Dèµæºå
","contact_author":"èç³»ä½è
","description":"æè¿°","download":"ä¸è½½","download_limit_exceeded":"æ¨å·²è¶
åºæ¯æ¥ä¸è½½éå¶ã请æå¤©åè¯ãæ¤éå¶ä¸éç¨äºè¿å»12个æå
æè´ä¹°è®°å½çç¨æ·ã","download_modal":{"chat_with_us":"å¨çº¿å¨è¯¢","contact_support":"请éè¿è天èç³»æä»¬ã","download_file":"ä¸è½½ %{name}","empty":"æªæ¾å°ä»»ä½æä»¶","generic_error":"åºäºç¹é®é¢ï¼è¯·éè¯","link_error":"徿±æï¼æ¨çä¸è½½é¾æ¥ä¼¼ä¹åºç°äºä¸ç¹é®é¢ã","pbr_ready":"æ¯æ PBR","preparing":"æ£å¨åå¤ä¸è½½...","title":"ä¸è½½æä»¶"},"format_downloads":"3Dè½¯ä»¶æ ¼å¼ä¸è½½","game_ready":"游æå°±ç»ªï¼ä½å¤è¾¹å½¢ï¼","geometry":"å ä½ç»æ","license":"许å¯è¯","make_offer":"åºä»·","materials":"æè´¨","messages":{"no_files":"没æä¸ä¼ çæä»¶","no_rating":"æ¤æ¨¡åå°æ è¯å"},"model_details":"3D模å详æ
","pbr_textures":"PBRè´´å¾","plugin_used":"使ç¨çæä»¶","polygons":"å¤è¾¹å½¢","price":"ä»·æ ¼","print_ready":"3Dæå°å°±ç»ª","product_id":"产åID","product_support":"äº§åæ¯æ","product_type":"产åç±»å","published":"å叿¥æ","rated":{"error":"æ¨å·²å¯¹è¯¥æ¨¡åè¯å","success":"æè°¢æ¨ä¸ºæ¤æ¨¡åè¯å"},"rating":"3D模åè¯å","ratings":{"desc":{"negative":"è´ä¹°è¯¥3D模åçç¨æ·è®¤ä¸ºè´¨éä½äºé¢æ","positive":"è´ä¹°è¯¥3D模åçç¨æ·è®¤ä¸ºè´¨éè¯å¥½"},"negative":"è´é¢è¯ä»·","positive":"æ£é¢è¯ä»·"},"recently_viewed_models":"æè¿æµè§ç模å","renderer":"渲æå¨","report":"举æ¥","rigged":"ç»å®","scripts-plugins":"èæ¬åæä»¶","similar_models":"ç¸ä¼¼æ¨¡å","statistics":"ç»è®¡","subscription":{"limit_reached":"æ¨å·²è¾¾å°æ¬è®¡è´¹å¨æçä¸è½½ä¸éã","limit_reached_detailed":"æ¨å·²è¾¾å°æ¬æ%{limit}次ä¸è½½ä¸éãæ¨çéå¶å°äº%{reset_date}éç½®ã å¦éç«å³ä¸è½½æ´å¤æ¨¡åï¼æ¨å¯ä»¥åç¬è´ä¹°ã","limit_reached_detailed_no_date":"æ¨å·²è¾¾å°æ¬æ%{limit}次ä¸è½½ä¸éã å¦éç«å³ä¸è½½æ´å¤æ¨¡åï¼æ¨å¯ä»¥åç¬è´ä¹°ã"},"tags":"æ ç¾","textures":"è´´å¾","title":"%{item_title} 3D模å","unwrapped_uvs":"å±å¼UV","uv_mapping":"UVæ å°","vat_notice":"ææä»·æ ¼åä¸å«å¢å¼ç¨","version":"çæ¬","vertices":"é¡¶ç¹","vr":"VR 模å"},"models":{"error":{"cannot_be_blank":" ä¸è½ä¸ºç©ºã"}},"navigation":{"3d-models":{"3d-printing":"3Dæå°æä»¶","discounts":"ææ£","find_designers":"å¯»æ¾æå¥½ç设计å¸","free":"å
è´¹ç3D模å","pbr":"åºäºç©ç渲æ","scanned_3d-models":"æ«æç3D模å","scripts_apps":"èæ¬ååºç¨","show-all":"æ¾ç¤ºææ","textures":"纹ç","title":"3D模å","vr_low-poly":"èæç°å® /ä½å¤è¾¹å½¢"},"already_added_message":"å·²ç»è¢«æ·»å å°è´ç©è½¦","already_purchased_message":"æ¨å·²ç»è´ä¹°æ¤äº§åã","aria":{"account":"è´¦æ·","cart":"è´ç©è½¦","close_menu":"å
³éèå","logo":"CGTrader - 3D模å / 3D设计å¸","messages":"æ¶æ¯","notifications":"éç¥","open_menu":"æå¼èå","search":"æç´¢","search_by_image":"ä»¥å¾æç´¢"},"budgets":{"below_10":"ä½äº$10","collections":"ç»åå
","free":"å
è´¹","more_than_20":"è¶
è¿$20","more_than_50":"è¶
è¿$50","sale":"ä¿éä¸","subscription":"订é
"},"cart_limit_reached":"æ¨çè´ç©è½¦å·²è¾¾å°500ä»¶ååçéå¶ãè¦ç»§ç»è´ç©ï¼è¯·å®æå½å订åï¼ç¶å为å
¶ä»ååå¼å§æ°è®¢åã","cart_widget":{"continue_shopping":"ç»§ç»è´ç©","discount":"ç¨ä¼æ å¸çä¼ä¸ï¼","discount_applied":"å·²åºç¨ææ£ï¼","final":"æç»ä»·æ ¼ï¼","have":"ä½ æ","items":" 卿¨çè´ç©è½¦ä¸çååã","left_to_unlock_discounts":"è¿å·® {{leftToUnlock}} å³å¯è§£éææ£","potential_discount":"æ½å¨ææ£ï¼","proceed":"è¿è¡ç»ç®","recently_viewed_empty_text":"å¼å§æ¢ç´¢ï¼æ¨æè¿æ¥ççåå伿¾ç¤ºå¨è¿éã","recently_viewed_empty_title":"è¿éè¿æ²¡æå
容","recently_viewed_tab":"æè¿æ¥ç","remainer":"è¦æ¿æ´»CGTrader积åï¼è¯·æ·»å ï¼","sale_discounts":"ææ£åºç¨ï¼","sale_time_left":"å©ä½æ¶é´","sale_tooltip":"æä»¬ä¿éæ´»å¨çææ£ä»
卿¨çè´ç©è½¦è¾¾å° ${{threshold}} æä»¥ä¸æ¶æä¼åºç¨ã","sale_tooltip_text":"æ¤å忣å¨ä¿éï¼ä½åªæå½æ¨çè´ç©è½¦å°è®¡è¾¾å° ${{threshold}} æä»¥ä¸æ¶æä¼åºç¨ææ£ã","text":"ä½ çè´ç©è½¦æ¯ç©ºçã","title":"è´ç©è½¦","total":"æ»ï¼","used":"积å使ç¨ï¼","view":" æ¥çè´ç©è½¦","wishlist_empty_text":"å¼å§æ¢ç´¢å¹¶æ¶èæ¨å欢çåå â å®ä»¬ä¼æ¾ç¤ºå¨è¿éã","wishlist_empty_title":"æ¨çå¿æ¿åæ¯ç©ºç","wishlist_tab":"å¿æ¿å"},"community":{"awards":"设计å¸å¥é¡¹ ð","blog":"å客","challenges":"ææ","community_ratings":"社åºè¯çº§","designers":"3D设计å¸","digital_art":"æ°åèºæ¯å¤§èµ","forum":"论å","galleries":"ç»å»","invite":"é请æå","printlist":"3DçprintList","sell_3d-models":"åºå®3D模å","title":"社åº","tutorials":"æç¨"},"conversations_widget":{"conversations":"对è¯","messages":{"loading":"å è½½æ¶ä»¶ç®±"},"types":{"cgtrader_support":"CGTraderæ¯æ","file_conversion_request":"æä»¶è½¬æ¢è¯·æ±","job_application":"ä¸ç»´å·¥ç¨","model_feedback":"产ååé¦","model_support":"模åçæ¯æ","offer":"æ¥ä»·","personal":"ä¸ªäººæ¶æ¯","promotions":"ä¿é"}},"create_ai":{"community_gallery":"社åºç»å»","free_trial":"å
è´¹è¯ç¨","generate_3d_model":"çæ3D模å","generation":{"dismiss":"å
³ééç¥","error_title":"çæé®é¢","generating_title":"æ£å¨çææ¨ç3D模å","open_model":"æå¼æ¨¡å","ready_title":"æ¨ç3D模å已就绪ï¼"}},"create_with_ai":"使ç¨AIå建","credits_guest_widget":{"create":"ç°å¨åå»ºå¸æ·ï¼","discount":" ææ£","for":"为æ¨","get":"å¹¶è·å¾é«è¾¾ ","learn_more":"äºè§£æ´å¤å
³äºCGTraderå¿ è¯å¦å ","link":"è¿é","purchase":"ç¬¬ä¸æ¬¡è´ä¹°ï¼","sign-up":"注å","text_below_1":"积åå¯ä»¥å¨è´ä¹°æ¶â使ç¨","text_below_2":"âç¾ç½²æ å¿ç模å¼åè¦çå°ä»·æ ¼ç30ï¼
ææ£ã"},"credits_user_widget":{"condition_1":"CGTrader积åå¯ç¨äºè´ä¹°æ æ\u003ci class=\"custom-font-icon custom-font-icon--small icon-wallet\"\u003e\u003c/i\u003eæ å¿ç模åï¼å¯äº«åé«è¾¾30%çææ£ã","condition_2":"积ååªè½å¨è´ç©è½¦æ»ä»·å¼è¾¾å°\u003cstrong\u003e$%{minimum}\u003c/strong\u003eæä»¥ä¸æ¶ä½¿ç¨ã","condition_3":"å¨ä¿éæ´»å¨æç¹ä»·é宿é´ï¼ç§¯åæ æ³ä½¿ç¨ã","condition_4":"请注æï¼ç§¯åææææ - æ¨ç积åå°å¨\u003cstrong\u003e%{days}\u003c/strong\u003e天åè¿æã","earn_rate":"ä¿¡ç¨èµåç","first_text_1":"è®¤ä¸ºè¿æ¯ä¸ä¸ªç¤¼ç©éç»ä½ çç¬¬ä¸æ¬¡è´ä¹° - ä½ å¯ä»¥ä½¿ç¨ç§¯åè´ä¹°æ¶â","first_text_2":" âæ æ¨¡åï¼å¹¶å¾å°äºå®çä»·æ ¼ç30ï¼
ç伿 ãå¦æä½ çè½¦çæ»ä»·å¼çäºæé«äº$ çæ´å¤§çå¦åæè½ä½¿ç¨ã","important":"éè¦ï¼","learn_more":"å¦å°æ´å¤","lifetime_spending":"ç»èº«æ¯åºï¼","list_item":"éè¿å¯¹CGTraderå¢å ä½ ä¸ççæ¶è´¹ï¼ä½ çä¿¡ç¨èµåçä¹å¢å ã","message":" 积åä¸è½å¨é宿´»å¨ä¸ä½¿ç¨ï¼ä½ä½ ä»ç¶å¯ä»¥å¢å ä½ çæææ°´å¹³ï¼å¹¶æ¶éæ´å¤å¦åæ¨ä¸æ¬¡è´ä¹°ã","more_credits":"å¦ä½è·å¾æ´å¤ç积åï¼","next_level":"ä¸ä¸çº§ï¼","notice":"注æï¼CGTrader积åå¨ä¿éæé´æ æ³ä½¿ç¨ï¼ä½ä¿éç»æåå°éæ°å¯ç¨ã䏿¤åæ¶ï¼æ¥ç3D模åçè¶
å¼ä¼æ \u003ca href=\"https://www.cgtrader.com/3d-models?sale_off=1\"\u003eè¿é\u003c/a\u003e","par_1":"ä½ æ","par_2":" CGTraderå¦åã","par_2_variation":" 卿²¡æä¿éæ´»å¨æ¶æ¨å¯ä»¥è±è´¹ç积åã","regular_text_1":"积åå¯ä»¥å¨è´ä¹°æ¶â使ç¨","regular_text_2":" âç¾ç½²æ å¿ç模ååæ©çå®çä»·æ ¼ç30ï¼
ææ£ã","title":"CGTraderå¿ è¯ææ£"},"enterprise":{"management":"3Dèµäº§ç®¡ç","title":"3Då
容å¶ä½"},"hire_a_freelancer":"è请èªç±èä¸è
","item_add_message":"å·²æåæ·»å å°è´ç©è½¦","item_restricted_message":"ç±äºå¯¹è®¾è®¡å¸æå¨å½å®¶ (RU/BY) çå¶è£ï¼æ¤ååæ æ³è´ä¹°ã","navbar":{"actions":{"new":"ææ°","top_selling":"ç
é","trending":"çé¨"},"budgets":{"below_10":"ä½äº$10","free":"å
è´¹","more_than_20":"è¶
è¿$20","more_than_50":"è¶
è¿$50","sale":"ä¿éä¸","up_to_10":"æå¤$10"}},"projects":{"3d_customs":"å®å¶3D","3d_printing":"3Dæå°","about":"å
³äº3D项ç®","browse":"æµè§é¡¹ç®","buyer_perspective":"è请设计å¸3D","for_designers":"为设计å¸","my_projects":"æç项ç®","seller_perspective":"èªç±3D项ç®","start":"å¼å§é¡¹ç®","work":"ä¸CGTraderå·¥ä½"},"sell_3d-models":"åºå®3D模å","sellers_hub":"åå®¶ä¸å¿","subscription_includes_item_message":"æ¤ååå·²å
å«å¨æ¨ç订é
ä¸ã","tooltips":{"cart":"è´ç©è½¦","conversations":"æç对è¯","discounts":"CGTraderå¿ è¯ææ£","notifications":"éç¥","publisher":"åºçè
"},"user":{"ban_notification":"æ¤ç¨æ·è´¦æ·å·²è¢«æåã请èç³»æä»¬çæ¯æå¢é以è·
16518å说æã","cannot_refer_yourself":"ä¸è½æ¨èèªå·±","email_confirmation":"æ¨ççµåé®ä»¶å°åå·²éªè¯ã","email_reconfirmation":"å·²ç»ç¡®è®¤ï¼è¯·å°è¯ç»å½","ends_at":"ç»ææ¶é´ï¼%{date}","handle_error_tfa_code_missmatch":"æ¨è¾å
¥çå®å
¨ç 䏿£ç¡®ã请éè¯ã","handle_error_tfa_code_missmatch_last":"æ¨çå®å
¨ç å·²è¿æãè¥è¦ç»§ç»ï¼è¯·ç¹å»éæ°åéé®ä»¶å¹¶è¾å
¥æ°çéªè¯ç ã","handle_error_tfa_default":"åºç°é误ï¼è¯·ç¨ååè¯ã","handle_error_tfa_expired":"æ¨çå®å
¨ç å·²è¿æã","hundred_percent_royalties_popover":"æ¨æ£å¨åä¸ä¸é¡¹ä¸´æ¶100%æ¶çæ´»å¨ï¼æææ°æ¨¡åçé宿¶å
¥å°å¨æ´»å¨ç»æåå
¨é¨å½æ¨ææ","invalid_email_message":"请è¾å
¥ææççµåé®ä»¶å°å以继ç»ã","login":"ç»å½","meta_description":"æ¥ç %{username} å¨CGTraderç3D设计å¸èµæãä½åéåå¯ç¨ç3D模åãæ¢ç´¢æ¥èªé¡¶çº§å»ºæ¨¡èºæ¯å®¶çæä½³3D模åã","meta_title_suffix":"3D设计å¸","not_valid_birthday":"åºçæ¥ææ æã","offline":"离线","online":"å¨çº¿","page_title":"设计å¸èµæ","rate_models_limit":"ä»å¤©æ¨ä¸è½åè¯ä»·æ´å¤æ¨¡åäºã","semantic_description":"设计å¸ç3D模åãèºæ¯ä½ååä½åéãæ¥CGTraderççä»çåä½","semantic_title":"设计å¸èµæ","session_failure":"æä¾çç¨æ·å/çµåé®ä»¶æå¯ç 䏿£ç¡®","session_password_expired":"ç±äºé¿æ¶é´æªä½¿ç¨ï¼æ¨çå¯ç å·²è¿æã请éè¿æä»¬åéççµåé®ä»¶é¾æ¥éç½®å¯ç ã","session_two_fa_failure":"éªè¯ç éªè¯å¤±è´¥","session_unconfirmed":"æ¨ççµåé®ä»¶å°åå°æªéªè¯ã","token_not_recognized":"æªè¯å«ä»¤ç","twitter_shareable_text":"å¼å¾å
³æ³¨ç#3dartist","username_error":"ä¸åºå
å«ç©ºæ ¼æéæä¸ç¬¦å·"},"user_menu":{"buyer":{"freelancers":"寻æ¾èªç±èä¸è
","purchases":"æçéè´","sell":"åºå®3D模å","wishlist":"ä¸ç»´æ¨¡åçæ¶è"},"dashboard":"管ç仪表æ¿","logout":"éåº","public_profile":"å
¬å¼èµæ","seller":{"analytics":"Analyticsï¼åæï¼","find_new_projects":"å¯»æ¾æ°ç3D项ç®","freelance":"èªç±3D项ç®","freelance_cgtrader":"èªç±ä¸CGTrader","models":"æç模å","publish_project":"åå¸é¡¹ç®","publishing":"åºç","sales":"æçéå®","subscription":"订é
","wishlist":"ä¸ç»´æ¨¡åçæ¶è"},"settings":"设置"}},"owly":{"failed_set_pending":"设置为å¾
å¤ç失败ã","failed_to_approve":"审æ¹å¤±è´¥ã","failed_to_suspend":"æå失败ã","failed_to_update_license":"æ´æ°è®¸å¯è¯å¤±è´¥ã","failed_to_update_status":"æ´æ°å®¡æ¹ç¶æå¤±è´¥ã"},"print_models":{"browse_all_makes":"æµè§ææ3Dæå°ä½å","browse_all_models":"æµè§æææ¨¡å","description":"åç°æµè¡ç坿å°3D模åãæå°èµæºåSTLæä»¶ï¼éç¨äºæ¸¸æãèºæ¯ãå®¶åºé¡¹ç®çã","makes_description":"æ¢ç´¢ç±ç¤¾åºä¸ä¼ çææ°3Dæå°ä½åââå±ç¤º3D模åå¨ç°å®ä¸ç䏿 ·è²ççå®ç¤ºä¾ã","makes_title":"æ°ç3Dæå°ä½å","new_description":"æ¥çæä»¬æ¶è䏿°å¢çææ°3Dæå°æ¨¡åââæ°é¢ç设计ï¼éæ¶å¯ä¸è½½å¹¶ç¨äºæ¨çä¸ä¸ä¸ªé¡¹ç®ã","new_title":"ææ°3Dæå°æ¨¡å","title":"æµè¡3Dæå°æ¨¡å"},"profile":{"account_settings":{"account":{"email":"é®ç®±","submit":"ä¿å","title":"ä¸ªäººèµæ","update":{"updated":"ä¸ªäººèµæå·²æ´æ°"},"username":"ç¨æ·å"},"email_settings":{"descriptions":{"ai_studio_notifications":"æå
³æ¨ç CGTrader AI çæçéç¥ï¼å
æ¬æ¨å°æªæå¼ç模åå·²åå¤å°±ç»ªæ¶","communication":"å
³äºæ¨ä¸å
¶ä» CGTrader ç¨æ·çéä¿¡çä¿¡æ¯ï¼å
æ¬ç§äººæ¶æ¯ãæ°ä»·æ ¼åèªå®ä¹å·¥ä½æ¥ä»·ãåé¦åäº§åæ¯æè¯·æ±","news":"å
³äº CGTrader 产åãæ°åè½å
¬ååç¤¾åºæ°é»çä¿¡æ¯","onboarding_and_edu":"å
³äºæ¨çå
¥èæµç¨å叮婿¨å
åå©ç¨ CGTrader çæç¤ºçä¿¡æ¯","push_notifications":"å
³äºéè¦è´¦æ·æ´»å¨åæ´æ°çéç¥","sales_and_offers":"å
³äºç¹å«ä¼æ ã3D 模åéå®å CGTrader å¥å±ç§¯åçä¿¡æ¯","seller_sold_item":"å
³äºæ¨åºå®ç 3D 模ååæ¶å°ç仿¬¾çä¿¡æ¯"},"privacy_policy_html":"请é
读æä»¬ç \u003ca href='https://www.cgtrader.com/pages/privacy-policy' 'target='_blank'\u003eéç§æ¿ç\u003c/a\u003e äºè§£æ´å¤ä¿¡æ¯ã ","titles":{"ai_studio_notifications":"CGTrader AI éç¥","communication":"éä¿¡ï¼ç§äººæ¶æ¯ã3D 模ååé¦ãç¤¾åºæ´»å¨ãæ¥ä»·ï¼","news":"3D æ°é» / CGTrader æ´æ°","onboarding_and_edu":"å
¥èåæè²","push_notifications":"éè¦è´¦æ·æ´»å¨åæ´æ°çéç¥","sales_and_offers":"éå®åç¹å«ä¼æ ","seller_sold_item":"éå®å仿¬¾ä¿¡æ¯"},"tracking_attributes":{"ai_studio_notifications":"CGTrader AI éç¥","communication":"éä¿¡","news":"3D æ°é» / CGTrader æ´æ°","onboarding_and_edu":"å
¥èåæè²","sales_and_offers":"éå®åç¹å«ä¼æ ","seller_sold_item":"éå®å仿¬¾ä¿¡æ¯"},"update":{"updated":"æ¨ççµåé®ä»¶å·²æåæ´æ°ã"}},"gdpr_success_notification":{"opt_in":"æè°¢æ¨ï¼æ¨å·²æåéæ°è®¢é
æä»¬ççµåé®ä»¶ã","opt_out":"æ¨å·²æååæ¶è®¢é
æä»¬çæ°é»éè®¯ãæ¨å¯ä»¥éæ¶éè¿è®¿é®æ¨çä¸ªäººèµæè®¾ç½®æ´æ¹æ¤å好ã\n"},"location_tooltip_text":"\u003cdiv\u003eæ¤å¤éæ¡å¯ç¨å¨ä¸ªäººèµæé¡µé¢æ¾ç¤ºä½ç½®ã\u003c/div\u003e \u003cdiv\u003e请注æï¼ç±äºåè§åå ï¼æ 论å¦ä½æ¨çä½ç½®é½ä¼æ¾ç¤ºç»æ¨çä¹°å®¶ï¼å¦ææ¨æ¯åå®¶ï¼ä»¥åæ¨è´ä¹°ååçåå®¶ã\u003c/div\u003e","moneybookers":{"account":"Skrill è´¦æ·"},"password":{"current_password":"å½åå¯ç ","new_password":"æ°å¯ç ","submit":"æ´æ¹å¯ç ","title":"å¯ç ","updated":"æ¨çå¯ç å·²æåæ´æ°ãæ¨ç°å¨å¯ä»¥ä½¿ç¨æ°å¯ç ç»å½ã","verify_password":"éªè¯å¯ç "},"paypal":{"account":"PayPal è´¦æ·","submit":"ä¿å","title":"PayPal 设置","update":{"updated":"æ¨ç PayPal 设置
16518å·²æ´æ°"}},"personal_info":{"areas_of_expertise":"ä¸ä¸é¢å","country":"å½å®¶","description":"å
³äºæ¨çå å¥è¯","full_name":"å
¨å","languages":"è¯è¨","preferred_tools":"é¦éå·¥å
·","submit":"ä¿å","title":"个人åä¸ä¸ä¿¡æ¯","update":{"updated":"æ¨çä¿¡æ¯å·²æåæ´æ°"},"website":"ç½ç«"},"personalization":{"no_muted_title":"没æå±è½ç设计å¸","title":"å±è½ç设计å¸","tooltip":"å表ä¸è®¾è®¡å¸ç 3D 模åå°ä»æ¨çæç´¢ç»æä¸æé¤ã","unmute_designer":{"confirm":"æ¨ç¡®å®åï¼"}},"professional_info":{"allow_private_job_requests":"ä¹°å®¶å°è½å¤åæ¨åéèªå®ä¹ 3D å·¥ä½è¯·æ±ã","buyer_engagement_program_html":"éè¿è®©å®¢æ·ä½¿ç¨ CGTrader 积åè´ä¹°æ¨çæ¨¡åæ¥å¸å¼æ´å¤å®¢æ·ã\u003ca href='https://www.cgtrader.com/pages/cgtrader-loyalty-discounts-explained' target='_blank'\u003eæ´å¤ä¿¡æ¯\u003c/a\u003e\n","pbr_program":"ä»
å½ä¸è½½è½¬æ¢æä»¶æ¶ï¼æéç¨è¾ä½çæ¶çç","pbr_program_agreement":"æ¨å·²åæäº %{date} åå PBR 计åï¼ä¸ºæ 24 个æãæå
³æ´å¤è¯¦ç»ä¿¡æ¯ï¼è¯·åé
æ¡æ¬¾åæ¡ä»¶ã妿任ä½çé®ï¼è¯·èç³»æä»¬çæ¯æå¢éã","product_analytics_participation_html":"æåä¸äº \u003ca href='https://www.cgtrader.com/profile/analytics'target='_blank'\u003eåæ\u003c/a\u003e å¹¶åæå
¶æ¡æ¬¾åæ¡ä»¶\n","product_analytics_participation_tooltip_html":"æ¨å·²åæåä¸åæå¹¶åæåææ¡æ¬¾åæ¡ä»¶ (\u003ca href='https://www.cgtrader.com/pages/cgtrader-analytics-terms-of-service'target='_blank'\u003e龿¥\u003c/a\u003e) äº %{accepted_at}ãå¦ææ¨æ³ç»æ¢åä¸ï¼è¯·èç³» CGTrader æ¯æ\n"},"security":{"allow_mfa":"å¯ç¨ä¸¤æ¥éªè¯ä»¥ä¿æ¤æ¨çè´¦æ·","use_authenticator_app":"使ç¨èº«ä»½éªè¯å¨åºç¨è¿è¡ä¸¤æ¥éªè¯","use_authenticator_app_tooltip":"ä½¿ç¨æ¨ç身份éªè¯å¨åºç¨ï¼Google Authenticator / Authyï¼æ«æäºç»´ç 以çæéªè¯ç ã","use_email":"使ç¨çµåé®ä»¶è¿è¡ä¸¤æ¥éªè¯"},"sidebar":{"general_settings":"常è§è®¾ç½®","member_since":"æ³¨åæ¶é´","paypal":"PayPal","title":"è´¦æ·ä¿¡æ¯"},"title":"æçè´¦æ·"},"conversations":{"conversations":"对è¯","messages":{"loading":"å è½½æ¶ä»¶ç®±"},"types":{"cgtrader_support":"CGTraderæ¯æ","file_conversion_request":"æä»¶è½¬æ¢è¯·æ±","job_application":"ä¸ç»´å·¥ç¨","model_feedback":"产ååé¦","model_support":"模åçæ¯æ","offer":"æ¥ä»·","personal":"ä¸ªäººæ¶æ¯","promotions":"ä¿é"}},"meta":{"description":"å¨ CGTrader 䏿¢ç´¢ %{username} çé«è´¨é 3D 模åãæµè§ç¨äºæ¸¸æãVR/AR åå¯è§åçç¬ç¹èµæºã","title":"3D 模å设计å¸ï¼%{username}"},"my_products":{"suspension_appeal":{"reasons":{"not_available":"N/A"}}},"settings_updated":"æ¨ç设置已æåæ´æ°ã"},"publishing":{"banned_error":"æ¨çè´¦æ·å åå¸åå¾å
å®¹å·²è¢«ç¦æ¢ã妿æ¨è®¤ä¸ºè¿æ¯ä¸ä¸ªé误ï¼è¯·èç³» [email protected]ã","files_not_finalized":"ä¸ä¸ªæå¤ä¸ªæä»¶å°æªå®æä¸ä¼ ï¼æ æ³åå¸ã请å é¤å®ä»¬å¹¶éæ°ä¸ä¼ åååå¸ã","spam_suspect":"æ¨çè´¦æ·æªè¢«ææå叿¤æ¨¡åã妿æ¨è®¤ä¸ºè¿æ¯ä¸ä¸ªé误ï¼è¯·èç³» [email protected]ã"},"rating":{"anonymous_buyer":"å¿åä¹°å®¶","errors":{"not_verified_buyer":"åªæç»è¿éªè¯çä¹°å®¶æè½çä¸è¯è®º"}},"routes":{"3d-models":"3d-models","3d-print-models":"3d-print-models","animated-3d-models":"animated-3d-models","discover":"faxian","free-3d-models":"free-3d-models","free-3d-print-models":"free-3d-print-models","low-poly-3d-models":"low-poly-3d-models","pbr-3d-models":"pbr-3d-models","pbr-textures":"pbr-textures","rigged-3d-models":"rigged-3d-models","search":"search"},"sale_off":{"no_overlapping_campaigns":"æ´»å¨æ¥æä¸å¦ä¸ç°æä¿éæ´»å¨éå ã","parse_discount_rules_text":"第 #{index} è¡ç¼ºå°å¿
éç 'discount:' åæ°"},"search":{"not_found":"æªæ¾å°æç´¢è®¢é
","subscription_created":"æç´¢è®¢é
å·²å建","successfully_unsubscribed":"æ¨å·²æåé订æç´¢è®¢é
"},"subscription_opt_ins":{"lock_period_error":"Some items cannot be opted out before the six-month lock period ends.","missing_items_error":"Items not found: %{items}."}
16518,"subscriptions":{"flash":{"active_subscription":"æ¨å·²ç»æ¥æææè®¢é
ã","premium_upgrade_unavailable":"åçº§å° Premium ææ¶ä¸å¯ç¨ã请ç¨ååè¯ã","update_payment_method":"æ¨ç订é
åå¨ä»æ¬¾é®é¢ãè¯·æ´æ°æ¨ç仿¬¾æ¹å¼ï¼è䏿¯è´ä¹°æ°ç订é
ã"},"payment_form":{"current_price":"%{price}","features":{"first":"æ¯æ %{downloads} ä¸ªèµæº â ä¸è½½æ¨¡åæä½¿ç¨ AI çæ","second":"峿¶è®¿é® %{models_count}+ ç²¾é 3D 模å","third":"å
çç¨ï¼æ AI"},"from_price_label":"èµ·","original_price":24.99,"per_model_label":"æ¯ä¸ªæ¨¡å","plan_name":"CGTrader Essentials 订é
â 年度计åï¼ææè®¡è´¹","premium":{"features":{"first":"æ¯æ %{downloads} ä¸ªèµæº â ä¸è½½æ¨¡åæä½¿ç¨ AI çæ","fourth":"å
çç¨ï¼æ AI","second":"峿¶è®¿é®æ»è®¡ %{models_count}+ 个å¯è®¿é®æ¨¡å","third":"Essentials ä¸ä¸å
å«çä¸ä¸çº§æ¨¡å"},"plan_name":"CGTrader Premium 订é
â 年度计åï¼ææè®¡è´¹"},"price_unit":"/æ","vat_amount":"%{vat_amount}"}},"tag":{"description":{"bottle":"ç§å¦å®¶ä»¬è¯´çè¡èé
ç¶ï¼æ¯å¤©æ¯ä¸æ¯å¯¹ä½ ä¸å¥½ï¼ä½æ¯å½æ¶åå°åå¨å£«å¿ææ³¢ææ´å¼ºç饮æï¼æä»¬ççåºè¯¥çæä»¬çé
ç²¾æå
¥éãæ¾ç¶ï¼ç»çæ¯å¡æç¶çæ°´å§é¿ç¸æ¹å¼å·å´å¨é¦æ§ï¼ä½æ³æ³æ´»æ´é¿ç使ç¨å¯¿å½åå¤é
ä¼ä¼¼ä¹æ¯ä¸ä¸ªåççºç²çå¯è½æ§ãè¿ä¸ªç±»å«æä¾ä¸ç¶3D模åçå¤ç§éæ©ï¼ä»åé
æ¶åå¼ç¶å¨äºåç±»ç¶3D模åï¼ä»æ´åæ°´å°æ©æ¦æ²¹ï¼çé
ç²¾ç¸å
³ç对象ã","brain":"å¤§èæ¯äººä½æå¤§ï¼æå¤æçå¨å®ä¹ä¸ãç±äºå
¶å¤æçç»æååè½ï¼å¤§èçè§£åç»æä¹å¾å¤æãç¶èï¼ç§å¦å®¶ä»¬æ´æ·±å
¥å°äºè§£äººç±»å¤§èçç»æï¼æç¤ºä»¤äººé¾ä»¥ç½®ä¿¡çç§å¯ã广æ³çé¼çèç»è
»ç大è3D模åå·²ç»åå¤å¥½è®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å
³ç3D设计任ä½å
¶ä»é¢åçå¯ä¾ä¸è½½ã","building":"ç®åè¿ä¸æ¸
æ¥å
¶ä¸ç°ä»£å»ºçå¸ä»ä»ä»¬ççµæï¼ä½ä¸çä¸ä¸äºèåç建çç©æ¯å¦æ¤å°ç«¯çä»ä»¬çèµ·æ¥åæ¯æ¥èªæªæ¥çæ¿æ¯ãæä»¬å¹¶ä¸ä»
ä»
æå³çå¤è¡¨é¨......å¨å¨æè½åæ åç建çæä¸ºä»¤äººæå¹ç建çåä½ä¸åæ°çå
é¥°è®¾è®¡ï¼æ è®ºå®æ¯ä¸ä¸ªåå
¬å®¤æåå¸å»ºçãæä»¬æå»º3D模åçéæ©å¯ä¾ä¸è½½ï¼å¹¶ä¸å¯ä»¥å¨å个é¢åçåºç¨ - ä¸ç»´å¨ç»ï¼å¹³é¢è®¾è®¡ï¼å¹¿åï¼3D游ææç½é¡µã","camera":"æå½±åææï¼ç®åå¨å¹´è½»äººä¸ææµè¡çèä¸é¢åä¹ä¸ï¼ä½ä¸æ¯æ¯ä¸ªäººé½ç¨ä¸ä¸æåæºæ¯ä¸ä¸ªèºæ¯å®¶ææå½±ãéçææºæå头å¨éå¹´æé«è´¨éï¼æä»¬çå°æäººæç
§çæ¯ä¸æ¥ï¼é£äºè°æ¥æäºæ°å¼åçå¾åç¼è¾æè½æ¯çæ£çåºç¥ãçæ´»çèµ·æ¥ç¡®å®æç¹ä¸åçï¼å½ä½ å¨é头çå¦ä¸è¾¹ï¼ä½æä»¬ä¸è¦å¾æå¿å½¢......ç§ç±»ç¹å¤è¯¦ç»çæå头3D模åå¯ä»¥ç±å¹³é¢è®¾è®¡å¸ï¼å¨ç»å游æå¼å人å使ç¨ä¸è½½åä¸ä¸äººå£«ç3Dç¸å
³çé¢åå·¥ä½ã","car":"ççè¿äºé常详ç»çåé«åº¦é¼çç3D车åï¼ä½ å ä¹å¯ä»¥å¬å°å卿ºç轰鸣声ï¼å¹¿æ³è½¦è¾çä¸ç»´æ¨¡åå¯ä»¥ä½¿ä½ ççæ´»å徿´è½»æ¾ï¼å¦æä½ ä¸è®¡ç®æºå¾å½¢ï¼å¨ç»æä»»ä½å
¶ä»3Dç¸å
³é¢åæ¼æã","cell":"ç§å¦å®¶ä»¬ä¼°è®¡ï¼äººä½å
å«5å亿200ä¸ä¸ªä¸äº¿ä¸ªç»èãæ¤ç©åå¨ç©æç»èäºãæä»¬ä¸æ³ç¦ä½ è¿ç§çç©çä¸è¥¿ï¼ä½å¹¿æ³çç»èçä¸ç»´æ¨¡åï¼æä»¬å·²ç»æ¶µçäºä»è¡æ¶²ï¼ç
æ¯åDNA骨é«åç»èå£ãè¿ä¸å°±æ¯......伤èçï¼","chair":"æä»¬å°±å卿¤
忝çæå½ç¶çï¼å¹¶ä¸æ»æ¯åç°ä»ä»¬æå¤ä¹çé
åå¯ä»¥æ·»å 尿们ç家䏿åå
¬å®¤å
ã主å¸å®é
䏿¯ä»»ä½å®¶åºä¸å¤®ä»¶å®¶å
·ä¹ä¸ãå¨è¿éï¼ä½ å¯ä»¥æ¾å°é«åè´¨ï¼å¯ä»¥å¨ä¸åçé¢åå¾å°åºç¨æ¢ç¼ç设计æ¤
åç3D模å - æ¥èªå¹¿ååä¸ç»´å¯è§åï¼ä»¥3D游æã","city":"åå¸çæ´»æ¯ä¸ä¸ªå¤æªç游æï¼è¡éèµè½¦åºç§è½¦ï¼ç°ä»£å»ºçï¼å¨å®å
¨éååå
¬å®¤è¡äººçè¡£æï¼ç¡è§æ¡¥æ¢åå
¬å......ä»ä¸æµ·å°çº½çº¦ï¼ï¼æ¼åé¡¿ï¼çæ£ï¼ä¼¦æ¦æå·´é» - æ¯ä¸ªåå¸é½æå
¶èªå·±åé å¥è¿¹ã广åï¼è®¡ç®æºå¾å½¢ï¼å¨ç»ï¼ä¸ç»´å¯è§åææ¸¸æ - ä½ å¯ä»¥ä»è¿ä¸ªä¸°å¯è¯¦ç»çåå¸ä¸ç»´æ¨¡åçéæ©ï¼å¯ä»¥å¨è®¸å¤é¢åç使ç¨éæ©ãæ¢ç´¢åå¸çæ´»ã","dragon":"é¾å¯è½æ¯ææµè¡ççç©çæ´»å¨å¹»æ³çä¸çãå®åç»å¨åç§æåï¼å¨ç»ï¼çµå½±å书ç±ï¼å®å·²æä¸ºä¼ 说ä¸çé£ä¹å¤çç¥è¯ãå®å°¤å
¶æ¯æ¸¸æå¼ååçåç±ï¼å 为å®å¢å äºé£ä¸ªç¥å¥çé
åé»æçæ´ç©´åå°ç¢ã广æ³çç°å®ï¼æçºµé¾3D模åå·²ç»åå¤å¥½è®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å
³ç3D设计任ä½å
¶ä»é¢åå¯ä¾ä¸è½½ã","earth":"ç»èå¨è°·æå°å¾æè¿æ·»å çå°çè§å¾æ°´å¹³éæäºè®¸å¤äººãæ¨å¯ä»¥æ¢ç´¢æ´ä¸ªå°ç - æµ·æ´ï¼å±±èåæ²æ¼ ï¼æ¢ç´¢åå¸åéè·¯éæ£ä¸ç¦»å¼ä½ çæ¿åã
16518è¿æ¯ä¸äºä¸å¯æè®®çäºæ
å°çæ¯äº²ä¹å没æç»åè¿ãç°å®çå°çä¸ç»´æ¨¡åçï¼å¯ç¨äºè®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å
³ç3D设计任ä½å
¶ä»é¢åçéæ©å¯ä¾ä¸è½½ã","engine":"æäºäººè½å¤éè¿ç®åå°å¬çå®ååºç声鳿¥å½åç弿ï¼è¿ç¡®å®æ¯æäººçãä¸ç®¡å®æ¯å·æ°å卿ºææ±½è½¦å卿ºï¼æä»¬ä½¿ç¨å¦æ¤é¢ç¹ï¼ä½ä¸è¦è±å¤ªå¤æ¶é´æèä¸ä¸ä»ä»¬ââæå
¶å¤æçæºå¨ã马达æ¯ä¸ä¸ªçµå¨æºï¼ç´å°å®åæ¢å·¥ä½ï¼ãè¿ä¸ªåç±»ä¸æåç§ä¸åç±»åçå卿º3D模åï¼èä¸è¿å
æ¬å卿ºé¨ä»¶ï¼å¦èºææ¡¨æç¼¸ï¼æä»¥æä»¬ç¸ä¿¡ï¼ä½ ä¼åç°ä½ æéè¦çã","female":"è¿å¯ä¸æ¯é¹çç©çï¼æç·æ§å女æ§ç大èä¹é´ï¼è¿æå³ç宿¯æ£å¸¸çï¼ä¸ä¸ªæ®éçç·äººå女人çè¡ä¸ºï¼ææåååºä»¥å®å
¨ä¸åçæ¹å¼æ¾èå·®å¼ã使¯ï¼è¿ä¸æ¯ææçè§£åãæ²¡æç±æ
æ
äºï¼çµå½±ææ¸¸ææå²ä»¥æ¥ä¸ææ¯ä¸æ²¡æå强ç女å©çæ§æ ¼ï¼äºä¸çæ·å¥³é
åçå鿝ä¸å¯å¦è®¤çãé¼çç女ä¸ç»´æ¨¡åç丰å¯éæ©å¯ä»¥ä¸ºæ¨æä¾ä½ éè¦çä¸å - 女æ§å¼å¸ç³»ç»ä»è£¸3D模åã","hand":"æä»¬ç¨æä»¬çåæä¸ºè¿ä¹å¤ä¸è¥¿çåå æ¯å
¶éå¡çè§£åãææåç¬ç±ä¹ä¸ªåç¬çèèæ§å¶ãå¾é¾ç¸ä¿¡ï¼ä½ä»å¤©æ©å¨ææ¯ä»»ä½ææ´å¥ç¹ç - æäºç§ç±»æä¸ä¸ªææãäººä½ææ¾èåå±ãæèææï¼å 为æä»¬çå°ä»å¤©çèµ·æ¥ä¸ç¹ä¹ä¸åå®çæ©æçæ¬ã广æ³çç°å®ï¼æçºµæç3D模åå·²ç»åå¤å¥½è®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å
³ç3D设计任ä½å
¶ä»é¢åå¯ä¾ä¸è½½ã","head":"å¨äººä½è§£åå¦ï¼å¤´é¨æ¯äººä½çä¸é¨ã建模ä¸ç»´äººä½å¤´é¨å¯ä»¥è¯ææç¹å¤æï¼å 为ï¼å³ä½¿æè¿ä¹å¤ä¸åçå½¢ç¶å大å°ï¼ï¼æä»¬å¯¹æ¤è¡¨ç¤ºèµèµå¯¹ç§°çï¼é¼çç头 - 没ææç¬çç¼çï¼è³æµï¼é¼»åï¼å´ååä¸å·´ç线æ¡ï¼è¯·ãè¸æ¯ä¸ä¸ªææçåºåï¼è¿çº¯ç²¹æ¯ç²é²æä¹è¶£è¿ä¸ç¹ãæä»¬çéæ©å
æ¬ç°å®çç·æ§ï¼å¥³æ§ï¼å¿ç«¥ï¼çè³æ
äºäººç©ååå©Â·æ³¢ç¹ä¸èè ä¾ æå汤å§Â·å
鲿¯åæ¯å丽·约翰éç头æ¯å¯ä¾ä¸è½½å人ã","helmet":"ä¸å®è¦è®°ä½ï¼å¥åº·åå®å
¨æ¯ç¬¬ä¸ä½çï¼æä»¥ä¿æ¤ä½ ç头æ¯ä¸ä¸ªå¥å
¨çæ³æ³ãä¸ä¸çºªéªå£«ï¼Daft Punkçï¼çè³é人æ´å¤´çï¼æä»¥å®æçè¶
级è±é䏿 ·éªèªè¡è½¦è
å建设è
ä¸åºè¯¥æ
å¿èªå·±ä¸å¤é
·ãå¦æä½ å¨å¹³é¢è®¾è®¡ï¼ä¸ç»´å¨ç»å¶ä½ï¼3D游ææå¯è§åé¢åå·¥ä½ç头ç3D模åçè¿ä¸ªéåï¼æ¯å¯ä¾ä¸è½½å°è¢«è¯ææ¯æç¨çã","house":"è¿æ¯ä¸ä¸ªå¤èçççï¼ä¸ä¸ªäººçå®¶å°±æ¯ä»çåå ¡ï¼ä½æ¯å½å®æ¶åå°å»ºè®¾çæ³çæ¿åæä¹°ä¸ä¸ªçæ³çå
¬å¯ï¼æä»¬ç¡®å®ä¼å¨å®å¤±å»æä»¬ç头ã幸è¿çæ¯ï¼è¿ææ¿åçä¸ç»´æ¨¡åç广æ³ï¼ä»å»ºçç»èï¼å
å¤å¢æ¶µçä¸åï¼å®¶å
·ï¼å°å¸®å©æ¨å建ç°ä»£åç3Då¯è§åï¼ä»¥ç¼è§£ç¼çã","human":"å½ä½ å¼å§æ¢ç´¢äººä½è§£åå¦ï¼ä½ æè¯å°äººæ¯è¿æ ·éç»¼å¤æçæºå¨ï¼å®éè¦ä½ çå¼å¸ãæ¯ä¸ä¸ªèº«ä½çä¸é¨åï¼èèï¼å
³èï¼å¨å®æéª¨éª¼ç»åè¿æ¥æä¸ä¸ªç³»ç»ï¼æ²¡æä»ä¹å·¥ä½å¤ç«ï¼è¿äºè¶
级é¼çç3Däººä½æ¨¡åå¯ä»¥è®©ä½ ä»å个è§åº¦å®¡è§è§£åç»æã","lamp":"å¦æä½ ççä½ çå®¶ï¼ç®ä¸åç±»ç¯å
·ï¼ä½ èªå·±çï¼ä½ 伿å¥å°åç°ï¼é
è¯»ï¼æ¡é¢ï¼å¢å£ï¼å¤©è±æ¿ï¼æ¡åï¼ä¸èæ¶ç¯......è¿æ¯è¶³ä»¥è®©ä½ 头æï¼ä¸ä¸è¯´é£æ ¼ï¼ä»ä»¬å¨æ¥ - ä»å¥¢ä¾çç°ä»£ç¯çå¤å¤æ¶å°æåå«ãå¨è¿ä¸ªç±»å«ä¸ï¼æä»¬æåç§ç¯ç3D模åï¼è®©æµè§åä¸è½½å°å¹³é¢è®¾è®¡ï¼ä¸ç»´å¯è§åæä»»ä½å
¶ä»3Dç¸å
³çé¢å使ç¨ã","light":"ä½ ææ²¡ææ³è¿ä¸ºä»ä¹ç¯æ³¡æ¯ä¸ä¸ªç»å¦ç主æç象å¾ï¼å½ç¶ï¼ä¸ä¸ªå¥½ä¸»æå¯ä»¥å¯è¿ªå¿çµçæ¶æï¼ä½ä¸æ¯å®ãè·¯ç¯ï¼ä¸çåç¯æä»»ä½å
¶ä»ç±»åçç¯å°æ°¸è¿ä¸ä¼ææºä¼éåç°åºã妿å½ä½ å¨å¤©è±æ¿æ¬å¤´ç¯çæç§å»ºçå
天æçæ³æ³ä¸æä½ ï¼è¿å¯è½æ¯å ä¸ºä½ å¨é误çéªçµç³»ç»ç¯ç......æä»¬é«åè´¨çå
çéæ©ä¸ä¸æ¬¡å¦ææ¨å¨å»ºçï¼è®¡ç®æºå¾å½¢å¦ï¼3Då¨ç»å设计é¢åå·¥ä½ç3D模åå°è¯æå¾å¿åºæã","machine":"è¯æ³ä¸ä¸ï¼å¦æææçæºå¨çªç¶åæ¢å·¥ä½ï¼æ²¡æåå¡ï¼æ²¡ææ¹ä¾¿æ´è¡£ï¼æ²¡æç°éç¹å¨å¤§è¡ä¸ï¼ä¸ä¸ªè§è½æ²¡æå¥èº«æ¿çæ¶é´ï¼æ²¡æé«ä¼°èªå¨å®è´§æº......è¿å¬èµ·æ¥ä»¤äººæ²®ä¸§ï¼ä¸æ¯åï¼æä»¬å·²ç»ä¹ æ¯è¿äºå®¶ç¨çµå¨åçµå产åï¼å®ä¼ä»åé¢ä¸é»æ¢ä¸ç转å¨ï¼å¹¸è¿çæ¯ï¼æä»¬éæ©çè¯¦ç»æºå¨ç3Dæ¨¡åæ¶µçäºä»æºæªå°åçµæºï¼å°è¯æä¸è®¡ç®æºå¾å½¢ï¼å¹¿åï¼3Då¨ç»ï¼3D游ææç½é¡µè®¾è®¡å¸çå·¥ä½é常æç¨ã","man":"ç·äººç3D模åçåºå¤§éåå¯ä¾ä¸è½½ãåå¨ç·äººï¼ç®åç人ï¼é£è¡çäººè¿æ¯æ®éäººï¼æä»¬å°±æ¥æäºä¸å - é¤äºå®ç¾çäººï¼æ¯ä¸ªäººçåã仿¯ä¸ä¸ªæ§æ ¼è
¥ï¼æä»¬ä¸æ³æèµ·è¿äºï¼ä½ä¹å¯è½æ¯ä¸ä¸ªç¥è¯......使¯ï¼å¿ï¼äººç±»æ¯å¤©çççæ£ï¼å¹¶ä¸å®ç¾ã","robot":"R2D2å¯è½æ¯ä¸ç䏿ç¥åçæºå¨äººï¼ä½å®è¯å®ä¸æ¯å¯ä¸çä¸ä¸ªãä»å·¥ä¸å°ç©å
·äººç±»çæºå¨äººï¼æä»¬çå°äºè¿äºæºæ¢°è®¾å¤çè¶æ¥è¶å¹¿æ³çéæ©ï¼è¿æ¯æ¢ç¾å¦åæç¹æ
å¿§ãè¿ä¸æ¯å¤ªé¾çè§£è°åæè®¤ä¸ºï¼è®¡ç®æºï¼ææ¯ï¼æºå¨äººæ£å¨å¯¹äººç±»å¤ªæ¾èå½±åç人ã广æ³çç°å®ï¼æçºµæºå¨äººç3D模åçï¼å¯ç¨äºè®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å
³ç3D设计任ä½å
¶ä»é¢åå¯ä¾ä¸è½½ã","ship":"è¹è¶æ¯å¼ºæåçè¡ç®¡åæåç§å°ºå¯¸ï¼é¢è²åå½¢ç¶ãå®ä»¬å¯ä»¥è¢«å½ç±»ä¸ºè´§è¹ï¼åè°æå®¢è¹ï¼ä½ä»ä»¬é½å¨æ·±æµ·æ°´åä½ä¸ãå¦æä½ ç»åäºæè½¦çä¸éï¼å®å¯è½ä¸æ¯ä»£æ¥èªå·±åæ¬¢çæ¹å¼ï¼ä½å¾å¤äººé½æä¹è¹æ¸¸è§çç¸å½ä¼é
åæå¿«ãæä»¬çè¹3D模åçéæ©å¯ä¾ä¸è½½ï¼å°æ»¡è¶³å³ä½¿æ¯æèå»çéé¿çæ åã","skeleton":"人类骨骼æéª¨éª¼ç³»ç»ï¼è§£åï¼æ¯å¨åºçæ¶ç±270个骨骼ç主ä½çå
鍿¡æ¶ã宿ä¾äºè½¦èº«ç»æï¼ä¿æ¤åè¿å¨ï¼æ¯æå¤æç骨骼系ç»ä¹ä¸ãäºä¸°å¯çéæ©æ£ç¡®çè§£åå¦ï¼æ±å®æ ç骨æ¶çä¸ç»´æ¨¡åï¼é常éåäºä¸ç»´å¨ç»ï¼å¹³é¢è®¾è®¡ï¼å¹¿åï¼3D游æåç½é¡µåºç¨å¯ä¾ä¸è½½ã","skull":"æå¤èæå®æ´çï¼å®æ´çåºå 人类头骨被åç°ç±å¤ç§çç»çå¨ç©ä½äºæµ·å¹³é¢40å¤ç±³çå
å´ãè¿æ¯å¨æ°çä¸çåç°çæå¤èç骨骼ä¹ä¸ï¼å®ä¹å
æ¬èº«ä½çææä¸»è¦ç骨骼åç齿çå®å¥½ç头ç骨åä¸å¥ã人类头骨æè¿æä¸ºæ¶å°å设计çäºæ
ï¼ä½æ¯å½ä½ çæ£ç»å®ä¸äºæ³æ³ï¼ä»ä»¬é£ç§åå¦çå
¨é¨æ ·åè§£åç¸å½¢......è¿ä¸ç±»æä¾å¹¿æ³ç头骨3D模åï¼å¯ä»¥å¨å¹³é¢è®¾è®¡ä¸ä½¿ç¨ï¼3Då¨ç»ï¼3D游ææå¹¿åã","sofa":"豪åæç®çº¦ï¼ç°ä»£æå¤å
¸ï¼ç®é©æç®çº¦ç设计ï¼ä½ 忬¢ä½ çæ²åï¼æ²å3D模åçèå´å
ï¼æä»¬å¿
须尿»¡è¶³å³ä½¿æ¯æä¸¥éçå®ç¾ä¸»ä¹è
ãå½ä½ å
16518䏿¥æ³ä¸æ³ï¼æ²åæ¯æ¯ä¸ªå®¢å çä¸å¿ï¼æä»¥éæ©è®¾è®¡æ¶ï¼ä½ å¿ é¡»æåæï¼","table":"ææ°çå®¶å ·æ½®æµçä¸åä½ç¨ï¼éæ©ä¸ä¸ªç°ä»£çï¼æ¶å°ç表åå¾è¿äºç´§å¼ ãæ¾ç»æä¸æ®µæ¶é´ï¼å½ä½ æä¸ä¸ªç®åç饿¡ä¸ä¸ºæ¨çèæ¥æ¸©åï¼é£æ¯è¶³å¤çï¼ä½æ¯ä»å¤© - 表åºè¯¥æ¯ä¸ä¸ªè¯å¥æè³å°ä¸ä¸ªéç®çå é¨å£é³ãè¿ä¸ªéæ©ç»ä½ ä¸ä¸ªå¹¿éçèå´è¡¨3D模åï¼ä»¥æ»¡è¶³æ¯ä¸ä¸ªå¿è¡æ¥æ½®ã","tower":"æ¯ä¸ªåå¸é½æä¸ä¸ªç¹æ®çå¡ï¼æ¯ä¸ªäººé½ççå¾èªè±ªãæ³æ³è¾è²å°é塿æ¯è¨æå¡ï¼æä¼¦æ¦å¡æ¡¥ï¼æ´ä¸ç¨è¯´åç§ç°ä»£åçæ©å¤©å¤§æ¥¼ï¼æªæ¥æ´¾å»ºçåå叿¯è§ï¼æ¸¸å®¢æ¬£èµãç¶èï¼å½æ¶åå°çåå¸ï¼æ°´æçµå¡å·¥ä¸é¶ä»¶ï¼å¤§å®¶å¾å¾æä»ä»¬çç¼çäº......使¯ï¼æä»¬åºè¯¥å¦ä¼æ¬£èµæ¯ä¸ä¸ªå»ºçåä½ï¼æ 论å¤ä»£ï¼å·¥ä¸æç°ä»£åã详ç»å¡3D模åçèå´å¯ä¾ä¸è½½ï¼å¹¶åå¤è®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å ³ç3D设计任ä½å ¶ä»é¢åã","tree":"å¦æä½ å¨ç§æ¤ä¸äºæ æ¨åå¥è±å¼èä¸ä¸ªä»»å¡ï¼ä½ æ¥å¯¹å°æ¹äºãæ¤ç±»å«æä¾ä¸ç³»åæäºä½¿ç¨ï¼é常é¼çç3Dæ æ¨¡åï¼ä»¥CGèºæ¯å®¶å建çå¸ï¼è°æ£å¨åªåä¸äºç»¿è²æ¤ç©æ·»å å°ä»ä»¬ç项ç®ãå¦ææ¨æ¬£èµä¼è¯çåè´¨ï¼æä»¬ç¸ä¿¡è¿ä¸ªéæ©3Dæ æ¤ç©è½¦åå°æ»¡è¶³ä½ çæ åï¼","truck":"驾驶ä¸è¾å¡è½¦æ¯ä¸é¡¹è°å·¨çä»»å¡ï¼ç¹å«æ¯å¦æä½ éè¦æ¾å°éè¿åå¸äº¤éæ¥å µçæ¹å¼ãæ è®ºå®æ¯å¦æ¯ä¸ä¸ªæ¶é²è½¦ï¼åå¾è½¦ï¼é£å车æä¸è¬ä¹ä¸ï¼å®éè¦é«è¶ çæå·§æ¥æçºµè¿äºå·¨å车è¾ãæä»¬ç¸ä¿¡ï¼æ¬æ¬¡è¯éé¼çï¼é«åè´¨å¡è½¦3Dæ¨¡åæ¯å®ç¾çä¸ç»´å¨ç»ï¼å¹³é¢è®¾è®¡ï¼å¹¿åæä»»ä½å ¶ä»3Dç¸å ³çç°åºä½¿ç¨ã","tv":"æ¾ç»æå½å£çæ¯æ¯ä¸ä¸ªå¯æ¬çå®¶åºï¼ç°å¨ççµè§æºä¸çå忬声å¨çæ ¸å¿æ¶é´æ¯å®¢å ï¼çè³æ¯å§å®¤ï¼çå½çãè¿å¹´æ¥çµè§å·²ç»èµ¶ä¸äºææ°çææ¯ãå æ¤ï¼æä»¬ææºè½3Dçµè§ï¼å¹³æ¿åç离åå±å¹ï¼ä¸ä¸ªæ°åè½å触æ¸å±è®¾è®¡ã龿ªçµè§æ¯æ¨å¨çµå½±å¸åºæ·æ±°ã丰å¯çå®é ï¼è¯¦ç»ççµè§3D模åå·²ç»åå¤å¥½è®¡ç®æºå¾å½¢åºç¨ï¼å¦å¹¿åï¼ä¸ç»´å¯è§åï¼3D游æï¼ç½ç»åç¸å ³ç3D设计任ä½å ¶ä»é¢åçå¯ä¾ä¸è½½ã"}},"tag_promotion":{"days_left_error":"å¿ é¡»å¨ 1 å° 30 ä¹é´","no_other_pending_promotions_for_same_item_tag":"å·²ç»æä¸ä¸ªå¾ å¤ççä¿éæ´»å¨"},"tooltips":{"buyer_loyalty_program_current_level_html":"ç®åï¼æ¨å·²ç»å¨CGTraderç¨%{total_price_paid}åä½ çä¿¡ç¨èµåç%{buyer_loyalty_rate} \u003cBR/\u003eè¿æå³çä½ ä¼ä»æ¯æ¬¡è´ä¹°è·å%{buyer_loyalty_rate}å¦åã\n","buyer_loyalty_program_html":"è¿æ¯ä½ éè¦å¤å°ï¼ä»æ¨è´ä¹°æ°çå¦åå¾å°çç¾åæ¯ã \u003cBR/\u003eè¿å°å¢å è³30%ä½ä¸ºCGTraderå¢å ä½ çä¸çæ¯åºã \u003cBR/\u003eç®åä½ çä¿¡ç¨èµåç%{buyer_loyalty_rate}ã\n","buyer_loyalty_program_next_level_html":"ä¸ä¸çº§%{next_lvl_expenses}ä¼å¢å ä½ çä¿¡ç¨èµåçé«è¾¾%{next_lvl_expenses_rate} ã \u003cbr/\u003eæ¨éè¦è´ä¹°$%{left_until_next_lvl}æ´è¾¾å°ä¸ä¸ªæ°çæ°´å¹³ã\n"},"trending_headers":{"models":"æ¥çå ¶ä»æµè¡ç3D模å","print":"æ¥çå ¶ä»æµè¡ç3Dæå°æ¨¡å"},"tutorial":{"destroy":"æç¨å·²æåå é¤ã","submit_for_review_error":"è¯·å¡«åææå¿ å¡«åæ®µã","submitted":"æè°¢æ¨æäº¤æç¨ãå®å°å¾å¿«è¢«å®¡æ ¸å¹¶åå¸ã"}}}; 16519})); 16520 16521 16522 16523(function($) { 16524 16525 var cocoon_element_counter = 0; 16526 16527 var create_new_id = function() { 16528 return (new Date().getTime() + cocoon_element_counter++); 16529 } 16530 16531 var newcontent_braced = function(id) { 16532 return '[' + id + ']$1'; 16533 } 16534 16535 var newcontent_underscord = function(id) { 16536 return '_' + id + '_$1'; 16537 } 16538 16539 var getInsertionNodeElem = function(insertionNode, insertionTraversal, $this){ 16540 16541 if (!insertionNode){ 16542 return $this.parent(); 16543 } 16544 16545 if (typeof insertionNode == 'function'){ 16546 if(insertionTraversal){ 16547 console.warn('association-insertion-traversal is ignored, because association-insertion-node is given as a function.') 16548 } 16549 return insertionNode($this); 16550 } 16551 16552 if(typeof insertionNode == 'string'){ 16553 if (insertionTraversal){ 16554 return $this[insertionTraversal](insertionNode); 16555 }else{ 16556 return insertionNode == "this" ? $this : $(insertionNode); 16557 } 16558 } 16559 16560 } 16561 16562 $(document).on('click', '.add_fields', function(e) { 16563 e.preventDefault(); 16564 e.stopPropagation(); 16565 16566 var $this = $(this), 16567 assoc = $this.data('association'), 16568 assocs = $this.data('associations'), 16569 content = $this.data('association-insertion-template'), 16570 insertionMethod = $this.data('association-insertion-method') || $this.data('association-insertion-position') || 'before', 16571 insertionNode = $this.data('association-insertion-node'), 16572 insertionTraversal = $this.data('association-insertion-traversal'), 16573 count = parseInt($this.data('count'), 10), 16574 regexp_braced = new RegExp('\\[new_' + assoc + '\\](.*?\\s)', 'g'), 16575 regexp_underscord = new RegExp('_new_' + assoc + '_(\\w*)', 'g'), 16576 new_id = create_new_id(), 16577 new_content = content.replace(regexp_braced, newcontent_braced(new_id)), 16578 new_contents = [], 16579 originalEvent = e; 16580 16581 16582 if (new_content == content) { 16583 regexp_braced = new RegExp('\\[new_' + assocs + '\\](.*?\\s)', 'g'); 16584 regexp_underscord = new RegExp('_new_' + assocs + '_(\\w*)', 'g'); 16585 new_content = content.replace(regexp_braced, newcontent_braced(new_id)); 16586 } 16587 16588 new_content = new_content.replace(regexp_underscord, newcontent_underscord(new_id)); 16589 new_contents = [new_content]; 16590 16591 count = (isNaN(count) ? 1 : Math.max(count, 1)); 16592 count -= 1; 16593 16594 while (count) { 16595 new_id = create_new_id(); 16596 new_content = content.replace(regexp_braced, newcontent_braced(new_id)); 16597 new_content = new_content.replace(regexp_underscord, newcontent_underscord(new_id)); 16598 new_contents.push(new_content); 16599 16600 count -= 1; 16601 } 16602 16603 var insertionNodeElem = getInsertionNodeElem(insertionNode, insertionTraversal, $this) 16604 16605 if( !insertionNodeElem || (insertionNodeElem.length == 0) ){ 16606 console.warn("Couldn't find the element to insert the template. Make sure your `data-association-insertion-*` on `link_to_add_association` is correct.") 16607 } 16608 16609 $.each(new_contents, function(i, node) { 16610 var contentNode = $(node); 16611 16612 var before_insert = jQuery.Event('cocoon:before-insert'); 16613 insertionNodeElem.trigger(before_insert, [contentNode, originalEvent]); 16614 16615 if (!before_insert.isDefaultPrevented()) { 16616 // allow any of the jquery dom manipulation methods (after, before, append, prepend, etc) 16617 // to be called on the node. allows the insertion node to be the parent of the inserted 16618 // code and doesn't force it to be a sibling like after/before does. default: 'before' 16619 var addedContent = insertionNodeElem[insertionMethod](contentNode); 16620 16621 insertionNodeElem.trigger('cocoon:after-insert', [contentNode, 16622 originalEvent]); 16623 } 16624 }); 16625 }); 16626 16627 $(document).on('click', '.remove_fields.dynamic, .remove_fields.existing', function(e) { 16628 var $this = $(this), 16629 wrapper_class = $this.data('wrapper-class') || 'nested-fields', 16630 node_to_delete = $this.closest('.' + wrapper_class), 16631 trigger_node = node_to_delete.parent(), 16632 originalEvent = e; 16633 16634 e.preventDefault(); 16635 e.stopPropagation(); 16636 16637 var before_remove = jQuery.Event('cocoon:before-remove'); 16638 trigger_node.trigger(before_remove, [node_to_delete, originalEvent]); 16639 16640 if (!before_remove.isDefaultPrevented()) { 16641 var timeout = trigger_node.data('remove-timeout') || 0; 16642 16643 setTimeout(function() { 16644 if ($this.hasClass('dynamic')) { 16645 node_to_delete.detach(); 16646 } else { 16647 $this.prev("input[type=hidden]").val("1"); 16648 node_to_delete.hide(); 16649 } 16650 trigger_node.trigger('cocoon:after-remove', [node_to_delete, 16651 originalEvent]); 16652 }, timeout); 16653 } 16654 }); 16655 16656 16657 $(document).on("ready page:load turbolinks:load", function() { 16658 $('.remove_fields.existing.destroyed').each(function(i, obj) { 16659 var $this = $(this), 16660 wrapper_class = $this.data('wrapper-class') || 'nested-fields'; 16661 16662 $this.closest('.' + wrapper_class).hide(); 16663 }); 16664 }); 16665 16666})(jQuery); 16667 16668 16669// moment.js 16670// version : 1.7.2 16671// author : Tim Wood 16672// license : MIT 16673// momentjs.com 16674 16675(function (undefined) { 16676 16677 /************************************ 16678 Constants 16679 ************************************/ 16680 16681 var moment, 16682 VERSION = "1.7.2", 16683 round = Math.round, i, 16684 // internal storage for language config files 16685 languages = {}, 16686 currentLanguage = 'en', 16687 16688 // check for nodeJS 16689 hasModule = (typeof module !== 'undefined' && module.exports), 16690 16691 // Parameters to check for on the lang config. This list of properties 16692 // will be inherited from English if not provided in a language 16693 // definition. monthsParse is also a lang config property, but it 16694 // cannot be inherited and as such cannot be enumerated here. 16695 langConfigProperties = 'months|monthsShort|weekdays|weekdaysShort|weekdaysMin|longDateFormat|calendar|relativeTime|ordinal|meridiem'.split('|'), 16696 16697 // ASP.NET json date format regex 16698 aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, 16699 16700 // format tokens 16701 formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|zz?|ZZ?|.)/g, 16702 localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?)/g, 16703 16704 // parsing tokens 16705 parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi, 16706 16707 // parsing token regexes 16708 parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 16709 parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 16710 parseTokenThreeDigits = /\d{3}/, // 000 - 999 16711 parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 16712 parseTokenWord = /[0-9a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+/i, // any word characters or numbers 16713 parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z 16714 parseTokenT = /T/i, // T (ISO seperator) 16715 16716 // preliminary iso regex 16717 // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 16718 isoRegex = /^\s*\d{4}-\d\d-\d\d(T(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, 16719 isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', 16720 16721 // iso time formats and regexes 16722 isoTimes = [ 16723 ['HH:mm:ss.S', /T\d\d:\d\d:\d\d\.\d{1,3}/], 16724 ['HH:mm:ss', /T\d\d:\d\d:\d\d/], 16725 ['HH:mm', /T\d\d:\d\d/], 16726 ['HH', /T\d\d/] 16727 ], 16728 16729 // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] 16730 parseTimezoneChunker = /([\+\-]|\d\d)/gi, 16731 16732 // getter and setter names 16733 proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), 16734 unitMillisecondFactors = { 16735 'Milliseconds' : 1, 16736 'Seconds' : 1e3, 16737 'Minutes' : 6e4, 16738 'Hours' : 36e5, 16739 'Days' : 864e5, 16740 'Months' : 2592e6, 16741 'Years' : 31536e6 16742 }, 16743 16744 // format function strings 16745 formatFunctions = {}, 16746 16747 // tokens to ordinalize and pad 16748 ordinalizeTokens = 'DDD w M D d'.split(' '), 16749 paddedTokens = 'M D H h m s w'.split(' '), 16750 16751 /* 16752 * moment.fn.format uses new Function() to create an inlined formatting function. 16753 * Results are a 3x speed boost 16754 * http://jsperf.com/momentjs-cached-format-functions 16755 * 16756 * These strings are appended into a function using replaceFormatTokens and makeFormatFunction 16757 */ 16758 formatTokenFunctions = { 16759 // a = placeholder 16760 // b = placeholder 16761 // t = the current moment being formatted
16762 // v = getValueAtKey function 16763 // o = language.ordinal function 16764 // p = leftZeroFill function 16765 // m = language.meridiem value or function 16766 M : function () { 16767 return this.month() + 1; 16768 }, 16769 MMM : function (format) { 16770 return getValueFromArray("monthsShort", this.month(), this, format); 16771 }, 16772 MMMM : function (format) { 16773 return getValueFromArray("months", this.month(), this, format); 16774 }, 16775 D : function () { 16776 return this.date(); 16777 }, 16778 DDD : function () { 16779 var a = new Date(this.year(), this.month(), this.date()), 16780 b = new Date(this.year(), 0, 1); 16781 return ~~(((a - b) / 864e5) + 1.5); 16782 }, 16783 d : function () { 16784 return this.day(); 16785 }, 16786 dd : function (format) { 16787 return getValueFromArray("weekdaysMin", this.day(), this, format); 16788 }, 16789 ddd : function (format) { 16790 return getValueFromArray("weekdaysShort", this.day(), this, format); 16791 }, 16792 dddd : function (format) { 16793 return getValueFromArray("weekdays", this.day(), this, format); 16794 }, 16795 w : function () { 16796 var a = new Date(this.year(), this.month(), this.date() - this.day() + 5), 16797 b = new Date(a.getFullYear(), 0, 4); 16798 return ~~((a - b) / 864e5 / 7 + 1.5); 16799 }, 16800 YY : function () { 16801 return leftZeroFill(this.year() % 100, 2); 16802 }, 16803 YYYY : function () { 16804 return leftZeroFill(this.year(), 4); 16805 }, 16806 a : function () { 16807 return this.lang().meridiem(this.hours(), this.minutes(), true); 16808 }, 16809 A : function () { 16810 return this.lang().meridiem(this.hours(), this.minutes(), false); 16811 }, 16812 H : function () { 16813 return this.hours(); 16814 }, 16815 h : function () { 16816 return this.hours() % 12 || 12; 16817 }, 16818 m : function () { 16819 return this.minutes(); 16820 }, 16821 s : function () { 16822 return this.seconds(); 16823 }, 16824 S : function () { 16825 return ~~(this.milliseconds() / 100); 16826 }, 16827 SS : function () { 16828 return leftZeroFill(~~(this.milliseconds() / 10), 2); 16829 }, 16830 SSS : function () { 16831 return leftZeroFill(this.milliseconds(), 3); 16832 }, 16833 Z : function () { 16834 var a = -this.zone(), 16835 b = "+"; 16836 if (a < 0) { 16837 a = -a; 16838 b = "-"; 16839 } 16840 return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2); 16841 }, 16842 ZZ : function () { 16843 var a = -this.zone(), 16844 b = "+"; 16845 if (a < 0) { 16846 a = -a; 16847 b = "-"; 16848 } 16849 return b + leftZeroFill(~~(10 * a / 6), 4); 16850 } 16851 }; 16852 16853 function getValueFromArray(key, index, m, format) { 16854 var lang = m.lang(); 16855 return lang[key].call ? lang[key](m, format) : lang[key][index]; 16856 } 16857 16858 function padToken(func, count) { 16859 return function (a) { 16860 return leftZeroFill(func.call(this, a), count); 16861 }; 16862 } 16863 function ordinalizeToken(func) { 16864 return function (a) { 16865 var b = func.call(this, a); 16866 return b + this.lang().ordinal(b); 16867 }; 16868 } 16869 16870 while (ordinalizeTokens.length) { 16871 i = ordinalizeTokens.pop(); 16872 formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]); 16873 } 16874 while (paddedTokens.length) { 16875 i = paddedTokens.pop(); 16876 formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); 16877 } 16878 formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); 16879 16880 16881 /************************************ 16882 Constructors 16883 ************************************/ 16884 16885 16886 // Moment prototype object 16887 function Moment(date, isUTC, lang) { 16888 this._d = date; 16889 this._isUTC = !!isUTC; 16890 this._a = date._a || null; 16891 this._lang = lang || false; 16892 } 16893 16894 // Duration Constructor 16895 function Duration(duration) { 16896 var data = this._data = {}, 16897 years = duration.years || duration.y || 0, 16898 months = duration.months || duration.M || 0, 16899 weeks = duration.weeks || duration.w || 0, 16900 days = duration.days || duration.d || 0, 16901 hours = duration.hours || duration.h || 0, 16902 minutes = duration.minutes || duration.m || 0, 16903 seconds = duration.seconds || duration.s || 0, 16904 milliseconds = duration.milliseconds || duration.ms || 0; 16905 16906 // representation for dateAddRemove 16907 this._milliseconds = milliseconds + 16908 seconds * 1e3 + // 1000 16909 minutes * 6e4 + // 1000 * 60 16910 hours * 36e5; // 1000 * 60 * 60 16911 // Because of dateAddRemove treats 24 hours as different from a 16912 // day when working around DST, we need to store them separately 16913 this._days = days + 16914 weeks * 7; 16915 // It is impossible translate months into days without knowing 16916 // which months you are are talking about, so we have to store 16917 // it separately. 16918 this._months = months + 16919 years * 12; 16920 16921 // The following code bubbles up values, see the tests for 16922 // examples of what that means. 16923 data.milliseconds = milliseconds % 1000; 16924 seconds += absRound(milliseconds / 1000); 16925 16926 data.seconds = seconds % 60; 16927 minutes += absRound(seconds / 60); 16928 16929 data.minutes = minutes % 60; 16930 hours += absRound(minutes / 60); 16931 16932 data.hours = hours % 24; 16933 days += absRound(hours / 24); 16934 16935 days += weeks * 7; 16936 data.days = days % 30; 16937 16938 months += absRound(days / 30); 16939 16940 data.months = months % 12; 16941 years += absRound(months / 12); 16942 16943 data.years = years; 16944 16945 this._lang = false;
16946 } 16947 16948 16949 /************************************ 16950 Helpers 16951 ************************************/ 16952 16953 16954 function absRound(number) { 16955 if (number < 0) { 16956 return Math.ceil(number); 16957 } else { 16958 return Math.floor(number); 16959 } 16960 } 16961 16962 // left zero fill a number 16963 // see http://jsperf.com/left-zero-filling for performance comparison 16964 function leftZeroFill(number, targetLength) { 16965 var output = number + ''; 16966 while (output.length < targetLength) { 16967 output = '0' + output; 16968 } 16969 return output; 16970 } 16971 16972 // helper function for _.addTime and _.subtractTime 16973 function addOrSubtractDurationFromMoment(mom, duration, isAdding) { 16974 var ms = duration._milliseconds, 16975 d = duration._days, 16976 M = duration._months, 16977 currentDate; 16978 16979 if (ms) { 16980 mom._d.setTime(+mom + ms * isAdding); 16981 } 16982 if (d) { 16983 mom.date(mom.date() + d * isAdding); 16984 } 16985 if (M) { 16986 currentDate = mom.date(); 16987 mom.date(1) 16988 .month(mom.month() + M * isAdding) 16989 .date(Math.min(currentDate, mom.daysInMonth())); 16990 } 16991 } 16992 16993 // check if is an array 16994 function isArray(input) { 16995 return Object.prototype.toString.call(input) === '[object Array]'; 16996 } 16997 16998 // compare two arrays, return the number of differences 16999 function compareArrays(array1, array2) { 17000 var len = Math.min(array1.length, array2.length), 17001 lengthDiff = Math.abs(array1.length - array2.length), 17002 diffs = 0, 17003 i; 17004 for (i = 0; i < len; i++) { 17005 if (~~array1[i] !== ~~array2[i]) { 17006 diffs++; 17007 } 17008 } 17009 return diffs + lengthDiff; 17010 } 17011 17012 // convert an array to a date. 17013 // the array should mirror the parameters below 17014 // note: all values past the year are optional and will default to the lowest possible value. 17015 // [year, month, day , hour, minute, second, millisecond] 17016 function dateFromArray(input, asUTC, hoursOffset, minutesOffset) { 17017 var i, date, forValid = []; 17018 for (i = 0; i < 7; i++) { 17019 forValid[i] = input[i] = (input[i] == null) ? (i === 2 ? 1 : 0) : input[i]; 17020 } 17021 // we store whether we used utc or not in the input array 17022 input[7] = forValid[7] = asUTC; 17023 // if the parser flagged the input as invalid, we pass the value along 17024 if (input[8] != null) { 17025 forValid[8] = input[8]; 17026 } 17027 // add the offsets to the time to be parsed so that we can have a clean array 17028 // for checking isValid 17029 input[3] += hoursOffset || 0; 17030 input[4] += minutesOffset || 0; 17031 date = new Date(0); 17032 if (asUTC) { 17033 date.setUTCFullYear(input[0], input[1], input[2]); 17034 date.setUTCHours(input[3], input[4], input[5], input[6]); 17035 } else { 17036 date.setFullYear(input[0], input[1], input[2]); 17037 date.setHours(input[3], input[4], input[5], input[6]); 17038 } 17039 date._a = forValid; 17040 return date; 17041 } 17042 17043 // Loads a language definition into the `languages` cache. The function 17044 // takes a key and optionally values. If not in the browser and no values 17045 // are provided, it will load the language file module. As a convenience, 17046 // this function also returns the language values. 17047 function loadLang(key, values) { 17048 var i, m, 17049 parse = []; 17050 17051 if (!values && hasModule) { 17052 values = require('./lang/' + key); 17053 } 17054 17055 for (i = 0; i < langConfigProperties.length; i++) { 17056 // If a language definition does not provide a value, inherit 17057 // from English 17058 values[langConfigProperties[i]] = values[langConfigProperties[i]] || 17059 languages.en[langConfigProperties[i]]; 17060 } 17061 17062 for (i = 0; i < 12; i++) { 17063 m = moment([2000, i]); 17064 parse[i] = new RegExp('^' + (values.months[i] || values.months(m, '')) + 17065 '|^' + (values.monthsShort[i] || values.monthsShort(m, '')).replace('.', ''), 'i'); 17066 } 17067 values.monthsParse = values.monthsParse || parse; 17068 17069 languages[key] = values; 17070 17071 return values; 17072 } 17073 17074 // Determines which language definition to use and returns it. 17075 // 17076 // With no parameters, it will return the global language. If you 17077 // pass in a language key, such as 'en', it will return the 17078 // definition for 'en', so long as 'en' has already been loaded using 17079 // moment.lang. If you pass in a moment or duration instance, it 17080 // will decide the language based on that, or default to the global 17081 // language. 17082 function getLangDefinition(m) { 17083 var langKey = (typeof m === 'string') && m || 17084 m && m._lang || 17085 null; 17086 17087 return langKey ? (languages[langKey] || loadLang(langKey)) : moment; 17088 } 17089 17090 17091 /************************************ 17092 Formatting 17093 ************************************/ 17094 17095 17096 function removeFormattingTokens(input) { 17097 if (input.match(/\[.*\]/)) { 17098 return input.replace(/^\[|\]$/g, ""); 17099 } 17100 return input.replace(/\\/g, ""); 17101 } 17102 17103 function makeFormatFunction(format) { 17104 var array = format.match(formattingTokens), i, length; 17105 17106 for (i = 0, length = array.length; i < length; i++) { 17107 if (formatTokenFunctions[array[i]]) { 17108 array[i] = formatTokenFunctions[array[i]]; 17109 } else { 17110 array[i] = removeFormattingTokens(array[i]); 17111 } 17112 } 17113 17114 return function (mom) { 17115 var output = ""; 17116 for (i = 0; i < length; i++) { 17117 output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i]; 17118 } 17119 return output; 17120 }; 17121 } 17122 17123 // format date using native date object 17124 function formatMoment(m, format) { 17125 var i = 5; 17126 17127 function replaceLongDateFormatTokens(input) { 17128 return m.lang().longDateFormat[input] || input; 17129 } 17130 17131 while (i-- && localFormattingTokens.test(format)) { 17132 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); 17133 } 17134 17135 if (!formatFunctions[format]) { 17136 formatFunctions[format] = makeFormatFunction(format); 17137 } 17138 17139 return formatFunctions[format](m); 17140 } 17141 17142 17143 /************************************ 17144 Parsing 17145 ************************************/ 17146 17147 17148 // get the regex to find the next token 17149 function getParseRegexForToken(token) { 17150 switch (token) { 17151 case 'DDDD': 17152 return parseTokenThreeDigits; 17153 case 'YYYY': 17154 return parseTokenFourDigits; 17155 case 'S': 17156 case 'SS': 17157 case 'SSS': 17158 case 'DDD': 17159 return parseTokenOneToThreeDigits; 17160 case 'MMM': 17161 case 'MMMM': 17162 case 'dd': 17163 case 'ddd': 17164 case 'dddd': 17165 case 'a': 17166 case 'A': 17167 return parseTokenWord; 17168 case 'Z': 17169 case 'ZZ': 17170 return parseTokenTimezone; 17171 case 'T': 17172 return parseTokenT; 17173 case 'MM': 17174 case 'DD': 17175 case 'YY': 17176 case 'HH': 17177 case 'hh': 17178 case 'mm': 17179 case 'ss': 17180 case 'M': 17181 case 'D': 17182 case 'd': 17183 case 'H': 17184 case 'h': 17185 case 'm': 17186 case 's': 17187 return parseTokenOneOrTwoDigits; 17188 default : 17189 return new RegExp(token.replace('\\', '')); 17190 } 17191 } 17192 17193 // function to convert string input to date 17194 function addTimeToArrayFromToken(token, input, datePartArray, config) { 17195 var a, b; 17196 17197 switch (token) { 17198 // MONTH 17199 case 'M' : // fall through to MM 17200 case 'MM' : 17201 datePartArray[1] = (input == null) ? 0 : ~~input - 1; 17202 break; 17203 case 'MMM' : // fall through to MMMM 17204 case 'MMMM' : 17205 for (a = 0; a < 12; a++) { 17206 if (getLangDefinition().monthsParse[a].test(input)) { 17207 datePartArray[1] = a; 17208 b = true; 17209 break; 17210 } 17211 } 17212 // if we didn't find a month name, mark the date as invali
17212d. 17213 if (!b) { 17214 datePartArray[8] = false; 17215 } 17216 break; 17217 // DAY OF MONTH 17218 case 'D' : // fall through to DDDD 17219 case 'DD' : // fall through to DDDD 17220 case 'DDD' : // fall through to DDDD 17221 case 'DDDD' : 17222 if (input != null) { 17223 datePartArray[2] = ~~input; 17224 } 17225 break; 17226 // YEAR 17227 case 'YY' : 17228 datePartArray[0] = ~~input + (~~input > 70 ? 1900 : 2000); 17229 break; 17230 case 'YYYY' : 17231 datePartArray[0] = ~~Math.abs(input); 17232 break; 17233 // AM / PM 17234 case 'a' : // fall through to A 17235 case 'A' : 17236 config.isPm = ((input + '').toLowerCase() === 'pm'); 17237 break; 17238 // 24 HOUR 17239 case 'H' : // fall through to hh 17240 case 'HH' : // fall through to hh 17241 case 'h' : // fall through to hh 17242 case 'hh' : 17243 datePartArray[3] = ~~input; 17244 break; 17245 // MINUTE 17246 case 'm' : // fall through to mm 17247 case 'mm' : 17248 datePartArray[4] = ~~input; 17249 break; 17250 // SECOND 17251 case 's' : // fall through to ss 17252 case 'ss' : 17253 datePartArray[5] = ~~input; 17254 break; 17255 // MILLISECOND 17256 case 'S' : 17257 case 'SS' : 17258 case 'SSS' : 17259 datePartArray[6] = ~~ (('0.' + input) * 1000); 17260 break; 17261 // TIMEZONE 17262 case 'Z' : // fall through to ZZ 17263 case 'ZZ' : 17264 config.isUTC = true; 17265 a = (input + '').match(parseTimezoneChunker); 17266 if (a && a[1]) { 17267 config.tzh = ~~a[1]; 17268 } 17269 if (a && a[2]) { 17270 config.tzm = ~~a[2]; 17271 } 17272 // reverse offsets 17273 if (a && a[0] === '+') { 17274 config.tzh = -config.tzh; 17275 config.tzm = -config.tzm; 17276 } 17277 break; 17278 } 17279 17280 // if the input is null, the date is not valid 17281 if (input == null) { 17282 datePartArray[8] = false; 17283 } 17284 } 17285 17286 // date from string and format string 17287 function makeDateFromStringAndFormat(string, format) { 17288 // This array is used to make a Date, either with `new Date` or `Date.UTC` 17289 // We store some additional data on the array for validation 17290 // datePartArray[7] is true if the Date was created with `Date.UTC` and false if created with `new Date` 17291 // datePartArray[8] is false if the Date is invalid, and undefined if the validity is unknown. 17292 var datePartArray = [0, 0, 1, 0, 0, 0, 0], 17293 config = { 17294 tzh : 0, // timezone hour offset 17295 tzm : 0 // timezone minute offset 17296 }, 17297 tokens = format.match(formattingTokens), 17298 i, parsedInput; 17299 17300 for (i = 0; i < tokens.length; i++) { 17301 parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0]; 17302 if (parsedInput) { 17303 string = string.slice(string.indexOf(parsedInput) + parsedInput.length); 17304 } 17305 // don't parse if its not a known token 17306 if (formatTokenFunctions[tokens[i]]) { 17307 addTimeToArrayFromToken(tokens[i], parsedInput, datePartArray, config); 17308 } 17309 } 17310 // handle am pm 17311 if (config.isPm && datePartArray[3] < 12) { 17312 datePartArray[3] += 12; 17313 } 17314 // if is 12 am, change hours to 0 17315 if (config.isPm === false && datePartArray[3] === 12) { 17316 datePartArray[3] = 0; 17317 } 17318 // return 17319 return dateFromArray(datePartArray, config.isUTC, config.tzh, config.tzm); 17320 } 17321 17322 // date from string and array of format strings 17323 function makeDateFromStringAndArray(string, formats) { 17324 var output, 17325 inputParts = string.match(parseMultipleFormatChunker) || [], 17326 formattedInputParts, 17327 scoreToBeat = 99, 17328 i, 17329 currentDate, 17330 currentScore; 17331 for (i = 0; i < formats.length; i++) { 17332 currentDate = makeDateFromStringAndFormat(string, formats[i]); 17333 formattedInputParts = formatMoment(new Moment(currentDate), formats[i]).match(parseMultipleFormatChunker) || []; 17334 currentScore = compareArrays(inputParts, formattedInputParts); 17335 if (currentScore < scoreToBeat) { 17336 scoreToBeat = currentScore; 17337 output = currentDate; 17338 } 17339 } 17340 return output; 17341 } 17342 17343 // date from iso format 17344 function makeDateFromString(string) { 17345 var format = 'YYYY-MM-DDT', 17346 i; 17347 if (isoRegex.exec(string)) { 17348 for (i = 0; i < 4; i++) { 17349 if (isoTimes[i][1].exec(string)) { 17350 format += isoTimes[i][0]; 17351 break; 17352 } 17353 } 17354 return parseTokenTimezone.exec(string) ? 17355 makeDateFromStringAndFormat(string, format + ' Z') : 17356 makeDateFromStringAndFormat(string, format); 17357 } 17358 return new Date(string); 17359 } 17360 17361 17362 /************************************ 17363 Relative Time 17364 ************************************/ 17365 17366 17367 // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize 17368 function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { 17369 var rt = lang.relativeTime[string]; 17370 return (typeof rt === 'function') ? 17371 rt(number || 1, !!withoutSuffix, string, isFuture) : 17372 rt.replace(/%d/i, number || 1); 17373 } 17374 17375 function relativeTime(milliseconds, withoutSuffix, lang) { 17376 var seconds = round(Math.abs(milliseconds) / 1000), 17377 minutes = round(seconds / 60), 17378 hours = round(minutes / 60), 17379 days = round(hours / 24), 17380 years = round(days / 365), 17381 args = seconds < 45 && ['s', seconds] || 17382 minutes === 1 && ['m'] || 17383 minutes < 45 && ['mm', minutes] || 17384 hours === 1 && ['h'] || 17385 hours < 22 && ['hh', hours] || 17386 days === 1 && ['d'] || 17387 days <= 25 && ['dd', days] || 17388 days <= 45 && ['M'] || 17389 days < 345 && ['MM', round(days / 30)] || 17390 years === 1 && ['y'] || ['yy', years]; 17391 args[2] = withoutSuffix; 17392 args[3] = milliseconds > 0; 17393 args[4] = lang; 17394 return substituteTimeAgo.apply({}, args); 17395 } 17396 17397 17398 /************************************ 17399 Top Level Functions 17400 ************************************/ 17401 17402 17403 moment = function (input, format) { 17404 if (input === null || input === '') { 17405 return null; 17406 } 17407 var date, 17408 matched; 17409 // parse Moment object 17410 if (moment.isMoment(input)) {
17411 return new Moment(new Date(+input._d), input._isUTC, input._lang); 17412 // parse string and format 17413 } else if (format) { 17414 if (isArray(format)) { 17415 date = makeDateFromStringAndArray(input, format); 17416 } else { 17417 date = makeDateFromStringAndFormat(input, format); 17418 } 17419 // evaluate it as a JSON-encoded date 17420 } else { 17421 matched = aspNetJsonRegex.exec(input); 17422 date = input === undefined ? new Date() : 17423 matched ? new Date(+matched[1]) : 17424 input instanceof Date ? input : 17425 isArray(input) ? dateFromArray(input) : 17426 typeof input === 'string' ? makeDateFromString(input) : 17427 new Date(input); 17428 } 17429 17430 return new Moment(date); 17431 }; 17432 17433 // creating with utc 17434 moment.utc = function (input, format) { 17435 if (isArray(input)) { 17436 return new Moment(dateFromArray(input, true), true); 17437 } 17438 // if we don't have a timezone, we need to add one to trigger parsing into utc 17439 if (typeof input === 'string' && !parseTokenTimezone.exec(input)) { 17440 input += ' +0000'; 17441 if (format) { 17442 format += ' Z'; 17443 } 17444 } 17445 return moment(input, format).utc(); 17446 }; 17447 17448 // creating with unix timestamp (in seconds) 17449 moment.unix = function (input) { 17450 return moment(input * 1000); 17451 }; 17452 17453 // duration 17454 moment.duration = function (input, key) { 17455 var isDuration = moment.isDuration(input), 17456 isNumber = (typeof input === 'number'), 17457 duration = (isDuration ? input._data : (isNumber ? {} : input)), 17458 ret; 17459 17460 if (isNumber) { 17461 if (key) { 17462 duration[key] = input; 17463 } else { 17464 duration.milliseconds = input; 17465 } 17466 } 17467 17468 ret = new Duration(duration); 17469 17470 if (isDuration) { 17471 ret._lang = input._lang; 17472 } 17473 17474 return ret; 17475 }; 17476 17477 // humanizeDuration 17478 // This method is deprecated in favor of the new Duration object. Please 17479 // see the moment.duration method. 17480 moment.humanizeDuration = function (num, type, withSuffix) { 17481 return moment.duration(num, type === true ? null : type).humanize(type === true ? true : withSuffix); 17482 }; 17483 17484 // version number 17485 moment.version = VERSION; 17486 17487 // default format 17488 moment.defaultFormat = isoFormat; 17489 17490 // This function will load languages and then set the global language. If 17491 // no arguments are passed in, it will simply return the current global 17492 // language key. 17493 moment.lang = function (key, values) { 17494 var i; 17495 17496 if (!key) { 17497 return currentLanguage; 17498 } 17499 if (values || !languages[key]) { 17500 loadLang(key, values); 17501 } 17502 if (languages[key]) { 17503 // deprecated, to get the language definition variables, use the 17504 // moment.fn.lang method or the getLangDefinition function. 17505 for (i = 0; i < langConfigProperties.length; i++) { 17506 moment[langConfigProperties[i]] = languages[key][langConfigProperties[i]]; 17507 } 17508 moment.monthsParse = languages[key].monthsParse; 17509 currentLanguage = key; 17510 } 17511 }; 17512 17513 // returns language data 17514 moment.langData = getLangDefinition; 17515 17516 // compare moment object 17517 moment.isMoment = function (obj) { 17518 return obj instanceof Moment; 17519 }; 17520 17521 // for typechecking Duration objects 17522 moment.isDuration = function (obj) { 17523 return obj instanceof Duration; 17524 }; 17525 17526 // Set default language, other languages will inherit from English. 17527 moment.lang('en', { 17528 months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), 17529 monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), 17530 weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), 17531 weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), 17532 weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), 17533 longDateFormat : { 17534 LT : "h:mm A", 17535 L : "MM/DD/YYYY", 17536 LL : "MMMM D YYYY", 17537 LLL : "MMMM D YYYY LT", 17538 LLLL : "dddd, MMMM D YYYY LT" 17539 }, 17540 meridiem : function (hours, minutes, isLower) { 17541 if (hours > 11) { 17542 return isLower ? 'pm' : 'PM'; 17543 } else { 17544 return isLower ? 'am' : 'AM'; 17545 } 17546 }, 17547 calendar : { 17548 sameDay : '[Today at] LT', 17549 nextDay : '[Tomorrow at] LT', 17550 nextWeek : 'dddd [at] LT', 17551 lastDay : '[Yesterday at] LT', 17552 lastWeek : '[last] dddd [at] LT', 17553 sameElse : 'L' 17554 }, 17555 relativeTime : { 17556 future : "in %s", 17557 past : "%s ago", 17558 s : "a few seconds", 17559 m : "a minute", 17560 mm : "%d minutes", 17561 h : "an hour", 17562 hh : "%d hours", 17563 d : "a day", 17564 dd : "%d days", 17565 M : "a month", 17566 MM : "%d months", 17567 y : "a year", 17568 yy : "%d years" 17569 }, 17570 ordinal : function (number) { 17571 var b = number % 10; 17572 return (~~ (number % 100 / 10) === 1) ? 'th' : 17573 (b === 1) ? 'st' : 17574 (b === 2) ? 'nd' : 17575 (b === 3) ? 'rd' : 'th'; 17576 } 17577 }); 17578 17579 17580 /************************************ 17581 Moment Prototype 17582 ************************************/ 17583 17584 17585 moment.fn = Moment.prototype = { 17586 17587 clone : function () { 17588 return moment(this); 17589 }, 17590 17591 valueOf : function () { 17592 return +this._d; 17593 }, 17594 17595 unix : function () { 17596 return Math.floor(+this._d / 1000); 17597 }, 17598 17599 toString : function () { 17600 return this._d.toString(); 17601 }, 17602 17603 toDate : function () { 17604 return this._d; 17605 }, 17606 17607 toArray : function () { 17608 var m = this; 17609 return [ 17610 m.year(), 17611 m.month(), 17612 m.date(), 17613 m.hours(), 17614 m.minutes(), 17615 m.seconds(), 17616 m.milliseconds(), 17617 !!this._isUTC 17618 ]; 17619 }, 17620 17621 isValid : function () { 17622 if (this._a) {
17623 // if the parser finds that the input is invalid, it sets 17624 // the eighth item in the input array to false. 17625 if (this._a[8] != null) { 17626 return !!this._a[8]; 17627 } 17628 return !compareArrays(this._a, (this._a[7] ? moment.utc(this._a) : moment(this._a)).toArray()); 17629 } 17630 return !isNaN(this._d.getTime()); 17631 }, 17632 17633 utc : function () { 17634 this._isUTC = true; 17635 return this; 17636 }, 17637 17638 local : function () { 17639 this._isUTC = false; 17640 return this; 17641 }, 17642 17643 format : function (inputString) { 17644 return formatMoment(this, inputString ? inputString : moment.defaultFormat); 17645 }, 17646 17647 add : function (input, val) { 17648 var dur = val ? moment.duration(+val, input) : moment.duration(input); 17649 addOrSubtractDurationFromMoment(this, dur, 1); 17650 return this; 17651 }, 17652 17653 subtract : function (input, val) { 17654 var dur = val ? moment.duration(+val, input) : moment.duration(input); 17655 addOrSubtractDurationFromMoment(this, dur, -1); 17656 return this; 17657 }, 17658 17659 diff : function (input, val, asFloat) { 17660 var inputMoment = this._isUTC ? moment(input).utc() : moment(input).local(), 17661 zoneDiff = (this.zone() - inputMoment.zone()) * 6e4, 17662 diff = this._d - inputMoment._d - zoneDiff, 17663 year = this.year() - inputMoment.year(), 17664 month = this.month() - inputMoment.month(), 17665 date = this.date() - inputMoment.date(), 17666 output; 17667 if (val === 'months') { 17668 output = year * 12 + month + date / 30; 17669 } else if (val === 'years') { 17670 output = year + (month + date / 30) / 12; 17671 } else { 17672 output = val === 'seconds' ? diff / 1e3 : // 1000 17673 val === 'minutes' ? diff / 6e4 : // 1000 * 60 17674 val === 'hours' ? diff / 36e5 : // 1000 * 60 * 60 17675 val === 'days' ? diff / 864e5 : // 1000 * 60 * 60 * 24 17676 val === 'weeks' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7 17677 diff; 17678 } 17679 return asFloat ? output : round(output); 17680 }, 17681 17682 from : function (time, withoutSuffix) { 17683 return moment.duration(this.diff(time)).lang(this._lang).humanize(!withoutSuffix); 17684 }, 17685 17686 fromNow : function (withoutSuffix) { 17687 return this.from(moment(), withoutSuffix); 17688 }, 17689 17690 calendar : function () { 17691 var diff = this.diff(moment().sod(), 'days', true), 17692 calendar = this.lang().calendar, 17693 allElse = calendar.sameElse, 17694 format = diff < -6 ? allElse : 17695 diff < -1 ? calendar.lastWeek : 17696 diff < 0 ? calendar.lastDay : 17697 diff < 1 ? calendar.sameDay : 17698 diff < 2 ? calendar.nextDay : 17699 diff < 7 ? calendar.nextWeek : allElse; 17700 return this.format(typeof format === 'function' ? format.apply(this) : format); 17701 }, 17702 17703 isLeapYear : function () { 17704 var year = this.year(); 17705 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; 17706 }, 17707 17708 isDST : function () { 17709 return (this.zone() < moment([this.year()]).zone() || 17710 this.zone() < moment([this.year(), 5]).zone()); 17711 }, 17712 17713 day : function (input) { 17714 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); 17715 return input == null ? day : 17716 this.add({ d : input - day }); 17717 }, 17718 17719 startOf: function (val) { 17720 // the following switch intentionally omits break keywords 17721 // to utilize falling through the cases. 17722 switch (val.replace(/s$/, '')) { 17723 case 'year': 17724 this.month(0); 17725 /* falls through */ 17726 case 'month': 17727 this.date(1); 17728 /* falls through */ 17729 case 'day': 17730 this.hours(0); 17731 /* falls through */ 17732 case 'hour': 17733 this.minutes(0); 17734 /* falls through */ 17735 case 'minute': 17736 this.seconds(0); 17737 /* falls through */ 17738 case 'second': 17739 this.milliseconds(0); 17740 /* falls through */ 17741 } 17742 return this; 17743 }, 17744 17745 endOf: function (val) { 17746 return this.startOf(val).add(val.replace(/s?$/, 's'), 1).subtract('ms', 1); 17747 }, 17748 17749 sod: function () { 17750 return this.clone().startOf('day'); 17751 }, 17752 17753 eod: function () { 17754 // end of day = start of day plus 1 day, minus 1 millisecond 17755 return this.clone().endOf('day'); 17756 }, 17757 17758 zone : function () { 17759 return this._isUTC ? 0 : this._d.getTimezoneOffset(); 17760 }, 17761 17762 daysInMonth : function () { 17763 return moment.utc([this.year(), this.month() + 1, 0]).date(); 17764 }, 17765 17766 // If passed a language key, it will set the language for this 17767 // instance. Otherwise, it will return the language configuration 17768 // variables for this instance. 17769 lang : function (lang) { 17770 if (lang === undefined) { 17771 return getLangDefinition(this); 17772 } else { 17773 this._lang = lang; 17774 return this; 17775 } 17776 } 17777 }; 17778 17779 // helper for adding shortcuts 17780 function makeGetterAndSetter(name, key) { 17781 moment.fn[name] = function (input) { 17782 var utc = this._isUTC ? 'UTC' : ''; 17783 if (input != null) { 17784 this._d['set' + utc + key](input); 17785 return this; 17786 } else { 17787 return this._d['get' + utc + key](); 17788 } 17789 }; 17790 } 17791 17792 // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) 17793 for (i = 0; i < proxyGettersAndSetters.length; i ++) { 17794 makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase(), proxyGettersAndSetters[i]); 17795 } 17796 17797 // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') 17798 makeGetterAndSetter('year', 'FullYear'); 17799 17800 17801 /************************************ 17802 Duration Prototype 17803 ************************************/ 17804 17805 17806 moment.duration.fn = Duration.prototype = { 17807 weeks : function () { 17808 return absRound(this.days() / 7); 17809 }, 17810 17811 valueOf : function () { 17812 return this._milliseconds + 17813 this._days * 864e5 + 17814 this._months * 2592e6; 17815 }, 17816 17817 humanize : function (withSuffix) { 17818 var difference = +this, 17819 rel = this.lang().relativeTime, 17820 output = relativeTime(difference, !withSuffix, this.lang()), 17821 fromNow = difference <= 0 ? rel.past : rel.future; 17822 17823 if (withSuffix) { 17824 if (typeof fromNow === 'function') { 17825 output = fromNow(output); 17826 } else { 17827 output = fromNow.replace(/%s/i, output); 17828 } 17829 } 17830 17831 return output; 17832 }, 17833 17834 lang : moment.fn.lang 17835 }; 17836 17837 function makeDurationGetter(name) { 17838 moment.duration.fn[name] = function () { 17839 return this._data[name]; 17840 }; 17841 } 17842 17843 function makeDurationAsGetter(name, factor) { 17844 moment.duration.fn['as' + name] = function () { 17845 return +this / factor; 17846 }; 17847 } 17848 17849 for (i in unitMillisecondFactors) { 17850 if (unitMillisecondFactors.hasOwnProperty(i)) { 17851 makeDurationAsGetter(i, unitMillisecondFactors[i]); 17852 makeDurationGetter(i.toLowerCase()); 17853 } 17854 } 17855 17856 makeDurationAsGetter('Weeks', 6048e5); 17857 17858 17859 /************************************ 17860 Exposing Moment 17861 ************************************/ 17862 17863 17864 // CommonJS module is defined 17865 if (hasModule) { 17866 module.exports = moment; 17867 } 17868 /*global ender:false */ 17869 if (typeof ender === 'undefined') { 17870 // here, `this` means `window` in the browser, or `global` on the server 17871 // add `moment` as a global object via a string identifier, 17872 // for Closure Compiler "advanced" mode 17873 this['moment'] = moment; 17874 } 17875 /*global define:false */ 17876 if (typeof define === "function" && define.amd) { 17877 define("moment", [], function () { 17878 return moment; 17879 }); 17880 } 17881}
17881).call(this); 17882/*! @preserve 17883 * numeral.js 17884 * version : 2.0.6 17885 * author : Adam Draper 17886 * license : MIT 17887 * http://adamwdraper.github.com/Numeral-js/ 17888 */
vendor: 11,308 bytes, lines 17889-17890
17889 17890!function(a,b){"function"==typeof define&&define.amd?define(b):"object"==typeof module&&module.exports?module.exports=b():a.numeral=b()}(this,function(){function a(a,b){this._input=a,this._value=b}var b,c,d="2.0.6",e={},f={},g={currentLocale:"en",zeroFormat:null,nullFormat:null,defaultFormat:"0,0",scalePercentBy100:!0},h={currentLocale:g.currentLocale,zeroFormat:g.zeroFormat,nullFormat:g.nullFormat,defaultFormat:g.defaultFormat,scalePercentBy100:g.scalePercentBy100};return b=function(d){var f,g,i,j;if(b.isNumeral(d))f=d.value();else if(0===d||"undefined"==typeof d)f=0;else if(null===d||c.isNaN(d))f=null;else if("string"==typeof d)if(h.zeroFormat&&d===h.zeroFormat)f=0;else if(h.nullFormat&&d===h.nullFormat||!d.replace(/[^0-9]+/g,"").length)f=null;else{for(g in e)if(j="function"==typeof e[g].regexps.unformat?e[g].regexps.unformat():e[g].regexps.unformat,j&&d.match(j)){i=e[g].unformat;break}i=i||b._.stringToNumber,f=i(d)}else f=Number(d)||null;return new a(d,f)},b.version=d,b.isNumeral=function(b){return b instanceof a},b._=c={numberToFormat:function(a,c,d){var e,g,h,i,j,k,l,m=f[b.options.currentLocale],n=!1,o=!1,p=0,q="",r=1e12,s=1e9,t=1e6,u=1e3,v="",w=!1;if(a=a||0,g=Math.abs(a),b._.includes(c,"(")?(n=!0,c=c.replace(/[\(|\)]/g,"")):(b._.includes(c,"+")||b._.includes(c,"-"))&&(j=b._.includes(c,"+")?c.indexOf("+"):0>a?c.indexOf("-"):-1,c=c.replace(/[\+|\-]/g,"")),b._.includes(c,"a")&&(e=c.match(/a(k|m|b|t)?/),e=e?e[1]:!1,b._.includes(c," a")&&(q=" "),c=c.replace(new RegExp(q+"a[kmbt]?"),""),g>=r&&!e||"t"===e?(q+=m.abbreviations.trillion,a/=r):r>g&&g>=s&&!e||"b"===e?(q+=m.abbreviations.billion,a/=s):s>g&&g>=t&&!e||"m"===e?(q+=m.abbreviations.million,a/=t):(t>g&&g>=u&&!e||"k"===e)&&(q+=m.abbreviations.thousand,a/=u)),b._.includes(c,"[.]")&&(o=!0,c=c.replace("[.]",".")),h=a.toString().split(".")[0],i=c.split(".")[1],k=c.indexOf(","),p=(c.split(".")[0].split(",")[0].match(/0/g)||[]).length,i?(b._.includes(i,"[")?(i=i.replace("]",""),i=i.split("["),v=b._.toFixed(a,i[0].length+i[1].length,d,i[1].length)):v=b._.toFixed(a,i.length,d),h=v.split(".")[0],v=b._.includes(v,".")?m.delimiters.decimal+v.split(".")[1]:"",o&&0===Number(v.slice(1))&&(v="")):h=b._.toFixed(a,0,d),q&&!e&&Number(h)>=1e3&&q!==m.abbreviations.trillion)switch(h=String(Number(h)/1e3),q){case m.abbreviations.thousand:q=m.abbreviations.million;break;case m.abbreviations.million:q=m.abbreviations.billion;break;case m.abbreviations.billion:q=m.abbreviations.trillion}if(b._.includes(h,"-")&&(h=h.slice(1),w=!0),h.length<p)for(var x=p-h.length;x>0;x--)h="0"+h;return k>-1&&(h=h.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+m.delimiters.thousands)),0===c.indexOf(".")&&(h=""),l=h+v+(q?q:""),n?l=(n&&w?"(":"")+l+(n&&w?")":""):j>=0?l=0===j?(w?"-":"+")+l:l+(w?"-":"+"):w&&(l="-"+l),l},stringToNumber:function(a){var b,c,d,e=f[h.currentLocale],g=a,i={thousand:3,million:6,billion:9,trillion:12};if(h.zeroFormat&&a===h.zeroFormat)c=0;else if(h.nullFormat&&a===h.nullFormat||!a.replace(/[^0-9]+/g,"").length)c=null;else{c=1,"."!==e.delimiters.decimal&&(a=a.replace(/\./g,"").replace(e.delimiters.decimal,"."));for(b in i)if(d=new RegExp("[^a-zA-Z]"+e.abbreviations[b]+"(?:\\)|(\\"+e.currency.symbol+")?(?:\\))?)?$"),g.match(d)){c*=Math.pow(10,i[b]);break}c*=(a.split("-").length+Math.min(a.split("(").length-1,a.split(")").length-1))%2?1:-1,a=a.replace(/[^0-9\.]+/g,""),c*=Number(a)}return c},isNaN:function(a){return"number"==typeof a&&isNaN(a)},includes:function(a,b){return-1!==a.indexOf(b)},insert:function(a,b,c){return a.slice(0,c)+b+a.slice(c)},reduce:function(a,b){if(null===this)throw new TypeError("Array.prototype.reduce called on null or undefined");if("function"!=typeof b)throw new TypeError(b+" is not a function");var c,d=Object(a),e=d.length>>>0,f=0;if(3===arguments.length)c=arguments[2];else{for(;e>f&&!(f in d);)f++;if(f>=e)throw new TypeError("Reduce of empty array with no initial value");c=d[f++]}for(;e>f;f++)f in d&&(c=b(c,d[f],f,d));return c},multiplier:function(a){var b=a.toString().split(".");return b.length<2?1:Math.pow(10,b[1].length)},correctionFactor:function(){var a=Array.prototype.slice.call(arguments);return a.reduce(function(a,b){var d=c.multiplier(b);return a>d?a:d},1)},toFixed:function(a,b,c,d){var e,f,g,h,i=a.toString().split("."),j=b-(d||0);return e=2===i.length?Math.min(Math.max(i[1].length,j),b):j,g=Math.pow(10,e),h=(c(a+"e+"+e)/g).toFixed(e),d>b-e&&(f=new RegExp("\\.?0{1,"+(d-(b-e))+"}$"),h=h.replace(f,"")),h}},b.options=h,b.formats=e,b.locales=f,b.locale=function(a){return a&&(h.currentLocale=a.toLowerCase()),h.currentLocale},b.localeData=function(a){if(!a)return f[h.currentLocale];if(a=a.toLowerCase(),!f[a])throw new Error("Unknown locale : "+a);return f[a]},b.reset=function(){for(var a in g)h[a]=g[a]},b.zeroFormat=function(a){h.zeroFormat="string"==typeof a?a:null},b.nullFormat=function(a){h.nullFormat="string"==typeof a?a:null},b.defaultFormat=function(a){h.defaultFormat="string"==typeof a?a:"0.0"},b.register=function(a,b,c){if(b=b.toLowerCase(),this[a+"s"][b])throw new TypeError(b+" "+a+" already registered.");return this[a+"s"][b]=c,c},b.validate=function(a,c){var d,e,f,g,h,i,j,k;if("string"!=typeof a&&(a+="",console.warn&&console.warn("Numeral.js: Value is not string. It has been co-erced to: ",a)),a=a.trim(),a.match(/^\d+$/))return!0;if(""===a)return!1;try{j=b.localeData(c)}catch(l){j=b.localeData(b.locale())}return f=j.currency.symbol,h=j.abbreviations,d=j.delimiters.decimal,e="."===j.delimiters.thousands?"\\.":j.delimiters.thousands,k=a.match(/^[^\d]+/),null!==k&&(a=a.substr(1),k[0]!==f)?!1:(k=a.match(/[^\d]+$/),null!==k&&(a=a.slice(0,-1),k[0]!==h.thousand&&k[0]!==h.million&&k[0]!==h.billion&&k[0]!==h.trillion)?!1:(i=new RegExp(e+"{2}"),a.match(/[^\d.,]/g)?!1:(g=a.split(d),g.length>2?!1:g.length<2?!!g[0].match(/^\d+.*\d$/)&&!g[0].match(i):1===g[0].length?!!g[0].match(/^\d+$/)&&!g[0].match(i)&&!!g[1].match(/^\d+$/):!!g[0].match(/^\d+.*\d$/)&&!g[0].match(i)&&!!g[1].match(/^\d+$/))))},b.fn=a.prototype={clone:function(){return b(this)},format:function(a,c){var d,f,g,i=this._value,j=a||h.defaultFormat;if(c=c||Math.round,0===i&&null!==h.zeroFormat)f=h.zeroFormat;else if(null===i&&null!==h.nullFormat)f=h.nullFormat;else{for(d in e)if(j.match(e[d].regexps.format)){g=e[d].format;break}g=g||b._.numberToFormat,f=g(i,j,c)}return f},value:function(){return this._value},input:function(){return this._input},set:function(a){return this._value=Number(a),this},add:function(a){function b(a,b,c,e){return a+Math.round(d*b)}var d=c.correctionFactor.call(null,this._value,a);return this._value=c.reduce([this._value,a],b,0)/d,this},subtract:function(a){function b(a,b,c,e){return a-Math.round(d*b)}var d=c.correctionFactor.call(null,this._value,a);return this._value=c.reduce([a],b,Math.round(this._value*d))/d,this},multiply:function(a){function b(a,b,d,e){var f=c.correctionFactor(a,b);return Math.round(a*f)*Math.round(b*f)/Math.round(f*f)}return this._value=c.reduce([this._value,a],b,1),this},divide:function(a){function b(a,b,d,e){var f=c.correctionFactor(a,b);return Math.round(a*f)/Math.round(b*f)}return this._value=c.reduce([this._value,a],b),this},difference:function(a){return Math.abs(b(this._value).subtract(a).value())}},b.register("locale","en",{delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th"},currency:{symbol:"$"}}),function(){b.register("format","bps",{regexps:{format:/(BPS)/,unformat:/(BPS)/},format:function(a,c,d){var e,f=b._.includes(c," BPS")?" ":"";return a=1e4*a,c=c.replace(/\s?BPS/,""),e=b._.numberToFormat(a,c,d),b._.includes(e,")")?(e=e.split(""),e.splice(-1,0,f+"BPS"),e=e.join("")):e=e+f+"BPS",e},unformat:function(a){return+(1e-4*b._.stringToNumber(a)).toFixed(15)}})}(),function(){var a={base:1e3,suffixes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]},c={base:1024,suffixes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},d=a.suffixes.concat(c.suffixes.filter(function(b){return a.suffixes.indexOf(b)<0})),e=d.join("|");e="("+e.replace("B","B(?!PS)")+")",b.register("format","bytes",{regexps:{format:/([0\s]i?b)/,unformat:new RegExp(e)},format:function(d,e,f){var g,h,i,j,k=b._.includes(e,"ib")?c:a,l=b._.includes(e," b")||b._.includes(e," ib")?" ":"";for(e=e.replace(/\s?i?b/,""),h=0;h<=k.suffixes.length;h++)if(i=Math.pow(k.base,h),j=Math.pow(k.base,h+1),null===d||0===d||d>=i&&j>d){l+=k.suffixes[h],i>0&&(d/=i);break}return g=b._.numberToFormat(d,e,f),g+l},unformat:function(d){var e,f,g=b._.stringToNumber(d);if(g){for(e=a.suffixes.length-1;e>=0;e--){if(b._.includes(d,a.suffixes[e])){f=Math.pow(a.base,e);break}if(b._.includes(d,c.suffixes[e])){f=Math.pow(c.base,e);break}}g*=f||1}return g}})}(),function(){b.register("format","currency",{regexps:{format:/(\$)/},format:function(a,c,d){var e,f,g,h=b.locales[b.options.currentLocale],i={before:c.match(/^([\+|\-|\(|\s|\$]*)/)[0],after:c.match(/([\+|\-|\)|\s|\$]*)$/)[0]};for(c=c.replace(/\s?\$\s?/,""),e=b._.numberToFormat(a,c,d),a>=0?(i.before=i.before.replace(/[\-\(]/,""),i.after=i.after.replace(/[\-\)]/,"")):0>a&&!b._.includes(i.before,"-")&&!b._.includes(i.before,"(")&&(i.before="-"+i.before),g=0;g<i.before.length;g++)switch(f=i.before[g]){case"$":e=b._.insert(e,h.currency.symbol,g);break;case" ":e=b._.insert(e," ",g+h.currency.symbol.length-1)}for(g=i.after.length-1;g>=0;g--)switch(f=i.after[g]){case"$":e=g===i.after.length-1?e+h.currency.symbol:b._.insert(e,h.currency.symbol,-(i.after.length-(1+g)));break;case" ":e=g===i.after.length-1?e+" ":b._.insert(e," ",-(i.after.length-(1+g)+h.currency.symbol.length-1))}return e}})}(),function(){b.register("format","exponential",{regexps:{format:/(e\+|e-)/,unformat:/(e\+|e-)/},format:function(a,c,d){var e,f="number"!=typeof a||b._.isNaN(a)?"0e+0":a.toExponential(),g=f.split("e");return c=c.replace(/e[\+|\-]{1}0/,""),e=b._.numberToFormat(Number(g[0]),c,d),e+"e"+g[1]},unformat:function(a){function c(a,c,d,e){var f=b._.correctionFactor(a,c),g=a*f*(c*f)/(f*f);return g}var d=b._.includes(a,"e+")?a.split("e+"):a.split("e-"),e=Number(d[0]),f=Number(d[1]);return f=b._.includes(a,"e-")?f*=-1:f,b._.reduce([e,Math.pow(10,f)],c,1)}})}(),function(){b.register("format","ordinal",{regexps:{format:/(o)/},format:function(a,c,d){var e,f=b.locales[b.options.currentLocale],g=b._.includes(c," o")?" ":"";return c=c.replace(/\s?o/,""),g+=f.ordinal(a),e=b._.numberToFormat(a,c,d),e+g}})}(),function(){b.register("format","percentage",{regexps:{format:/(%)/,unformat:/(%)/},format:function(a,c,d){var e,f=b._.includes(c," %")?" ":"";return b.options.scalePercentBy100&&(a=100*a),c=c.replace(/\s?\%/,""),e=b._.numberToFormat(a,c,d),b._.includes(e,")")?(e=e.split(""),e.splice(-1,0,f+"%"),e=e.join("")):e=e+f+"%",e},unformat:function(a){var c=b._.stringToNumber(a);return b.options.scalePercentBy100?.01*c:c}})}(),function(){b.register("format","time",{regexps:{format:/(:)/,unformat:/(:)/},format:function(a,b,c){var d=Math.floor(a/60/60),e=Math.floor((a-60*d*60)/60),f=Math.round(a-60*d*60-60*e);return d+":"+(10>e?"0"+e:e)+":"+(10>f?"0"+f:f)},unformat:function(a){var b=a.split(":"),c=0;return 3===b.length?(c+=60*Number(b[0])*60,c+=60*Number(b[1]),c+=Number(b[2])):2===b.length&&(c+=60*Number(b[0]),c+=Number(b[1])),Number(c)}})}(),b});
17890 17891/** 17892 * @license 17893 * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/> 17894 * Build: `lodash modern -o ./dist/lodash.js` 17895 * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/> 17896 * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE> 17897 * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 17898 * Available under MIT license <http://lodash.com/license> 17899 */ 17900 17901;(function() { 17902 17903 /** Used as a safe reference for `undefined` in pre ES5 environments */ 17904 var undefined; 17905 17906 /** Used to pool arrays and objects used internally */ 17907 var arrayPool = [], 17908 objectPool = []; 17909 17910 /** Used to generate unique IDs */ 17911 var idCounter = 0; 17912 17913 /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */ 17914 var keyPrefix = +new Date + ''; 17915 17916 /** Used as the size when optimizations are enabled for large arrays */ 17917 var largeArraySize = 75; 17918 17919 /** Used as the max size of the `arrayPool` and `objectPool` */ 17920 var maxPoolSize = 40; 17921 17922 /** Used to detect and test whitespace */ 17923 var whitespace = ( 17924 // whitespace 17925 ' \t\x0B\f\xA0\ufeff' + 17926 17927 // line terminators 17928 '\n\r\u2028\u2029' + 17929 17930 // unicode category "Zs" space separators 17931 '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000' 17932 ); 17933 17934 /** Used to match empty string literals in compiled template source */ 17935 var reEmptyStringLeading = /\b__p \+= '';/g, 17936 reEmptyStringMiddle = /\b(__p \+=) '' \+/g, 17937 reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; 17938 17939 /** 17940 * Used to match ES6 template delimiters 17941 * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals 17942 */ 17943 var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; 17944 17945 /** Used to match regexp flags from their coerced string values */ 17946 var reFlags = /\w*$/; 17947 17948 /** Used to detected named functions */ 17949 var reFuncName = /^\s*function[ \n\r\t]+\w/; 17950 17951 /** Used to match "interpolate" template delimiters */ 17952 var reInterpolate = /<%=([\s\S]+?)%>/g; 17953 17954 /** Used to match leading whitespace and zeros to be removed */ 17955 var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)'); 17956 17957 /** Used to ensure capturing order of template delimiters */ 17958 var reNoMatch = /($^)/; 17959 17960 /** Used to detect functions containing a `this` reference */ 17961 var reThis = /\bthis\b/; 17962 17963 /** Used to match unescaped characters in compiled string literals */ 17964 var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g; 17965 17966 /** Used to assign default `context` object properties */ 17967 var contextProps = [ 17968 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 17969 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 17970 'parseInt', 'setTimeout' 17971 ]; 17972 17973 /** Used to make template sourceURLs easier to identify */ 17974 var templateCounter = 0; 17975 17976 /** `Object#toString` result shortcuts */ 17977 var argsClass = '[object Arguments]', 17978 arrayClass = '[object Array]', 17979 boolClass = '[object Boolean]', 17980 dateClass = '[object Date]', 17981 funcClass = '[object Function]', 17982 numberClass = '[object Number]', 17983 objectClass = '[object Object]', 17984 regexpClass = '[object RegExp]', 17985 stringClass = '[object String]'; 17986 17987 /** Used to identify object classifications that `_.clone` supports */ 17988 var cloneableClasses = {}; 17989 cloneableClasses[funcClass] = false; 17990 cloneableClasses[argsClass] = cloneableClasses[arrayClass] = 17991 cloneableClasses[boolClass] = cloneableClasses[dateClass] = 17992 cloneableClasses[numberClass] = cloneableClasses[objectClass] = 17993 cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; 17994 17995 /** Used as an internal `_.debounce` options object */ 17996 var debounceOptions = { 17997 'leading': false, 17998 'maxWait': 0, 17999 'trailing': false 18000 }; 18001 18002 /** Used as the property descriptor for `__bindData__` */ 18003 var descriptor = { 18004 'configurable': false, 18005 'enumerable': false, 18006 'value': null, 18007 'writable': false 18008 }; 18009 18010 /** Used to determine if values are of the language type Object */ 18011 var objectTypes = { 18012 'boolean': false, 18013 'function': true, 18014 'object': true, 18015 'number': false, 18016 'string': false, 18017 'undefined': false 18018 }; 18019 18020 /** Used to escape characters for inclusion in compiled string literals */ 18021 var stringEscapes = { 18022 '\\': '\\', 18023 "'": "'", 18024 '\n': 'n', 18025 '\r': 'r', 18026 '\t': 't', 18027 '\u2028': 'u2028', 18028 '\u2029': 'u2029' 18029 }; 18030 18031 /** Used as a reference to the global object */ 18032 var root = (objectTypes[typeof window] && window) || this; 18033 18034 /** Detect free variable `exports` */ 18035 var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; 18036 18037 /** Detect free variable `module` */ 18038 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; 18039 18040 /** Detect the popular CommonJS extension `module.exports` */ 18041 var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; 18042 18043 /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */ 18044 var freeGlobal = objectTypes[typeof global] && global; 18045 if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) { 18046 root = freeGlobal; 18047 } 18048 18049 /*--------------------------------------------------------------------------*/ 18050 18051 /** 18052 * The base implementation of `_.indexOf` without support for binary searches 18053 * or `fromIndex` constraints. 18054 * 18055 * @private 18056 * @param {Array} array The array to search. 18057 * @param {*} value The value to search for. 18058 * @param {number} [fromIndex=0] The index to search from. 18059 * @returns {number} Returns the index of the matched value or `-1`. 18060 */ 18061 function baseIndexOf(array, value, fromIndex) { 18062 var index = (fromIndex || 0) - 1, 18063 length = array ? array.length : 0; 18064 18065 while (++index < length) { 18066 if (array[index] === value) { 18067 return index; 18068 } 18069 } 18070 return -1; 18071 } 18072 18073 /** 18074 * An implementation of `_.contains` for cache objects that mimics the return 18075 * signature of `_.indexOf` by returning `0` if the value is found, else `-1`. 18076 * 18077 * @private 18078 * @param {Object} cache The cache object to inspect. 18079 * @param {*} value The value to search for. 18080 * @returns {number} Returns `0` if `value` is found, else `-1`. 18081 */ 18082 function cacheIndexOf(cache, value) { 18083 var type = typeof value;
18084 cache = cache.cache; 18085 18086 if (type == 'boolean' || value == null) { 18087 return cache[value] ? 0 : -1; 18088 } 18089 if (type != 'number' && type != 'string') { 18090 type = 'object'; 18091 } 18092 var key = type == 'number' ? value : keyPrefix + value; 18093 cache = (cache = cache[type]) && cache[key]; 18094 18095 return type == 'object' 18096 ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1) 18097 : (cache ? 0 : -1); 18098 } 18099 18100 /** 18101 * Adds a given value to the corresponding cache object. 18102 * 18103 * @private 18104 * @param {*} value The value to add to the cache. 18105 */ 18106 function cachePush(value) { 18107 var cache = this.cache, 18108 type = typeof value; 18109 18110 if (type == 'boolean' || value == null) { 18111 cache[value] = true; 18112 } else { 18113 if (type != 'number' && type != 'string') { 18114 type = 'object'; 18115 } 18116 var key = type == 'number' ? value : keyPrefix + value, 18117 typeCache = cache[type] || (cache[type] = {}); 18118 18119 if (type == 'object') { 18120 (typeCache[key] || (typeCache[key] = [])).push(value); 18121 } else { 18122 typeCache[key] = true; 18123 } 18124 } 18125 } 18126 18127 /** 18128 * Used by `_.max` and `_.min` as the default callback when a given 18129 * collection is a string value. 18130 * 18131 * @private 18132 * @param {string} value The character to inspect. 18133 * @returns {number} Returns the code unit of given character. 18134 */ 18135 function charAtCallback(value) { 18136 return value.charCodeAt(0); 18137 } 18138 18139 /** 18140 * Used by `sortBy` to compare transformed `collection` elements, stable sorting 18141 * them in ascending order. 18142 * 18143 * @private 18144 * @param {Object} a The object to compare to `b`. 18145 * @param {Object} b The object to compare to `a`. 18146 * @returns {number} Returns the sort order indicator of `1` or `-1`. 18147 */ 18148 function compareAscending(a, b) { 18149 var ac = a.criteria, 18150 bc = b.criteria, 18151 index = -1, 18152 length = ac.length; 18153 18154 while (++index < length) { 18155 var value = ac[index], 18156 other = bc[index]; 18157 18158 if (value !== other) { 18159 if (value > other || typeof value == 'undefined') { 18160 return 1; 18161 } 18162 if (value < other || typeof other == 'undefined') { 18163 return -1; 18164 } 18165 } 18166 } 18167 // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications 18168 // that causes it, under certain circumstances, to return the same value for 18169 // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 18170 // 18171 // This also ensures a stable sort in V8 and other engines. 18172 // See http://code.google.com/p/v8/issues/detail?id=90 18173 return a.index - b.index; 18174 } 18175 18176 /** 18177 * Creates a cache object to optimize linear searches of large arrays. 18178 * 18179 * @private 18180 * @param {Array} [array=[]] The array to search. 18181 * @returns {null|Object} Returns the cache object or `null` if caching should not be used. 18182 */ 18183 function createCache(array) { 18184 var index = -1, 18185 length = array.length, 18186 first = array[0], 18187 mid = array[(length / 2) | 0], 18188 last = array[length - 1]; 18189 18190 if (first && typeof first == 'object' && 18191 mid && typeof mid == 'object' && last && typeof last == 'object') { 18192 return false; 18193 } 18194 var cache = getObject(); 18195 cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false; 18196 18197 var result = getObject(); 18198 result.array = array; 18199 result.cache = cache; 18200 result.push = cachePush; 18201 18202 while (++index < length) { 18203 result.push(array[index]); 18204 } 18205 return result; 18206 } 18207 18208 /** 18209 * Used by `template` to escape characters for inclusion in compiled 18210 * string literals. 18211 * 18212 * @private 18213 * @param {string} match The matched character to escape. 18214 * @returns {string} Returns the escaped character. 18215 */ 18216 function escapeStringChar(match) { 18217 return '\\' + stringEscapes[match]; 18218 } 18219 18220 /** 18221 * Gets an array from the array pool or creates a new one if the pool is empty. 18222 * 18223 * @private 18224 * @returns {Array} The array from the pool. 18225 */ 18226 function getArray() { 18227 return arrayPool.pop() || []; 18228 } 18229 18230 /** 18231 * Gets an object from the object pool or creates a new one if the pool is empty. 18232 * 18233 * @private 18234 * @returns {Object} The object from the pool. 18235 */ 18236 function getObject() { 18237 return objectPool.pop() || { 18238 'array': null, 18239 'cache': null, 18240 'criteria': null, 18241 'false': false, 18242 'index': 0, 18243 'null': false, 18244 'number': null, 18245 'object': null, 18246 'push': null, 18247 'string': null, 18248 'true': false, 18249 'undefined': false, 18250 'value': null 18251 }; 18252 } 18253 18254 /** 18255 * Releases the given array back to the array pool. 18256 * 18257 * @private 18258 * @param {Array} [array] The array to release. 18259 */ 18260 function releaseArray(array) { 18261 array.length = 0; 18262 if (arrayPool.length < maxPoolSize) { 18263 arrayPool.push(array); 18264 } 18265 } 18266 18267 /** 18268 * Releases the given object back to the object pool. 18269 * 18270 * @private 18271 * @param {Object} [object] The object to release. 18272 */ 18273 function releaseObject(object) { 18274 var cache = object.cache;
18275 if (cache) { 18276 releaseObject(cache); 18277 } 18278 object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; 18279 if (objectPool.length < maxPoolSize) { 18280 objectPool.push(object); 18281 } 18282 } 18283 18284 /** 18285 * Slices the `collection` from the `start` index up to, but not including, 18286 * the `end` index. 18287 * 18288 * Note: This function is used instead of `Array#slice` to support node lists 18289 * in IE < 9 and to ensure dense arrays are returned. 18290 * 18291 * @private 18292 * @param {Array|Object|string} collection The collection to slice. 18293 * @param {number} start The start index. 18294 * @param {number} end The end index. 18295 * @returns {Array} Returns the new array. 18296 */ 18297 function slice(array, start, end) { 18298 start || (start = 0); 18299 if (typeof end == 'undefined') { 18300 end = array ? array.length : 0; 18301 } 18302 var index = -1, 18303 length = end - start || 0, 18304 result = Array(length < 0 ? 0 : length); 18305 18306 while (++index < length) { 18307 result[index] = array[start + index]; 18308 } 18309 return result; 18310 } 18311 18312 /*--------------------------------------------------------------------------*/ 18313 18314 /** 18315 * Create a new `lodash` function using the given context object. 18316 * 18317 * @static 18318 * @memberOf _ 18319 * @category Utilities 18320 * @param {Object} [context=root] The context object. 18321 * @returns {Function} Returns the `lodash` function. 18322 */ 18323 function runInContext(context) { 18324 // Avoid issues with some ES3 environments that attempt to use values, named 18325 // after built-in constructors like `Object`, for the creation of literals. 18326 // ES5 clears this up by stating that literals must use built-in constructors. 18327 // See http://es5.github.io/#x11.1.5. 18328 context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; 18329 18330 /** Native constructor references */ 18331 var Array = context.Array, 18332 Boolean = context.Boolean, 18333 Date = context.Date, 18334 Function = context.Function, 18335 Math = context.Math, 18336 Number = context.Number, 18337 Object = context.Object, 18338 RegExp = context.RegExp, 18339 String = context.String, 18340 TypeError = context.TypeError; 18341 18342 /** 18343 * Used for `Array` method references. 18344 * 18345 * Normally `Array.prototype` would suffice, however, using an array literal 18346 * avoids issues in Narwhal. 18347 */ 18348 var arrayRef = []; 18349 18350 /** Used for native method references */ 18351 var objectProto = Object.prototype; 18352 18353 /** Used to restore the original `_` reference in `noConflict` */ 18354 var oldDash = context._; 18355 18356 /** Used to resolve the internal [[Class]] of values */ 18357 var toString = objectProto.toString; 18358 18359 /** Used to detect if a method is native */ 18360 var reNative = RegExp('^' + 18361 String(toString) 18362 .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') 18363 .replace(/toString| for [^\]]+/g, '.*?') + '$' 18364 ); 18365 18366 /** Native method shortcuts */ 18367 var ceil = Math.ceil, 18368 clearTimeout = context.clearTimeout, 18369 floor = Math.floor, 18370 fnToString = Function.prototype.toString, 18371 getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, 18372 hasOwnProperty = objectProto.hasOwnProperty, 18373 push = arrayRef.push, 18374 setTimeout = context.setTimeout, 18375 splice = arrayRef.splice, 18376 unshift = arrayRef.unshift; 18377 18378 /** Used to set meta data on functions */ 18379 var defineProperty = (function() { 18380 // IE 8 only accepts DOM elements 18381 try { 18382 var o = {}, 18383 func = isNative(func = Object.defineProperty) && func, 18384 result = func(o, o, o) && func; 18385 } catch(e) { } 18386 return result; 18387 }()); 18388 18389 /* Native method shortcuts for methods with the same name as other `lodash` methods */ 18390 var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate, 18391 nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
18392 nativeIsFinite = context.isFinite, 18393 nativeIsNaN = context.isNaN, 18394 nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, 18395 nativeMax = Math.max, 18396 nativeMin = Math.min, 18397 nativeParseInt = context.parseInt, 18398 nativeRandom = Math.random; 18399 18400 /** Used to lookup a built-in constructor by [[Class]] */ 18401 var ctorByClass = {}; 18402 ctorByClass[arrayClass] = Array; 18403 ctorByClass[boolClass] = Boolean; 18404 ctorByClass[dateClass] = Date; 18405 ctorByClass[funcClass] = Function; 18406 ctorByClass[objectClass] = Object; 18407 ctorByClass[numberClass] = Number; 18408 ctorByClass[regexpClass] = RegExp; 18409 ctorByClass[stringClass] = String; 18410 18411 /*--------------------------------------------------------------------------*/ 18412 18413 /** 18414 * Creates a `lodash` object which wraps the given value to enable intuitive 18415 * method chaining. 18416 * 18417 * In addition to Lo-Dash methods, wrappers also have the following `Array` methods: 18418 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`, 18419 * and `unshift` 18420 * 18421 * Chaining is supported in custom builds as long as the `value` method is 18422 * implicitly or explicitly included in the build. 18423 * 18424 * The chainable wrapper functions are: 18425 * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, 18426 * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`, 18427 * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, 18428 * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, 18429 * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, 18430 * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, 18431 * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, 18432 * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, 18433 * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`, 18434 * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`, 18435 * and `zip` 18436 * 18437 * The non-chainable wrapper functions are: 18438 * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`, 18439 * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`, 18440 * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, 18441 * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, 18442 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, 18443 * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`, 18444 * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`, 18445 * `template`, `unescape`, `uniqueId`, and `value` 18446 * 18447 * The wrapper functions `first` and `last` return wrapped values when `n` is 18448 * provided, otherwise they return unwrapped values. 18449 * 18450 * Explicit chaining can be enabled by using the `_.chain` method. 18451 * 18452 * @name _ 18453 * @constructor 18454 * @category Chaining 18455 * @param {*} value The value to wrap in a `lodash` instance. 18456 * @returns {Object} Returns a `lodash` instance. 18457 * @example 18458 * 18459 * var wrapped = _([1, 2, 3]); 18460 * 18461 * // returns an unwrapped value 18462 * wrapped.reduce(function(sum, num) { 18463 * return sum + num; 18464 * }); 18465 * // => 6 18466 * 18467 * // returns a wrapped value 18468 * var squares = wrapped.map(function(num) { 18469 * return num * num; 18470 * }); 18471 * 18472 * _.isArray(squares); 18473 * // => false 18474 * 18475 * _.isArray(squares.value()); 18476 * // => true 18477 */ 18478 function lodash(value) { 18479 // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor 18480 return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__')) 18481 ? value 18482 : new lodashWrapper(value); 18483 } 18484 18485 /** 18486 * A fast path for creating `lodash` wrapper objects. 18487 * 18488 * @private 18489 * @param {*} value The value to wrap in a `lodash` instance. 18490 * @param {boolean} chainAll A flag to enable chaining for all methods 18491 * @returns {Object} Returns a `lodash` instance. 18492 */ 18493 function lodashWrapper(value, chainAll) { 18494 this.__chain__ = !!chainAll; 18495 this.__wrapped__ = value; 18496 } 18497 // ensure `new lodashWrapper` is an instance of `lodash` 18498 lodashWrapper.prototype = lodash.prototype; 18499 18500 /** 18501 * An object used to flag environments features. 18502 * 18503 * @static 18504 * @memberOf _ 18505 * @type Object 18506 */ 18507 var support = lodash.support = {}; 18508 18509 /** 18510 * Detect if functions can be decompiled by `Function#toString` 18511 * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). 18512 * 18513 * @memberOf _.support 18514 * @type boolean 18515 */ 18516 support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext); 18517 18518 /** 18519 * Detect if `Function#name` is supported (all but IE). 18520 * 18521 * @memberOf _.support 18522 * @type boolean 18523 */ 18524 support.funcNames = typeof Function.name == 'string'; 18525 18526 /** 18527 * By default, the template delimiters used by Lo-Dash are similar to those in 18528 * embedded Ruby (ERB). Change the following template settings to use alternative 18529 * delimiters. 18530 * 18531 * @static 18532 * @memberOf _ 18533 * @type Object 18534 */ 18535 lodash.templateSettings = { 18536 18537 /** 18538 * Used to detect `data` property values to be HTML-escaped. 18539 * 18540 * @memberOf _.templateSettings 18541 * @type RegExp 18542 */ 18543 'escape': /<%-([\s\S]+?)%>/g, 18544 18545 /** 18546 * Used to detect code to be evaluated. 18547 * 18548 * @memberOf _.templateSettings 18549 * @type RegExp 18550 */ 18551 'evaluate': /<%([\s\S]+?)%>/g, 18552 18553 /** 18554 * Used to detect `data` property values to inject. 18555 * 18556 * @memberOf _.templateSettings 18557 * @type RegExp 18558 */ 18559 'interpolate': reInterpolate, 18560 18561 /** 18562 * Used to reference the data object in the template text. 18563 * 18564 * @memberOf _.templateSettings 18565 * @type string 18566 */ 18567 'variable': '', 18568 18569 /** 18570 * Used to import variables into the compiled template. 18571 * 18572 * @memberOf _.templateSettings 18573 * @type Object 18574 */ 18575 'imports': { 18576 18577 /** 18578 * A reference to the `lodash` function. 18579 * 18580 * @memberOf _.templateSettings.imports 18581 * @type Function 18582 */ 18583 '_': lodash 18584 } 18585 }; 18586 18587 /*--------------------------------------------------------------------------*/ 18588 18589 /** 18590 * The base implementation of `_.bind` that creates the bound function and 18591 * sets its meta data. 18592 * 18593 * @private 18594 * @param {Array} bindData The bind data array.
18595 * @returns {Function} Returns the new bound function. 18596 */ 18597 function baseBind(bindData) { 18598 var func = bindData[0], 18599 partialArgs = bindData[2], 18600 thisArg = bindData[4]; 18601 18602 function bound() { 18603 // `Function#bind` spec 18604 // http://es5.github.io/#x15.3.4.5 18605 if (partialArgs) { 18606 // avoid `arguments` object deoptimizations by using `slice` instead 18607 // of `Array.prototype.slice.call` and not assigning `arguments` to a 18608 // variable as a ternary expression 18609 var args = slice(partialArgs); 18610 push.apply(args, arguments); 18611 } 18612 // mimic the constructor's `return` behavior 18613 // http://es5.github.io/#x13.2.2 18614 if (this instanceof bound) { 18615 // ensure `new bound` is an instance of `func` 18616 var thisBinding = baseCreate(func.prototype), 18617 result = func.apply(thisBinding, args || arguments); 18618 return isObject(result) ? result : thisBinding; 18619 } 18620 return func.apply(thisArg, args || arguments); 18621 } 18622 setBindData(bound, bindData); 18623 return bound; 18624 } 18625 18626 /** 18627 * The base implementation of `_.clone` without argument juggling or support 18628 * for `thisArg` binding. 18629 * 18630 * @private 18631 * @param {*} value The value to clone. 18632 * @param {boolean} [isDeep=false] Specify a deep clone. 18633 * @param {Function} [callback] The function to customize cloning values. 18634 * @param {Array} [stackA=[]] Tracks traversed source objects. 18635 * @param {Array} [stackB=[]] Associates clones with source counterparts. 18636 * @returns {*} Returns the cloned value. 18637 */ 18638 function baseClone(value, isDeep, callback, stackA, stackB) { 18639 if (callback) { 18640 var result = callback(value); 18641 if (typeof result != 'undefined') { 18642 return result; 18643 } 18644 } 18645 // inspect [[Class]] 18646 var isObj = isObject(value); 18647 if (isObj) { 18648 var className = toString.call(value); 18649 if (!cloneableClasses[className]) { 18650 return value; 18651 } 18652 var ctor = ctorByClass[className]; 18653 switch (className) { 18654 case boolClass: 18655 case dateClass: 18656 return new ctor(+value); 18657 18658 case numberClass: 18659 case stringClass: 18660 return new ctor(value); 18661 18662 case regexpClass: 18663 result = ctor(value.source, reFlags.exec(value)); 18664 result.lastIndex = value.lastIndex; 18665 return result; 18666 } 18667 } else { 18668 return value; 18669 } 18670 var isArr = isArray(value); 18671 if (isDeep) { 18672 // check for circular references and return corresponding clone 18673 var initedStack = !stackA; 18674 stackA || (stackA = getArray()); 18675 stackB || (stackB = getArray()); 18676 18677 var length = stackA.length; 18678 while (length--) { 18679 if (stackA[length] == value) { 18680 return stackB[length]; 18681 } 18682 } 18683 result = isArr ? ctor(value.length) : {}; 18684 } 18685 else { 18686 result = isArr ? slice(value) : assign({}, value); 18687 } 18688 // add array properties assigned by `RegExp#exec` 18689 if (isArr) { 18690 if (hasOwnProperty.call(value, 'index')) { 18691 result.index = value.index; 18692 } 18693 if (hasOwnProperty.call(value, 'input')) { 18694 result.input = value.input; 18695 } 18696 } 18697 // exit for shallow clone 18698 if (!isDeep) { 18699 return result; 18700 } 18701 // add the source value to the stack of traversed objects 18702 // and associate it with its clone 18703 stackA.push(value); 18704 stackB.push(result); 18705 18706 // recursively populate clone (susceptible to call stack limits) 18707 (isArr ? forEach : forOwn)(value, function(objValue, key) { 18708 result[key] = baseClone(objValue, isDeep, callback, stackA, stackB); 18709 }); 18710 18711 if (initedStack) { 18712 releaseArray(stackA); 18713 releaseArray(stackB); 18714 } 18715 return result; 18716 } 18717 18718 /** 18719 * The base implementation of `_.create` without support for assigning 18720 * properties to the created object. 18721 * 18722 * @private 18723 * @param {Object} prototype The object to inherit from. 18724 * @returns {Object} Returns the new object. 18725 */ 18726 function baseCreate(prototype, properties) { 18727 return isObject(prototype) ? nativeCreate(prototype) : {}; 18728 } 18729 // fallback for browsers without `Object.create` 18730 if (!nativeCreate) { 18731 baseCreate = (function() { 18732 function Object() {} 18733 return function(prototype) { 18734 if (isObject(prototype)) { 18735 Object.prototype = prototype; 18736 var result = new Object; 18737 Object.prototype = null; 18738 } 18739 return result || context.Object(); 18740 }; 18741 }()); 18742 } 18743 18744 /** 18745 * The base implementation of `_.createCallback` without support for creating 18746 * "_.pluck" or "_.where" style callbacks. 18747 * 18748 * @private 18749 * @param {*} [func=identity] The value to convert to a callback. 18750 * @param {*} [thisArg] The `this` binding of the created callback. 18751 * @param {number} [argCount] The number of arguments the callback accepts. 18752 * @returns {Function} Returns a callback function. 18753 */ 18754 function baseCreateCallback(func, thisArg, argCount) { 18755 if (typeof func != 'function') { 18756 return identity; 18757 } 18758 // exit early for no `thisArg` or already bound by `Function#bind` 18759 if (typeof thisArg == 'undefined' || !('prototype' in func)) { 18760 return func; 18761 } 18762 var bindData = func.__bindData__; 18763 if (typeof bindData == 'undefined') { 18764 if (support.funcNames) { 18765 bindData = !func.name; 18766 } 18767 bindData = bindData || !support.funcDecomp; 18768 if (!bindData) { 18769 var source = fnToString.call(func); 18770 if (!support.funcNames) { 18771 bindData = !reFuncName.test(source); 18772 } 18773 if (!bindData) { 18774 // checks if `func` references the `this` keyword and stores the result 18775 bindData = reThis.test(source); 18776 setBindData(func, bindData); 18777 } 18778 } 18779 } 18780 // exit early if there are no `this` references or `func` is bound 18781 if (bindData === false || (bindData !== true && bindData[1] & 1)) { 18782 return func; 18783 } 18784 switch (argCount) { 18785 case 1: return function(value) { 18786 return func.call(thisArg, value); 18787 }; 18788 case 2: return function(a, b) { 18789 return func.call(thisArg, a, b); 18790 }; 18791 case 3: return function(value, index, collection) { 18792 return func.call(thisArg, value, index, collection); 18793 }; 18794 case 4: return function(accumulator, value, index, collection) { 18795 return func.call(thisArg, accumulator, value, index, collection); 18796 }; 18797 } 18798 return bind(func, thisArg); 18799 } 18800 18801 /** 18802 * The base implementation of `createWrapper` that creates the wrapper and 18803 * sets its meta data. 18804 * 18805 * @private 18806 * @param {Array} bindData The bind data array.
18807 * @returns {Function} Returns the new function. 18808 */ 18809 function baseCreateWrapper(bindData) { 18810 var func = bindData[0], 18811 bitmask = bindData[1], 18812 partialArgs = bindData[2], 18813 partialRightArgs = bindData[3], 18814 thisArg = bindData[4], 18815 arity = bindData[5]; 18816 18817 var isBind = bitmask & 1, 18818 isBindKey = bitmask & 2, 18819 isCurry = bitmask & 4, 18820 isCurryBound = bitmask & 8, 18821 key = func; 18822 18823 function bound() { 18824 var thisBinding = isBind ? thisArg : this; 18825 if (partialArgs) { 18826 var args = slice(partialArgs); 18827 push.apply(args, arguments); 18828 } 18829 if (partialRightArgs || isCurry) { 18830 args || (args = slice(arguments)); 18831 if (partialRightArgs) { 18832 push.apply(args, partialRightArgs); 18833 } 18834 if (isCurry && args.length < arity) { 18835 bitmask |= 16 & ~32; 18836 return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); 18837 } 18838 } 18839 args || (args = arguments); 18840 if (isBindKey) { 18841 func = thisBinding[key]; 18842 } 18843 if (this instanceof bound) { 18844 thisBinding = baseCreate(func.prototype); 18845 var result = func.apply(thisBinding, args); 18846 return isObject(result) ? result : thisBinding; 18847 } 18848 return func.apply(thisBinding, args); 18849 } 18850 setBindData(bound, bindData); 18851 return bound; 18852 } 18853 18854 /** 18855 * The base implementation of `_.difference` that accepts a single array 18856 * of values to exclude. 18857 * 18858 * @private 18859 * @param {Array} array The array to process. 18860 * @param {Array} [values] The array of values to exclude. 18861 * @returns {Array} Returns a new array of filtered values. 18862 */ 18863 function baseDifference(array, values) { 18864 var index = -1, 18865 indexOf = getIndexOf(), 18866 length = array ? array.length : 0, 18867 isLarge = length >= largeArraySize && indexOf === baseIndexOf, 18868 result = []; 18869 18870 if (isLarge) { 18871 var cache = createCache(values); 18872 if (cache) { 18873 indexOf = cacheIndexOf; 18874 values = cache; 18875 } else { 18876 isLarge = false; 18877 } 18878 } 18879 while (++index < length) { 18880 var value = array[index]; 18881 if (indexOf(values, value) < 0) { 18882 result.push(value); 18883 } 18884 } 18885 if (isLarge) { 18886 releaseObject(values); 18887 } 18888 return result; 18889 } 18890 18891 /** 18892 * The base implementation of `_.flatten` without support for callback 18893 * shorthands or `thisArg` binding. 18894 * 18895 * @private 18896 * @param {Array} array The array to flatten. 18897 * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. 18898 * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects. 18899 * @param {number} [fromIndex=0] The index to start from. 18900 * @returns {Array} Returns a new flattened array. 18901 */ 18902 function baseFlatten(array, isShallow, isStrict, fromIndex) { 18903 var index = (fromIndex || 0) - 1, 18904 length = array ? array.length : 0, 18905 result = []; 18906 18907 while (++index < length) { 18908 var value = array[index]; 18909 18910 if (value && typeof value == 'object' && typeof value.length == 'number' 18911 && (isArray(value) || isArguments(value))) { 18912 // recursively flatten arrays (susceptible to call stack limits) 18913 if (!isShallow) { 18914 value = baseFlatten(value, isShallow, isStrict); 18915 } 18916 var valIndex = -1, 18917 valLength = value.length, 18918 resIndex = result.length; 18919 18920 result.length += valLength; 18921 while (++valIndex < valLength) { 18922 result[resIndex++] = value[valIndex]; 18923 } 18924 } else if (!isStrict) { 18925 result.push(value); 18926 } 18927 } 18928 return result; 18929 } 18930 18931 /** 18932 * The base implementation of `_.isEqual`, without support for `thisArg` binding, 18933 * that allows partial "_.where" style comparisons. 18934 * 18935 * @private 18936 * @param {*} a The value to compare. 18937 * @param {*} b The other value to compare. 18938 * @param {Function} [callback] The function to customize comparing values. 18939 * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons. 18940 * @param {Array} [stackA=[]] Tracks traversed `a` objects. 18941 * @param {Array} [stackB=[]] Tracks traversed `b` objects. 18942 * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 18943 */ 18944 function baseIsEqual(a, b, callback, isWhere, stackA, stackB) { 18945 // used to indicate that when comparing objects, `a` has at least the properties of `b` 18946 if (callback) { 18947 var result = callback(a, b); 18948 if (typeof result != 'undefined') { 18949 return !!result; 18950 } 18951 } 18952 // exit early for identical values 18953 if (a === b) { 18954 // treat `+0` vs. `-0` as not equal 18955 return a !== 0 || (1 / a == 1 / b); 18956 } 18957 var type = typeof a, 18958 otherType = typeof b; 18959 18960 // exit early for unlike primitive values 18961 if (a === a && 18962 !(a && objectTypes[type]) && 18963 !(b && objectTypes[otherType])) { 18964 return false;
18965 } 18966 // exit early for `null` and `undefined` avoiding ES3's Function#call behavior 18967 // http://es5.github.io/#x15.3.4.4 18968 if (a == null || b == null) { 18969 return a === b; 18970 } 18971 // compare [[Class]] names 18972 var className = toString.call(a), 18973 otherClass = toString.call(b); 18974 18975 if (className == argsClass) { 18976 className = objectClass; 18977 } 18978 if (otherClass == argsClass) { 18979 otherClass = objectClass; 18980 } 18981 if (className != otherClass) { 18982 return false; 18983 } 18984 switch (className) { 18985 case boolClass: 18986 case dateClass: 18987 // coerce dates and booleans to numbers, dates to milliseconds and booleans 18988 // to `1` or `0` treating invalid dates coerced to `NaN` as not equal 18989 return +a == +b; 18990 18991 case numberClass: 18992 // treat `NaN` vs. `NaN` as equal 18993 return (a != +a) 18994 ? b != +b 18995 // but treat `+0` vs. `-0` as not equal 18996 : (a == 0 ? (1 / a == 1 / b) : a == +b); 18997 18998 case regexpClass: 18999 case stringClass: 19000 // coerce regexes to strings (http://es5.github.io/#x15.10.6.4) 19001 // treat string primitives and their corresponding object instances as equal 19002 return a == String(b); 19003 } 19004 var isArr = className == arrayClass; 19005 if (!isArr) { 19006 // unwrap any `lodash` wrapped values 19007 var aWrapped = hasOwnProperty.call(a, '__wrapped__'), 19008 bWrapped = hasOwnProperty.call(b, '__wrapped__'); 19009 19010 if (aWrapped || bWrapped) { 19011 return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB); 19012 } 19013 // exit for functions and DOM nodes 19014 if (className != objectClass) { 19015 return false; 19016 } 19017 // in older versions of Opera, `arguments` objects have `Array` constructors 19018 var ctorA = a.constructor, 19019 ctorB = b.constructor; 19020 19021 // non `Object` object instances with different constructors are not equal 19022 if (ctorA != ctorB && 19023 !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && 19024 ('constructor' in a && 'constructor' in b) 19025 ) { 19026 return false; 19027 } 19028 } 19029 // assume cyclic structures are equal 19030 // the algorithm for detecting cyclic structures is adapted from ES 5.1 19031 // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3) 19032 var initedStack = !stackA; 19033 stackA || (stackA = getArray()); 19034 stackB || (stackB = getArray()); 19035 19036 var length = stackA.length; 19037 while (length--) { 19038 if (stackA[length] == a) { 19039 return stackB[length] == b; 19040 } 19041 } 19042 var size = 0; 19043 result = true; 19044 19045 // add `a` and `b` to the stack of traversed objects 19046 stackA.push(a); 19047 stackB.push(b); 19048 19049 // recursively compare objects and arrays (susceptible to call stack limits) 19050 if (isArr) { 19051 // compare lengths to determine if a deep comparison is necessary 19052 length = a.length; 19053 size = b.length; 19054 result = size == length; 19055 19056 if (result || isWhere) { 19057 // deep compare the contents, ignoring non-numeric properties 19058 while (size--) { 19059 var index = length, 19060 value = b[size]; 19061 19062 if (isWhere) { 19063 while (index--) { 19064 if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { 19065 break; 19066 } 19067 } 19068 } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { 19069 break; 19070 } 19071 } 19072 } 19073 } 19074 else { 19075 // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` 19076 // which, in this case, is more costly 19077 forIn(b, function(value, key, b) { 19078 if (hasOwnProperty.call(b, key)) { 19079 // count the number of properties. 19080 size++; 19081 // deep compare each property value.
19082 return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); 19083 } 19084 }); 19085 19086 if (result && !isWhere) { 19087 // ensure both objects have the same number of properties 19088 forIn(a, function(value, key, a) { 19089 if (hasOwnProperty.call(a, key)) { 19090 // `size` will be `-1` if `a` has more properties than `b` 19091 return (result = --size > -1); 19092 } 19093 }); 19094 } 19095 } 19096 stackA.pop(); 19097 stackB.pop(); 19098 19099 if (initedStack) { 19100 releaseArray(stackA); 19101 releaseArray(stackB); 19102 } 19103 return result; 19104 } 19105 19106 /** 19107 * The base implementation of `_.merge` without argument juggling or support 19108 * for `thisArg` binding. 19109 * 19110 * @private 19111 * @param {Object} object The destination object. 19112 * @param {Object} source The source object. 19113 * @param {Function} [callback] The function to customize merging properties. 19114 * @param {Array} [stackA=[]] Tracks traversed source objects. 19115 * @param {Array} [stackB=[]] Associates values with source counterparts. 19116 */ 19117 function baseMerge(object, source, callback, stackA, stackB) { 19118 (isArray(source) ? forEach : forOwn)(source, function(source, key) { 19119 var found, 19120 isArr, 19121 result = source, 19122 value = object[key]; 19123 19124 if (source && ((isArr = isArray(source)) || isPlainObject(source))) { 19125 // avoid merging previously merged cyclic sources 19126 var stackLength = stackA.length; 19127 while (stackLength--) { 19128 if ((found = stackA[stackLength] == source)) { 19129 value = stackB[stackLength]; 19130 break; 19131 } 19132 } 19133 if (!found) { 19134 var isShallow; 19135 if (callback) { 19136 result = callback(value, source); 19137 if ((isShallow = typeof result != 'undefined')) { 19138 value = result; 19139 } 19140 } 19141 if (!isShallow) { 19142 value = isArr 19143 ? (isArray(value) ? value : []) 19144 : (isPlainObject(value) ? value : {}); 19145 } 19146 // add `source` and associated `value` to the stack of traversed objects 19147 stackA.push(source); 19148 stackB.push(value); 19149 19150 // recursively merge objects and arrays (susceptible to call stack limits) 19151 if (!isShallow) { 19152 baseMerge(value, source, callback, stackA, stackB); 19153 } 19154 } 19155 } 19156 else { 19157 if (callback) { 19158 result = callback(value, source); 19159 if (typeof result == 'undefined') { 19160 result = source; 19161 } 19162 } 19163 if (typeof result != 'undefined') { 19164 value = result; 19165 } 19166 } 19167 object[key] = value; 19168 }); 19169 } 19170 19171 /** 19172 * The base implementation of `_.random` without argument juggling or support 19173 * for returning floating-point numbers. 19174 * 19175 * @private 19176 * @param {number} min The minimum possible value. 19177 * @param {number} max The maximum possible value. 19178 * @returns {number} Returns a random number. 19179 */ 19180 function baseRandom(min, max) { 19181 return min + floor(nativeRandom() * (max - min + 1)); 19182 } 19183 19184 /** 19185 * The base implementation of `_.uniq` without support for callback shorthands 19186 * or `thisArg` binding. 19187 * 19188 * @private 19189 * @param {Array} array The array to process. 19190 * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted. 19191 * @param {Function} [callback] The function called per iteration. 19192 * @returns {Array} Returns a duplicate-value-free array. 19193 */ 19194 function baseUniq(array, isSorted, callback) { 19195 var index = -1, 19196 indexOf = getIndexOf(), 19197 length = array ? array.length : 0, 19198 result = []; 19199 19200 var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf, 19201 seen = (callback || isLarge) ? getArray() : result; 19202 19203 if (isLarge) { 19204 var cache = createCache(seen); 19205 indexOf = cacheIndexOf; 19206 seen = cache; 19207 } 19208 while (++index < length) { 19209 var value = array[index], 19210 computed = callback ? callback(value, index, array) : value; 19211 19212 if (isSorted 19213 ? !index || seen[seen.length - 1] !== computed 19214 : indexOf(seen, computed) < 0 19215 ) { 19216 if (callback || isLarge) { 19217 seen.push(computed); 19218 } 19219 result.push(value); 19220 } 19221 } 19222 if (isLarge) { 19223 releaseArray(seen.array); 19224 releaseObject(seen); 19225 } else if (callback) { 19226 releaseArray(seen); 19227 } 19228 return result; 19229 } 19230 19231 /** 19232 * Creates a function that aggregates a collection, creating an object c
19232omposed 19233 * of keys generated from the results of running each element of the collection 19234 * through a callback. The given `setter` function sets the keys and values 19235 * of the composed object. 19236 * 19237 * @private 19238 * @param {Function} setter The setter function. 19239 * @returns {Function} Returns the new aggregator function. 19240 */ 19241 function createAggregator(setter) { 19242 return function(collection, callback, thisArg) { 19243 var result = {}; 19244 callback = lodash.createCallback(callback, thisArg, 3); 19245 19246 var index = -1, 19247 length = collection ? collection.length : 0; 19248 19249 if (typeof length == 'number') { 19250 while (++index < length) { 19251 var value = collection[index]; 19252 setter(result, value, callback(value, index, collection), collection); 19253 } 19254 } else { 19255 forOwn(collection, function(value, key, collection) { 19256 setter(result, value, callback(value, key, collection), collection); 19257 }); 19258 } 19259 return result; 19260 }; 19261 } 19262 19263 /** 19264 * Creates a function that, when called, either curries or invokes `func` 19265 * with an optional `this` binding and partially applied arguments. 19266 * 19267 * @private 19268 * @param {Function|string} func The function or method name to reference. 19269 * @param {number} bitmask The bitmask of method flags to compose. 19270 * The bitmask may be composed of the following flags: 19271 * 1 - `_.bind` 19272 * 2 - `_.bindKey` 19273 * 4 - `_.curry` 19274 * 8 - `_.curry` (bound) 19275 * 16 - `_.partial` 19276 * 32 - `_.partialRight` 19277 * @param {Array} [partialArgs] An array of arguments to prepend to those 19278 * provided to the new function. 19279 * @param {Array} [partialRightArgs] An array of arguments to append to those 19280 * provided to the new function. 19281 * @param {*} [thisArg] The `this` binding of `func`. 19282 * @param {number} [arity] The arity of `func`. 19283 * @returns {Function} Returns the new function. 19284 */ 19285 function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { 19286 var isBind = bitmask & 1, 19287 isBindKey = bitmask & 2, 19288 isCurry = bitmask & 4, 19289 isCurryBound = bitmask & 8, 19290 isPartial = bitmask & 16, 19291 isPartialRight = bitmask & 32; 19292 19293 if (!isBindKey && !isFunction(func)) { 19294 throw new TypeError; 19295 } 19296 if (isPartial && !partialArgs.length) { 19297 bitmask &= ~16; 19298 isPartial = partialArgs = false; 19299 } 19300 if (isPartialRight && !partialRightArgs.length) { 19301 bitmask &= ~32; 19302 isPartialRight = partialRightArgs = false; 19303 } 19304 var bindData = func && func.__bindData__; 19305 if (bindData && bindData !== true) { 19306 // clone `bindData` 19307 bindData = slice(bindData); 19308 if (bindData[2]) { 19309 bindData[2] = slice(bindData[2]); 19310 } 19311 if (bindData[3]) { 19312 bindData[3] = slice(bindData[3]); 19313 } 19314 // set `thisBinding` is not previously bound 19315 if (isBind && !(bindData[1] & 1)) { 19316 bindData[4] = thisArg; 19317 } 19318 // set if previously bound but not currently (subsequent curried functions) 19319 if (!isBind && bindData[1] & 1) { 19320 bitmask |= 8; 19321 } 19322 // set curried arity if not yet set 19323 if (isCurry && !(bindData[1] & 4)) { 19324 bindData[5] = arity; 19325 } 19326 // append partial left arguments 19327 if (isPartial) { 19328 push.apply(bindData[2] || (bindData[2] = []), partialArgs); 19329 } 19330 // append partial right arguments 19331 if (isPartialRight) { 19332 unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs); 19333 } 19334 // merge flags 19335 bindData[1] |= bitmask; 19336 return createWrapper.apply(null, bindData); 19337 } 19338 // fast path for `_.bind` 19339 var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper; 19340 return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]); 19341 } 19342 19343 /** 19344 * Used by `escape` to convert characters to HTML entities. 19345 * 19346 * @private 19347 * @param {string} match The matched character to escape. 19348 * @returns {string} Returns the escaped character. 19349 */ 19350 function escapeHtmlChar(match) { 19351 return htmlEscapes[match]; 19352 } 19353 19354 /** 19355 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is 19356 * customized, this method returns the custom method, otherwise it returns 19357 * the `baseIndexOf` function. 19358 * 19359 * @private 19360 * @returns {Function} Returns the "indexOf" function. 19361 */ 19362 function getIndexOf() { 19363 var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result; 19364 return result; 19365 } 19366 19367 /** 19368 * Checks if `value` is a native function. 19369 * 19370 * @private 19371 * @param {*} value The value to check. 19372 * @returns {boolean} Returns `true` if the `value` is a native function, else `false`. 19373 */ 19374 function isNative(value) { 19375 return typeof value == 'function' && reNative.test(value); 19376 } 19377 19378 /** 19379 * Sets `this` binding data on a given function. 19380 * 19381 * @private 19382 * @param {Function} func The function to set data on. 19383 * @param {Array} value The data array to set. 19384 */ 19385 var setBindData = !defineProperty ? noop : function(func, value) { 19386 descriptor.value = value; 19387 defineProperty(func, '__bindData__', descriptor); 19388 }; 19389 19390 /** 19391 * A fallback implementation of `isPlainObject` which checks if a given value 19392 * is an object created by the `Object` constructor, assuming objects created 19393 * by the `Object` constructor have no inherited enumerable properties and that 19394 * there are no `Object.prototype` extensions. 19395 * 19396 * @private 19397 * @param {*} value The value to check. 19398 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. 19399 */ 19400 function shimIsPlainObject(value) { 19401 var ctor, 19402 result; 19403 19404 // avoid non Object objects, `arguments` objects, and DOM elements 19405 if (!(value && toString.call(value) == objectClass) || 19406 (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) { 19407 return false;
19408 } 19409 // In most environments an object's own properties are iterated before 19410 // its inherited properties. If the last iterated property is an object's 19411 // own property then there are no inherited enumerable properties. 19412 forIn(value, function(value, key) { 19413 result = key; 19414 }); 19415 return typeof result == 'undefined' || hasOwnProperty.call(value, result); 19416 } 19417 19418 /** 19419 * Used by `unescape` to convert HTML entities to characters. 19420 * 19421 * @private 19422 * @param {string} match The matched character to unescape. 19423 * @returns {string} Returns the unescaped character. 19424 */ 19425 function unescapeHtmlChar(match) { 19426 return htmlUnescapes[match]; 19427 } 19428 19429 /*--------------------------------------------------------------------------*/ 19430 19431 /** 19432 * Checks if `value` is an `arguments` object. 19433 * 19434 * @static 19435 * @memberOf _ 19436 * @category Objects 19437 * @param {*} value The value to check. 19438 * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`. 19439 * @example 19440 * 19441 * (function() { return _.isArguments(arguments); })(1, 2, 3); 19442 * // => true 19443 * 19444 * _.isArguments([1, 2, 3]); 19445 * // => false 19446 */ 19447 function isArguments(value) { 19448 return value && typeof value == 'object' && typeof value.length == 'number' && 19449 toString.call(value) == argsClass || false; 19450 } 19451 19452 /** 19453 * Checks if `value` is an array. 19454 * 19455 * @static 19456 * @memberOf _ 19457 * @type Function 19458 * @category Objects 19459 * @param {*} value The value to check. 19460 * @returns {boolean} Returns `true` if the `value` is an array, else `false`. 19461 * @example 19462 * 19463 * (function() { return _.isArray(arguments); })(); 19464 * // => false 19465 * 19466 * _.isArray([1, 2, 3]); 19467 * // => true 19468 */ 19469 var isArray = nativeIsArray || function(value) { 19470 return value && typeof value == 'object' && typeof value.length == 'number' && 19471 toString.call(value) == arrayClass || false; 19472 }; 19473 19474 /** 19475 * A fallback implementation of `Object.keys` which produces an array of the 19476 * given object's own enumerable property names. 19477 * 19478 * @private 19479 * @type Function 19480 * @param {Object} object The object to inspect. 19481 * @returns {Array} Returns an array of property names. 19482 */ 19483 var shimKeys = function(object) { 19484 var index, iterable = object, result = []; 19485 if (!iterable) return result; 19486 if (!(objectTypes[typeof object])) return result; 19487 for (index in iterable) { 19488 if (hasOwnProperty.call(iterable, index)) { 19489 result.push(index); 19490 } 19491 } 19492 return result 19493 }; 19494 19495 /** 19496 * Creates an array composed of the own enumerable property names of an object. 19497 * 19498 * @static 19499 * @memberOf _ 19500 * @category Objects 19501 * @param {Object} object The object to inspect. 19502 * @returns {Array} Returns an array of property names. 19503 * @example 19504 * 19505 * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); 19506 * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) 19507 */ 19508 var keys = !nativeKeys ? shimKeys : function(object) { 19509 if (!isObject(object)) { 19510 return []; 19511 } 19512 return nativeKeys(object); 19513 }; 19514 19515 /** 19516 * Used to convert characters to HTML entities: 19517 * 19518 * Though the `>` character is escaped for symmetry, characters like `>` and `/` 19519 * don't require escaping in HTML and have no special meaning unless they're part 19520 * of a tag or an unquoted attribute value. 19521 * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact") 19522 */ 19523 var htmlEscapes = { 19524 '&': '&', 19525 '<': '<', 19526 '>': '>', 19527 '"': '"', 19528 "'": ''' 19529 }; 19530 19531 /** Used to convert HTML entities to characters */ 19532 var htmlUnescapes = invert(htmlEscapes); 19533 19534 /** Used to match HTML entities and HTML characters */ 19535 var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'), 19536 reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g'); 19537 19538 /*--------------------------------------------------------------------------*/ 19539 19540 /** 19541 * Assigns own enumerable properties of source object(s) to the destination
19542 * object. Subsequent sources will overwrite property assignments of previous 19543 * sources. If a callback is provided it will be executed to produce the 19544 * assigned values. The callback is bound to `thisArg` and invoked with two 19545 * arguments; (objectValue, sourceValue). 19546 * 19547 * @static 19548 * @memberOf _ 19549 * @type Function 19550 * @alias extend 19551 * @category Objects 19552 * @param {Object} object The destination object. 19553 * @param {...Object} [source] The source objects. 19554 * @param {Function} [callback] The function to customize assigning values. 19555 * @param {*} [thisArg] The `this` binding of `callback`. 19556 * @returns {Object} Returns the destination object. 19557 * @example 19558 * 19559 * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); 19560 * // => { 'name': 'fred', 'employer': 'slate' } 19561 * 19562 * var defaults = _.partialRight(_.assign, function(a, b) { 19563 * return typeof a == 'undefined' ? b : a; 19564 * }); 19565 * 19566 * var object = { 'name': 'barney' }; 19567 * defaults(object, { 'name': 'fred', 'employer': 'slate' }); 19568 * // => { 'name': 'barney', 'employer': 'slate' } 19569 */ 19570 var assign = function(object, source, guard) { 19571 var index, iterable = object, result = iterable; 19572 if (!iterable) return result; 19573 var args = arguments, 19574 argsIndex = 0, 19575 argsLength = typeof guard == 'number' ? 2 : args.length; 19576 if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { 19577 var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); 19578 } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { 19579 callback = args[--argsLength]; 19580 } 19581 while (++argsIndex < argsLength) { 19582 iterable = args[argsIndex]; 19583 if (iterable && objectTypes[typeof iterable]) { 19584 var ownIndex = -1, 19585 ownProps = objectTypes[typeof iterable] && keys(iterable), 19586 length = ownProps ? ownProps.length : 0; 19587 19588 while (++ownIndex < length) { 19589 index = ownProps[ownIndex]; 19590 result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; 19591 } 19592 } 19593 } 19594 return result 19595 }; 19596 19597 /** 19598 * Creates a clone of `value`. If `isDeep` is `true` nested objects will also 19599 * be cloned, otherwise they will be assigned by reference. If a callback 19600 * is provided it will be executed to produce the cloned values. If the 19601 * callback returns `undefined` cloning will be handled by the method instead. 19602 * The callback is bound to `thisArg` and invoked with one argument; (value). 19603 * 19604 * @static 19605 * @memberOf _ 19606 * @category Objects 19607 * @param {*} value The value to clone. 19608 * @param {boolean} [isDeep=false] Specify a deep clone. 19609 * @param {Function} [callback] The function to customize cloning values. 19610 * @param {*} [thisArg] The `this` binding of `callback`. 19611 * @returns {*} Returns the cloned value. 19612 * @example 19613 * 19614 * var characters = [ 19615 * { 'name': 'barney', 'age': 36 }, 19616 * { 'name': 'fred', 'age': 40 } 19617 * ]; 19618 * 19619 * var shallow = _.clone(characters); 19620 * shallow[0] === characters[0]; 19621 * // => true 19622 * 19623 * var deep = _.clone(characters, true); 19624 * deep[0] === characters[0]; 19625 * // => false 19626 * 19627 * _.mixin({ 19628 * 'clone': _.partialRight(_.clone, function(value) { 19629 * return _.isElement(value) ? value.cloneNode(false) : undefined; 19630 * }) 19631 * }); 19632 * 19633 * var clone = _.clone(document.body); 19634 * clone.childNodes.length; 19635 * // => 0 19636 */ 19637 function clone(value, isDeep, callback, thisArg) { 19638 // allows working with "Collections" methods without using their `index` 19639 // and `collection` arguments for `isDeep` and `callback` 19640 if (typeof isDeep != 'boolean' && isDeep != null) { 19641 thisArg = callback; 19642 callback = isDeep; 19643 isDeep = false; 19644 } 19645 return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); 19646 } 19647 19648 /** 19649 * Creates a deep clone of `value`. If a callback is provided it will be 19650 * executed to produce the cloned values. If the callback returns `undefined` 19651 * cloning will be handled by the method instead. The callback is bound to 19652 * `thisArg` and invoked with one argument; (value). 19653 * 19654 * Note: This method is loosely based on the structured clone algorithm. Functions 19655 * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and 19656 * objects created by constructors other than `Object` are cloned to plain `Object` objects.
19657 * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm. 19658 * 19659 * @static 19660 * @memberOf _ 19661 * @category Objects 19662 * @param {*} value The value to deep clone. 19663 * @param {Function} [callback] The function to customize cloning values. 19664 * @param {*} [thisArg] The `this` binding of `callback`. 19665 * @returns {*} Returns the deep cloned value. 19666 * @example 19667 * 19668 * var characters = [ 19669 * { 'name': 'barney', 'age': 36 }, 19670 * { 'name': 'fred', 'age': 40 } 19671 * ]; 19672 * 19673 * var deep = _.cloneDeep(characters); 19674 * deep[0] === characters[0]; 19675 * // => false 19676 * 19677 * var view = { 19678 * 'label': 'docs', 19679 * 'node': element 19680 * }; 19681 * 19682 * var clone = _.cloneDeep(view, function(value) { 19683 * return _.isElement(value) ? value.cloneNode(true) : undefined; 19684 * }); 19685 * 19686 * clone.node == view.node; 19687 * // => false 19688 */ 19689 function cloneDeep(value, callback, thisArg) { 19690 return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); 19691 } 19692 19693 /** 19694 * Creates an object that inherits from the given `prototype` object. If a 19695 * `properties` object is provided its own enumerable properties are assigned 19696 * to the created object. 19697 * 19698 * @static 19699 * @memberOf _ 19700 * @category Objects 19701 * @param {Object} prototype The object to inherit from. 19702 * @param {Object} [properties] The properties to assign to the object. 19703 * @returns {Object} Returns the new object. 19704 * @example 19705 * 19706 * function Shape() { 19707 * this.x = 0; 19708 * this.y = 0; 19709 * } 19710 * 19711 * function Circle() { 19712 * Shape.call(this); 19713 * } 19714 * 19715 * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle }); 19716 * 19717 * var circle = new Circle; 19718 * circle instanceof Circle; 19719 * // => true 19720 * 19721 * circle instanceof Shape; 19722 * // => true 19723 */ 19724 function create(prototype, properties) { 19725 var result = baseCreate(prototype); 19726 return properties ? assign(result, properties) : result; 19727 } 19728 19729 /** 19730 * Assigns own enumerable properties of source object(s) to the destination 19731 * object for all destination properties that resolve to `undefined`. Once a 19732 * property is set, additional defaults of the same property will be ignored. 19733 * 19734 * @static 19735 * @memberOf _ 19736 * @type Function 19737 * @category Objects 19738 * @param {Object} object The destination object. 19739 * @param {...Object} [source] The source objects. 19740 * @param- {Object} [guard] Allows working with `_.reduce` without using its 19741 * `key` and `object` arguments as sources. 19742 * @returns {Object} Returns the destination object. 19743 * @example 19744 * 19745 * var object = { 'name': 'barney' }; 19746 * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); 19747 * // => { 'name': 'barney', 'employer': 'slate' } 19748 */ 19749 var defaults = function(object, source, guard) { 19750 var index, iterable = object, result = iterable; 19751 if (!iterable) return result; 19752 var args = arguments, 19753 argsIndex = 0, 19754 argsLength = typeof guard == 'number' ? 2 : args.length; 19755 while (++argsIndex < argsLength) { 19756 iterable = args[argsIndex]; 19757 if (iterable && objectTypes[typeof iterable]) { 19758 var ownIndex = -1, 19759 ownProps = objectTypes[typeof iterable] && keys(iterable), 19760 length = ownProps ? ownProps.length : 0; 19761 19762 while (++ownIndex < length) { 19763 index = ownProps[ownIndex]; 19764 if (typeof result[index] == 'undefined') result[index] = iterable[index]; 19765 } 19766 } 19767 } 19768 return result 19769 }; 19770 19771 /** 19772 * This method is like `_.findIndex` except that it returns the key of the 19773 * first element that passes the callback check, instead of the element itself. 19774 * 19775 * If a property name is provided for `callback` the created "_.pluck" style 19776 * callback will return the property value of the given element. 19777 * 19778 * If an object is provided for `callback` the created "_.where" style callback 19779 * will return `true` for elements that have the properties of the given object, 19780 * else `false`. 19781 * 19782 * @static 19783 * @memberOf _ 19784 * @category Objects 19785 * @param {Object} object The object to search. 19786 * @param {Function|Object|string} [callback=identity] The function called per 19787 * iteration. If a property name or object is provided it will be used to 19788 * create a "_.pluck" or "_.where" style callback, respectively. 19789 * @param {*} [thisArg] The `this` binding of `callback`. 19790 * @returns {string|undefined} Returns the key of the found element, else `undefined`. 19791 * @example 19792 * 19793 * var characters = { 19794 * 'barney': { 'age': 36, 'blocked': false }, 19795 * 'fred': { 'age': 40, 'blocked': true }, 19796 * 'pebbles': { 'age': 1, 'blocked': false } 19797 * }; 19798 * 19799 * _.findKey(characters, function(chr) { 19800 * return chr.age < 40; 19801 * }); 19802 * // => 'barney' (property order is not guaranteed across environments) 19803 * 19804 * // using "_.where" callback shorthand 19805 * _.findKey(characters, { 'age': 1 }); 19806 * // => 'pebbles' 19807 * 19808 * // using "_.pluck" callback shorthand 19809 * _.findKey(characters, 'blocked'); 19810 * // => 'fred' 19811 */ 19812 function findKey(object, callback, thisArg) { 19813 var result; 19814 callback = lodash.createCallback(callback, thisArg, 3); 19815 forOwn(object, function(value, key, object) { 19816 if (callback(value, key, object)) { 19817 result = key; 19818 return false;
19819 } 19820 }); 19821 return result; 19822 } 19823 19824 /** 19825 * This method is like `_.findKey` except that it iterates over elements 19826 * of a `collection` in the opposite order. 19827 * 19828 * If a property name is provided for `callback` the created "_.pluck" style 19829 * callback will return the property value of the given element. 19830 * 19831 * If an object is provided for `callback` the created "_.where" style callback 19832 * will return `true` for elements that have the properties of the given object, 19833 * else `false`. 19834 * 19835 * @static 19836 * @memberOf _ 19837 * @category Objects 19838 * @param {Object} object The object to search. 19839 * @param {Function|Object|string} [callback=identity] The function called per 19840 * iteration. If a property name or object is provided it will be used to 19841 * create a "_.pluck" or "_.where" style callback, respectively. 19842 * @param {*} [thisArg] The `this` binding of `callback`. 19843 * @returns {string|undefined} Returns the key of the found element, else `undefined`. 19844 * @example 19845 * 19846 * var characters = { 19847 * 'barney': { 'age': 36, 'blocked': true }, 19848 * 'fred': { 'age': 40, 'blocked': false }, 19849 * 'pebbles': { 'age': 1, 'blocked': true } 19850 * }; 19851 * 19852 * _.findLastKey(characters, function(chr) { 19853 * return chr.age < 40; 19854 * }); 19855 * // => returns `pebbles`, assuming `_.findKey` returns `barney` 19856 * 19857 * // using "_.where" callback shorthand 19858 * _.findLastKey(characters, { 'age': 40 }); 19859 * // => 'fred' 19860 * 19861 * // using "_.pluck" callback shorthand 19862 * _.findLastKey(characters, 'blocked'); 19863 * // => 'pebbles' 19864 */ 19865 function findLastKey(object, callback, thisArg) { 19866 var result; 19867 callback = lodash.createCallback(callback, thisArg, 3); 19868 forOwnRight(object, function(value, key, object) { 19869 if (callback(value, key, object)) { 19870 result = key; 19871 return false; 19872 } 19873 }); 19874 return result; 19875 } 19876 19877 /** 19878 * Iterates over own and inherited enumerable properties of an object, 19879 * executing the callback for each property. The callback is bound to `thisArg` 19880 * and invoked with three arguments; (value, key, object). Callbacks may exit 19881 * iteration early by explicitly returning `false`. 19882 * 19883 * @static 19884 * @memberOf _ 19885 * @type Function 19886 * @category Objects 19887 * @param {Object} object The object to iterate over. 19888 * @param {Function} [callback=identity] The function called per iteration. 19889 * @param {*} [thisArg] The `this` binding of `callback`. 19890 * @returns {Object} Returns `object`. 19891 * @example 19892 * 19893 * function Shape() { 19894 * this.x = 0; 19895 * this.y = 0; 19896 * } 19897 * 19898 * Shape.prototype.move = function(x, y) { 19899 * this.x += x; 19900 * this.y += y; 19901 * }; 19902 * 19903 * _.forIn(new Shape, function(value, key) { 19904 * console.log(key); 19905 * }); 19906 * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments) 19907 */ 19908 var forIn = function(collection, callback, thisArg) { 19909 var index, iterable = collection, result = iterable; 19910 if (!iterable) return result; 19911 if (!objectTypes[typeof iterable]) return result; 19912 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); 19913 for (index in iterable) { 19914 if (callback(iterable[index], index, collection) === false) return result; 19915 } 19916 return result 19917 }; 19918 19919 /** 19920 * This method is like `_.forIn` except that it iterates over elements 19921 * of a `collection` in the opposite order. 19922 * 19923 * @static 19924 * @memberOf _ 19925 * @category Objects 19926 * @param {Object} object The object to iterate over. 19927 * @param {Function} [callback=identity] The function called per iteration. 19928 * @param {*} [thisArg] The `this` binding of `callback`. 19929 * @returns {Object} Returns `object`. 19930 * @example 19931 * 19932 * function Shape() { 19933 * this.x = 0; 19934 * this.y = 0; 19935 * } 19936 * 19937 * Shape.prototype.move = function(x, y) { 19938 * this.x += x; 19939 * this.y += y; 19940 * }; 19941 * 19942 * _.forInRight(new Shape, function(value, key) { 19943 * console.log(key); 19944 * }); 19945 * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move' 19946 */ 19947 function forInRight(object, callback, thisArg) { 19948 var pairs = []; 19949 19950 forIn(object, function(value, key) { 19951 pairs.push(key, value); 19952 }); 19953 19954 var length = pairs.length; 19955 callback = baseCreateCallback(callback, thisArg, 3); 19956 while (length--) { 19957 if (callback(pairs[length--], pairs[length], object) === false) { 19958 break; 19959 } 19960 } 19961 return object; 19962 } 19963 19964 /** 19965 * Iterates over own enumerable properties of an object, executing the callback 19966 * for each property. The callback is bound to `thisArg` and invoked with three 19967 * arguments; (value, key, object). Callbacks may exit iteration early by 19968 * explicitly returning `false`. 19969 * 19970 * @static 19971 * @memberOf _ 19972 * @type Function 19973 * @category Objects 19974 * @param {Object} object The object to iterate over. 19975 * @param {Function} [callback=identity] The function called per iteration. 19976 * @param {*} [thisArg] The `this` binding of `callback`. 19977 * @returns {Object} Returns `object`. 19978 * @example 19979 * 19980 * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { 19981 * console.log(key); 19982 * }); 19983 * // => logs '0', '1', and 'length' (property order is not guaranteed across environments) 19984 */ 19985 var forOwn = function(collection, callback, thisArg) { 19986 var index, iterable = collection, result = iterable; 19987 if (!iterable) return result; 19988 if (!objectTypes[typeof iterable]) return result; 19989 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); 19990 var ownIndex = -1, 19991 ownProps = objectTypes[typeof iterable] && keys(iterable), 19992 length = ownProps ? ownProps.length : 0; 19993 19994 while (++ownIndex < length) { 19995 index = ownProps[ownIndex]; 19996 if (callback(iterable[index], index, collection) === false) return result; 19997 } 19998 return result 19999 }; 20000 20001 /** 20002 * This method is like `_.forOwn` except that it iterates over elements 20003 * of a `collection` in the opposite order. 20004 * 20005 * @static 20006 * @memberOf _ 20007 * @category Objects 20008 * @param {Object} object The object to iterate over. 20009 * @param {Function} [callback=identity] The function called per iteration. 20010 * @param {*} [thisArg] The `this` binding of `callback`. 20011 * @returns {Object} Returns `object`. 20012 * @example 20013 * 20014 * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { 20015 * console.log(key); 20016 * }); 20017 * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length' 20018 */ 20019 function forOwnRight(object, callback, thisArg) { 20020 var props = keys(object), 20021 length = props.length; 20022 20023 callback = baseCreateCallback(callback, thisArg, 3); 20024 while (length--) { 20025 var key = props[length]; 20026 if (callback(object[key], key, object) === false) { 20027 break; 20028 } 20029 } 20030 return object; 20031 } 20032 20033 /** 20034 * Creates a sorted array of property names of all enumerable properties, 20035 * own and inherited, of `object` that have function values. 20036 * 20037 * @static 20038 * @memberOf _ 20039 * @alias methods 20040 * @category Objects 20041 * @param {Object} object The object to inspect. 20042 * @returns {Array} Returns an array of property names that have function values. 20043 * @example 20044 * 20045 * _.functions(_); 20046 * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] 20047 */ 20048 function functions(object) { 20049 var result = []; 20050 forIn(object, function(value, key) { 20051 if (isFunction(value)) { 20052 result.push(key); 20053 } 20054 }); 20055 return result.sort(); 20056 } 20057 20058 /** 20059 * Checks if the specified property name exists as a direct property of `object`, 20060 * instead of an inherited property. 20061 * 20062 * @static 20063 * @memberOf _ 20064 * @category Objects 20065 * @param {Object} object The object to inspect. 20066 * @param {string} key The name of the property to check. 20067 * @returns {boolean} Returns `true` if key is a direct property, else `false`. 20068 * @example 20069 * 20070 * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); 20071 * // => true 20072 */ 20073 function has(object, key) { 20074 return object ? hasOwnProperty.call(object, key) : false;
20075 } 20076 20077 /** 20078 * Creates an object composed of the inverted keys and values of the given object. 20079 * 20080 * @static 20081 * @memberOf _ 20082 * @category Objects 20083 * @param {Object} object The object to invert. 20084 * @returns {Object} Returns the created inverted object. 20085 * @example 20086 * 20087 * _.invert({ 'first': 'fred', 'second': 'barney' }); 20088 * // => { 'fred': 'first', 'barney': 'second' } 20089 */ 20090 function invert(object) { 20091 var index = -1, 20092 props = keys(object), 20093 length = props.length, 20094 result = {}; 20095 20096 while (++index < length) { 20097 var key = props[index]; 20098 result[object[key]] = key; 20099 } 20100 return result; 20101 } 20102 20103 /** 20104 * Checks if `value` is a boolean value. 20105 * 20106 * @static 20107 * @memberOf _ 20108 * @category Objects 20109 * @param {*} value The value to check. 20110 * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`. 20111 * @example 20112 * 20113 * _.isBoolean(null); 20114 * // => false 20115 */ 20116 function isBoolean(value) { 20117 return value === true || value === false || 20118 value && typeof value == 'object' && toString.call(value) == boolClass || false; 20119 } 20120 20121 /** 20122 * Checks if `value` is a date. 20123 * 20124 * @static 20125 * @memberOf _ 20126 * @category Objects 20127 * @param {*} value The value to check. 20128 * @returns {boolean} Returns `true` if the `value` is a date, else `false`. 20129 * @example 20130 * 20131 * _.isDate(new Date); 20132 * // => true 20133 */ 20134 function isDate(value) { 20135 return value && typeof value == 'object' && toString.call(value) == dateClass || false; 20136 } 20137 20138 /** 20139 * Checks if `value` is a DOM element. 20140 * 20141 * @static 20142 * @memberOf _ 20143 * @category Objects 20144 * @param {*} value The value to check. 20145 * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`. 20146 * @example 20147 * 20148 * _.isElement(document.body); 20149 * // => true 20150 */ 20151 function isElement(value) { 20152 return value && value.nodeType === 1 || false; 20153 } 20154 20155 /** 20156 * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a 20157 * length of `0` and objects with no own enumerable properties are considered 20158 * "empty". 20159 * 20160 * @static 20161 * @memberOf _ 20162 * @category Objects 20163 * @param {Array|Object|string} value The value to inspect. 20164 * @returns {boolean} Returns `true` if the `value` is empty, else `false`. 20165 * @example 20166 * 20167 * _.isEmpty([1, 2, 3]); 20168 * // => false 20169 * 20170 * _.isEmpty({}); 20171 * // => true 20172 * 20173 * _.isEmpty(''); 20174 * // => true 20175 */ 20176 function isEmpty(value) { 20177 var result = true; 20178 if (!value) { 20179 return result; 20180 } 20181 var className = toString.call(value), 20182 length = value.length; 20183 20184 if ((className == arrayClass || className == stringClass || className == argsClass ) || 20185 (className == objectClass && typeof length == 'number' && isFunction(value.splice))) { 20186 return !length; 20187 } 20188 forOwn(value, function() { 20189 return (result = false); 20190 }); 20191 return result; 20192 } 20193 20194 /** 20195 * Performs a deep comparison between two values to determine if they are 20196 * equivalent to each other. If a callback is provided it will be executed 20197 * to compare values. If the callback returns `undefined` comparisons will 20198 * be handled by the method instead. The callback is bound to `thisArg` and 20199 * invoked with two arguments; (a, b). 20200 * 20201 * @static 20202 * @memberOf _ 20203 * @category Objects 20204 * @param {*} a The value to compare. 20205 * @param {*} b The other value to compare. 20206 * @param {Function} [callback] The function to customize comparing values. 20207 * @param {*} [thisArg] The `this` binding of `callback`. 20208 * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 20209 * @example 20210 * 20211 * var object = { 'name': 'fred' }; 20212 * var copy = { 'name': 'fred' }; 20213 * 20214 * object == copy; 20215 * // => false 20216 * 20217 * _.isEqual(object, copy); 20218 * // => true 20219 * 20220 * var words = ['hello', 'goodbye']; 20221 * var otherWords = ['hi', 'goodbye']; 20222 * 20223 * _.isEqual(words, otherWords, function(a, b) { 20224 * var reGreet = /^(?:hello|hi)$/i, 20225 * aGreet = _.isString(a) && reGreet.test(a), 20226 * bGreet = _.isString(b) && reGreet.test(b); 20227 * 20228 * return (aGreet || bGreet) ? (aGreet == bGreet) : undefined; 20229 * }); 20230 * // => true 20231 */ 20232 function isEqual(a, b, callback, thisArg) { 20233 return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2)); 20234 } 20235 20236 /** 20237 * Checks if `value` is, or can be coerced to, a finite number. 20238 * 20239 * Note: This is not the same as native `isFinite` which will return true for 20240 * booleans and empty strings. See http://es5.github.io/#x15.1.2.5. 20241 * 20242 * @static 20243 * @memberOf _ 20244 * @category Objects 20245 * @param {*} value The value to check. 20246 * @returns {boolean} Returns `true` if the `value` is finite, else `false`. 20247 * @example 20248 * 20249 * _.isFinite(-101); 20250 * // => true 20251 * 20252 * _.isFinite('10'); 20253 * // => true 20254 * 20255 * _.isFinite(true); 20256 * // => false 20257 * 20258 * _.isFinite(''); 20259 * // => false 20260 * 20261 * _.isFinite(Infinity); 20262 * // => false 20263 */ 20264 function isFinite(value) { 20265 return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); 20266 } 20267 20268 /** 20269 * Checks if `value` is a function. 20270 * 20271 * @static 20272 * @memberOf _ 20273 * @category Objects 20274 * @param {*} value The value to check. 20275 * @returns {boolean} Returns `true` if the `value` is a function, else `false`. 20276 * @example 20277 * 20278 * _.isFunction(_); 20279 * // => true 20280 */ 20281 function isFunction(value) { 20282 return typeof value == 'function'; 20283 } 20284 20285 /** 20286 * Checks if `value` is the language type of Object. 20287 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 20288 * 20289 * @static 20290 * @memberOf _ 20291 * @category Objects 20292 * @param {*} value The value to check. 20293 * @returns {boolean} Returns `true` if the `value` is an object, else `false`. 20294 * @example 20295 * 20296 * _.isObject({}); 20297 * // => true 20298 * 20299 * _.isObject([1, 2, 3]); 20300 * // => true 20301 * 20302 * _.isObject(1); 20303 * // => false 20304 */ 20305 function isObject(value) { 20306 // check if the value is the ECMAScript language type of Object 20307 // http://es5.github.io/#x8 20308 // and avoid a V8 bug 20309 // http://code.google.com/p/v8/issues/detail?id=2291 20310 return !!(value && objectTypes[typeof value]); 20311 } 20312 20313 /** 20314 * Checks if `value` is `NaN`. 20315 * 20316 * Note: This is not the same as native `isNaN` which will return `true` for 20317 * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4. 20318 * 20319 * @static 20320 * @memberOf _ 20321 * @category Objects 20322 * @param {*} value The value to check. 20323 * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`. 20324 * @example 20325 * 20326 * _.isNaN(NaN); 20327 * // => true 20328 * 20329 * _.isNaN(new Number(NaN)); 20330 * // => true 20331 * 20332 * isNaN(undefined); 20333 * // => true 20334 * 20335 * _.isNaN(undefined); 20336 * // => false 20337 */ 20338 function isNaN(value) { 20339 // `NaN` as a primitive is the only value that is not equal to itself 20340 // (perform the [[Class]] check first to avoid errors with some host objects in IE) 20341 return isNumber(value) && value != +value; 20342 } 20343 20344 /** 20345 * Checks if `value` is `null`. 20346 * 20347 * @static 20348 * @memberOf _ 20349 * @category Objects 20350 * @param {*} value The value to check. 20351 * @returns {boolean} Returns `true` if the `value` is `null`, else `false`. 20352 * @example 20353 * 20354 * _.isNull(null); 20355 * // => true 20356 * 20357 * _.isNull(undefined); 20358 * // => false 20359 */ 20360 function isNull(value) { 20361 return value === null; 20362 } 20363 20364 /** 20365 * Checks if `value` is a number. 20366 * 20367 * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5. 20368 * 20369 * @static 20370 * @memberOf _ 20371 * @category Objects 20372 * @param {*} value The value to check. 20373 * @returns {boolean} Returns `true` if the `value` is a number, else `false`. 20374 * @example 20375 * 20376 * _.isNumber(8.4 * 5); 20377 * // => true 20378 */ 20379 function isNumber(value) { 20380 return typeof value == 'number' || 20381 value && typeof value == 'object' && toString.call(value) == numberClass || false; 20382 } 20383 20384 /** 20385 * Checks if `value` is an object created by the `Object` constructor. 20386 * 20387 * @static 20388 * @memberOf _ 20389 * @category Objects 20390 * @param {*} value The value to check. 20391 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. 20392 * @example 20393 * 20394 * function Shape() { 20395 * this.x = 0; 20396 * this.y = 0; 20397 * } 20398 * 20399 * _.isPlainObject(new Shape); 20400 * // => false 20401 * 20402 * _.isPlainObject([1, 2, 3]); 20403 * // => false 20404 * 20405 * _.isPlainObject({ 'x': 0, 'y': 0 }); 20406 * // => true 20407 */ 20408 var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { 20409 if (!(value && toString.call(value) == objectClass)) { 20410 return false;
20411 } 20412 var valueOf = value.valueOf, 20413 objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); 20414 20415 return objProto 20416 ? (value == objProto || getPrototypeOf(value) == objProto) 20417 : shimIsPlainObject(value); 20418 }; 20419 20420 /** 20421 * Checks if `value` is a regular expression. 20422 * 20423 * @static 20424 * @memberOf _ 20425 * @category Objects 20426 * @param {*} value The value to check. 20427 * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`. 20428 * @example 20429 * 20430 * _.isRegExp(/fred/); 20431 * // => true 20432 */ 20433 function isRegExp(value) { 20434 return value && typeof value == 'object' && toString.call(value) == regexpClass || false; 20435 } 20436 20437 /** 20438 * Checks if `value` is a string. 20439 * 20440 * @static 20441 * @memberOf _ 20442 * @category Objects 20443 * @param {*} value The value to check. 20444 * @returns {boolean} Returns `true` if the `value` is a string, else `false`. 20445 * @example 20446 * 20447 * _.isString('fred'); 20448 * // => true 20449 */ 20450 function isString(value) { 20451 return typeof value == 'string' || 20452 value && typeof value == 'object' && toString.call(value) == stringClass || false; 20453 } 20454 20455 /** 20456 * Checks if `value` is `undefined`. 20457 * 20458 * @static 20459 * @memberOf _ 20460 * @category Objects 20461 * @param {*} value The value to check. 20462 * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`. 20463 * @example 20464 * 20465 * _.isUndefined(void 0); 20466 * // => true 20467 */ 20468 function isUndefined(value) { 20469 return typeof value == 'undefined'; 20470 } 20471 20472 /** 20473 * Creates an object with the same keys as `object` and values generated by 20474 * running each own enumerable property of `object` through the callback. 20475 * The callback is bound to `thisArg` and invoked with three arguments; 20476 * (value, key, object). 20477 * 20478 * If a property name is provided for `callback` the created "_.pluck" style 20479 * callback will return the property value of the given element. 20480 * 20481 * If an object is provided for `callback` the created "_.where" style callback 20482 * will return `true` for elements that have the properties of the given object, 20483 * else `false`. 20484 * 20485 * @static 20486 * @memberOf _ 20487 * @category Objects 20488 * @param {Object} object The object to iterate over. 20489 * @param {Function|Object|string} [callback=identity] The function called 20490 * per iteration. If a property name or object is provided it will be used 20491 * to create a "_.pluck" or "_.where" style callback, respectively. 20492 * @param {*} [thisArg] The `this` binding of `callback`. 20493 * @returns {Array} Returns a new object with values of the results of each `callback` execution. 20494 * @example 20495 * 20496 * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; }); 20497 * // => { 'a': 3, 'b': 6, 'c': 9 } 20498 * 20499 * var characters = {
20500 * 'fred': { 'name': 'fred', 'age': 40 }, 20501 * 'pebbles': { 'name': 'pebbles', 'age': 1 } 20502 * }; 20503 * 20504 * // using "_.pluck" callback shorthand 20505 * _.mapValues(characters, 'age'); 20506 * // => { 'fred': 40, 'pebbles': 1 } 20507 */ 20508 function mapValues(object, callback, thisArg) { 20509 var result = {}; 20510 callback = lodash.createCallback(callback, thisArg, 3); 20511 20512 forOwn(object, function(value, key, object) { 20513 result[key] = callback(value, key, object); 20514 }); 20515 return result; 20516 } 20517 20518 /** 20519 * Recursively merges own enumerable properties of the source object(s), that 20520 * don't resolve to `undefined` into the destination object. Subsequent sources 20521 * will overwrite property assignments of previous sources. If a callback is 20522 * provided it will be executed to produce the merged values of the destination 20523 * and source properties. If the callback returns `undefined` merging will 20524 * be handled by the method instead. The callback is bound to `thisArg` and 20525 * invoked with two arguments; (objectValue, sourceValue). 20526 * 20527 * @static 20528 * @memberOf _ 20529 * @category Objects 20530 * @param {Object} object The destination object. 20531 * @param {...Object} [source] The source objects. 20532 * @param {Function} [callback] The function to customize merging properties. 20533 * @param {*} [thisArg] The `this` binding of `callback`. 20534 * @returns {Object} Returns the destination object. 20535 * @example 20536 * 20537 * var names = { 20538 * 'characters': [ 20539 * { 'name': 'barney' }, 20540 * { 'name': 'fred' } 20541 * ] 20542 * }; 20543 * 20544 * var ages = { 20545 * 'characters': [ 20546 * { 'age': 36 }, 20547 * { 'age': 40 } 20548 * ] 20549 * }; 20550 * 20551 * _.merge(names, ages); 20552 * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] } 20553 * 20554 * var food = { 20555 * 'fruits': ['apple'], 20556 * 'vegetables': ['beet'] 20557 * }; 20558 * 20559 * var otherFood = { 20560 * 'fruits': ['banana'], 20561 * 'vegetables': ['carrot'] 20562 * }; 20563 * 20564 * _.merge(food, otherFood, function(a, b) { 20565 * return _.isArray(a) ? a.concat(b) : undefined; 20566 * }); 20567 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] } 20568 */ 20569 function merge(object) { 20570 var args = arguments, 20571 length = 2; 20572 20573 if (!isObject(object)) { 20574 return object; 20575 } 20576 // allows working with `_.reduce` and `_.reduceRight` without using 20577 // their `index` and `collection` arguments 20578 if (typeof args[2] != 'number') { 20579 length = args.length; 20580 } 20581 if (length > 3 && typeof args[length - 2] == 'function') { 20582 var callback = baseCreateCallback(args[--length - 1], args[length--], 2); 20583 } else if (length > 2 && typeof args[length - 1] == 'function') { 20584 callback = args[--length]; 20585 } 20586 var sources = slice(arguments, 1, length), 20587 index = -1, 20588 stackA = getArray(), 20589 stackB = getArray(); 20590 20591 while (++index < length) { 20592 baseMerge(object, sources[index], callback, stackA, stackB); 20593 } 20594 releaseArray(stackA); 20595 releaseArray(stackB); 20596 return object; 20597 } 20598 20599 /** 20600 * Creates a shallow clone of `object` excluding the specified properties. 20601 * Property names may be specified as individual arguments or as arrays of 20602 * property names. If a callback is provided it will be executed for each 20603 * property of `object` omitting the properties the callback returns truey 20604 * for. The callback is bound to `thisArg` and invoked with three arguments; 20605 * (value, key, object). 20606 * 20607 * @static 20608 * @memberOf _ 20609 * @category Objects 20610 * @param {Object} object The source object. 20611 * @param {Function|...string|string[]} [callback] The properties to omit or the 20612 * function called per iteration. 20613 * @param {*} [thisArg] The `this` binding of `callback`. 20614 * @returns {Object} Returns an object without the omitted properties. 20615 * @example 20616 * 20617 * _.omit({ 'name': 'fred', 'age': 40 }, 'age'); 20618 * // => { 'name': 'fred' } 20619 * 20620 * _.omit({ 'name': 'fred', 'age': 40 }, function(value) { 20621 * return typeof value == 'number'; 20622 * }); 20623 * // => { 'name': 'fred' } 20624 */ 20625 function omit(object, callback, thisArg) { 20626 var result = {}; 20627 if (typeof callback != 'function') { 20628 var props = []; 20629 forIn(object, function(value, key) { 20630 props.push(key); 20631 }); 20632 props = baseDifference(props, baseFlatten(arguments, true, false, 1)); 20633 20634 var index = -1, 20635 length = props.length; 20636 20637 while (++index < length) { 20638 var key = props[index]; 20639 result[key] = object[key]; 20640 } 20641 } else { 20642 callback = lodash.createCallback(callback, thisArg, 3); 20643 forIn(object, function(value, key, object) { 20644 if (!callback(value, key, object)) { 20645 result[key] = value; 20646 } 20647 }); 20648 } 20649 return result; 20650 } 20651 20652 /** 20653 * Creates a two dimensional array of an object's key-value pairs, 20654 * i.e. `[[key1, value1], [key2, value2]]`. 20655 * 20656 * @static 20657 * @memberOf _ 20658 * @category Objects 20659 * @param {Object} object The object to inspect. 20660 * @returns {Array} Returns new array of key-value pairs. 20661 * @example 20662 * 20663 * _.pairs({ 'barney': 36, 'fred': 40 }); 20664 * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments) 20665 */ 20666 function pairs(object) { 20667 var index = -1, 20668 props = keys(object), 20669 length = props.length, 20670 result = Array(length); 20671 20672 while (++index < length) { 20673 var key = props[index]; 20674 result[index] = [key, object[key]]; 20675 } 20676 return result; 20677 } 20678 20679 /** 20680 * Creates a shallow clone of `object` composed of the specified properties. 20681 * Property names may be specified as individual arguments or as arrays of 20682 * property names. If a callback is provided it will be executed for each 20683 * property of `object` picking the properties the callback returns truey 20684 * for. The callback is bound to `thisArg` and invoked with three arguments; 20685 * (value, key, object). 20686 * 20687 * @static 20688 * @memberOf _ 20689 * @category Objects 20690 * @param {Object} object The source object. 20691 * @param {Function|...string|string[]} [callback] The function called per 20692 * iteration or property names to pick, specified as individual property 20693 * names or arrays of property names. 20694 * @param {*} [thisArg] The `this` binding of `callback`. 20695 * @returns {Object}
20695 Returns an object composed of the picked properties. 20696 * @example 20697 * 20698 * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name'); 20699 * // => { 'name': 'fred' } 20700 * 20701 * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) { 20702 * return key.charAt(0) != '_'; 20703 * }); 20704 * // => { 'name': 'fred' } 20705 */ 20706 function pick(object, callback, thisArg) { 20707 var result = {}; 20708 if (typeof callback != 'function') { 20709 var index = -1, 20710 props = baseFlatten(arguments, true, false, 1), 20711 length = isObject(object) ? props.length : 0; 20712 20713 while (++index < length) { 20714 var key = props[index]; 20715 if (key in object) { 20716 result[key] = object[key]; 20717 } 20718 } 20719 } else { 20720 callback = lodash.createCallback(callback, thisArg, 3); 20721 forIn(object, function(value, key, object) { 20722 if (callback(value, key, object)) { 20723 result[key] = value; 20724 } 20725 }); 20726 } 20727 return result; 20728 } 20729 20730 /** 20731 * An alternative to `_.reduce` this method transforms `object` to a new 20732 * `accumulator` object which is the result of running each of its own 20733 * enumerable properties through a callback, with each callback execution 20734 * potentially mutating the `accumulator` object. The callback is bound to 20735 * `thisArg` and invoked with four arguments; (accumulator, value, key, object). 20736 * Callbacks may exit iteration early by explicitly returning `false`. 20737 * 20738 * @static 20739 * @memberOf _ 20740 * @category Objects 20741 * @param {Array|Object} object The object to iterate over. 20742 * @param {Function} [callback=identity] The function called per iteration. 20743 * @param {*} [accumulator] The custom accumulator value. 20744 * @param {*} [thisArg] The `this` binding of `callback`. 20745 * @returns {*} Returns the accumulated value. 20746 * @example 20747 * 20748 * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) { 20749 * num *= num; 20750 * if (num % 2) { 20751 * return result.push(num) < 3; 20752 * } 20753 * }); 20754 * // => [1, 9, 25] 20755 * 20756 * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { 20757 * result[key] = num * 3; 20758 * }); 20759 * // => { 'a': 3, 'b': 6, 'c': 9 } 20760 */ 20761 function transform(object, callback, accumulator, thisArg) { 20762 var isArr = isArray(object); 20763 if (accumulator == null) { 20764 if (isArr) { 20765 accumulator = []; 20766 } else { 20767 var ctor = object && object.constructor, 20768 proto = ctor && ctor.prototype; 20769 20770 accumulator = baseCreate(proto); 20771 } 20772 } 20773 if (callback) { 20774 callback = lodash.createCallback(callback, thisArg, 4); 20775 (isArr ? forEach : forOwn)(object, function(value, index, object) { 20776 return callback(accumulator, value, index, object); 20777 }); 20778 } 20779 return accumulator; 20780 } 20781 20782 /** 20783 * Creates an array composed of the own enumerable property values of `object`. 20784 * 20785 * @static 20786 * @memberOf _ 20787 * @category Objects 20788 * @param {Object} object The object to inspect. 20789 * @returns {Array} Returns an array of property values. 20790 * @example 20791 * 20792 * _.values({ 'one': 1, 'two': 2, 'three': 3 }); 20793 * // => [1, 2, 3] (property order is not guaranteed across environments) 20794 */ 20795 function values(object) { 20796 var index = -1, 20797 props = keys(object), 20798 length = props.length, 20799 result = Array(length); 20800 20801 while (++index < length) { 20802 result[index] = object[props[index]]; 20803 } 20804 return result; 20805 } 20806 20807 /*--------------------------------------------------------------------------*/ 20808 20809 /** 20810 * Creates an array of elements from the specified indexes, or keys, of the 20811 * `collection`. Indexes may be specified as individual arguments or as arrays 20812 * of indexes. 20813 * 20814 * @static 20815 * @memberOf _ 20816 * @category Collections 20817 * @param {Array|Object|string} collection The collection to iterate over. 20818 * @param {...(number|number[]|string|string[])} [index] The indexes of `collection` 20819 * to retrieve, specified as individual indexes or arrays of indexes. 20820 * @returns {Array} Returns a new array of elements corresponding to the 20821 * provided indexes. 20822 * @example 20823 * 20824 * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); 20825 * // => ['a', 'c', 'e'] 20826 * 20827 * _.at(['fred', 'barney', 'pebbles'], 0, 2); 20828 * // => ['fred', 'pebbles'] 20829 */ 20830 function at(collection) { 20831 var args = arguments, 20832 index = -1, 20833 props = baseFlatten(args, true, false, 1), 20834 length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length, 20835 result = Array(length); 20836 20837 while(++index < length) { 20838 result[index] = collection[props[index]]; 20839 } 20840 return result; 20841 } 20842 20843 /** 20844 * Checks if a given value is present in a collection using strict equality 20845 * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the 20846 * offset from the end of the collection. 20847 * 20848 * @static 20849 * @memberOf _ 20850 * @alias include 20851 * @category Collections 20852 * @param {Array|Object|string} collection The collection to iterate over. 20853 * @param {*} target The value to check for. 20854 * @param {number} [fromIndex=0] The index to search from. 20855 * @returns {boolean} Returns `true` if the `target` element is found, else `false`. 20856 * @example 20857 * 20858 * _.contains([1, 2, 3], 1); 20859 * // => true 20860 * 20861 * _.contains([1, 2, 3], 1, 2); 20862 * // => false 20863 * 20864 * _.contains({ 'name': 'fred', 'age': 40 }, 'fred'); 20865 * // => true 20866 * 20867 * _.contains('pebbles', 'eb'); 20868 * // => true 20869 */ 20870 function contains(collection, target, fromIndex) { 20871 var index = -1, 20872 indexOf = getIndexOf(),
20873 length = collection ? collection.length : 0, 20874 result = false; 20875 20876 fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; 20877 if (isArray(collection)) { 20878 result = indexOf(collection, target, fromIndex) > -1; 20879 } else if (typeof length == 'number') { 20880 result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1; 20881 } else { 20882 forOwn(collection, function(value) { 20883 if (++index >= fromIndex) { 20884 return !(result = value === target); 20885 } 20886 }); 20887 } 20888 return result; 20889 } 20890 20891 /** 20892 * Creates an object composed of keys generated from the results of running 20893 * each element of `collection` through the callback. The corresponding value 20894 * of each key is the number of times the key was returned by the callback. 20895 * The callback is bound to `thisArg` and invoked with three arguments; 20896 * (value, index|key, collection). 20897 * 20898 * If a property name is provided for `callback` the created "_.pluck" style 20899 * callback will return the property value of the given element. 20900 * 20901 * If an object is provided for `callback` the created "_.where" style callback 20902 * will return `true` for elements that have the properties of the given object, 20903 * else `false`. 20904 * 20905 * @static 20906 * @memberOf _ 20907 * @category Collections 20908 * @param {Array|Object|string} collection The collection to iterate over. 20909 * @param {Function|Object|string} [callback=identity] The function called 20910 * per iteration. If a property name or object is provided it will be used 20911 * to create a "_.pluck" or "_.where" style callback, respectively. 20912 * @param {*} [thisArg] The `this` binding of `callback`. 20913 * @returns {Object} Returns the composed aggregate object. 20914 * @example 20915 * 20916 * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); 20917 * // => { '4': 1, '6': 2 } 20918 * 20919 * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); 20920 * // => { '4': 1, '6': 2 } 20921 * 20922 * _.countBy(['one', 'two', 'three'], 'length'); 20923 * // => { '3': 2, '5': 1 } 20924 */ 20925 var countBy = createAggregator(function(result, value, key) { 20926 (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); 20927 }); 20928 20929 /** 20930 * Checks if the given callback returns truey value for **all** elements of 20931 * a collection. The callback is bound to `thisArg` and invoked with three 20932 * arguments; (value, index|key, collection). 20933 * 20934 * If a property name is provided for `callback` the created "_.pluck" style 20935 * callback will return the property value of the given element. 20936 * 20937 * If an object is provided for `callback` the created "_.where" style callback 20938 * will return `true` for elements that have the properties of the given object, 20939 * else `false`. 20940 * 20941 * @static 20942 * @memberOf _ 20943 * @alias all 20944 * @category Collections 20945 * @param {Array|Object|string} collection The collection to iterate over. 20946 * @param {Function|Object|string} [callback=identity] The function called 20947 * per iteration. If a property name or object is provided it will be used 20948 * to create a "_.pluck" or "_.where" style callback, respectively. 20949 * @param {*} [thisArg] The `this` binding of `callback`. 20950 * @returns {boolean} Returns `true` if all elements passed the callback check, 20951 * else `false`. 20952 * @example 20953 * 20954 * _.every([true, 1, null, 'yes']); 20955 * // => false 20956 * 20957 * var characters = [ 20958 * { 'name': 'barney', 'age': 36 }, 20959 * { 'name': 'fred', 'age': 40 } 20960 * ]; 20961 * 20962 * // using "_.pluck" callback shorthand 20963 * _.every(characters, 'age'); 20964 * // => true 20965 * 20966 * // using "_.where" callback shorthand 20967 * _.every(characters, { 'age': 36 }); 20968 * // => false 20969 */ 20970 function every(collection, callback, thisArg) { 20971 var result = true; 20972 callback = lodash.createCallback(callback, thisArg, 3); 20973 20974 var index = -1,
20975 length = collection ? collection.length : 0; 20976 20977 if (typeof length == 'number') { 20978 while (++index < length) { 20979 if (!(result = !!callback(collection[index], index, collection))) { 20980 break; 20981 } 20982 } 20983 } else { 20984 forOwn(collection, function(value, index, collection) { 20985 return (result = !!callback(value, index, collection)); 20986 }); 20987 } 20988 return result; 20989 } 20990 20991 /** 20992 * Iterates over elements of a collection, returning an array of all elements 20993 * the callback returns truey for. The callback is bound to `thisArg` and 20994 * invoked with three arguments; (value, index|key, collection). 20995 * 20996 * If a property name is provided for `callback` the created "_.pluck" style 20997 * callback will return the property value of the given element. 20998 * 20999 * If an object is provided for `callback` the created "_.where" style callback 21000 * will return `true` for elements that have the properties of the given object, 21001 * else `false`. 21002 * 21003 * @static 21004 * @memberOf _ 21005 * @alias select 21006 * @category Collections 21007 * @param {Array|Object|string} collection The collection to iterate over. 21008 * @param {Function|Object|string} [callback=identity] The function called 21009 * per iteration. If a property name or object is provided it will be used 21010 * to create a "_.pluck" or "_.where" style callback, respectively. 21011 * @param {*} [thisArg] The `this` binding of `callback`. 21012 * @returns {Array} Returns a new array of elements that passed the callback check. 21013 * @example 21014 * 21015 * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); 21016 * // => [2, 4, 6] 21017 * 21018 * var characters = [ 21019 * { 'name': 'barney', 'age': 36, 'blocked': false }, 21020 * { 'name': 'fred', 'age': 40, 'blocked': true } 21021 * ]; 21022 * 21023 * // using "_.pluck" callback shorthand 21024 * _.filter(characters, 'blocked'); 21025 * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] 21026 * 21027 * // using "_.where" callback shorthand 21028 * _.filter(characters, { 'age': 36 }); 21029 * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] 21030 */ 21031 function filter(collection, callback, thisArg) { 21032 var result = []; 21033 callback = lodash.createCallback(callback, thisArg, 3); 21034 21035 var index = -1,
21036 length = collection ? collection.length : 0; 21037 21038 if (typeof length == 'number') { 21039 while (++index < length) { 21040 var value = collection[index]; 21041 if (callback(value, index, collection)) { 21042 result.push(value); 21043 } 21044 } 21045 } else { 21046 forOwn(collection, function(value, index, collection) { 21047 if (callback(value, index, collection)) { 21048 result.push(value); 21049 } 21050 }); 21051 } 21052 return result; 21053 } 21054 21055 /** 21056 * Iterates over elements of a collection, returning the first element that 21057 * the callback returns truey for. The callback is bound to `thisArg` and 21058 * invoked with three arguments; (value, index|key, collection). 21059 * 21060 * If a property name is provided for `callback` the created "_.pluck" style 21061 * callback will return the property value of the given element. 21062 * 21063 * If an object is provided for `callback` the created "_.where" style callback 21064 * will return `true` for elements that have the properties of the given object, 21065 * else `false`. 21066 * 21067 * @static 21068 * @memberOf _ 21069 * @alias detect, findWhere 21070 * @category Collections 21071 * @param {Array|Object|string} collection The collection to iterate over. 21072 * @param {Function|Object|string} [callback=identity] The function called 21073 * per iteration. If a property name or object is provided it will be used 21074 * to create a "_.pluck" or "_.where" style callback, respectively. 21075 * @param {*} [thisArg] The `this` binding of `callback`. 21076 * @returns {*} Returns the found element, else `undefined`. 21077 * @example 21078 * 21079 * var characters = [ 21080 * { 'name': 'barney', 'age': 36, 'blocked': false }, 21081 * { 'name': 'fred', 'age': 40, 'blocked': true }, 21082 * { 'name': 'pebbles', 'age': 1, 'blocked': false } 21083 * ]; 21084 * 21085 * _.find(characters, function(chr) { 21086 * return chr.age < 40; 21087 * }); 21088 * // => { 'name': 'barney', 'age': 36, 'blocked': false } 21089 * 21090 * // using "_.where" callback shorthand 21091 * _.find(characters, { 'age': 1 }); 21092 * // => { 'name': 'pebbles', 'age': 1, 'blocked': false } 21093 * 21094 * // using "_.pluck" callback shorthand 21095 * _.find(characters, 'blocked'); 21096 * // => { 'name': 'fred', 'age': 40, 'blocked': true } 21097 */ 21098 function find(collection, callback, thisArg) { 21099 callback = lodash.createCallback(callback, thisArg, 3); 21100 21101 var index = -1,
21102 length = collection ? collection.length : 0; 21103 21104 if (typeof length == 'number') { 21105 while (++index < length) { 21106 var value = collection[index]; 21107 if (callback(value, index, collection)) { 21108 return value; 21109 } 21110 } 21111 } else { 21112 var result; 21113 forOwn(collection, function(value, index, collection) { 21114 if (callback(value, index, collection)) { 21115 result = value; 21116 return false; 21117 } 21118 }); 21119 return result; 21120 } 21121 } 21122 21123 /** 21124 * This method is like `_.find` except that it iterates over elements 21125 * of a `collection` from right to left. 21126 * 21127 * @static 21128 * @memberOf _ 21129 * @category Collections 21130 * @param {Array|Object|string} collection The collection to iterate over. 21131 * @param {Function|Object|string} [callback=identity] The function called 21132 * per iteration. If a property name or object is provided it will be used 21133 * to create a "_.pluck" or "_.where" style callback, respectively. 21134 * @param {*} [thisArg] The `this` binding of `callback`. 21135 * @returns {*} Returns the found element, else `undefined`. 21136 * @example 21137 * 21138 * _.findLast([1, 2, 3, 4], function(num) { 21139 * return num % 2 == 1; 21140 * }); 21141 * // => 3 21142 */ 21143 function findLast(collection, callback, thisArg) { 21144 var result; 21145 callback = lodash.createCallback(callback, thisArg, 3); 21146 forEachRight(collection, function(value, index, collection) { 21147 if (callback(value, index, collection)) { 21148 result = value; 21149 return false; 21150 } 21151 }); 21152 return result; 21153 } 21154 21155 /** 21156 * Iterates over elements of a collection, executing the callback for each 21157 * element. The callback is bound to `thisArg` and invoked with three arguments; 21158 * (value, index|key, collection). Callbacks may exit iteration early by 21159 * explicitly returning `false`. 21160 * 21161 * Note: As with other "Collections" methods, objects with a `length` property 21162 * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` 21163 * may be used for object iteration. 21164 * 21165 * @static 21166 * @memberOf _ 21167 * @alias each 21168 * @category Collections 21169 * @param {Array|Object|string} collection The collection to iterate over. 21170 * @param {Function} [callback=identity] The function called per iteration. 21171 * @param {*} [thisArg] The `this` binding of `callback`. 21172 * @returns {Array|Object|string} Returns `collection`. 21173 * @example 21174 * 21175 * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(','); 21176 * // => logs each number and returns '1,2,3' 21177 * 21178 * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); }); 21179 * // => logs each number and returns the object (property order is not guaranteed across environments) 21180 */ 21181 function forEach(collection, callback, thisArg) { 21182 var index = -1,
21183 length = collection ? collection.length : 0; 21184 21185 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); 21186 if (typeof length == 'number') { 21187 while (++index < length) { 21188 if (callback(collection[index], index, collection) === false) { 21189 break; 21190 } 21191 } 21192 } else { 21193 forOwn(collection, callback); 21194 } 21195 return collection; 21196 } 21197 21198 /** 21199 * This method is like `_.forEach` except that it iterates over elements 21200 * of a `collection` from right to left. 21201 * 21202 * @static 21203 * @memberOf _ 21204 * @alias eachRight 21205 * @category Collections 21206 * @param {Array|Object|string} collection The collection to iterate over. 21207 * @param {Function} [callback=identity] The function called per iteration. 21208 * @param {*} [thisArg] The `this` binding of `callback`. 21209 * @returns {Array|Object|string} Returns `collection`. 21210 * @example 21211 * 21212 * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(','); 21213 * // => logs each number from right to left and returns '3,2,1' 21214 */ 21215 function forEachRight(collection, callback, thisArg) {
21216 var length = collection ? collection.length : 0; 21217 callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); 21218 if (typeof length == 'number') { 21219 while (length--) { 21220 if (callback(collection[length], length, collection) === false) { 21221 break; 21222 } 21223 } 21224 } else { 21225 var props = keys(collection); 21226 length = props.length; 21227 forOwn(collection, function(value, key, collection) { 21228 key = props ? props[--length] : --length; 21229 return callback(collection[key], key, collection); 21230 }); 21231 } 21232 return collection; 21233 } 21234 21235 /** 21236 * Creates an object composed of keys generated from the results of running 21237 * each element of a collection through the callback. The corresponding value 21238 * of each key is an array of the elements responsible for generating the key. 21239 * The callback is bound to `thisArg` and invoked with three arguments; 21240 * (value, index|key, collection). 21241 * 21242 * If a property name is provided for `callback` the created "_.pluck" style 21243 * callback will return the property value of the given element. 21244 * 21245 * If an object is provided for `callback` the created "_.where" style callback 21246 * will return `true` for elements that have the properties of the given object, 21247 * else `false` 21248 * 21249 * @static 21250 * @memberOf _ 21251 * @category Collections 21252 * @param {Array|Object|string} collection The collection to iterate over. 21253 * @param {Function|Object|string} [callback=identity] The function called 21254 * per iteration. If a property name or object is provided it will be used 21255 * to create a "_.pluck" or "_.where" style callback, respectively. 21256 * @param {*} [thisArg] The `this` binding of `callback`. 21257 * @returns {Object} Returns the composed aggregate object. 21258 * @example 21259 * 21260 * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); 21261 * // => { '4': [4.2], '6': [6.1, 6.4] } 21262 * 21263 * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); 21264 * // => { '4': [4.2], '6': [6.1, 6.4] } 21265 * 21266 * // using "_.pluck" callback shorthand 21267 * _.groupBy(['one', 'two', 'three'], 'length'); 21268 * // => { '3': ['one', 'two'], '5': ['three'] } 21269 */ 21270 var groupBy = createAggregator(function(result, value, key) { 21271 (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); 21272 }); 21273 21274 /**
21275 * Creates an object composed of keys generated from the results of running 21276 * each element of the collection through the given callback. The corresponding 21277 * value of each key is the last element responsible for generating the key. 21278 * The callback is bound to `thisArg` and invoked with three arguments; 21279 * (value, index|key, collection). 21280 * 21281 * If a property name is provided for `callback` the created "_.pluck" style 21282 * callback will return the property value of the given element. 21283 * 21284 * If an object is provided for `callback` the created "_.where" style callback 21285 * will return `true` for elements that have the properties of the given object, 21286 * else `false`. 21287 * 21288 * @static 21289 * @memberOf _ 21290 * @category Collections 21291 * @param {Array|Object|string} collection The collection to iterate over. 21292 * @param {Function|Object|string} [callback=identity] The function called 21293 * per iteration. If a property name or object is provided it will be used 21294 * to create a "_.pluck" or "_.where" style callback, respectively. 21295 * @param {*} [thisArg] The `this` binding of `callback`. 21296 * @returns {Object} Returns the composed aggregate object. 21297 * @example 21298 * 21299 * var keys = [ 21300 * { 'dir': 'left', 'code': 97 }, 21301 * { 'dir': 'right', 'code': 100 } 21302 * ]; 21303 * 21304 * _.indexBy(keys, 'dir'); 21305 * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } 21306 * 21307 * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); }); 21308 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } 21309 * 21310 * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String); 21311 * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } 21312 */ 21313 var indexBy = createAggregator(function(result, value, key) { 21314 result[key] = value; 21315 }); 21316 21317 /** 21318 * Invokes the method named by `methodName` on each element in the `collection` 21319 * returning an array of the results of each invoked method. Additional arguments 21320 * will be provided to each invoked method. If `methodName` is a function it 21321 * will be invoked for, and `this` bound to, each element in the `collection`. 21322 * 21323 * @static 21324 * @memberOf _ 21325 * @category Collections 21326 * @param {Array|Object|string} collection The collection to iterate over. 21327 * @param {Function|string} methodName The name of the method to invoke or 21328 * the function invoked per iteration. 21329 * @param {...*} [arg] Arguments to invoke the method with. 21330 * @returns {Array} Returns a new array of the results of each invoked method. 21331 * @example 21332 * 21333 * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); 21334 * // => [[1, 5, 7], [1, 2, 3]] 21335 * 21336 * _.invoke([123, 456], String.prototype.split, ''); 21337 * // => [['1', '2', '3'], ['4', '5', '6']] 21338 */ 21339 function invoke(collection, methodName) { 21340 var args = slice(arguments, 2), 21341 index = -1, 21342 isFunc = typeof methodName == 'function',
21343 length = collection ? collection.length : 0, 21344 result = Array(typeof length == 'number' ? length : 0); 21345 21346 forEach(collection, function(value) { 21347 result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args); 21348 }); 21349 return result; 21350 } 21351 21352 /** 21353 * Creates an array of values by running each element in the collection 21354 * through the callback. The callback is bound to `thisArg` and invoked with 21355 * three arguments; (value, index|key, collection). 21356 * 21357 * If a property name is provided for `callback` the created "_.pluck" style 21358 * callback will return the property value of the given element. 21359 * 21360 * If an object is provided for `callback` the created "_.where" style callback 21361 * will return `true` for elements that have the properties of the given object, 21362 * else `false`. 21363 * 21364 * @static 21365 * @memberOf _ 21366 * @alias collect 21367 * @category Collections 21368 * @param {Array|Object|string} collection The collection to iterate over. 21369 * @param {Function|Object|string} [callback=identity] The function called 21370 * per iteration. If a property name or object is provided it will be used 21371 * to create a "_.pluck" or "_.where" style callback, respectively. 21372 * @param {*} [thisArg] The `this` binding of `callback`. 21373 * @returns {Array} Returns a new array of the results of each `callback` execution. 21374 * @example 21375 * 21376 * _.map([1, 2, 3], function(num) { return num * 3; }); 21377 * // => [3, 6, 9] 21378 * 21379 * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); 21380 * // => [3, 6, 9] (property order is not guaranteed across environments) 21381 * 21382 * var characters = [ 21383 * { 'name': 'barney', 'age': 36 }, 21384 * { 'name': 'fred', 'age': 40 } 21385 * ]; 21386 * 21387 * // using "_.pluck" callback shorthand 21388 * _.map(characters, 'name'); 21389 * // => ['barney', 'fred'] 21390 */ 21391 function map(collection, callback, thisArg) { 21392 var index = -1,
21393 length = collection ? collection.length : 0; 21394 21395 callback = lodash.createCallback(callback, thisArg, 3); 21396 if (typeof length == 'number') { 21397 var result = Array(length); 21398 while (++index < length) { 21399 result[index] = callback(collection[index], index, collection); 21400 } 21401 } else { 21402 result = []; 21403 forOwn(collection, function(value, key, collection) { 21404 result[++index] = callback(value, key, collection); 21405 }); 21406 } 21407 return result; 21408 } 21409 21410 /** 21411 * Retrieves the maximum value of a collection. If the collection is empty or 21412 * falsey `-Infinity` is returned. If a callback is provided it will be executed 21413 * for each value in the collection to generate the criterion by which the value 21414 * is ranked. The callback is bound to `thisArg` and invoked with three 21415 * arguments; (value, index, collection). 21416 * 21417 * If a property name is provided for `callback` the created "_.pluck" style 21418 * callback will return the property value of the given element. 21419 * 21420 * If an object is provided for `callback` the created "_.where" style callback 21421 * will return `true` for elements that have the properties of the given object, 21422 * else `false`. 21423 * 21424 * @static 21425 * @memberOf _ 21426 * @category Collections 21427 * @param {Array|Object|string} collection The collection to iterate over. 21428 * @param {Function|Object|string} [callback=identity] The function called 21429 * per iteration. If a property name or object is provided it will be used 21430 * to create a "_.pluck" or "_.where" style callback, respectively. 21431 * @param {*} [thisArg] The `this` binding of `callback`. 21432 * @returns {*} Returns the maximum value. 21433 * @example 21434 * 21435 * _.max([4, 2, 8, 6]); 21436 * // => 8 21437 * 21438 * var characters = [ 21439 * { 'name': 'barney', 'age': 36 }, 21440 * { 'name': 'fred', 'age': 40 } 21441 * ]; 21442 * 21443 * _.max(characters, function(chr) { return chr.age; }); 21444 * // => { 'name': 'fred', 'age': 40 }; 21445 * 21446 * // using "_.pluck" callback shorthand 21447 * _.max(characters, 'age'); 21448 * // => { 'name': 'fred', 'age': 40 }; 21449 */ 21450 function max(collection, callback, thisArg) { 21451 var computed = -Infinity, 21452 result = computed; 21453 21454 // allows working with functions like `_.map` without using 21455 // their `index` argument as a callback 21456 if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { 21457 callback = null; 21458 } 21459 if (callback == null && isArray(collection)) { 21460 var index = -1, 21461 length = collection.length; 21462 21463 while (++index < length) { 21464 var value = collection[index]; 21465 if (value > result) { 21466 result = value; 21467 } 21468 } 21469 } else { 21470 callback = (callback == null && isString(collection)) 21471 ? charAtCallback 21472 : lodash.createCallback(callback, thisArg, 3); 21473 21474 forEach(collection, function(value, index, collection) { 21475 var current = callback(value, index, collection); 21476 if (current > computed) { 21477 computed = current; 21478 result = value; 21479 } 21480 }); 21481 } 21482 return result; 21483 } 21484 21485 /** 21486 * Retrieves the minimum value of a collection. If the collection is empty or 21487 * falsey `Infinity` is returned. If a callback is provided it will be executed 21488 * for each value in the collection to generate the criterion by which the value 21489 * is ranked. The callback is bound to `thisArg` and invoked with three 21490 * arguments; (value, index, collection). 21491 * 21492 * If a property name is provided for `callback` the created "_.pluck" style 21493 * callback will return the property value of the given element. 21494 * 21495 * If an object is provided for `callback` the created "_.where" style callback 21496 * will return `true` for elements that have the properties of the given object, 21497 * else `false`. 21498 * 21499 * @static 21500 * @memberOf _ 21501 * @category Collections 21502 * @param {Array|Object|string} collection The collection to iterate over. 21503 * @param {Function|Object|string} [callback=identity] The function called 21504 * per iteration. If a property name or object is provided it will be used 21505 * to create a "_.pluck" or "_.where" style callback, respectively. 21506 * @param {*} [thisArg] The `this` binding of `callback`. 21507 * @returns {*} Returns the minimum value. 21508 * @example 21509 * 21510 * _.min([4, 2, 8, 6]); 21511 * // => 2 21512 * 21513 * var characters = [ 21514 * { 'name': 'barney', 'age': 36 }, 21515 * { 'name': 'fred', 'age': 40 } 21516 * ]; 21517 * 21518 * _.min(characters, function(chr) { return chr.age; }); 21519 * // => { 'name': 'barney', 'age': 36 }; 21520 * 21521 * // using "_.pluck" callback shorthand 21522 * _.min(characters, 'age'); 21523 * // => { 'name': 'barney', 'age': 36 }; 21524 */ 21525 function min(collection, callback, thisArg) { 21526 var computed = Infinity, 21527 result = computed; 21528 21529 // allows working with functions like `_.map` without using 21530 // their `index` argument as a callback 21531 if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { 21532 callback = null; 21533 } 21534 if (callback == null && isArray(collection)) { 21535 var index = -1, 21536 length = collection.length; 21537 21538 while (++index < length) { 21539 var value = collection[index]; 21540 if (value < result) { 21541 result = value; 21542 } 21543 } 21544 } else { 21545 callback = (callback == null && isString(collection)) 21546 ? charAtCallback 21547 : lodash.createCallback(callback, thisArg, 3); 21548
21549 forEach(collection, function(value, index, collection) { 21550 var current = callback(value, index, collection); 21551 if (current < computed) { 21552 computed = current; 21553 result = value; 21554 } 21555 }); 21556 } 21557 return result; 21558 } 21559 21560 /** 21561 * Retrieves the value of a specified property from all elements in the collection. 21562 * 21563 * @static 21564 * @memberOf _ 21565 * @type Function 21566 * @category Collections 21567 * @param {Array|Object|string} collection The collection to iterate over. 21568 * @param {string} property The name of the property to pluck. 21569 * @returns {Array} Returns a new array of property values. 21570 * @example 21571 * 21572 * var characters = [ 21573 * { 'name': 'barney', 'age': 36 }, 21574 * { 'name': 'fred', 'age': 40 } 21575 * ]; 21576 * 21577 * _.pluck(characters, 'name'); 21578 * // => ['barney', 'fred'] 21579 */ 21580 var pluck = map; 21581 21582 /** 21583 * Reduces a collection to a value which is the accumulated result of running 21584 * each element in the collection through the callback, where each successive 21585 * callback execution consumes the return value of the previous execution. If 21586 * `accumulator` is not provided the first element of the collection will be 21587 * used as the initial `accumulator` value. The callback is bound to `thisArg` 21588 * and invoked with four arguments; (accumulator, value, index|key, collection). 21589 * 21590 * @static 21591 * @memberOf _ 21592 * @alias foldl, inject 21593 * @category Collections 21594 * @param {Array|Object|string} collection The collection to iterate over. 21595 * @param {Function} [callback=identity] The function called per iteration. 21596 * @param {*} [accumulator] Initial value of the accumulator. 21597 * @param {*} [thisArg] The `this` binding of `callback`. 21598 * @returns {*} Returns the accumulated value. 21599 * @example 21600 * 21601 * var sum = _.reduce([1, 2, 3], function(sum, num) { 21602 * return sum + num; 21603 * }); 21604 * // => 6 21605 * 21606 * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) { 21607 * result[key] = num * 3; 21608 * return result; 21609 * }, {}); 21610 * // => { 'a': 3, 'b': 6, 'c': 9 } 21611 */ 21612 function reduce(collection, callback, accumulator, thisArg) { 21613 if (!collection) return accumulator; 21614 var noaccum = arguments.length < 3; 21615 callback = lodash.createCallback(callback, thisArg, 4); 21616 21617 var index = -1, 21618 length = collection.length; 21619 21620 if (typeof length == 'number') { 21621 if (noaccum) { 21622 accumulator = collection[++index]; 21623 } 21624 while (++index < length) { 21625 accumulator = callback(accumulator, collection[index], index, collection); 21626 } 21627 } else { 21628 forOwn(collection, function(value, index, collection) { 21629 accumulator = noaccum 21630 ? (noaccum = false, value) 21631 : callback(accumulator, value, index, collection) 21632 }); 21633 } 21634 return accumulator; 21635 } 21636 21637 /** 21638 * This method is like `_.reduce` except that it iterates over elements 21639 * of a `collection` from right to left. 21640 * 21641 * @static 21642 * @memberOf _ 21643 * @alias foldr 21644 * @category Collections 21645 * @param {Array|Object|string} collection The collection to iterate over. 21646 * @param {Function} [callback=identity] The function called per iteration. 21647 * @param {*} [accumulator] Initial value of the accumulator. 21648 * @param {*} [thisArg] The `this` binding of `callback`. 21649 * @returns {*} Returns the accumulated value. 21650 * @example 21651 * 21652 * var list = [[0, 1], [2, 3], [4, 5]]; 21653 * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); 21654 * // => [4, 5, 2, 3, 0, 1] 21655 */ 21656 function reduceRight(collection, callback, accumulator, thisArg) { 21657 var noaccum = arguments.length < 3; 21658 callback = lodash.createCallback(callback, thisArg, 4); 21659 forEachRight(collection, function(value, index, collection) { 21660 accumulator = noaccum 21661 ? (noaccum = false, value) 21662 : callback(accumulator, value, index, collection); 21663 }); 21664 return accumulator; 21665 } 21666 21667 /** 21668 * The opposite of `_.filter` this method returns the elements of a 21669 * collection that the callback does **not** return truey for. 21670 * 21671 * If a property name is provided for `callback` the created "_.pluck" style 21672 * callback will return the property value of the given element. 21673 * 21674 * If an object is provided for `callback` the created "_.where" style callback 21675 * will return `true` for elements that have the properties of the given object, 21676 * else `false`. 21677 * 21678 * @static 21679 * @memberOf _ 21680 * @category Collections 21681 * @param {Array|Object|string} collection The collection to iterate over. 21682 * @param {Function|Object|string} [callback=identity] The function called 21683 * per iteration. If a property name or object is provided it will be used 21684 * to create a "_.pluck" or "_.where" style callback, respectively. 21685 * @param {*} [thisArg] The `this` binding of `callback`. 21686 * @returns {Array} Returns a new array of elements that failed the callback check. 21687 * @example 21688 * 21689 * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); 21690 * // => [1, 3, 5] 21691 * 21692 * var characters = [ 21693 * { 'name': 'barney', 'age': 36, 'blocked': false }, 21694 * { 'name': 'fred', 'age': 40, 'blocked': true } 21695 * ]; 21696 * 21697 * // using "_.pluck" callback shorthand 21698 * _.reject(characters, 'blocked'); 21699 * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] 21700 * 21701 * // using "_.where" callback shorthand 21702 * _.reject(characters, { 'age': 36 }); 21703 * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] 21704 */ 21705 function reject(collection, callback, thisArg) { 21706 callback = lodash.createCallback(callback, thisArg, 3); 21707 return filter(collection, function(value, index, collection) { 21708 return !callback(value, index, collection); 21709 }); 21710 } 21711 21712 /** 21713 * Retrieves a random element or `n` random elements from a collection. 21714 * 21715 * @static 21716 * @memberOf _ 21717 * @category Collections 21718 * @param {Array|Object|string} collection The collection to sample. 21719 * @param {number} [n] The number of elements to sample. 21720 * @param- {Object} [guard] Allows working with functions like `_.map` 21721 * without using their `index` arguments as `n`. 21722 * @returns {Array} Returns the random sample(s) of `collection`. 21723 * @example 21724 * 21725 * _.sample([1, 2, 3, 4]); 21726 * // => 2 21727 * 21728 * _.sample([1, 2, 3, 4], 2); 21729 * // => [3, 1] 21730 */ 21731 function sample(collection, n, guard) { 21732 if (collection && typeof collection.length != 'number') { 21733 collection = values(collection); 21734 } 21735 if (n == null || guard) {
21736 return collection ? collection[baseRandom(0, collection.length - 1)] : undefined; 21737 } 21738 var result = shuffle(collection); 21739 result.length = nativeMin(nativeMax(0, n), result.length); 21740 return result; 21741 } 21742 21743 /** 21744 * Creates an array of shuffled values, using a version of the Fisher-Yates 21745 * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. 21746 * 21747 * @static 21748 * @memberOf _ 21749 * @category Collections 21750 * @param {Array|Object|string} collection The collection to shuffle. 21751 * @returns {Array} Returns a new shuffled collection. 21752 * @example 21753 * 21754 * _.shuffle([1, 2, 3, 4, 5, 6]); 21755 * // => [4, 1, 6, 3, 5, 2] 21756 */ 21757 function shuffle(collection) { 21758 var index = -1, 21759 length = collection ? collection.length : 0, 21760 result = Array(typeof length == 'number' ? length : 0); 21761 21762 forEach(collection, function(value) { 21763 var rand = baseRandom(0, ++index); 21764 result[index] = result[rand]; 21765 result[rand] = value; 21766 }); 21767 return result; 21768 } 21769 21770 /** 21771 * Gets the size of the `collection` by returning `collection.length` for arrays 21772 * and array-like objects or the number of own enumerable properties for objects. 21773 * 21774 * @static 21775 * @memberOf _ 21776 * @category Collections 21777 * @param {Array|Object|string} collection The collection to inspect. 21778 * @returns {number} Returns `collection.length` or number of own enumerable properties. 21779 * @example 21780 * 21781 * _.size([1, 2]); 21782 * // => 2 21783 * 21784 * _.size({ 'one': 1, 'two': 2, 'three': 3 }); 21785 * // => 3 21786 * 21787 * _.size('pebbles'); 21788 * // => 7 21789 */ 21790 function size(collection) {
21791 var length = collection ? collection.length : 0; 21792 return typeof length == 'number' ? length : keys(collection).length; 21793 } 21794 21795 /** 21796 * Checks if the callback returns a truey value for **any** element of a 21797 * collection. The function returns as soon as it finds a passing value and 21798 * does not iterate over the entire collection. The callback is bound to 21799 * `thisArg` and invoked with three arguments; (value, index|key, collection). 21800 * 21801 * If a property name is provided for `callback` the created "_.pluck" style 21802 * callback will return the property value of the given element. 21803 * 21804 * If an object is provided for `callback` the created "_.where" style callback 21805 * will return `true` for elements that have the properties of the given object, 21806 * else `false`. 21807 * 21808 * @static 21809 * @memberOf _ 21810 * @alias any 21811 * @category Collections 21812 * @param {Array|Object|string} collection The collection to iterate over. 21813 * @param {Function|Object|string} [callback=identity] The function called 21814 * per iteration. If a property name or object is provided it will be used 21815 * to create a "_.pluck" or "_.where" style callback, respectively. 21816 * @param {*} [thisArg] The `this` binding of `callback`. 21817 * @returns {boolean} Returns `true` if any element passed the callback check, 21818 * else `false`. 21819 * @example 21820 * 21821 * _.some([null, 0, 'yes', false], Boolean); 21822 * // => true 21823 * 21824 * var characters = [ 21825 * { 'name': 'barney', 'age': 36, 'blocked': false }, 21826 * { 'name': 'fred', 'age': 40, 'blocked': true } 21827 * ]; 21828 * 21829 * // using "_.pluck" callback shorthand 21830 * _.some(characters, 'blocked'); 21831 * // => true 21832 * 21833 * // using "_.where" callback shorthand 21834 * _.some(characters, { 'age': 1 }); 21835 * // => false 21836 */ 21837 function some(collection, callback, thisArg) { 21838 var result; 21839 callback = lodash.createCallback(callback, thisArg, 3); 21840 21841 var index = -1,
21842 length = collection ? collection.length : 0; 21843 21844 if (typeof length == 'number') { 21845 while (++index < length) { 21846 if ((result = callback(collection[index], index, collection))) { 21847 break; 21848 } 21849 } 21850 } else { 21851 forOwn(collection, function(value, index, collection) { 21852 return !(result = callback(value, index, collection)); 21853 }); 21854 } 21855 return !!result; 21856 } 21857 21858 /** 21859 * Creates an array of elements, sorted in ascending order by the results of 21860 * running each element in a collection through the callback. This method 21861 * performs a stable sort, that is, it will preserve the original sort order 21862 * of equal elements. The callback is bound to `thisArg` and invoked with 21863 * three arguments; (value, index|key, collection). 21864 * 21865 * If a property name is provided for `callback` the created "_.pluck" style 21866 * callback will return the property value of the given element. 21867 * 21868 * If an array of property names is provided for `callback` the collection 21869 * will be sorted by each property value. 21870 * 21871 * If an object is provided for `callback` the created "_.where" style callback 21872 * will return `true` for elements that have the properties of the given object, 21873 * else `false`. 21874 * 21875 * @static 21876 * @memberOf _ 21877 * @category Collections 21878 * @param {Array|Object|string} collection The collection to iterate over. 21879 * @param {Array|Function|Object|string} [callback=identity] The function called 21880 * per iteration. If a property name or object is provided it will be used 21881 * to create a "_.pluck" or "_.where" style callback, respectively. 21882 * @param {*} [thisArg] The `this` binding of `callback`. 21883 * @returns {Array} Returns a new array of sorted elements. 21884 * @example 21885 * 21886 * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); 21887 * // => [3, 1, 2] 21888 * 21889 * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); 21890 * // => [3, 1, 2] 21891 * 21892 * var characters = [ 21893 * { 'name': 'barney', 'age': 36 }, 21894 * { 'name': 'fred', 'age': 40 }, 21895 * { 'name': 'barney', 'age': 26 }, 21896 * { 'name': 'fred', 'age': 30 } 21897 * ]; 21898 * 21899 * // using "_.pluck" callback shorthand 21900 * _.map(_.sortBy(characters, 'age'), _.values); 21901 * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] 21902 * 21903 * // sorting by multiple properties 21904 * _.map(_.sortBy(characters, ['name', 'age']), _.values); 21905 * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] 21906 */ 21907 function sortBy(collection, callback, thisArg) { 21908 var index = -1, 21909 isArr = isArray(callback),
21910 length = collection ? collection.length : 0, 21911 result = Array(typeof length == 'number' ? length : 0); 21912 21913 if (!isArr) { 21914 callback = lodash.createCallback(callback, thisArg, 3); 21915 } 21916 forEach(collection, function(value, key, collection) { 21917 var object = result[++index] = getObject(); 21918 if (isArr) { 21919 object.criteria = map(callback, function(key) { return value[key]; }); 21920 } else { 21921 (object.criteria = getArray())[0] = callback(value, key, collection); 21922 } 21923 object.index = index; 21924 object.value = value; 21925 }); 21926 21927 length = result.length; 21928 result.sort(compareAscending); 21929 while (length--) { 21930 var object = result[length]; 21931 result[length] = object.value; 21932 if (!isArr) { 21933 releaseArray(object.criteria); 21934 } 21935 releaseObject(object); 21936 } 21937 return result; 21938 } 21939 21940 /** 21941 * Converts the `collection` to an array. 21942 * 21943 * @static 21944 * @memberOf _ 21945 * @category Collections 21946 * @param {Array|Object|string} collection The collection to convert. 21947 * @returns {Array} Returns the new converted array. 21948 * @example 21949 * 21950 * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); 21951 * // => [2, 3, 4] 21952 */ 21953 function toArray(collection) { 21954 if (collection && typeof collection.length == 'number') { 21955 return slice(collection); 21956 } 21957 return values(collection); 21958 } 21959 21960 /** 21961 * Performs a deep comparison of each element in a `collection` to the given 21962 * `properties` object, returning an array of all elements that have equivalent 21963 * property values. 21964 * 21965 * @static 21966 * @memberOf _ 21967 * @type Function 21968 * @category Collections 21969 * @param {Array|Object|string} collection The collection to iterate over. 21970 * @param {Object} props The object of property values to filter by. 21971 * @returns {Array} Returns a new array of elements that have the given properties. 21972 * @example 21973 * 21974 * var characters = [ 21975 * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }, 21976 * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } 21977 * ]; 21978 * 21979 * _.where(characters, { 'age': 36 }); 21980 * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }] 21981 * 21982 * _.where(characters, { 'pets': ['dino'] }); 21983 * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }] 21984 */ 21985 var where = filter; 21986 21987 /*--------------------------------------------------------------------------*/ 21988 21989 /** 21990 * Creates an array with all falsey values removed. The values `false`, `null`, 21991 * `0`, `""`, `undefined`, and `NaN` are all falsey. 21992 * 21993 * @static 21994 * @memberOf _ 21995 * @category Arrays 21996 * @param {Array} array The array to compact. 21997 * @returns {Array} Returns a new array of filtered values. 21998 * @example 21999 * 22000 * _.compact([0, 1, false, 2, '', 3]); 22001 * // => [1, 2, 3] 22002 */ 22003 function compact(array) { 22004 var index = -1, 22005 length = array ? array.length : 0, 22006 result = []; 22007 22008 while (++index < length) { 22009 var value = array[index]; 22010 if (value) { 22011 result.push(value); 22012 } 22013 } 22014 return result; 22015 } 22016 22017 /** 22018 * Creates an array excluding all values of the provided arrays using strict 22019 * equality for comparisons, i.e. `===`. 22020 * 22021 * @static 22022 * @memberOf _ 22023 * @category Arrays 22024 * @param {Array} array The array to process. 22025 * @param {...Array} [values] The arrays of values to exclude. 22026 * @returns {Array} Returns a new array of filtered values. 22027 * @example 22028 * 22029 * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); 22030 * // => [1, 3, 4] 22031 */ 22032 function difference(array) { 22033 return baseDifference(array, baseFlatten(arguments, true, true, 1)); 22034 } 22035 22036 /** 22037 * This method is like `_.find` except that it returns the index of the first 22038 * element that passes the callback check, instead of the element itself. 22039 * 22040 * If a property name is provided for `callback` the created "_.pluck" style 22041 * callback will return the property value of the given element. 22042 * 22043 * If an object is provided for `callback` the created "_.where" style callback 22044 * will return `true` for elements that have the properties of the given object, 22045 * else `false`. 22046 * 22047 * @static 22048 * @memberOf _ 22049 * @category Arrays 22050 * @param {Array} array The array to search. 22051 * @param {Function|Object|string} [callback=identity] The function called 22052 * per iteration. If a property name or object is provided it will be used 22053 * to create a "_.pluck" or "_.where" style callback, respectively. 22054 * @param {*} [thisArg] The `this` binding of `callback`. 22055 * @returns {number} Returns the index of the found element, else `-1`. 22056 * @example 22057 * 22058 * var characters = [ 22059 * { 'name': 'barney', 'age': 36, 'blocked': false }, 22060 * { 'name': 'fred', 'age': 40, 'blocked': true }, 22061 * { 'name': 'pebbles', 'age': 1, 'blocked': false } 22062 * ]; 22063 * 22064 * _.findIndex(characters, function(chr) { 22065 * return chr.age < 20; 22066 * }); 22067 * // => 2 22068 * 22069 * // using "_.where" callback shorthand 22070 * _.findIndex(characters, { 'age': 36 }); 22071 * // => 0 22072 * 22073 * // using "_.pluck" callback shorthand 22074 * _.findIndex(characters, 'blocked'); 22075 * // => 1 22076 */ 22077 function findIndex(array, callback, thisArg) { 22078 var index = -1, 22079 length = array ? array.length : 0; 22080 22081 callback = lodash.createCallback(callback, thisArg, 3); 22082 while (++index < length) { 22083 if (callback(array[index], index, array)) { 22084 return index; 22085 } 22086 } 22087 return -1; 22088 } 22089 22090 /** 22091 * This method is like `_.findIndex` except that it iterates over elements 22092 * of a `collection` from right to left. 22093 * 22094 * If a property name is provided for `callback` the created "_.pluck" style 22095 * callback will return the property value of the given element. 22096 * 22097 * If an object is provided for `callback` the created "_.where" style callback 22098 * will return `true` for elements that have the properties of the given object, 22099 * else `false`. 22100 * 22101 * @static 22102 * @memberOf _ 22103 * @category Arrays 22104 * @param {Array} array The array to search. 22105 * @param {Function|Object|string} [callback=identity] The function called 22106 * per iteration. If a property name or object is provided it will be used 22107 * to create a "_.pluck" or "_.where" style callback, respectively. 22108 * @param {*} [thisArg] The `this` binding of `callback`. 22109 * @returns {number} Returns the index of the found element, else `-1`. 22110 * @example 22111 * 22112 * var characters = [ 22113 * { 'name': 'barney', 'age': 36, 'blocked': true }, 22114 * { 'name': 'fred', 'age': 40, 'blocked': false }, 22115 * { 'name': 'pebbles', 'age': 1, 'blocked': true } 22116 * ]; 22117 * 22118 * _.findLastIndex(characters, function(chr) { 22119 * return chr.age > 30; 22120 * }); 22121 * // => 1 22122 * 22123 * // using "_.where" callback shorthand 22124 * _.findLastIndex(characters, { 'age': 36 }); 22125 * // => 0 22126 * 22127 * // using "_.pluck" callback shorthand 22128 * _.findLastIndex(characters, 'blocked'); 22129 * // => 2 22130 */ 22131 function findLastIndex(array, callback, thisArg) { 22132 var length = array ? array.length : 0; 22133 callback = lodash.createCallback(callback, thisArg, 3); 22134 while (length--) { 22135 if (callback(array[length], length, array)) { 22136 return length; 22137 } 22138 } 22139 return -1; 22140 } 22141 22142 /** 22143 * Gets the first element or first `n` elements of an array. If a callback 22144 * is provided elements at the beginning of the array are returned as long 22145 * as the callback returns truey. The callback is bound to `thisArg` and 22146 * invoked with three arguments; (value, index, array). 22147 * 22148 * If a property name is provided for `callback` the created "_.pluck" style 22149 * callback will return the property value of the given element. 22150 * 22151 * If an object is provided for `callback` the created "_.where" style callback 22152 * will return `true` for elements that have the properties of the given object, 22153 * else `false`. 22154 * 22155 * @static 22156 * @memberOf _ 22157 * @alias head, take 22158 * @category Arrays 22159 * @param {Array} array The array to query. 22160 * @param {Function|Object|number|string} [callback] The function called 22161 * per element or the number of elements to return. If a property name or 22162 * object is provided it will be used to create a "_.pluck" or "_.where" 22163 * style callback, respectively. 22164 * @param {*} [thisArg] The `this` binding of `callback`. 22165 * @returns {*}
22165 Returns the first element(s) of `array`. 22166 * @example 22167 * 22168 * _.first([1, 2, 3]); 22169 * // => 1 22170 * 22171 * _.first([1, 2, 3], 2); 22172 * // => [1, 2] 22173 * 22174 * _.first([1, 2, 3], function(num) { 22175 * return num < 3; 22176 * }); 22177 * // => [1, 2] 22178 * 22179 * var characters = [ 22180 * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, 22181 * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, 22182 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } 22183 * ]; 22184 * 22185 * // using "_.pluck" callback shorthand 22186 * _.first(characters, 'blocked'); 22187 * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }] 22188 * 22189 * // using "_.where" callback shorthand 22190 * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name'); 22191 * // => ['barney', 'fred'] 22192 */ 22193 function first(array, callback, thisArg) { 22194 var n = 0, 22195 length = array ? array.length : 0; 22196 22197 if (typeof callback != 'number' && callback != null) { 22198 var index = -1; 22199 callback = lodash.createCallback(callback, thisArg, 3); 22200 while (++index < length && callback(array[index], index, array)) { 22201 n++; 22202 } 22203 } else { 22204 n = callback; 22205 if (n == null || thisArg) { 22206 return array ? array[0] : undefined; 22207 } 22208 } 22209 return slice(array, 0, nativeMin(nativeMax(0, n), length)); 22210 } 22211 22212 /** 22213 * Flattens a nested array (the nesting can be to any depth). If `isShallow` 22214 * is truey, the array will only be flattened a single level. If a callback 22215 * is provided each element of the array is passed through the callback before 22216 * flattening. The callback is bound to `thisArg` and invoked with three 22217 * arguments; (value, index, array). 22218 * 22219 * If a property name is provided for `callback` the created "_.pluck" style 22220 * callback will return the property value of the given element. 22221 * 22222 * If an object is provided for `callback` the created "_.where" style callback 22223 * will return `true` for elements that have the properties of the given object, 22224 * else `false`. 22225 * 22226 * @static 22227 * @memberOf _ 22228 * @category Arrays 22229 * @param {Array} array The array to flatten. 22230 * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. 22231 * @param {Function|Object|string} [callback=identity] The function called 22232 * per iteration. If a property name or object is provided it will be used 22233 * to create a "_.pluck" or "_.where" style callback, respectively. 22234 * @param {*} [thisArg] The `this` binding of `callback`. 22235 * @returns {Array} Returns a new flattened array. 22236 * @example 22237 * 22238 * _.flatten([1, [2], [3, [[4]]]]); 22239 * // => [1, 2, 3, 4]; 22240 * 22241 * _.flatten([1, [2], [3, [[4]]]], true); 22242 * // => [1, 2, 3, [[4]]]; 22243 * 22244 * var characters = [ 22245 * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }, 22246 * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } 22247 * ]; 22248 * 22249 * // using "_.pluck" callback shorthand 22250 * _.flatten(characters, 'pets'); 22251 * // => ['hoppy', 'baby puss', 'dino'] 22252 */ 22253 function flatten(array, isShallow, callback, thisArg) { 22254 // juggle arguments 22255 if (typeof isShallow != 'boolean' && isShallow != null) { 22256 thisArg = callback; 22257 callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow; 22258 isShallow = false; 22259 } 22260 if (callback != null) { 22261 array = map(array, callback, thisArg); 22262 } 22263 return baseFlatten(array, isShallow); 22264 } 22265 22266 /** 22267 * Gets the index at which the first occurrence of `value` is found using 22268 * strict equality for comparisons, i.e. `===`. If the array is already sorted 22269 * providing `true` for `fromIndex` will run a faster binary search. 22270 * 22271 * @static 22272 * @memberOf _ 22273 * @category Arrays 22274 * @param {Array} array The array to search. 22275 * @param {*} value The value to search for. 22276 * @param {boolean|number} [fromIndex=0] The index to search from or `true` 22277 * to perform a binary search on a sorted array.
22278 * @returns {number} Returns the index of the matched value or `-1`. 22279 * @example 22280 * 22281 * _.indexOf([1, 2, 3, 1, 2, 3], 2); 22282 * // => 1 22283 * 22284 * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3); 22285 * // => 4 22286 * 22287 * _.indexOf([1, 1, 2, 2, 3, 3], 2, true); 22288 * // => 2 22289 */ 22290 function indexOf(array, value, fromIndex) { 22291 if (typeof fromIndex == 'number') { 22292 var length = array ? array.length : 0; 22293 fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); 22294 } else if (fromIndex) { 22295 var index = sortedIndex(array, value); 22296 return array[index] === value ? index : -1; 22297 } 22298 return baseIndexOf(array, value, fromIndex); 22299 } 22300 22301 /** 22302 * Gets all but the last element or last `n` elements of an array. If a 22303 * callback is provided elements at the end of the array are excluded from 22304 * the result as long as the callback returns truey. The callback is bound 22305 * to `thisArg` and invoked with three arguments; (value, index, array). 22306 * 22307 * If a property name is provided for `callback` the created "_.pluck" style 22308 * callback will return the property value of the given element. 22309 * 22310 * If an object is provided for `callback` the created "_.where" style callback 22311 * will return `true` for elements that have the properties of the given object, 22312 * else `false`. 22313 * 22314 * @static 22315 * @memberOf _ 22316 * @category Arrays 22317 * @param {Array} array The array to query. 22318 * @param {Function|Object|number|string} [callback=1] The function called 22319 * per element or the number of elements to exclude. If a property name or 22320 * object is provided it will be used to create a "_.pluck" or "_.where" 22321 * style callback, respectively. 22322 * @param {*} [thisArg] The `this` binding of `callback`. 22323 * @returns {Array} Returns a slice of `array`. 22324 * @example 22325 * 22326 * _.initial([1, 2, 3]); 22327 * // => [1, 2] 22328 * 22329 * _.initial([1, 2, 3], 2); 22330 * // => [1] 22331 * 22332 * _.initial([1, 2, 3], function(num) { 22333 * return num > 1; 22334 * }); 22335 * // => [1] 22336 * 22337 * var characters = [ 22338 * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, 22339 * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, 22340 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } 22341 * ]; 22342 * 22343 * // using "_.pluck" callback shorthand 22344 * _.initial(characters, 'blocked'); 22345 * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }] 22346 * 22347 * // using "_.where" callback shorthand 22348 * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name'); 22349 * // => ['barney', 'fred'] 22350 */ 22351 function initial(array, callback, thisArg) { 22352 var n = 0, 22353 length = array ? array.length : 0; 22354 22355 if (typeof callback != 'number' && callback != null) { 22356 var index = length; 22357 callback = lodash.createCallback(callback, thisArg, 3); 22358 while (index-- && callback(array[index], index, array)) { 22359 n++; 22360 } 22361 } else { 22362 n = (callback == null || thisArg) ? 1 : callback || n; 22363 } 22364 return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); 22365 } 22366 22367 /** 22368 * Creates an array of unique values present in all provided arrays using 22369 * strict equality for comparisons, i.e. `===`. 22370 * 22371 * @static 22372 * @memberOf _ 22373 * @category Arrays 22374 * @param {...Array} [array] The arrays to inspect. 22375 * @returns {Array} Returns an array of shared values. 22376 * @example 22377 * 22378 * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]); 22379 * // => [1, 2] 22380 */ 22381 function intersection() { 22382 var args = [], 22383 argsIndex = -1, 22384 argsLength = arguments.length, 22385 caches = getArray(), 22386 indexOf = getIndexOf(), 22387 trustIndexOf = indexOf === baseIndexOf, 22388 seen = getArray(); 22389 22390 while (++argsIndex < argsLength) { 22391 var value = arguments[argsIndex]; 22392 if (isArray(value) || isArguments(value)) { 22393 args.push(value); 22394 caches.push(trustIndexOf && value.length >= largeArraySize && 22395 createCache(argsIndex ? args[argsIndex] : seen)); 22396 } 22397 } 22398 var array = args[0], 22399 index = -1, 22400 length = array ? array.length : 0, 22401 result = []; 22402 22403 outer: 22404 while (++index < length) { 22405 var cache = caches[0]; 22406 value = array[index]; 22407 22408 if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) { 22409 argsIndex = argsLength; 22410 (cache || seen).push(value); 22411 while (--argsIndex) { 22412 cache = caches[argsIndex]; 22413 if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) { 22414 continue outer; 22415 } 22416 } 22417 result.push(value); 22418 } 22419 } 22420 while (argsLength--) { 22421 cache = caches[argsLength]; 22422 if (cache) { 22423 releaseObject(cache); 22424 } 22425 } 22426 releaseArray(caches); 22427 releaseArray(seen); 22428 return result; 22429 } 22430 22431 /** 22432 * Gets the last element or last `n` elements of an array. If a callback is 22433 * provided elements at the end of the array are returned as long as the 22434 * callback returns truey. The callback is bound to `thisArg` and invoked 22435 * with three arguments; (value, index, array). 22436 * 22437 * If a property name is provided for `callback` the created "_.pluck" style 22438 * callback will return the property value of the given element. 22439 * 22440 * If an object is provided for `callback` the created "_.where" style callback 22441 * will return `true` for elements that have the properties of the given object, 22442 * else `false`. 22443 * 22444 * @static 22445 * @memberOf _ 22446 * @category Arrays 22447 * @param {Array} array The array to query. 22448 * @param {Function|Object|number|string} [callback] The function called 22449 * per element or the number of elements to return. If a property name or 22450 * object is provided it will be used to create a "_.pluck" or "_.where" 22451 * style callback, respectively. 22452 * @param {*} [thisArg] The `this` binding of `callback`. 22453 * @returns {*}
22453 Returns the last element(s) of `array`. 22454 * @example 22455 * 22456 * _.last([1, 2, 3]); 22457 * // => 3 22458 * 22459 * _.last([1, 2, 3], 2); 22460 * // => [2, 3] 22461 * 22462 * _.last([1, 2, 3], function(num) { 22463 * return num > 1; 22464 * }); 22465 * // => [2, 3] 22466 * 22467 * var characters = [ 22468 * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, 22469 * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, 22470 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } 22471 * ]; 22472 * 22473 * // using "_.pluck" callback shorthand 22474 * _.pluck(_.last(characters, 'blocked'), 'name'); 22475 * // => ['fred', 'pebbles'] 22476 * 22477 * // using "_.where" callback shorthand 22478 * _.last(characters, { 'employer': 'na' }); 22479 * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] 22480 */ 22481 function last(array, callback, thisArg) { 22482 var n = 0, 22483 length = array ? array.length : 0; 22484 22485 if (typeof callback != 'number' && callback != null) { 22486 var index = length; 22487 callback = lodash.createCallback(callback, thisArg, 3); 22488 while (index-- && callback(array[index], index, array)) { 22489 n++; 22490 } 22491 } else { 22492 n = callback; 22493 if (n == null || thisArg) { 22494 return array ? array[length - 1] : undefined; 22495 } 22496 } 22497 return slice(array, nativeMax(0, length - n)); 22498 } 22499 22500 /** 22501 * Gets the index at which the last occurrence of `value` is found using strict 22502 * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used 22503 * as the offset from the end of the collection. 22504 * 22505 * If a property name is provided for `callback` the created "_.pluck" style 22506 * callback will return the property value of the given element. 22507 * 22508 * If an object is provided for `callback` the created "_.where" style callback 22509 * will return `true` for elements that have the properties of the given object, 22510 * else `false`. 22511 * 22512 * @static 22513 * @memberOf _ 22514 * @category Arrays 22515 * @param {Array} array The array to search. 22516 * @param {*} value The value to search for. 22517 * @param {number} [fromIndex=array.length-1] The index to search from. 22518 * @returns {number} Returns the index of the matched value or `-1`. 22519 * @example 22520 * 22521 * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); 22522 * // => 4 22523 * 22524 * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); 22525 * // => 1 22526 */ 22527 function lastIndexOf(array, value, fromIndex) { 22528 var index = array ? array.length : 0; 22529 if (typeof fromIndex == 'number') { 22530 index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; 22531 } 22532 while (index--) { 22533 if (array[index] === value) { 22534 return index; 22535 } 22536 } 22537 return -1; 22538 } 22539 22540 /** 22541 * Removes all provided values from the given array using strict equality for 22542 * comparisons, i.e. `===`. 22543 * 22544 * @static 22545 * @memberOf _ 22546 * @category Arrays 22547 * @param {Array} array The array to modify. 22548 * @param {...*} [value] The values to remove. 22549 * @returns {Array} Returns `array`. 22550 * @example 22551 * 22552 * var array = [1, 2, 3, 1, 2, 3]; 22553 * _.pull(array, 2, 3); 22554 * console.log(array); 22555 * // => [1, 1] 22556 */ 22557 function pull(array) { 22558 var args = arguments, 22559 argsIndex = 0, 22560 argsLength = args.length, 22561 length = array ? array.length : 0; 22562 22563 while (++argsIndex < argsLength) { 22564 var index = -1, 22565 value = args[argsIndex]; 22566 while (++index < length) { 22567 if (array[index] === value) { 22568 splice.call(array, index--, 1); 22569 length--; 22570 } 22571 } 22572 } 22573 return array; 22574 } 22575 22576 /** 22577 * Creates an array of numbers (positive and/or negative) progressing from 22578 * `start` up to but not including `end`. If `start` is less than `stop` a 22579 * zero-length range is created unless a negative `step` is specified. 22580 * 22581 * @static 22582 * @memberOf _ 22583 * @category Arrays 22584 * @param {number} [start=0] The start of the range. 22585 * @param {number} end The end of the range. 22586 * @param {number} [step=1] The value to increment or decrement by. 22587 * @returns {Array} Returns a new range array. 22588 * @example 22589 * 22590 * _.range(4); 22591 * // => [0, 1, 2, 3] 22592 * 22593 * _.range(1, 5); 22594 * // => [1, 2, 3, 4] 22595 * 22596 * _.range(0, 20, 5); 22597 * // => [0, 5, 10, 15] 22598 * 22599 * _.range(0, -4, -1); 22600 * // => [0, -1, -2, -3] 22601 * 22602 * _.range(1, 4, 0); 22603 * // => [1, 1, 1] 22604 * 22605 * _.range(0); 22606 * // => [] 22607 */ 22608 function range(start, end, step) { 22609 start = +start || 0; 22610 step = typeof step == 'number' ? step : (+step || 1); 22611 22612 if (end == null) { 22613 end = start; 22614 start = 0; 22615 } 22616 // use `Array(length)` so engines like Chakra and V8 avoid slower modes 22617 // http://youtu.be/XAqIpGU8ZZk#t=17m25s 22618 var index = -1, 22619 length = nativeMax(0, ceil((end - start) / (step || 1))), 22620 result = Array(length); 22621 22622 while (++index < length) { 22623 result[index] = start; 22624 start += step; 22625 } 22626 return result; 22627 } 22628 22629 /** 22630 * Removes all elements from an array that the callback returns truey for 22631 * and returns an array of removed elements. The callback is bound to `thisArg` 22632 * and invoked with three arguments; (value, index, array). 22633 * 22634 * If a property name is provided for `callback` the created "_.pluck" style 22635 * callback will return the property value of the given element. 22636 * 22637 * If an object is provided for `callback` the created "_.where" style callback 22638 * will return `true` for elements that have the properties of the given object, 22639 * else `false`. 22640 * 22641 * @static 22642 * @memberOf _ 22643 * @category Arrays 22644 * @param {Array} array The array to modify. 22645 * @param {Function|Object|string} [callback=identity] The function called 22646 * per iteration. If a property name or object is provided it will be used 22647 * to create a "_.pluck" or "_.where" style callback, respectively. 22648 * @param {*} [thisArg] The `this` binding of `callback`. 22649 * @returns {Array} Returns a new array of removed elements. 22650 * @example 22651 * 22652 * var array = [1, 2, 3, 4, 5, 6]; 22653 * var evens = _.remove(array, function(num) { return num % 2 == 0; }); 22654 * 22655 * console.log(array); 22656 * // => [1, 3, 5] 22657 * 22658 * console.log(evens); 22659 * // => [2, 4, 6] 22660 */ 22661 function remove(array, callback, thisArg) { 22662 var index = -1, 22663 length = array ? array.length : 0, 22664 result = []; 22665 22666 callback = lodash.createCallback(callback, thisArg, 3); 22667 while (++index < length) { 22668 var value = array[index]; 22669 if (callback(value, index, array)) { 22670 result.push(value); 22671 splice.call(array, index--, 1); 22672 length--; 22673 } 22674 } 22675 return result; 22676 } 22677 22678 /** 22679 * The opposite of `_.initial` this method gets all but the first element or 22680 * first `n` elements of an array. If a callback function is provided elements 22681 * at the beginning of the array are excluded from the result as long as the 22682 * callback returns truey. The callback is bound to `thisArg` and invoked 22683 * with three arguments; (value, index, array). 22684 * 22685 * If a property name is provided for `callback` the created "_.pluck" style 22686 * callback will return the property value of the given element. 22687 * 22688 * If an object is provided for `callback` the created "_.where" style callback 22689 * will return `true` for elements that have the properties of the given object, 22690 * else `false`. 22691 * 22692 * @static 22693 * @memberOf _ 22694 * @alias drop, tail 22695 * @category Arrays 22696 * @param {Array} array The array to query. 22697 * @param {Function|Object|number|string} [callback=1] The function called 22698 * per element or the number of elements to exclude. If a property name or 22699 * object is provided it will be used to create a "_.pluck" or "_.where" 22700 * style callback, respectively. 22701 * @param {*} [thisArg] The `this` binding of `callback`. 22702 * @returns {Array} Returns a slice of `array`. 22703 * @example 22704 * 22705 * _.rest([1, 2, 3]); 22706 * // => [2, 3] 22707 * 22708 * _.rest([1, 2, 3], 2); 22709 * // => [3] 22710 * 22711 * _.rest([1, 2, 3], function(num) { 22712 * return num < 3; 22713 * }); 22714 * // => [3] 22715 * 22716 * var characters = [ 22717 * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, 22718 * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, 22719 * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } 22720 * ]; 22721 * 22722 * // using "_.pluck" callback shorthand 22723 * _.pluck(_.rest(characters, 'blocked'), 'name'); 22724 * // => ['fred', 'pebbles'] 22725 * 22726 * // using "_.where" callback shorthand 22727 * _.rest(characters, { 'employer': 'slate' }); 22728 * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] 22729 */ 22730 function rest(array, callback, thisArg) { 22731 if (typeof callback != 'number' && callback != null) { 22732 var n = 0, 22733 index = -1, 22734 length = array ? array.length : 0; 22735 22736 callback = lodash.createCallback(callback, thisArg, 3); 22737 while (++index < length && callback(array[index], index, array)) { 22738 n++; 22739 } 22740 } else {
22741 n = (callback == null || thisArg) ? 1 : nativeMax(0, callback); 22742 } 22743 return slice(array, n); 22744 } 22745 22746 /** 22747 * Uses a binary search to determine the smallest index at which a value 22748 * should be inserted into a given sorted array in order to maintain the sort 22749 * order of the array. If a callback is provided it will be executed for 22750 * `value` and each element of `array` to compute their sort ranking. The 22751 * callback is bound to `thisArg` and invoked with one argument; (value). 22752 * 22753 * If a property name is provided for `callback` the created "_.pluck" style 22754 * callback will return the property value of the given element. 22755 * 22756 * If an object is provided for `callback` the created "_.where" style callback 22757 * will return `true` for elements that have the properties of the given object, 22758 * else `false`. 22759 * 22760 * @static 22761 * @memberOf _ 22762 * @category Arrays 22763 * @param {Array} array The array to inspect. 22764 * @param {*} value The value to evaluate. 22765 * @param {Function|Object|string} [callback=identity] The function called 22766 * per iteration. If a property name or object is provided it will be used 22767 * to create a "_.pluck" or "_.where" style callback, respectively. 22768 * @param {*} [thisArg] The `this` binding of `callback`. 22769 * @returns {number} Returns the index at which `value` should be inserted 22770 * into `array`. 22771 * @example 22772 * 22773 * _.sortedIndex([20, 30, 50], 40); 22774 * // => 2 22775 * 22776 * // using "_.pluck" callback shorthand 22777 * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); 22778 * // => 2 22779 * 22780 * var dict = { 22781 * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } 22782 * }; 22783 * 22784 * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { 22785 * return dict.wordToNumber[word]; 22786 * }); 22787 * // => 2 22788 * 22789 * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { 22790 * return this.wordToNumber[word]; 22791 * }, dict); 22792 * // => 2 22793 */ 22794 function sortedIndex(array, value, callback, thisArg) { 22795 var low = 0, 22796 high = array ? array.length : low; 22797 22798 // explicitly reference `identity` for better inlining in Firefox 22799 callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity; 22800 value = callback(value); 22801 22802 while (low < high) { 22803 var mid = (low + high) >>> 1; 22804 (callback(array[mid]) < value) 22805 ? low = mid + 1 22806 : high = mid; 22807 } 22808 return low; 22809 } 22810 22811 /** 22812 * Creates an array of unique values, in order, of the provided arrays using 22813 * strict equality for comparisons, i.e. `===`. 22814 * 22815 * @static 22816 * @memberOf _ 22817 * @category Arrays 22818 * @param {...Array} [array] The arrays to inspect. 22819 * @returns {Array} Returns an array of combined values. 22820 * @example 22821 * 22822 * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]); 22823 * // => [1, 2, 3, 5, 4] 22824 */ 22825 function union() { 22826 return baseUniq(baseFlatten(arguments, true, true)); 22827 } 22828 22829 /** 22830 * Creates a duplicate-value-free version of an array using strict equality 22831 * for comparisons, i.e. `===`. If the array is sorted, providing 22832 * `true` for `isSorted` will use a faster algorithm. If a callback is provided 22833 * each element of `array` is passed through the callback before uniqueness 22834 * is computed. The callback is bound to `thisArg` and invoked with three 22835 * arguments; (value, index, array). 22836 * 22837 * If a property name is provided for `callback` the created "_.pluck" style 22838 * callback will return the property value of the given element. 22839 * 22840 * If an object is provided for `callback` the created "_.where" style callback 22841 * will return `true` for elements that have the properties of the given object, 22842 * else `false`. 22843 * 22844 * @static 22845 * @memberOf _ 22846 * @alias unique 22847 * @category Arrays 22848 * @param {Array} array The array to process. 22849 * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted. 22850 * @param {Function|Object|string} [callback=identity] The function called 22851 * per iteration. If a property name or object is provided it will be used 22852 * to create a "_.pluck" or "_.where" style callback, respectively. 22853 * @param {*} [thisArg] The `this` binding of `callback`. 22854 * @returns {Array} Returns a duplicate-value-free array. 22855 * @example 22856 * 22857 * _.uniq([1, 2, 1, 3, 1]); 22858 * // => [1, 2, 3] 22859 * 22860 * _.uniq([1, 1, 2, 2, 3], true); 22861 * // => [1, 2, 3] 22862 * 22863 * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); }); 22864 * // => ['A', 'b', 'C'] 22865 * 22866 * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math); 22867 * // => [1, 2.5, 3] 22868 * 22869 * // using "_.pluck" callback shorthand 22870 * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); 22871 * // => [{ 'x': 1 }, { 'x': 2 }] 22872 */ 22873 function uniq(array, isSorted, callback, thisArg) { 22874 // juggle arguments 22875 if (typeof isSorted != 'boolean' && isSorted != null) { 22876 thisArg = callback; 22877 callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted; 22878 isSorted = false;
22879 } 22880 if (callback != null) { 22881 callback = lodash.createCallback(callback, thisArg, 3); 22882 } 22883 return baseUniq(array, isSorted, callback); 22884 } 22885 22886 /** 22887 * Creates an array excluding all provided values using strict equality for 22888 * comparisons, i.e. `===`. 22889 * 22890 * @static 22891 * @memberOf _ 22892 * @category Arrays 22893 * @param {Array} array The array to filter. 22894 * @param {...*} [value] The values to exclude. 22895 * @returns {Array} Returns a new array of filtered values. 22896 * @example 22897 * 22898 * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); 22899 * // => [2, 3, 4] 22900 */ 22901 function without(array) { 22902 return baseDifference(array, slice(arguments, 1)); 22903 } 22904 22905 /** 22906 * Creates an array that is the symmetric difference of the provided arrays. 22907 * See http://en.wikipedia.org/wiki/Symmetric_difference. 22908 * 22909 * @static 22910 * @memberOf _ 22911 * @category Arrays 22912 * @param {...Array} [array] The arrays to inspect. 22913 * @returns {Array} Returns an array of values. 22914 * @example 22915 * 22916 * _.xor([1, 2, 3], [5, 2, 1, 4]); 22917 * // => [3, 5, 4] 22918 * 22919 * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); 22920 * // => [1, 4, 5] 22921 */ 22922 function xor() { 22923 var index = -1, 22924 length = arguments.length; 22925 22926 while (++index < length) { 22927 var array = arguments[index]; 22928 if (isArray(array) || isArguments(array)) { 22929 var result = result 22930 ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result))) 22931 : array; 22932 } 22933 } 22934 return result || []; 22935 } 22936 22937 /** 22938 * Creates an array of grouped elements, the first of which contains the first 22939 * elements of the given arrays, the second of which contains the second 22940 * elements of the given arrays, and so on. 22941 * 22942 * @static 22943 * @memberOf _ 22944 * @alias unzip 22945 * @category Arrays 22946 * @param {...Array} [array] Arrays to process. 22947 * @returns {Array} Returns a new array of grouped elements. 22948 * @example 22949 * 22950 * _.zip(['fred', 'barney'], [30, 40], [true, false]); 22951 * // => [['fred', 30, true], ['barney', 40, false]] 22952 */ 22953 function zip() { 22954 var array = arguments.length > 1 ? arguments : arguments[0], 22955 index = -1, 22956 length = array ? max(pluck(array, 'length')) : 0, 22957 result = Array(length < 0 ? 0 : length); 22958 22959 while (++index < length) { 22960 result[index] = pluck(array, index); 22961 } 22962 return result; 22963 } 22964 22965 /**
22966 * Creates an object composed from arrays of `keys` and `values`. Provide 22967 * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]` 22968 * or two arrays, one of `keys` and one of corresponding `values`. 22969 * 22970 * @static 22971 * @memberOf _ 22972 * @alias object 22973 * @category Arrays 22974 * @param {Array} keys The array of keys. 22975 * @param {Array} [values=[]] The array of values. 22976 * @returns {Object} Returns an object composed of the given keys and 22977 * corresponding values. 22978 * @example 22979 * 22980 * _.zipObject(['fred', 'barney'], [30, 40]); 22981 * // => { 'fred': 30, 'barney': 40 } 22982 */ 22983 function zipObject(keys, values) { 22984 var index = -1, 22985 length = keys ? keys.length : 0, 22986 result = {}; 22987 22988 if (!values && length && !isArray(keys[0])) { 22989 values = []; 22990 } 22991 while (++index < length) { 22992 var key = keys[index]; 22993 if (values) { 22994 result[key] = values[index]; 22995 } else if (key) { 22996 result[key[0]] = key[1]; 22997 } 22998 } 22999 return result; 23000 } 23001 23002 /*--------------------------------------------------------------------------*/ 23003 23004 /** 23005 * Creates a function that executes `func`, with the `this` binding and 23006 * arguments of the created function, only after being called `n` times. 23007 * 23008 * @static 23009 * @memberOf _ 23010 * @category Functions 23011 * @param {number} n The number of times the function must be called before 23012 * `func` is executed. 23013 * @param {Function} func The function to restrict. 23014 * @returns {Function} Returns the new restricted function. 23015 * @example 23016 * 23017 * var saves = ['profile', 'settings']; 23018 * 23019 * var done = _.after(saves.length, function() { 23020 * console.log('Done saving!'); 23021 * }); 23022 * 23023 * _.forEach(saves, function(type) { 23024 * asyncSave({ 'type': type, 'complete': done }); 23025 * }); 23026 * // => logs 'Done saving!', after all saves have completed 23027 */ 23028 function after(n, func) { 23029 if (!isFunction(func)) { 23030 throw new TypeError; 23031 } 23032 return function() { 23033 if (--n < 1) { 23034 return func.apply(this, arguments); 23035 } 23036 }; 23037 } 23038 23039 /** 23040 * Creates a function that, when called, invokes `func` with the `this` 23041 * binding of `thisArg` and prepends any additional `bind` arguments to those 23042 * provided to the bound function. 23043 * 23044 * @static 23045 * @memberOf _ 23046 * @category Functions 23047 * @param {Function} func The function to bind. 23048 * @param {*} [thisArg] The `this` binding of `func`. 23049 * @param {...*} [arg] Arguments to be partially applied. 23050 * @returns {Function} Returns the new bound function. 23051 * @example 23052 * 23053 * var func = function(greeting) { 23054 * return greeting + ' ' + this.name; 23055 * }; 23056 * 23057 * func = _.bind(func, { 'name': 'fred' }, 'hi'); 23058 * func(); 23059 * // => 'hi fred' 23060 */ 23061 function bind(func, thisArg) { 23062 return arguments.length > 2 23063 ? createWrapper(func, 17, slice(arguments, 2), null, thisArg) 23064 : createWrapper(func, 1, null, null, thisArg); 23065 } 23066 23067 /** 23068 * Binds methods of an object to the object itself, overwriting the existing 23069 * method. Method names may be specified as individual arguments or as arrays 23070 * of method names. If no method names are provided all the function properties 23071 * of `object` will be bound. 23072 * 23073 * @static 23074 * @memberOf _ 23075 * @category Functions 23076 * @param {Object} object The object to bind and assign the bound methods to. 23077 * @param {...string} [methodName] The object method names to 23078 * bind, specified as individual method names or arrays of method names. 23079 * @returns {Object} Returns `object`. 23080 * @example 23081 * 23082 * var view = { 23083 * 'label': 'docs', 23084 * 'onClick': function() { console.log('clicked ' + this.label); } 23085 * }; 23086 * 23087 * _.bindAll(view); 23088 * jQuery('#docs').on('click', view.onClick); 23089 * // => logs 'clicked docs', when the button is clicked 23090 */ 23091 function bindAll(object) { 23092 var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object), 23093 index = -1, 23094 length = funcs.length; 23095 23096 while (++index < length) { 23097 var key = funcs[index]; 23098 object[key] = createWrapper(object[key], 1, null, null, object); 23099 } 23100 return object; 23101 } 23102 23103 /** 23104 * Creates a function that, when called, invokes the method at `object[key]` 23105 * and prepends any additional `bindKey` arguments to those provided to the bound 23106 * function. This method differs from `_.bind` by allowing bound functions to 23107 * reference methods that will be redefined or don't yet exist. 23108 * See http://michaux.ca/articles/lazy-function-definition-pattern. 23109 * 23110 * @static 23111 * @memberOf _ 23112 * @category Functions 23113 * @param {Object} object The object the method belongs to. 23114 * @param {string} key The key of the method. 23115 * @param {...*} [arg] Arguments to be partially applied. 23116 * @returns {Function} Returns the new bound function. 23117 * @example 23118 * 23119 * var object = { 23120 * 'name': 'fred', 23121 * 'greet': function(greeting) { 23122 * return greeting + ' ' + this.name; 23123 * } 23124 * }; 23125 * 23126 * var func = _.bindKey(object, 'greet', 'hi'); 23127 * func(); 23128 * // => 'hi fred' 23129 * 23130 * object.greet = function(greeting) { 23131 * return greeting + 'ya ' + this.name + '!'; 23132 * }; 23133 * 23134 * func(); 23135 * // => 'hiya fred!' 23136 */ 23137 function bindKey(object, key) { 23138 return arguments.length > 2 23139 ? createWrapper(key, 19, slice(arguments, 2), null, object) 23140 : createWrapper(key, 3, null, null, object); 23141 } 23142 23143 /** 23144 * Creates a function that is the composition of the provided functions, 23145 * where each function consumes the return value of the function that follows. 23146 * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. 23147 * Each function is executed with the `this` binding of the composed function. 23148 * 23149 * @static 23150 * @memberOf _ 23151 * @category Functions 23152 * @param {...Function} [func] Functions to compose. 23153 * @returns {Function} Returns the new composed function. 23154 * @example 23155 * 23156 * var realNameMap = { 23157 * 'pebbles': 'penelope' 23158 * }; 23159 * 23160 * var format = function(name) { 23161 * name = realNameMap[name.toLowerCase()] || name; 23162 * return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase(); 23163 * }; 23164 * 23165 * var greet = function(formatted) { 23166 * return 'Hiya ' + formatted + '!'; 23167 * }; 23168 * 23169 * var welcome = _.compose(greet, format); 23170 * welcome('pebbles'); 23171 * // => 'Hiya Penelope!' 23172 */ 23173 function compose() { 23174 var funcs = arguments, 23175 length = funcs.length; 23176 23177 while (length--) { 23178 if (!isFunction(funcs[length])) { 23179 throw new TypeError; 23180 } 23181 } 23182 return function() { 23183 var args = arguments, 23184 length = funcs.length; 23185 23186 while (length--) { 23187 args = [funcs[length].apply(this, args)]; 23188 } 23189 return args[0]; 23190 }; 23191 } 23192 23193 /** 23194 * Creates a function which accepts one or more arguments of `func` that when 23195 * invoked either executes `func` returning its result, if all `func` arguments 23196 * have been provided, or returns a function that accepts one or more of the 23197 * remaining `func` arguments, and so on. The arity of `func` can be specified 23198 * if `func.length` is not sufficient. 23199 * 23200 * @static 23201 * @memberOf _ 23202 * @category Functions 23203 * @param {Function} func The function to curry. 23204 * @param {number} [arity=func.length] The arity of `func`. 23205 * @returns {Function} Returns the new curried function. 23206 * @example 23207 * 23208 * var curried = _.curry(function(a, b, c) { 23209 * console.log(a + b + c); 23210 * }); 23211 * 23212 * curried(1)(2)(3); 23213 * // => 6 23214 * 23215 * curried(1, 2)(3); 23216 * // => 6 23217 * 23218 * curried(1, 2, 3); 23219 * // => 6 23220 */ 23221 function curry(func, arity) { 23222 arity = typeof arity == 'number' ? arity : (+arity || func.length); 23223 return createWrapper(func, 4, null, null, null, arity); 23224 } 23225 23226 /** 23227 * Creates a function that will delay the execution of `func` until after 23228 * `wait` milliseconds have elapsed since the last time it was invoked. 23229 * Provide an options object to indicate that `func` should be invoked on 23230 * the leading and/or trailing edge of the `wait` timeout. Subsequent calls 23231 * to the debounced function will return the result of the last `func` call. 23232 * 23233 * Note: If `leading` and `trailing` options are `true` `func` will be called 23234 * on the trailing edge of the timeout only if the the debounced function is 23235 * invoked more than once during the `wait` timeout. 23236 * 23237 * @static 23238 * @memberOf _ 23239 * @category Functions 23240 * @param {Function} func The function to debounce. 23241 * @param {number} wait The number of milliseconds to delay. 23242 * @param {Object} [options] The options object. 23243 * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout. 23244 * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called. 23245 * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout. 23246 * @returns {Function} Returns the new debounced function. 23247 * @example 23248 * 23249 * // avoid costly calculations while the window size is in flux 23250 * var lazyLayout = _.debounce(calculateLayout, 150); 23251 * jQuery(window).on('resize', lazyLayout); 23252 * 23253 * // execute `sendMail` when the click event is fired, debouncing subsequent calls 23254 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { 23255 * 'leading': true, 23256 * 'trailing': false 23257 * }); 23258 * 23259 * // ensure `batchLog` is executed once after 1 second of debounced calls 23260 * var source = new EventSource('/stream'); 23261 * source.addEventListener('message', _.debounce(batchLog, 250, { 23262 * 'maxWait': 1000 23263 * }, false); 23264 */ 23265 function debounce(func, wait, options) { 23266 var args, 23267 maxTimeoutId, 23268 result, 23269 stamp, 23270 thisArg, 23271 timeoutId, 23272 trailingCall, 23273 lastCalled = 0, 23274 maxWait = false, 23275 trailing = true; 23276 23277 if (!isFunction(func)) { 23278 throw new TypeError; 23279 } 23280 wait = nativeMax(0, wait) || 0; 23281 if (options === true) { 23282 var leading = true; 23283 trailing = false;
23284 } else if (isObject(options)) { 23285 leading = options.leading; 23286 maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0); 23287 trailing = 'trailing' in options ? options.trailing : trailing; 23288 } 23289 var delayed = function() { 23290 var remaining = wait - (now() - stamp); 23291 if (remaining <= 0) { 23292 if (maxTimeoutId) { 23293 clearTimeout(maxTimeoutId); 23294 } 23295 var isCalled = trailingCall; 23296 maxTimeoutId = timeoutId = trailingCall = undefined; 23297 if (isCalled) { 23298 lastCalled = now(); 23299 result = func.apply(thisArg, args); 23300 if (!timeoutId && !maxTimeoutId) { 23301 args = thisArg = null; 23302 } 23303 } 23304 } else { 23305 timeoutId = setTimeout(delayed, remaining); 23306 } 23307 }; 23308 23309 var maxDelayed = function() { 23310 if (timeoutId) { 23311 clearTimeout(timeoutId); 23312 } 23313 maxTimeoutId = timeoutId = trailingCall = undefined; 23314 if (trailing || (maxWait !== wait)) { 23315 lastCalled = now(); 23316 result = func.apply(thisArg, args); 23317 if (!timeoutId && !maxTimeoutId) { 23318 args = thisArg = null; 23319 } 23320 } 23321 }; 23322 23323 return function() { 23324 args = arguments; 23325 stamp = now(); 23326 thisArg = this; 23327 trailingCall = trailing && (timeoutId || !leading); 23328 23329 if (maxWait === false) { 23330 var leadingCall = leading && !timeoutId; 23331 } else { 23332 if (!maxTimeoutId && !leading) { 23333 lastCalled = stamp; 23334 } 23335 var remaining = maxWait - (stamp - lastCalled), 23336 isCalled = remaining <= 0; 23337 23338 if (isCalled) { 23339 if (maxTimeoutId) { 23340 maxTimeoutId = clearTimeout(maxTimeoutId); 23341 } 23342 lastCalled = stamp; 23343 result = func.apply(thisArg, args); 23344 } 23345 else if (!maxTimeoutId) { 23346 maxTimeoutId = setTimeout(maxDelayed, remaining); 23347 } 23348 } 23349 if (isCalled && timeoutId) { 23350 timeoutId = clearTimeout(timeoutId); 23351 } 23352 else if (!timeoutId && wait !== maxWait) { 23353 timeoutId = setTimeout(delayed, wait); 23354 } 23355 if (leadingCall) { 23356 isCalled = true; 23357 result = func.apply(thisArg, args); 23358 } 23359 if (isCalled && !timeoutId && !maxTimeoutId) { 23360 args = thisArg = null; 23361 } 23362 return result; 23363 }; 23364 } 23365 23366 /** 23367 * Defers executing the `func` function until the current call stack has cleared. 23368 * Additional arguments will be provided to `func` when it is invoked. 23369 * 23370 * @static 23371 * @memberOf _ 23372 * @category Functions 23373 * @param {Function} func The function to defer. 23374 * @param {...*} [arg] Arguments to invoke the function with. 23375 * @returns {number} Returns the timer id. 23376 * @example 23377 * 23378 * _.defer(function(text) { console.log(text); }, 'deferred'); 23379 * // logs 'deferred' after one or more milliseconds 23380 */ 23381 function defer(func) { 23382 if (!isFunction(func)) { 23383 throw new TypeError; 23384 } 23385 var args = slice(arguments, 1); 23386 return setTimeout(function() { func.apply(undefined, args); }, 1); 23387 } 23388 23389 /** 23390 * Executes the `func` function after `wait` milliseconds. Additional arguments 23391 * will be provided to `func` when it is invoked. 23392 * 23393 * @static 23394 * @memberOf _ 23395 * @category Functions 23396 * @param {Function} func The function to delay. 23397 * @param {number} wait The number of milliseconds to delay execution. 23398 * @param {...*} [arg] Arguments to invoke the function with. 23399 * @returns {number} Returns the timer id. 23400 * @example 23401 * 23402 * _.delay(function(text) { console.log(text); }, 1000, 'later'); 23403 * // => logs 'later' after one second 23404 */ 23405 function delay(func, wait) { 23406 if (!isFunction(func)) { 23407 throw new TypeError; 23408 } 23409 var args = slice(arguments, 2); 23410 return setTimeout(function() { func.apply(undefined, args); }, wait); 23411 } 23412 23413 /** 23414 * Creates a function that memoizes the result of `func`. If `resolver` is 23415 * provided it will be used to determine the cache key for storing the result 23416 * based on the arguments provided to the memoized function. By default, the 23417 * first argument provided to the memoized function is used as the cache key. 23418 * The `func` is executed with the `this` binding of the memoized function. 23419 * The result cache is exposed as the `cache` property on the memoized function. 23420 * 23421 * @static 23422 * @memberOf _ 23423 * @category Functions 23424 * @param {Function} func The function to have its output memoized. 23425 * @param {Function} [resolver] A function used to resolve the cache key. 23426 * @returns {Function} Returns the new memoizing function. 23427 * @example 23428 * 23429 * var fibonacci = _.memoize(function(n) { 23430 * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); 23431 * }); 23432 * 23433 * fibonacci(9) 23434 * // => 34 23435 * 23436 * var data = {
23437 * 'fred': { 'name': 'fred', 'age': 40 }, 23438 * 'pebbles': { 'name': 'pebbles', 'age': 1 } 23439 * }; 23440 * 23441 * // modifying the result cache 23442 * var get = _.memoize(function(name) { return data[name]; }, _.identity); 23443 * get('pebbles'); 23444 * // => { 'name': 'pebbles', 'age': 1 } 23445 * 23446 * get.cache.pebbles.name = 'penelope'; 23447 * get('pebbles'); 23448 * // => { 'name': 'penelope', 'age': 1 } 23449 */ 23450 function memoize(func, resolver) { 23451 if (!isFunction(func)) { 23452 throw new TypeError; 23453 } 23454 var memoized = function() { 23455 var cache = memoized.cache, 23456 key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0]; 23457 23458 return hasOwnProperty.call(cache, key) 23459 ? cache[key] 23460 : (cache[key] = func.apply(this, arguments)); 23461 } 23462 memoized.cache = {}; 23463 return memoized; 23464 } 23465 23466 /** 23467 * Creates a function that is restricted to execute `func` once. Repeat calls to 23468 * the function will return the value of the first call. The `func` is executed 23469 * with the `this` binding of the created function. 23470 * 23471 * @static 23472 * @memberOf _ 23473 * @category Functions 23474 * @param {Function} func The function to restrict. 23475 * @returns {Function} Returns the new restricted function. 23476 * @example 23477 * 23478 * var initialize = _.once(createApplication); 23479 * initialize(); 23480 * initialize(); 23481 * // `initialize` executes `createApplication` once 23482 */ 23483 function once(func) { 23484 var ran, 23485 result; 23486 23487 if (!isFunction(func)) { 23488 throw new TypeError; 23489 } 23490 return function() { 23491 if (ran) { 23492 return result; 23493 } 23494 ran = true; 23495 result = func.apply(this, arguments); 23496 23497 // clear the `func` variable so the function may be garbage collected 23498 func = null; 23499 return result; 23500 }; 23501 } 23502 23503 /** 23504 * Creates a function that, when called, invokes `func` with any additional 23505 * `partial` arguments prepended to those provided to the new function. This 23506 * method is similar to `_.bind` except it does **not** alter the `this` binding. 23507 * 23508 * @static 23509 * @memberOf _ 23510 * @category Functions 23511 * @param {Function} func The function to partially apply arguments to. 23512 * @param {...*} [arg] Arguments to be partially applied. 23513 * @returns {Function} Returns the new partially applied function. 23514 * @example 23515 * 23516 * var greet = function(greeting, name) { return greeting + ' ' + name; }; 23517 * var hi = _.partial(greet, 'hi'); 23518 * hi('fred'); 23519 * // => 'hi fred' 23520 */ 23521 function partial(func) { 23522 return createWrapper(func, 16, slice(arguments, 1)); 23523 } 23524 23525 /** 23526 * This method is like `_.partial` except that `partial` arguments are 23527 * appended to those provided to the new function. 23528 * 23529 * @static 23530 * @memberOf _ 23531 * @category Functions 23532 * @param {Function} func The function to partially apply arguments to. 23533 * @param {...*} [arg] Arguments to be partially applied. 23534 * @returns {Function} Returns the new partially applied function. 23535 * @example 23536 * 23537 * var defaultsDeep = _.partialRight(_.merge, _.defaults); 23538 * 23539 * var options = { 23540 * 'variable': 'data', 23541 * 'imports': { 'jq': $ } 23542 * }; 23543 * 23544 * defaultsDeep(options, _.templateSettings); 23545 * 23546 * options.variable 23547 * // => 'data' 23548 * 23549 * options.imports 23550 * // => { '_': _, 'jq': $ } 23551 */ 23552 function partialRight(func) { 23553 return createWrapper(func, 32, null, slice(arguments, 1)); 23554 } 23555 23556 /** 23557 * Creates a function that, when executed, will only call the `func` function 23558 * at most once per every `wait` milliseconds. Provide an options object to 23559 * indicate that `func` should be invoked on the leading and/or trailing edge 23560 * of the `wait` timeout. Subsequent calls to the throttled function will 23561 * return the result of the last `func` call. 23562 * 23563 * Note: If `leading` and `trailing` options are `true` `func` will be called 23564 * on the trailing edge of the timeout only if the the throttled function is 23565 * invoked more than once during the `wait` timeout. 23566 * 23567 * @static 23568 * @memberOf _ 23569 * @category Functions 23570 * @param {Function} func The function to throttle. 23571 * @param {number} wait The number of milliseconds to throttle executions to. 23572 * @param {Object} [options] The options object. 23573 * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout. 23574 * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout. 23575 * @returns {Function} Returns the new throttled function. 23576 * @example 23577 * 23578 * // avoid excessively updating the position while scrolling 23579 * var throttled = _.throttle(updatePosition, 100); 23580 * jQuery(window).on('scroll', throttled); 23581 * 23582 * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes 23583 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { 23584 * 'trailing': false 23585 * })); 23586 */ 23587 function throttle(func, wait, options) { 23588 var leading = true, 23589 trailing = true; 23590 23591 if (!isFunction(func)) { 23592 throw new TypeError; 23593 } 23594 if (options === false) { 23595 leading = false;
23596 } else if (isObject(options)) { 23597 leading = 'leading' in options ? options.leading : leading; 23598 trailing = 'trailing' in options ? options.trailing : trailing; 23599 } 23600 debounceOptions.leading = leading; 23601 debounceOptions.maxWait = wait; 23602 debounceOptions.trailing = trailing; 23603 23604 return debounce(func, wait, debounceOptions); 23605 } 23606 23607 /** 23608 * Creates a function that provides `value` to the wrapper function as its 23609 * first argument. Additional arguments provided to the function are appended 23610 * to those provided to the wrapper function. The wrapper is executed with 23611 * the `this` binding of the created function. 23612 * 23613 * @static 23614 * @memberOf _ 23615 * @category Functions 23616 * @param {*} value The value to wrap. 23617 * @param {Function} wrapper The wrapper function. 23618 * @returns {Function} Returns the new function. 23619 * @example 23620 * 23621 * var p = _.wrap(_.escape, function(func, text) { 23622 * return '<p>' + func(text) + '</p>'; 23623 * }); 23624 * 23625 * p('Fred, Wilma, & Pebbles'); 23626 * // => '<p>Fred, Wilma, & Pebbles</p>' 23627 */ 23628 function wrap(value, wrapper) { 23629 return createWrapper(wrapper, 16, [value]); 23630 } 23631 23632 /*--------------------------------------------------------------------------*/ 23633 23634 /** 23635 * Creates a function that returns `value`. 23636 * 23637 * @static 23638 * @memberOf _ 23639 * @category Utilities 23640 * @param {*} value The value to return from the new function. 23641 * @returns {Function} Returns the new function. 23642 * @example 23643 * 23644 * var object = { 'name': 'fred' }; 23645 * var getter = _.constant(object); 23646 * getter() === object; 23647 * // => true 23648 */ 23649 function constant(value) { 23650 return function() { 23651 return value; 23652 }; 23653 } 23654 23655 /** 23656 * Produces a callback bound to an optional `thisArg`. If `func` is a property 23657 * name the created callback will return the property value for a given element. 23658 * If `func` is an object the created callback will return `true` for elements 23659 * that contain the equivalent object properties, otherwise it will return `false`. 23660 * 23661 * @static 23662 * @memberOf _ 23663 * @category Utilities 23664 * @param {*} [func=identity] The value to convert to a callback. 23665 * @param {*} [thisArg] The `this` binding of the created callback. 23666 * @param {number} [argCount] The number of arguments the callback accepts. 23667 * @returns {Function} Returns a callback function. 23668 * @example 23669 * 23670 * var characters = [ 23671 * { 'name': 'barney', 'age': 36 }, 23672 * { 'name': 'fred', 'age': 40 } 23673 * ]; 23674 * 23675 * // wrap to create custom callback shorthands 23676 * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) { 23677 * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback); 23678 * return !match ? func(callback, thisArg) : function(object) { 23679 * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3]; 23680 * }; 23681 * }); 23682 * 23683 * _.filter(characters, 'age__gt38'); 23684 * // => [{ 'name': 'fred', 'age': 40 }] 23685 */ 23686 function createCallback(func, thisArg, argCount) { 23687 var type = typeof func; 23688 if (func == null || type == 'function') { 23689 return baseCreateCallback(func, thisArg, argCount); 23690 } 23691 // handle "_.pluck" style callback shorthands 23692 if (type != 'object') { 23693 return property(func); 23694 } 23695 var props = keys(func), 23696 key = props[0], 23697 a = func[key]; 23698 23699 // handle "_.where" style callback shorthands 23700 if (props.length == 1 && a === a && !isObject(a)) { 23701 // fast path the common case of providing an object with a single 23702 // property containing a primitive value 23703 return function(object) { 23704 var b = object[key]; 23705 return a === b && (a !== 0 || (1 / a == 1 / b)); 23706 }; 23707 } 23708 return function(object) { 23709 var length = props.length, 23710 result = false;
23711 23712 while (length--) { 23713 if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { 23714 break; 23715 } 23716 } 23717 return result; 23718 }; 23719 } 23720 23721 /** 23722 * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their 23723 * corresponding HTML entities. 23724 * 23725 * @static 23726 * @memberOf _ 23727 * @category Utilities 23728 * @param {string} string The string to escape. 23729 * @returns {string} Returns the escaped string. 23730 * @example 23731 * 23732 * _.escape('Fred, Wilma, & Pebbles'); 23733 * // => 'Fred, Wilma, & Pebbles' 23734 */ 23735 function escape(string) { 23736 return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar); 23737 } 23738 23739 /** 23740 * This method returns the first argument provided to it. 23741 * 23742 * @static 23743 * @memberOf _ 23744 * @category Utilities 23745 * @param {*} value Any value. 23746 * @returns {*} Returns `value`. 23747 * @example 23748 * 23749 * var object = { 'name': 'fred' }; 23750 * _.identity(object) === object; 23751 * // => true 23752 */ 23753 function identity(value) { 23754 return value; 23755 } 23756 23757 /** 23758 * Adds function properties of a source object to the destination object. 23759 * If `object` is a function methods will be added to its prototype as well. 23760 * 23761 * @static 23762 * @memberOf _ 23763 * @category Utilities 23764 * @param {Function|Object} [object=lodash] object The destination object. 23765 * @param {Object} source The object of functions to add. 23766 * @param {Object} [options] The options object. 23767 * @param {boolean} [options.chain=true] Specify whether the functions added are chainable. 23768 * @example 23769 * 23770 * function capitalize(string) { 23771 * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); 23772 * } 23773 * 23774 * _.mixin({ 'capitalize': capitalize }); 23775 * _.capitalize('fred'); 23776 * // => 'Fred' 23777 * 23778 * _('fred').capitalize().value(); 23779 * // => 'Fred' 23780 * 23781 * _.mixin({ 'capitalize': capitalize }, { 'chain': false }); 23782 * _('fred').capitalize(); 23783 * // => 'Fred' 23784 */ 23785 function mixin(object, source, options) { 23786 var chain = true, 23787 methodNames = source && functions(source); 23788 23789 if (!source || (!options && !methodNames.length)) { 23790 if (options == null) { 23791 options = source; 23792 } 23793 ctor = lodashWrapper; 23794 source = object; 23795 object = lodash; 23796 methodNames = functions(source); 23797 } 23798 if (options === false) { 23799 chain = false; 23800 } else if (isObject(options) && 'chain' in options) { 23801 chain = options.chain; 23802 } 23803 var ctor = object, 23804 isFunc = isFunction(ctor); 23805 23806 forEach(methodNames, function(methodName) { 23807 var func = object[methodName] = source[methodName]; 23808 if (isFunc) { 23809 ctor.prototype[methodName] = function() { 23810 var chainAll = this.__chain__, 23811 value = this.__wrapped__, 23812 args = [value]; 23813 23814 push.apply(args, arguments); 23815 var result = func.apply(object, args); 23816 if (chain || chainAll) { 23817 if (value === result && isObject(result)) { 23818 return this; 23819 } 23820 result = new ctor(result); 23821 result.__chain__ = chainAll; 23822 } 23823 return result; 23824 }; 23825 } 23826 }); 23827 } 23828 23829 /** 23830 * Reverts the '_' variable to its previous value and returns a reference to 23831 * the `lodash` function. 23832 * 23833 * @static 23834 * @memberOf _ 23835 * @category Utilities 23836 * @returns {Function} Returns the `lodash` function. 23837 * @example 23838 * 23839 * var lodash = _.noConflict(); 23840 */ 23841 function noConflict() { 23842 context._ = oldDash; 23843 return this; 23844 } 23845 23846 /** 23847 * A no-operation function. 23848 * 23849 * @static 23850 * @memberOf _ 23851 * @category Utilities 23852 * @example 23853 * 23854 * var object = { 'name': 'fred' }; 23855 * _.noop(object) === undefined; 23856 * // => true 23857 */ 23858 function noop() { 23859 // no operation performed 23860 } 23861 23862 /** 23863 * Gets the number of milliseconds that have elapsed since the Unix epoch 23864 * (1 January 1970 00:00:00 UTC). 23865 * 23866 * @static 23867 * @memberOf _ 23868 * @category Utilities 23869 * @example 23870 * 23871 * var stamp = _.now(); 23872 * _.defer(function() { console.log(_.now() - stamp); }); 23873 * // => logs the number of milliseconds it took for the deferred function to be called 23874 */ 23875 var now = isNative(now = Date.now) && now || function() { 23876 return new Date().getTime(); 23877 }; 23878 23879 /** 23880 * Converts the given value into an integer of the specified radix. 23881 * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the 23882 * `value` is a hexadecimal, in which case a `radix` of `16` is used. 23883 * 23884 * Note: This method avoids differences in native ES3 and ES5 `parseInt` 23885 * implementations. See http://es5.github.io/#E. 23886 * 23887 * @static 23888 * @memberOf _ 23889 * @category Utilities 23890 * @param {string} value The value to parse. 23891 * @param {number} [radix] The radix used to interpret the value to parse. 23892 * @returns {number} Returns the new integer value. 23893 * @example 23894 * 23895 * _.parseInt('08'); 23896 * // => 8 23897 */
23898 var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) { 23899 // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt` 23900 return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0); 23901 }; 23902 23903 /** 23904 * Creates a "_.pluck" style function, which returns the `key` value of a 23905 * given object. 23906 * 23907 * @static 23908 * @memberOf _ 23909 * @category Utilities 23910 * @param {string} key The name of the property to retrieve. 23911 * @returns {Function} Returns the new function. 23912 * @example 23913 * 23914 * var characters = [ 23915 * { 'name': 'fred', 'age': 40 }, 23916 * { 'name': 'barney', 'age': 36 } 23917 * ]; 23918 * 23919 * var getName = _.property('name'); 23920 * 23921 * _.map(characters, getName); 23922 * // => ['barney', 'fred'] 23923 * 23924 * _.sortBy(characters, getName); 23925 * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] 23926 */ 23927 function property(key) { 23928 return function(object) { 23929 return object[key]; 23930 }; 23931 } 23932 23933 /** 23934 * Produces a random number between `min` and `max` (inclusive). If only one 23935 * argument is provided a number between `0` and the given number will be 23936 * returned. If `floating` is truey or either `min` or `max` are floats a 23937 * floating-point number will be returned instead of an integer. 23938 * 23939 * @static 23940 * @memberOf _ 23941 * @category Utilities 23942 * @param {number} [min=0] The minimum possible value. 23943 * @param {number} [max=1] The maximum possible value. 23944 * @param {boolean} [floating=false] Specify returning a floating-point number. 23945 * @returns {number} Returns a random number. 23946 * @example 23947 * 23948 * _.random(0, 5); 23949 * // => an integer between 0 and 5 23950 * 23951 * _.random(5); 23952 * // => also an integer between 0 and 5 23953 * 23954 * _.random(5, true); 23955 * // => a floating-point number between 0 and 5 23956 * 23957 * _.random(1.2, 5.2); 23958 * // => a floating-point number between 1.2 and 5.2 23959 */ 23960 function random(min, max, floating) { 23961 var noMin = min == null, 23962 noMax = max == null; 23963 23964 if (floating == null) { 23965 if (typeof min == 'boolean' && noMax) { 23966 floating = min; 23967 min = 1; 23968 } 23969 else if (!noMax && typeof max == 'boolean') { 23970 floating = max; 23971 noMax = true; 23972 } 23973 } 23974 if (noMin && noMax) { 23975 max = 1; 23976 } 23977 min = +min || 0; 23978 if (noMax) { 23979 max = min; 23980 min = 0; 23981 } else { 23982 max = +max || 0; 23983 } 23984 if (floating || min % 1 || max % 1) { 23985 var rand = nativeRandom(); 23986 return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max); 23987 } 23988 return baseRandom(min, max); 23989 } 23990 23991 /** 23992 * Resolves the value of property `key` on `object`. If `key` is a function 23993 * it will be invoked with the `this` binding of `object` and its result returned, 23994 * else the property value is returned. If `object` is falsey then `undefined` 23995 * is returned. 23996 * 23997 * @static 23998 * @memberOf _ 23999 * @category Utilities 24000 * @param {Object} object The object to inspect. 24001 * @param {string} key The name of the property to resolve. 24002 * @returns {*} Returns the resolved value. 24003 * @example 24004 * 24005 * var object = { 24006 * 'cheese': 'crumpets', 24007 * 'stuff': function() { 24008 * return 'nonsense'; 24009 * } 24010 * }; 24011 * 24012 * _.result(object, 'cheese'); 24013 * // => 'crumpets' 24014 * 24015 * _.result(object, 'stuff'); 24016 * // => 'nonsense' 24017 */ 24018 function result(object, key) { 24019 if (object) { 24020 var value = object[key]; 24021 return isFunction(value) ? object[key]() : value; 24022 } 24023 } 24024 24025 /** 24026 * A micro-templating method that handles arbitrary delimiters, preserves 24027 * whitespace, and correctly escapes quotes within interpolated code. 24028 * 24029 * Note: In the development build, `_.template` utilizes sourceURLs for easier 24030 * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl 24031 * 24032 * For more information on precompiling templates see: 24033 * http://lodash.com/custom-builds 24034 * 24035 * For more information on Chrome extension sandboxes see: 24036 * http://developer.chrome.com/stable/extensions/sandboxingEval.html 24037 * 24038 * @static 24039 * @memberOf _ 24040 * @category Utilities 24041 * @param {string} text The template text. 24042 * @param {Object} data The data object used to populate the text. 24043 * @param {Object} [options] The options object. 24044 * @param {RegExp} [options.escape] The "escape" delimiter. 24045 * @param {RegExp} [options.evaluate] The "evaluate" delimiter. 24046 * @param {Object} [options.imports] An object to import into the template as local variables. 24047 * @param {RegExp} [options.interpolate] The "interpolate" delimiter. 24048 * @param {string} [sourceURL] The sourceURL of the template's compiled source. 24049 * @param {string} [variable] The data object variable name. 24050 * @returns {Function|string} Returns a compiled function when no `data` object 24051 * is given, else it returns the interpolated text. 24052 * @example 24053 * 24054 * // using the "interpolate" delimiter to create a compiled template 24055 * var compiled = _.template('hello <%= name %>'); 24056 * compiled({ 'name': 'fred' }); 24057 * // => 'hello fred' 24058 * 24059 * // using the "escape" delimiter to escape HTML in data property values 24060 * _.template('<b><%- value %></b>', { 'value': '<script>' }); 24061 * // => '<b><script></b>' 24062 * 24063 * // using the "evaluate" delimiter to generate HTML 24064 * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
24065 * _.template(list, { 'people': ['fred', 'barney'] }); 24066 * // => '<li>fred</li><li>barney</li>' 24067 * 24068 * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter 24069 * _.template('hello ${ name }', { 'name': 'pebbles' }); 24070 * // => 'hello pebbles' 24071 * 24072 * // using the internal `print` function in "evaluate" delimiters 24073 * _.template('<% print("hello " + name); %>!', { 'name': 'barney' }); 24074 * // => 'hello barney!' 24075 * 24076 * // using a custom template delimiters 24077 * _.templateSettings = { 24078 * 'interpolate': /{{([\s\S]+?)}}/g 24079 * }; 24080 * 24081 * _.template('hello {{ name }}!', { 'name': 'mustache' }); 24082 * // => 'hello mustache!' 24083 * 24084 * // using the `imports` option to import jQuery 24085 * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>'; 24086 * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } }); 24087 * // => '<li>fred</li><li>barney</li>' 24088 * 24089 * // using the `sourceURL` option to specify a custom sourceURL for the template 24090 * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' }); 24091 * compiled(data); 24092 * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector 24093 * 24094 * // using the `variable` option to ensure a with-statement isn't used in the compiled template 24095 * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' }); 24096 * compiled.source; 24097 * // => function(data) { 24098 * var __t, __p = '', __e = _.escape; 24099 * __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!'; 24100 * return __p; 24101 * } 24102 * 24103 * // using the `source` property to inline compiled templates for meaningful 24104 * // line numbers in error messages and a stack trace 24105 * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ 24106 * var JST = {\ 24107 * "main": ' + _.template(mainText).source + '\ 24108 * };\ 24109 * '); 24110 */ 24111 function template(text, data, options) { 24112 // based on John Resig's `tmpl` implementation 24113 // http://ejohn.org/blog/javascript-micro-templating/ 24114 // and Laura Doktorova's doT.js 24115 // https://github.com/olado/doT 24116 var settings = lodash.templateSettings; 24117 text = String(text || ''); 24118 24119 // avoid missing dependencies when `iteratorTemplate` is not defined 24120 options = defaults({}, options, settings); 24121 24122 var imports = defaults({}, options.imports, settings.imports), 24123 importsKeys = keys(imports), 24124 importsValues = values(imports); 24125 24126 var isEvaluating, 24127 index = 0, 24128 interpolate = options.interpolate || reNoMatch, 24129 source = "__p += '"; 24130 24131 // compile the regexp to match each delimiter 24132 var reDelimiters = RegExp( 24133 (options.escape || reNoMatch).source + '|' + 24134 interpolate.source + '|' + 24135 (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' + 24136 (options.evaluate || reNoMatch).source + '|$' 24137 , 'g'); 24138 24139 text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) { 24140 interpolateValue || (interpolateValue = esTemplateValue); 24141 24142 // escape characters that cannot be included in string literals 24143 source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar); 24144 24145 // replace delimiters with snippets 24146 if (escapeValue) { 24147 source += "' +\n__e(" + escapeValue + ") +\n'"; 24148 } 24149 if (evaluateValue) { 24150 isEvaluating = true; 24151 source += "';\n" + evaluateValue + ";\n__p += '"; 24152 } 24153 if (interpolateValue) { 24154 source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'"; 24155 } 24156 index = offset + match.length; 24157 24158 // the JS engine embedded in Adobe products requires returning the `match` 24159 // string in order to produce the correct `offset` value 24160 return match; 24161 }); 24162 24163 source += "';\n"; 24164 24165 // if `variable` is not specified, wrap a with-statement around the generated 24166 // code to add the data object to the top of the scope chain 24167 var variable = options.variable, 24168 hasVariable = variable; 24169 24170 if (!hasVariable) { 24171 variable = 'obj'; 24172 source = 'with (' + variable + ') {\n' + source + '\n}\n'; 24173 } 24174 // cleanup code by stripping empty strings 24175 source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) 24176 .replace(reEmptyStringMiddle, '$1') 24177 .replace(reEmptyStringTrailing, '$1;'); 24178 24179 // frame code as the function body
24180 source = 'function(' + variable + ') {\n' + 24181 (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') + 24182 "var __t, __p = '', __e = _.escape" + 24183 (isEvaluating 24184 ? ', __j = Array.prototype.join;\n' + 24185 "function print() { __p += __j.call(arguments, '') }\n" 24186 : ';\n' 24187 ) + 24188 source + 24189 'return __p\n}'; 24190 24191 // Use a sourceURL for easier debugging. 24192 // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl 24193 var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/'; 24194 24195 try { 24196 var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues); 24197 } catch(e) { 24198 e.source = source; 24199 throw e; 24200 } 24201 if (data) { 24202 return result(data); 24203 } 24204 // provide the compiled function's source by its `toString` method, in 24205 // supported environments, or the `source` property as a convenience for 24206 // inlining compiled templates during the build process 24207 result.source = source; 24208 return result; 24209 } 24210 24211 /** 24212 * Executes the callback `n` times, returning an array of the results 24213 * of each callback execution. The callback is bound to `thisArg` and invoked 24214 * with one argument; (index). 24215 * 24216 * @static 24217 * @memberOf _ 24218 * @category Utilities 24219 * @param {number} n The number of times to execute the callback. 24220 * @param {Function} callback The function called per iteration. 24221 * @param {*} [thisArg] The `this` binding of `callback`. 24222 * @returns {Array} Returns an array of the results of each `callback` execution. 24223 * @example 24224 * 24225 * var diceRolls = _.times(3, _.partial(_.random, 1, 6)); 24226 * // => [3, 6, 4] 24227 * 24228 * _.times(3, function(n) { mage.castSpell(n); }); 24229 * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively 24230 * 24231 * _.times(3, function(n) { this.cast(n); }, mage); 24232 * // => also calls `mage.castSpell(n)` three times 24233 */ 24234 function times(n, callback, thisArg) { 24235 n = (n = +n) > -1 ? n : 0; 24236 var index = -1, 24237 result = Array(n); 24238 24239 callback = baseCreateCallback(callback, thisArg, 1); 24240 while (++index < n) { 24241 result[index] = callback(index); 24242 } 24243 return result; 24244 } 24245 24246 /** 24247 * The inverse of `_.escape` this method converts the HTML entities 24248 * `&`, `<`, `>`, `"`, and `'` in `string` to their 24249 * corresponding characters. 24250 * 24251 * @static 24252 * @memberOf _ 24253 * @category Utilities 24254 * @param {string} string The string to unescape. 24255 * @returns {string} Returns the unescaped string. 24256 * @example 24257 * 24258 * _.unescape('Fred, Barney & Pebbles'); 24259 * // => 'Fred, Barney & Pebbles' 24260 */ 24261 function unescape(string) { 24262 return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar); 24263 } 24264 24265 /** 24266 * Generates a unique ID. If `prefix` is provided the ID will be appended to it. 24267 * 24268 * @static 24269 * @memberOf _ 24270 * @category Utilities 24271 * @param {string} [prefix] The value to prefix the ID with. 24272 * @returns {string} Returns the unique ID. 24273 * @example 24274 * 24275 * _.uniqueId('contact_'); 24276 * // => 'contact_104' 24277 * 24278 * _.uniqueId(); 24279 * // => '105' 24280 */ 24281 function uniqueId(prefix) { 24282 var id = ++idCounter; 24283 return String(prefix == null ? '' : prefix) + id; 24284 } 24285 24286 /*--------------------------------------------------------------------------*/ 24287 24288 /** 24289 * Creates a `lodash` object that wraps the given value with explicit 24290 * method chaining enabled. 24291 * 24292 * @static 24293 * @memberOf _ 24294 * @category Chaining 24295 * @param {*} value The value to wrap. 24296 * @returns {Object} Returns the wrapper object. 24297 * @example 24298 * 24299 * var characters = [ 24300 * { 'name': 'barney', 'age': 36 }, 24301 * { 'name': 'fred', 'age': 40 }, 24302 * { 'name': 'pebbles', 'age': 1 } 24303 * ]; 24304 * 24305 * var youngest = _.chain(characters) 24306 * .sortBy('age') 24307 * .map(function(chr) { return chr.name + ' is ' + chr.age; }) 24308 * .first() 24309 * .value(); 24310 * // => 'pebbles is 1' 24311 */ 24312 function chain(value) { 24313 value = new lodashWrapper(value); 24314 value.__chain__ = true; 24315 return value; 24316 } 24317 24318 /** 24319 * Invokes `interceptor` with the `value` as the first argument and then
24320 * returns `value`. The purpose of this method is to "tap into" a method 24321 * chain in order to perform operations on intermediate results within 24322 * the chain. 24323 * 24324 * @static 24325 * @memberOf _ 24326 * @category Chaining 24327 * @param {*} value The value to provide to `interceptor`. 24328 * @param {Function} interceptor The function to invoke. 24329 * @returns {*} Returns `value`. 24330 * @example 24331 * 24332 * _([1, 2, 3, 4]) 24333 * .tap(function(array) { array.pop(); }) 24334 * .reverse() 24335 * .value(); 24336 * // => [3, 2, 1] 24337 */ 24338 function tap(value, interceptor) { 24339 interceptor(value); 24340 return value; 24341 } 24342 24343 /** 24344 * Enables explicit method chaining on the wrapper object. 24345 * 24346 * @name chain 24347 * @memberOf _ 24348 * @category Chaining 24349 * @returns {*} Returns the wrapper object. 24350 * @example 24351 * 24352 * var characters = [ 24353 * { 'name': 'barney', 'age': 36 }, 24354 * { 'name': 'fred', 'age': 40 } 24355 * ]; 24356 * 24357 * // without explicit chaining 24358 * _(characters).first(); 24359 * // => { 'name': 'barney', 'age': 36 } 24360 * 24361 * // with explicit chaining 24362 * _(characters).chain() 24363 * .first() 24364 * .pick('age') 24365 * .value(); 24366 * // => { 'age': 36 } 24367 */ 24368 function wrapperChain() { 24369 this.__chain__ = true; 24370 return this; 24371 } 24372 24373 /** 24374 * Produces the `toString` result of the wrapped value. 24375 * 24376 * @name toString 24377 * @memberOf _ 24378 * @category Chaining 24379 * @returns {string} Returns the string result. 24380 * @example 24381 * 24382 * _([1, 2, 3]).toString(); 24383 * // => '1,2,3' 24384 */ 24385 function wrapperToString() { 24386 return String(this.__wrapped__); 24387 } 24388 24389 /** 24390 * Extracts the wrapped value. 24391 * 24392 * @name valueOf 24393 * @memberOf _ 24394 * @alias value 24395 * @category Chaining 24396 * @returns {*} Returns the wrapped value. 24397 * @example 24398 * 24399 * _([1, 2, 3]).valueOf(); 24400 * // => [1, 2, 3] 24401 */ 24402 function wrapperValueOf() { 24403 return this.__wrapped__; 24404 } 24405 24406 /*--------------------------------------------------------------------------*/ 24407 24408 // add functions that return wrapped values when chaining 24409 lodash.after = after; 24410 lodash.assign = assign; 24411 lodash.at = at; 24412 lodash.bind = bind; 24413 lodash.bindAll = bindAll; 24414 lodash.bindKey = bindKey; 24415 lodash.chain = chain; 24416 lodash.compact = compact; 24417 lodash.compose = compose; 24418 lodash.constant = constant; 24419 lodash.countBy = countBy; 24420 lodash.create = create; 24421 lodash.createCallback = createCallback; 24422 lodash.curry = curry; 24423 lodash.debounce = debounce; 24424 lodash.defaults = defaults; 24425 lodash.defer = defer; 24426 lodash.delay = delay; 24427 lodash.difference = difference; 24428 lodash.filter = filter; 24429 lodash.flatten = flatten; 24430 lodash.forEach = forEach; 24431 lodash.forEachRight = forEachRight; 24432 lodash.forIn = forIn; 24433 lodash.forInRight = forInRight; 24434 lodash.forOwn = forOwn; 24435 lodash.forOwnRight = forOwnRight; 24436 lodash.functions = functions; 24437 lodash.groupBy = groupBy; 24438 lodash.indexBy = indexBy; 24439 lodash.initial = initial; 24440 lodash.intersection = intersection; 24441 lodash.invert = invert; 24442 lodash.invoke = invoke; 24443 lodash.keys = keys; 24444 lodash.map = map; 24445 lodash.mapValues = mapValues; 24446 lodash.max = max; 24447 lodash.memoize = memoize; 24448 lodash.merge = merge; 24449 lodash.min = min; 24450 lodash.omit = omit; 24451 lodash.once = once; 24452 lodash.pairs = pairs; 24453 lodash.partial = partial; 24454 lodash.partialRight = partialRight; 24455 lodash.pick = pick; 24456 lodash.pluck = pluck; 24457 lodash.property = property; 24458 lodash.pull = pull; 24459 lodash.range = range; 24460 lodash.reject = reject; 24461 lodash.remove = remove; 24462 lodash.rest = rest; 24463 lodash.shuffle = shuffle; 24464 lodash.sortBy = sortBy; 24465 lodash.tap = tap; 24466 lodash.throttle = throttle; 24467 lodash.times = times; 24468 lodash.toArray = toArray; 24469 lodash.transform = transform; 24470 lodash.union = union; 24471 lodash.uniq = uniq; 24472 lodash.values = values; 24473 lodash.where = where; 24474 lodash.without = without; 24475 lodash.wrap = wrap; 24476 lodash.xor = xor; 24477 lodash.zip = zip; 24478 lodash.zipObject = zipObject; 24479 24480 // add aliases 24481 lodash.collect = map; 24482 lodash.drop = rest; 24483 lodash.each = forEach; 24484 lodash.eachRight = forEachRight; 24485 lodash.extend = assign; 24486 lodash.methods = functions; 24487 lodash.object = zipObject; 24488 lodash.select = filter; 24489 lodash.tail = rest; 24490 lodash.unique = uniq; 24491 lodash.unzip = zip; 24492 24493 // add functions to `lodash.prototype`
24494 mixin(lodash); 24495 24496 /*--------------------------------------------------------------------------*/ 24497 24498 // add functions that return unwrapped values when chaining 24499 lodash.clone = clone; 24500 lodash.cloneDeep = cloneDeep; 24501 lodash.contains = contains; 24502 lodash.escape = escape; 24503 lodash.every = every; 24504 lodash.find = find; 24505 lodash.findIndex = findIndex; 24506 lodash.findKey = findKey; 24507 lodash.findLast = findLast; 24508 lodash.findLastIndex = findLastIndex; 24509 lodash.findLastKey = findLastKey; 24510 lodash.has = has; 24511 lodash.identity = identity; 24512 lodash.indexOf = indexOf; 24513 lodash.isArguments = isArguments; 24514 lodash.isArray = isArray; 24515 lodash.isBoolean = isBoolean; 24516 lodash.isDate = isDate; 24517 lodash.isElement = isElement; 24518 lodash.isEmpty = isEmpty; 24519 lodash.isEqual = isEqual; 24520 lodash.isFinite = isFinite; 24521 lodash.isFunction = isFunction; 24522 lodash.isNaN = isNaN; 24523 lodash.isNull = isNull; 24524 lodash.isNumber = isNumber; 24525 lodash.isObject = isObject; 24526 lodash.isPlainObject = isPlainObject; 24527 lodash.isRegExp = isRegExp; 24528 lodash.isString = isString; 24529 lodash.isUndefined = isUndefined; 24530 lodash.lastIndexOf = lastIndexOf; 24531 lodash.mixin = mixin; 24532 lodash.noConflict = noConflict; 24533 lodash.noop = noop; 24534 lodash.now = now; 24535 lodash.parseInt = parseInt; 24536 lodash.random = random; 24537 lodash.reduce = reduce; 24538 lodash.reduceRight = reduceRight; 24539 lodash.result = result; 24540 lodash.runInContext = runInContext; 24541 lodash.size = size; 24542 lodash.some = some; 24543 lodash.sortedIndex = sortedIndex; 24544 lodash.template = template; 24545 lodash.unescape = unescape; 24546 lodash.uniqueId = uniqueId; 24547 24548 // add aliases 24549 lodash.all = every; 24550 lodash.any = some; 24551 lodash.detect = find; 24552 lodash.findWhere = find; 24553 lodash.foldl = reduce; 24554 lodash.foldr = reduceRight; 24555 lodash.include = contains; 24556 lodash.inject = reduce; 24557 24558 mixin(function() { 24559 var source = {} 24560 forOwn(lodash, function(func, methodName) { 24561 if (!lodash.prototype[methodName]) { 24562 source[methodName] = func; 24563 } 24564 }); 24565 return source; 24566 }(), false); 24567 24568 /*--------------------------------------------------------------------------*/ 24569 24570 // add functions capable of returning wrapped and unwrapped values when chaining 24571 lodash.first = first; 24572 lodash.last = last; 24573 lodash.sample = sample; 24574 24575 // add aliases 24576 lodash.take = first; 24577 lodash.head = first; 24578 24579 forOwn(lodash, function(func, methodName) { 24580 var callbackable = methodName !== 'sample'; 24581 if (!lodash.prototype[methodName]) { 24582 lodash.prototype[methodName]= function(n, guard) { 24583 var chainAll = this.__chain__, 24584 result = func(this.__wrapped__, n, guard); 24585 24586 return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function'))) 24587 ? result 24588 : new lodashWrapper(result, chainAll); 24589 }; 24590 } 24591 }); 24592 24593 /*--------------------------------------------------------------------------*/ 24594 24595 /** 24596 * The semantic version number. 24597 * 24598 * @static 24599 * @memberOf _ 24600 * @type string 24601 */ 24602 lodash.VERSION = '2.4.1'; 24603 24604 // add "Chaining" functions to the wrapper 24605 lodash.prototype.chain = wrapperChain; 24606 lodash.prototype.toString = wrapperToString; 24607 lodash.prototype.value = wrapperValueOf; 24608 lodash.prototype.valueOf = wrapperValueOf; 24609 24610 // add `Array` functions that return unwrapped values 24611 forEach(['join', 'pop', 'shift'], function(methodName) { 24612 var func = arrayRef[methodName]; 24613 lodash.prototype[methodName] = function() { 24614 var chainAll = this.__chain__, 24615 result = func.apply(this.__wrapped__, arguments); 24616 24617 return chainAll 24618 ? new lodashWrapper(result, chainAll) 24619 : result; 24620 }; 24621 }); 24622 24623 // add `Array` functions that return the existing wrapped value 24624 forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) { 24625 var func = arrayRef[methodName]; 24626 lodash.prototype[methodName] = function() { 24627 func.apply(this.__wrapped__, arguments); 24628 return this; 24629 }; 24630 }); 24631 24632 // add `Array` functions that return new wrapped values
24633 forEach(['concat', 'slice', 'splice'], function(methodName) { 24634 var func = arrayRef[methodName]; 24635 lodash.prototype[methodName] = function() { 24636 return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__); 24637 }; 24638 }); 24639 24640 return lodash; 24641 } 24642 24643 /*--------------------------------------------------------------------------*/ 24644 24645 // expose Lo-Dash 24646 var _ = runInContext(); 24647 24648 // some AMD build optimizers like r.js check for condition patterns like the following: 24649 if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { 24650 // Expose Lo-Dash to the global object even when an AMD loader is present in 24651 // case Lo-Dash is loaded with a RequireJS shim config. 24652 // See http://requirejs.org/docs/api.html#config-shim 24653 root._ = _; 24654 24655 // define as an anonymous module so, through path mapping, it can be 24656 // referenced as the "underscore" module 24657 define(function() { 24658 return _; 24659 }); 24660 } 24661 // check for `exports` after `define` in case a build optimizer adds an `exports` object 24662 else if (freeExports && freeModule) { 24663 // in Node.js or RingoJS 24664 if (moduleExports) { 24665 (freeModule.exports = _)._ = _; 24666 } 24667 // in Narwhal or Rhino -require 24668 else { 24669 freeExports._ = _; 24670 } 24671 } 24672 else { 24673 // in a browser or Rhino 24674 root._ = _; 24675 } 24676}.call(this)); 24677/*! 24678Chosen, a Select Box Enhancer for jQuery and Prototype 24679by Patrick Filler for Harvest, http://getharvest.com 24680 24681Version 1.6.2 24682Full source at https://github.com/harvesthq/chosen 24683Copyright (c) 2011-2016 Harvest http://getharvest.com 24684 24685MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md 24686This file is generated by `grunt build`, do not edit it by hand. 24687*/ 24688 24689 24690(function() { 24691 var $, AbstractChosen, Chosen, SelectParser, _ref, 24692 __hasProp = {}.hasOwnProperty, 24693 __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 24694 24695 SelectParser = (function() { 24696 function SelectParser() { 24697 this.options_index = 0; 24698 this.parsed = []; 24699 } 24700 24701 SelectParser.prototype.add_node = function(child) { 24702 if (child.nodeName.toUpperCase() === "OPTGROUP") { 24703 return this.add_group(child); 24704 } else { 24705 return this.add_option(child); 24706 } 24707 }; 24708 24709 SelectParser.prototype.add_group = function(group) { 24710 var group_position, option, _i, _len, _ref, _results; 24711 group_position = this.parsed.length; 24712 this.parsed.push({ 24713 array_index: group_position, 24714 group: true, 24715 label: this.escapeExpression(group.label), 24716 title: group.title ? group.title : void 0, 24717 children: 0, 24718 disabled: group.disabled, 24719 classes: group.className 24720 }); 24721 _ref = group.childNodes; 24722 _results = []; 24723 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 24724 option = _ref[_i]; 24725 _results.push(this.add_option(option, group_position, group.disabled)); 24726 } 24727 return _results; 24728 }; 24729 24730 SelectParser.prototype.add_option = function(option, group_position, group_disabled) { 24731 if (option.nodeName.toUpperCase() === "OPTION") { 24732 if (option.text !== "") { 24733 if (group_position != null) { 24734 this.parsed[group_position].children += 1; 24735 } 24736 this.parsed.push({ 24737 array_index: this.parsed.length, 24738 options_index: this.options_index, 24739 value: option.value, 24740 text: option.text, 24741 html: option.innerHTML, 24742 title: option.title ? option.title : void 0, 24743 selected: option.selected, 24744 disabled: group_disabled === true ? group_disabled : option.disabled, 24745 group_array_index: group_position, 24746 group_label: group_position != null ? this.parsed[group_position].label : null, 24747 classes: option.className, 24748 style: option.style.cssText 24749 }); 24750 } else { 24751 this.parsed.push({ 24752 array_index: this.parsed.length, 24753 options_index: this.options_index, 24754 empty: true 24755 }); 24756 } 24757 return this.options_index += 1; 24758 } 24759 }; 24760 24761 SelectParser.prototype.escapeExpression = function(text) { 24762 var map, unsafe_chars; 24763 if ((text == null) || text === false) { 24764 return ""; 24765 } 24766 if (!/[\&\<\>\"\'\`]/.test(text)) { 24767 return text; 24768 } 24769 map = { 24770 "<": "<", 24771 ">": ">", 24772 '"': """, 24773 "'": "'", 24774 "`": "`" 24775 }; 24776 unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g; 24777 return text.replace(unsafe_chars, function(chr) { 24778 return map[chr] || "&"; 24779 }); 24780 }; 24781 24782 return SelectParser; 24783 24784 })(); 24785 24786 SelectParser.select_to_array = function(select) { 24787 var child, parser, _i, _len, _ref; 24788 parser = new SelectParser(); 24789 _ref = select.childNodes; 24790 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 24791 child = _ref[_i]; 24792 parser.add_node(child); 24793 } 24794 return parser.parsed; 24795 }; 24796 24797 AbstractChosen = (function() { 24798 function AbstractChosen(form_field, options) { 24799 this.form_field = form_field; 24800 this.options = options != null ? options : {}; 24801 if (!AbstractChosen.browser_is_supported()) { 24802 return; 24803 } 24804 this.is_multiple = this.form_field.multiple; 24805 this.set_default_text(); 24806 this.set_default_values(); 24807 this.setup(); 24808 this.set_up_html(); 24809 this.register_observers(); 24810 this.on_ready(); 24811 } 24812 24813 AbstractChosen.prototype.set_default_values = function() { 24814 var _this = this; 24815 this.click_test_action = function(evt) { 24816 return _this.test_active_click(evt); 24817 }; 24818 this.activate_action = function(evt) { 24819 return _this.activate_field(evt); 24820 }; 24821 this.active_field = false;
vendor: 8,018 bytes, lines 24822-25035
24822 this.mouse_on_container = false; 24823 this.results_showing = false; 24824 this.result_highlighted = null; 24825 this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false; 24826 this.disable_search_threshold = this.options.disable_search_threshold || 0; 24827 this.disable_search = this.options.disable_search || false; 24828 this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true; 24829 this.group_search = this.options.group_search != null ? this.options.group_search : true; 24830 this.search_contains = this.options.search_contains || false; 24831 this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true; 24832 this.max_selected_options = this.options.max_selected_options || Infinity; 24833 this.inherit_select_classes = this.options.inherit_select_classes || false; 24834 this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true; 24835 this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true; 24836 this.include_group_label_in_selected = this.options.include_group_label_in_selected || false; 24837 this.max_shown_results = this.options.max_shown_results || Number.POSITIVE_INFINITY; 24838 return this.case_sensitive_search = this.options.case_sensitive_search || false; 24839 }; 24840 24841 AbstractChosen.prototype.set_default_text = function() { 24842 if (this.form_field.getAttribute("data-placeholder")) { 24843 this.default_text = this.form_field.getAttribute("data-placeholder"); 24844 } else if (this.is_multiple) { 24845 this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text; 24846 } else { 24847 this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text; 24848 } 24849 return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text; 24850 }; 24851 24852 AbstractChosen.prototype.choice_label = function(item) { 24853 if (this.include_group_label_in_selected && (item.group_label != null)) { 24854 return "<b class='group-name'>" + item.group_label + "</b>" + item.html; 24855 } else { 24856 return item.html; 24857 } 24858 }; 24859 24860 AbstractChosen.prototype.mouse_enter = function() { 24861 return this.mouse_on_container = true; 24862 }; 24863 24864 AbstractChosen.prototype.mouse_leave = function() { 24865 return this.mouse_on_container = false; 24866 }; 24867 24868 AbstractChosen.prototype.input_focus = function(evt) { 24869 var _this = this; 24870 if (this.is_multiple) { 24871 if (!this.active_field) { 24872 return setTimeout((function() { 24873 return _this.container_mousedown(); 24874 }), 50); 24875 } 24876 } else { 24877 if (!this.active_field) { 24878 return this.activate_field(); 24879 } 24880 } 24881 }; 24882 24883 AbstractChosen.prototype.input_blur = function(evt) { 24884 var _this = this; 24885 if (!this.mouse_on_container) { 24886 this.active_field = false; 24887 return setTimeout((function() { 24888 return _this.blur_test(); 24889 }), 100); 24890 } 24891 }; 24892 24893 AbstractChosen.prototype.results_option_build = function(options) { 24894 var content, data, data_content, shown_results, _i, _len, _ref; 24895 content = ''; 24896 shown_results = 0; 24897 _ref = this.results_data; 24898 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 24899 data = _ref[_i]; 24900 data_content = ''; 24901 if (data.group) { 24902 data_content = this.result_add_group(data); 24903 } else { 24904 data_content = this.result_add_option(data); 24905 } 24906 if (data_content !== '') { 24907 shown_results++; 24908 content += data_content; 24909 } 24910 if (options != null ? options.first : void 0) { 24911 if (data.selected && this.is_multiple) { 24912 this.choice_build(data); 24913 } else if (data.selected && !this.is_multiple) { 24914 this.single_set_selected_text(this.choice_label(data)); 24915 } 24916 } 24917 if (shown_results >= this.max_shown_results) { 24918 break; 24919 } 24920 } 24921 return content; 24922 }; 24923 24924 AbstractChosen.prototype.result_add_option = function(option) { 24925 var classes, option_el; 24926 if (!option.search_match) { 24927 return ''; 24928 } 24929 if (!this.include_option_in_results(option)) { 24930 return ''; 24931 } 24932 classes = []; 24933 if (!option.disabled && !(option.selected && this.is_multiple)) { 24934 classes.push("active-result"); 24935 } 24936 if (option.disabled && !(option.selected && this.is_multiple)) { 24937 classes.push("disabled-result"); 24938 } 24939 if (option.selected) { 24940 classes.push("result-selected"); 24941 } 24942 if (option.group_array_index != null) { 24943 classes.push("group-option"); 24944 } 24945 if (option.classes !== "") { 24946 classes.push(option.classes); 24947 } 24948 option_el = document.createElement("li"); 24949 option_el.className = classes.join(" "); 24950 option_el.style.cssText = option.style; 24951 option_el.setAttribute("data-option-array-index", option.array_index); 24952 option_el.innerHTML = option.search_text; 24953 if (option.title) { 24954 option_el.title = option.title; 24955 } 24956 return this.outerHTML(option_el); 24957 }; 24958 24959 AbstractChosen.prototype.result_add_group = function(group) { 24960 var classes, group_el; 24961 if (!(group.search_match || group.group_match)) { 24962 return ''; 24963 } 24964 if (!(group.active_options > 0)) { 24965 return ''; 24966 } 24967 classes = []; 24968 classes.push("group-result"); 24969 if (group.classes) { 24970 classes.push(group.classes); 24971 } 24972 group_el = document.createElement("li"); 24973 group_el.className = classes.join(" "); 24974 group_el.innerHTML = group.search_text; 24975 if (group.title) { 24976 group_el.title = group.title; 24977 } 24978 return this.outerHTML(group_el); 24979 }; 24980 24981 AbstractChosen.prototype.results_update_field = function() { 24982 this.set_default_text(); 24983 if (!this.is_multiple) { 24984 this.results_reset_cleanup(); 24985 } 24986 this.result_clear_highlight(); 24987 this.results_build(); 24988 if (this.results_showing) { 24989 return this.winnow_results(); 24990 } 24991 }; 24992 24993 AbstractChosen.prototype.reset_single_select_options = function() { 24994 var result, _i, _len, _ref, _results; 24995 _ref = this.results_data; 24996 _results = []; 24997 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 24998 result = _ref[_i]; 24999 if (result.selected) { 25000 _results.push(result.selected = false); 25001 } else { 25002 _results.push(void 0); 25003 } 25004 } 25005 return _results; 25006 }; 25007 25008 AbstractChosen.prototype.results_toggle = function() { 25009 if (this.results_showing) { 25010 return this.results_hide(); 25011 } else { 25012 return this.results_show(); 25013 } 25014 }; 25015 25016 AbstractChosen.prototype.results_search = function(evt) { 25017 if (this.results_showing) { 25018 return this.winnow_results(); 25019 } else { 25020 return this.results_show(); 25021 } 25022 }; 25023 25024 AbstractChosen.prototype.winnow_results = function() { 25025 var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref; 25026 this.no_results_clear(); 25027 results = 0; 25028 searchText = this.get_search_text(); 25029 escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 25030 zregex = new RegExp(escapedSearchText, 'i'); 25031 regex = this.get_search_regex(escapedSearchText); 25032 _ref = this.results_data; 25033 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 25034 option = _ref[_i]; 25035 option.search_match = false;
25036 results_group = null; 25037 if (this.include_option_in_results(option)) { 25038 if (option.group) { 25039 option.group_match = false; 25040 option.active_options = 0; 25041 } 25042 if ((option.group_array_index != null) && this.results_data[option.group_array_index]) { 25043 results_group = this.results_data[option.group_array_index]; 25044 if (results_group.active_options === 0 && results_group.search_match) { 25045 results += 1; 25046 } 25047 results_group.active_options += 1; 25048 } 25049 option.search_text = option.group ? option.label : option.html; 25050 if (!(option.group && !this.group_search)) { 25051 option.search_match = this.search_string_match(option.search_text, regex); 25052 if (option.search_match && !option.group) { 25053 results += 1; 25054 } 25055 if (option.search_match) { 25056 if (searchText.length) { 25057 startpos = option.search_text.search(zregex); 25058 text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length); 25059 option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos); 25060 } 25061 if (results_group != null) { 25062 results_group.group_match = true; 25063 } 25064 } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) { 25065 option.search_match = true; 25066 } 25067 } 25068 } 25069 } 25070 this.result_clear_highlight(); 25071 if (results < 1 && searchText.length) { 25072 this.update_results_content(""); 25073 return this.no_results(searchText); 25074 } else { 25075 this.update_results_content(this.results_option_build()); 25076 return this.winnow_results_set_highlight(); 25077 } 25078 }; 25079 25080 AbstractChosen.prototype.get_search_regex = function(escaped_search_string) { 25081 var regex_anchor, regex_flag; 25082 regex_anchor = this.search_contains ? "" : "^"; 25083 regex_flag = this.case_sensitive_search ? "" : "i"; 25084 return new RegExp(regex_anchor + escaped_search_string, regex_flag); 25085 }; 25086 25087 AbstractChosen.prototype.search_string_match = function(search_string, regex) { 25088 var part, parts, _i, _len; 25089 if (regex.test(search_string)) { 25090 return true; 25091 } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) { 25092 parts = search_string.replace(/\[|\]/g, "").split(" "); 25093 if (parts.length) { 25094 for (_i = 0, _len = parts.length; _i < _len; _i++) { 25095 part = parts[_i]; 25096 if (regex.test(part)) { 25097 return true; 25098 } 25099 } 25100 } 25101 } 25102 }; 25103 25104 AbstractChosen.prototype.choices_count = function() { 25105 var option, _i, _len, _ref; 25106 if (this.selected_option_count != null) { 25107 return this.selected_option_count; 25108 } 25109 this.selected_option_count = 0; 25110 _ref = this.form_field.options; 25111 for (_i = 0, _len = _ref.length; _i < _len; _i++) { 25112 option = _ref[_i]; 25113 if (option.selected) { 25114 this.selected_option_count += 1; 25115 } 25116 } 25117 return this.selected_option_count; 25118 }; 25119 25120 AbstractChosen.prototype.choices_click = function(evt) { 25121 evt.preventDefault(); 25122 if (!(this.results_showing || this.is_disabled)) { 25123 return this.results_show(); 25124 } 25125 }; 25126 25127 AbstractChosen.prototype.keyup_checker = function(evt) { 25128 var stroke, _ref; 25129 stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; 25130 this.search_field_scale(); 25131 switch (stroke) { 25132 case 8: 25133 if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) { 25134 return this.keydown_backstroke(); 25135 } else if (!this.pending_backstroke) { 25136 this.result_clear_highlight(); 25137 return this.results_search(); 25138 } 25139 break; 25140 case 13: 25141 evt.preventDefault(); 25142 if (this.results_showing) { 25143 return this.result_select(evt); 25144 } 25145 break; 25146 case 27: 25147 if (this.results_showing) { 25148 this.results_hide(); 25149 } 25150 return true; 25151 case 9: 25152 case 38: 25153 case 40: 25154 case 16: 25155 case 91: 25156 case 17: 25157 case 18: 25158 break; 25159 default: 25160 return this.results_search(); 25161 } 25162 }; 25163 25164 AbstractChosen.prototype.clipboard_event_checker = function(evt) { 25165 var _this = this; 25166 return setTimeout((function() { 25167 return _this.results_search(); 25168 }), 50); 25169 }; 25170 25171 AbstractChosen.prototype.container_width = function() { 25172 if (this.options.width != null) { 25173 return this.options.width; 25174 } else { 25175 return "" + this.form_field.offsetWidth + "px"; 25176 } 25177 }; 25178 25179 AbstractChosen.prototype.include_option_in_results = function(option) { 25180 if (this.is_multiple && (!this.display_selected_options && option.selected)) { 25181 return false;
25182 } 25183 if (!this.display_disabled_options && option.disabled) { 25184 return false; 25185 } 25186 if (option.empty) { 25187 return false; 25188 } 25189 return true; 25190 }; 25191 25192 AbstractChosen.prototype.search_results_touchstart = function(evt) { 25193 this.touch_started = true; 25194 return this.search_results_mouseover(evt); 25195 }; 25196 25197 AbstractChosen.prototype.search_results_touchmove = function(evt) { 25198 this.touch_started = false; 25199 return this.search_results_mouseout(evt); 25200 }; 25201 25202 AbstractChosen.prototype.search_results_touchend = function(evt) { 25203 if (this.touch_started) { 25204 return this.search_results_mouseup(evt); 25205 } 25206 }; 25207 25208 AbstractChosen.prototype.outerHTML = function(element) { 25209 var tmp; 25210 if (element.outerHTML) { 25211 return element.outerHTML; 25212 } 25213 tmp = document.createElement("div"); 25214 tmp.appendChild(element); 25215 return tmp.innerHTML; 25216 }; 25217 25218 AbstractChosen.browser_is_supported = function() { 25219 if ("Microsoft Internet Explorer" === window.navigator.appName) { 25220 return document.documentMode >= 8; 25221 } 25222 return true; 25223 }; 25224 25225 AbstractChosen.default_multiple_text = "Select Some Options"; 25226 25227 AbstractChosen.default_single_text = "Select an Option"; 25228 25229 AbstractChosen.default_no_result_text = "No results match"; 25230 25231 return AbstractChosen; 25232 25233 })(); 25234 25235 $ = jQuery; 25236 25237 $.fn.extend({ 25238 chosen: function(options) { 25239 if (!AbstractChosen.browser_is_supported()) { 25240 return this; 25241 } 25242 return this.each(function(input_field) { 25243 var $this, chosen; 25244 $this = $(this); 25245 chosen = $this.data('chosen'); 25246 if (options === 'destroy') { 25247 if (chosen instanceof Chosen) { 25248 chosen.destroy(); 25249 } 25250 return; 25251 } 25252 if (!(chosen instanceof Chosen)) { 25253 $this.data('chosen', new Chosen(this, options)); 25254 } 25255 }); 25256 } 25257 }); 25258 25259 Chosen = (function(_super) { 25260 __extends(Chosen, _super); 25261 25262 function Chosen() { 25263 _ref = Chosen.__super__.constructor.apply(this, arguments); 25264 return _ref; 25265 } 25266 25267 Chosen.prototype.setup = function() { 25268 this.form_field_jq = $(this.form_field); 25269 this.current_selectedIndex = this.form_field.selectedIndex; 25270 return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl"); 25271 }; 25272 25273 Chosen.prototype.set_up_html = function() {
25274 var container_classes, container_props; 25275 container_classes = ["chosen-container"]; 25276 container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single")); 25277 if (this.inherit_select_classes && this.form_field.className) { 25278 container_classes.push(this.form_field.className); 25279 } 25280 if (this.is_rtl) { 25281 container_classes.push("chosen-rtl"); 25282 } 25283 container_props = { 25284 'class': container_classes.join(' '), 25285 'style': "width: " + (this.container_width()) + ";", 25286 'title': this.form_field.title 25287 }; 25288 if (this.form_field.id.length) { 25289 container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen"; 25290 } 25291 this.container = $("<div />", container_props); 25292 if (this.is_multiple) { 25293 this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>'); 25294 } else { 25295 this.container.html('<a class="chosen-single chosen-default"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>'); 25296 } 25297 this.form_field_jq.hide().after(this.container); 25298 this.dropdown = this.container.find('div.chosen-drop').first(); 25299 this.search_field = this.container.find('input').first(); 25300 this.search_results = this.container.find('ul.chosen-results').first(); 25301 this.search_field_scale(); 25302 this.search_no_results = this.container.find('li.no-results').first(); 25303 if (this.is_multiple) { 25304 this.search_choices = this.container.find('ul.chosen-choices').first(); 25305 this.search_container = this.container.find('li.search-field').first(); 25306 } else { 25307 this.search_container = this.container.find('div.chosen-search').first(); 25308 this.selected_item = this.container.find('.chosen-single').first(); 25309 } 25310 this.results_build(); 25311 this.set_tab_index(); 25312 return this.set_label_behavior(); 25313 }; 25314 25315 Chosen.prototype.on_ready = function() { 25316 return this.form_field_jq.trigger("chosen:ready", { 25317 chosen: this 25318 }); 25319 }; 25320 25321 Chosen.prototype.register_observers = function() { 25322 var _this = this; 25323 this.container.bind('touchstart.chosen', function(evt) { 25324 _this.container_mousedown(evt); 25325 return evt.preventDefault(); 25326 }); 25327 this.container.bind('touchend.chosen', function(evt) { 25328 _this.container_mouseup(evt); 25329 return evt.preventDefault(); 25330 }); 25331 this.container.bind('mousedown.chosen', function(evt) { 25332 _this.container_mousedown(evt); 25333 }); 25334 this.container.bind('mouseup.chosen', function(evt) { 25335 _this.container_mouseup(evt); 25336 }); 25337 this.container.bind('mouseenter.chosen', function(evt) { 25338 _this.mouse_enter(evt); 25339 }); 25340 this.container.bind('mouseleave.chosen', function(evt) { 25341 _this.mouse_leave(evt); 25342 }); 25343 this.search_results.bind('mouseup.chosen', function(evt) { 25344 _this.search_results_mouseup(evt); 25345 }); 25346 this.search_results.bind('mouseover.chosen', function(evt) { 25347 _this.search_results_mouseover(evt); 25348 }); 25349 this.search_results.bind('mouseout.chosen', function(evt) { 25350 _this.search_results_mouseout(evt); 25351 }); 25352 this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) { 25353 _this.search_results_mousewheel(evt); 25354 }); 25355 this.search_results.bind('touchstart.chosen', function(evt) { 25356 _this.search_results_touchstart(evt); 25357 }); 25358 this.search_results.bind('touchmove.chosen', function(evt) { 25359 _this.search_results_touchmove(evt); 25360 }); 25361 this.search_results.bind('touchend.chosen', function(evt) { 25362 _this.search_results_touchend(evt); 25363 }); 25364 this.form_field_jq.bind("chosen:updated.chosen", function(evt) { 25365 _this.results_update_field(evt); 25366 }); 25367 this.form_field_jq.bind("chosen:activate.chosen", function(evt) { 25368 _this.activate_field(evt); 25369 }); 25370 this.form_field_jq.bind("chosen:open.chosen", function(evt) { 25371 _this.container_mousedown(evt); 25372 }); 25373 this.form_field_jq.bind("chosen:close.chosen", function(evt) { 25374 _this.input_blur(evt); 25375 }); 25376 this.search_field.bind('blur.chosen', function(evt) { 25377 _this.input_blur(evt); 25378 }); 25379 this.search_field.bind('keyup.chosen', function(evt) { 25380 _this.keyup_checker(evt); 25381 }); 25382 this.search_field.bind('keydown.chosen', function(evt) { 25383 _this.keydown_checker(evt); 25384 }); 25385 this.search_field.bind('focus.chosen', function(evt) { 25386 _this.input_focus(evt); 25387 }); 25388 this.search_field.bind('cut.chosen', function(evt) { 25389 _this.clipboard_event_checker(evt); 25390 }); 25391 this.search_field.bind('paste.chosen', function(evt) { 25392 _this.clipboard_event_checker(evt); 25393 }); 25394 if (this.is_multiple) { 25395 return this.search_choices.bind('click.chosen', function(evt) { 25396 _this.choices_click(evt); 25397 }); 25398 } else { 25399 return this.container.bind('click.chosen', function(evt) { 25400 evt.preventDefault(); 25401 }); 25402 } 25403 }; 25404 25405 Chosen.prototype.destroy = function() { 25406 $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); 25407 if (this.search_field[0].tabIndex) { 25408 this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex; 25409 } 25410 this.container.remove(); 25411 this.form_field_jq.removeData('chosen'); 25412 return this.form_field_jq.show(); 25413 }; 25414 25415 Chosen.prototype.search_field_disabled = function() { 25416 this.is_disabled = this.form_field_jq[0].disabled; 25417 if (this.is_disabled) { 25418 this.container.addClass('chosen-disabled'); 25419 this.search_field[0].disabled = true; 25420 if (!this.is_multiple) { 25421 this.selected_item.unbind("focus.chosen", this.activate_action); 25422 } 25423 return this.close_field(); 25424 } else { 25425 this.container.removeClass('chosen-disabled'); 25426 this.search_field[0].disabled = false;
vendor: 5,123 bytes, lines 25427-25563
25427 if (!this.is_multiple) { 25428 return this.selected_item.bind("focus.chosen", this.activate_action); 25429 } 25430 } 25431 }; 25432 25433 Chosen.prototype.container_mousedown = function(evt) { 25434 if (!this.is_disabled) { 25435 if (evt && evt.type === "mousedown" && !this.results_showing) { 25436 evt.preventDefault(); 25437 } 25438 if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) { 25439 if (!this.active_field) { 25440 if (this.is_multiple) { 25441 this.search_field.val(""); 25442 } 25443 $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action); 25444 this.results_show(); 25445 } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) { 25446 evt.preventDefault(); 25447 this.results_toggle(); 25448 } 25449 return this.activate_field(); 25450 } 25451 } 25452 }; 25453 25454 Chosen.prototype.container_mouseup = function(evt) { 25455 if (evt.target.nodeName === "ABBR" && !this.is_disabled) { 25456 return this.results_reset(evt); 25457 } 25458 }; 25459 25460 Chosen.prototype.search_results_mousewheel = function(evt) { 25461 var delta; 25462 if (evt.originalEvent) { 25463 delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail; 25464 } 25465 if (delta != null) { 25466 evt.preventDefault(); 25467 if (evt.type === 'DOMMouseScroll') { 25468 delta = delta * 40; 25469 } 25470 return this.search_results.scrollTop(delta + this.search_results.scrollTop()); 25471 } 25472 }; 25473 25474 Chosen.prototype.blur_test = function(evt) { 25475 if (!this.active_field && this.container.hasClass("chosen-container-active")) { 25476 return this.close_field(); 25477 } 25478 }; 25479 25480 Chosen.prototype.close_field = function() { 25481 $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); 25482 this.active_field = false; 25483 this.results_hide(); 25484 this.container.removeClass("chosen-container-active"); 25485 this.clear_backstroke(); 25486 this.show_search_field_default(); 25487 return this.search_field_scale(); 25488 }; 25489 25490 Chosen.prototype.activate_field = function() { 25491 this.container.addClass("chosen-container-active"); 25492 this.active_field = true; 25493 this.search_field.val(this.search_field.val()); 25494 return this.search_field.focus(); 25495 }; 25496 25497 Chosen.prototype.test_active_click = function(evt) { 25498 var active_container; 25499 active_container = $(evt.target).closest('.chosen-container'); 25500 if (active_container.length && this.container[0] === active_container[0]) { 25501 return this.active_field = true; 25502 } else { 25503 return this.close_field(); 25504 } 25505 }; 25506 25507 Chosen.prototype.results_build = function() { 25508 this.parsing = true; 25509 this.selected_option_count = null; 25510 this.results_data = SelectParser.select_to_array(this.form_field); 25511 if (this.is_multiple) { 25512 this.search_choices.find("li.search-choice").remove(); 25513 } else if (!this.is_multiple) { 25514 this.single_set_selected_text(); 25515 if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) { 25516 this.search_field[0].readOnly = true; 25517 this.container.addClass("chosen-container-single-nosearch"); 25518 } else { 25519 this.search_field[0].readOnly = false; 25520 this.container.removeClass("chosen-container-single-nosearch"); 25521 } 25522 } 25523 this.update_results_content(this.results_option_build({ 25524 first: true 25525 })); 25526 this.search_field_disabled(); 25527 this.show_search_field_default(); 25528 this.search_field_scale(); 25529 return this.parsing = false; 25530 }; 25531 25532 Chosen.prototype.result_do_highlight = function(el) { 25533 var high_bottom, high_top, maxHeight, visible_bottom, visible_top; 25534 if (el.length) { 25535 this.result_clear_highlight(); 25536 this.result_highlight = el; 25537 this.result_highlight.addClass("highlighted"); 25538 maxHeight = parseInt(this.search_results.css("maxHeight"), 10); 25539 visible_top = this.search_results.scrollTop(); 25540 visible_bottom = maxHeight + visible_top; 25541 high_top = this.result_highlight.position().top + this.search_results.scrollTop(); 25542 high_bottom = high_top + this.result_highlight.outerHeight(); 25543 if (high_bottom >= visible_bottom) { 25544 return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0); 25545 } else if (high_top < visible_top) { 25546 return this.search_results.scrollTop(high_top); 25547 } 25548 } 25549 }; 25550 25551 Chosen.prototype.result_clear_highlight = function() { 25552 if (this.result_highlight) { 25553 this.result_highlight.removeClass("highlighted"); 25554 } 25555 return this.result_highlight = null; 25556 }; 25557 25558 Chosen.prototype.results_show = function() { 25559 if (this.is_multiple && this.max_selected_options <= this.choices_count()) { 25560 this.form_field_jq.trigger("chosen:maxselected", { 25561 chosen: this 25562 }); 25563 return false;
25564 } 25565 this.container.addClass("chosen-with-drop"); 25566 this.results_showing = true; 25567 this.search_field.focus(); 25568 this.search_field.val(this.search_field.val()); 25569 this.winnow_results(); 25570 return this.form_field_jq.trigger("chosen:showing_dropdown", { 25571 chosen: this 25572 }); 25573 }; 25574 25575 Chosen.prototype.update_results_content = function(content) { 25576 return this.search_results.html(content); 25577 }; 25578 25579 Chosen.prototype.results_hide = function() { 25580 if (this.results_showing) { 25581 this.result_clear_highlight(); 25582 this.container.removeClass("chosen-with-drop"); 25583 this.form_field_jq.trigger("chosen:hiding_dropdown", { 25584 chosen: this 25585 }); 25586 } 25587 return this.results_showing = false; 25588 }; 25589 25590 Chosen.prototype.set_tab_index = function(el) { 25591 var ti; 25592 if (this.form_field.tabIndex) { 25593 ti = this.form_field.tabIndex; 25594 this.form_field.tabIndex = -1; 25595 return this.search_field[0].tabIndex = ti; 25596 } 25597 }; 25598 25599 Chosen.prototype.set_label_behavior = function() { 25600 var _this = this; 25601 this.form_field_label = this.form_field_jq.parents("label"); 25602 if (!this.form_field_label.length && this.form_field.id.length) { 25603 this.form_field_label = $("label[for='" + this.form_field.id + "']"); 25604 } 25605 if (this.form_field_label.length > 0) { 25606 return this.form_field_label.bind('click.chosen', function(evt) { 25607 if (_this.is_multiple) { 25608 return _this.container_mousedown(evt); 25609 } else { 25610 return _this.activate_field(); 25611 } 25612 }); 25613 } 25614 }; 25615 25616 Chosen.prototype.show_search_field_default = function() { 25617 if (this.is_multiple && this.choices_count() < 1 && !this.active_field) { 25618 this.search_field.val(this.default_text); 25619 return this.search_field.addClass("default"); 25620 } else { 25621 this.search_field.val(""); 25622 return this.search_field.removeClass("default"); 25623 } 25624 }; 25625 25626 Chosen.prototype.search_results_mouseup = function(evt) { 25627 var target; 25628 target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); 25629 if (target.length) { 25630 this.result_highlight = target; 25631 this.result_select(evt); 25632 return this.search_field.focus(); 25633 } 25634 }; 25635 25636 Chosen.prototype.search_results_mouseover = function(evt) { 25637 var target; 25638 target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); 25639 if (target) { 25640 return this.result_do_highlight(target); 25641 } 25642 }; 25643 25644 Chosen.prototype.search_results_mouseout = function(evt) { 25645 if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { 25646 return this.result_clear_highlight(); 25647 } 25648 }; 25649 25650 Chosen.prototype.choice_build = function(item) { 25651 var choice, close_link, 25652 _this = this; 25653 choice = $('<li />', { 25654 "class": "search-choice" 25655 }).html("<span>" + (this.choice_label(item)) + "</span>"); 25656 if (item.disabled) { 25657 choice.addClass('search-choice-disabled'); 25658 } else { 25659 close_link = $('<a />', { 25660 "class": 'search-choice-close', 25661 'data-option-array-index': item.array_index 25662 }); 25663 close_link.bind('click.chosen', function(evt) { 25664 return _this.choice_destroy_link_click(evt); 25665 }); 25666 choice.append(close_link); 25667 } 25668 return this.search_container.before(choice); 25669 }; 25670 25671 Chosen.prototype.choice_destroy_link_click = function(evt) { 25672 evt.preventDefault(); 25673 evt.stopPropagation(); 25674 if (!this.is_disabled) { 25675 return this.choice_destroy($(evt.target)); 25676 } 25677 }; 25678 25679 Chosen.prototype.choice_destroy = function(link) { 25680 if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) { 25681 this.show_search_field_default(); 25682 if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) { 25683 this.results_hide(); 25684 } 25685 link.parents('li').first().remove(); 25686 return this.search_field_scale(); 25687 } 25688 }; 25689 25690 Chosen.prototype.results_reset = function() { 25691 this.reset_single_select_options(); 25692 this.form_field.options[0].selected = true; 25693 this.single_set_selected_text(); 25694 this.show_search_field_default(); 25695 this.results_reset_cleanup(); 25696 this.form_field_jq.trigger("change"); 25697 if (this.active_field) { 25698 return this.results_hide(); 25699 } 25700 }; 25701 25702 Chosen.prototype.results_reset_cleanup = function() { 25703 this.current_selectedIndex = this.form_field.selectedIndex; 25704 return this.selected_item.find("abbr").remove(); 25705 }; 25706 25707 Chosen.prototype.result_select = function(evt) { 25708 var high, item; 25709 if (this.result_highlight) { 25710 high = this.result_highlight; 25711 this.result_clear_highlight(); 25712 if (this.is_multiple && this.max_selected_options <= this.choices_count()) { 25713 this.form_field_jq.trigger("chosen:maxselected", { 25714 chosen: this 25715 }); 25716 return false;
vendor: 6,155 bytes, lines 25717-25888
25717 } 25718 if (this.is_multiple) { 25719 high.removeClass("active-result"); 25720 } else { 25721 this.reset_single_select_options(); 25722 } 25723 high.addClass("result-selected"); 25724 item = this.results_data[high[0].getAttribute("data-option-array-index")]; 25725 item.selected = true; 25726 this.form_field.options[item.options_index].selected = true; 25727 this.selected_option_count = null; 25728 if (this.is_multiple) { 25729 this.choice_build(item); 25730 } else { 25731 this.single_set_selected_text(this.choice_label(item)); 25732 } 25733 if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) { 25734 this.results_hide(); 25735 } 25736 this.show_search_field_default(); 25737 if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) { 25738 this.form_field_jq.trigger("change", { 25739 'selected': this.form_field.options[item.options_index].value 25740 }); 25741 } 25742 this.current_selectedIndex = this.form_field.selectedIndex; 25743 evt.preventDefault(); 25744 return this.search_field_scale(); 25745 } 25746 }; 25747 25748 Chosen.prototype.single_set_selected_text = function(text) { 25749 if (text == null) { 25750 text = this.default_text; 25751 } 25752 if (text === this.default_text) { 25753 this.selected_item.addClass("chosen-default"); 25754 } else { 25755 this.single_deselect_control_build(); 25756 this.selected_item.removeClass("chosen-default"); 25757 } 25758 return this.selected_item.find("span").html(text); 25759 }; 25760 25761 Chosen.prototype.result_deselect = function(pos) { 25762 var result_data; 25763 result_data = this.results_data[pos]; 25764 if (!this.form_field.options[result_data.options_index].disabled) { 25765 result_data.selected = false; 25766 this.form_field.options[result_data.options_index].selected = false; 25767 this.selected_option_count = null; 25768 this.result_clear_highlight(); 25769 if (this.results_showing) { 25770 this.winnow_results(); 25771 } 25772 this.form_field_jq.trigger("change", { 25773 deselected: this.form_field.options[result_data.options_index].value 25774 }); 25775 this.search_field_scale(); 25776 return true; 25777 } else { 25778 return false; 25779 } 25780 }; 25781 25782 Chosen.prototype.single_deselect_control_build = function() { 25783 if (!this.allow_single_deselect) { 25784 return; 25785 } 25786 if (!this.selected_item.find("abbr").length) { 25787 this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>"); 25788 } 25789 return this.selected_item.addClass("chosen-single-with-deselect"); 25790 }; 25791 25792 Chosen.prototype.get_search_text = function() { 25793 return $('<div/>').text($.trim(this.search_field.val())).html(); 25794 }; 25795 25796 Chosen.prototype.winnow_results_set_highlight = function() { 25797 var do_high, selected_results; 25798 selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : []; 25799 do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first(); 25800 if (do_high != null) { 25801 return this.result_do_highlight(do_high); 25802 } 25803 }; 25804 25805 Chosen.prototype.no_results = function(terms) { 25806 var no_results_html; 25807 no_results_html = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>'); 25808 no_results_html.find("span").first().html(terms); 25809 this.search_results.append(no_results_html); 25810 return this.form_field_jq.trigger("chosen:no_results", { 25811 chosen: this 25812 }); 25813 }; 25814 25815 Chosen.prototype.no_results_clear = function() { 25816 return this.search_results.find(".no-results").remove(); 25817 }; 25818 25819 Chosen.prototype.keydown_arrow = function() { 25820 var next_sib; 25821 if (this.results_showing && this.result_highlight) { 25822 next_sib = this.result_highlight.nextAll("li.active-result").first(); 25823 if (next_sib) { 25824 return this.result_do_highlight(next_sib); 25825 } 25826 } else { 25827 return this.results_show(); 25828 } 25829 }; 25830 25831 Chosen.prototype.keyup_arrow = function() { 25832 var prev_sibs; 25833 if (!this.results_showing && !this.is_multiple) { 25834 return this.results_show(); 25835 } else if (this.result_highlight) { 25836 prev_sibs = this.result_highlight.prevAll("li.active-result"); 25837 if (prev_sibs.length) { 25838 return this.result_do_highlight(prev_sibs.first()); 25839 } else { 25840 if (this.choices_count() > 0) { 25841 this.results_hide(); 25842 } 25843 return this.result_clear_highlight(); 25844 } 25845 } 25846 }; 25847 25848 Chosen.prototype.keydown_backstroke = function() { 25849 var next_available_destroy; 25850 if (this.pending_backstroke) { 25851 this.choice_destroy(this.pending_backstroke.find("a").first()); 25852 return this.clear_backstroke(); 25853 } else { 25854 next_available_destroy = this.search_container.siblings("li.search-choice").last(); 25855 if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) { 25856 this.pending_backstroke = next_available_destroy; 25857 if (this.single_backstroke_delete) { 25858 return this.keydown_backstroke(); 25859 } else { 25860 return this.pending_backstroke.addClass("search-choice-focus"); 25861 } 25862 } 25863 } 25864 }; 25865 25866 Chosen.prototype.clear_backstroke = function() { 25867 if (this.pending_backstroke) { 25868 this.pending_backstroke.removeClass("search-choice-focus"); 25869 } 25870 return this.pending_backstroke = null; 25871 }; 25872 25873 Chosen.prototype.keydown_checker = function(evt) { 25874 var stroke, _ref1; 25875 stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode; 25876 this.search_field_scale(); 25877 if (stroke !== 8 && this.pending_backstroke) { 25878 this.clear_backstroke(); 25879 } 25880 switch (stroke) { 25881 case 8: 25882 this.backstroke_length = this.search_field.val().length; 25883 break; 25884 case 9: 25885 if (this.results_showing && !this.is_multiple) { 25886 this.result_select(evt); 25887 } 25888 this.mouse_on_container = false;
25889 break; 25890 case 13: 25891 if (this.results_showing) { 25892 evt.preventDefault(); 25893 } 25894 break; 25895 case 32: 25896 if (this.disable_search) { 25897 evt.preventDefault(); 25898 } 25899 break; 25900 case 38: 25901 evt.preventDefault(); 25902 this.keyup_arrow(); 25903 break; 25904 case 40: 25905 evt.preventDefault(); 25906 this.keydown_arrow(); 25907 break; 25908 } 25909 }; 25910 25911 Chosen.prototype.search_field_scale = function() { 25912 var div, f_width, h, style, style_block, styles, w, _i, _len; 25913 if (this.is_multiple) { 25914 h = 0; 25915 w = 0; 25916 style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"; 25917 styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing']; 25918 for (_i = 0, _len = styles.length; _i < _len; _i++) { 25919 style = styles[_i]; 25920 style_block += style + ":" + this.search_field.css(style) + ";"; 25921 } 25922 div = $('<div />', { 25923 'style': style_block 25924 }); 25925 div.text(this.search_field.val()); 25926 $('body').append(div); 25927 w = div.width() + 25; 25928 div.remove(); 25929 f_width = this.container.outerWidth(); 25930 if (w > f_width - 10) { 25931 w = f_width - 10; 25932 } 25933 return this.search_field.css({ 25934 'width': w + 'px' 25935 }); 25936 } 25937 }; 25938 25939 return Chosen; 25940 25941 })(AbstractChosen); 25942 25943}).call(this); 25944/* 25945 25946 scrollup v2.3.2 25947 Author: Mark Goodyear - http://markgoodyear.com 25948 Git: https://github.com/markgoodyear/scrollup 25949 25950 Copyright 2014 Mark Goodyear. 25951 Licensed under the MIT license 25952 http://www.opensource.org/licenses/mit-license.php 25953 25954 Twitter: @markgdyr 25955 25956 */ 25957 25958(function($, window, document) { 25959 25960 // Main function 25961 $.fn.scrollUp = function (options) { 25962 25963 // Ensure that only one scrollUp exists 25964 if (!$.data(document.body, 'scrollUp')) { 25965 $.data(document.body, 'scrollUp', true); 25966 $.fn.scrollUp.init(options); 25967 } 25968 }; 25969 25970 // Init 25971 $.fn.scrollUp.init = function(options) { 25972 25973 // Apply any options to the settings, override the defaults 25974 var o = $.fn.scrollUp.settings = $.extend({}, $.fn.scrollUp.defaults, options), 25975 25976 // Create element 25977 $self; 25978 if (o.scrollTrigger) { 25979 $self = $(o.scrollTrigger); 25980 } else { 25981 $self = $('<a/>', { 25982 id: o.scrollName, 25983 href: '#top' 25984 }); 25985 } 25986 25987 // Set scrollTitle if there is one 25988 if (o.scrollTitle) { 25989 $self.attr('title', o.scrollTitle); 25990 } 25991 25992 $self.appendTo('body'); 25993 25994 // If not using an image display text 25995 if (!(o.scrollImg || o.scrollTrigger)) { 25996 $self.html(o.scrollText); 25997 } 25998 25999 // Minimum CSS to make the magic happen 26000 $self.css({ 26001 display: 'none', 26002 position: 'fixed', 26003 zIndex: o.zIndex 26004 }); 26005 26006 // Active point overlay 26007 if (o.activeOverlay) { 26008 $('<div/>', { id: o.scrollName + '-active' }).css({ position: 'absolute', 'top': o.scrollDistance + 'px', width: '100%', borderTop: '1px dotted' + o.activeOverlay, zIndex: o.zIndex }).appendTo('body'); 26009 } 26010 26011 // Switch animation type 26012 var animIn, animOut, animSpeed, scrollDis; 26013 26014 switch (o.animation) { 26015 case 'fade': 26016 animIn = 'fadeIn'; 26017 animOut = 'fadeOut'; 26018 animSpeed = o.animationInSpeed; 26019 break; 26020 case 'slide': 26021 animIn = 'slideDown'; 26022 animOut = 'slideUp'; 26023 animSpeed = o.animationInSpeed; 26024 break; 26025 default: 26026 animIn = 'show'; 26027 animOut = 'hide'; 26028 animSpeed = 0; 26029 } 26030 26031 // If from top or bottom 26032 if (o.scrollFrom === 'top') { 26033 scrollDis = o.scrollDistance; 26034 } else { 26035 scrollDis = $(document).height() - $(window).height() - o.scrollDistance; 26036 } 26037 26038 // Trigger visible false by default 26039 var triggerVisible = false;
26040 26041 // Scroll function 26042 scrollEvent = $(window).scroll(function() { 26043 if ( $(window).scrollTop() > scrollDis ) { 26044 if (!triggerVisible) { 26045 $self[animIn](animSpeed); 26046 triggerVisible = true; 26047 } 26048 } else { 26049 if (triggerVisible) { 26050 $self[animOut](animSpeed); 26051 triggerVisible = false; 26052 } 26053 } 26054 }); 26055 26056 var scrollTarget; 26057 if (o.scrollTarget) { 26058 if (typeof o.scrollTarget === 'number') { 26059 scrollTarget = o.scrollTarget; 26060 } else if (typeof o.scrollTarget === 'string') { 26061 scrollTarget = Math.floor($(o.scrollTarget).offset().top); 26062 } 26063 } else { 26064 scrollTarget = 0; 26065 } 26066 26067 // To the top 26068 $self.click(function(e) { 26069 e.preventDefault(); 26070 26071 $('html, body').animate({ 26072 scrollTop: scrollTarget 26073 }, o.scrollSpeed, o.easingType); 26074 }); 26075 }; 26076 26077 // Defaults 26078 $.fn.scrollUp.defaults = { 26079 scrollName: 'scrollUp', // Element ID 26080 scrollDistance: 300, // Distance from top/bottom before showing element (px) 26081 scrollFrom: 'top', // 'top' or 'bottom' 26082 scrollSpeed: 300, // Speed back to top (ms) 26083 easingType: 'linear', // Scroll to top easing (see http://easings.net/) 26084 animation: 'fade', // Fade, slide, none 26085 animationInSpeed: 200, // Animation in speed (ms) 26086 animationOutSpeed: 200, // Animation out speed (ms) 26087 scrollTrigger: false, // Set a custom triggering element. Can be an HTML string or jQuery object 26088 scrollTarget: false, // Set a custom target element for scrolling to. Can be element or number 26089 scrollText: 'Scroll to top', // Text for element, can contain HTML 26090 scrollTitle: false, // Set a custom <a> title if required. Defaults to scrollText 26091 scrollImg: false, // Set true to use image 26092 activeOverlay: false, // Set CSS color to display scrollUp active point, e.g '#00FFFF' 26093 zIndex: 2147483647 // Z-Index for the overlay 26094 }; 26095 26096 // Destroy scrollUp plugin and clean all modifications to the DOM 26097 $.fn.scrollUp.destroy = function (scrollEvent){ 26098 $.removeData( document.body, 'scrollUp' ); 26099 $( '#' + $.fn.scrollUp.settings.scrollName ).remove(); 26100 $( '#' + $.fn.scrollUp.settings.scrollName + '-active' ).remove(); 26101 26102 // If 1.7 or above use the new .off() 26103 if ($.fn.jquery.split('.')[1] >= 7) { 26104 $(window).off( 'scroll', scrollEvent ); 26105 26106 // Else use the old .unbind() 26107 } else { 26108 $(window).unbind( 'scroll', scrollEvent ); 26109 } 26110 }; 26111 26112 $.scrollUp = $.fn.scrollUp; 26113 26114})(jQuery, window, document); 26115// Sticky Plugin v1.0.0 for jQuery 26116// ============= 26117// Author: Anthony Garand 26118// Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk) 26119// Improvements by Leonardo C. Daronco (daronco) 26120// Created: 2/14/2011 26121// Date: 2/12/2012 26122// Website: http://labs.anthonygarand.com/sticky 26123// Description: Makes an element on the page stick on the screen as you scroll 26124// It will only set the 'top' and 'position' of your element, you 26125// might need to adjust the width in some cases. 26126 26127(function($) { 26128 var defaults = { 26129 topSpacing: 0, 26130 bottomSpacing: 0, 26131 className: 'is-sticky', 26132 wrapperClassName: 'sticky-wrapper', 26133 center: false, 26134 getWidthFrom: '' 26135 }, 26136 $window = $(window), 26137 $document = $(document), 26138 sticked = [], 26139 windowHeight = $window.height(), 26140 scroller = function() { 26141 var scrollTop = $window.scrollTop(), 26142 documentHeight = $document.height(), 26143 dwh = documentHeight - windowHeight, 26144 extra = (scrollTop > dwh) ? dwh - scrollTop : 0; 26145 26146 for (var i = 0; i < sticked.length; i++) { 26147 var s = sticked[i], 26148 elementTop = s.stickyWrapper.offset().top, 26149 etse = elementTop - s.topSpacing - extra; 26150 26151 if (scrollTop <= etse) { 26152 if (s.currentTop !== null) { 26153 s.stickyElement 26154 .css('position', '') 26155 .css('top', ''); 26156 s.stickyElement.parent().removeClass(s.className); 26157 s.currentTop = null; 26158 } 26159 } 26160 else { 26161 var newTop = documentHeight - s.stickyElement.outerHeight() 26162 - s.topSpacing - s.bottomSpacing - scrollTop - extra; 26163 if (newTop < 0) { 26164 newTop = newTop + s.topSpacing; 26165 } else { 26166 newTop = s.topSpacing; 26167 } 26168 if (s.currentTop != newTop) { 26169 s.stickyElement 26170 .css('position', 'fixed') 26171 .css('top', newTop); 26172 26173 if (typeof s.getWidthFrom !== 'undefined') { 26174 s.stickyElement.css('width', $(s.getWidthFrom).width()); 26175 } 26176 26177 s.stickyElement.parent().addClass(s.className); 26178 s.currentTop = newTop; 26179 } 26180 } 26181 } 26182 }, 26183 resizer = function() { 26184 windowHeight = $window.height(); 26185 }, 26186 methods = { 26187 init: function(options) { 26188 var o = $.extend(defaults, options); 26189 return this.each(function() { 26190 var stickyElement = $(this); 26191 26192 var stickyId = stickyElement.attr('id');
26193 var wrapper = $('<div></div>') 26194 .attr('id', stickyId + '-sticky-wrapper') 26195 .addClass(o.wrapperClassName); 26196 stickyElement.wrapAll(wrapper); 26197 26198 if (o.center) { 26199 stickyElement.parent().css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"}); 26200 } 26201 26202 if (stickyElement.css("float") == "right") { 26203 stickyElement.css({"float":"none"}).parent().css({"float":"right"}); 26204 } 26205 26206 var stickyWrapper = stickyElement.parent(); 26207 stickyWrapper.css('height', stickyElement.outerHeight()); 26208 sticked.push({ 26209 topSpacing: o.topSpacing, 26210 bottomSpacing: o.bottomSpacing, 26211 stickyElement: stickyElement, 26212 currentTop: null, 26213 stickyWrapper: stickyWrapper, 26214 className: o.className, 26215 getWidthFrom: o.getWidthFrom 26216 }); 26217 }); 26218 }, 26219 update: scroller 26220 }; 26221 26222 // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): 26223 if (window.addEventListener) { 26224 window.addEventListener('scroll', scroller, false); 26225 window.addEventListener('resize', resizer, false); 26226 } else if (window.attachEvent) { 26227 window.attachEvent('onscroll', scroller); 26228 window.attachEvent('onresize', resizer); 26229 } 26230 26231 $.fn.sticky = function(method) { 26232 if (methods[method]) { 26233 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 26234 } else if (typeof method === 'object' || !method ) { 26235 return methods.init.apply( this, arguments ); 26236 } else { 26237 $.error('Method ' + method + ' does not exist on jQuery.sticky'); 26238 } 26239 }; 26240 $(function() { 26241 setTimeout(scroller, 0); 26242 }); 26243})(jQuery); 26244/* 26245 * jQuery plugin for easily checking/unchecking all checkboxes 26246 * 26247 * Copyright (c) 2013 Edmundas Kondrasovas 26248 * Dual licensed under the MIT and GPL licenses. 26249 * Uses the same license as jQuery, see: 26250 * http://docs.jquery.com/License 26251 * 26252 */ 26253 26254(function($) { 26255 26256 $.fn.checkControl = function() { 26257 return this.each(function() { 26258 var $this = $(this), 26259 target = $this.data("targets"), 26260 action = $this.data("action"); 26261 26262 $this.on("click", function(e) { 26263 if(action == "check") { 26264 $(target).prop("checked", true); 26265 } else if(action == "uncheck") { 26266 $(target).prop("checked", false); 26267 } 26268 26269 $(target).trigger("change"); 26270 26271 e.preventDefault(); 26272 return false; 26273 }); 26274 }); 26275 }; 26276 26277})(jQuery); 26278/* 26279 * jQuery Easing v1.4.0 - http://gsgd.co.uk/sandbox/jquery/easing/ 26280 * Open source under the BSD License. 26281 * Copyright © 2008 George McGinley Smith 26282 * All rights reserved. 26283 * https://raw.github.com/gdsmith/jquery-easing/master/LICENSE 26284 */ 26285 26286 26287(function (factory) { 26288 if (typeof define === "function" && define.amd) { 26289 define(['jquery'], function ($) { 26290 return factory($); 26291 }); 26292 } else if (typeof module === "object" && typeof module.exports === "object") { 26293 exports = factory(require('jquery')); 26294 } else { 26295 factory(jQuery); 26296 } 26297})(function($){ 26298 26299 // Preserve the original jQuery "swing" easing as "jswing" 26300 $.easing['jswing'] = $.easing['swing']; 26301 26302 var pow = Math.pow, 26303 sqrt = Math.sqrt, 26304 sin = Math.sin, 26305 cos = Math.cos, 26306 PI = Math.PI, 26307 c1 = 1.70158, 26308 c2 = c1 * 1.525, 26309 c3 = c1 + 1, 26310 c4 = ( 2 * PI ) / 3, 26311 c5 = ( 2 * PI ) / 4.5; 26312 26313 // x is the fraction of animation progress, in the range 0..1 26314 function bounceOut(x) { 26315 var n1 = 7.5625, 26316 d1 = 2.75; 26317 if ( x < 1/d1 ) { 26318 return n1*x*x; 26319 } else if ( x < 2/d1 ) { 26320 return n1*(x-=(1.5/d1))*x + .75; 26321 } else if ( x < 2.5/d1 ) { 26322 return n1*(x-=(2.25/d1))*x + .9375; 26323 } else { 26324 return n1*(x-=(2.625/d1))*x + .984375; 26325 } 26326 } 26327 26328 $.extend( $.easing, 26329 { 26330 def: 'easeOutQuad', 26331 swing: function (x) { 26332 return $.easing[$.easing.def](x); 26333 }, 26334 easeInQuad: function (x) { 26335 return x * x; 26336 }, 26337 easeOutQuad: function (x) { 26338 return 1 - ( 1 - x ) * ( 1 - x ); 26339 }, 26340 easeInOutQuad: function (x) { 26341 return x < 0.5 ? 26342 2 * x * x : 26343 1 - pow( -2 * x + 2, 2 ) / 2; 26344 }, 26345 easeInCubic: function (x) { 26346 return x * x * x; 26347 }, 26348 easeOutCubic: function (x) { 26349 return 1 - pow( 1 - x, 3 ); 26350 }, 26351 easeInOutCubic: function (x) { 26352 return x < 0.5 ? 26353 4 * x * x * x : 26354 1 - pow( -2 * x + 2, 3 ) / 2; 26355 }, 26356 easeInQuart: function (x) { 26357 return x * x * x * x; 26358 }, 26359 easeOutQuart: function (x) { 26360 return 1 - pow( 1 - x, 4 ); 26361 }, 26362 easeInOutQuart: function (x) { 26363 return x < 0.5 ? 26364 8 * x * x * x * x : 26365 1 - pow( -2 * x + 2, 4 ) / 2; 26366 }, 26367 easeInQuint: function (x) { 26368 return x * x * x * x * x; 26369 }, 26370 easeOutQuint: function (x) { 26371 return 1 - pow( 1 - x, 5 ); 26372 }, 26373 easeInOutQuint: function (x) { 26374 return x < 0.5 ? 26375 16 * x * x * x * x * x : 26376 1 - pow( -2 * x + 2, 5 ) / 2; 26377 }, 26378 easeInSine: function (x) { 26379 return 1 - cos( x * PI/2 ); 26380 }, 26381 easeOutSine: function (x) { 26382 return sin( x * PI/2 ); 26383 }, 26384 easeInOutSine: function (x) { 26385 return -( cos( PI * x ) - 1 ) / 2; 26386 }, 26387 easeInExpo: function (x) { 26388 return x === 0 ? 0 : pow( 2, 10 * x - 10 ); 26389 }, 26390 easeOutExpo: function (x) { 26391 return x === 1 ? 1 : 1 - pow( 2, -10 * x ); 26392 }, 26393 easeInOutExpo: function (x) { 26394 return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? 26395 pow( 2, 20 * x - 10 ) / 2 : 26396 ( 2 - pow( 2, -20 * x + 10 ) ) / 2; 26397 }, 26398 easeInCirc: function (x) { 26399 return 1 - sqrt( 1 - pow( x, 2 ) ); 26400 }, 26401 easeOutCirc: function (x) { 26402 return sqrt( 1 - pow( x - 1, 2 ) ); 26403 }, 26404 easeInOutCirc: function (x) { 26405 return x < 0.5 ? 26406 ( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 : 26407 ( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2; 26408 }, 26409 easeInElastic: function (x) { 26410 return x === 0 ? 0 : x === 1 ? 1 : 26411 -pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 ); 26412 }, 26413 easeOutElastic: function (x) { 26414 return x === 0 ? 0 : x === 1 ? 1 : 26415 pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1; 26416 }, 26417 easeInOutElastic: function (x) { 26418 return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? 26419 -( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 : 26420 pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1; 26421 }, 26422 easeInBack: function (x) { 26423 return c3 * x * x * x - c1 * x * x; 26424 }, 26425 easeOutBack: function (x) { 26426 return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 ); 26427 }, 26428 easeInOutBack: function (x) { 26429 return x < 0.5 ? 26430 ( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 : 26431 ( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2; 26432 }, 26433 easeInBounce: function (x) { 26434 return 1 - bounceOut( 1 - x ); 26435 }, 26436 easeOutBounce: bounceOut, 26437 easeInOutBounce: function (x) { 26438 return x < 0.5 ? 26439 ( 1 - bounceOut( 1 - 2 * x ) ) / 2 : 26440 ( 1 + bounceOut( 2 * x - 1 ) ) / 2; 26441 } 26442 }); 26443 26444}); 26445/** 26446 * Timeago is a jQuery plugin that makes it easy to support automatically 26447 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). 26448 * 26449 * @name timeago 26450 * @version 1.4.1 26451 * @requires jQuery v1.2.3+ 26452 * @author Ryan McGeary 26453 * @license MIT License - http://www.opensource.org/licenses/mit-license.php 26454 * 26455 * For usage and examples, visit: 26456 * http://timeago.yarp.com/ 26457 * 26458 * Copyright (c) 2008-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) 26459 */ 26460 26461 26462(function (factory) { 26463 if (typeof define === 'function' && define.amd) { 26464 // AMD. Register as an anonymous module. 26465 define(['jquery'], factory); 26466 } else { 26467 // Browser globals 26468 factory(jQuery); 26469 } 26470}(function ($) { 26471 $.timeago = function(timestamp) { 26472 if (timestamp instanceof Date) { 26473 return inWords(timestamp); 26474 } else if (typeof timestamp === "string") {
vendor: 4,206 bytes, lines 26475-26595
26475 return inWords($.timeago.parse(timestamp)); 26476 } else if (typeof timestamp === "number") { 26477 return inWords(new Date(timestamp)); 26478 } else { 26479 return inWords($.timeago.datetime(timestamp)); 26480 } 26481 }; 26482 var $t = $.timeago; 26483 26484 $.extend($.timeago, { 26485 settings: { 26486 refreshMillis: 60000, 26487 allowPast: true, 26488 allowFuture: false, 26489 localeTitle: false, 26490 cutoff: 0, 26491 strings: { 26492 prefixAgo: null, 26493 prefixFromNow: null, 26494 suffixAgo: "ago", 26495 suffixFromNow: "from now", 26496 inPast: 'any moment now', 26497 seconds: "less than a minute", 26498 minute: "about a minute", 26499 minutes: "%d minutes", 26500 hour: "about an hour", 26501 hours: "about %d hours", 26502 day: "a day", 26503 days: "%d days", 26504 month: "about a month", 26505 months: "%d months", 26506 year: "about a year", 26507 years: "%d years", 26508 wordSeparator: " ", 26509 numbers: [] 26510 } 26511 }, 26512 26513 inWords: function(distanceMillis) { 26514 if(!this.settings.allowPast && ! this.settings.allowFuture) { 26515 throw 'timeago allowPast and allowFuture settings can not both be set to false.'; 26516 } 26517 26518 var $l = this.settings.strings; 26519 var prefix = $l.prefixAgo; 26520 var suffix = $l.suffixAgo; 26521 if (this.settings.allowFuture) { 26522 if (distanceMillis < 0) { 26523 prefix = $l.prefixFromNow; 26524 suffix = $l.suffixFromNow; 26525 } 26526 } 26527 26528 if(!this.settings.allowPast && distanceMillis >= 0) { 26529 return this.settings.strings.inPast; 26530 } 26531 26532 var seconds = Math.abs(distanceMillis) / 1000; 26533 var minutes = seconds / 60; 26534 var hours = minutes / 60; 26535 var days = hours / 24; 26536 var years = days / 365; 26537 26538 function substitute(stringOrFunction, number) { 26539 var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; 26540 var value = ($l.numbers && $l.numbers[number]) || number; 26541 return string.replace(/%d/i, value); 26542 } 26543 26544 var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || 26545 seconds < 90 && substitute($l.minute, 1) || 26546 minutes < 45 && substitute($l.minutes, Math.round(minutes)) || 26547 minutes < 90 && substitute($l.hour, 1) || 26548 hours < 24 && substitute($l.hours, Math.round(hours)) || 26549 hours < 42 && substitute($l.day, 1) || 26550 days < 30 && substitute($l.days, Math.round(days)) || 26551 days < 45 && substitute($l.month, 1) || 26552 days < 365 && substitute($l.months, Math.round(days / 30)) || 26553 years < 1.5 && substitute($l.year, 1) || 26554 substitute($l.years, Math.round(years)); 26555 26556 var separator = $l.wordSeparator || ""; 26557 if ($l.wordSeparator === undefined) { separator = " "; } 26558 return $.trim([prefix, words, suffix].join(separator)); 26559 }, 26560 26561 parse: function(iso8601) { 26562 var s = $.trim(iso8601); 26563 s = s.replace(/\.\d+/,""); // remove milliseconds 26564 s = s.replace(/-/,"/").replace(/-/,"/"); 26565 s = s.replace(/T/," ").replace(/Z/," UTC"); 26566 s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 26567 s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900 26568 return new Date(s); 26569 }, 26570 datetime: function(elem) { 26571 var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title"); 26572 return $t.parse(iso8601); 26573 }, 26574 isTime: function(elem) { 26575 // jQuery's `is()` doesn't play well with HTML5 in IE 26576 return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); 26577 } 26578 }); 26579 26580 // functions that can be called via $(el).timeago('action') 26581 // init is default when no action is given 26582 // functions are called with context of a single element 26583 var functions = { 26584 init: function(){ 26585 var refresh_el = $.proxy(refresh, this); 26586 refresh_el(); 26587 var $s = $t.settings; 26588 if ($s.refreshMillis > 0) { 26589 this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis); 26590 } 26591 }, 26592 update: function(time){ 26593 var parsedTime = $t.parse(time); 26594 $(this).data('timeago', { datetime: parsedTime }); 26595 if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleStr
26595ing()); 26596 refresh.apply(this); 26597 }, 26598 updateFromDOM: function(){ 26599 $(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) }); 26600 refresh.apply(this); 26601 }, 26602 dispose: function () { 26603 if (this._timeagoInterval) { 26604 window.clearInterval(this._timeagoInterval); 26605 this._timeagoInterval = null; 26606 } 26607 } 26608 }; 26609 26610 $.fn.timeago = function(action, options) { 26611 var fn = action ? functions[action] : functions.init; 26612 if(!fn){ 26613 throw new Error("Unknown function name '"+ action +"' for timeago"); 26614 } 26615 // each over objects here and call the requested function 26616 this.each(function(){ 26617 fn.call(this, options); 26618 }); 26619 return this; 26620 }; 26621 26622 function refresh() { 26623 //check if it's still visible 26624 if(!$.contains(document.documentElement,this)){ 26625 //stop if it has been removed 26626 $(this).timeago("dispose"); 26627 return this; 26628 } 26629 26630 var data = prepareData(this); 26631 var $s = $t.settings; 26632 26633 if (!isNaN(data.datetime)) { 26634 if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) { 26635 $(this).text(inWords(data.datetime)); 26636 } 26637 } 26638 return this; 26639 } 26640 26641 function prepareData(element) { 26642 element = $(element); 26643 if (!element.data("timeago")) { 26644 element.data("timeago", { datetime: $t.datetime(element) }); 26645 var text = $.trim(element.text()); 26646 if ($t.settings.localeTitle) { 26647 element.attr("title", element.data('timeago').datetime.toLocaleString()); 26648 } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { 26649 element.attr("title", text); 26650 } 26651 } 26652 return element.data("timeago"); 26653 } 26654 26655 function inWords(date) { 26656 return $t.inWords(distance(date)); 26657 } 26658 26659 function distance(date) { 26660 return (new Date().getTime() - date.getTime()); 26661 } 26662 26663 // fix for IE6 suckage 26664 document.createElement("abbr"); 26665 document.createElement("time"); 26666})); 26667/*! 26668 * imagesLoaded PACKAGED v3.1.4 26669 * JavaScript is all like "You images are done yet or what?" 26670 * MIT License 26671 */ 26672 26673 26674/*! 26675 * EventEmitter v4.2.6 - git.io/ee 26676 * Oliver Caldwell 26677 * MIT license 26678 * @preserve 26679 */ 26680 26681 26682(function () { 26683 26684 26685 /** 26686 * Class for managing events. 26687 * Can be extended to provide event functionality in other classes. 26688 * 26689 * @class EventEmitter Manages event registering and emitting. 26690 */ 26691 function EventEmitter() {} 26692 26693 // Shortcuts to improve speed and size 26694 var proto = EventEmitter.prototype; 26695 var exports = this; 26696 var originalGlobalValue = exports.EventEmitter; 26697 26698 /** 26699 * Finds the index of the listener for the event in it's storage array. 26700 * 26701 * @param {Function[]} listeners Array of listeners to search through. 26702 * @param {Function} listener Method to look for. 26703 * @return {Number} Index of the specified listener, -1 if not found 26704 * @api private 26705 */ 26706 function indexOfListener(listeners, listener) { 26707 var i = listeners.length; 26708 while (i--) { 26709 if (listeners[i].listener === listener) { 26710 return i; 26711 } 26712 } 26713 26714 return -1; 26715 } 26716 26717 /** 26718 * Alias a method while keeping the context correct, to allow for overwriting of target method. 26719 * 26720 * @param {String} name The name of the target method. 26721 * @return {Function} The aliased method 26722 * @api private 26723 */ 26724 function alias(name) { 26725 return function aliasClosure() { 26726 return this[name].apply(this, arguments); 26727 }; 26728 } 26729 26730 /** 26731 * Returns the listener array for the specified event. 26732 * Will initialise the event object and listener arrays if required. 26733 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object c
26733ontaining bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 26734 * Each property in the object response is an array of listener functions. 26735 * 26736 * @param {String|RegExp} evt Name of the event to return the listeners from. 26737 * @return {Function[]|Object} All listener functions for the event. 26738 */ 26739 proto.getListeners = function getListeners(evt) { 26740 var events = this._getEvents(); 26741 var response; 26742 var key; 26743 26744 // Return a concatenated array of all matching events if 26745 // the selector is a regular expression. 26746 if (typeof evt === 'object') { 26747 response = {}; 26748 for (key in events) { 26749 if (events.hasOwnProperty(key) && evt.test(key)) { 26750 response[key] = events[key]; 26751 } 26752 } 26753 } 26754 else { 26755 response = events[evt] || (events[evt] = []); 26756 } 26757 26758 return response; 26759 }; 26760 26761 /** 26762 * Takes a list of listener objects and flattens it into a list of listener functions. 26763 * 26764 * @param {Object[]} listeners Raw listener objects. 26765 * @return {Function[]} Just the listener functions. 26766 */ 26767 proto.flattenListeners = function flattenListeners(listeners) { 26768 var flatListeners = []; 26769 var i; 26770 26771 for (i = 0; i < listeners.length; i += 1) { 26772 flatListeners.push(listeners[i].listener); 26773 } 26774 26775 return flatListeners; 26776 }; 26777 26778 /** 26779 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. 26780 * 26781 * @param {String|RegExp} evt Name of the event to return the listeners from. 26782 * @return {Object} All listener functions for an event in an object. 26783 */ 26784 proto.getListenersAsObject = function getListenersAsObject(evt) { 26785 var listeners = this.getListeners(evt); 26786 var response; 26787 26788 if (listeners instanceof Array) { 26789 response = {}; 26790 response[evt] = listeners; 26791 } 26792 26793 return response || listeners; 26794 }; 26795 26796 /** 26797 * Adds a listener function to the specified event. 26798 * The listener will not be added if it is a duplicate. 26799 * If the listener returns true then it will be removed after it is called. 26800 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 26801 * 26802 * @param {String|RegExp} evt Name of the event to attach the listener to. 26803 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 26804 * @return {Object} Current instance of EventEmitter for chaining. 26805 */ 26806 proto.addListener = function addListener(evt, listener) { 26807 var listeners = this.getListenersAsObject(evt); 26808 var listenerIsWrapped = typeof listener === 'object'; 26809 var key; 26810 26811 for (key in listeners) { 26812 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 26813 listeners[key].push(listenerIsWrapped ? listener : { 26814 listener: listener, 26815 once: false 26816 }); 26817 } 26818 } 26819 26820 return this; 26821 }; 26822 26823 /** 26824 * Alias of addListener 26825 */ 26826 proto.on = alias('addListener'); 26827 26828 /** 26829 * Semi-alias of addListener. It will add a listener that will be 26830 * automatically removed after it's first execution. 26831 * 26832 * @param {String|RegExp} evt Name of the event to attach the listener to. 26833 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 26834 * @return {Object} Current instance of EventEmitter for chaining. 26835 */ 26836 proto.addOnceListener = function addOnceListener(evt, listener) { 26837 return this.addListener(evt, { 26838 listener: listener, 26839 once: true 26840 }); 26841 }; 26842 26843 /** 26844 * Alias of addOnceListener. 26845 */ 26846 proto.once = alias('addOnceListener'); 26847 26848 /** 26849 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. 26850 * You need to tell it what event names should be matched by a regex. 26851 * 26852 * @param {String} evt Name of the event to create. 26853 * @return {Object} Current instance of EventEmitter for chaining. 26854 */ 26855 proto.defineEvent = function defineEvent(evt) { 26856 this.getListeners(evt); 26857 return this; 26858 }; 26859 26860 /** 26861 * Uses defineEvent to define multiple events. 26862 * 26863 * @param {String[]} evts An array of event names to define. 26864 * @return {Object} Current instance of EventEmitter for chaining. 26865 */ 26866 proto.defineEvents = function defineEvents(evts) { 26867 for (var i = 0; i < evts.length; i += 1) { 26868 this.defineEvent(evts[i]); 26869 } 26870 return this; 26871 }; 26872 26873 /** 26874 * Removes a listener function from the specified event. 26875 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 26876 * 26877 * @param {String|RegExp} evt Name of the event to remove the listener from. 26878 * @param {Function} listener Method to remove from the event. 26879 * @return {Object} Current instance of EventEmitter for chaining. 26880 */ 26881 proto.removeListener = function removeListener(evt, listener) { 26882 var listeners = this.getListenersAsObject(evt); 26883 var index; 26884 var key; 26885 26886 for (key in listeners) { 26887 if (listeners.hasOwnProperty(key)) { 26888 index = indexOfListener(listeners[key], listener); 26889 26890 if (index !== -1) { 26891 listeners[key].splice(index, 1); 26892 } 26893 } 26894 } 26895 26896 return this; 26897 }; 26898 26899 /** 26900 * Alias of removeListener 26901 */ 26902 proto.off = alias('removeListener'); 26903 26904 /** 26905 * Adds listeners in bulk using the manipulateListeners method. 26906 * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. 26907 * You can also pass it a regular expression to add the array of listeners to all events that match it. 26908 * Yeah, this function does quite a bit. That's probably a bad thing. 26909 * 26910 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. 26911 * @param {Function[]} [listeners] An optional array of listener functions to add. 26912 * @return {Object} Current instance of EventEmitter for chaining. 26913 */ 26914 proto.addListeners = function addListeners(evt, listeners) { 26915 // Pass through to manipulateListeners 26916 return this.manipulateListeners(false, evt, listeners); 26917 }; 26918 26919 /** 26920 * Removes listeners in bulk using the manipulateListeners method. 26921 * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 26922 * You can also pass it an event name and an array of listeners to be removed. 26923 * You can also pass it a regular expression to remove the listeners from all events that match it. 26924 * 26925 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. 26926 * @param {Function[]} [listeners] An optional array of listener functions to remove. 26927 * @return {Object} Current instance of EventEmitter for chaining. 26928 */ 26929 proto.removeListeners = function removeListeners(evt, listeners) { 26930 // Pass through to manipulateListeners 26931 return this.manipulateListeners(true, evt, listeners); 26932 }; 26933 26934 /** 26935 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. 26936 * The first argument will determine if the listeners are removed (true) or added (false). 26937 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 26938 * You can also pass it an event name and an array of listeners to be added/removed. 26939 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 26940 * 26941 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 26942 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. 26943 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 26944 * @return {Object} Current instance of EventEmitter for chaining. 26945 */ 26946 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 26947 var i; 26948 var value; 26949 var single = remove ? this.removeListener : this.addListener; 26950 var multiple = remove ? this.removeListeners : this.addListeners; 26951 26952 // If evt is an object then pass each of it's properties to this method 26953 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 26954 for (i in evt) { 26955 if (evt.hasOwnProperty(i) && (value = evt[i])) { 26956 // Pass the single listener straight through to the singular method 26957 if (typeof value === 'function') { 26958 single.call(this, i, value); 26959 } 26960 else { 26961 // Otherwise pass back to the multiple function 26962 multiple.call(this, i, value); 26963 } 26964 } 26965 } 26966 } 26967 else { 26968 // So evt must be a string 26969 // And listeners must be an array of listeners 26970 // Loop over it and pass each one to the multiple method 26971 i = listeners.length; 26972 while (i--) { 26973 single.call(this, evt, listeners[i]); 26974 } 26975 } 26976 26977 return this; 26978 }; 26979 26980 /** 26981 * Removes all listeners from a specified event. 26982 * If you do not specify an event then all listeners will be removed. 26983 * That means every event will be emptied. 26984 * You can also pass a regex to remove all events that match it. 26985 * 26986 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 26987 * @return {Object} Current instance of EventEmitter for chaining. 26988 */ 26989 proto.removeEvent = function removeEvent(evt) { 26990 var type = typeof evt; 26991 var events = this._getEvents(); 26992 var key; 26993 26994 // Remove different things depending on the state of evt 26995 if (type === 'string') { 26996 // Remove all listeners for the specified event 26997 delete events[evt]; 26998 } 26999 else if (type === 'object') { 27000 // Remove all events matching the regex. 27001 for (key in events) { 27002 if (events.hasOwnProperty(key) && evt.test(key)) { 27003 delete events[key]; 27004 } 27005 } 27006 } 27007 else { 27008 // Remove all listeners in all events 27009 delete this._events; 27010 } 27011 27012 return this; 27013 }; 27014 27015 /** 27016 * Alias of removeEvent. 27017 * 27018 * Added to mirror the node API. 27019 */ 27020 proto.removeAllListeners = alias('removeEvent'); 27021 27022 /** 27023 * Emits an event of your choice. 27024 * When emitted, every listener attached to that event will be executed. 27025 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 27026 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
27027 * So they will not arrive within the array on the other side, they will be separate. 27028 * You can also pass a regular expression to emit to all events that match it. 27029 * 27030 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 27031 * @param {Array} [args] Optional array of arguments to be passed to each listener. 27032 * @return {Object} Current instance of EventEmitter for chaining. 27033 */ 27034 proto.emitEvent = function emitEvent(evt, args) { 27035 var listeners = this.getListenersAsObject(evt); 27036 var listener; 27037 var i; 27038 var key; 27039 var response; 27040 27041 for (key in listeners) { 27042 if (listeners.hasOwnProperty(key)) { 27043 i = listeners[key].length; 27044 27045 while (i--) { 27046 // If the listener returns true then it shall be removed from the event 27047 // The function is executed either with a basic call or an apply if there is an args array 27048 listener = listeners[key][i]; 27049 27050 if (listener.once === true) { 27051 this.removeListener(evt, listener.listener); 27052 } 27053 27054 response = listener.listener.apply(this, args || []); 27055 27056 if (response === this._getOnceReturnValue()) { 27057 this.removeListener(evt, listener.listener); 27058 } 27059 } 27060 } 27061 } 27062 27063 return this; 27064 }; 27065 27066 /** 27067 * Alias of emitEvent 27068 */ 27069 proto.trigger = alias('emitEvent'); 27070 27071 /** 27072 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. 27073 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 27074 * 27075 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 27076 * @param {...*} Optional additional arguments to be passed to each listener. 27077 * @return {Object} Current instance of EventEmitter for chaining. 27078 */ 27079 proto.emit = function emit(evt) { 27080 var args = Array.prototype.slice.call(arguments, 1); 27081 return this.emitEvent(evt, args); 27082 }; 27083 27084 /** 27085 * Sets the current value to check against when executing listeners. If a 27086 * listeners return value matches the one set here then it will be removed 27087 * after execution. This value defaults to true. 27088 * 27089 * @param {*} value The new value to check for when executing listeners. 27090 * @return {Object} Current instance of EventEmitter for chaining. 27091 */ 27092 proto.setOnceReturnValue = function setOnceReturnValue(value) { 27093 this._onceReturnValue = value; 27094 return this; 27095 }; 27096 27097 /** 27098 * Fetches the current value to check against when executing listeners. If 27099 * the listeners return value matches this one then it should be removed 27100 * automatically. It will return true by default. 27101 * 27102 * @return {*|Boolean} The current value to check for or the default, true. 27103 * @api private 27104 */ 27105 proto._getOnceReturnValue = function _getOnceReturnValue() { 27106 if (this.hasOwnProperty('_onceReturnValue')) { 27107 return this._onceReturnValue; 27108 } 27109 else { 27110 return true; 27111 } 27112 }; 27113 27114 /** 27115 * Fetches the events object and creates one if required. 27116 * 27117 * @return {Object} The events storage object. 27118 * @api private 27119 */ 27120 proto._getEvents = function _getEvents() { 27121 return this._events || (this._events = {}); 27122 }; 27123 27124 /** 27125 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 27126 * 27127 * @return {Function} Non conflicting EventEmitter class. 27128 */ 27129 EventEmitter.noConflict = function noConflict() { 27130 exports.EventEmitter = originalGlobalValue; 27131 return EventEmitter; 27132 }; 27133 27134 // Expose the class either via AMD, CommonJS or the global object 27135 if (typeof define === 'function' && define.amd) { 27136 define('eventEmitter/EventEmitter',[],function () { 27137 return EventEmitter; 27138 }); 27139 } 27140 else if (typeof module === 'object' && module.exports){ 27141 module.exports = EventEmitter; 27142 } 27143 else { 27144 this.EventEmitter = EventEmitter; 27145 } 27146}.call(this)); 27147 27148/*! 27149 * eventie v1.0.4 27150 * event binding helper 27151 * eventie.bind( elem, 'click', myFn ) 27152 * eventie.unbind( elem, 'click', myFn ) 27153 */ 27154 27155/*jshint browser: true, undef: true, unused: true */ 27156/*global define: false */ 27157 27158( function( window ) { 27159 27160 27161 27162var docElem = document.documentElement; 27163 27164var bind = function() {}; 27165 27166function getIEEvent( obj ) { 27167 var event = window.event; 27168 // add event.target 27169 event.target = event.target || event.srcElement || obj; 27170 return event; 27171} 27172 27173if ( docElem.addEventListener ) { 27174 bind = function( obj, type, fn ) { 27175 obj.addEventListener( type, fn, false ); 27176 }; 27177} else if ( docElem.attachEvent ) { 27178 bind = function( obj, type, fn ) { 27179 obj[ type + fn ] = fn.handleEvent ? 27180 function() { 27181 var event = getIEEvent( obj ); 27182 fn.handleEvent.call( fn, event ); 27183 } : 27184 function() { 27185 var event = getIEEvent( obj ); 27186 fn.call( obj, event ); 27187 }; 27188 obj.attachEvent( "on" + type, obj[ type + fn ] ); 27189 }; 27190} 27191 27192var unbind = function() {}; 27193 27194if ( docElem.removeEventListener ) { 27195 unbind = function( obj, type, fn ) { 27196 obj.removeEventListener( type, fn, false ); 27197 }; 27198} else if ( docElem.detachEvent ) { 27199 unbind = function( obj, type, fn ) { 27200 obj.detachEvent( "on" + type, obj[ type + fn ] ); 27201 try { 27202 delete obj[ type + fn ]; 27203 } catch ( err ) { 27204 // can't delete window object properties 27205 obj[ type + fn ] = undefined; 27206 } 27207 }; 27208} 27209 27210var eventie = { 27211 bind: bind, 27212 unbind: unbind 27213}; 27214 27215// transport 27216if ( typeof define === 'function' && define.amd ) { 27217 // AMD 27218 define( 'eventie/eventie',eventie ); 27219} else { 27220 // browser global 27221 window.eventie = eventie; 27222} 27223 27224})( this ); 27225 27226/*! 27227 * imagesLoaded v3.1.4 27228 * JavaScript is all like "You images are done yet or what?" 27229 * MIT License 27230 */ 27231 27232( function( window, factory ) { 27233 // universal module definition 27234 27235 /*global define: false, module: false, require: false */ 27236 27237 if ( typeof define === 'function' && define.amd ) { 27238 // AMD 27239 define( [ 27240 'eventEmitter/EventEmitter', 27241 'eventie/eventie' 27242 ], function( EventEmitter, eventie ) { 27243 return factory( window, EventEmitter, eventie ); 27244 }); 27245 } else if ( typeof exports === 'object' ) { 27246 // CommonJS 27247 module.exports = factory( 27248 window, 27249 require('eventEmitter'), 27250 require('eventie') 27251 ); 27252 } else { 27253 // browser global 27254 window.imagesLoaded = factory( 27255 window, 27256 window.EventEmitter, 27257 window.eventie 27258 ); 27259 } 27260 27261})( this, 27262
27263// -------------------------- factory -------------------------- // 27264 27265function factory( window, EventEmitter, eventie ) { 27266 27267 27268 27269var $ = window.jQuery; 27270var console = window.console; 27271var hasConsole = typeof console !== 'undefined'; 27272 27273// -------------------------- helpers -------------------------- // 27274 27275// extend objects 27276function extend( a, b ) { 27277 for ( var prop in b ) { 27278 a[ prop ] = b[ prop ]; 27279 } 27280 return a; 27281} 27282 27283var objToString = Object.prototype.toString; 27284function isArray( obj ) { 27285 return objToString.call( obj ) === '[object Array]'; 27286} 27287 27288// turn element or nodeList into an array 27289function makeArray( obj ) { 27290 var ary = []; 27291 if ( isArray( obj ) ) { 27292 // use object if already an array 27293 ary = obj; 27294 } else if ( typeof obj.length === 'number' ) { 27295 // convert nodeList to array 27296 for ( var i=0, len = obj.length; i < len; i++ ) { 27297 ary.push( obj[i] ); 27298 } 27299 } else { 27300 // array of single index 27301 ary.push( obj ); 27302 } 27303 return ary; 27304} 27305 27306 // -------------------------- imagesLoaded -------------------------- // 27307 27308 /** 27309 * @param {Array, Element, NodeList, String} elem 27310 * @param {Object or Function} options - if function, use as callback 27311 * @param {Function} onAlways - callback function 27312 */ 27313 function ImagesLoaded( elem, options, onAlways ) { 27314 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 27315 if ( !( this instanceof ImagesLoaded ) ) { 27316 return new ImagesLoaded( elem, options ); 27317 } 27318 // use elem as selector string 27319 if ( typeof elem === 'string' ) { 27320 elem = document.querySelectorAll( elem ); 27321 } 27322 27323 this.elements = makeArray( elem ); 27324 this.options = extend( {}, this.options ); 27325 27326 if ( typeof options === 'function' ) { 27327 onAlways = options; 27328 } else { 27329 extend( this.options, options ); 27330 } 27331 27332 if ( onAlways ) { 27333 this.on( 'always', onAlways ); 27334 } 27335 27336 this.getImages(); 27337 27338 if ( $ ) { 27339 // add jQuery Deferred object 27340 this.jqDeferred = new $.Deferred(); 27341 } 27342 27343 // HACK check async to allow time to bind listeners 27344 var _this = this; 27345 setTimeout( function() { 27346 _this.check(); 27347 }); 27348 } 27349 27350 ImagesLoaded.prototype = new EventEmitter(); 27351 27352 ImagesLoaded.prototype.options = {}; 27353 27354 ImagesLoaded.prototype.getImages = function() { 27355 this.images = []; 27356 27357 // filter & find items if we have an item selector 27358 for ( var i=0, len = this.elements.length; i < len; i++ ) { 27359 var elem = this.elements[i]; 27360 // filter siblings 27361 if ( elem.nodeName === 'IMG' ) { 27362 this.addImage( elem ); 27363 } 27364 // find children 27365 var childElems = elem.querySelectorAll('img'); 27366 // concat childElems to filterFound array 27367 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 27368 var img = childElems[j]; 27369 this.addImage( img ); 27370 } 27371 } 27372 }; 27373 27374 /** 27375 * @param {Image} img 27376 */ 27377 ImagesLoaded.prototype.addImage = function( img ) { 27378 var loadingImage = new LoadingImage( img ); 27379 this.images.push( loadingImage ); 27380 }; 27381 27382 ImagesLoaded.prototype.check = function() { 27383 var _this = this; 27384 var checkedCount = 0; 27385 var length = this.images.length; 27386 this.hasAnyBroken = false; 27387 // complete if no images 27388 if ( !length ) { 27389 this.complete(); 27390 return; 27391 } 27392 27393 function onConfirm( image, message ) { 27394 if ( _this.options.debug && hasConsole ) { 27395 console.log( 'confirm', image, message ); 27396 } 27397 27398 _this.progress( image ); 27399 checkedCount++; 27400 if ( checkedCount === length ) { 27401 _this.complete(); 27402 } 27403 return true; // bind once 27404 } 27405 27406 for ( var i=0; i < length; i++ ) { 27407 var loadingImage = this.images[i]; 27408 loadingImage.on( 'confirm', onConfirm ); 27409 loadingImage.check(); 27410 } 27411 }; 27412 27413 ImagesLoaded.prototype.progress = function( image ) { 27414 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 27415 // HACK - Chrome triggers event before object properties have changed. #83 27416 var _this = this; 27417 setTimeout( function() { 27418 _this.emit( 'progress', _this, image ); 27419 if ( _this.jqDeferred && _this.jqDeferred.notify ) { 27420 _this.jqDeferred.notify( _this, image ); 27421 } 27422 }); 27423 }; 27424 27425 ImagesLoaded.prototype.complete = function() { 27426 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 27427 this.isComplete = true; 27428 var _this = this; 27429 // HACK - another setTimeout so that confirm happens after progress 27430 setTimeout( function() {
27431 _this.emit( eventName, _this ); 27432 _this.emit( 'always', _this ); 27433 if ( _this.jqDeferred ) { 27434 var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve'; 27435 _this.jqDeferred[ jqMethod ]( _this ); 27436 } 27437 }); 27438 }; 27439 27440 // -------------------------- jquery -------------------------- // 27441 27442 if ( $ ) { 27443 $.fn.imagesLoaded = function( options, callback ) { 27444 var instance = new ImagesLoaded( this, options, callback ); 27445 return instance.jqDeferred.promise( $(this) ); 27446 }; 27447 } 27448 27449 27450 // -------------------------- -------------------------- // 27451 27452 function LoadingImage( img ) { 27453 this.img = img; 27454 } 27455 27456 LoadingImage.prototype = new EventEmitter(); 27457 27458 LoadingImage.prototype.check = function() { 27459 // first check cached any previous images that have same src 27460 var resource = cache[ this.img.src ] || new Resource( this.img.src ); 27461 if ( resource.isConfirmed ) { 27462 this.confirm( resource.isLoaded, 'cached was confirmed' ); 27463 return; 27464 } 27465 27466 // If complete is true and browser supports natural sizes, 27467 // try to check for image status manually. 27468 if ( this.img.complete && this.img.naturalWidth !== undefined ) { 27469 // report based on naturalWidth 27470 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 27471 return; 27472 } 27473 27474 // If none of the checks above matched, simulate loading on detached element. 27475 var _this = this; 27476 resource.on( 'confirm', function( resrc, message ) { 27477 _this.confirm( resrc.isLoaded, message ); 27478 return true; 27479 }); 27480 27481 resource.check(); 27482 }; 27483 27484 LoadingImage.prototype.confirm = function( isLoaded, message ) { 27485 this.isLoaded = isLoaded; 27486 this.emit( 'confirm', this, message ); 27487 }; 27488 27489 // -------------------------- Resource -------------------------- // 27490 27491 // Resource checks each src, only once 27492 // separate class from LoadingImage to prevent memory leaks. See #115 27493 27494 var cache = {}; 27495 27496 function Resource( src ) { 27497 this.src = src; 27498 // add to cache 27499 cache[ src ] = this; 27500 } 27501 27502 Resource.prototype = new EventEmitter(); 27503 27504 Resource.prototype.check = function() { 27505 // only trigger checking once 27506 if ( this.isChecked ) { 27507 return; 27508 } 27509 // simulate loading on detached element 27510 var proxyImage = new Image(); 27511 eventie.bind( proxyImage, 'load', this ); 27512 eventie.bind( proxyImage, 'error', this ); 27513 proxyImage.src = this.src; 27514 // set flag 27515 this.isChecked = true; 27516 }; 27517 27518 // ----- events ----- // 27519 27520 // trigger specified handler for event type 27521 Resource.prototype.handleEvent = function( event ) { 27522 var method = 'on' + event.type; 27523 if ( this[ method ] ) { 27524 this[ method ]( event ); 27525 } 27526 }; 27527 27528 Resource.prototype.onload = function( event ) { 27529 this.confirm( true, 'onload' ); 27530 this.unbindProxyEvents( event ); 27531 }; 27532 27533 Resource.prototype.onerror = function( event ) { 27534 this.confirm( false, 'onerror' ); 27535 this.unbindProxyEvents( event ); 27536 }; 27537 27538 // ----- confirm ----- // 27539 27540 Resource.prototype.confirm = function( isLoaded, message ) { 27541 this.isConfirmed = true; 27542 this.isLoaded = isLoaded; 27543 this.emit( 'confirm', this, message ); 27544 }; 27545 27546 Resource.prototype.unbindProxyEvents = function( event ) { 27547 eventie.unbind( event.target, 'load', this ); 27548 eventie.unbind( event.target, 'error', this ); 27549 }; 27550 27551 // ----- ----- // 27552 27553 return ImagesLoaded; 27554 27555}); 27556/* 27557 * Backstretch 27558 * http://srobbin.com/jquery-plugins/backstretch/ 27559 * 27560 * Copyright (c) 2013 Scott Robbin 27561 * Licensed under the MIT license. 27562 */ 27563 27564 27565;(function ($, window, undefined) { 27566 'use strict'; 27567 27568 /* PLUGIN DEFINITION 27569 * ========================= */ 27570 27571 $.fn.backstretch = function (images, options) { 27572 // We need at least one image or method name 27573 if (images === undefined || images.length === 0) { 27574 $.error("No images were supplied for Backstretch"); 27575 } 27576 27577 /* 27578 * Scroll the page one pixel to get the right window height on iOS 27579 * Pretty harmless for everyone else 27580 */ 27581 if ($(window).scrollTop() === 0 ) { 27582 window.scrollTo(0, 0); 27583 } 27584 27585 return this.each(function () { 27586 var $this = $(this) 27587 , obj = $this.data('backstretch'); 27588 27589 // Do we already have an instance attached to this element? 27590 if (obj) { 27591 27592 // Is this a method they're trying to execute? 27593 if (typeof images == 'string' && typeof obj[images] == 'function') { 27594 // Call the method 27595 obj[images](options); 27596 27597 // No need to do anything further 27598 return; 27599 } 27600 27601 // Merge the old options with the new 27602 options = $.extend(obj.options, options); 27603 27604 // Remove the old instance 27605 obj.destroy(true); 27606 } 27607 27608 obj = new Backstretch(this, images, options); 27609 $this.data('backstretch', obj); 27610 }); 27611 }; 27612 27613 // If no element is supplied, we'll attach to body 27614 $.backstretch = function (images, options) { 27615 // Return the instance 27616 return $('body') 27617 .backstretch(images, options) 27618 .data('backstretch'); 27619 }; 27620 27621 // Custom selector 27622 $.expr[':'].backstretch = function(elem) { 27623 return $(elem).data('backstretch') !== undefined; 27624 }; 27625 27626 /* DEFAULTS 27627 * ========================= */ 27628 27629 $.fn.backstretch.defaults = { 27630 centeredX: true // Should we center the image on the X axis? 27631 , centeredY: true // Should we center the image on the Y axis? 27632 , duration: 5000 // Amount of time in between slides (if slideshow) 27633 , fade: 0 // Speed of fade transition between slides 27634 }; 27635
27636 /* STYLES 27637 * 27638 * Baked-in styles that we'll apply to our elements. 27639 * In an effort to keep the plugin simple, these are not exposed as options. 27640 * That said, anyone can override these in their own stylesheet. 27641 * ========================= */ 27642 var styles = { 27643 wrap: { 27644 left: 0 27645 , top: 0 27646 , overflow: 'hidden' 27647 , margin: 0 27648 , padding: 0 27649 , height: '100%' 27650 , width: '100%' 27651 , zIndex: -999999 27652 } 27653 , img: { 27654 position: 'absolute' 27655 , display: 'none' 27656 , margin: 0 27657 , padding: 0 27658 , border: 'none' 27659 , width: 'auto' 27660 , height: 'auto' 27661 , maxHeight: 'none' 27662 , maxWidth: 'none' 27663 , zIndex: -999999 27664 } 27665 }; 27666 27667 /* CLASS DEFINITION 27668 * ========================= */ 27669 var Backstretch = function (container, images, options) { 27670 this.options = $.extend({}, $.fn.backstretch.defaults, options || {}); 27671 27672 /* In its simplest form, we allow Backstretch to be called on an image path. 27673 * e.g. $.backstretch('/path/to/image.jpg') 27674 * So, we need to turn this back into an array. 27675 */ 27676 this.images = $.isArray(images) ? images : [images]; 27677 27678 // Preload images 27679 $.each(this.images, function () { 27680 $('<img />')[0].src = this; 27681 }); 27682 27683 // Convenience reference to know if the container is body. 27684 this.isBody = container === document.body; 27685 27686 /* We're keeping track of a few different elements 27687 * 27688 * Container: the element that Backstretch was called on. 27689 * Wrap: a DIV that we place the image into, so we can hide the overflow. 27690 * Root: Convenience reference to help calculate the correct height. 27691 */ 27692 this.$container = $(container); 27693 this.$root = this.isBody ? supportsFixedPosition ? $(window) : $(document) : this.$container; 27694 27695 // Don't create a new wrap if one already exists (from a previous instance of Backstretch) 27696 var $existing = this.$container.children(".backstretch").first(); 27697 this.$wrap = $existing.length ? $existing : $('<div class="backstretch"></div>').css(styles.wrap).appendTo(this.$container); 27698 27699 // Non-body elements need some style adjustments 27700 if (!this.isBody) { 27701 // If the container is statically positioned, we need to make it relative, 27702 // and if no zIndex is defined, we should set it to zero. 27703 var position = this.$container.css('position') 27704 , zIndex = this.$container.css('zIndex'); 27705 27706 this.$container.css({ 27707 position: position === 'static' ? 'relative' : position 27708 , zIndex: zIndex === 'auto' ? 0 : zIndex 27709 //, background: 'none' 27710 }); 27711 27712 // Needs a higher z-index 27713 this.$wrap.css({zIndex: -999998}); 27714 } 27715 27716 // Fixed or absolute positioning? 27717 this.$wrap.css({ 27718 position: this.isBody && supportsFixedPosition ? 'fixed' : 'absolute' 27719 }); 27720 27721 // Set the first image 27722 this.index = 0; 27723 this.show(this.index); 27724 27725 // Listen for resize 27726 $(window).on('resize.backstretch', $.proxy(this.resize, this)) 27727 .on('orientationchange.backstretch', $.proxy(function () { 27728 // Need to do this in order to get the right window height 27729 if (this.isBody && window.pageYOffset === 0) { 27730 window.scrollTo(0, 1); 27731 this.resize(); 27732 } 27733 }, this)); 27734 }; 27735 27736 /* PUBLIC METHODS 27737 * ========================= */ 27738 Backstretch.prototype = { 27739 resize: function () { 27740 try { 27741 var bgCSS = {left: 0, top: 0} 27742 , rootWidth = this.isBody ? this.$root.width() : this.$root.innerWidth() 27743 , bgWidth = rootWidth 27744 , rootHeight = this.isBody ? ( window.innerHeight ? window.innerHeight : this.$root.height() ) : this.$root.innerHeight() 27745 , bgHeight = bgWidth / this.$img.data('ratio') 27746 , bgOffset; 27747 27748 // Make adjustments based on image ratio 27749 if (bgHeight >= rootHeight) { 27750 bgOffset = (bgHeight - rootHeight) / 2; 27751 if(this.options.centeredY) { 27752 bgCSS.top = '-' + bgOffset + 'px'; 27753 } 27754 } else { 27755 bgHeight = rootHeight; 27756 bgWidth = bgHeight * this.$img.data('ratio'); 27757 bgOffset = (bgWidth - rootWidth) / 2; 27758 if(this.options.centeredX) { 27759 bgCSS.left = '-' + bgOffset + 'px'; 27760 } 27761 } 27762 27763 this.$wrap.css({width: rootWidth, height: rootHeight}) 27764 .find('img:not(.deleteable)').css({width: bgWidth, height: bgHeight}).css(bgCSS); 27765 } catch(err) { 27766 // IE7 seems to trigger resize before the image is loaded.
27767 // This try/catch block is a hack to let it fail gracefully. 27768 } 27769 27770 return this; 27771 } 27772 27773 // Show the slide at a certain position 27774 , show: function (newIndex) { 27775 27776 // Validate index 27777 if (Math.abs(newIndex) > this.images.length - 1) { 27778 return; 27779 } 27780 27781 // Vars 27782 var self = this 27783 , oldImage = self.$wrap.find('img').addClass('deleteable') 27784 , evtOptions = { relatedTarget: self.$container[0] }; 27785 27786 // Trigger the "before" event 27787 self.$container.trigger($.Event('backstretch.before', evtOptions), [self, newIndex]); 27788 27789 // Set the new index 27790 this.index = newIndex; 27791 27792 // Pause the slideshow 27793 clearInterval(self.interval); 27794 27795 // New image 27796 self.$img = $('<img />') 27797 .css(styles.img) 27798 .bind('load', function (e) { 27799 var imgWidth = this.width || $(e.target).width() 27800 , imgHeight = this.height || $(e.target).height(); 27801 27802 // Save the ratio 27803 $(this).data('ratio', imgWidth / imgHeight); 27804 27805 // Show the image, then delete the old one 27806 // "speed" option has been deprecated, but we want backwards compatibilty 27807 $(this).fadeIn(self.options.speed || self.options.fade, function () { 27808 oldImage.remove(); 27809 27810 // Resume the slideshow 27811 if (!self.paused) { 27812 self.cycle(); 27813 } 27814 27815 // Trigger the "after" and "show" events 27816 // "show" is being deprecated 27817 $(['after', 'show']).each(function () { 27818 self.$container.trigger($.Event('backstretch.' + this, evtOptions), [self, newIndex]); 27819 }); 27820 }); 27821 27822 // Resize 27823 self.resize(); 27824 }) 27825 .appendTo(self.$wrap); 27826 27827 // Hack for IE img onload event 27828 self.$img.attr('src', self.images[newIndex]); 27829 return self; 27830 } 27831 27832 , next: function () { 27833 // Next slide 27834 return this.show(this.index < this.images.length - 1 ? this.index + 1 : 0); 27835 } 27836 27837 , prev: function () { 27838 // Previous slide 27839 return this.show(this.index === 0 ? this.images.length - 1 : this.index - 1); 27840 } 27841 27842 , pause: function () { 27843 // Pause the slideshow 27844 this.paused = true; 27845 return this; 27846 } 27847 27848 , resume: function () { 27849 // Resume the slideshow 27850 this.paused = false; 27851 this.next(); 27852 return this; 27853 } 27854 27855 , cycle: function () { 27856 // Start/resume the slideshow 27857 if(this.images.length > 1) { 27858 // Clear the interval, just in case 27859 clearInterval(this.interval); 27860 27861 this.interval = setInterval($.proxy(function () { 27862 // Check for paused slideshow 27863 if (!this.paused) { 27864 this.next(); 27865 } 27866 }, this), this.options.duration); 27867 } 27868 return this; 27869 } 27870
27871 , destroy: function (preserveBackground) { 27872 // Stop the resize events 27873 $(window).off('resize.backstretch orientationchange.backstretch'); 27874 27875 // Clear the interval 27876 clearInterval(this.interval); 27877 27878 // Remove Backstretch 27879 if(!preserveBackground) { 27880 this.$wrap.remove(); 27881 } 27882 this.$container.removeData('backstretch'); 27883 } 27884 }; 27885 27886 /* SUPPORTS FIXED POSITION? 27887 * 27888 * Based on code from jQuery Mobile 1.1.0 27889 * http://jquerymobile.com/ 27890 * 27891 * In a nutshell, we need to figure out if fixed positioning is supported. 27892 * Unfortunately, this is very difficult to do on iOS, and usually involves 27893 * injecting content, scrolling the page, etc.. It's ugly. 27894 * jQuery Mobile uses this workaround. It's not ideal, but works. 27895 * 27896 * Modified to detect IE6 27897 * ========================= */ 27898 27899 var supportsFixedPosition = (function () { 27900 var ua = navigator.userAgent 27901 , platform = navigator.platform 27902 // Rendering engine is Webkit, and capture major version 27903 , wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ) 27904 , wkversion = !!wkmatch && wkmatch[ 1 ] 27905 , ffmatch = ua.match( /Fennec\/([0-9]+)/ ) 27906 , ffversion = !!ffmatch && ffmatch[ 1 ] 27907 , operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ) 27908 , omversion = !!operammobilematch && operammobilematch[ 1 ] 27909 , iematch = ua.match( /MSIE ([0-9]+)/ ) 27910 , ieversion = !!iematch && iematch[ 1 ]; 27911 27912 return !( 27913 // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5) 27914 ((platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534) || 27915 27916 // Opera Mini 27917 (window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]") || 27918 (operammobilematch && omversion < 7458) || 27919 27920 //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2) 27921 (ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533) || 27922 27923 // Firefox Mobile before 6.0 - 27924 (ffversion && ffversion < 6) || 27925 27926 // WebOS less than 3 27927 ("palmGetResource" in window && wkversion && wkversion < 534) || 27928 27929 // MeeGo 27930 (ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1) || 27931 27932 // IE6 27933 (ieversion && ieversion <= 6) 27934 ); 27935 }()); 27936 27937}(jQuery, window)); 27938/* 27939 27940Tooltipster 3.1.4 | 2014-03-20 27941A rockin' custom tooltip jQuery plugin 27942 27943Developed by Caleb Jacob under the MIT license http://opensource.org/licenses/MIT 27944 27945THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27946 27947*/ 27948 27949 27950;(function ($, window, document) { 27951 27952 var pluginName = "tooltipster", 27953 defaults = { 27954 animation: 'fade', 27955 arrow: true, 27956 arrowColor: '', 27957 autoClose: true, 27958 content: null, 27959 contentAsHTML: false, 27960 contentCloning: true, 27961 delay: 200, 27962 fixedWidth: 0, 27963 maxWidth: 0, 27964 functionInit: function(origin, content) {}, 27965 functionBefore: function(origin, continueTooltip) { 27966 continueTooltip(); 27967 }, 27968 functionReady: function(origin, tooltip) {}, 27969 functionAfter: function(origin) {}, 27970 icon: '(?)', 27971 iconCloning: true, 27972 iconDesktop: false, 27973 iconTouch: false, 27974 iconTheme: 'tooltipster-icon', 27975 interactive: false, 27976 interactiveTolerance: 350, 27977 offsetX: 0, 27978 offsetY: 0, 27979 onlyOne: false, 27980 position: 'top', 27981 positionTracker: false, 27982 speed: 350, 27983 timer: 0, 27984 theme: 'tooltipster-default', 27985 touchDevices: true, 27986 trigger: 'hover', 27987 updateAnimation: true 27988 }; 27989 27990 function Plugin(element, options) { 27991 27992 // list of instance variables 27993 27994 this.bodyOverflowX; 27995 // stack of custom callbacks provided as parameters to API methods 27996 this.callbacks = { 27997 hide: [], 27998 show: [] 27999 }; 28000 this.checkInterval = null; 28001 // this will be the user content shown in the tooltip 28002 this.content; 28003 // this is the original element which is being applied the tooltipster plugin 28004 this.$el = $(element); 28005 // this will be the element which triggers the appearance of the tooltip on hover/click/custom events. 28006 // it will be the same as this.$el if icons are not used (see in the options), otherwise it will correspond to the created icon 28007 this.$elProxy; 28008 this.elProxyPosition; 28009 this.enabled = true; 28010 this.options = $.extend({}, defaults, options); 28011 this.mouseIsOverProxy = false;
28012 // a unique namespace per instance, for easy selective unbinding 28013 this.namespace = 'tooltipster-'+ Math.round(Math.random()*100000); 28014 // status can be either : appearing, shown, disappearing, hidden 28015 this.status = 'hidden'; 28016 this.timerHide = null; 28017 this.timerShow = null; 28018 // this will be the tooltip element (jQuery wrapped HTML element) 28019 this.$tooltip; 28020 28021 // for backward compatibility 28022 this.options.iconTheme = this.options.iconTheme.replace('.', ''); 28023 this.options.theme = this.options.theme.replace('.', ''); 28024 28025 // launch 28026 28027 this.init(); 28028 } 28029 28030 Plugin.prototype = { 28031 28032 init: function() { 28033 28034 var self = this; 28035 28036 // disable the plugin on old browsers (including IE7 and lower) 28037 if (document.querySelector) { 28038 28039 // note : the content is null (empty) by default and can stay that way if the plugin remains initialized but not fed any content. The tooltip will just not appear. 28040 28041 // if content is provided in the options, its has precedence over the title attribute. Remark : an empty string is considered content, only 'null' represents the absence of content. 28042 if (self.options.content !== null){ 28043 self.setContent(self.options.content); 28044 } 28045 else { 28046 // the same remark as above applies : empty strings (like title="") are considered content and will be shown. Do not define any attribute at all if you want to initialize the plugin without content at start. 28047 var t = self.$el.attr('title'); 28048 if(typeof t === 'undefined') t = null; 28049 28050 self.setContent(t); 28051 } 28052 28053 var c = self.options.functionInit.call(self.$el, self.$el, self.content); 28054 if(typeof c !== 'undefined') self.setContent(c); 28055 28056 self.$el 28057 // strip the title off of the element to prevent the default tooltips from popping up 28058 .removeAttr('title') 28059 // to be able to find all instances on the page later (upon window events in particular) 28060 .addClass('tooltipstered'); 28061 28062 // detect if we're changing the tooltip origin to an icon 28063 // note about this condition : if the device has touch capability and self.options.iconTouch is false, you'll have no icons event though you may consider your device as a desktop if it also has a mouse. Not sure why someone would have this use case though. 28064 if ((!deviceHasTouchCapability && self.options.iconDesktop) || (deviceHasTouchCapability && self.options.iconTouch)) { 28065 28066 // TODO : the tooltip should be automatically be given an absolute position to be near the origin. Otherwise, when the origin is floating or what, it's going to be nowhere near it and disturb the position flow of the page elements. It will imply that the icon also detects when its origin moves, to follow it : not trivial. 28067 // Until it's done, the icon feature does not really make sense since the user still has most of the work to do by himself 28068 28069 // if the icon provided is in the form of a string 28070 if(typeof self.options.icon === 'string'){ 28071 // wrap it in a span with the icon class 28072 self.$elProxy = $('<span class="'+ self.options.iconTheme +'"></span>'); 28073 self.$elProxy.text(self.options.icon); 28074 } 28075 // if it is an object (sensible choice) 28076 else { 28077 // (deep) clone the object if iconCloning == true, to make sure every instance has its own proxy. We use the icon without wrapping, no need to. We do not give it a class either, as the user will undoubtedly style the object on his own and since our css properties may conflict with his own 28078 if (self.options.iconCloning) self.$elProxy = self.options.icon.clone(true); 28079 else self.$elProxy = self.options.icon; 28080 } 28081 28082 self.$elProxy.insertAfter(self.$el); 28083 } 28084 else { 28085 self.$elProxy = self.$el; 28086 } 28087 28088 // for 'click' and 'hover' triggers : bind on events to open the tooltip. Closing is now handled in showTooltipNow() because of its bindings. 28089 // Notes about touch events : 28090 // - mouseenter, mouseleave and clicks happen even on pure touch devices because they are emulated. deviceIsPureTouch() is a simple attempt to detect them. 28091 // - on hybrid devices, we do not prevent touch gesture from opening tooltips. It would be too complex to differentiate real mouse events from emulated ones. 28092 // - we check deviceIsPureTouch() at each event rather than prior to binding because the situation may change during browsing 28093 if (self.options.trigger == 'hover') { 28094 28095 // these binding are for mouse interaction only 28096 self.$elProxy 28097 .on('mouseenter.'+ self.namespace, function() { 28098 if (!deviceIsPureTouch() || self.options.touchDevices) { 28099 self.mouseIsOverProxy = true; 28100 self.showTooltip(); 28101 } 28102 }) 28103 .on('mouseleave.'+ self.namespace, function() { 28104 if (!deviceIsPureTouch() || self.options.touchDevices) { 28105 self.mouseIsOverProxy = false;
28106 } 28107 }); 28108 28109 // for touch interaction only 28110 if (deviceHasTouchCapability && self.options.touchDevices) { 28111 28112 // for touch devices, we immediately display the tooltip because we cannot rely on mouseleave to handle the delay 28113 self.$elProxy.on('touchstart.'+ self.namespace, function() { 28114 self.showTooltipNow(); 28115 }); 28116 } 28117 } 28118 else if (self.options.trigger == 'click') { 28119 28120 // note : for touch devices, we do not bind on touchstart, we only rely on the emulated clicks (triggered by taps) 28121 self.$elProxy.on('click.'+ self.namespace, function() { 28122 if (!deviceIsPureTouch() || self.options.touchDevices) { 28123 self.showTooltip(); 28124 } 28125 }); 28126 } 28127 } 28128 }, 28129 28130 // this function will schedule the opening of the tooltip after the delay, if there is one 28131 showTooltip: function() { 28132 28133 var self = this; 28134 28135 if (self.status != 'shown' && self.status != 'appearing') { 28136 28137 if (self.options.delay) { 28138 self.timerShow = setTimeout(function(){ 28139 28140 // for hover trigger, we check if the mouse is still over the proxy, otherwise we do not show anything 28141 if (self.options.trigger == 'click' || (self.options.trigger == 'hover' && self.mouseIsOverProxy)) { 28142 self.showTooltipNow(); 28143 } 28144 }, self.options.delay); 28145 } 28146 else self.showTooltipNow(); 28147 } 28148 }, 28149 28150 // this function will open the tooltip right away 28151 showTooltipNow: function(callback) { 28152 28153 var self = this; 28154 28155 // call our constructor custom function before continuing 28156 self.options.functionBefore.call(self.$el, self.$el, function() { 28157 28158 // continue only if the tooltip is enabled and has any content 28159 if (self.enabled && self.content !== null) { 28160 28161 // save the method callback and cancel hide method callbacks 28162 if (callback) self.callbacks.show.push(callback); 28163 self.callbacks.hide = []; 28164 28165 //get rid of any appearance timer 28166 clearTimeout(self.timerShow); 28167 self.timerShow = null; 28168 clearTimeout(self.timerHide); 28169 self.timerHide = null; 28170 28171 // if we only want one tooltip open at a time, close all auto-closing tooltips currently open and not already disappearing 28172 if (self.options.onlyOne) { 28173 $('.tooltipstered').not(self.$el).each(function(i,el) { 28174 28175 // we have to use the public methods here 28176 var $el = $(el), 28177 s = $el[pluginName]('status'), 28178 ac = $el[pluginName]('option', 'autoClose'); 28179 28180 if (s !== 'hidden' && s !== 'disappearing' && ac) { 28181 $el[pluginName]('hide'); 28182 } 28183 }); 28184 } 28185 28186 var finish = function() { 28187 self.status = 'shown'; 28188 28189 // trigger any show method custom callbacks and reset them 28190 $.each(self.callbacks.show, function(i,c) { c.call(self.$el); }); 28191 self.callbacks.show = []; 28192 }; 28193 28194 // if this origin already has its tooltip open 28195 if (self.status !== 'hidden') { 28196 28197 // the timer (if any) will start (or restart) right now 28198 var extraTime = 0; 28199 28200 // if it was disappearing, cancel that 28201 if (self.status === 'disappearing') { 28202 28203 self.status = 'appearing'; 28204 28205 if (supportsTransitions()) { 28206 28207 self.$tooltip 28208 .clearQueue() 28209 .removeClass('tooltipster-dying') 28210 .addClass('tooltipster-'+ self.options.animation +'-show'); 28211 28212 if (self.options.speed > 0) self.$tooltip.delay(self.options.speed); 28213 28214 self.$tooltip.queue(finish); 28215 } 28216 else { 28217 // in case the tooltip was currently fading out, bring it back to life 28218 self.$tooltip 28219 .stop() 28220 .fadeIn(finish); 28221 } 28222 } 28223 // if the tooltip is already open, we still need to trigger the method custom callback 28224 else if(self.status === 'shown') { 28225 finish(); 28226 } 28227 } 28228 // if the tooltip isn't already open, open that sucker up! 28229 else { 28230 28231 self.status = 'appearing'; 28232 28233 // the timer (if any) will start when the tooltip has fully appeared after its transition 28234 var extraTime = self.options.speed; 28235 28236 // disable horizontal scrollbar to keep overflowing tooltips from jacking with it and then restore it to its previous value 28237 self.bodyOverflowX = $('body').css('overflow-x'); 28238 $('body').css('overflow-x', 'hidden'); 28239 28240 // get some other settings related to building the tooltip 28241 var animation = 'tooltipster-' + self.options.animation, 28242 animationSpeed = '-webkit-transition-duration: '+ self.options.speed +'ms; -webkit-animation-duration: '+ self.options.speed +'ms; -moz-transition-duration: '+ self.options.speed +'ms; -moz-animation-duration: '+ self.options.speed +'ms; -o-transition-duration: '+ self.options.speed +'ms; -o-animation-duration: '+ self.options.speed +'ms; -ms-transition-duration: '+ self.options.speed +'ms; -ms-animation-duration: '+ self.options.speed +'ms; transition-duration: '+ self.options.speed +'ms; animation-duration: '+ self.options.speed +'ms;', 28243 fixedWidth = self.options.fixedWidth > 0 ? 'width:'+ Math.round(self.options.fixedWidth) +'px;' : '', 28244 maxWidth = self.options.maxWidth > 0 ? 'max-width:'+ Math.round(self.options.maxWidth) +'px;' : '', 28245 pointerEvents = self.options.interactive ? 'pointer-events: auto;' : ''; 28246 28247 // build the base of our tooltip 28248 self.$tooltip = $('<div class="tooltipster-base '+ self.options.theme +'" style="'+ fixedWidth +' '+ maxWidth +' '+ pointerEvents +' '+ animationSpeed +'"><div class="tooltipster-content"></div></div>'); 28249 28250 // only add the animation class if the user has a browser that supports animations 28251 if (supportsTransitions()) self.$tooltip.addClass(animation); 28252 28253 // insert the content 28254 self.insertContent(); 28255 28256 // attach 28257 self.$tooltip.appendTo('body'); 28258 28259 // do all the crazy calculations and positioning 28260 self.positionTooltip(); 28261 28262 // call our custom callback since the content of the tooltip is now part of the DOM 28263 self.options.functionReady.call(self.$el, self.$el, self.$tooltip); 28264 28265 // animate in the tooltip 28266 if (supportsTransitions()) { 28267 28268 self.$tooltip.addClass(animation + '-show'); 28269 28270 if(self.options.speed > 0) self.$tooltip.delay(self.options.speed); 28271 28272 self.$tooltip.queue(finish); 28273 } 28274 else { 28275 self.$tooltip.css('display', 'none').fadeIn(self.options.speed, finish); 28276 } 28277 28278 // will check if our tooltip origin is removed while the tooltip is shown 28279 self.setCheckInterval(); 28280 28281 // reposition on scroll (otherwise position:fixed element's tooltips will move away form their origin) and on resize (in case position can/has to be changed) 28282 $(window).on('scroll.'+ self.namespace +' resize.'+ self.namespace, function() { 28283 self.positionTooltip(); 28284 }); 28285 28286 // auto-close bindings 28287 if (self.options.autoClose) { 28288 28289 // in case a listener is already bound for autoclosing (mouse or touch, hover or click), unbind it first 28290 $('body').off('.'+ self.namespace); 28291 28292 // here we'll have to set different sets of bindings for both touch and mouse 28293 if (self.options.trigger == 'hover') { 28294 28295 // if the user touches the body, hide 28296 if (deviceHasTouchCapability) { 28297 // timeout 0 : explanation below in click section 28298 setTimeout(function() { 28299 // we don't want to bind on click here because the initial touchstart event has not yet triggered its click event, which is thus about to happen 28300 $('body').on('touchstart.'+ self.namespace, function() { 28301 self.hideTooltip(); 28302 }); 28303 }, 0); 28304 } 28305 28306 // if we have to allow interaction 28307 if (self.options.interactive) { 28308 28309 // touch events inside the tooltip must not close it 28310 if (deviceHasTouchCapability) { 28311 self.$tooltip.on('touchstart.'+ self.namespace, function(event) { 28312 event.stopPropagation(); 28313 }); 28314 } 28315 28316 // as for mouse interaction, we get rid of the tooltip only after the mouse has spent some time out of it 28317 var tolerance = null; 28318 28319 self.$elProxy.add(self.$tooltip) 28320 // hide after some time out of the proxy and the tooltip 28321 .on('mouseleave.'+ self.namespace + '-autoClose', function() { 28322 clearTimeout(tolerance); 28323 tolerance = setTimeout(function(){ 28324 self.hideTooltip(); 28325 }, self.options.interactiveTolerance); 28326 }) 28327 // suspend timeout when the mouse is over the proxy or the tooltip 28328 .on('mouseenter.'+ self.namespace + '-autoClose', function() { 28329 clearTimeout(tolerance); 28330 }); 28331 } 28332 // if this is a non-interactive tooltip, get rid of it if the mouse leaves 28333 else { 28334 self.$elProxy.on('mouseleave.'+ self.namespace + '-autoClose', function() { 28335 self.hideTooltip(); 28336 }); 28337 } 28338 } 28339 // here we'll set the same bindings for both clicks and touch on the body to hide the tooltip 28340 else if(self.options.trigger == 'click'){ 28341 28342 // use a timeout to prevent immediate closing if the method was called on a click event and if options.delay == 0 (because of bubbling) 28343 setTimeout(function() { 28344 $('body').on('click.'+ self.namespace +' touchstart.'+ self.namespace, function() { 28345 self.hideTooltip(); 28346 }); 28347 }, 0); 28348 28349 // if interactive, we'll stop the events that were emitted from inside the tooltip to stop autoClosing 28350 if (self.options.interactive) { 28351 28352 // note : the touch events will just not be used if the plugin is not enabled on touch devices 28353 self.$tooltip.on('click.'+ self.namespace +' touchstart.'+ self.namespace, function(event) { 28354 event.stopPropagation(); 28355 }); 28356 } 28357 } 28358 } 28359 } 28360 28361 // if we have a timer set, let the countdown begin 28362 if (self.options.timer > 0) { 28363 28364 self.timerHide = setTimeout(function() { 28365 self.timerHide = null; 28366 self.hideTooltip(); 28367 }, self.options.timer + extraTime); 28368 } 28369 } 28370 }); 28371 }, 28372 28373 setCheckInterval: function(){ 28374 28375 var self = this; 28376 28377 self.checkInterval = setInterval(function() { 28378 28379 // if the tooltip and/or its interval should be stopped 28380 if ( 28381 // if the origin has been removed 28382 $('body').find(self.$el).length === 0 28383 // if the elProxy has been removed 28384 || $('body').find(self.$elProxy).length === 0 28385 // if the tooltip has been closed 28386 || self.status == 'hidden' 28387 // if the tooltip has somehow been removed 28388 || $('body').find(self.$tooltip).length === 0 28389 ) { 28390 // remove the tooltip if it's still here 28391 if (self.status == 'shown' || self.status == 'appearing') self.hideTooltip(); 28392 28393 // clear this interval as it is no longer necessary 28394 self.cancelCheckInterval(); 28395 } 28396 // if everything is alright 28397 else { 28398 // compare the former and current positions of the elProxy to reposition the tooltip if need be 28399 if(self.options.positionTracker){ 28400 28401 var p = self.positionInfo(self.$elProxy), 28402 identical = false;
28403 28404 // compare size first (a change requires repositioning too) 28405 if(areEqual(p.dimension, self.elProxyPosition.dimension)){ 28406 28407 // for elements with a fixed position, we track the top and left properties (relative to window) 28408 if(self.$elProxy.css('position') === 'fixed'){ 28409 if(areEqual(p.position, self.elProxyPosition.position)) identical = true; 28410 } 28411 // otherwise, track total offset (relative to document) 28412 else { 28413 if(areEqual(p.offset, self.elProxyPosition.offset)) identical = true; 28414 } 28415 } 28416 28417 if(!identical){ 28418 self.positionTooltip(); 28419 } 28420 } 28421 } 28422 }, 200); 28423 }, 28424 28425 cancelCheckInterval: function(){ 28426 clearInterval(this.checkInterval); 28427 // clean delete 28428 this.checkInterval = null; 28429 }, 28430 28431 hideTooltip: function(callback) { 28432 28433 var self = this; 28434 28435 // save the method custom callback and cancel any show method custom callbacks 28436 if (callback) self.callbacks.hide.push(callback); 28437 self.callbacks.show = []; 28438 28439 // get rid of any appearance timeout 28440 clearTimeout(self.timerShow); 28441 self.timerShow = null; 28442 clearTimeout(self.timerHide); 28443 self.timerHide = null; 28444 28445 var finishCallbacks = function() { 28446 // trigger any hide method custom callbacks and reset them 28447 $.each(self.callbacks.hide, function(i,c) { c.call(self.$el); }); 28448 self.callbacks.hide = []; 28449 }; 28450 28451 // hide 28452 if (self.status == 'shown' || self.status == 'appearing') { 28453 28454 self.status = 'disappearing'; 28455 28456 var finish = function() { 28457 28458 self.status = 'hidden'; 28459 28460 // detach our content object first, so the next jQuery's remove() call does not unbind its event handlers 28461 if (typeof self.content == 'object' && self.content !== null) { 28462 self.content.detach(); 28463 } 28464 28465 self.$tooltip.remove(); 28466 self.$tooltip = null; 28467 28468 // unbind orientationchange, scroll and resize listeners 28469 $(window).off('.'+ self.namespace); 28470 28471 $('body') 28472 // unbind any auto-closing click/touch listeners 28473 .off('.'+ self.namespace) 28474 .css('overflow-x', self.bodyOverflowX); 28475 28476 // unbind any auto-closing click/touch listeners 28477 $('body').off('.'+ self.namespace); 28478 28479 // unbind any auto-closing hover listeners 28480 self.$elProxy.off('.'+ self.namespace + '-autoClose'); 28481 28482 // call our constructor custom callback function 28483 self.options.functionAfter.call(self.$el, self.$el); 28484 28485 // call our method custom callbacks functions 28486 finishCallbacks(); 28487 }; 28488 28489 if (supportsTransitions()) { 28490 28491 self.$tooltip 28492 .clearQueue() 28493 .removeClass('tooltipster-' + self.options.animation + '-show') 28494 // for transitions only 28495 .addClass('tooltipster-dying'); 28496 28497 if(self.options.speed > 0) self.$tooltip.delay(self.options.speed); 28498 28499 self.$tooltip.queue(finish); 28500 } 28501 else { 28502 self.$tooltip 28503 .stop() 28504 .fadeOut(self.options.speed, finish); 28505 } 28506 } 28507 // if the tooltip is already hidden, we still need to trigger the method custom callback 28508 else if(self.status == 'hidden') { 28509 finishCallbacks(); 28510 } 28511 }, 28512 28513 setContent: function(content) { 28514 // clone if asked. Cloning the object makes sure that each instance has its own version of the content (in case a same object were provided for several instances) 28515 // reminder : typeof null === object 28516 if (typeof content === 'object' && content !== null && this.options.contentCloning) { 28517 content = content.clone(true); 28518 } 28519 this.content = content; 28520 }, 28521 28522 insertContent: function() { 28523 28524 var self = this, 28525 $d = this.$tooltip.find('.tooltipster-content'); 28526 28527 if (typeof self.content === 'string' && !self.options.contentAsHTML) { 28528 $d.text(self.content); 28529 } 28530 else { 28531 $d 28532 .empty() 28533 .append(self.content); 28534 } 28535 }, 28536 28537 updateTooltip: function(content) { 28538 28539 var self = this; 28540 28541 // change the content 28542 self.setContent(content); 28543 28544 if (self.content !== null) { 28545 28546 // update the tooltip if it is open 28547 if (self.status !== 'hidden') { 28548 28549 // reset the content in the tooltip 28550 self.insertContent(); 28551 28552 // reposition and resize the tooltip 28553 self.positionTooltip(); 28554 28555 // if we want to play a little animation showing the content changed 28556 if (self.options.updateAnimation) { 28557 28558 if (supportsTransitions()) { 28559 28560 self.$tooltip.css({ 28561 'width': '', 28562 '-webkit-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', 28563 '-moz-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', 28564 '-o-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', 28565 '-ms-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms', 28566 'transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms' 28567 }).addClass('tooltipster-content-changing'); 28568 28569 // reset the CSS transitions and finish the change animation 28570 setTimeout(function() { 28571 28572 if(self.status != 'hidden'){ 28573 28574 self.$tooltip.removeClass('tooltipster-content-changing'); 28575 28576 // after the changing animation has completed, reset the CSS transitions 28577 setTimeout(function() { 28578 28579 if(self.status !== 'hidden'){ 28580 self.$tooltip.css({ 28581 '-webkit-transition': self.options.speed + 'ms', 28582 '-moz-transition': self.options.speed + 'ms', 28583 '-o-transition': self.options.speed + 'ms', 28584 '-ms-transition': self.options.speed + 'ms', 28585 'transition': self.options.speed + 'ms' 28586 }); 28587 } 28588 }, self.options.speed); 28589 } 28590 }, self.options.speed); 28591 } 28592 else { 28593 self.$tooltip.fadeTo(self.options.speed, 0.5, function() { 28594 if(self.status != 'hidden'){ 28595 self.$tooltip.fadeTo(self.options.speed, 1); 28596 } 28597 }); 28598 } 28599 } 28600 } 28601 } 28602 else { 28603 self.hideTooltip(); 28604 } 28605 }, 28606 28607 positionInfo: function($el){ 28608 return { 28609 dimension: { 28610 height: $el.outerHeight(false), 28611 width: $el.outerWidth(false) 28612 }, 28613 offset: $el.offset(), 28614 position: { 28615 left: parseInt($el.css('left')), 28616 top: parseInt($el.css('top')) 28617 } 28618 }; 28619 }, 28620 28621 positionTooltip: function() { 28622 28623 var self = this; 28624 28625 // in case the tooltip has been removed from DOM manually 28626 if ($('body').find(self.$tooltip).length !== 0) { 28627 28628 // reset width 28629 self.$tooltip.css('width', ''); 28630 28631 // find variables to determine placement 28632 self.elProxyPosition = self.positionInfo(self.$elProxy); 28633 var arrowReposition = null, 28634 windowWidth = $(window).width(), 28635 // shorthand 28636 proxy = self.elProxyPosition, 28637 tooltipWidth = self.$tooltip.outerWidth(false), 28638 tooltipInnerWidth = self.$tooltip.innerWidth() + 1, // this +1 stops FireFox from sometimes forcing an additional text line 28639 tooltipHeight = self.$tooltip.outerHeight(false); 28640 28641 // if this is an <area> tag inside a <map>, all hell breaks loose. Recalculate all the measurements based on coordinates 28642 if (self.$elProxy.is('area')) { 28643 var areaShape = self.$elProxy.attr('shape'), 28644 mapName = self.$elProxy.parent().attr('name'), 28645 map = $('img[usemap="#'+ mapName +'"]'), 28646 mapOffsetLeft = map.offset().left, 28647 mapOffsetTop = map.offset().top, 28648 areaMeasurements = self.$elProxy.attr('coords') !== undefined ? self.$elProxy.attr('coords').split(',') : undefined; 28649 28650 if (areaShape == 'circle') { 28651 var areaLeft = parseInt(areaMeasurements[0]), 28652 areaTop = parseInt(areaMeasurements[1]), 28653 areaWidth = parseInt(areaMeasurements[2]); 28654 proxy.dimension.height = areaWidth * 2; 28655 proxy.dimension.width = areaWidth * 2; 28656 proxy.offset.top = mapOffsetTop + areaTop - areaWidth; 28657 proxy.offset.left = mapOffsetLeft + areaLeft - areaWidth; 28658 } 28659 else if (areaShape == 'rect') { 28660 var areaLeft = parseInt(areaMeasurements[0]), 28661 areaTop = parseInt(areaMeasurements[1]), 28662 areaRight = parseInt(areaMeasurements[2]), 28663 areaBottom = parseInt(areaMeasurements[3]); 28664 proxy.dimension.height = areaBottom - areaTop; 28665 proxy.dimension.width = areaRight - areaLeft; 28666 proxy.offset.top = mapOffsetTop + areaTop; 28667 proxy.offset.left = mapOffsetLeft + areaLeft; 28668 } 28669 else if (areaShape == 'poly') { 28670 var areaXs = [], 28671 areaYs = [], 28672 areaSmallestX = 0, 28673 areaSmallestY = 0, 28674 areaGreatestX = 0, 28675 areaGreatestY = 0, 28676 arrayAlternate = 'even'; 28677 28678 for (var i = 0; i < areaMeasurements.length; i++) { 28679 var areaNumber = parseInt(areaMeasurements[i]); 28680 28681 if (arrayAlternate == 'even') { 28682 if (areaNumber > areaGreatestX) { 28683 areaGreatestX = areaNumber; 28684 if (i === 0) { 28685 areaSmallestX = areaGreatestX; 28686 } 28687 } 28688 28689 if (areaNumber < areaSmallestX) { 28690 areaSmallestX = areaNumber; 28691 } 28692 28693 arrayAlternate = 'odd'; 28694 } 28695 else { 28696 if (areaNumber > areaGreatestY) { 28697 areaGreatestY = areaNumber; 28698 if (i == 1) { 28699 areaSmallestY = areaGreatestY; 28700 } 28701 } 28702 28703 if (areaNumber < areaSmallestY) { 28704 areaSmallestY = areaNumber; 28705 } 28706 28707 arrayAlternate = 'even'; 28708 } 28709 } 28710 28711 proxy.dimension.height = areaGreatestY - areaSmallestY; 28712 proxy.dimension.width = areaGreatestX - areaSmallestX; 28713 proxy.offset.top = mapOffsetTop + areaSmallestY; 28714 proxy.offset.left = mapOffsetLeft + areaSmallestX; 28715 } 28716 else { 28717 proxy.dimension.height = map.outerHeight(false); 28718 proxy.dimension.width = map.outerWidth(false); 28719 proxy.offset.top = mapOffsetTop; 28720 proxy.offset.left = mapOffsetLeft; 28721 } 28722 } 28723 28724 // hardcoding the width and removing the padding fixed an issue with the tooltip width collapsing when the window size is small 28725 if(self.options.fixedWidth === 0) { 28726 self.$tooltip.css({ 28727 'width': Math.round(tooltipInnerWidth) + 'px', 28728 'padding-left': '0px', 28729 'padding-right': '0px' 28730 }); 28731 } 28732 28733 // our function and global vars for positioning our tooltip 28734 var myLeft = 0, 28735 myLeftMirror = 0, 28736 myTop = 0, 28737 offsetY = parseInt(self.options.offsetY), 28738 offsetX = parseInt(self.options.offsetX), 28739 // this is the arrow position that will eventually be used. It may differ from the position option if the tooltip cannot be displayed in this position 28740 practicalPosition = self.options.position; 28741 28742 // a function to detect if the tooltip is going off the screen horizontally. If so, reposition the crap out of it! 28743 function dontGoOffScreenX() { 28744 28745 var windowLeft = $(window).scrollLeft(); 28746 28747 // if the tooltip goes off the left side of the screen, line it up with the left side of the window 28748 if((myLeft - windowLeft) < 0) { 28749 arrowReposition = myLeft - windowLeft; 28750 myLeft = windowLeft; 28751 } 28752 28753 // if the tooltip goes off the right of the screen, line it up with the right side of the window 28754 if (((myLeft + tooltipWidth) - windowLeft) > windowWidth) { 28755 arrowReposition = myLeft - ((windowWidth + windowLeft) - tooltipWidth); 28756 myLeft = (windowWidth + windowLeft) - tooltipWidth; 28757 } 28758 } 28759 28760 // a function to detect if the tooltip is going off the screen vertically. If so, switch to the opposite! 28761 function dontGoOffScreenY(switchTo, switchFrom) { 28762 // if it goes off the top off the page 28763 if(((proxy.offset.top - $(window).scrollTop() - tooltipHeight - offsetY - 12) < 0) && (switchFrom.indexOf('top') > -1)) { 28764 practicalPosition = switchTo; 28765 } 28766 28767 // if it goes off the bottom of the page 28768 if (((proxy.offset.top + proxy.dimension.height + tooltipHeight + 12 + offsetY) > ($(window).scrollTop() + $(window).height())) && (switchFrom.indexOf('bottom') > -1)) { 28769 practicalPosition = switchTo; 28770 myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12; 28771 } 28772 } 28773 28774 if(practicalPosition == 'top') { 28775 var leftDifference = (proxy.offset.left + tooltipWidth) - (proxy.offset.left + proxy.dimension.width); 28776 myLeft = (proxy.offset.left + offsetX) - (leftDifference / 2); 28777 myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12; 28778 dontGoOffScreenX(); 28779 dontGoOffScreenY('bottom', 'top'); 28780 } 28781 28782 if(practicalPosition == 'top-left') { 28783 myLeft = proxy.offset.left + offsetX; 28784 myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12; 28785 dontGoOffScreenX(); 28786 dontGoOffScreenY('bottom-left', 'top-left'); 28787 } 28788 28789 if(practicalPosition == 'top-right') { 28790 myLeft = (proxy.offset.left + proxy.dimension.width + offsetX) - tooltipWidth; 28791 myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12; 28792 dontGoOffScreenX(); 28793 dontGoOffScreenY('bottom-right', 'top-right'); 28794 } 28795 28796 if(practicalPosition == 'bottom') { 28797 var leftDifference = (proxy.offset.left + tooltipWidth) - (proxy.offset.left + proxy.dimension.width); 28798 myLeft = proxy.offset.left - (leftDifference / 2) + offsetX; 28799 myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12; 28800 dontGoOffScreenX(); 28801 dontGoOffScreenY('top', 'bottom'); 28802 } 28803 28804 if(practicalPosition == 'bottom-left') { 28805 myLeft = proxy.offset.left + offsetX; 28806 myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12; 28807 dontGoOffScreenX(); 28808 dontGoOffScreenY('top-left', 'bottom-left'); 28809 } 28810 28811 if(practicalPosition == 'bottom-right') { 28812 myLeft = (proxy.offset.left + proxy.dimension.width + offsetX) - tooltipWidth; 28813 myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12; 28814 dontGoOffScreenX(); 28815 dontGoOffScreenY('top-right', 'bottom-right'); 28816 } 28817 28818 if(practicalPosition == 'left') { 28819 myLeft = proxy.offset.left - offsetX - tooltipWidth - 12; 28820 myLeftMirror = proxy.offset.left + offsetX + proxy.dimension.width + 12; 28821 var topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height); 28822 myTop = proxy.offset.top - (topDifference / 2) - offsetY; 28823 28824 // if the tooltip goes off boths sides of the page 28825 if((myLeft < 0) && ((myLeftMirror + tooltipWidth) > windowWidth)) { 28826 var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2, 28827 newWidth = (tooltipWidth + myLeft) - borderWidth; 28828 self.$tooltip.css('width', newWidth + 'px'); 28829 28830 tooltipHeight = self.$tooltip.outerHeight(false); 28831 myLeft = proxy.offset.left - offsetX - newWidth - 12 - borderWidth; 28832 topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height); 28833 myTop = proxy.offset.top - (topDifference / 2) - offsetY; 28834 } 28835 28836 // if it only goes off one side, flip it to the other side
28837 else if(myLeft < 0) { 28838 myLeft = proxy.offset.left + offsetX + proxy.dimension.width + 12; 28839 arrowReposition = 'left'; 28840 } 28841 } 28842 28843 if(practicalPosition == 'right') { 28844 myLeft = proxy.offset.left + offsetX + proxy.dimension.width + 12; 28845 myLeftMirror = proxy.offset.left - offsetX - tooltipWidth - 12; 28846 var topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height); 28847 myTop = proxy.offset.top - (topDifference / 2) - offsetY; 28848 28849 // if the tooltip goes off boths sides of the page 28850 if(((myLeft + tooltipWidth) > windowWidth) && (myLeftMirror < 0)) { 28851 var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2, 28852 newWidth = (windowWidth - myLeft) - borderWidth; 28853 self.$tooltip.css('width', newWidth + 'px'); 28854 28855 tooltipHeight = self.$tooltip.outerHeight(false); 28856 topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height); 28857 myTop = proxy.offset.top - (topDifference / 2) - offsetY; 28858 } 28859 28860 // if it only goes off one side, flip it to the other side 28861 else if((myLeft + tooltipWidth) > windowWidth) { 28862 myLeft = proxy.offset.left - offsetX - tooltipWidth - 12; 28863 arrowReposition = 'right'; 28864 } 28865 } 28866 28867 // if arrow is set true, style it and append it 28868 if (self.options.arrow) { 28869 28870 var arrowClass = 'tooltipster-arrow-' + practicalPosition; 28871 28872 // set color of the arrow 28873 if(self.options.arrowColor.length < 1) { 28874 var arrowColor = self.$tooltip.css('background-color'); 28875 } 28876 else { 28877 var arrowColor = self.options.arrowColor; 28878 } 28879 28880 // if the tooltip was going off the page and had to re-adjust, we need to update the arrow's position 28881 if (!arrowReposition) { 28882 arrowReposition = ''; 28883 } 28884 else if (arrowReposition == 'left') { 28885 arrowClass = 'tooltipster-arrow-right'; 28886 arrowReposition = ''; 28887 } 28888 else if (arrowReposition == 'right') { 28889 arrowClass = 'tooltipster-arrow-left'; 28890 arrowReposition = ''; 28891 } 28892 else { 28893 arrowReposition = 'left:'+ Math.round(arrowReposition) +'px;'; 28894 } 28895 28896 // building the logic to create the border around the arrow of the tooltip 28897 if ((practicalPosition == 'top') || (practicalPosition == 'top-left') || (practicalPosition == 'top-right')) { 28898 var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')), 28899 tooltipBorderColor = self.$tooltip.css('border-bottom-color'); 28900 } 28901 else if ((practicalPosition == 'bottom') || (practicalPosition == 'bottom-left') || (practicalPosition == 'bottom-right')) { 28902 var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-top-width')), 28903 tooltipBorderColor = self.$tooltip.css('border-top-color'); 28904 } 28905 else if (practicalPosition == 'left') { 28906 var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-right-width')), 28907 tooltipBorderColor = self.$tooltip.css('border-right-color'); 28908 } 28909 else if (practicalPosition == 'right') { 28910 var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-left-width')), 28911 tooltipBorderColor = self.$tooltip.css('border-left-color'); 28912 } 28913 else { 28914 var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')), 28915 tooltipBorderColor = self.$tooltip.css('border-bottom-color'); 28916 } 28917 28918 if (tooltipBorderWidth > 1) { 28919 tooltipBorderWidth++; 28920 } 28921 28922 var arrowBorder = ''; 28923 if (tooltipBorderWidth !== 0) { 28924 var arrowBorderSize = '', 28925 arrowBorderColor = 'border-color: '+ tooltipBorderColor +';'; 28926 if (arrowClass.indexOf('bottom') !== -1) { 28927 arrowBorderSize = 'margin-top: -'+ Math.round(tooltipBorderWidth) +'px;'; 28928 } 28929 else if (arrowClass.indexOf('top') !== -1) { 28930 arrowBorderSize = 'margin-bottom: -'+ Math.round(tooltipBorderWidth) +'px;'; 28931 } 28932 else if (arrowClass.indexOf('left') !== -1) { 28933 arrowBorderSize = 'margin-right: -'+ Math.round(tooltipBorderWidth) +'px;'; 28934 } 28935 else if (arrowClass.indexOf('right') !== -1) { 28936 arrowBorderSize = 'margin-left: -'+ Math.round(tooltipBorderWidth) +'px;'; 28937 } 28938 arrowBorder = '<span class="tooltipster-arrow-border" style="'+ arrowBorderSize +' '+ arrowBorderColor +';"></span>'; 28939 } 28940 28941 // if the arrow already exists, remove and replace it 28942 self.$tooltip.find('.tooltipster-arrow').remove(); 28943 28944 // build out the arrow and append it 28945 var arrowConstruct = '<div class="'+ arrowClass +' tooltipster-arrow" style="'+ arrowReposition +'">'+ arrowBorder +'<span style="border-color:'+ arrowColor +';"></span></div>'; 28946 self.$tooltip.append(arrowConstruct); 28947 } 28948 28949 // position the tooltip 28950 self.$tooltip.css({'top': Math.round(myTop) + 'px', 'left': Math.round(myLeft) + 'px'}); 28951 } 28952 } 28953 }; 28954 28955 $.fn[pluginName] = function () { 28956 28957 // for using in closures 28958 var args = arguments; 28959 28960 // if we are not in the context of jQuery wrapped HTML element(s) : 28961 // this happens when calling static methods in the form $.fn.tooltipster('methodName'), or when calling $(sel).tooltipster('methodName or options') where $(sel) does not match anything 28962 if (this.length === 0) { 28963
28964 // if the first argument is a method name 28965 if (typeof args[0] === 'string') { 28966 28967 var methodIsStatic = true; 28968 28969 // list static methods here (usable by calling $.fn.tooltipster('methodName');) 28970 switch (args[0]) { 28971 28972 case 'setDefaults': 28973 // change default options for all future instances 28974 $.extend(defaults, args[1]); 28975 break; 28976 28977 default: 28978 methodIsStatic = false; 28979 break; 28980 } 28981 28982 // $.fn.tooltipster('methodName') calls will return true 28983 if (methodIsStatic) return true; 28984 // $(sel).tooltipster('methodName') calls will return the list of objects event though it's empty because chaining should work on empty lists 28985 else return this; 28986 } 28987 // the first argument is undefined or an object of options : we are initalizing but there is no element matched by selector 28988 else { 28989 // still chainable : same as above 28990 return this; 28991 } 28992 } 28993 // this happens when calling $(sel).tooltipster('methodName or options') where $(sel) matches one or more elements 28994 else { 28995 28996 // method calls 28997 if (typeof args[0] === 'string') { 28998 28999 var v = '#*$~&'; 29000 29001 this.each(function() { 29002 29003 // self represent the instance of the tooltipster plugin associated to the current HTML object of the loop 29004 var self = $(this).data('tooltipster'); 29005 29006 // if the current element is a tooltipster instance 29007 if(self){ 29008 switch (args[0]) { 29009 29010 case 'content': 29011 // 'update' is deprecated but kept for retrocompatibility 29012 case 'update': 29013 // getter method 29014 if(typeof args[1] === 'undefined'){ 29015 v = self.content; 29016 // return false to stop .each iteration on the first element matched by the selector 29017 return false; 29018 } 29019 // setter method 29020 else { 29021 self.updateTooltip(args[1]); 29022 break; 29023 } 29024 29025 case 'destroy': 29026 self.hideTooltip(); 29027 29028 if(self.$el[0] !== self.$elProxy[0]) self.$elProxy.remove(); 29029 29030 // old school technique when outerHTML is not supported 29031 var stringifiedContent = (typeof self.content === 'string') ? self.content : $('<div></div>').append(self.content).html(); 29032 29033 self.$el 29034 .removeClass('tooltipstered') 29035 .attr('title', stringifiedContent) 29036 .removeData('tooltipster') 29037 .off('.'+ self.namespace); 29038 break; 29039 29040 case 'disable': 29041 // hide first, in case the tooltip would not disappear on its own (autoClose false) 29042 self.hideTooltip(); 29043 self.enabled = false; 29044 break; 29045 29046 case 'elementIcon': 29047 v = (self.$el[0] !== self.$elProxy[0]) ? self.$elProxy[0] : undefined; 29048 // return false : same as above 29049 return false; 29050 29051 case 'elementTooltip': 29052 v = self.$tooltip ? self.$tooltip[0] : undefined; 29053 // return false : same as above 29054 return false; 29055 29056 case 'enable': 29057 self.enabled = true; 29058 break; 29059 29060 case 'hide': 29061 self.hideTooltip(args[1]); 29062 break; 29063 29064 // for internal use only 29065 case 'option': 29066 v = self.options[args[1]]; 29067 return false; 29068 29069 case 'reposition': 29070 self.positionTooltip(); 29071 break; 29072 29073 case 'show': 29074 self.showTooltipNow(args[1]); 29075 break; 29076 29077 // for internal use use only, not part of the public API 29078 case 'status': 29079 v = self.status; 29080 return false; 29081 29082 default: 29083 throw new Error('Unknown method .tooltipster("' + args[0] + '")'); 29084 break; 29085 } 29086 } 29087 else { 29088 throw new Error('You called Tooltipster\'s "' + args[0] + '" method on an uninitialized element'); 29089 } 29090 }); 29091 29092 return (v !== '#*$~&') ? v : this; 29093 } 29094 // first argument is undefined or an object : the tooltip is initializing 29095 else { 29096 // initialize a tooltipster instance for each element if it doesn't already have one, and attach the object to it 29097 return this.each(function () { 29098 29099 if (!$(this).data('tooltipster')) { 29100 $(this).data('tooltipster', new Plugin( this, args[0] )); 29101 } 29102 }); 29103 } 29104 } 29105 }; 29106 29107 // quick & dirty compare function (not bijective nor multidimensional) 29108 function areEqual(a,b) { 29109 var same = true; 29110 $.each(a, function(i, el){ 29111 if(typeof b[i] === 'undefined' || a[i] !== b[i]){ 29112 same = false;
29113 return false; 29114 } 29115 }); 29116 return same; 29117 } 29118 29119 // detect if this device can trigger touch events 29120 var deviceHasTouchCapability = !!('ontouchstart' in window); 29121 29122 // we'll assume the device has no mouse until we detect any mouse movement 29123 var deviceHasMouse = false; 29124 $('body').one('mousemove', function() { 29125 deviceHasMouse = true; 29126 }); 29127 29128 function deviceIsPureTouch() { 29129 return (!deviceHasMouse && deviceHasTouchCapability); 29130 } 29131 29132 // detecting support for CSS transitions 29133 function supportsTransitions() { 29134 var b = document.body || document.documentElement, 29135 s = b.style, 29136 p = 'transition'; 29137 29138 if(typeof s[p] == 'string') {return true; } 29139 29140 v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'], 29141 p = p.charAt(0).toUpperCase() + p.substr(1); 29142 for(var i=0; i<v.length; i++) { 29143 if(typeof s[v[i] + p] == 'string') { return true; } 29144 } 29145 return false; 29146 } 29147})( jQuery, window, document ); 29148(function() { 29149 String.prototype.toCamel = function() { 29150 return this.replace(/(\_[a-z])/g, function($1) { 29151 return $1.toUpperCase().replace("_", ""); 29152 }); 29153 }; 29154 29155 String.prototype.camelToUnderscore = function() { 29156 return this.replace(/\W+/g, '-').replace(/([a-z\d])([A-Z])/g, '$1_$2').toLowerCase(); 29157 }; 29158 29159 String.prototype.capitalizeFirst = function() { 29160 return this.charAt(0).toUpperCase() + this.slice(1); 29161 }; 29162 29163 String.prototype.truncate = function(length) { 29164 if (length == null) { 29165 length = 30; 29166 } 29167 if (this.length > length) { 29168 return this.substring(0, length) + '...'; 29169 } else { 29170 return String(this); 29171 } 29172 }; 29173 29174 this.parseDate = function(date) { 29175 var m, tzOffset; 29176 m = /^(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d) UTC$/.exec(date); 29177 tzOffset = new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]).getTimezoneOffset(); 29178 return new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5] - tzOffset, +m[6]); 29179 }; 29180 29181}).call(this); 29182/*! 29183* Mediator.js Library v0.9.8 29184* https://github.com/ajacksified/Mediator.js 29185* 29186* MIT Licensed (http://www.opensource.org/licenses/mit-license.php) 29187* 29188* For more information: http://thejacklawson.com/2011/06/mediators-for-modularized-asynchronous-programming-in-javascript/index.html 29189* Project on GitHub: https://github.com/ajacksified/Mediator.js 29190* 29191*/ 29192 29193 29194!function(a,b){"use strict";"function"==typeof define&&define.amd?define("mediator-js",[],function(){return a.Mediator=b(),a.Mediator}):"undefined"!=typeof exports?exports.Mediator=b():a.Mediator=b()}(this,function(){"use strict";function a(){var a=function(){return(0|65536*(1+Math.random())).toString(16).substring(1)};return a()+a()+"-"+a()+"-"+a()+"-"+a()+"-"+a()+a()+a()}function b(c,d,e){return this instanceof b?(this.id=a(),this.fn=c,this.options=d,this.context=e,this.channel=null,void 0):new b(c,d,e)}function c(a,b){return this instanceof c?(this.namespace=a||"",this._subscribers=[],this._channels={},this._parent=b,this.stopped=!1,void 0):new c(a)}function d(){return this instanceof d?(this._channels=new c(""),void 0):new d}return b.prototype={update:function(a){a&&(this.fn=a.fn||this.fn,this.context=a.context||this.context,this.options=a.options||this.options,this.channel&&this.options&&void 0!==this.options.priority&&this.channel.setPriority(this.id,this.options.priority))}},c.prototype={addSubscriber:function(a,c,d){var e=new b(a,c,d);return c&&void 0!==c.priority?(c.priority=c.priority>>0,c.priority<0&&(c.priority=0),c.priority>=this._subscribers.length&&(c.priority=this._subscribers.length-1),this._subscribers.splice(c.priority,0,e)):this._subscribers.push(e),e.channel=this,e},stopPropagation:function(){this.stopped=!0},getSubscriber:function(a){var b=0,c=this._subscribers.length;for(c;c>b;b++)if(this._subscribers[b].id===a||this._subscribers[b].fn===a)return this._subscribers[b]},setPriority:function(a,b){var e,f,g,h,c=0,d=0;for(d=0,h=this._subscribers.length;h>d&&this._subscribers[d].id!==a&&this._subscribers[d].fn!==a;d++)c++;e=this._subscribers[c],f=this._subscribers.slice(0,c),g=this._subscribers.slice(c+1),this._subscribers=f.concat(g),this._subscribers.splice(b,0,e)},addChannel:function(a){this._channels[a]=new c((this.namespace?this.namespace+":":"")+a,this)},hasChannel:function(a){return this._channels.hasOwnProperty(a)},returnChannel:function(a){return this._channels[a]},removeSubscriber:function(a){var b=this._subscribers.length-1;if(!a)return this._subscribers=[],void 0;for(b;b>=0;b--)(this._subscribers[b].fn===a||this._subscribers[b].id===a)&&(this._subscribers[b].channel=null,this._subscribers.splice(b,1))},publish:function(a){var e,g,h,b=0,c=this._subscribers.length,d=!1;for(c;c>b;b++)d=!1,e=this._subscribers[b],this.stopped||(g=this._subscribers.length,void 0!==e.options&&"function"==typeof e.o
29194ptions.predicate?e.options.predicate.apply(e.context,a)&&(d=!0):d=!0),d&&(e.options&&void 0!==e.options.calls&&(e.options.calls--,e.options.calls<1&&this.removeSubscriber(e.id)),e.fn.apply(e.context,a),h=this._subscribers.length,c=h,h===g-1&&b--);this._parent&&this._parent.publish(a),this.stopped=!1}},d.prototype={getChannel:function(a,b){var c=this._channels,d=a.split(":"),e=0,f=d.length;if(""===a)return c;if(d.length>0)for(f;f>e;e++){if(!c.hasChannel(d[e])){if(b)break;c.addChannel(d[e])}c=c.returnChannel(d[e])}return c},subscribe:function(a,b,c,d){var e=this.getChannel(a||"",!1);return c=c||{},d=d||{},e.addSubscriber(b,c,d)},once:function(a,b,c,d){return c=c||{},c.calls=1,this.subscribe(a,b,c,d)},getSubscriber:function(a,b){var c=this.getChannel(b||"",!0);return c.namespace!==b?null:c.getSubscriber(a)},remove:function(a,b){var c=this.getChannel(a||"",!0);return c.namespace!==a?!1:(c.removeSubscriber(b),void 0)},publish:function(a){var b=this.getChannel(a||"",!0);if(b.namespace!==a)return null;var c=Array.prototype.slice.call(arguments,1);c.push(b),b.publish(c)}},d.prototype.on=d.prototype.subscribe,d.prototype.bind=d.prototype.subscribe,d.prototype.emit=d.prototype.publish,d.prototype.trigger=d.prototype.publish,d.prototype.off=d.prototype.remove,d.Channel=c,d.Subscriber=b,d.version="0.9.8",d}); 29195(function() { 29196 var context = this; 29197 29198 (function() { 29199 (function() { 29200 var slice = [].slice; 29201 29202 this.ActionCable = { 29203 INTERNAL: { 29204 "message_types": { 29205 "welcome": "welcome", 29206 "ping": "ping", 29207 "confirmation": "confirm_subscription", 29208 "rejection": "reject_subscription" 29209 }, 29210 "default_mount_path": "/cable", 29211 "protocols": ["actioncable-v1-json", "actioncable-unsupported"] 29212 }, 29213 WebSocket: window.WebSocket, 29214 logger: window.console, 29215 createConsumer: function(url) { 29216 var ref; 29217 if (url == null) { 29218 url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path; 29219 } 29220 return new ActionCable.Consumer(this.createWebSocketURL(url)); 29221 }, 29222 getConfig: function(name) { 29223 var element; 29224 element = document.head.querySelector("meta[name='action-cable-" + name + "']"); 29225 return element != null ? element.getAttribute("content") : void 0; 29226 }, 29227 createWebSocketURL: function(url) { 29228 var a; 29229 if (url && !/^wss?:/i.test(url)) { 29230 a = document.createElement("a"); 29231 a.href = url; 29232 a.href = a.href; 29233 a.protocol = a.protocol.replace("http", "ws"); 29234 return a.href; 29235 } else { 29236 return url; 29237 } 29238 }, 29239 startDebugging: function() { 29240 return this.debugging = true; 29241 }, 29242 stopDebugging: function() { 29243 return this.debugging = null; 29244 }, 29245 log: function() { 29246 var messages, ref; 29247 messages = 1 <= arguments.length ? slice.call(arguments, 0) : []; 29248 if (this.debugging) { 29249 messages.push(Date.now()); 29250 return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages))); 29251 } 29252 } 29253 }; 29254 29255 }).call(this); 29256 }).call(context); 29257 29258 var ActionCable = context.ActionCable; 29259 29260 (function() { 29261 (function() { 29262 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 29263 29264 ActionCable.ConnectionMonitor = (function() { 29265 var clamp, now, secondsSince; 29266 29267 ConnectionMonitor.pollInterval = { 29268 min: 3, 29269 max: 30 29270 }; 29271 29272 ConnectionMonitor.staleThreshold = 6; 29273 29274 function ConnectionMonitor(connection) { 29275 this.connection = connection; 29276 this.visibilityDidChange = bind(this.visibilityDidChange, this); 29277 this.reconnectAttempts = 0; 29278 } 29279 29280 ConnectionMonitor.prototype.start = function() { 29281 if (!this.isRunning()) { 29282 this.startedAt = now(); 29283 delete this.stoppedAt; 29284 this.startPolling(); 29285 document.addEventListener("visibilitychange", this.visibilityDidChange); 29286 return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms"); 29287 } 29288 }; 29289 29290 ConnectionMonitor.prototype.stop = function() { 29291 if (this.isRunning()) { 29292 this.stoppedAt = now(); 29293 this.stopPolling(); 29294 document.removeEventListener("visibilitychange", this.visibilityDidChange); 29295 return ActionCable.log("ConnectionMonitor stopped"); 29296 } 29297 }; 29298 29299 ConnectionMonitor.prototype.isRunning = function() { 29300 return (this.startedAt != null) && (this.stoppedAt == null); 29301 }; 29302 29303 ConnectionMonitor.prototype.recordPing = function() { 29304 return this.pingedAt = now(); 29305 }; 29306 29307 ConnectionMonitor.prototype.recordConnect = function() { 29308 this.reconnectAttempts = 0; 29309 this.recordPing(); 29310 delete this.disconnectedAt; 29311 return ActionCable.log("ConnectionMonitor recorded connect"); 29312 }; 29313 29314 ConnectionMonitor.prototype.recordDisconnect = function() { 29315 this.disconnectedAt = now(); 29316 return ActionCable.log("ConnectionMonitor recorded disconnect"); 29317 }; 29318 29319 ConnectionMonitor.prototype.startPolling = function() { 29320 this.stopPolling(); 29321 return this.poll(); 29322 }; 29323 29324 ConnectionMonitor.prototype.stopPolling = function() { 29325 return clearTimeout(this.pollTimeout); 29326 }; 29327 29328 ConnectionMonitor.prototype.poll = function() { 29329 return this.pollTimeout = setTimeout((function(_this) { 29330 return function() { 29331 _this.reconnectIfStale(); 29332 return _this.poll(); 29333 }; 29334 })(this), this.getPollInterval()); 29335 }; 29336 29337 ConnectionMonitor.prototype.getPollInterval = function() { 29338 var interval, max, min, ref; 29339 ref = this.constructor.pollInterval, min = ref.min, max = ref.max; 29340 interval = 5 * Math.log(this.reconnectAttempts + 1); 29341 return Math.round(clamp(interval, min, max) * 1000); 29342 }; 29343 29344 ConnectionMonitor.prototype.reconnectIfStale = function() { 29345 if (this.connectionIsStale()) {
29346 ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); 29347 this.reconnectAttempts++; 29348 if (this.disconnectedRecently()) { 29349 return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect"); 29350 } else { 29351 ActionCable.log("ConnectionMonitor reopening"); 29352 return this.connection.reopen(); 29353 } 29354 } 29355 }; 29356 29357 ConnectionMonitor.prototype.connectionIsStale = function() { 29358 var ref; 29359 return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold; 29360 }; 29361 29362 ConnectionMonitor.prototype.disconnectedRecently = function() { 29363 return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; 29364 }; 29365 29366 ConnectionMonitor.prototype.visibilityDidChange = function() { 29367 if (document.visibilityState === "visible") { 29368 return setTimeout((function(_this) { 29369 return function() { 29370 if (_this.connectionIsStale() || !_this.connection.isOpen()) { 29371 ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState); 29372 return _this.connection.reopen(); 29373 } 29374 }; 29375 })(this), 200); 29376 } 29377 }; 29378 29379 now = function() { 29380 return new Date().getTime(); 29381 }; 29382 29383 secondsSince = function(time) { 29384 return (now() - time) / 1000; 29385 }; 29386 29387 clamp = function(number, min, max) { 29388 return Math.max(min, Math.min(max, number)); 29389 }; 29390 29391 return ConnectionMonitor; 29392 29393 })(); 29394 29395 }).call(this); 29396 (function() { 29397 var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol, 29398 slice = [].slice, 29399 bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 29400 indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 29401 29402 ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols; 29403 29404 supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++]; 29405 29406 ActionCable.Connection = (function() { 29407 Connection.reopenDelay = 500; 29408 29409 function Connection(consumer) { 29410 this.consumer = consumer; 29411 this.open = bind(this.open, this); 29412 this.subscriptions = this.consumer.subscriptions; 29413 this.monitor = new ActionCable.ConnectionMonitor(this); 29414 this.disconnected = true; 29415 } 29416 29417 Connection.prototype.send = function(data) { 29418 if (this.isOpen()) { 29419 this.webSocket.send(JSON.stringify(data)); 29420 return true; 29421 } else { 29422 return false; 29423 } 29424 }; 29425 29426 Connection.prototype.open = function() { 29427 if (this.isActive()) { 29428 ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState())); 29429 return false; 29430 } else { 29431 ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols); 29432 if (this.webSocket != null) { 29433 this.uninstallEventHandlers(); 29434 } 29435 this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols); 29436 this.installEventHandlers(); 29437 this.monitor.start(); 29438 return true; 29439 } 29440 }; 29441 29442 Connection.prototype.close = function(arg) { 29443 var allowReconnect, ref1; 29444 allowReconnect = (arg != null ? arg : { 29445 allowReconnect: true 29446 }).allowReconnect; 29447 if (!allowReconnect) { 29448 this.monitor.stop(); 29449 } 29450 if (this.isActive()) { 29451 return (ref1 = this.webSocket) != null ? ref1.close() : void 0; 29452 } 29453 }; 29454 29455 Connection.prototype.reopen = function() { 29456 var error; 29457 ActionCable.log("Reopening WebSocket, current state is " + (this.getState())); 29458 if (this.isActive()) { 29459 try { 29460 return this.close(); 29461 } catch (error1) { 29462 error = error1; 29463 return ActionCable.log("Failed to reopen WebSocket", error); 29464 } finally { 29465 ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); 29466 setTimeout(this.open, this.constructor.reopenDelay); 29467 } 29468 } else { 29469 return this.open(); 29470 } 29471 }; 29472 29473 Connection.prototype.getProtocol = function() { 29474 var ref1; 29475 return (ref1 = this.webSocket) != null ? ref1.protocol : void 0; 29476 }; 29477 29478 Connection.prototype.isOpen = function() { 29479 return this.isState("open"); 29480 }; 29481 29482 Connection.prototype.isActive = function() { 29483 return this.isState("open", "connecting"); 29484 }; 29485
29486 Connection.prototype.isProtocolSupported = function() { 29487 var ref1; 29488 return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0; 29489 }; 29490 29491 Connection.prototype.isState = function() { 29492 var ref1, states; 29493 states = 1 <= arguments.length ? slice.call(arguments, 0) : []; 29494 return ref1 = this.getState(), indexOf.call(states, ref1) >= 0; 29495 }; 29496 29497 Connection.prototype.getState = function() { 29498 var ref1, state, value; 29499 for (state in WebSocket) { 29500 value = WebSocket[state]; 29501 if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) { 29502 return state.toLowerCase(); 29503 } 29504 } 29505 return null; 29506 }; 29507 29508 Connection.prototype.installEventHandlers = function() { 29509 var eventName, handler; 29510 for (eventName in this.events) { 29511 handler = this.events[eventName].bind(this); 29512 this.webSocket["on" + eventName] = handler; 29513 } 29514 }; 29515 29516 Connection.prototype.uninstallEventHandlers = function() { 29517 var eventName; 29518 for (eventName in this.events) { 29519 this.webSocket["on" + eventName] = function() {}; 29520 } 29521 }; 29522 29523 Connection.prototype.events = { 29524 message: function(event) { 29525 var identifier, message, ref1, type; 29526 if (!this.isProtocolSupported()) { 29527 return; 29528 } 29529 ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type; 29530 switch (type) { 29531 case message_types.welcome: 29532 this.monitor.recordConnect(); 29533 return this.subscriptions.reload(); 29534 case message_types.ping: 29535 return this.monitor.recordPing(); 29536 case message_types.confirmation: 29537 return this.subscriptions.notify(identifier, "connected"); 29538 case message_types.rejection: 29539 return this.subscriptions.reject(identifier); 29540 default: 29541 return this.subscriptions.notify(identifier, "received", message); 29542 } 29543 }, 29544 open: function() { 29545 ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol"); 29546 this.disconnected = false; 29547 if (!this.isProtocolSupported()) { 29548 ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting."); 29549 return this.close({ 29550 allowReconnect: false 29551 }); 29552 } 29553 }, 29554 close: function(event) { 29555 ActionCable.log("WebSocket onclose event"); 29556 if (this.disconnected) { 29557 return; 29558 } 29559 this.disconnected = true; 29560 this.monitor.recordDisconnect(); 29561 return this.subscriptions.notifyAll("disconnected", { 29562 willAttemptReconnect: this.monitor.isRunning() 29563 }); 29564 }, 29565 error: function() { 29566 return ActionCable.log("WebSocket onerror event"); 29567 } 29568 }; 29569 29570 return Connection; 29571 29572 })(); 29573 29574 }).call(this); 29575 (function() { 29576 var slice = [].slice; 29577 29578 ActionCable.Subscriptions = (function() { 29579 function Subscriptions(consumer) { 29580 this.consumer = consumer; 29581 this.subscriptions = []; 29582 } 29583 29584 Subscriptions.prototype.create = function(channelName, mixin) { 29585 var channel, params, subscription; 29586 channel = channelName; 29587 params = typeof channel === "object" ? channel : { 29588 channel: channel 29589 }; 29590 subscription = new ActionCable.Subscription(this.consumer, params, mixin); 29591 return this.add(subscription); 29592 }; 29593 29594 Subscriptions.prototype.add = function(subscription) { 29595 this.subscriptions.push(subscription); 29596 this.consumer.ensureActiveConnection(); 29597 this.notify(subscription, "initialized"); 29598 this.sendCommand(subscription, "subscribe"); 29599 return subscription; 29600 }; 29601 29602 Subscriptions.prototype.remove = function(subscription) { 29603 this.forget(subscription); 29604 if (!this.findAll(subscription.identifier).length) { 29605 this.sendCommand(subscription, "unsubscribe"); 29606 } 29607 return subscription; 29608 }; 29609 29610 Subscriptions.prototype.reject = function(identifier) { 29611 var i, len, ref, results, subscription; 29612 ref = this.findAll(identifier); 29613 results = []; 29614 for (i = 0, len = ref.length; i < len; i++) { 29615 subscription = ref[i]; 29616 this.forget(subscription); 29617 this.notify(subscription, "rejected"); 29618 results.push(subscription); 29619 } 29620 return results; 29621 }; 29622 29623 Subscriptions.prototype.forget = function(subscription) { 29624 var s; 29625 this.subscriptions = (function() { 29626 var i, len, ref, results; 29627 ref = this.subscriptions; 29628 results = []; 29629 for (i = 0, len = ref.length; i < len; i++) { 29630 s = ref[i]; 29631 if (s !== subscription) { 29632 results.push(s); 29633 } 29634 } 29635 return results; 29636 }).call(this); 29637 return subscription; 29638 }; 29639 29640 Subscriptions.prototype.findAll = function(identifier) { 29641 var i, len, ref, results, s; 29642 ref = this.subscriptions; 29643 results = []; 29644 for (i = 0, len = ref.length; i < len; i++) { 29645 s = ref[i]; 29646 if (s.identifier === identifier) { 29647 results.push(s); 29648 } 29649 } 29650 return results; 29651 }; 29652 29653 Subscriptions.prototype.reload = function() { 29654 var i, len, ref, results, subscription; 29655 ref = this.subscriptions; 29656 results = []; 29657 for (i = 0, len = ref.length; i < len; i++) { 29658 subscription = ref[i]; 29659 results.push(this.sendCommand(subscription, "subscribe")); 29660 } 29661 return results; 29662 }; 29663 29664 Subscriptions.prototype.notifyAll = function() { 29665 var args, callbackName, i, len, ref, results, subscription; 29666 callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; 29667 ref = this.subscriptions; 29668 results = []; 29669 for (i = 0, len = ref.length; i < len; i++) { 29670 subscription = ref[i]; 29671 results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args)))); 29672 } 29673 return results; 29674 }; 29675 29676 Subscriptions.prototype.notify = function() { 29677 var args, callbackName, i, len, results, subscription, subscriptions; 29678 subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; 29679 if (typeof subscription === "string") { 29680 subscriptions = this.findAll(subscription); 29681 } else { 29682 subscriptions = [subscription]; 29683 } 29684 results = []; 29685 for (i = 0, len = subscriptions.length; i < len; i++) { 29686 subscription = subscriptions[i]; 29687 results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0); 29688 } 29689 return results; 29690 }; 29691 29692 Subscriptions.prototype.sendCommand = function(subscription, command) { 29693 var identifier; 29694 identifier = subscription.identifier; 29695 return this.consumer.send({ 29696 command: command, 29697 identifier: identifier 29698 }); 29699 }; 29700 29701 return Subscriptions; 29702 29703 })(); 29704 29705 }).call(this); 29706 (function() { 29707 ActionCable.Subscription = (function() { 29708 var extend; 29709 29710 function Subscription(consumer, params, mixin) { 29711 this.consumer = consumer; 29712 if (params == null) { 29713 params = {}; 29714 } 29715 this.identifier = JSON.stringify(params); 29716 extend(this, mixin); 29717 } 29718 29719 Subscription.prototype.perform = function(action, data) { 29720 if (data == null) { 29721 data = {}; 29722 } 29723 data.action = action; 29724 return this.send(data); 29725 }; 29726 29727 Subscription.prototype.send = function(data) { 29728 return this.consumer.send({ 29729 command: "message", 29730 identifier: this.identifier, 29731 data: JSON.stringify(data) 29732 }); 29733 }; 29734 29735 Subscription.prototype.unsubscribe = function() { 29736 return this.consumer.subscriptions.remove(this); 29737 }; 29738 29739 extend = function(object, properties) { 29740 var key, value; 29741 if (properties != null) { 29742 for (key in properties) { 29743 value = properties[key]; 29744 object[key] = value; 29745 } 29746 } 29747 return object; 29748 }; 29749 29750 return Subscription; 29751 29752 })(); 29753 29754 }).call(this); 29755 (function() { 29756 ActionCable.Consumer = (function() { 29757 function Consumer(url) { 29758 this.url = url; 29759 this.subscriptions = new ActionCable.Subscriptions(this); 29760 this.connection = new ActionCable.Connection(this); 29761 } 29762 29763 Consumer.prototype.send = function(data) { 29764 return this.connection.send(data); 29765 }; 29766 29767 Consumer.prototype.connect = function() { 29768 return this.connection.open(); 29769 }; 29770 29771 Consumer.prototype.disconnect = function() { 29772 return this.connection.close({ 29773 allowReconnect: false 29774 }); 29775 }; 29776 29777 Consumer.prototype.ensureActiveConnection = function() { 29778 if (!this.connection.isActive()) { 29779 return this.connection.open(); 29780 } 29781 }; 29782 29783 return Consumer; 29784 29785 })(); 29786 29787 }).call(this); 29788 }).call(this); 29789 29790 if (typeof module === "object" && module.exports) { 29791 module.exports = ActionCable; 29792 } else if (typeof define === "function" && define.amd) { 29793 define(ActionCable); 29794 } 29795}).call(this); 29796(function() { 29797 var config, mediator, settings; 29798 29799 mediator = typeof window.App !== 'undefined' && typeof window.App.events !== 'undefined' ? window.App.events : new Mediator(); 29800 29801 config = typeof window.App !== 'undefined' && typeof (window.App.config !== 'undefined') ? window.App.config : {}; 29802 29803 window.App = { 29804 Core: {}, 29805 Pages: {}, 29806 Widgets: {}, 29807 Modules: {}, 29808 Models: {}, 29809 Collections: {}, 29810 Routers: {}, 29811 Views: {}, 29812 events: mediator, 29813 config: config, 29814 state: {}, 29815 cable: {} 29816 }; 29817 29818 settings = $('#application-settings').data(); 29819 29820 if (settings != null ? settings.userSignedIn : void 0) { 29821 window.App.cable = ActionCable.createConsumer(); 29822 window.App.cable.subscriptions.create({ 29823 channel: 'AppearanceChannel' 29824 }); 29825 } 29826 29827}).call(this); 29828(function() { 29829 if (App.Core == null) { 29830 App.Core = {}; 29831 } 29832 29833 App.Core.Page = (function() { 29834 Page.prototype.widgets = []; 29835 29836 Page.prototype._widgetInstances = {}; 29837 29838 function Page() { 29839 $.extend(this, App.Core.Page); 29840 this._loadWidgets(); 29841 } 29842 29843 Page.prototype._loadWidget = function(name) { 29844 var klass; 29845 klass = name.capitalizeFirst(); 29846 if (App.Widgets[klass] == null) { 29847 if (typeof console !== "undefined" && console !== null) { 29848 if (typeof console.warn === "function") { 29849 console.warn("Widget " + name + " - App.Widgets." + klass + " not found!"); 29850 } 29851 } 29852 return; 29853 } 29854 this._widgetInstances[name] = new App.Widgets[klass]; 29855 return this._widgetInstances[name].initialize(); 29856 }; 29857 29858 Page.prototype._loadWidgets = function() { 29859 return _.each(this.widgets, (function(_this) { 29860 return function(name) { 29861 return _this._loadWidget(name); 29862 }; 29863 })(this)); 29864 }; 29865 29866 Page.prototype.initialize = function() {}; 29867 29868 return Page; 29869 29870 })(); 29871 29872}).call(this); 29873(function() { 29874 App.events.subscribe('app:page:execute', function() { 29875 var action, controller, globalPageInstance, hasNamespace, namespace, page, pageInstance, pageName; 29876 controller = document.body.getAttribute('data-controller'); 29877 action = document.body.getAttribute('data-action');
29878 page = (controller + "_" + action).toCamel(); 29879 page = page.charAt(0).toUpperCase() + page.slice(1); 29880 I18n.locale = document.getElementsByTagName('html')[0].getAttribute('lang'); 29881 I18n.fallbacks = true; 29882 hasNamespace = _.rest(page.split("/")).length !== 0; 29883 if (App.Pages.Global != null) { 29884 globalPageInstance = new App.Pages.Global; 29885 if (globalPageInstance != null) { 29886 globalPageInstance.initialize(); 29887 } 29888 } 29889 if (hasNamespace) { 29890 namespace = _.first(page.split("/")); 29891 pageName = (_.rest(page.split("/")).map(function(word) { 29892 return word[0].toUpperCase() + word.slice(1); 29893 })).join(''); 29894 if ((App.Pages[namespace] != null) && (App.Pages[namespace][pageName] != null)) { 29895 pageInstance = new App.Pages[namespace][pageName]; 29896 } 29897 } else { 29898 if (App.Pages[page] != null) { 29899 pageInstance = new App.Pages[page]; 29900 } 29901 } 29902 return pageInstance != null ? pageInstance.initialize() : void 0; 29903 }); 29904 29905 App.events.subscribe('app:config:load', function(data) { 29906 _.extend(App.config, data); 29907 return App.state.csrfToken = $("meta[name='csrf-token']").attr('content'); 29908 }); 29909 29910}).call(this); 29911(function() { 29912 29913 29914}).call(this); 29915(function() { 29916 App.events.subscribe('app:ui:refresh', function(scope) { 29917 var $scope; 29918 $scope = $(scope); 29919 $scope.find('.select').chosen({ 29920 disable_search_threshold: 10, 29921 search_contains: true 29922 }); 29923 $scope.find('.has-tooltip, .js-tooltip').tooltipster({ 29924 theme: 'tooltip--light', 29925 animation: 'grow' 29926 }); 29927 $scope.find('.js-popover').tooltipster({ 29928 theme: 'tooltip--light tooltip--popover', 29929 animation: 'grow', 29930 interactive: true, 29931 contentAsHTML: true, 29932 functionInit: function(origin) { 29933 return origin.data('content'); 29934 } 29935 }); 29936 return $scope.find('[data-check-control]').checkControl(); 29937 }); 29938 29939 App.events.subscribe('app:ui:init', function() { 29940 App.events.publish('app:ui:refresh', 'body'); 29941 App.events.publish('app:bg:init'); 29942 return App.events.publish('app:action-bar:init'); 29943 }); 29944 29945 App.events.subscribe('app:element:focus', function($el, delay) { 29946 if (delay == null) { 29947 delay = 0; 29948 } 29949 return setTimeout(function() { 29950 return $('html, body').animate({ 29951 scrollTop: $el.offset().top, 29952 easing: 'easeInOutCirc' 29953 }, { 29954 easing: 'easeInOutCirc', 29955 duration: 600 29956 }); 29957 }, delay); 29958 }); 29959 29960 App.events.subscribe('app:bg:init', function() { 29961 var $backgrounds; 29962 $backgrounds = $('.js-bg').not('.is-loaded'); 29963 $backgrounds.addClass('is-loading'); 29964 return $backgrounds.each(function(index, el) { 29965 var deferred, trigger; 29966 trigger = $(el).data('trigger'); 29967 switch (trigger) { 29968 case 'load': 29969 deferred = $.Deferred(function(promise) { 29970 return $(function() { 29971 return promise.resolve(); 29972 }); 29973 }); 29974 break; 29975 case 'delay': 29976 deferred = $.Deferred(function(promise) { 29977 var delay; 29978 delay = parseInt($(el).data('delay'), 10); 29979 return setTimeout(function() { 29980 return promise.resolve(); 29981 }, delay); 29982 }); 29983 break; 29984 default: 29985 deferred = $.Deferred(function(promise) { 29986 return promise.resolve(); 29987 }); 29988 } 29989 return deferred.then(function() { 29990 var img, imgLoad; 29991 img = new Image(); 29992 img.src = $(el).data('bg'); 29993 imgLoad = imagesLoaded(img); 29994 imgLoad.on('done', function() { 29995 return $(el).backstretch([$(el).data('bg')], { 29996 fade: 600 29997 }); 29998 }); 29999 return imgLoad.on('always', function() { 30000 return $(el).removeClass('is-loading').addClass('is-loaded'); 30001 }); 30002 }); 30003 }); 30004 }); 30005 30006 App.events.subscribe('app:action-bar:init', function() { 30007 var $actionBar, $siteFooter, actionBarHeight; 30008 $actionBar = $('.action-bar'); 30009 $siteFooter = $('.site-footer'); 30010 if (!($actionBar.exists() && $siteFooter.exists())) { 30011 return; 30012 } 30013 actionBarHeight = $(window).innerHeight() - $actionBar.position().top; 30014 return $siteFooter.css('margin-bottom', actionBarHeight); 30015 }); 30016 30017}).call(this); 30018(function() { 30019 30020 30021}).call(this); 30022// Backbone.js 1.1.2 30023 30024// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 30025// Backbone may be freely distributed under the MIT license. 30026// For all details and documentation: 30027// http://backbonejs.org 30028 30029(function(root, factory) { 30030 30031 // Set up Backbone appropriately for the environment. Start with AMD. 30032 if (typeof define === 'function' && define.amd) { 30033 define(['underscore', 'jquery', 'exports'], function(_, $, exports
30033) { 30034 // Export global even in AMD case in case this script is loaded with 30035 // others that may still expect a global Backbone. 30036 root.Backbone = factory(root, exports, _, $); 30037 }); 30038 30039 // Next for Node.js or CommonJS. jQuery may not be needed as a module. 30040 } else if (typeof exports !== 'undefined') { 30041 var _ = require('underscore'); 30042 factory(root, exports, _); 30043 30044 // Finally, as a browser global. 30045 } else { 30046 root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); 30047 } 30048 30049}(this, function(root, Backbone, _, $) { 30050 30051 // Initial Setup 30052 // ------------- 30053 30054 // Save the previous value of the `Backbone` variable, so that it can be 30055 // restored later on, if `noConflict` is used. 30056 var previousBackbone = root.Backbone; 30057 30058 // Create local references to array methods we'll want to use later. 30059 var array = []; 30060 var push = array.push; 30061 var slice = array.slice; 30062 var splice = array.splice; 30063 30064 // Current version of the library. Keep in sync with `package.json`. 30065 Backbone.VERSION = '1.1.2'; 30066 30067 // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns 30068 // the `$` variable. 30069 Backbone.$ = $; 30070 30071 // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable 30072 // to its previous owner. Returns a reference to this Backbone object. 30073 Backbone.noConflict = function() { 30074 root.Backbone = previousBackbone; 30075 return this; 30076 }; 30077 30078 // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option 30079 // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and 30080 // set a `X-Http-Method-Override` header. 30081 Backbone.emulateHTTP = false;
30082 30083 // Turn on `emulateJSON` to support legacy servers that can't deal with direct 30084 // `application/json` requests ... will encode the body as 30085 // `application/x-www-form-urlencoded` instead and will send the model in a 30086 // form param named `model`. 30087 Backbone.emulateJSON = false; 30088 30089 // Backbone.Events 30090 // --------------- 30091 30092 // A module that can be mixed in to *any object* in order to provide it with 30093 // custom events. You may bind with `on` or remove with `off` callback 30094 // functions to an event; `trigger`-ing an event fires all callbacks in 30095 // succession. 30096 // 30097 // var object = {}; 30098 // _.extend(object, Backbone.Events); 30099 // object.on('expand', function(){ alert('expanded'); }); 30100 // object.trigger('expand'); 30101 // 30102 var Events = Backbone.Events = { 30103 30104 // Bind an event to a `callback` function. Passing `"all"` will bind 30105 // the callback to all events fired. 30106 on: function(name, callback, context) { 30107 if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; 30108 this._events || (this._events = {}); 30109 var events = this._events[name] || (this._events[name] = []); 30110 events.push({callback: callback, context: context, ctx: context || this}); 30111 return this; 30112 }, 30113 30114 // Bind an event to only be triggered a single time. After the first time 30115 // the callback is invoked, it will be removed. 30116 once: function(name, callback, context) { 30117 if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; 30118 var self = this; 30119 var once = _.once(function() { 30120 self.off(name, once); 30121 callback.apply(this, arguments); 30122 }); 30123 once._callback = callback; 30124 return this.on(name, once, context); 30125 }, 30126 30127 // Remove one or many callbacks. If `context` is null, removes all 30128 // callbacks with that function. If `callback` is null, removes all 30129 // callbacks for the event. If `name` is null, removes all bound 30130 // callbacks for all events. 30131 off: function(name, callback, context) { 30132 var retain, ev, events, names, i, l, j, k; 30133 if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; 30134 if (!name && !callback && !context) { 30135 this._events = void 0; 30136 return this; 30137 } 30138 names = name ? [name] : _.keys(this._events); 30139 for (i = 0, l = names.length; i < l; i++) { 30140 name = names[i]; 30141 if (events = this._events[name]) { 30142 this._events[name] = retain = []; 30143 if (callback || context) { 30144 for (j = 0, k = events.length; j < k; j++) { 30145 ev = events[j]; 30146 if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || 30147 (context && context !== ev.context)) { 30148 retain.push(ev); 30149 } 30150 } 30151 } 30152 if (!retain.length) delete this._events[name]; 30153 } 30154 } 30155 30156 return this; 30157 }, 30158 30159 // Trigger one or many events, firing all bound callbacks. Callbacks are 30160 // passed the same arguments as `trigger` is, apart from the event name 30161 // (unless you're listening on `"all"`, which will cause your callback to 30162 // receive the true name of the event as the first argument). 30163 trigger: function(name) { 30164 if (!this._events) return this; 30165 var args = slice.call(arguments, 1); 30166 if (!eventsApi(this, 'trigger', name, args)) return this; 30167 var events = this._events[name]; 30168 var allEvents = this._events.all; 30169 if (events) triggerEvents(events, args); 30170 if (allEvents) triggerEvents(allEvents, arguments); 30171 return this; 30172 }, 30173 30174 // Tell this object to stop listening to either specific events ... or 30175 // to every object it's currently listening to. 30176 stopListening: function(obj, name, callback) { 30177 var listeningTo = this._listeningTo; 30178 if (!listeningTo) return this; 30179 var remove = !name && !callback; 30180 if (!callback && typeof name === 'object') callback = this; 30181 if (obj) (listeningTo = {})[obj._listenId] = obj; 30182 for (var id in listeningTo) { 30183 obj = listeningTo[id]; 30184 obj.off(name, callback, this); 30185 if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; 30186 } 30187 return this; 30188 } 30189 30190 }; 30191 30192 // Regular expression used to split event strings. 30193 var eventSplitter = /\s+/; 30194 30195 // Implement fancy features of the Events API such as multiple event 30196 // names `"change blur"` and jQuery-style event maps `{change: action}` 30197 // in terms of the existing API. 30198 var eventsApi = function(obj, action, name, rest) { 30199 if (!name) return true; 30200 30201 // Handle event maps. 30202 if (typeof name === 'object') { 30203 for (var key in name) { 30204 obj[action].apply(obj, [key, name[key]].concat(rest)); 30205 } 30206 return false;
30207 } 30208 30209 // Handle space separated event names. 30210 if (eventSplitter.test(name)) { 30211 var names = name.split(eventSplitter); 30212 for (var i = 0, l = names.length; i < l; i++) { 30213 obj[action].apply(obj, [names[i]].concat(rest)); 30214 } 30215 return false; 30216 } 30217 30218 return true; 30219 }; 30220 30221 // A difficult-to-believe, but optimized internal dispatch function for 30222 // triggering events. Tries to keep the usual cases speedy (most internal 30223 // Backbone events have 3 arguments). 30224 var triggerEvents = function(events, args) { 30225 var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; 30226 switch (args.length) { 30227 case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; 30228 case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; 30229 case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; 30230 case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; 30231 default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; 30232 } 30233 }; 30234 30235 var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; 30236 30237 // Inversion-of-control versions of `on` and `once`. Tell *this* object to 30238 // listen to an event in another object ... keeping track of what it's 30239 // listening to. 30240 _.each(listenMethods, function(implementation, method) { 30241 Events[method] = function(obj, name, callback) { 30242 var listeningTo = this._listeningTo || (this._listeningTo = {}); 30243 var id = obj._listenId || (obj._listenId = _.uniqueId('l')); 30244 listeningTo[id] = obj; 30245 if (!callback && typeof name === 'object') callback = this; 30246 obj[implementation](name, callback, this); 30247 return this; 30248 }; 30249 }); 30250 30251 // Aliases for backwards compatibility. 30252 Events.bind = Events.on; 30253 Events.unbind = Events.off; 30254 30255 // Allow the `Backbone` object to serve as a global event bus, for folks who 30256 // want global "pubsub" in a convenient place. 30257 _.extend(Backbone, Events); 30258 30259 // Backbone.Model 30260 // -------------- 30261 30262 // Backbone **Models** are the basic data object in the framework -- 30263 // frequently representing a row in a table in a database on your server. 30264 // A discrete chunk of data and a bunch of useful, related methods for 30265 // performing computations and transformations on that data. 30266 30267 // Create a new model with the specified attributes. A client id (`cid`) 30268 // is automatically generated and assigned for you. 30269 var Model = Backbone.Model = function(attributes, options) { 30270 var attrs = attributes || {}; 30271 options || (options = {}); 30272 this.cid = _.uniqueId('c'); 30273 this.attributes = {}; 30274 if (options.collection) this.collection = options.collection; 30275 if (options.parse) attrs = this.parse(attrs, options) || {}; 30276 attrs = _.defaults({}, attrs, _.result(this, 'defaults')); 30277 this.set(attrs, options); 30278 this.changed = {}; 30279 this.initialize.apply(this, arguments); 30280 }; 30281 30282 // Attach all inheritable methods to the Model prototype. 30283 _.extend(Model.prototype, Events, { 30284 30285 // A hash of attributes whose current and previous value differ. 30286 changed: null, 30287 30288 // The value returned during the last failed validation. 30289 validationError: null, 30290 30291 // The default name for the JSON `id` attribute is `"id"`. MongoDB and 30292 // CouchDB users may want to set this to `"_id"`. 30293 idAttribute: 'id', 30294 30295 // Initialize is an empty function by default. Override it with your own 30296 // initialization logic. 30297 initialize: function(){}, 30298 30299 // Return a copy of the model's `attributes` object. 30300 toJSON: function(options) { 30301 return _.clone(this.attributes); 30302 }, 30303 30304 // Proxy `Backbone.sync` by default -- but override this if you need 30305 // custom syncing semantics for *this* particular model. 30306 sync: function() { 30307 return Backbone.sync.apply(this, arguments); 30308 }, 30309 30310 // Get the value of an attribute. 30311 get: function(attr) { 30312 return this.attributes[attr]; 30313 }, 30314 30315 // Get the HTML-escaped value of an attribute. 30316 escape: function(attr) { 30317 return _.escape(this.get(attr)); 30318 }, 30319 30320 // Returns `true` if the attribute contains a value that is not null 30321 // or undefined. 30322 has: function(attr) { 30323 return this.get(attr) != null; 30324 }, 30325 30326 // Set a hash of model attributes on the object, firing `"change"`. This is 30327 // the core primitive operation of a model, updating the data and notifying 30328 // anyone who needs to know about the change in state. The heart of the beast. 30329 set: function(key, val, options) { 30330 var attr, attrs, unset, changes, silent, changing, prev, current; 30331 if (key == null) return this; 30332 30333 // Handle both `"key", value` and `{key: value}` -style arguments. 30334 if (typeof key === 'object') { 30335 attrs = key; 30336 options = val; 30337 } else { 30338 (attrs = {})[key] = val; 30339 } 30340
30341 options || (options = {}); 30342 30343 // Run validation. 30344 if (!this._validate(attrs, options)) return false; 30345 30346 // Extract attributes and options. 30347 unset = options.unset; 30348 silent = options.silent; 30349 changes = []; 30350 changing = this._changing; 30351 this._changing = true; 30352 30353 if (!changing) { 30354 this._previousAttributes = _.clone(this.attributes); 30355 this.changed = {}; 30356 } 30357 current = this.attributes, prev = this._previousAttributes; 30358 30359 // Check for changes of `id`. 30360 if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; 30361 30362 // For each `set` attribute, update or delete the current value. 30363 for (attr in attrs) { 30364 val = attrs[attr]; 30365 if (!_.isEqual(current[attr], val)) changes.push(attr); 30366 if (!_.isEqual(prev[attr], val)) { 30367 this.changed[attr] = val; 30368 } else { 30369 delete this.changed[attr]; 30370 } 30371 unset ? delete current[attr] : current[attr] = val; 30372 } 30373 30374 // Trigger all relevant attribute changes. 30375 if (!silent) { 30376 if (changes.length) this._pending = options; 30377 for (var i = 0, l = changes.length; i < l; i++) { 30378 this.trigger('change:' + changes[i], this, current[changes[i]], options); 30379 } 30380 } 30381 30382 // You might be wondering why there's a `while` loop here. Changes can 30383 // be recursively nested within `"change"` events. 30384 if (changing) return this; 30385 if (!silent) { 30386 while (this._pending) { 30387 options = this._pending; 30388 this._pending = false; 30389 this.trigger('change', this, options); 30390 } 30391 } 30392 this._pending = false; 30393 this._changing = false; 30394 return this; 30395 }, 30396 30397 // Remove an attribute from the model, firing `"change"`. `unset` is a noop 30398 // if the attribute doesn't exist. 30399 unset: function(attr, options) { 30400 return this.set(attr, void 0, _.extend({}, options, {unset: true})); 30401 }, 30402 30403 // Clear all attributes on the model, firing `"change"`. 30404 clear: function(options) { 30405 var attrs = {}; 30406 for (var key in this.attributes) attrs[key] = void 0; 30407 return this.set(attrs, _.extend({}, options, {unset: true})); 30408 }, 30409 30410 // Determine if the model has changed since the last `"change"` event. 30411 // If you specify an attribute name, determine if that attribute has changed. 30412 hasChanged: function(attr) { 30413 if (attr == null) return !_.isEmpty(this.changed); 30414 return _.has(this.changed, attr); 30415 }, 30416
30417 // Return an object containing all the attributes that have changed, or 30418 // false if there are no changed attributes. Useful for determining what 30419 // parts of a view need to be updated and/or what attributes need to be 30420 // persisted to the server. Unset attributes will be set to undefined. 30421 // You can also pass an attributes object to diff against the model, 30422 // determining if there *would be* a change. 30423 changedAttributes: function(diff) { 30424 if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; 30425 var val, changed = false; 30426 var old = this._changing ? this._previousAttributes : this.attributes; 30427 for (var attr in diff) { 30428 if (_.isEqual(old[attr], (val = diff[attr]))) continue; 30429 (changed || (changed = {}))[attr] = val; 30430 } 30431 return changed; 30432 }, 30433 30434 // Get the previous value of an attribute, recorded at the time the last 30435 // `"change"` event was fired. 30436 previous: function(attr) { 30437 if (attr == null || !this._previousAttributes) return null; 30438 return this._previousAttributes[attr]; 30439 }, 30440 30441 // Get all of the attributes of the model at the time of the previous 30442 // `"change"` event. 30443 previousAttributes: function() { 30444 return _.clone(this._previousAttributes); 30445 }, 30446 30447 // Fetch the model from the server. If the server's representation of the 30448 // model differs from its current attributes, they will be overridden, 30449 // triggering a `"change"` event. 30450 fetch: function(options) { 30451 options = options ? _.clone(options) : {}; 30452 if (options.parse === void 0) options.parse = true; 30453 var model = this; 30454 var success = options.success; 30455 options.success = function(resp) { 30456 if (!model.set(model.parse(resp, options), options)) return false; 30457 if (success) success(model, resp, options); 30458 model.trigger('sync', model, resp, options); 30459 }; 30460 wrapError(this, options); 30461 return this.sync('read', this, options); 30462 }, 30463 30464 // Set a hash of model attributes, and sync the model to the server. 30465 // If the server returns an attributes hash that differs, the model's 30466 // state will be `set` again. 30467 save: function(key, val, options) { 30468 var attrs, method, xhr, attributes = this.attributes; 30469 30470 // Handle both `"key", value` and `{key: value}` -style arguments. 30471 if (key == null || typeof key === 'object') { 30472 attrs = key; 30473 options = val; 30474 } else { 30475 (attrs = {})[key] = val; 30476 } 30477 30478 options = _.extend({validate: true}, options); 30479 30480 // If we're not waiting and attributes exist, save acts as 30481 // `set(attr).save(null, opts)` with validation. Otherwise, check if 30482 // the model will be valid when the attributes, if any, are set. 30483 if (attrs && !options.wait) { 30484 if (!this.set(attrs, options)) return false; 30485 } else { 30486 if (!this._validate(attrs, options)) return false; 30487 } 30488 30489 // Set temporary attributes if `{wait: true}`. 30490 if (attrs && options.wait) { 30491 this.attributes = _.extend({}, attributes, attrs); 30492 } 30493 30494 // After a successful server-side save, the client is (optionally) 30495 // updated with the server-side state. 30496 if (options.parse === void 0) options.parse = true; 30497 var model = this; 30498 var success = options.success; 30499 options.success = function(resp) { 30500 // Ensure attributes are restored during synchronous saves. 30501 model.attributes = attributes; 30502 var serverAttrs = model.parse(resp, options); 30503 if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); 30504 if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { 30505 return false; 30506 } 30507 if (success) success(model, resp, options); 30508 model.trigger('sync', model, resp, options); 30509 }; 30510 wrapError(this, options); 30511 30512 method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); 30513 if (method === 'patch') options.attrs = attrs; 30514 xhr = this.sync(method, this, options); 30515 30516 // Restore attributes. 30517 if (attrs && options.wait) this.attributes = attributes; 30518 30519 return xhr; 30520 }, 30521 30522 // Destroy this model on the server if it was already persisted. 30523 // Optimistically removes the model from its collection, if it has one. 30524 // If `wait: true` is passed, waits for the server to respond before removal. 30525 destroy: function(options) { 30526 options = options ? _.clone(options) : {}; 30527 var model = this; 30528 var success = options.success; 30529 30530 var destroy = function() { 30531 model.trigger('destroy', model, model.collection, options); 30532 }; 30533 30534 options.success = function(resp) { 30535 if (options.wait || model.isNew()) destroy(); 30536 if (success) success(model, resp, options); 30537 if (!model.isNew()) model.trigger('sync', model, resp, options); 30538 }; 30539 30540 if (this.isNew()) { 30541 options.success(); 30542 return false;
30543 } 30544 wrapError(this, options); 30545 30546 var xhr = this.sync('delete', this, options); 30547 if (!options.wait) destroy(); 30548 return xhr; 30549 }, 30550 30551 // Default URL for the model's representation on the server -- if you're 30552 // using Backbone's restful methods, override this to change the endpoint 30553 // that will be called. 30554 url: function() { 30555 var base = 30556 _.result(this, 'urlRoot') || 30557 _.result(this.collection, 'url') || 30558 urlError(); 30559 if (this.isNew()) return base; 30560 return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id); 30561 }, 30562 30563 // **parse** converts a response into the hash of attributes to be `set` on 30564 // the model. The default implementation is just to pass the response along. 30565 parse: function(resp, options) { 30566 return resp; 30567 }, 30568 30569 // Create a new model with identical attributes to this one. 30570 clone: function() { 30571 return new this.constructor(this.attributes); 30572 }, 30573 30574 // A model is new if it has never been saved to the server, and lacks an id. 30575 isNew: function() { 30576 return !this.has(this.idAttribute); 30577 }, 30578 30579 // Check if the model is currently in a valid state. 30580 isValid: function(options) { 30581 return this._validate({}, _.extend(options || {}, { validate: true })); 30582 }, 30583 30584 // Run validation against the next complete set of model attributes, 30585 // returning `true` if all is well. Otherwise, fire an `"invalid"` event. 30586 _validate: function(attrs, options) { 30587 if (!options.validate || !this.validate) return true; 30588 attrs = _.extend({}, this.attributes, attrs); 30589 var error = this.validationError = this.validate(attrs, options) || null; 30590 if (!error) return true; 30591 this.trigger('invalid', this, error, _.extend(options, {validationError: error})); 30592 return false; 30593 } 30594 30595 }); 30596 30597 // Underscore methods that we want to implement on the Model. 30598 var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; 30599 30600 // Mix in each Underscore method as a proxy to `Model#attributes`. 30601 _.each(modelMethods, function(method) { 30602 Model.prototype[method] = function() { 30603 var args = slice.call(arguments); 30604 args.unshift(this.attributes); 30605 return _[method].apply(_, args); 30606 }; 30607 }); 30608 30609 // Backbone.Collection 30610 // ------------------- 30611 30612 // If models tend to represent a single row of data, a Backbone Collection is 30613 // more analagous to a table full of data ... or a small slice or page of that 30614 // table, or a collection of rows that belong together for a particular reason 30615 // -- all of the messages in this particular folder, all of the documents
30616 // belonging to this particular author, and so on. Collections maintain 30617 // indexes of their models, both in order, and for lookup by `id`. 30618 30619 // Create a new **Collection**, perhaps to contain a specific type of `model`. 30620 // If a `comparator` is specified, the Collection will maintain 30621 // its models in sort order, as they're added and removed. 30622 var Collection = Backbone.Collection = function(models, options) { 30623 options || (options = {}); 30624 if (options.model) this.model = options.model; 30625 if (options.comparator !== void 0) this.comparator = options.comparator; 30626 this._reset(); 30627 this.initialize.apply(this, arguments); 30628 if (models) this.reset(models, _.extend({silent: true}, options)); 30629 }; 30630 30631 // Default options for `Collection#set`. 30632 var setOptions = {add: true, remove: true, merge: true}; 30633 var addOptions = {add: true, remove: false}; 30634 30635 // Define the Collection's inheritable methods. 30636 _.extend(Collection.prototype, Events, { 30637 30638 // The default model for a collection is just a **Backbone.Model**. 30639 // This should be overridden in most cases. 30640 model: Model, 30641 30642 // Initialize is an empty function by default. Override it with your own 30643 // initialization logic. 30644 initialize: function(){}, 30645 30646 // The JSON representation of a Collection is an array of the 30647 // models' attributes. 30648 toJSON: function(options) { 30649 return this.map(function(model){ return model.toJSON(options); }); 30650 }, 30651 30652 // Proxy `Backbone.sync` by default. 30653 sync: function() { 30654 return Backbone.sync.apply(this, arguments); 30655 }, 30656 30657 // Add a model, or list of models to the set. 30658 add: function(models, options) { 30659 return this.set(models, _.extend({merge: false}, options, addOptions)); 30660 }, 30661 30662 // Remove a model, or a list of models from the set. 30663 remove: function(models, options) { 30664 var singular = !_.isArray(models); 30665 models = singular ? [models] : _.clone(models); 30666 options || (options = {}); 30667 var i, l, index, model; 30668 for (i = 0, l = models.length; i < l; i++) { 30669 model = models[i] = this.get(models[i]); 30670 if (!model) continue; 30671 delete this._byId[model.id]; 30672 delete this._byId[model.cid]; 30673 index = this.indexOf(model); 30674 this.models.splice(index, 1); 30675 this.length--; 30676 if (!options.silent) { 30677 options.index = index; 30678 model.trigger('remove', model, this, options); 30679 } 30680 this._removeReference(model, options); 30681 } 30682 return singular ? models[0] : models; 30683 }, 30684 30685 // Update a collection by `set`-ing a new list of models, adding new ones, 30686 // removing models that are no longer present, and merging models that 30687 // already exist in the collection, as necessary. Similar to **Model#set**, 30688 // the core operation for updating the data contained by the collection. 30689 set: function(models, options) { 30690 options = _.defaults({}, options, setOptions); 30691 if (options.parse) models = this.parse(models, options); 30692 var singular = !_.isArray(models); 30693 models = singular ? (models ? [models] : []) : _.clone(models); 30694 var i, l, id, model, attrs, existing, sort; 30695 var at = options.at; 30696 var targetModel = this.model; 30697 var sortable = this.comparator && (at == null) && options.sort !== false; 30698 var sortAttr = _.isString(this.comparator) ? this.comparator : null; 30699 var toAdd = [], toRemove = [], modelMap = {}; 30700 var add = options.add, merge = options.merge, remove = options.remove; 30701 var order = !sortable && add && remove ? [] : false; 30702 30703 // Turn bare objects into model references, and prevent invalid models 30704 // from being added. 30705 for (i = 0, l = models.length; i < l; i++) { 30706 attrs = models[i] || {}; 30707 if (attrs instanceof Model) { 30708 id = model = attrs; 30709 } else { 30710 id = attrs[targetModel.prototype.idAttribute || 'id']; 30711 } 30712 30713 // If a duplicate is found, prevent it from being added and 30714 // optionally merge it into the existing model. 30715 if (existing = this.get(id)) { 30716 if (remove) modelMap[existing.cid] = true; 30717 if (merge) { 30718 attrs = attrs === model ? model.attributes : attrs; 30719 if (options.parse) attrs = existing.parse(attrs, options); 30720 existing.set(attrs, options); 30721 if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; 30722 } 30723 models[i] = existing; 30724 30725 // If this is a new, valid model, push it to the `toAdd` list. 30726 } else if (add) { 30727 model = models[i] = this._prepareModel(attrs, options); 30728 if (!model) continue; 30729 toAdd.push(model); 30730 this._addReference(model, options); 30731 } 30732
30733 // Do not add multiple models with the same `id`. 30734 model = existing || model; 30735 if (order && (model.isNew() || !modelMap[model.id])) order.push(model); 30736 modelMap[model.id] = true; 30737 } 30738 30739 // Remove nonexistent models if appropriate. 30740 if (remove) { 30741 for (i = 0, l = this.length; i < l; ++i) { 30742 if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); 30743 } 30744 if (toRemove.length) this.remove(toRemove, options); 30745 } 30746 30747 // See if sorting is needed, update `length` and splice in new models. 30748 if (toAdd.length || (order && order.length)) { 30749 if (sortable) sort = true; 30750 this.length += toAdd.length; 30751 if (at != null) { 30752 for (i = 0, l = toAdd.length; i < l; i++) { 30753 this.models.splice(at + i, 0, toAdd[i]); 30754 } 30755 } else { 30756 if (order) this.models.length = 0; 30757 var orderedModels = order || toAdd; 30758 for (i = 0, l = orderedModels.length; i < l; i++) { 30759 this.models.push(orderedModels[i]); 30760 } 30761 } 30762 } 30763 30764 // Silently sort the collection if appropriate. 30765 if (sort) this.sort({silent: true}); 30766 30767 // Unless silenced, it's time to fire all appropriate add/sort events. 30768 if (!options.silent) { 30769 for (i = 0, l = toAdd.length; i < l; i++) { 30770 (model = toAdd[i]).trigger('add', model, this, options); 30771 } 30772 if (sort || (order && order.length)) this.trigger('sort', this, options); 30773 } 30774 30775 // Return the added (or merged) model (or models). 30776 return singular ? models[0] : models; 30777 }, 30778 30779 // When you have more items than you want to add or remove individually, 30780 // you can reset the entire set with a new list of models, without firing 30781 // any granular `add` or `remove` events. Fires `reset` when finished. 30782 // Useful for bulk operations and optimizations. 30783 reset: function(models, options) { 30784 options || (options = {}); 30785 for (var i = 0, l = this.models.length; i < l; i++) { 30786 this._removeReference(this.models[i], options); 30787 } 30788 options.previousModels = this.models; 30789 this._reset(); 30790 models = this.add(models, _.extend({silent: true}, options)); 30791 if (!options.silent) this.trigger('reset', this, options); 30792 return models; 30793 }, 30794 30795 // Add a model to the end of the collection. 30796 push: function(model, options) { 30797 return this.add(model, _.extend({at: this.length}, options)); 30798 }, 30799 30800 // Remove a model from the end of the collection. 30801 pop: function(options) { 30802 var model = this.at(this.length - 1); 30803 this.remove(model, options); 30804 return model; 30805 }, 30806 30807 // Add a model to the beginning of the collection. 30808 unshift: function(model, options) { 30809 return this.add(model, _.extend({at: 0}, options)); 30810 }, 30811 30812 // Remove a model from the beginning of the collection. 30813 shift: function(options) { 30814 var model = this.at(0); 30815 this.remove(model, options); 30816 return model; 30817 }, 30818 30819 // Slice out a sub-array of models from the collection. 30820 slice: function() { 30821 return slice.apply(this.models, arguments); 30822 }, 30823 30824 // Get a model from the set by id. 30825 get: function(obj) { 30826 if (obj == null) return void 0; 30827 return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid]; 30828 }, 30829 30830 // Get the model at the given index. 30831 at: function(index) { 30832 return this.models[index]; 30833 }, 30834 30835 // Return models with matching attributes. Useful for simple cases of 30836 // `filter`. 30837 where: function(attrs, first) { 30838 if (_.isEmpty(attrs)) return first ? void 0 : []; 30839 return this[first ? 'find' : 'filter'](function(model) { 30840 for (var key in attrs) { 30841 if (attrs[key] !== model.get(key)) return false; 30842 } 30843 return true; 30844 }); 30845 }, 30846 30847 // Return the first model with matching attributes. Useful for simple cases 30848 // of `find`. 30849 findWhere: function(attrs) { 30850 return this.where(attrs, true); 30851 }, 30852 30853 // Force the collection to re-sort itself. You don't need to call this under 30854 // normal circumstances, as the set will maintain sort order as each item 30855 // is added. 30856 sort: function(options) { 30857 if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
30858 options || (options = {}); 30859 30860 // Run sort based on type of `comparator`. 30861 if (_.isString(this.comparator) || this.comparator.length === 1) { 30862 this.models = this.sortBy(this.comparator, this); 30863 } else { 30864 this.models.sort(_.bind(this.comparator, this)); 30865 } 30866 30867 if (!options.silent) this.trigger('sort', this, options); 30868 return this; 30869 }, 30870 30871 // Pluck an attribute from each model in the collection. 30872 pluck: function(attr) { 30873 return _.invoke(this.models, 'get', attr); 30874 }, 30875 30876 // Fetch the default set of models for this collection, resetting the 30877 // collection when they arrive. If `reset: true` is passed, the response 30878 // data will be passed through the `reset` method instead of `set`. 30879 fetch: function(options) { 30880 options = options ? _.clone(options) : {}; 30881 if (options.parse === void 0) options.parse = true; 30882 var success = options.success; 30883 var collection = this; 30884 options.success = function(resp) { 30885 var method = options.reset ? 'reset' : 'set'; 30886 collection[method](resp, options); 30887 if (success) success(collection, resp, options); 30888 collection.trigger('sync', collection, resp, options); 30889 }; 30890 wrapError(this, options); 30891 return this.sync('read', this, options); 30892 }, 30893 30894 // Create a new instance of a model in this collection. Add the model to the 30895 // collection immediately, unless `wait: true` is passed, in which case we 30896 // wait for the server to agree. 30897 create: function(model, options) { 30898 options = options ? _.clone(options) : {}; 30899 if (!(model = this._prepareModel(model, options))) return false; 30900 if (!options.wait) this.add(model, options); 30901 var collection = this; 30902 var success = options.success; 30903 options.success = function(model, resp) { 30904 if (options.wait) collection.add(model, options); 30905 if (success) success(model, resp, options); 30906 }; 30907 model.save(null, options); 30908 return model; 30909 }, 30910 30911 // **parse** converts a response into a list of models to be added to the 30912 // collection. The default implementation is just to pass it through. 30913 parse: function(resp, options) { 30914 return resp; 30915 }, 30916 30917 // Create a new collection with an identical list of models as this one. 30918 clone: function() { 30919 return new this.constructor(this.models); 30920 }, 30921 30922 // Private method to reset all internal state. Called when the collection 30923 // is first initialized or reset. 30924 _reset: function() { 30925 this.length = 0; 30926 this.models = []; 30927 this._byId = {}; 30928 }, 30929 30930 // Prepare a hash of attributes (or other model) to be added to this 30931 // collection. 30932 _prepareModel: function(attrs, options) { 30933 if (attrs instanceof Model) return attrs; 30934 options = options ? _.clone(options) : {}; 30935 options.collection = this; 30936 var model = new this.model(attrs, options); 30937 if (!model.validationError) return model; 30938 this.trigger('invalid', this, model.validationError, options); 30939 return false; 30940 }, 30941 30942 // Internal method to create a model's ties to a collection. 30943 _addReference: function(model, options) { 30944 this._byId[model.cid] = model; 30945 if (model.id != null) this._byId[model.id] = model; 30946 if (!model.collection) model.collection = this; 30947 model.on('all', this._onModelEvent, this); 30948 }, 30949 30950 // Internal method to sever a model's ties to a collection. 30951 _removeReference: function(model, options) { 30952 if (this === model.collection) delete model.collection; 30953 model.off('all', this._onModelEvent, this); 30954 }, 30955 30956 // Internal method called every time a model in the set fires an event. 30957 // Sets need to update their indexes when models change ids. All other 30958 // events simply proxy through. "add" and "remove" events that originate 30959 // in other collections are ignored. 30960 _onModelEvent: function(event, model, collection, options) { 30961 if ((event === 'add' || event === 'remove') && collection !== this) return; 30962 if (event === 'destroy') this.remove(model, options); 30963 if (model && event === 'change:' + model.idAttribute) { 30964 delete this._byId[model.previous(model.idAttribute)]; 30965 if (model.id != null) this._byId[model.id] = model; 30966 } 30967 this.trigger.apply(this, arguments); 30968 } 30969 30970 }); 30971 30972 // Underscore methods that we want to implement on the Collection. 30973 // 90% of the core usefulness of Backbone Collections is actually implemented 30974 // right here: 30975 var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', 30976 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', 30977 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 30978 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', 30979 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', 30980 'lastIndexOf', 'isEmpty', 'chain', 'sample']; 30981
30982 // Mix in each Underscore method as a proxy to `Collection#models`. 30983 _.each(methods, function(method) { 30984 Collection.prototype[method] = function() { 30985 var args = slice.call(arguments); 30986 args.unshift(this.models); 30987 return _[method].apply(_, args); 30988 }; 30989 }); 30990 30991 // Underscore methods that take a property name as an argument. 30992 var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; 30993 30994 // Use attributes instead of properties. 30995 _.each(attributeMethods, function(method) { 30996 Collection.prototype[method] = function(value, context) { 30997 var iterator = _.isFunction(value) ? value : function(model) { 30998 return model.get(value); 30999 }; 31000 return _[method](this.models, iterator, context); 31001 }; 31002 }); 31003 31004 // Backbone.View 31005 // ------------- 31006 31007 // Backbone Views are almost more convention than they are actual code. A View 31008 // is simply a JavaScript object that represents a logical chunk of UI in the 31009 // DOM. This might be a single item, an entire list, a sidebar or panel, or 31010 // even the surrounding frame which wraps your whole app. Defining a chunk of 31011 // UI as a **View** allows you to define your DOM events declaratively, without 31012 // having to worry about render order ... and makes it easy for the view to 31013 // react to specific changes in the state of your models. 31014 31015 // Creating a Backbone.View creates its initial element outside of the DOM, 31016 // if an existing element is not provided... 31017 var View = Backbone.View = function(options) { 31018 this.cid = _.uniqueId('view'); 31019 options || (options = {}); 31020 _.extend(this, _.pick(options, viewOptions)); 31021 this._ensureElement(); 31022 this.initialize.apply(this, arguments); 31023 this.delegateEvents(); 31024 }; 31025 31026 // Cached regex to split keys for `delegate`. 31027 var delegateEventSplitter = /^(\S+)\s*(.*)$/; 31028 31029 // List of view options to be merged as properties. 31030 var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; 31031 31032 // Set up all inheritable **Backbone.View** properties and methods. 31033 _.extend(View.prototype, Events, { 31034 31035 // The default `tagName` of a View's element is `"div"`. 31036 tagName: 'div', 31037 31038 // jQuery delegate for element lookup, scoped to DOM elements within the 31039 // current view. This should be preferred to global lookups where possible. 31040 $: function(selector) { 31041 return this.$el.find(selector); 31042 }, 31043 31044 // Initialize is an empty function by default. Override it with your own 31045 // initialization logic. 31046 initialize: function(){}, 31047 31048 // **render** is the core function that your view should override, in order 31049 // to populate its element (`this.el`), with the appropriate HTML. The 31050 // convention is for **render** to always return `this`. 31051 render: function() { 31052 return this; 31053 }, 31054 31055 // Remove this view by taking the element out of the DOM, and removing any 31056 // applicable Backbone.Events listeners. 31057 remove: function() { 31058 this.$el.remove(); 31059 this.stopListening(); 31060 return this; 31061 }, 31062 31063 // Change the view's element (`this.el` property), including event 31064 // re-delegation. 31065 setElement: function(element, delegate) { 31066 if (this.$el) this.undelegateEvents(); 31067 this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); 31068 this.el = this.$el[0]; 31069 if (delegate !== false) this.delegateEvents(); 31070 return this; 31071 }, 31072 31073 // Set callbacks, where `this.events` is a hash of 31074 // 31075 // *{"event selector": "callback"}* 31076 // 31077 // { 31078 // 'mousedown .title': 'edit', 31079 // 'click .button': 'save', 31080 // 'click .open': function(e) { ... } 31081 // } 31082 // 31083 // pairs. Callbacks will be bound to the view, with `this` set properly. 31084 // Uses event delegation for efficiency. 31085 // Omitting the selector binds the event to `this.el`. 31086 // This only works for delegate-able events: not `focus`, `blur`, and 31087 // not `change`, `submit`, and `reset` in Internet Explorer. 31088 delegateEvents: function(events) { 31089 if (!(events || (events = _.result(this, 'events')))) return this; 31090 this.undelegateEvents(); 31091 for (var key in events) { 31092 var method = events[key]; 31093 if (!_.isFunction(method)) method = this[events[key]];
31094 if (!method) continue; 31095 31096 var match = key.match(delegateEventSplitter); 31097 var eventName = match[1], selector = match[2]; 31098 method = _.bind(method, this); 31099 eventName += '.delegateEvents' + this.cid; 31100 if (selector === '') { 31101 this.$el.on(eventName, method); 31102 } else { 31103 this.$el.on(eventName, selector, method); 31104 } 31105 } 31106 return this; 31107 }, 31108 31109 // Clears all callbacks previously bound to the view with `delegateEvents`. 31110 // You usually don't need to use this, but may wish to if you have multiple 31111 // Backbone views attached to the same DOM element. 31112 undelegateEvents: function() { 31113 this.$el.off('.delegateEvents' + this.cid); 31114 return this; 31115 }, 31116 31117 // Ensure that the View has a DOM element to render into. 31118 // If `this.el` is a string, pass it through `$()`, take the first 31119 // matching element, and re-assign it to `el`. Otherwise, create 31120 // an element from the `id`, `className` and `tagName` properties. 31121 _ensureElement: function() { 31122 if (!this.el) { 31123 var attrs = _.extend({}, _.result(this, 'attributes')); 31124 if (this.id) attrs.id = _.result(this, 'id'); 31125 if (this.className) attrs['class'] = _.result(this, 'className'); 31126 var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); 31127 this.setElement($el, false); 31128 } else { 31129 this.setElement(_.result(this, 'el'), false); 31130 } 31131 } 31132 31133 }); 31134 31135 // Backbone.sync 31136 // ------------- 31137 31138 // Override this function to change the manner in which Backbone persists 31139 // models to the server. You will be passed the type of request, and the 31140 // model in question. By default, makes a RESTful Ajax request 31141 // to the model's `url()`. Some possible customizations could be: 31142 // 31143 // * Use `setTimeout` to batch rapid-fire updates into a single request. 31144 // * Send up the models as XML instead of JSON. 31145 // * Persist models via WebSockets instead of Ajax. 31146 // 31147 // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests 31148 // as `POST`, with a `_method` parameter containing the true HTTP method, 31149 // as well as all requests with the body as `application/x-www-form-urlencoded` 31150 // instead of `application/json` with the model in a param named `model`. 31151 // Useful when interfacing with server-side languages like **PHP** that make 31152 // it difficult to read the body of `PUT` requests. 31153 Backbone.sync = function(method, model, options) { 31154 var type = methodMap[method]; 31155 31156 // Default options, unless specified. 31157 _.defaults(options || (options = {}), { 31158 emulateHTTP: Backbone.emulateHTTP, 31159 emulateJSON: Backbone.emulateJSON 31160 }); 31161 31162 // Default JSON-request options. 31163 var params = {type: type, dataType: 'json'}; 31164 31165 // Ensure that we have a URL. 31166 if (!options.url) { 31167 params.url = _.result(model, 'url') || urlError(); 31168 } 31169 31170 // Ensure that we have the appropriate request data. 31171 if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { 31172 params.contentType = 'application/json'; 31173 params.data = JSON.stringify(options.attrs || model.toJSON(options)); 31174 } 31175 31176 // For older servers, emulate JSON by encoding the request into an HTML-form. 31177 if (options.emulateJSON) { 31178 params.contentType = 'application/x-www-form-urlencoded'; 31179 params.data = params.data ? {model: params.data} : {}; 31180 } 31181 31182 // For older servers, emulate HTTP by mimicking the HTTP method with `_method` 31183 // And an `X-HTTP-Method-Override` header. 31184 if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { 31185 params.type = 'POST'; 31186 if (options.emulateJSON) params.data._method = type; 31187 var beforeSend = options.beforeSend; 31188 options.beforeSend = function(xhr) { 31189 xhr.setRequestHeader('X-HTTP-Method-Override', type); 31190 if (beforeSend) return beforeSend.apply(this, arguments); 31191 }; 31192 } 31193 31194 // Don't process data on a non-GET request. 31195 if (params.type !== 'GET' && !options.emulateJSON) { 31196 params.processData = false;
31197 } 31198 31199 // If we're sending a `PATCH` request, and we're in an old Internet Explorer 31200 // that still has ActiveX enabled by default, override jQuery to use that 31201 // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. 31202 if (params.type === 'PATCH' && noXhrPatch) { 31203 params.xhr = function() { 31204 return new ActiveXObject("Microsoft.XMLHTTP"); 31205 }; 31206 } 31207 31208 // Make the request, allowing the user to override any Ajax options. 31209 var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); 31210 model.trigger('request', model, xhr, options); 31211 return xhr; 31212 }; 31213 31214 var noXhrPatch = 31215 typeof window !== 'undefined' && !!window.ActiveXObject && 31216 !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent); 31217 31218 // Map from CRUD to HTTP for our default `Backbone.sync` implementation. 31219 var methodMap = { 31220 'create': 'POST', 31221 'update': 'PUT', 31222 'patch': 'PATCH', 31223 'delete': 'DELETE', 31224 'read': 'GET' 31225 }; 31226 31227 // Set the default implementation of `Backbone.ajax` to proxy through to `$`. 31228 // Override this if you'd like to use a different library. 31229 Backbone.ajax = function() { 31230 return Backbone.$.ajax.apply(Backbone.$, arguments); 31231 }; 31232 31233 // Backbone.Router 31234 // --------------- 31235 31236 // Routers map faux-URLs to actions, and fire events when routes are 31237 // matched. Creating a new one sets its `routes` hash, if not set statically. 31238 var Router = Backbone.Router = function(options) { 31239 options || (options = {}); 31240 if (options.routes) this.routes = options.routes; 31241 this._bindRoutes(); 31242 this.initialize.apply(this, arguments); 31243 }; 31244 31245 // Cached regular expressions for matching named param parts and splatted 31246 // parts of route strings. 31247 var optionalParam = /\((.*?)\)/g; 31248 var namedParam = /(\(\?)?:\w+/g; 31249 var splatParam = /\*\w+/g; 31250 var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; 31251 31252 // Set up all inheritable **Backbone.Router** properties and methods. 31253 _.extend(Router.prototype, Events, { 31254 31255 // Initialize is an empty function by default. Override it with your own 31256 // initialization logic. 31257 initialize: function(){}, 31258 31259 // Manually bind a single named route to a callback. For example: 31260 // 31261 // this.route('search/:query/p:num', 'search', function(query, num) { 31262 // ... 31263 // }); 31264 // 31265 route: function(route, name, callback) { 31266 if (!_.isRegExp(route)) route = this._routeToRegExp(route); 31267 if (_.isFunction(name)) { 31268 callback = name; 31269 name = ''; 31270 } 31271 if (!callback) callback = this[name]; 31272 var router = this; 31273 Backbone.history.route(route, function(fragment) { 31274 var args = router._extractParameters(route, fragment); 31275 router.execute(callback, args); 31276 router.trigger.apply(router, ['route:' + name].concat(args)); 31277 router.trigger('route', name, args); 31278 Backbone.history.trigger('route', router, name, args); 31279 }); 31280 return this; 31281 }, 31282 31283 // Execute a route handler with the provided parameters. This is an 31284 // excellent place to do pre-route setup or post-route cleanup. 31285 execute: function(callback, args) { 31286 if (callback) callback.apply(this, args); 31287 }, 31288 31289 // Simple proxy to `Backbone.history` to save a fragment into the history. 31290 navigate: function(fragment, options) { 31291 Backbone.history.navigate(fragment, options); 31292 return this; 31293 }, 31294 31295 // Bind all defined routes to `Backbone.history`. We have to reverse the 31296 // order of the routes here to support behavior where the most general 31297 // routes can be defined at the bottom of the route map. 31298 _bindRoutes: function() { 31299 if (!this.routes) return; 31300 this.routes = _.result(this, 'routes'); 31301 var route, routes = _.keys(this.routes); 31302 while ((route = routes.pop()) != null) { 31303 this.route(route, this.routes[route]); 31304 } 31305 }, 31306 31307 // Convert a route string into a regular expression, suitable for matching 31308 // against the current location hash. 31309 _routeToRegExp: function(route) { 31310 route = route.replace(escapeRegExp, '\\$&') 31311 .replace(optionalParam, '(?:$1)?') 31312 .replace(namedParam, function(match, optional) { 31313 return optional ? match : '([^/?]+)'; 31314 }) 31315 .replace(splatParam, '([^?]*?)'); 31316 return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); 31317 }, 31318 31319 // Given a route, and a URL fragment that it matches, return the array of 31320 // extracted decoded parameters. Empty or unmatched parameters will be 31321 // treated as `null` to normalize cross-browser behavior. 31322 _extractParameters: function(route, fragment) { 31323 var params = route.exec(fragment).slice(1); 31324 return _.map(params, function(param, i) { 31325 // Don't decode the search params. 31326 if (i === params.length - 1) return param || null; 31327 if (!param) return null 31328 try { 31329 return decodeURIComponent(param) 31330 } catch (e) { 31331 if (typeof window !== 'undefined' && window.Sentry && window.Sentry.captureException) { 31332 window.Sentry.captureException(new Error('URL parameter decoding failed'), { 31333 tags: { 31334 error_type: 'url_decode_failure', 31335 library: 'backbone', 31336 version: '1.1.2', 31337 }, 31338 extra: { 31339 original_param: param, 31340 param_index: i, 31341 route_fragment: fragment, 31342 error_message: e.message, 31343 stack_trace: e.stack, 31344 timestamp: new Date().toISOString(), 31345 page_url: typeof window !== 'undefined' ? window.location.href : 'unknown', 31346 }, 31347 level: 'warning', 31348 }) 31349 } 31350 return param 31351 } 31352 }); 31353 } 31354 }); 31355 31356 // Backbone.History 31357 // ---------------- 31358 31359 // Handles cross-browser history management, based on either 31360 // [pushState](http://diveintohtml5.info/history.html) and real URLs, or 31361 // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) 31362 // and URL fragments. If the browser supports neither (old IE, natch), 31363 // falls back to polling. 31364 var History = Backbone.History = function() { 31365 this.handlers = []; 31366 _.bindAll(this, 'checkUrl'); 31367 31368 // Ensure that `History` can be used outside of the browser. 31369 if (typeof window !== 'undefined') { 31370 this.location = window.location; 31371 this.history = window.history; 31372 } 31373 }; 31374 31375 // Cached regex for stripping a leading hash/slash and trailing space. 31376 var routeStripper = /^[#\/]|\s+$/g; 31377 31378 // Cached regex for stripping leading and trailing slashes. 31379 var rootStripper = /^\/+|\/+$/g; 31380 31381 // Cached regex for detecting MSIE. 31382 var isExplorer = /msie [\w.]+/; 31383 31384 // Cached regex for removing a trailing slash. 31385 var trailingSlash = /\/$/; 31386 31387 // Cached regex for stripping urls of hash. 31388 var pathStripper = /#.*$/; 31389 31390 // Has the history handling already been started? 31391 History.started = false;
31392 31393 // Set up all inheritable **Backbone.History** properties and methods. 31394 _.extend(History.prototype, Events, { 31395 31396 // The default interval to poll for hash changes, if necessary, is 31397 // twenty times a second. 31398 interval: 50, 31399 31400 // Are we at the app root? 31401 atRoot: function() { 31402 return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root; 31403 }, 31404 31405 // Gets the true hash value. Cannot use location.hash directly due to bug 31406 // in Firefox where location.hash will always be decoded. 31407 getHash: function(window) { 31408 var match = (window || this).location.href.match(/#(.*)$/); 31409 return match ? match[1] : ''; 31410 }, 31411 31412 // Get the cross-browser normalized URL fragment, either from the URL, 31413 // the hash, or the override. 31414 getFragment: function(fragment, forcePushState) { 31415 if (fragment == null) { 31416 if (this._hasPushState || !this._wantsHashChange || forcePushState) { 31417 fragment = decodeURI(this.location.pathname + this.location.search); 31418 var root = this.root.replace(trailingSlash, ''); 31419 if (!fragment.indexOf(root)) fragment = fragment.slice(root.length); 31420 } else { 31421 fragment = this.getHash(); 31422 } 31423 } 31424 return fragment.replace(routeStripper, ''); 31425 }, 31426 31427 // Start the hash change handling, returning `true` if the current URL matches 31428 // an existing route, and `false` otherwise. 31429 start: function(options) { 31430 if (History.started) throw new Error("Backbone.history has already been started"); 31431 History.started = true; 31432 31433 // Figure out the initial configuration. Do we need an iframe? 31434 // Is pushState desired ... is it available? 31435 this.options = _.extend({root: '/'}, this.options, options); 31436 this.root = this.options.root; 31437 this._wantsHashChange = this.options.hashChange !== false; 31438 this._wantsPushState = !!this.options.pushState; 31439 this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); 31440 var fragment = this.getFragment(); 31441 var docMode = document.documentMode; 31442 var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); 31443 31444 // Normalize root to always include a leading and trailing slash. 31445 this.root = ('/' + this.root + '/').replace(rootStripper, '/'); 31446 31447 if (oldIE && this._wantsHashChange) { 31448 var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">'); 31449 this.iframe = frame.hide().appendTo('body')[0].contentWindow; 31450 this.navigate(fragment); 31451 } 31452 31453 // Depending on whether we're using pushState or hashes, and whether 31454 // 'onhashchange' is supported, determine how we check the URL state. 31455 if (this._hasPushState) { 31456 Backbone.$(window).on('popstate', this.checkUrl); 31457 } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) { 31458 Backbone.$(window).on('hashchange', this.checkUrl); 31459 } else if (this._wantsHashChange) { 31460 this._checkUrlInterval = setInterval(this.checkUrl, this.interval); 31461 } 31462 31463 // Determine if we need to change the base url, for a pushState link 31464 // opened by a non-pushState browser. 31465 this.fragment = fragment; 31466 var loc = this.location; 31467 31468 // Transition from hashChange to pushState or vice versa if both are 31469 // requested. 31470 if (this._wantsHashChange && this._wantsPushState) { 31471 31472 // If we've started off with a route from a `pushState`-enabled 31473 // browser, but we're currently in a browser that doesn't support it... 31474 if (!this._hasPushState && !this.atRoot()) { 31475 this.fragment = this.getFragment(null, true); 31476 this.location.replace(this.root + '#' + this.fragment); 31477 // Return immediately as browser will do redirect to new url 31478 return true; 31479 31480 // Or if we've started out with a hash-based route, but we're currently 31481 // in a browser where it could be `pushState`-based instead... 31482 } else if (this._hasPushState && this.atRoot() && loc.hash) { 31483 this.fragment = this.getHash().replace(routeStripper, ''); 31484 this.history.replaceState({}, document.title, this.root + this.fragment); 31485 } 31486 31487 } 31488 31489 if (!this.options.silent) return this.loadUrl(); 31490 }, 31491 31492 // Disable Backbone.history, perhaps temporarily. Not useful in a real app, 31493 // but possibly useful for unit testing Routers. 31494 stop: function() { 31495 Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl); 31496 if (this._checkUrlInterval) clearInterval(this._checkUrlInterval); 31497 History.started = false;
31498 }, 31499 31500 // Add a route to be tested when the fragment changes. Routes added later 31501 // may override previous routes. 31502 route: function(route, callback) { 31503 this.handlers.unshift({route: route, callback: callback}); 31504 }, 31505 31506 // Checks the current URL to see if it has changed, and if it has, 31507 // calls `loadUrl`, normalizing across the hidden iframe. 31508 checkUrl: function(e) { 31509 var current = this.getFragment(); 31510 if (current === this.fragment && this.iframe) { 31511 current = this.getFragment(this.getHash(this.iframe)); 31512 } 31513 if (current === this.fragment) return false; 31514 if (this.iframe) this.navigate(current); 31515 this.loadUrl(); 31516 }, 31517 31518 // Attempt to load the current URL fragment. If a route succeeds with a 31519 // match, returns `true`. If no defined routes matches the fragment, 31520 // returns `false`. 31521 loadUrl: function(fragment) { 31522 fragment = this.fragment = this.getFragment(fragment); 31523 return _.any(this.handlers, function(handler) { 31524 if (handler.route.test(fragment)) { 31525 handler.callback(fragment); 31526 return true; 31527 } 31528 }); 31529 }, 31530 31531 // Save a fragment into the hash history, or replace the URL state if the 31532 // 'replace' option is passed. You are responsible for properly URL-encoding 31533 // the fragment in advance. 31534 // 31535 // The options object can contain `trigger: true` if you wish to have the 31536 // route callback be fired (not usually desirable), or `replace: true`, if 31537 // you wish to modify the current URL without adding an entry to the history. 31538 navigate: function(fragment, options) { 31539 if (!History.started) return false; 31540 if (!options || options === true) options = {trigger: !!options}; 31541 31542 var url = this.root + (fragment = this.getFragment(fragment || '')); 31543 31544 // Strip the hash for matching. 31545 fragment = fragment.replace(pathStripper, ''); 31546 31547 if (this.fragment === fragment) return; 31548 this.fragment = fragment; 31549 31550 // Don't include a trailing slash on the root. 31551 if (fragment === '' && url !== '/') url = url.slice(0, -1); 31552 31553 // If pushState is available, we use it to set the fragment as a real URL. 31554 if (this._hasPushState) { 31555 this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url); 31556 31557 // If hash changes haven't been explicitly disabled, update the hash 31558 // fragment to store history. 31559 } else if (this._wantsHashChange) { 31560 this._updateHash(this.location, fragment, options.replace); 31561 if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) { 31562 // Opening and closing the iframe tricks IE7 and earlier to push a 31563 // history entry on hash-tag change. When replace is true, we don't 31564 // want this. 31565 if(!options.replace) this.iframe.document.open().close(); 31566 this._updateHash(this.iframe.location, fragment, options.replace); 31567 } 31568 31569 // If you've told us that you explicitly don't want fallback hashchange- 31570 // based history, then `navigate` becomes a page refresh. 31571 } else { 31572 return this.location.assign(url); 31573 } 31574 if (options.trigger) return this.loadUrl(fragment); 31575 }, 31576 31577 // Update the hash location, either replacing the current entry, or adding 31578 // a new one to the browser history. 31579 _updateHash: function(location, fragment, replace) { 31580 if (replace) { 31581 var href = location.href.replace(/(javascript:|#).*$/, ''); 31582 location.replace(href + '#' + fragment); 31583 } else { 31584 // Some browsers require that `hash` contains a leading #. 31585 location.hash = '#' + fragment; 31586 } 31587 } 31588 31589 }); 31590 31591 // Create the default Backbone.history. 31592 Backbone.history = new History; 31593 31594 // Helpers 31595 // ------- 31596 31597 // Helper function to correctly set up the prototype chain, for subclasses. 31598 // Similar to `goog.inherits`, but uses a hash of prototype properties and 31599 // class properties to be extended. 31600 var extend = function(protoProps, staticProps) { 31601 var parent = this; 31602 var child; 31603 31604 // The constructor function for the new subclass is either defined by you 31605 // (the "constructor" property in your `extend` definition), or defaulted 31606 // by us to simply call the parent's constructor. 31607 if (protoProps && _.has(protoProps, 'constructor')) { 31608 child = protoProps.constructor; 31609 } else { 31610 child = function(){ return parent.apply(this, arguments); }; 31611 } 31612 31613 // Add static properties to the constructor function, if supplied.
31614 _.extend(child, parent, staticProps); 31615 31616 // Set the prototype chain to inherit from `parent`, without calling 31617 // `parent`'s constructor function. 31618 var Surrogate = function(){ this.constructor = child; }; 31619 Surrogate.prototype = parent.prototype; 31620 child.prototype = new Surrogate; 31621 31622 // Add prototype properties (instance properties) to the subclass, 31623 // if supplied. 31624 if (protoProps) _.extend(child.prototype, protoProps); 31625 31626 // Set a convenience property in case the parent's prototype is needed 31627 // later. 31628 child.__super__ = parent.prototype; 31629 31630 return child; 31631 }; 31632 31633 // Set up inheritance for the model, collection, router, view and history. 31634 Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend; 31635 31636 // Throw an error when a URL is needed, and none is supplied. 31637 var urlError = function() { 31638 throw new Error('A "url" property or function must be specified'); 31639 }; 31640 31641 // Wrap an optional error callback with a fallback error event. 31642 var wrapError = function(model, options) { 31643 var error = options.error; 31644 options.error = function(resp) { 31645 if (error) error(model, resp, options); 31646 model.trigger('error', model, resp, options); 31647 }; 31648 }; 31649 31650 return Backbone; 31651 31652})); 31653// Backbone.Syphon, v0.4.1 31654// Copyright (c)2012 Derick Bailey, Muted Solutions, LLC. 31655// Distributed under MIT license 31656// http://github.com/derickbailey/backbone.syphon 31657Backbone.Syphon = (function(Backbone, $, _){ 31658 var Syphon = {}; 31659 31660 // Ignore Element Types 31661 // -------------------- 31662 31663 // Tell Syphon to ignore all elements of these types. You can 31664 // push new types to ignore directly in to this array. 31665 Syphon.ignoredTypes = ["button", "submit", "reset", "fieldset"]; 31666 31667 // Syphon 31668 // ------ 31669 31670 // Get a JSON object that represents 31671 // all of the form inputs, in this view. 31672 // Alternately, pass a form element directly 31673 // in place of the view. 31674 Syphon.serialize = function(view, options){ 31675 var data = {}; 31676 31677 // Build the configuration 31678 var config = buildConfig(options); 31679 31680 // Get all of the elements to process 31681 var elements = getInputElements(view, config); 31682 31683 // Process all of the elements 31684 _.each(elements, function(el){ 31685 var $el = $(el); 31686 var type = getElementType($el); 31687 31688 // Get the key for the input 31689 var keyExtractor = config.keyExtractors.get(type); 31690 var key = keyExtractor($el); 31691 31692 // Get the value for the input 31693 var inputReader = config.inputReaders.get(type); 31694 var value = inputReader($el); 31695 31696 // Get the key assignment validator and make sure 31697 // it's valid before assigning the value to the key 31698 var validKeyAssignment = config.keyAssignmentValidators.get(type); 31699 if (validKeyAssignment($el, key, value)){ 31700 var keychain = config.keySplitter(key); 31701 data = assignKeyValue(data, keychain, value); 31702 } 31703 }); 31704 31705 // Done; send back the results. 31706 return data; 31707 }; 31708 31709 // Use the given JSON object to populate 31710 // all of the form inputs, in this view. 31711 // Alternately, pass a form element directly 31712 // in place of the view. 31713 Syphon.deserialize = function(view, data, options){ 31714 // Build the configuration 31715 var config = buildConfig(options); 31716 31717 // Get all of the elements to process 31718 var elements = getInputElements(view, config); 31719 31720 // Flatten the data structure that we are deserializing 31721 var flattenedData = flattenData(config, data); 31722 31723 // Process all of the elements 31724 _.each(elements, function(el){ 31725 var $el = $(el); 31726 var type = getElementType($el); 31727 31728 // Get the key for the input 31729 var keyExtractor = config.keyExtractors.get(type); 31730 var key = keyExtractor($el); 31731 31732 // Get the input writer and the value to write 31733 var inputWriter = config.inputWriters.get(type); 31734 var value = flattenedData[key]; 31735 31736 // Write the value to the input 31737 inputWriter($el, value); 31738 }); 31739 }; 31740 31741 // Helpers 31742 // ------- 31743 31744 // Retrieve all of the form inputs 31745 // from the form 31746 var getInputElements = function(view, config){ 31747 var form = getForm(view); 31748 var elements = form.elements; 31749 31750 elements = _.reject(elements, function(el){ 31751 var reject; 31752 var type = getElementType(el); 31753 var extractor = config.keyExtractors.get(type); 31754 var identifier = extractor($(el)); 31755 31756 var foundInIgnored = _.include(config.ignoredTypes, type); 31757 var foundInInclude = _.include(config.include, identifier); 31758 var foundInExclude = _.include(config.exclude, identifier); 31759 31760 if (foundInInclude){ 31761 reject = false;
31762 } else { 31763 if (config.include){ 31764 reject = true; 31765 } else { 31766 reject = (foundInExclude || foundInIgnored); 31767 } 31768 } 31769 31770 return reject; 31771 }); 31772 31773 return elements; 31774 }; 31775 31776 // Determine what type of element this is. It 31777 // will either return the `type` attribute of 31778 // an `<input>` element, or the `tagName` of 31779 // the element when the element is not an `<input>`. 31780 var getElementType = function(el){ 31781 var typeAttr; 31782 var $el = $(el); 31783 var tagName = $el[0].tagName; 31784 var type = tagName; 31785 31786 if (tagName.toLowerCase() === "input"){ 31787 typeAttr = $el.attr("type"); 31788 if (typeAttr){ 31789 type = typeAttr; 31790 } else { 31791 type = "text"; 31792 } 31793 } 31794 31795 // Always return the type as lowercase 31796 // so it can be matched to lowercase 31797 // type registrations. 31798 return type.toLowerCase(); 31799 }; 31800 31801 // If a form element is given, just return it. 31802 // Otherwise, get the form element from the view. 31803 var getForm = function(viewOrForm){ 31804 if (_.isUndefined(viewOrForm.$el) && viewOrForm.tagName.toLowerCase() === 'form'){ 31805 return viewOrForm; 31806 } else { 31807 return viewOrForm.$el.is("form") ? viewOrForm.el : viewOrForm.$("form")[0]; 31808 } 31809 }; 31810 31811 // Build a configuration object and initialize 31812 // default values. 31813 var buildConfig = function(options){ 31814 var config = _.clone(options) || {}; 31815 31816 config.ignoredTypes = _.clone(Syphon.ignoredTypes); 31817 config.inputReaders = config.inputReaders || Syphon.InputReaders; 31818 config.inputWriters = config.inputWriters || Syphon.InputWriters; 31819 config.keyExtractors = config.keyExtractors || Syphon.KeyExtractors; 31820 config.keySplitter = config.keySplitter || Syphon.KeySplitter; 31821 config.keyJoiner = config.keyJoiner || Syphon.KeyJoiner; 31822 config.keyAssignmentValidators = config.keyAssignmentValidators || Syphon.KeyAssignmentValidators; 31823 31824 return config; 31825 }; 31826 31827 // Assigns `value` to a parsed JSON key. 31828 // 31829 // The first parameter is the object which will be 31830 // modified to store the key/value pair. 31831 // 31832 // The second parameter accepts an array of keys as a 31833 // string with an option array containing a 31834 // single string as the last option. 31835 // 31836 // The third parameter is the value to be assigned. 31837 // 31838 // Examples: 31839 // 31840 // `["foo", "bar", "baz"] => {foo: {bar: {baz: "value"}}}` 31841 // 31842 // `["foo", "bar", ["baz"]] => {foo: {bar: {baz: ["value"]}}}` 31843 // 31844 // When the final value is an array with a string, the key 31845 // becomes an array, and values are pushed in to the array, 31846 // allowing multiple fields with the same name to be 31847 // assigned to the array. 31848 var assignKeyValue = function(obj, keychain, value) { 31849 if (!keychain){ return obj; } 31850 31851 var key = keychain.shift(); 31852 31853 // build the current object we need to store data 31854 if (!obj[key]){ 31855 obj[key] = _.isArray(key) ? [] : {}; 31856 } 31857 31858 // if it's the last key in the chain, assign the value directly 31859 if (keychain.length === 0){ 31860 if (_.isArray(obj[key])){ 31861 obj[key].push(value); 31862 } else { 31863 obj[key] = value; 31864 } 31865 } 31866 31867 // recursive parsing of the array, depth-first 31868 if (keychain.length > 0){ 31869 assignKeyValue(obj[key], keychain, value); 31870 } 31871 31872 return obj; 31873 }; 31874 31875 // Flatten the data structure in to nested strings, using the 31876 // provided `KeyJoiner` function. 31877 // 31878 // Example: 31879 // 31880 // This input: 31881 // 31882 // ```js 31883 // { 31884 // widget: "wombat", 31885 // foo: { 31886 // bar: "baz", 31887 // baz: { 31888 // quux: "qux" 31889 // }, 31890 // quux: ["foo", "bar"] 31891 // } 31892 // } 31893 // ``` 31894 // 31895 // With a KeyJoiner that uses [ ] square brackets, 31896 // should produce this output: 31897 // 31898 // ```js 31899 // { 31900 // "widget": "wombat", 31901 // "foo[bar]": "baz", 31902 // "foo[baz][quux]": "qux", 31903 // "foo[quux]": ["foo", "bar"] 31904 // } 31905 // ``` 31906 var flattenData = function(config, data, parentKey){ 31907 var flatData = {}; 31908 31909 _.each(data, function(value, keyName){ 31910 var hash = {}; 31911 31912 // If there is a parent key, join it with 31913 // the current, child key. 31914 if (parentKey){
31915 keyName = config.keyJoiner(parentKey, keyName); 31916 } 31917 31918 if (_.isArray(value)){ 31919 keyName += "[]"; 31920 hash[keyName] = value; 31921 } else if (_.isObject(value)){ 31922 hash = flattenData(config, value, keyName); 31923 } else { 31924 hash[keyName] = value; 31925 } 31926 31927 // Store the resulting key/value pairs in the 31928 // final flattened data object 31929 _.extend(flatData, hash); 31930 }); 31931 31932 return flatData; 31933 }; 31934 31935 return Syphon; 31936})(Backbone, jQuery, _); 31937 31938// Type Registry 31939// ------------- 31940 31941// Type Registries allow you to register something to 31942// an input type, and retrieve either the item registered 31943// for a specific type or the default registration 31944Backbone.Syphon.TypeRegistry = function(){ 31945 this.registeredTypes = {}; 31946}; 31947 31948// Borrow Backbone's `extend` keyword for our TypeRegistry 31949Backbone.Syphon.TypeRegistry.extend = Backbone.Model.extend; 31950 31951_.extend(Backbone.Syphon.TypeRegistry.prototype, { 31952 31953 // Get the registered item by type. If nothing is 31954 // found for the specified type, the default is 31955 // returned. 31956 get: function(type){ 31957 var item = this.registeredTypes[type]; 31958 31959 if (!item){ 31960 item = this.registeredTypes["default"]; 31961 } 31962 31963 return item; 31964 }, 31965 31966 // Register a new item for a specified type 31967 register: function(type, item){ 31968 this.registeredTypes[type] = item; 31969 }, 31970 31971 // Register a default item to be used when no 31972 // item for a specified type is found 31973 registerDefault: function(item){ 31974 this.registeredTypes["default"] = item; 31975 }, 31976 31977 // Remove an item from a given type registration 31978 unregister: function(type){ 31979 if (this.registeredTypes[type]){ 31980 delete this.registeredTypes[type]; 31981 } 31982 } 31983}); 31984 31985 31986 31987 31988// Key Extractors 31989// -------------- 31990 31991// Key extractors produce the "key" in `{key: "value"}` 31992// pairs, when serializing. 31993Backbone.Syphon.KeyExtractorSet = Backbone.Syphon.TypeRegistry.extend(); 31994 31995// Built-in Key Extractors 31996Backbone.Syphon.KeyExtractors = new Backbone.Syphon.KeyExtractorSet(); 31997 31998// The default key extractor, which uses the 31999// input element's "id" attribute 32000Backbone.Syphon.KeyExtractors.registerDefault(function($el){ 32001 return $el.prop("name"); 32002}); 32003 32004 32005// Input Readers 32006// ------------- 32007 32008// Input Readers are used to extract the value from 32009// an input element, for the serialized object result 32010Backbone.Syphon.InputReaderSet = Backbone.Syphon.TypeRegistry.extend(); 32011 32012// Built-in Input Readers 32013Backbone.Syphon.InputReaders = new Backbone.Syphon.InputReaderSet(); 32014 32015// The default input reader, which uses an input 32016// element's "value" 32017Backbone.Syphon.InputReaders.registerDefault(function($el){ 32018 return $el.val(); 32019}); 32020 32021// Checkbox reader, returning a boolean value for 32022// whether or not the checkbox is checked. 32023Backbone.Syphon.InputReaders.register("checkbox", function($el){ 32024 var checked = $el.prop("checked"); 32025 return checked; 32026}); 32027 32028 32029// Input Writers 32030// ------------- 32031 32032// Input Writers are used to insert a value from an 32033// object into an input element. 32034Backbone.Syphon.InputWriterSet = Backbone.Syphon.TypeRegistry.extend(); 32035 32036// Built-in Input Writers 32037Backbone.Syphon.InputWriters = new Backbone.Syphon.InputWriterSet(); 32038 32039// The default input writer, which sets an input 32040// element's "value" 32041Backbone.Syphon.InputWriters.registerDefault(function($el, value){ 32042 $el.val(value); 32043}); 32044 32045// Checkbox writer, set whether or not the checkbox is checked 32046// depending on the boolean value. 32047Backbone.Syphon.InputWriters.register("checkbox", function($el, value){ 32048 $el.prop("checked", value); 32049}); 32050 32051// Radio button writer, set whether or not the radio button is 32052// checked. The button should only be checked if it's value 32053// equals the given value. 32054Backbone.Syphon.InputWriters.register("radio", function($el, value){ 32055 $el.prop("checked", $el.val() === value); 32056}); 32057 32058// Key Assignment Validators 32059// ------------------------- 32060 32061// Key Assignment Validators are used to determine whether or not a 32062// key should be assigned to a value, after the key and value have been 32063// extracted from the element. This is the last opportunity to prevent 32064// bad data from getting serialized to your object. 32065 32066Backbone.Syphon.KeyAssignmentValidatorSet = Backbone.Syphon.TypeRegistry.extend(); 32067 32068// Build-in Key Assignment Validators 32069Backbone.Syphon.KeyAssignmentValidators = new Backbone.Syphon.KeyAssignmentValidatorSet(); 32070 32071// Everything is valid by default 32072Backbone.Syphon.KeyAssignmentValidators.registerDefault(function(){ return true; }); 32073 32074// But only the "checked" radio button for a given 32075// radio button group is valid 32076Backbone.Syphon.KeyAssignmentValidators.register("radio", function($el, key, value){ 32077 return $el.prop("checked"); 32078}); 32079 32080 32081// Backbone.Syphon.KeySplitter 32082// --------------------------- 32083 32084// This function is used to split DOM element keys in to an array 32085// of parts, which are then used to create a nested result structure. 32086// returning `["foo", "bar"]` results in `{foo: { bar: "value" }}`. 32087// 32088// Override this method to use a custom key splitter, such as: 32089// `<input name="foo.bar.baz">`, `return key.split(".")` 32090Backbone.Syphon.KeySplitter = function(key){ 32091 var matches = key.match(/[^\[\]]+/g); 32092 32093 if (key.indexOf("[]") === key.length - 2){ 32094 lastKey = matches.pop(); 32095 matches.push([lastKey]); 32096 } 32097 32098 return matches; 32099} 32100 32101 32102// Backbone.Syphon.KeyJoiner 32103// ------------------------- 32104 32105// Take two segments of a key and join them together, to create the 32106// de-normalized key name, when deserializing a data structure back 32107// in to a form. 32108// 32109// Example: 32110// 32111// With this data strucutre `{foo: { bar: {baz: "value", quux: "another"} } }`, 32112// the key joiner will be called with these parameters, and assuming the 32113// join happens with "[ ]" square brackets, the specified output: 32114// 32115// `KeyJoiner("foo", "bar")` //=> "foo[bar]" 32116// `KeyJoiner("foo[bar]", "baz")` //=> "foo[bar][baz]" 32117// `KeyJoiner("foo[bar]", "quux")` //=> "foo[bar][quux]" 32118
vendor: 5,964 bytes, lines 32119-32335
32119Backbone.Syphon.KeyJoiner = function(parentKey, childKey){ 32120 return parentKey + "[" + childKey + "]"; 32121} 32122; 32123/**! 32124 32125 @license 32126 handlebars v4.7.7 32127 32128Copyright (C) 2011-2019 by Yehuda Katz 32129 32130Permission is hereby granted, free of charge, to any person obtaining a copy 32131of this software and associated documentation files (the "Software"), to deal 32132in the Software without restriction, including without limitation the rights 32133to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32134copies of the Software, and to permit persons to whom the Software is 32135furnished to do so, subject to the following conditions: 32136 32137The above copyright notice and this permission notice shall be included in 32138all copies or substantial portions of the Software. 32139 32140THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32141IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32142FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32143AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32144LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32145OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32146THE SOFTWARE. 32147 32148*/ 32149 32150(function webpackUniversalModuleDefinition(root, factory) { 32151 if(typeof exports === 'object' && typeof module === 'object') 32152 module.exports = factory(); 32153 else if(typeof define === 'function' && define.amd) 32154 define([], factory); 32155 else if(typeof exports === 'object') 32156 exports["Handlebars"] = factory(); 32157 else 32158 root["Handlebars"] = factory(); 32159})(this, function() { 32160return /******/ (function(modules) { // webpackBootstrap 32161/******/ // The module cache 32162/******/ var installedModules = {}; 32163 32164/******/ // The require function 32165/******/ function __webpack_require__(moduleId) { 32166 32167/******/ // Check if module is in cache 32168/******/ if(installedModules[moduleId]) 32169/******/ return installedModules[moduleId].exports; 32170 32171/******/ // Create a new module (and put it into the cache) 32172/******/ var module = installedModules[moduleId] = { 32173/******/ exports: {}, 32174/******/ id: moduleId, 32175/******/ loaded: false 32176/******/ }; 32177 32178/******/ // Execute the module function 32179/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 32180 32181/******/ // Flag the module as loaded 32182/******/ module.loaded = true; 32183 32184/******/ // Return the exports of the module 32185/******/ return module.exports; 32186/******/ } 32187 32188 32189/******/ // expose the modules object (__webpack_modules__) 32190/******/ __webpack_require__.m = modules; 32191 32192/******/ // expose the module cache 32193/******/ __webpack_require__.c = installedModules; 32194 32195/******/ // __webpack_public_path__ 32196/******/ __webpack_require__.p = ""; 32197 32198/******/ // Load entry module and return exports 32199/******/ return __webpack_require__(0); 32200/******/ }) 32201/************************************************************************/ 32202/******/ ([ 32203/* 0 */ 32204/***/ (function(module, exports, __webpack_require__) { 32205 32206 'use strict'; 32207 32208 var _interopRequireWildcard = __webpack_require__(1)['default']; 32209 32210 var _interopRequireDefault = __webpack_require__(2)['default']; 32211 32212 exports.__esModule = true; 32213 32214 var _handlebarsBase = __webpack_require__(3); 32215 32216 var base = _interopRequireWildcard(_handlebarsBase); 32217 32218 // Each of these augment the Handlebars object. No need to setup here. 32219 // (This is done to easily share code between commonjs and browse envs) 32220 32221 var _handlebarsSafeString = __webpack_require__(36); 32222 32223 var _handlebarsSafeString2 = _interopRequireDefault(_handlebarsSafeString); 32224 32225 var _handlebarsException = __webpack_require__(5); 32226 32227 var _handlebarsException2 = _interopRequireDefault(_handlebarsException); 32228 32229 var _handlebarsUtils = __webpack_require__(4); 32230 32231 var Utils = _interopRequireWildcard(_handlebarsUtils); 32232 32233 var _handlebarsRuntime = __webpack_require__(37); 32234 32235 var runtime = _interopRequireWildcard(_handlebarsRuntime); 32236 32237 var _handlebarsNoConflict = __webpack_require__(43); 32238 32239 var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); 32240 32241 // For compatibility and usage outside of module systems, make the Handlebars object a namespace 32242 function create() { 32243 var hb = new base.HandlebarsEnvironment(); 32244 32245 Utils.extend(hb, base); 32246 hb.SafeString = _handlebarsSafeString2['default']; 32247 hb.Exception = _handlebarsException2['default']; 32248 hb.Utils = Utils; 32249 hb.escapeExpression = Utils.escapeExpression; 32250 32251 hb.VM = runtime; 32252 hb.template = function (spec) { 32253 return runtime.template(spec, hb); 32254 }; 32255 32256 return hb; 32257 } 32258 32259 var inst = create(); 32260 inst.create = create; 32261 32262 _handlebarsNoConflict2['default'](inst); 32263 32264 inst['default'] = inst; 32265 32266 exports['default'] = inst; 32267 module.exports = exports['default']; 32268 32269/***/ }), 32270/* 1 */ 32271/***/ (function(module, exports) { 32272 32273 "use strict"; 32274 32275 exports["default"] = function (obj) { 32276 if (obj && obj.__esModule) { 32277 return obj; 32278 } else { 32279 var newObj = {}; 32280 32281 if (obj != null) { 32282 for (var key in obj) { 32283 if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; 32284 } 32285 } 32286 32287 newObj["default"] = obj; 32288 return newObj; 32289 } 32290 }; 32291 32292 exports.__esModule = true; 32293 32294/***/ }), 32295/* 2 */ 32296/***/ (function(module, exports) { 32297 32298 "use strict"; 32299 32300 exports["default"] = function (obj) { 32301 return obj && obj.__esModule ? obj : { 32302 "default": obj 32303 }; 32304 }; 32305 32306 exports.__esModule = true; 32307 32308/***/ }), 32309/* 3 */ 32310/***/ (function(module, exports, __webpack_require__) { 32311 32312 'use strict'; 32313 32314 var _interopRequireDefault = __webpack_require__(2)['default']; 32315 32316 exports.__esModule = true; 32317 exports.HandlebarsEnvironment = HandlebarsEnvironment; 32318 32319 var _utils = __webpack_require__(4); 32320 32321 var _exception = __webpack_require__(5); 32322 32323 var _exception2 = _interopRequireDefault(_exception); 32324 32325 var _helpers = __webpack_require__(9); 32326 32327 var _decorators = __webpack_require__(29); 32328 32329 var _logger = __webpack_require__(31); 32330 32331 var _logger2 = _interopRequireDefault(_logger); 32332 32333 var _internalProtoAccess = __webpack_require__(32); 32334 32335 var VERSION = '4.7.7
vendor: 9,203 bytes, lines 32335-32678
32335'; 32336 exports.VERSION = VERSION; 32337 var COMPILER_REVISION = 8; 32338 exports.COMPILER_REVISION = COMPILER_REVISION; 32339 var LAST_COMPATIBLE_COMPILER_REVISION = 7; 32340 32341 exports.LAST_COMPATIBLE_COMPILER_REVISION = LAST_COMPATIBLE_COMPILER_REVISION; 32342 var REVISION_CHANGES = { 32343 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 32344 2: '== 1.0.0-rc.3', 32345 3: '== 1.0.0-rc.4', 32346 4: '== 1.x.x', 32347 5: '== 2.0.0-alpha.x', 32348 6: '>= 2.0.0-beta.1', 32349 7: '>= 4.0.0 <4.3.0', 32350 8: '>= 4.3.0' 32351 }; 32352 32353 exports.REVISION_CHANGES = REVISION_CHANGES; 32354 var objectType = '[object Object]'; 32355 32356 function HandlebarsEnvironment(helpers, partials, decorators) { 32357 this.helpers = helpers || {}; 32358 this.partials = partials || {}; 32359 this.decorators = decorators || {}; 32360 32361 _helpers.registerDefaultHelpers(this); 32362 _decorators.registerDefaultDecorators(this); 32363 } 32364 32365 HandlebarsEnvironment.prototype = { 32366 constructor: HandlebarsEnvironment, 32367 32368 logger: _logger2['default'], 32369 log: _logger2['default'].log, 32370 32371 registerHelper: function registerHelper(name, fn) { 32372 if (_utils.toString.call(name) === objectType) { 32373 if (fn) { 32374 throw new _exception2['default']('Arg not supported with multiple helpers'); 32375 } 32376 _utils.extend(this.helpers, name); 32377 } else { 32378 this.helpers[name] = fn; 32379 } 32380 }, 32381 unregisterHelper: function unregisterHelper(name) { 32382 delete this.helpers[name]; 32383 }, 32384 32385 registerPartial: function registerPartial(name, partial) { 32386 if (_utils.toString.call(name) === objectType) { 32387 _utils.extend(this.partials, name); 32388 } else { 32389 if (typeof partial === 'undefined') { 32390 throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); 32391 } 32392 this.partials[name] = partial; 32393 } 32394 }, 32395 unregisterPartial: function unregisterPartial(name) { 32396 delete this.partials[name]; 32397 }, 32398 32399 registerDecorator: function registerDecorator(name, fn) { 32400 if (_utils.toString.call(name) === objectType) { 32401 if (fn) { 32402 throw new _exception2['default']('Arg not supported with multiple decorators'); 32403 } 32404 _utils.extend(this.decorators, name); 32405 } else { 32406 this.decorators[name] = fn; 32407 } 32408 }, 32409 unregisterDecorator: function unregisterDecorator(name) { 32410 delete this.decorators[name]; 32411 }, 32412 /** 32413 * Reset the memory of illegal property accesses that have already been logged. 32414 * @deprecated should only be used in handlebars test-cases 32415 */ 32416 resetLoggedPropertyAccesses: function resetLoggedPropertyAccesses() { 32417 _internalProtoAccess.resetLoggedProperties(); 32418 } 32419 }; 32420 32421 var log = _logger2['default'].log; 32422 32423 exports.log = log; 32424 exports.createFrame = _utils.createFrame; 32425 exports.logger = _logger2['default']; 32426 32427/***/ }), 32428/* 4 */ 32429/***/ (function(module, exports) { 32430 32431 'use strict'; 32432 32433 exports.__esModule = true; 32434 exports.extend = extend; 32435 exports.indexOf = indexOf; 32436 exports.escapeExpression = escapeExpression; 32437 exports.isEmpty = isEmpty; 32438 exports.createFrame = createFrame; 32439 exports.blockParams = blockParams; 32440 exports.appendContextPath = appendContextPath; 32441 var escape = { 32442 '&': '&', 32443 '<': '<', 32444 '>': '>', 32445 '"': '"', 32446 "'": ''', 32447 '`': '`', 32448 '=': '=' 32449 }; 32450 32451 var badChars = /[&<>"'`=]/g, 32452 possible = /[&<>"'`=]/; 32453 32454 function escapeChar(chr) { 32455 return escape[chr]; 32456 } 32457 32458 function extend(obj /* , ...source */) { 32459 for (var i = 1; i < arguments.length; i++) { 32460 for (var key in arguments[i]) { 32461 if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { 32462 obj[key] = arguments[i][key]; 32463 } 32464 } 32465 } 32466 32467 return obj; 32468 } 32469 32470 var toString = Object.prototype.toString; 32471 32472 exports.toString = toString; 32473 // Sourced from lodash 32474 // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt 32475 /* eslint-disable func-style */ 32476 var isFunction = function isFunction(value) { 32477 return typeof value === 'function'; 32478 }; 32479 // fallback for older versions of Chrome and Safari 32480 /* istanbul ignore next */ 32481 if (isFunction(/x/)) { 32482 exports.isFunction = isFunction = function (value) { 32483 return typeof value === 'function' && toString.call(value) === '[object Function]'; 32484 }; 32485 } 32486 exports.isFunction = isFunction; 32487 32488 /* eslint-enable func-style */ 32489 32490 /* istanbul ignore next */ 32491 var isArray = Array.isArray || function (value) { 32492 return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; 32493 }; 32494 32495 exports.isArray = isArray; 32496 // Older IE versions do not directly support indexOf so we must implement our own, sadly. 32497 32498 function indexOf(array, value) { 32499 for (var i = 0, len = array.length; i < len; i++) { 32500 if (array[i] === value) { 32501 return i; 32502 } 32503 } 32504 return -1; 32505 } 32506 32507 function escapeExpression(string) { 32508 if (typeof string !== 'string') { 32509 // don't escape SafeStrings, since they're already safe 32510 if (string && string.toHTML) { 32511 return string.toHTML(); 32512 } else if (string == null) { 32513 return ''; 32514 } else if (!string) { 32515 return string + ''; 32516 } 32517 32518 // Force a string conversion as this will be done by the append regardless and 32519 // the regex test will do this transparently behind the scenes, causing issues if 32520 // an object's to string has escaped characters in it. 32521 string = '' + string; 32522 } 32523 32524 if (!possible.test(string)) { 32525 return string; 32526 } 32527 return string.replace(badChars, escapeChar); 32528 } 32529 32530 function isEmpty(value) { 32531 if (!value && value !== 0) { 32532 return true; 32533 } else if (isArray(value) && value.length === 0) { 32534 return true; 32535 } else { 32536 return false; 32537 } 32538 } 32539 32540 function createFrame(object) { 32541 var frame = extend({}, object); 32542 frame._parent = object; 32543 return frame; 32544 } 32545 32546 function blockParams(params, ids) { 32547 params.path = ids; 32548 return params; 32549 } 32550 32551 function appendContextPath(contextPath, id) { 32552 return (contextPath ? contextPath + '.' : '') + id; 32553 } 32554 32555/***/ }), 32556/* 5 */ 32557/***/ (function(module, exports, __webpack_require__) { 32558 32559 'use strict'; 32560 32561 var _Object$defineProperty = __webpack_require__(6)['default']; 32562 32563 exports.__esModule = true; 32564 var errorProps = ['description', 'fileName', 'lineNumber', 'endLineNumber', 'message', 'name', 'number', 'stack']; 32565 32566 function Exception(message, node) { 32567 var loc = node && node.loc, 32568 line = undefined, 32569 endLineNumber = undefined, 32570 column = undefined, 32571 endColumn = undefined; 32572 32573 if (loc) { 32574 line = loc.start.line; 32575 endLineNumber = loc.end.line; 32576 column = loc.start.column; 32577 endColumn = loc.end.column; 32578 32579 message += ' - ' + line + ':' + column; 32580 } 32581 32582 var tmp = Error.prototype.constructor.call(this, message); 32583 32584 // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. 32585 for (var idx = 0; idx < errorProps.length; idx++) { 32586 this[errorProps[idx]] = tmp[errorProps[idx]]; 32587 } 32588 32589 /* istanbul ignore else */ 32590 if (Error.captureStackTrace) { 32591 Error.captureStackTrace(this, Exception); 32592 } 32593 32594 try { 32595 if (loc) { 32596 this.lineNumber = line; 32597 this.endLineNumber = endLineNumber; 32598 32599 // Work around issue under safari where we can't directly set the column value 32600 /* istanbul ignore next */ 32601 if (_Object$defineProperty) { 32602 Object.defineProperty(this, 'column', { 32603 value: column, 32604 enumerable: true 32605 }); 32606 Object.defineProperty(this, 'endColumn', { 32607 value: endColumn, 32608 enumerable: true 32609 }); 32610 } else { 32611 this.column = column; 32612 this.endColumn = endColumn; 32613 } 32614 } 32615 } catch (nop) { 32616 /* Ignore if the browser is very particular */ 32617 } 32618 } 32619 32620 Exception.prototype = new Error(); 32621 32622 exports['default'] = Exception; 32623 module.exports = exports['default']; 32624 32625/***/ }), 32626/* 6 */ 32627/***/ (function(module, exports, __webpack_require__) { 32628 32629 module.exports = { "default": __webpack_require__(7), __esModule: true }; 32630 32631/***/ }), 32632/* 7 */ 32633/***/ (function(module, exports, __webpack_require__) { 32634 32635 var $ = __webpack_require__(8); 32636 module.exports = function defineProperty(it, key, desc){ 32637 return $.setDesc(it, key, desc); 32638 }; 32639 32640/***/ }), 32641/* 8 */ 32642/***/ (function(module, exports) { 32643 32644 var $Object = Object; 32645 module.exports = { 32646 create: $Object.create, 32647 getProto: $Object.getPrototypeOf, 32648 isEnum: {}.propertyIsEnumerable, 32649 getDesc: $Object.getOwnPropertyDescriptor, 32650 setDesc: $Object.defineProperty, 32651 setDescs: $Object.defineProperties, 32652 getKeys: $Object.keys, 32653 getNames: $Object.getOwnPropertyNames, 32654 getSymbols: $Object.getOwnPropertySymbols, 32655 each: [].forEach 32656 }; 32657 32658/***/ }), 32659/* 9 */ 32660/***/ (function(module, exports, __webpack_require__) { 32661 32662 'use strict'; 32663 32664 var _interopRequireDefault = __webpack_require__(2)['default']; 32665 32666 exports.__esModule = true; 32667 exports.registerDefaultHelpers = registerDefaultHelpers; 32668 exports.moveHelperToHooks = moveHelperToHooks; 32669 32670 var _helpersBlockHelperMissing = __webpack_require__(10); 32671 32672 var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); 32673 32674 var _helpersEach = __webpack_require__(11); 32675 32676 var _helpersEach2 = _interopRequireDefault(_helpersEach); 32677 32678 var _helpersHelperMissing = __webpack_require__(
vendor: 29,993 bytes, lines 32678-33696
3267824); 32679 32680 var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); 32681 32682 var _helpersIf = __webpack_require__(25); 32683 32684 var _helpersIf2 = _interopRequireDefault(_helpersIf); 32685 32686 var _helpersLog = __webpack_require__(26); 32687 32688 var _helpersLog2 = _interopRequireDefault(_helpersLog); 32689 32690 var _helpersLookup = __webpack_require__(27); 32691 32692 var _helpersLookup2 = _interopRequireDefault(_helpersLookup); 32693 32694 var _helpersWith = __webpack_require__(28); 32695 32696 var _helpersWith2 = _interopRequireDefault(_helpersWith); 32697 32698 function registerDefaultHelpers(instance) { 32699 _helpersBlockHelperMissing2['default'](instance); 32700 _helpersEach2['default'](instance); 32701 _helpersHelperMissing2['default'](instance); 32702 _helpersIf2['default'](instance); 32703 _helpersLog2['default'](instance); 32704 _helpersLookup2['default'](instance); 32705 _helpersWith2['default'](instance); 32706 } 32707 32708 function moveHelperToHooks(instance, helperName, keepHelper) { 32709 if (instance.helpers[helperName]) { 32710 instance.hooks[helperName] = instance.helpers[helperName]; 32711 if (!keepHelper) { 32712 delete instance.helpers[helperName]; 32713 } 32714 } 32715 } 32716 32717/***/ }), 32718/* 10 */ 32719/***/ (function(module, exports, __webpack_require__) { 32720 32721 'use strict'; 32722 32723 exports.__esModule = true; 32724 32725 var _utils = __webpack_require__(4); 32726 32727 exports['default'] = function (instance) { 32728 instance.registerHelper('blockHelperMissing', function (context, options) { 32729 var inverse = options.inverse, 32730 fn = options.fn; 32731 32732 if (context === true) { 32733 return fn(this); 32734 } else if (context === false || context == null) { 32735 return inverse(this); 32736 } else if (_utils.isArray(context)) { 32737 if (context.length > 0) { 32738 if (options.ids) { 32739 options.ids = [options.name]; 32740 } 32741 32742 return instance.helpers.each(context, options); 32743 } else { 32744 return inverse(this); 32745 } 32746 } else { 32747 if (options.data && options.ids) { 32748 var data = _utils.createFrame(options.data); 32749 data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); 32750 options = { data: data }; 32751 } 32752 32753 return fn(context, options); 32754 } 32755 }); 32756 }; 32757 32758 module.exports = exports['default']; 32759 32760/***/ }), 32761/* 11 */ 32762/***/ (function(module, exports, __webpack_require__) { 32763 32764 /* WEBPACK VAR INJECTION */(function(global) {'use strict'; 32765 32766 var _Object$keys = __webpack_require__(12)['default']; 32767 32768 var _interopRequireDefault = __webpack_require__(2)['default']; 32769 32770 exports.__esModule = true; 32771 32772 var _utils = __webpack_require__(4); 32773 32774 var _exception = __webpack_require__(5); 32775 32776 var _exception2 = _interopRequireDefault(_exception); 32777 32778 exports['default'] = function (instance) { 32779 instance.registerHelper('each', function (context, options) { 32780 if (!options) { 32781 throw new _exception2['default']('Must pass iterator to #each'); 32782 } 32783 32784 var fn = options.fn, 32785 inverse = options.inverse, 32786 i = 0, 32787 ret = '', 32788 data = undefined, 32789 contextPath = undefined; 32790 32791 if (options.data && options.ids) { 32792 contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; 32793 } 32794 32795 if (_utils.isFunction(context)) { 32796 context = context.call(this); 32797 } 32798 32799 if (options.data) { 32800 data = _utils.createFrame(options.data); 32801 } 32802 32803 function execIteration(field, index, last) { 32804 if (data) { 32805 data.key = field; 32806 data.index = index; 32807 data.first = index === 0; 32808 data.last = !!last; 32809 32810 if (contextPath) { 32811 data.contextPath = contextPath + field; 32812 } 32813 } 32814 32815 ret = ret + fn(context[field], { 32816 data: data, 32817 blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) 32818 }); 32819 } 32820 32821 if (context && typeof context === 'object') { 32822 if (_utils.isArray(context)) { 32823 for (var j = context.length; i < j; i++) { 32824 if (i in context) { 32825 execIteration(i, i, i === context.length - 1); 32826 } 32827 } 32828 } else if (global.Symbol && context[global.Symbol.iterator]) { 32829 var newContext = []; 32830 var iterator = context[global.Symbol.iterator](); 32831 for (var it = iterator.next(); !it.done; it = iterator.next()) { 32832 newContext.push(it.value); 32833 } 32834 context = newContext; 32835 for (var j = context.length; i < j; i++) { 32836 execIteration(i, i, i === context.length - 1); 32837 } 32838 } else { 32839 (function () { 32840 var priorKey = undefined; 32841 32842 _Object$keys(context).forEach(function (key) { 32843 // We're running the iterations one step out of sync so we can detect 32844 // the last iteration without have to scan the object twice and create 32845 // an itermediate keys array. 32846 if (priorKey !== undefined) { 32847 execIteration(priorKey, i - 1); 32848 } 32849 priorKey = key; 32850 i++; 32851 }); 32852 if (priorKey !== undefined) { 32853 execIteration(priorKey, i - 1, true); 32854 } 32855 })(); 32856 } 32857 } 32858 32859 if (i === 0) { 32860 ret = inverse(this); 32861 } 32862 32863 return ret; 32864 }); 32865 }; 32866 32867 module.exports = exports['default']; 32868 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 32869 32870/***/ }), 32871/* 12 */ 32872/***/ (function(module, exports, __webpack_require__) { 32873 32874 module.exports = { "default": __webpack_require__(13), __esModule: true }; 32875 32876/***/ }), 32877/* 13 */ 32878/***/ (function(module, exports, __webpack_require__) { 32879 32880 __webpack_require__(14); 32881 module.exports = __webpack_require__(20).Object.keys; 32882 32883/***/ }), 32884/* 14 */ 32885/***/ (function(module, exports, __webpack_require__) { 32886 32887 // 19.1.2.14 Object.keys(O) 32888 var toObject = __webpack_require__(15); 32889 32890 __webpack_require__(17)('keys', function($keys){ 32891 return function keys(it){ 32892 return $keys(toObject(it)); 32893 }; 32894 }); 32895 32896/***/ }), 32897/* 15 */ 32898/***/ (function(module, exports, __webpack_require__) { 32899 32900 // 7.1.13 ToObject(argument) 32901 var defined = __webpack_require__(16); 32902 module.exports = function(it){ 32903 return Object(defined(it)); 32904 }; 32905 32906/***/ }), 32907/* 16 */ 32908/***/ (function(module, exports) { 32909 32910 // 7.2.1 RequireObjectCoercible(argument) 32911 module.exports = function(it){ 32912 if(it == undefined)throw TypeError("Can't call method on " + it); 32913 return it; 32914 }; 32915 32916/***/ }), 32917/* 17 */ 32918/***/ (function(module, exports, __webpack_require__) { 32919 32920 // most Object methods by ES6 should accept primitives 32921 var $export = __webpack_require__(18) 32922 , core = __webpack_require__(20) 32923 , fails = __webpack_require__(23); 32924 module.exports = function(KEY, exec){ 32925 var fn = (core.Object || {})[KEY] || Object[KEY] 32926 , exp = {}; 32927 exp[KEY] = exec(fn); 32928 $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); 32929 }; 32930 32931/***/ }), 32932/* 18 */ 32933/***/ (function(module, exports, __webpack_require__) { 32934 32935 var global = __webpack_require__(19) 32936 , core = __webpack_require__(20) 32937 , ctx = __webpack_require__(21) 32938 , PROTOTYPE = 'prototype'; 32939 32940 var $export = function(type, name, source){ 32941 var IS_FORCED = type & $export.F 32942 , IS_GLOBAL = type & $export.G 32943 , IS_STATIC = type & $export.S 32944 , IS_PROTO = type & $export.P 32945 , IS_BIND = type & $export.B 32946 , IS_WRAP = type & $export.W 32947 , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) 32948 , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] 32949 , key, own, out; 32950 if(IS_GLOBAL)source = name; 32951 for(key in source){ 32952 // contains in native 32953 own = !IS_FORCED && target && key in target; 32954 if(own && key in exports)continue; 32955 // export native or passed 32956 out = own ? target[key] : source[key]; 32957 // prevent global pollution for namespaces 32958 exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] 32959 // bind timers to global for call from export context 32960 : IS_BIND && own ? ctx(out, global) 32961 // wrap global constructors for prevent change them in library 32962 : IS_WRAP && target[key] == out ? (function(C){ 32963 var F = function(param){ 32964 return this instanceof C ? new C(param) : C(param); 32965 }; 32966 F[PROTOTYPE] = C[PROTOTYPE]; 32967 return F; 32968 // make static versions for prototype methods 32969 })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; 32970 if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; 32971 } 32972 }; 32973 // type bitmap 32974 $export.F = 1; // forced 32975 $export.G = 2; // global 32976 $export.S = 4; // static 32977 $export.P = 8; // proto 32978 $export.B = 16; // bind 32979 $export.W = 32; // wrap 32980 module.exports = $export; 32981 32982/***/ }), 32983/* 19 */ 32984/***/ (function(module, exports) { 32985 32986 // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 32987 var global = module.exports = typeof window != 'undefined' && window.Math == Math 32988 ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); 32989 if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef 32990 32991/***/ }), 32992/* 20 */ 32993/***/ (function(module, exports) { 32994 32995 var core = module.exports = {version: '1.2.6'}; 32996 if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef 32997 32998/***/ }), 32999/* 21 */ 33000/***/ (function(module, exports, __webpack_require__) { 33001 33002 // optional / simple context binding 33003 var aFunction = __webpack_require__(22); 33004 module.exports = function(fn, that, length){ 33005 aFunction(fn); 33006 if(that === undefined)return fn; 33007 switch(length){ 33008 case 1: return function(a){ 33009 return fn.call(that, a); 33010 }; 33011 case 2: return function(a, b){ 33012 return fn.call(that, a, b); 33013 }; 33014 case 3: return function(a, b, c){ 33015 return fn.call(that, a, b, c); 33016 }; 33017 } 33018 return function(/* ...args */){ 33019 return fn.apply(that, arguments); 33020 }; 33021 }; 33022 33023/***/ }), 33024/* 22 */ 33025/***/ (function(module, exports) { 33026 33027 module.exports = function(it){ 33028 if(typeof it != 'function')throw TypeError(it + ' is not a function!'); 33029 return it; 33030 }; 33031 33032/***/ }), 33033/* 23 */ 33034/***/ (function(module, exports) { 33035 33036 module.exports = function(exec){ 33037 try { 33038 return !!exec(); 33039 } catch(e){ 33040 return true; 33041 } 33042 }; 33043 33044/***/ }), 33045/* 24 */ 33046/***/ (function(module, exports, __webpack_require__) { 33047 33048 'use strict'; 33049 33050 var _interopRequireDefault = __webpack_require__(2)['default']; 33051 33052 exports.__esModule = true; 33053 33054 var _exception = __webpack_require__(5); 33055 33056 var _exception2 = _interopRequireDefault(_exception); 33057 33058 exports['default'] = function (instance) { 33059 instance.registerHelper('helperMissing', function () /* [args, ]options */{ 33060 if (arguments.length === 1) { 33061 // A missing field in a {{foo}} construct. 33062 return undefined; 33063 } else { 33064 // Someone is actually trying to call something, blow up. 33065 throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); 33066 } 33067 }); 33068 }; 33069 33070 module.exports = exports['default']; 33071 33072/***/ }), 33073/* 25 */ 33074/***/ (function(module, exports, __webpack_require__) { 33075 33076 'use strict'; 33077 33078 var _interopRequireDefault = __webpack_require__(2)['default']; 33079 33080 exports.__esModule = true; 33081 33082 var _utils = __webpack_require__(4); 33083 33084 var _exception = __webpack_require__(5); 33085 33086 var _exception2 = _interopRequireDefault(_exception); 33087 33088 exports['default'] = function (instance) { 33089 instance.registerHelper('if', function (conditional, options) { 33090 if (arguments.length != 2) { 33091 throw new _exception2['default']('#if requires exactly one argument'); 33092 } 33093 if (_utils.isFunction(conditional)) { 33094 conditional = conditional.call(this); 33095 } 33096 33097 // Default behavior is to render the positive path if the value is truthy and not empty. 33098 // The `includeZero` option may be set to treat the condtional as purely not empty based on the 33099 // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. 33100 if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { 33101 return options.inverse(this); 33102 } else { 33103 return options.fn(this); 33104 } 33105 }); 33106 33107 instance.registerHelper('unless', function (conditional, options) { 33108 if (arguments.length != 2) { 33109 throw new _exception2['default']('#unless requires exactly one argument'); 33110 } 33111 return instance.helpers['if'].call(this, conditional, { 33112 fn: options.inverse, 33113 inverse: options.fn, 33114 hash: options.hash 33115 }); 33116 }); 33117 }; 33118 33119 module.exports = exports['default']; 33120 33121/***/ }), 33122/* 26 */ 33123/***/ (function(module, exports) { 33124 33125 'use strict'; 33126 33127 exports.__esModule = true; 33128 33129 exports['default'] = function (instance) { 33130 instance.registerHelper('log', function () /* message, options */{ 33131 var args = [undefined], 33132 options = arguments[arguments.length - 1]; 33133 for (var i = 0; i < arguments.length - 1; i++) { 33134 args.push(arguments[i]); 33135 } 33136 33137 var level = 1; 33138 if (options.hash.level != null) { 33139 level = options.hash.level; 33140 } else if (options.data && options.data.level != null) { 33141 level = options.data.level; 33142 } 33143 args[0] = level; 33144 33145 instance.log.apply(instance, args); 33146 }); 33147 }; 33148 33149 module.exports = exports['default']; 33150 33151/***/ }), 33152/* 27 */ 33153/***/ (function(module, exports) { 33154 33155 'use strict'; 33156 33157 exports.__esModule = true; 33158 33159 exports['default'] = function (instance) { 33160 instance.registerHelper('lookup', function (obj, field, options) { 33161 if (!obj) { 33162 // Note for 5.0: Change to "obj == null" in 5.0 33163 return obj; 33164 } 33165 return options.lookupProperty(obj, field); 33166 }); 33167 }; 33168 33169 module.exports = exports['default']; 33170 33171/***/ }), 33172/* 28 */ 33173/***/ (function(module, exports, __webpack_require__) { 33174 33175 'use strict'; 33176 33177 var _interopRequireDefault = __webpack_require__(2)['default']; 33178 33179 exports.__esModule = true; 33180 33181 var _utils = __webpack_require__(4); 33182 33183 var _exception = __webpack_require__(5); 33184 33185 var _exception2 = _interopRequireDefault(_exception); 33186 33187 exports['default'] = function (instance) { 33188 instance.registerHelper('with', function (context, options) { 33189 if (arguments.length != 2) { 33190 throw new _exception2['default']('#with requires exactly one argument'); 33191 } 33192 if (_utils.isFunction(context)) { 33193 context = context.call(this); 33194 } 33195 33196 var fn = options.fn; 33197 33198 if (!_utils.isEmpty(context)) { 33199 var data = options.data; 33200 if (options.data && options.ids) { 33201 data = _utils.createFrame(options.data); 33202 data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); 33203 } 33204 33205 return fn(context, { 33206 data: data, 33207 blockParams: _utils.blockParams([context], [data && data.contextPath]) 33208 }); 33209 } else { 33210 return options.inverse(this); 33211 } 33212 }); 33213 }; 33214 33215 module.exports = exports['default']; 33216 33217/***/ }), 33218/* 29 */ 33219/***/ (function(module, exports, __webpack_require__) { 33220 33221 'use strict'; 33222 33223 var _interopRequireDefault = __webpack_require__(2)['default']; 33224 33225 exports.__esModule = true; 33226 exports.registerDefaultDecorators = registerDefaultDecorators; 33227 33228 var _decoratorsInline = __webpack_require__(30); 33229 33230 var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); 33231 33232 function registerDefaultDecorators(instance) { 33233 _decoratorsInline2['default'](instance); 33234 } 33235 33236/***/ }), 33237/* 30 */ 33238/***/ (function(module, exports, __webpack_require__) { 33239 33240 'use strict'; 33241 33242 exports.__esModule = true; 33243 33244 var _utils = __webpack_require__(4); 33245 33246 exports['default'] = function (instance) { 33247 instance.registerDecorator('inline', function (fn, props, container, options) { 33248 var ret = fn; 33249 if (!props.partials) { 33250 props.partials = {}; 33251 ret = function (context, options) { 33252 // Create a new partials stack frame prior to exec. 33253 var original = container.partials; 33254 container.partials = _utils.extend({}, original, props.partials); 33255 var ret = fn(context, options); 33256 container.partials = original; 33257 return ret; 33258 }; 33259 } 33260 33261 props.partials[options.args[0]] = options.fn; 33262 33263 return ret; 33264 }); 33265 }; 33266 33267 module.exports = exports['default']; 33268 33269/***/ }), 33270/* 31 */ 33271/***/ (function(module, exports, __webpack_require__) { 33272 33273 'use strict'; 33274 33275 exports.__esModule = true; 33276 33277 var _utils = __webpack_require__(4); 33278 33279 var logger = { 33280 methodMap: ['debug', 'info', 'warn', 'error'], 33281 level: 'info', 33282 33283 // Maps a given level value to the `methodMap` indexes above. 33284 lookupLevel: function lookupLevel(level) { 33285 if (typeof level === 'string') { 33286 var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); 33287 if (levelMap >= 0) { 33288 level = levelMap; 33289 } else { 33290 level = parseInt(level, 10); 33291 } 33292 } 33293 33294 return level; 33295 }, 33296 33297 // Can be overridden in the host environment 33298 log: function log(level) { 33299 level = logger.lookupLevel(level); 33300 33301 if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { 33302 var method = logger.methodMap[level]; 33303 // eslint-disable-next-line no-console 33304 if (!console[method]) { 33305 method = 'log'; 33306 } 33307 33308 for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 33309 message[_key - 1] = arguments[_key]; 33310 } 33311 33312 console[method].apply(console, message); // eslint-disable-line no-console 33313 } 33314 } 33315 }; 33316 33317 exports['default'] = logger; 33318 module.exports = exports['default']; 33319 33320/***/ }), 33321/* 32 */ 33322/***/ (function(module, exports, __webpack_require__) { 33323 33324 'use strict'; 33325 33326 var _Object$create = __webpack_require__(33)['default']; 33327 33328 var _Object$keys = __webpack_require__(12)['default']; 33329 33330 var _interopRequireWildcard = __webpack_require__(1)['default']; 33331 33332 exports.__esModule = true; 33333 exports.createProtoAccessControl = createProtoAccessControl; 33334 exports.resultIsAllowed = resultIsAllowed; 33335 exports.resetLoggedProperties = resetLoggedProperties; 33336 33337 var _createNewLookupObject = __webpack_require__(35); 33338 33339 var _logger = __webpack_require__(31); 33340 33341 var logger = _interopRequireWildcard(_logger); 33342 33343 var loggedProperties = _Object$create(null); 33344 33345 function createProtoAccessControl(runtimeOptions) { 33346 var defaultMethodWhiteList = _Object$create(null); 33347 defaultMethodWhiteList['constructor'] = false; 33348 defaultMethodWhiteList['__defineGetter__'] = false; 33349 defaultMethodWhiteList['__defineSetter__'] = false; 33350 defaultMethodWhiteList['__lookupGetter__'] = false; 33351 33352 var defaultPropertyWhiteList = _Object$create(null); 33353 // eslint-disable-next-line no-proto 33354 defaultPropertyWhiteList['__proto__'] = false; 33355 33356 return { 33357 properties: { 33358 whitelist: _createNewLookupObject.createNewLookupObject(defaultPropertyWhiteList, runtimeOptions.allowedProtoProperties), 33359 defaultValue: runtimeOptions.allowProtoPropertiesByDefault 33360 }, 33361 methods: { 33362 whitelist: _createNewLookupObject.createNewLookupObject(defaultMethodWhiteList, runtimeOptions.allowedProtoMethods), 33363 defaultValue: runtimeOptions.allowProtoMethodsByDefault 33364 } 33365 }; 33366 } 33367 33368 function resultIsAllowed(result, protoAccessControl, propertyName) { 33369 if (typeof result === 'function') { 33370 return checkWhiteList(protoAccessControl.methods, propertyName); 33371 } else { 33372 return checkWhiteList(protoAccessControl.properties, propertyName); 33373 } 33374 } 33375 33376 function checkWhiteList(protoAccessControlForType, propertyName) { 33377 if (protoAccessControlForType.whitelist[propertyName] !== undefined) { 33378 return protoAccessControlForType.whitelist[propertyName] === true; 33379 } 33380 if (protoAccessControlForType.defaultValue !== undefined) { 33381 return protoAccessControlForType.defaultValue; 33382 } 33383 logUnexpecedPropertyAccessOnce(propertyName); 33384 return false; 33385 } 33386 33387 function logUnexpecedPropertyAccessOnce(propertyName) { 33388 if (loggedProperties[propertyName] !== true) { 33389 loggedProperties[propertyName] = true; 33390 logger.log('error', 'Handlebars: Access has been denied to resolve the property "' + propertyName + '" because it is not an "own property" of its parent.\n' + 'You can add a runtime option to disable the check or this warning:\n' + 'See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details'); 33391 } 33392 } 33393 33394 function resetLoggedProperties() { 33395 _Object$keys(loggedProperties).forEach(function (propertyName) { 33396 delete loggedProperties[propertyName]; 33397 }); 33398 } 33399 33400/***/ }), 33401/* 33 */ 33402/***/ (function(module, exports, __webpack_require__) { 33403 33404 module.exports = { "default": __webpack_require__(34), __esModule: true }; 33405 33406/***/ }), 33407/* 34 */ 33408/***/ (function(module, exports, __webpack_require__) { 33409 33410 var $ = __webpack_require__(8); 33411 module.exports = function create(P, D){ 33412 return $.create(P, D); 33413 }; 33414 33415/***/ }), 33416/* 35 */ 33417/***/ (function(module, exports, __webpack_require__) { 33418 33419 'use strict'; 33420 33421 var _Object$create = __webpack_require__(33)['default']; 33422 33423 exports.__esModule = true; 33424 exports.createNewLookupObject = createNewLookupObject; 33425 33426 var _utils = __webpack_require__(4); 33427 33428 /** 33429 * Create a new object with "null"-prototype to avoid truthy results on prototype properties. 33430 * The resulting object can be used with "object[property]" to check if a property exists 33431 * @param {...object} sources a varargs parameter of source objects that will be merged 33432 * @returns {object} 33433 */ 33434 33435 function createNewLookupObject() { 33436 for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) { 33437 sources[_key] = arguments[_key]; 33438 } 33439 33440 return _utils.extend.apply(undefined, [_Object$create(null)].concat(sources)); 33441 } 33442 33443/***/ }), 33444/* 36 */ 33445/***/ (function(module, exports) { 33446 33447 // Build out our basic SafeString type 33448 'use strict'; 33449 33450 exports.__esModule = true; 33451 function SafeString(string) { 33452 this.string = string; 33453 } 33454 33455 SafeString.prototype.toString = SafeString.prototype.toHTML = function () { 33456 return '' + this.string; 33457 }; 33458 33459 exports['default'] = SafeString; 33460 module.exports = exports['default']; 33461 33462/***/ }), 33463/* 37 */ 33464/***/ (function(module, exports, __webpack_require__) { 33465 33466 'use strict'; 33467 33468 var _Object$seal = __webpack_require__(38)['default']; 33469 33470 var _Object$keys = __webpack_require__(12)['default']; 33471 33472 var _interopRequireWildcard = __webpack_require__(1)['default']; 33473 33474 var _interopRequireDefault = __webpack_require__(2)['default']; 33475 33476 exports.__esModule = true; 33477 exports.checkRevision = checkRevision; 33478 exports.template = template; 33479 exports.wrapProgram = wrapProgram; 33480 exports.resolvePartial = resolvePartial; 33481 exports.invokePartial = invokePartial; 33482 exports.noop = noop; 33483 33484 var _utils = __webpack_require__(4); 33485 33486 var Utils = _interopRequireWildcard(_utils); 33487 33488 var _exception = __webpack_require__(5); 33489 33490 var _exception2 = _interopRequireDefault(_exception); 33491 33492 var _base = __webpack_require__(3); 33493 33494 var _helpers = __webpack_require__(9); 33495 33496 var _internalWrapHelper = __webpack_require__(42); 33497 33498 var _internalProtoAccess = __webpack_require__(32); 33499 33500 function checkRevision(compilerInfo) { 33501 var compilerRevision = compilerInfo && compilerInfo[0] || 1, 33502 currentRevision = _base.COMPILER_REVISION; 33503 33504 if (compilerRevision >= _base.LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= _base.COMPILER_REVISION) { 33505 return; 33506 } 33507 33508 if (compilerRevision < _base.LAST_COMPATIBLE_COMPILER_REVISION) { 33509 var runtimeVersions = _base.REVISION_CHANGES[currentRevision], 33510 compilerVersions = _base.REVISION_CHANGES[compilerRevision]; 33511 throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); 33512 } else { 33513 // Use the embedded version info since the runtime doesn't know about this revision yet 33514 throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); 33515 } 33516 } 33517 33518 function template(templateSpec, env) { 33519 /* istanbul ignore next */ 33520 if (!env) { 33521 throw new _exception2['default']('No environment passed to template'); 33522 } 33523 if (!templateSpec || !templateSpec.main) { 33524 throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); 33525 } 33526 33527 templateSpec.main.decorator = templateSpec.main_d; 33528 33529 // Note: Using env.VM references rather than local var references throughout this section to allow 33530 // for external users to override these as pseudo-supported APIs. 33531 env.VM.checkRevision(templateSpec.compiler); 33532 33533 // backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0) 33534 var templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7; 33535 33536 function invokePartialWrapper(partial, context, options) { 33537 if (options.hash) { 33538 context = Utils.extend({}, context, options.hash); 33539 if (options.ids) { 33540 options.ids[0] = true; 33541 } 33542 } 33543 partial = env.VM.resolvePartial.call(this, partial, context, options); 33544 33545 var extendedOptions = Utils.extend({}, options, { 33546 hooks: this.hooks, 33547 protoAccessControl: this.protoAccessControl 33548 }); 33549 33550 var result = env.VM.invokePartial.call(this, partial, context, extendedOptions); 33551 33552 if (result == null && env.compile) { 33553 options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); 33554 result = options.partials[options.name](context, extendedOptions); 33555 } 33556 if (result != null) { 33557 if (options.indent) { 33558 var lines = result.split('\n'); 33559 for (var i = 0, l = lines.length; i < l; i++) { 33560 if (!lines[i] && i + 1 === l) { 33561 break; 33562 } 33563 33564 lines[i] = options.indent + lines[i]; 33565 } 33566 result = lines.join('\n'); 33567 } 33568 return result; 33569 } else { 33570 throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); 33571 } 33572 } 33573 33574 // Just add water 33575 var container = { 33576 strict: function strict(obj, name, loc) { 33577 if (!obj || !(name in obj)) { 33578 throw new _exception2['default']('"' + name + '" not defined in ' + obj, { 33579 loc: loc 33580 }); 33581 } 33582 return container.lookupProperty(obj, name); 33583 }, 33584 lookupProperty: function lookupProperty(parent, propertyName) { 33585 var result = parent[propertyName]; 33586 if (result == null) { 33587 return result; 33588 } 33589 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 33590 return result; 33591 } 33592 33593 if (_internalProtoAccess.resultIsAllowed(result, container.protoAccessControl, propertyName)) { 33594 return result; 33595 } 33596 return undefined; 33597 }, 33598 lookup: function lookup(depths, name) { 33599 var len = depths.length; 33600 for (var i = 0; i < len; i++) { 33601 var result = depths[i] && container.lookupProperty(depths[i], name); 33602 if (result != null) { 33603 return depths[i][name]; 33604 } 33605 } 33606 }, 33607 lambda: function lambda(current, context) { 33608 return typeof current === 'function' ? current.call(context) : current; 33609 }, 33610 33611 escapeExpression: Utils.escapeExpression, 33612 invokePartial: invokePartialWrapper, 33613 33614 fn: function fn(i) { 33615 var ret = templateSpec[i]; 33616 ret.decorator = templateSpec[i + '_d']; 33617 return ret; 33618 }, 33619 33620 programs: [], 33621 program: function program(i, data, declaredBlockParams, blockParams, depths) { 33622 var programWrapper = this.programs[i], 33623 fn = this.fn(i); 33624 if (data || depths || blockParams || declaredBlockParams) { 33625 programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); 33626 } else if (!programWrapper) { 33627 programWrapper = this.programs[i] = wrapProgram(this, i, fn); 33628 } 33629 return programWrapper; 33630 }, 33631 33632 data: function data(value, depth) { 33633 while (value && depth--) { 33634 value = value._parent; 33635 } 33636 return value; 33637 }, 33638 mergeIfNeeded: function mergeIfNeeded(param, common) { 33639 var obj = param || common; 33640 33641 if (param && common && param !== common) { 33642 obj = Utils.extend({}, common, param); 33643 } 33644 33645 return obj; 33646 }, 33647 // An empty object to use as replacement for null-contexts 33648 nullContext: _Object$seal({}), 33649 33650 noop: env.VM.noop, 33651 compilerInfo: templateSpec.compiler 33652 }; 33653 33654 function ret(context) { 33655 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 33656 33657 var data = options.data; 33658 33659 ret._setup(options); 33660 if (!options.partial && templateSpec.useData) { 33661 data = initData(context, data); 33662 } 33663 var depths = undefined, 33664 blockParams = templateSpec.useBlockParams ? [] : undefined; 33665 if (templateSpec.useDepths) { 33666 if (options.depths) { 33667 depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; 33668 } else { 33669 depths = [context]; 33670 } 33671 } 33672 33673 function main(context /*, options*/) { 33674 return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); 33675 } 33676 33677 main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); 33678 return main(context, options); 33679 } 33680 33681 ret.isTop = true; 33682 33683 ret._setup = function (options) { 33684 if (!options.partial) { 33685 var mergedHelpers = Utils.extend({}, env.helpers, options.helpers); 33686 wrapHelpersToPassLookupProperty(mergedHelpers, container); 33687 container.helpers = mergedHelpers; 33688 33689 if (templateSpec.usePartial) { 33690 // Use mergeIfNeeded here to prevent compiling global partials multiple times 33691 container.partials = container.mergeIfNeeded(options.partials, env.partials); 33692 } 33693 if (templateSpec.usePartial || templateSpec.useDecorators) { 33694 container.decorators = Utils.extend({}, env.decorators, options.decorators); 33695 } 33696
vendor: 4,565 bytes, lines 33697-33825
33697 container.hooks = {}; 33698 container.protoAccessControl = _internalProtoAccess.createProtoAccessControl(options); 33699 33700 var keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7; 33701 _helpers.moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers); 33702 _helpers.moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers); 33703 } else { 33704 container.protoAccessControl = options.protoAccessControl; // internal option 33705 container.helpers = options.helpers; 33706 container.partials = options.partials; 33707 container.decorators = options.decorators; 33708 container.hooks = options.hooks; 33709 } 33710 }; 33711 33712 ret._child = function (i, data, blockParams, depths) { 33713 if (templateSpec.useBlockParams && !blockParams) { 33714 throw new _exception2['default']('must pass block params'); 33715 } 33716 if (templateSpec.useDepths && !depths) { 33717 throw new _exception2['default']('must pass parent depths'); 33718 } 33719 33720 return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); 33721 }; 33722 return ret; 33723 } 33724 33725 function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { 33726 function prog(context) { 33727 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 33728 33729 var currentDepths = depths; 33730 if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { 33731 currentDepths = [context].concat(depths); 33732 } 33733 33734 return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); 33735 } 33736 33737 prog = executeDecorators(fn, prog, container, depths, data, blockParams); 33738 33739 prog.program = i; 33740 prog.depth = depths ? depths.length : 0; 33741 prog.blockParams = declaredBlockParams || 0; 33742 return prog; 33743 } 33744 33745 /** 33746 * This is currently part of the official API, therefore implementation details should not be changed. 33747 */ 33748 33749 function resolvePartial(partial, context, options) { 33750 if (!partial) { 33751 if (options.name === '@partial-block') { 33752 partial = options.data['partial-block']; 33753 } else { 33754 partial = options.partials[options.name]; 33755 } 33756 } else if (!partial.call && !options.name) { 33757 // This is a dynamic partial that returned a string 33758 options.name = partial; 33759 partial = options.partials[partial]; 33760 } 33761 return partial; 33762 } 33763 33764 function invokePartial(partial, context, options) { 33765 // Use the current closure context to save the partial-block if this partial 33766 var currentPartialBlock = options.data && options.data['partial-block']; 33767 options.partial = true; 33768 if (options.ids) { 33769 options.data.contextPath = options.ids[0] || options.data.contextPath; 33770 } 33771 33772 var partialBlock = undefined; 33773 if (options.fn && options.fn !== noop) { 33774 (function () { 33775 options.data = _base.createFrame(options.data); 33776 // Wrapper function to get access to currentPartialBlock from the closure 33777 var fn = options.fn; 33778 partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { 33779 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 33780 33781 // Restore the partial-block from the closure for the execution of the block 33782 // i.e. the part inside the block of the partial call. 33783 options.data = _base.createFrame(options.data); 33784 options.data['partial-block'] = currentPartialBlock; 33785 return fn(context, options); 33786 }; 33787 if (fn.partials) { 33788 options.partials = Utils.extend({}, options.partials, fn.partials); 33789 } 33790 })(); 33791 } 33792 33793 if (partial === undefined && partialBlock) { 33794 partial = partialBlock; 33795 } 33796 33797 if (partial === undefined) { 33798 throw new _exception2['default']('The partial ' + options.name + ' could not be found'); 33799 } else if (partial instanceof Function) { 33800 return partial(context, options); 33801 } 33802 } 33803 33804 function noop() { 33805 return ''; 33806 } 33807 33808 function initData(context, data) { 33809 if (!data || !('root' in data)) { 33810 data = data ? _base.createFrame(data) : {}; 33811 data.root = context; 33812 } 33813 return data; 33814 } 33815 33816 function executeDecorators(fn, prog, container, depths, data, blockParams) { 33817 if (fn.decorator) { 33818 var props = {}; 33819 prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); 33820 Utils.extend(prog, props); 33821 } 33822 return prog; 33823 } 33824 33825 function wrapHelpersToPassLookupProperty(mergedHelpers, container) {
33826 _Object$keys(mergedHelpers).forEach(function (helperName) { 33827 var helper = mergedHelpers[helperName]; 33828 mergedHelpers[helperName] = passLookupPropertyOption(helper, container); 33829 }); 33830 } 33831 33832 function passLookupPropertyOption(helper, container) { 33833 var lookupProperty = container.lookupProperty; 33834 return _internalWrapHelper.wrapHelper(helper, function (options) { 33835 return Utils.extend({ lookupProperty: lookupProperty }, options); 33836 }); 33837 } 33838 33839/***/ }), 33840/* 38 */ 33841/***/ (function(module, exports, __webpack_require__) { 33842 33843 module.exports = { "default": __webpack_require__(39), __esModule: true }; 33844 33845/***/ }), 33846/* 39 */ 33847/***/ (function(module, exports, __webpack_require__) { 33848 33849 __webpack_require__(40); 33850 module.exports = __webpack_require__(20).Object.seal; 33851 33852/***/ }), 33853/* 40 */ 33854/***/ (function(module, exports, __webpack_require__) { 33855 33856 // 19.1.2.17 Object.seal(O) 33857 var isObject = __webpack_require__(41); 33858 33859 __webpack_require__(17)('seal', function($seal){ 33860 return function seal(it){ 33861 return $seal && isObject(it) ? $seal(it) : it; 33862 }; 33863 }); 33864 33865/***/ }), 33866/* 41 */ 33867/***/ (function(module, exports) { 33868 33869 module.exports = function(it){ 33870 return typeof it === 'object' ? it !== null : typeof it === 'function'; 33871 }; 33872 33873/***/ }), 33874/* 42 */ 33875/***/ (function(module, exports) { 33876 33877 'use strict'; 33878 33879 exports.__esModule = true; 33880 exports.wrapHelper = wrapHelper; 33881 33882 function wrapHelper(helper, transformOptionsFn) { 33883 if (typeof helper !== 'function') { 33884 // This should not happen, but apparently it does in https://github.com/wycats/handlebars.js/issues/1639 33885 // We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function. 33886 return helper; 33887 } 33888 var wrapper = function wrapper() /* dynamic arguments */{ 33889 var options = arguments[arguments.length - 1]; 33890 arguments[arguments.length - 1] = transformOptionsFn(options); 33891 return helper.apply(this, arguments); 33892 }; 33893 return wrapper; 33894 } 33895 33896/***/ }), 33897/* 43 */ 33898/***/ (function(module, exports) { 33899 33900 /* WEBPACK VAR INJECTION */(function(global) {'use strict'; 33901 33902 exports.__esModule = true; 33903 33904 exports['default'] = function (Handlebars) { 33905 /* istanbul ignore next */ 33906 var root = typeof global !== 'undefined' ? global : window, 33907 $Handlebars = root.Handlebars; 33908 /* istanbul ignore next */ 33909 Handlebars.noConflict = function () { 33910 if (root.Handlebars === Handlebars) { 33911 root.Handlebars = $Handlebars; 33912 } 33913 return Handlebars; 33914 }; 33915 }; 33916 33917 module.exports = exports['default']; 33918 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 33919 33920/***/ }) 33921/******/ ]) 33922}); 33923; 33924Handlebars.registerHelper('I18n', 33925 function (str) { 33926 return (I18n !== undefined ? I18n.t(str) : str); 33927 } 33928); 33929(function() { 33930 (function($) { 33931 var defaults, methods; 33932 defaults = { 33933 zIndex: 500 33934 }; 33935 methods = { 33936 close: function(options) { 33937 var $modal, uuid; 33938 $modal = $(this); 33939 uuid = $modal.attr('data-modal-uuid'); 33940 $modal.hide().removeAttr('data-modal-uuid').trigger('close'); 33941 $('body').removeClass('is-scroll-locked'); 33942 $('body').append($modal); 33943 return $(".modal-backdrop[data-modal-uuid='" + uuid + "']").remove(); 33944 }, 33945 align: function() { 33946 var $modal, left, uuid; 33947 $modal = $(this); 33948 uuid = $modal.attr('data-modal-uuid'); 33949 if (uuid != null) { 33950 left = ($(window).width() - $modal.width()) / 2.0; 33951 return $modal.css({ 33952 left: left 33953 }); 33954 } 33955 }, 33956 init: function(options) { 33957 options = $.extend(defaults, options); 33958 return this.each(function() { 33959 var $backDrop, $modal, uuid; 33960 $modal = $(this); 33961 if ($modal.data('modal-uuid') == null) { 33962 defaults.zIndex += 2; 33963 $modal.css({ 33964 zIndex: defaults.zIndex 33965 }).addClass('animated fadeInDown').show(); 33966 setTimeout(function() { 33967 return $modal.removeClass('animated fadeInDown'); 33968 }, 300); 33969 uuid = guid(); 33970 $modal.attr('data-modal-uuid', uuid); 33971 $backDrop = $("<div class='modal-backdrop' data-modal-uuid='" + uuid + "'></div>"); 33972 $('body').addClass('is-scroll-locked').append($backDrop); 33973 $backDrop.append($modal); 33974 $backDrop.css({ 33975 zIndex: defaults.zIndex - 1 33976 }).show(); 33977 $modal.makeMeModal('align'); 33978 $(window).resize((function(_this) { 33979 return function() { 33980 return $modal.makeMeModal('align'); 33981 }; 33982 })(this)); 33983 return $modal.find('.js-modal-close').one('click', (function(_this) { 33984 return function() { 33985 if (typeof options.onClose === "function") { 33986 options.onClose(); 33987 } 33988 return $(_this).makeMeModal('close'); 33989 }; 33990 })(this)); 33991 } 33992 }); 33993 } 33994 }; 33995 return $.fn.makeMeModal = function(method) { 33996 if (methods[method]) { 33997 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 33998 } else if (typeof method === "object" || !method) { 33999 return methods.init.apply(this, arguments); 34000 } else { 34001 return $.error("Method " + method + " does not exist on jQuery.makeMeModal"); 34002 } 34003 }; 34004 })(jQuery); 34005 34006}
34006).call(this); 34007/* 34008(Built: Tue, May 08, 2018 12:40:15 PM) 34009Marmoset Viewer Code and Tools 34010 34011Copyright (c) 2018 Marmoset LLC. 34012All rights reserved. 34013 34014Redistribution and use of this software are permitted provided 34015that the software remains whole and unmodified and this copyright 34016notice remains attached. Use or inclusion of any portion of this 34017code in other software programs is prohibited, excepting simple 34018embedding of this file in web applications. This software, or any 34019derivatives thereof, may not be resold, rented, leased, or 34020distributed on any other for-charge basis. 34021 34022THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 34023IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 34024WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 34025*/ 34026 34027marmoset={};(function(marmoset){'use strict';function AnimatedObject(a,b,c){this.name=b.partName;this.animatedProperties=[];this.sceneObjectType=b.sceneObjectType;this.skinningRigIndex=b.skinningRigIndex;this.id=c;this.mesh=this.skinningRig=0;this.materialIndex=this.lightIndex=this.meshIndex=-1;this.emissiveProperty=this.offsetVProperty=this.offsetUProperty=this.material=0;this.debugMe=b.debugMe;this.debugString="";this.hasTransform=!1;this.modelPartIndex=b.modelPartIndex;this.modelPartFPS=b.modelPartFPS;this.modelPartScale=b.modelPartScale; 34028this.parentIndex=b.parentIndex;this.startTime=b.startTime;this.endTime=b.endTime;this.animationLength=this.endTime-this.startTime;this.totalFrames=b.totalFrames;this.turnTableSpinOffset=this.turnTableSpin=this.spinProperty=this.dispersionProperty=this.lightIllumProperty=this.skyIllumProperty=this.opacityProperty=this.spotSharpnessProperty=this.spotAngleProperty=this.distanceProperty=this.brightnessProperty=this.blueProperty=this.greenProperty=this.redProperty=this.visibleProperty=0;if(b.animatedProperties){c= 34029b.animatedProperties.length;for(var d=0;d<c;++d){var e=b.animatedProperties[d],f=new AnimatedProperty;f.name=e.name;this.animatedProperties.push(f);"Red"!=f.name||this.redProperty||(this.redProperty=f);"Green"!=f.name||this.greenProperty||(this.greenProperty=f);"Blue"!=f.name||this.blueProperty||(this.blueProperty=f);"Brightness"!=f.name||this.brightnessProperty||(this.brightnessProperty=f);"Distance"!=f.name||this.distanceProperty||(this.distanceProperty=f);"Spot Angle"!=f.name||this.spotAngleProperty|| 34030(this.spotAngleProperty=f);"Spot Sharpness"!=f.name||this.spotSharpnessProperty||(this.spotSharpnessProperty=f);"Opacity"!=f.name||this.opacityProperty||(this.opacityProperty=f);"Sky Illumination"!=f.name||this.skyIllumProperty||(this.skyIllumProperty=f);"Light Illumination"!=f.name||this.lightIllumProperty||(this.lightIllumProperty=f);"Dispersion"!=f.name||this.dispersionProperty||(this.dispersionProperty=f);"Visible"!=f.name||this.visibleProperty||(this.visibleProperty=f);"Spin Rate"==f.name&&(this.spinProperty= 34031f);"OffsetU"==f.name&&(this.offsetUProperty=f);"OffsetV"==f.name&&(this.offsetVProperty=f);"EmissiveIntensity"==f.name&&(this.emissiveProperty=f)}}this.keyframesSharedBufferUShorts=this.keyframesSharedBufferFloats=this.keyFramesByteStream=0;if(a=a.get(b.file))this.keyFramesByteStream=new ByteStream(a.data),this.unPackKeyFrames();this.animatedLocalTransform=new AnimatedTransform(this);this.hasTransform=this.animatedLocalTransform.hasTranslation||this.animatedLocalTransform.hasRotation||this.animatedLocalTransform.hasScale; 34032this.cachedWorldTransform0=Matrix.identity();this.cachedWorldTransform1=Matrix.identity();this.cachedWorldTransform2=Matrix.identity();this.cachedWorldTransform3=Matrix.identity();this.cachedFrame3=this.cachedFrame2=this.cachedFrame1=this.cachedFrame0=-10;this.cachedFrameUse3=this.cachedFrameUse2=this.cachedFrameUse1=this.cachedFrameUse0=0;this.useFixedLocalTransform=this.useFixedWorldTransform=!1} 34033AnimatedObject.prototype.setFixedWorldTransform=function(a){this.useFixedWorldTransform=!0;Matrix.copy(this.cachedWorldTransform0,a)};AnimatedObject.prototype.setFixedLocalTransform=function(a){this.useFixedLocalTransform=!0;this.animatedLocalTransform.lockTransform=!0;Matrix.copy(this.animatedLocalTransform.cachedmatrix0,a)}; 34034AnimatedObject.prototype.getCachedWorldTransform=function(a){return this.useFixedWorldTransform?0:a==this.cachedFrame0?this.cachedmatrix0:a==this.cachedFrame1?this.cachedmatrix1:a==this.cachedFrame2?this.cachedmatrix2:a==this.cachedFrame3?this.cachedmatrix3:0}; 34035AnimatedObject.prototype.getFreeCachedWorldTransform=function(a){if
34035(this.useFixedWorldTransform)return 0;this.cachedFrameUse0--;this.cachedFrameUse1--;this.cachedFrameUse2--;this.cachedFrameUse3--;if(this.cachedFrameUse0<=this.cachedFrameUse1&&this.cachedFrameUse0<=this.cachedFrameUse2&&this.cachedFrameUse0<=this.cachedFrameUse3)return this.cachedFrame0=a,this.cachedFrameUse0=0,this.cachedWorldTransform0;if(this.cachedFrameUse1<=this.cachedFrameUse0&&this.cachedFrameUse1<=this.cachedFrameUse2&&this.cachedFrameUse1<= 34036this.cachedFrameUse3)return this.cachedFrame1=a,this.cachedFrameUse1=0,this.cachedWorldTransform1;if(this.cachedFrameUse2<=this.cachedFrameUse0&&this.cachedFrameUse2<=this.cachedFrameUse1&&this.cachedFrameUse2<=this.cachedFrameUse3)return this.cachedFrame2=a,this.cachedFrameUse2=0,this.cachedWorldTransform2;this.cachedFrame3=a;this.cachedFrameUse3=0;return this.cachedWorldTransform3}; 34037AnimatedObject.prototype.unPackKeyFrames=function(){if(this.keyFramesByteStream){var a=new Float32Array(this.keyFramesByteStream.bytes.buffer),b=new Uint32Array(this.keyFramesByteStream.bytes.buffer),c=new Uint16Array(this.keyFramesByteStream.bytes.buffer),d=new Uint8Array(this.keyFramesByteStream.bytes.buffer);this.keyframesSharedBufferFloats=a;this.keyframesSharedBufferUShorts=b;for(var a=0,b=b[0],a=1+b,b=this.animatedProperties.length,e=0;e<b;e++){var f=this.animatedProperties[e],g=2+2*e,h=2*g; 34038f.keyframeBufferStartIndexFloat=a;f.numKeyframes=c[g];f.keyframePackingType=d[h+2];f.interpolationType=d[h+3];f.indexFloatSkip=0;f.indexUShortSkip=0;0<f.numKeyframes&&(0==f.keyframePackingType?(f.bytesPerKeyFrame=16,f.indexFloatSkip=4,f.indexUShortSkip=8,f.valueOffsetFloat=0,f.weighInOffsetFloat=1,f.weighOutOffsetFloat=2,f.frameIndexOffsetUShort=6,f.interpolationOffsetUShort=7):1==f.keyframePackingType?(f.bytesPerKeyFrame=8,f.indexFloatSkip=2,f.indexUShortSkip=4,f.valueOffsetFloat=0,f.weighInOffsetFloat= 340390,f.weighOutOffsetFloat=0,f.frameIndexOffsetUShort=2,f.interpolationOffsetUShort=3):2==f.keyframePackingType&&(f.bytesPerKeyFrame=4,f.indexFloatSkip=1,f.indexUShortSkip=2,f.valueOffsetFloat=0,f.weighInOffsetFloat=0,f.weighOutOffsetFloat=0,f.frameIndexOffsetUShort=0,f.interpolationOffsetUShort=0));a+=f.numKeyframes*f.indexFloatSkip}}}; 34040AnimatedObject.prototype.setupSkinningRig=function(a,b,c,d){var e=Matrix.identity(),f=Matrix.identity(),g=a.animatedObjects[b],h=c*g.modelPartFPS,h=h-Math.floor(h);c=Math.floor(a.getObjectAnimationFramePercent(g,c));var g=c+1,k=1-h,l=d.skinningClusters.length;if(0<l)for(var n=0;n<l;n++){var m=d.skinningClusters[n];m.solveClusterTransformAtFrame(a,b,c,e);m.solveClusterTransformAtFrame(a,b,g,f);for(var m=m.matrix,p=0;16>p;p++)m[p]=e[p]*k+f[p]*h}}; 34041AnimatedObject.prototype.evaluateLocalTransformAtFramePercent=function(a,b,c,d){if(this.useFixedLocalTransform)Matrix.copy(b,this.animatedLocalTransform.cachedmatrix0);else{var e=0;d&&(e=this.animatedLocalTransform.getCachedTransform(a));e?Matrix.copy(b,e):((e=this.animatedLocalTransform.getFreeCachedTransform(a))?(this.animatedLocalTransform.evaluateMatrix(e,this.totalFrames,a,c),Matrix.copy(b,e)):this.animatedLocalTransform.evaluateMatrix(b,this.totalFrames,a,c),0!=this.turnTableSpin&&(a=Matrix.rotation(Matrix.empty(), 34042this.turnTableSpin,1),Matrix.mul(b,b,a)))}};AnimatedObject.prototype.hasAnimatedTransform=function(){var a=this.animatedLocalTransform;return a.TX&&1<a.TX.numKeyframes||a.TY&&1<a.TY.numKeyframes||a.TZ&&1<a.TZ.numKeyframes||a.RX&&1<a.RX.numKeyframes||a.RY&&1<a.RY.numKeyframes||a.RZ&&1<a.RZ.numKeyframes||a.SX&&1<a.SX.numKeyframes||a.SY&&1<a.SY.numKeyframes||a.SZ&&1<a.SZ.numKeyframes?!0:!1};function AnimatedProperty(){this.currentValue=0;this.keyframeBufferStartIndexFloat=-1;this.lastValue=this.interpolationOffsetUShort=this.frameIndexOffsetUShort=this.weighOutOffsetFloat=this.weighInOffsetFloat=this.valueOffsetFloat=this.indexUShortSkip=this.indexFloatSkip=this.interpolationType=this.bytesPerKeyFrame=this.keyframePackingType=0;this.lastFramePercent=-10;this.enable=!0;this.name="NONE";this.splineKF0=new KeyFrame(0,0);this.splineKF1=new KeyFrame(0,0);this.splineKF2=new KeyFrame(0,0); 34043this.splineKF3=new KeyFrame(0,0);this.debugMe=!0;this.debugString="";this.lastSearchIndex=1;this.savedSearchIndex=0;this.splineKF0.frameIndex=0;this.splineKF1.frameIndex=1;this.splineKF2.frameIndex=2;this.splineKF3.frameIndex=3;
34043this.numKeyframes=0} 34044AnimatedProperty.prototype.evaluateCurve=function(a,b){var c=this.splineKF1.frameIndex,d=this.splineKF2.frameIndex,e=this.splineKF1.value,f=this.splineKF2.value,g=c-(this.splineKF2.frameIndex-this.splineKF0.frameIndex),h=d-(this.splineKF1.frameIndex-this.splineKF3.frameIndex),k=e-(this.splineKF2.value-this.splineKF0.value)*this.splineKF1.weighOut,l=f-(this.splineKF1.value-this.splineKF3.value)*this.splineKF2.weighIn;3==this.splineKF1.interpolation&&(g=c-(this.splineKF2.frameIndex-this.splineKF1.frameIndex), 34045k=e-this.splineKF1.weighOut);3==this.splineKF2.interpolation&&(h=d-(this.splineKF1.frameIndex-this.splineKF2.frameIndex),l=f+this.splineKF2.weighIn);g=(a-g)/(c-g);c=(a-c)/(d-c);d=(a-d)/(h-d);h=e*(1-c)+f*c;return((k*(1-g)+e*g)*(1-c)+h*c)*(1-c)+((f*(1-d)+l*d)*c+h*(1-c))*c}; 34046AnimatedProperty.prototype.evaluate=function(a,b,c){if(!c)return b;if(0==this.numKeyframes)return this.lastValue=b;if(1==this.numKeyframes)return this.lastValue=2==this.keyframePackingType?c.keyframesSharedBufferFloats[this.keyframeBufferStartIndexFloat]:c.keyframesSharedBufferFloats[this.keyframeBufferStartIndexFloat+this.valueOffsetFloat];if(this.lastFramePercent==a)return this.lastValue;var d=this.keyframeBufferStartIndexFloat,e=2*this.keyframeBufferStartIndexFloat;this.lastValue=b;this.lastFramePercent= 34047a;if(2==this.keyframePackingType){b=Math.floor(a);var f=a-b;a>=this.numKeyframes&&(b-=Math.floor(a/this.numKeyframes)*this.numKeyframes);if(b>=this.numKeyframes-1)return this.lastValue=c.keyframesSharedBufferFloats[d+(this.numKeyframes-1)];if(0>b)return this.lastValue=c.keyframesSharedBufferFloats[d];if(0==f)return this.lastValue=c.keyframesSharedBufferFloats[d+b];a=e=c.keyframesSharedBufferFloats[d+b];b++;b>=this.numKeyframes&&(b-=this.numKeyframes);0<=b&&b<this.numKeyframes?a=e*(1-f)+c.keyframesSharedBufferFloats[d+ 34048b]*f:c.debugString+="<br>bad lerp frame "+b+" of "+this.numKeyframes;return this.lastValue=a}var g=this.numKeyframes,f=c.keyframesSharedBufferUShorts[e+this.frameIndexOffsetUShort];if(a>=c.keyframesSharedBufferUShorts[e+(g-1)*this.indexUShortSkip+this.frameIndexOffsetUShort])return this.lastValue=c.keyframesSharedBufferFloats[d+(g-1)*this.indexFloatSkip+this.valueOffsetFloat];if(a<f)return this.lastValue=c.keyframesSharedBufferFloats[d+this.valueOffsetFloat];this.lastSearchIndex<this.numKeyframes&& 34049a>c.keyframesSharedBufferUShorts[e+this.lastSearchIndex*this.indexUShortSkip+this.frameIndexOffsetUShort]&&(this.lastSearchIndex=1);for(var h=this.lastSearchIndex;h<g;h++){var f=d+h*this.indexFloatSkip,k=d+(h-1)*this.indexFloatSkip,l=e+h*this.indexUShortSkip,n=e+(h-1)*this.indexUShortSkip;if(a>=c.keyframesSharedBufferUShorts[n+this.frameIndexOffsetUShort]&&a<=c.keyframesSharedBufferUShorts[l+this.frameIndexOffsetUShort]){this.lastSearchIndex=h;var m=c.keyframesSharedBufferUShorts[n+this.interpolationOffsetUShort]; 34050if(2==m){this.lastValue=a=a>=c.keyframesSharedBufferUShorts[l+this.frameIndexOffsetUShort]?c.keyframesSharedBufferFloats[f+this.valueOffsetFloat]:c.keyframesSharedBufferFloats[k+this.valueOffsetFloat];break}if(0==m){d=c.keyframesSharedBufferUShorts[n+this.frameIndexOffsetUShort];b=c.keyframesSharedBufferFloats[k+this.valueOffsetFloat];e=c.keyframesSharedBufferFloats[f+this.valueOffsetFloat];f=(a-d)/(c.keyframesSharedBufferUShorts[l+this.frameIndexOffsetUShort]-d);this.lastValue=a=b*(1-f)+e*f;break}if(1== 34051m||3==m){var p=m=!1,r=0,s=c.keyframesSharedBufferFloats[k+this.valueOffsetFloat],u=c.keyframesSharedBufferFloats[f+this.valueOffsetFloat],q=0,x=0,n=c.keyframesSharedBufferUShorts[n+this.frameIndexOffsetUShort],l=c.keyframesSharedBufferUShorts[l+this.frameIndexOffsetUShort],w=0,v=1,t=1,y=1,E=1,F=1,A=1,B=1,z=1;0!=this.weighInOffsetFloat&&(t=c.keyframesSharedBufferFloats[k+this.weighInOffsetFloat],y=c.keyframesSharedBufferFloats[f+this.weighInOffsetFloat],A=c.keyframesSharedBufferFloats[k+this.weighOutOffsetFloat], 34052B=c.keyframesSharedBufferFloats[f+this.weighOutOffsetFloat]);1<h&&(m=!0,r=c.keyframesSharedBufferFloats[d+(h-2)*this.indexFloatSkip+this.valueOffsetFloat],x=c.keyframesSharedBufferUShorts[e+(h-2)*this.indexUShortSkip+this.frameIndexOffsetUShort],0!=this.weighInOffsetFloat&&(v=c.keyframesSharedBufferFloats[d+(h-2)*this.indexFloatSkip+this.weighInOffsetFloat],F=c.keyframesSharedBufferFloats[d+(h-2)*this.indexFloatSkip+this.weighOutOffsetFloat]));h<g-1&&(p=!0,q=c.keyframesSharedBufferFloats[d+(h+1)* 34053this.indexFloatSkip+this.valueOffsetFloat],w=c.keyframesSharedBufferUShorts[e+(h+1)*this.indexUShortSkip+this.frameIndexOffsetUShort],0!=this.weighInOffsetFloat&&(E=c.keyframesSharedBufferFloats[d+(h+1)*this.indexFloatSkip+this.weighInOffsetFloat],z=c.keyframesSharedBufferFloats[d+(h+1)*this.indexFloatSkip+this.weighOutOffsetFloat]));m&&p?(this.splineKF0.value=r,this.splineKF1.value=s,this.splineKF2.value=u,this.splineKF3.value=q,this.splineKF0.frameIndex=x,this.splineKF1.frameIndex=n,this.splineKF2.frameIndex= 34054l,this.splineKF3.frameIndex=w,this.splineKF0.weighIn=v,this.splineKF0.weighOut=F,this.splineKF1.weighIn=t,this.splineKF1.weighOut=A,this.splineKF2.weighIn=y,this.splineKF2.weighOut=B,this.splineKF3.weighIn=E,this.splineKF3.weighOut=z):(this.splineKF0.value=s,this.splineKF1.value=s,this.splineKF2.value=u,this.splineKF3.value=u,this.splineKF0.frameIndex=n,this.splineKF1.frameIndex=n,this.splineKF2.frameIndex=l,this.splineKF3.frameIndex=l,this.splineKF1.weighIn=t,this.splineKF2.weighIn=y,this.splineKF1.weighOut= 34055A,this.splineKF2.weighOut=B,p?(this.splineKF3.value=q,this.splineKF3.frameIndex=w,this.splineKF3.weighIn=E,this.splineKF3.weighOut=z):(this.splineKF3.frameIndex++,this.splineKF3.value=this.splineKF1.value,this.splineKF3.weighIn=1,this.splineKF3.weighOut=1),m?(this.splineKF0.value=r,this.splineKF0.frameIndex=x,this.splineKF0.weighIn=v,this.splineKF0.weighOut=F):(this.splineKF0.value=this.splineKF2.value,this.splineKF0.weighIn=1,this.splineKF0.weighOut=1,0<this.splineKF0.frameIndex?this.splineKF0.frameIndex--: 34056(this.splineKF1.frameIndex++,this.splineKF2.frameIndex++,this.splineKF3.frameIndex++,a++)));this.lastValue=a=this.evaluateCurve(a,b);break}}}return this.lastValue};function AnimatedTransform(a){var b=a.animatedProperties;this.TX=this.TY=this.TZ=this.RX=this.RY=this.RZ=this.SX=this.SY=this.SZ=0;this.hostObject=a;this.matrix=Matrix.identity();this.cachedmatrix0=Matrix.identity();this.cachedmatrix1=Matrix.identity();this.cachedmatrix2=Matrix.identity();this.cachedmatrix3=Matrix.identity();this.cachedFrame3=this.cachedFrame2=this.cachedFrame1=this.cachedFrame0=-1;this.cachedFrameUse3=this.cachedFrameUse2=this.cachedFrameUse1=this.cachedFrameUse0=0;this.debugString= 34057"";for(a=0;a<b.length;a++){var c=b[a];"Translation X"==c.name?this.TX=c:"Translation Y"==c.name?this.TY=c:"Translation Z"==c.name?this.TZ=c:"Rotation X"==c.name?this.RX=c:"Rotation Y"==c.name?this.RY=c:"Rotation Z"==c.name?this.RZ=c:"Scale X"==c.name?this.SX=c:"Scale Y"==c.name?this.SY=c:"Scale Z"==c.name&&(this.SZ=c)}this.hasTranslation=this.TX&&this.TY&&this.TZ;this.hasRotation=this.RX&&this.RY&&this.RZ;this.hasScale=this.SX&&this.SY&&this.SZ;this.lockTransform=!1} 34058AnimatedTransform.prototype.getTRSValue=function(a,b,c){if(!b)return c;b.evaluate(a,c,this.hostObject);""!=b.debugString&&(this.debugString+=b.debugString);return b.lastValue}; 34059AnimatedTransform.prototype.evaluateMatrix=function(a,b,c,d){if(this.lockTransform)Matrix.copy(a,this.cachedmatrix0);else{var e=0,f=b=0,e=f=b=0,e=f=b=1;this.hasRotation?(e=this.getTRSValue(c,this.RX,0),b=this.getTRSValue(c,this.RY,0),f=this.getTRSValue(c,this.RZ,0),d?(this.matrix=Matrix.rotation(Matrix.empty(),f,2),d=Matrix.rotation(Matrix.empty(),e,0),Matrix.mul(d,d,this.matrix
34059),this.matrix=Matrix.rotation(Matrix.empty(),b,1)):(this.matrix=Matrix.rotation(Matrix.empty(),e,0),d=Matrix.rotation(Matrix.empty(), 34060b,1),Matrix.mul(d,d,this.matrix),this.matrix=Matrix.rotation(Matrix.empty(),f,2)),Matrix.mul(this.matrix,this.matrix,d)):Matrix.copy(this.matrix,Matrix.identity());this.hasTranslation&&(b=this.getTRSValue(c,this.TX,0),f=this.getTRSValue(c,this.TY,0),e=this.getTRSValue(c,this.TZ,0),this.matrix[12]=b,this.matrix[13]=f,this.matrix[14]=e);this.hasScale&&(b=this.getTRSValue(c,this.SX,1),f=this.getTRSValue(c,this.SY,1),e=this.getTRSValue(c,this.SZ,1),this.matrix[0]*=b,this.matrix[4]*=f,this.matrix[8]*= 34061e,this.matrix[1]*=b,this.matrix[5]*=f,this.matrix[9]*=e,this.matrix[2]*=b,this.matrix[6]*=f,this.matrix[10]*=e,this.matrix[3]*=b,this.matrix[7]*=f,this.matrix[11]*=e);Matrix.copy(a,this.matrix)}}; 34062AnimatedTransform.prototype.clearCachedTransforms=function(){this.cachedFrame3=this.cachedFrame2=this.cachedFrame1=this.cachedFrame0=-1;this.cachedFrameUse3=this.cachedFrameUse2=this.cachedFrameUse1=this.cachedFrameUse0=0;this.TX&&(this.TX.lastFramePercent=-10);this.TY&&(this.TY.lastFramePercent=-10);this.TZ&&(this.TZ.lastFramePercent=-10);this.RX&&(this.RX.lastFramePercent=-10);this.RY&&(this.RY.lastFramePercent=-10);this.RZ&&(this.RZ.lastFramePercent=-10);this.SX&&(this.SX.lastFramePercent=-10); 34063this.SY&&(this.SY.lastFramePercent=-10);this.SZ&&(this.SZ.lastFramePercent=-10);this.lockTransform=!1};AnimatedTransform.prototype.getCachedTransform=function(a){return this.lockTransform?0:this.cachedFrame0==a?this.cachedmatrix0:this.cachedFrame1==a?this.cachedmatrix1:this.cachedFrame2==a?this.cachedmatrix2:this.cachedFrame3==a?this.cachedmatrix3:0}; 34064AnimatedTransform.prototype.getFreeCachedTransform=function(a){if(this.lockTransform)return 0;this.cachedFrameUse0--;this.cachedFrameUse1--;this.cachedFrameUse2--;this.cachedFrameUse3--;if(this.cachedFrameUse0<=this.cachedFrameUse1&&this.cachedFrameUse0<=this.cachedFrameUse2&&this.cachedFrameUse0<=this.cachedFrameUse3||this.cachedFrame0==a)return this.cachedFrame0=a,this.cachedFrameUse0=0,this.cachedmatrix0;if(this.cachedFrameUse1<=this.cachedFrameUse0&&this.cachedFrameUse1<=this.cachedFrameUse2&& 34065this.cachedFrameUse1<=this.cachedFrameUse3||this.cachedFrame1==a)return this.cachedFrame1=a,this.cachedFrameUse1=0,this.cachedmatrix1;if(this.cachedFrameUse2<=this.cachedFrameUse0&&this.cachedFrameUse2<=this.cachedFrameUse1&&this.cachedFrameUse2<=this.cachedFrameUse3||this.cachedFrame2==a)return this.cachedFrame2=a,this.cachedFrameUse2=0,this.cachedmatrix2;this.cachedFrame3=a;this.cachedFrameUse3=0;return this.cachedmatrix3};function Animation(a,b){this.originalFPS=1;this.name=b.name;this.totalSeconds=b.length;this.originalFPS=b.originalFPS;this.totalFrames=b.totalFrames;this.expectedNumAnimatedObjects=b.numAnimatedObjects;this.animatedObjects=[];this.sceneTransform=Matrix.identity();this.debugString="";if(b.animatedObjects)for(var c=b.animatedObjects.length,d=0;d<c;++d){var e=new AnimatedObject(a,b.animatedObjects[d],d);this.animatedObjects.push(e);this.debugString+=e.debugString}this.meshObjects=[];this.lightObjects= 34066[];this.materialObjects=[];this.turnTableObjects=[];this.cameraObjects=[]} 34067Animation.prototype.evaluateModelPartTransformAtFrame=function(a,b,c,d){Matrix.copy(c,Matrix.identity());for(var e=0;100>e;e++){var f=this.animatedObjects[a];if(a==f.parentIndex)break;if(f.useFixedWorldTransform){Matrix.mul(c,f.cachedWorldTransform0,c);break}else{var g=0;d&&(g=f.getCachedWorldTransform(b));if(g){Matrix.mul(c,g,c);break}else g=Matrix.identity(),f.evaluateLocalTransformAtFramePercent(b,g,!1,d),Matrix.mul(c,g,c),a==f.parentIndex&&(e=100),a=f.parentIndex}}}; 34068Animation.prototype.lerpModelPartTransform=function(a,b,c,d){var e=this.animatedObjects[a];if(e.useFixedWorldTransform)Matrix.copy(c,e.cachedWorldTransform0);else{var f=b*e.modelPartFPS,f=f-Math.floor(f),g=Math.floor(this.getObjectAnimationFramePercent(e,b)),h=g+1,k=b=0;d&&(b=e.getCachedWorldTransform(g),k=e.getCachedWorldTransform(h));b||((b=e.getFreeCachedWorldTransform(g))||(b=Matrix.identity()),this.evaluateModelPartTransformAtFrame(a,g,b,d));k||((k=e.getFreeCachedWorldTransform(h))||(k=Matrix.identity()), 34069this.evaluateModelPartTransformAtFrame(a,h,k,d));a=1-f;for(d=0;16>d;d++)c[d]=b[d]*a+k[d]*f}};Animation.prototype.getModelPartTransform=function(a,b,c,d){this.lerpModelPartTransform(a,b,c,d)}; 34070Animation.prototype.getAnimatedLocalTransform=function(a,b,c,d){a=this.animatedObjects[a];var e=this.animatedObjects[a.parentIndex],f=e.modelPartIndex!=e.id,g=Matrix.identity();this.getModelPartTransform(a.modelPartIndex,b,g,d);if(f){var f=Matrix.identity(),h=Matrix.identity();this.getModelPartTransform(e.modelPartIndex,b,f,d);Matrix.invert(h,f);
34070Matrix.mul(c,h,g);c[12]*=a.modelPartScale;c[13]*=a.modelPartScale;c[14]*=a.modelPartScale}else Matrix.copy(c,g)}; 34071Animation.prototype.isVisibleAtFramePercent=function(a,b){for(var c=a,d=0,e=0;100>e;e++){d=this.animatedObjects[c];if(d.visibleProperty){d.visibleProperty.evaluate(b,1,d);if(""!=d.debugString||""!=d.visibleProperty.debugString)return this.debugString+=d.debugString,this.debugString+=d.visibleProperty.debugString,!1;if(0==d.visibleProperty.lastValue)return!1}c==d.parentIndex&&(e=100);c=d.parentIndex}return!0}; 34072Animation.prototype.getWorldTransform=function(a,b,c,d,e){a=this.animatedObjects[a];if(a.useFixedWorldTransform)Matrix.copy(c,a.cachedWorldTransform0);else{var f=this.getObjectAnimationFramePercent(a,b),g=Matrix.identity();a.evaluateLocalTransformAtFramePercent(f,g,!0,e);if(f=a.modelPartIndex!=a.id){var f=Matrix.identity(),h=Matrix.identity();Matrix.copy(h,g);this.getAnimatedLocalTransform(a.id,b,f);Matrix.mul(g,f,h)}Matrix.copy(c,g);if(a.parentIndex!=a.id)for(var k=a.parentIndex,l=0;100>l;l++)a= 34073this.animatedObjects[k],f=this.getObjectAnimationFramePercent(a,b),g=Matrix.identity(),a.evaluateLocalTransformAtFramePercent(f,g,!0,e),(f=a.modelPartIndex!=a.id)?(f=Matrix.identity(),this.getAnimatedLocalTransform(a.id,b,f),h=Matrix.identity(),Matrix.mul(h,g,c),Matrix.mul(c,f,h)):(h=Matrix.identity(),Matrix.copy(h,c),Matrix.mul(c,g,h)),k==a.parentIndex&&(l=100),k=a.parentIndex;c[12]*=d;c[13]*=d;c[14]*=d}}; 34074Animation.prototype.hasParentInHierarchy=function(a,b){for(var c=a.parentIndex,d=0;100>d;d++){a=this.animatedObjects[c];if(a.id==b)return!0;c==a.parentIndex&&(d=100);c=a.parentIndex}return!1};Animation.prototype.hasParentTypeInHierarchy=function(a,b){for(var c=a.parentIndex,d=0;100>d;d++){a=this.animatedObjects[c];if(a.sceneObjectType==b)return!0;c==a.parentIndex&&(d=100);c=a.parentIndex}return!1}; 34075Animation.prototype.searchAnimationUpHierarchy=function(a){for(var b=a.id,c=0;100>c;c++){a=this.animatedObjects[b];if(a.animatedLocalTransform&&(a.hasAnimatedTransform()||a.id!=a.modelPartIndex&&this.searchAnimationUpHierarchy(this.animatedObjects[a.modelPartIndex])))return!0;b==a.parentIndex&&(c=100);b=a.parentIndex}return!1}; 34076Animation.prototype.hasAnimationInHierarchy=function(a){return this.searchAnimationUpHierarchy(a)||a.id!=a.modelPartIndex&&this.searchAnimationUpHierarchy(this.animatedObjects[a.modelPartIndex])||this.hasParentTypeInHierarchy(a,"TurnTableSO")||this.hasParentTypeInHierarchy(a,"CameraSO")||"CameraSO"==a.sceneObjectType?!0:!1}; 34077Animation.prototype.getObjectAnimationFramePercent=function(a,b){if(0==this.totalFrames||0==a.animationLength)return 0;if(a.endTime==this.totalSeconds)return b*a.modelPartFPS;var c=b/a.animationLength,c=Math.floor(c);b-=a.animationLength*c;c=b*a.modelPartFPS;c>=a.totalFrames+1&&(c=a.totalFrames);return c};function Archive(a){this.files=[];for(a=new ByteStream(a);!a.empty();){var b={};b.name=a.readCString();b.type=a.readCString();var c=a.readUint32(),d=a.readUint32(),e=a.readUint32();b.data=a.readBytes(d);if(!(b.data.length<d)){if(c&1&&(b.data=this.decompress(b.data,e),null===b.data))continue;this.files[b.name]=b}}}Archive.prototype.get=function(a){return this.files[a]};Archive.prototype.extract=function(a){var b=this.files[a];delete this.files[a];return b}; 34078Archive.prototype.checkSignature=function(a){if(!a)return!1;var b=this.get(a.name+".sig");if(!b)return!1;b=JSON.parse(String.fromCharCode.apply(null,b.data));if(!b)return!1;for(var c=5381,d=0;d<a.data.length;++d)c=33*c+a.data[d]&4294967295;a=new BigInt;a.setBytes([0,233,33,170,116,86,29,195,228,46,189,3,185,31,245,19,159,105,73,190,158,80,175,38,210,116,221,229,171,134,104,144,140,5,99,255,208,78,248,215,172,44,79,83,5,244,152,19,92,137,112,10,101,142,209,100,244,92,190,125,28,0,185,54,143,247,49, 3407937,15,254,142,180,185,232,50,219,11,186,106,116,78,212,10,105,53,26,14,181,80,47,87,213,182,19,126,151,86,109,182,224,37,135,80,59,22,93,125,68,214,106,209,152,235,157,249,245,48,76,203,0,0,95,200,246,243,229,85,79,169],!0);d=new BigInt;d.setBytes(b[0]);return d.powmod(65537,a).toInt32()!=c?!1:!0}; 34080Archive.prototype.decompress=function(a,b){var c=new Uint8Array(b),d=0,e=new Uint32Array(4096),f=new Uint32Array(4096),g=256,h=a.length,k=0,l=1,n=0,m=1;c[d++]=a[0];for(var p=1;;p++){m=p+(p>>1);if(m+1>=h)break;var n=a[m+1],m=a[m],r=p&1?n<<4|m>>4:(n&15)<<8|m;if(r<g)if(256>r)n=d,m=1,c[d++]=r;else for(var n=d,m=f[r],r=e[r],s=r+m;r<s;)c[d++]=c[r++];else if(r==g){n=d;m=l+1;r=k;for(s=k+l;r<s;)c[d++]=c[r++];c[d++]=c[k]}else break;e[g]=k;f[g++]=l+1;k=n;l=m;g=4096<=g?256:g}return d==b?c:null};function BigInt(a){this.digits=new Uint16Array(a||0)}BigInt.prototype.setBytes=function(a,b){var c=(a.length+1)/2|0;this.digits=new Uint16Array(c);if(b)for(var d=0,c=a.length-1;0<=c;c-=2)this.digits[d++]=a[c]+(0<c?256*a[c-1]:0);else for(d=0;d<c;++d)this.digits[d]=a[2*d]+256*a[2*d+1];this.trim()};BigInt.prototype.toInt32=function(){var a=0;0<this.digits.length&&(a=this.digits[0],1<this.digits.length&&(a|=this.digits[1]<<16));return a};
34081BigInt.prototype.lessThan=function(a){if(this.digits.length==a.digits.length)for(var b=this.digits.length-1;0<=b;--b){var c=this.digits[b],d=a.digits[b];if(c!=d)return c<d}return this.digits.length<a.digits.length};BigInt.prototype.shiftRight=function(){for(var a=0,b=this.digits,c=b.length-1;0<=c;--c){var d=b[c];b[c]=d>>1|a<<15;a=d}this.trim()}; 34082BigInt.prototype.shiftLeft=function(a){if(0<a){var b=a/16|0;a%=16;for(var c=16-a,d=this.digits.length+b+1,e=new BigInt(d),f=0;f<d;++f)e.digits[f]=((f<b||f>=this.digits.length+b?0:this.digits[f-b])<<a|(f<b+1?0:this.digits[f-b-1])>>>c)&65535;e.trim();return e}return new BigInt(this)};BigInt.prototype.bitCount=function(){var a=0;if(0<this.digits.length)for(var a=16*(this.digits.length-1),b=this.digits[this.digits.length-1];b;)b>>>=1,++a;return a}; 34083BigInt.prototype.sub=function(a){var b=this.digits,c=a.digits,d=this.digits.length;a=a.digits.length;for(var e=0,f=0;f<d;++f){var g=b[f],h=f<a?c[f]:0,h=h+e,e=h>g?1:0,g=g+(e<<16);b[f]=g-h&65535}this.trim()};BigInt.prototype.mul=function(a){for(var b=new BigInt(this.digits.length+a.digits.length),c=b.digits,d=0;d<this.digits.length;++d)for(var e=this.digits[d],f=0;f<a.digits.length;++f)for(var g=e*a.digits[f],h=d+f;g;){var k=(g&65535)+c[h];c[h]=k&65535;g>>>=16;g+=k>>>16;++h}b.trim();return b}; 34084BigInt.prototype.mod=function(a){if(0>=this.digits.length||0>=a.digits.length)return new BigInt(0);var b=new BigInt(this.digits);if(!this.lessThan(a)){for(var c=new BigInt(a.digits),c=c.shiftLeft(b.bitCount()-c.bitCount());!b.lessThan(a);)c.lessThan(b)&&b.sub(c),c.shiftRight();b.trim()}return b};BigInt.prototype.powmod=function(a,b){for(var c=new BigInt([1]),d=this.mod(b);a;)a&1&&(c=c.mul(d).mod(b)),a>>>=1,d=d.mul(d).mod(b);return c}; 34085BigInt.prototype.trim=function(){for(var a=this.digits.length;0<a&&0==this.digits[a-1];)--a;a!=this.digits.length&&(this.digits=this.digits.subarray(0,a))};function Bounds(a){for(var b=0;b<a.length;++b){var c=a[b].bounds;if(void 0===this.min)this.min=[c.min[0],c.min[1],c.min[2]],this.max=[c.max[0],c.max[1],c.max[2]];else for(var d=0;3>d;++d)this.min[d]=Math.min(c.min[d],this.min[d]),this.max[d]=Math.max(c.max[d],this.max[d])}this.min=this.min?this.min:[0,0,0];this.max=this.max?this.max:[0,0,0];this.center=[0.5*(this.min[0]+this.max[0]),0.5*(this.min[1]+this.max[1]),0.5*(this.min[2]+this.max[2])];this.radius=[this.max[0]-this.center[0],this.max[1]-this.center[1], 34086this.max[2]-this.center[2]];this.radiusDiagonal=Math.sqrt(this.radius[0]*this.radius[0]+this.radius[1]*this.radius[1]+this.radius[2]*this.radius[2])};function Button(a){this.name="none";this.text="default text";this.title="none";this.debugString=this.imagePath="";this.controlRect=new ControlRect(a);this.defaultAlpha=0.5;this.focusAlpha=1;this.updateAlphas=!0;this.linkedBackground=this.backgroundOffsetY=this.backgroundOffsetX=this.edgePixelsY=this.edgePixelsX=this.backgroundBottomMiddle=this.backgroundBottomRight=this.backgroundBottomLeft=this.backgroundMiddleMiddle=this.backgroundMiddleRight=this.backgroundMiddleLeft=this.backgroundTopMiddle=this.backgroundTopRight= 34087this.backgroundTopLeft=this.backgroundMiddle=this.backgroundRight=this.backgroundLeft=0}Button.prototype.setBackground3x1=function(a,b,c,d,e,f,g){this.backgroundOffsetX=b;this.backgroundOffsetY=c;this.edgePixelsX=g;this.backgroundLeft=a.addImage(d);this.backgroundMiddle=a.addImage(e);this.backgroundRight=a.addImage(f);this.backgroundLeft.linkedControl.style.zIndex="0";this.backgroundMiddle.linkedControl.style.zIndex="0";this.backgroundRight.linkedControl.style.zIndex="0";this.setOpacity(this.defaultAlpha)}; 34088Button.prototype.setBackground3x3=function(a,b,c,d,e,f,g,h,k,l,n,m,p,r){this.backgroundOffsetX=b;this.backgroundOffsetY=c;this.edgePixelsX=p;this.edgePixelsY=r;this.backgroundTopLeft=a.addImage(d);this.backgroundMiddleLeft=a.addImage(g);this.backgroundBottomLeft=a.addImage(l);this.backgroundTopMiddle=a.addImage(e);this.backgroundMiddleMiddle=a.addImage(h);this.backgroundBottomMiddle=a.addImage(n);this.backgroundTopRight=a.addImage(f);this.backgroundMiddleRight=a.addImage(k);this.backgroundBottomRight= 34089a.addImage(m);this.backgroundTopLeft.linkedControl.style.zIndex="0";this.backgroundTopRight.linkedControl.style.zIndex="0";this.backgroundTopMiddle.linkedControl.style.zIndex="0";this.backgroundMiddleLeft.linkedControl.style.zIndex="0";this.backgroundMiddleRight.linkedControl.style.zIndex="0";this.backgroundMiddleMiddle.linkedControl.style.zIndex="0";this.backgroundBottomLeft.linkedControl.style.zIndex="0";this.backgroundBottomRight.linkedControl.style.zIndex="0";this.backgroundBottomMiddle.linkedControl.style.zIndex= 34090"0";this.setOpacity(this.defaultAlpha)};
34091Button.prototype.alignBackground=function(){var a=this.controlRect,b=a.guiScreen,c=b.left*(1-a.getScreenXPercent()),d=b.bottom*(1-a.getScreenYPercent()),e=b.width*a.getScreenWidthPercent(),a=b.height*a.getScreenHeightPercent(),d=d+this.backgroundOffsetY,c=c+this.backgroundOffsetX;if(this.backgroundTopLeft&&this.backgroundTopRight&&this.backgroundTopMiddle&&this.backgroundMiddleLeft&&this.backgroundMiddleRight&&this.backgroundMiddleMiddle&&this.backgroundBottomLeft&&this.backgroundBottomRight&&this.backgroundBottomMiddle){var b= 34092e-2*this.edgePixelsX,f=a-2*this.edgePixelsY;this.backgroundTopLeft.linkedControl.style.height=this.edgePixelsY+"px";this.backgroundTopMiddle.linkedControl.style.height=this.edgePixelsY+"px";this.backgroundTopRight.linkedControl.style.height=this.edgePixelsY+"px";this.backgroundBottomLeft.linkedControl.style.height=this.edgePixelsY+"px";this.backgroundBottomMiddle.linkedControl.style.height=this.edgePixelsY+"px";this.backgroundBottomRight.linkedControl.style.height=this.edgePixelsY+"px";this.backgroundMiddleLeft.linkedControl.style.height= 34093f+"px";this.backgroundMiddleMiddle.linkedControl.style.height=f+"px";this.backgroundMiddleRight.linkedControl.style.height=f+"px";this.backgroundTopLeft.linkedControl.style.width=this.edgePixelsX+"px";this.backgroundBottomLeft.linkedControl.style.width=this.edgePixelsX+"px";this.backgroundMiddleLeft.linkedControl.style.width=this.edgePixelsX+"px";this.backgroundTopRight.linkedControl.style.width=this.edgePixelsX+"px";this.backgroundBottomRight.linkedControl.style.width=this.edgePixelsX+"px";this.backgroundMiddleRight.linkedControl.style.width= 34094this.edgePixelsX+"px";this.backgroundTopMiddle.linkedControl.style.width=b+"px";this.backgroundBottomMiddle.linkedControl.style.width=b+"px";this.backgroundMiddleMiddle.linkedControl.style.width=b+"px";this.backgroundTopLeft.linkedControl.style.left=c+"px";this.backgroundBottomLeft.linkedControl.style.left=c+"px";this.backgroundMiddleLeft.linkedControl.style.left=c+"px";c+=this.edgePixelsX;this.backgroundTopMiddle.linkedControl.style.left=c+"px";this.backgroundBottomMiddle.linkedControl.style.left= 34095c+"px";this.backgroundMiddleMiddle.linkedControl.style.left=c+"px";c+=b;this.backgroundTopRight.linkedControl.style.left=c+"px";this.backgroundBottomRight.linkedControl.style.left=c+"px";this.backgroundMiddleRight.linkedControl.style.left=c+"px";this.backgroundBottomLeft.linkedControl.style.bottom=d+"px";this.backgroundBottomMiddle.linkedControl.style.bottom=d+"px";this.backgroundBottomRight.linkedControl.style.bottom=d+"px";d+=this.edgePixelsY;this.backgroundMiddleLeft.linkedControl.style.bottom= 34096d+"px";this.backgroundMiddleRight.linkedControl.style.bottom=d+"px";this.backgroundMiddleMiddle.linkedControl.style.bottom=d+"px";d+=f;this.backgroundTopLeft.linkedControl.style.bottom=d+"px";this.backgroundTopMiddle.linkedControl.style.bottom=d+"px";this.backgroundTopRight.linkedControl.style.bottom=d+"px"}this.backgroundLeft&&this.backgroundRight&&this.backgroundMiddle&&(e-=2*this.edgePixelsX,this.backgroundLeft.linkedControl.style.bottom=d+"px",this.backgroundMiddle.linkedControl.style.bottom= 34097d+"px",this.backgroundRight.linkedControl.style.bottom=d+"px",this.backgroundLeft.linkedControl.style.height=a+"px",this.backgroundMiddle.linkedControl.style.height=a+"px",this.backgroundRight.linkedControl.style.height=a+"px",this.backgroundLeft.linkedControl.style.width=this.edgePixelsX+"px",this.backgroundMiddle.linkedControl.style.width=e+"px",this.backgroundRight.linkedControl.style.width=this.edgePixelsX+"px",this.backgroundLeft.linkedControl.style.left=c+"px",c+=this.edgePixelsX,this.backgroundMiddle.linkedControl.style.left= 34098c+"px",this.backgroundRight.linkedControl.style.left=c+e+"px")}; 34099Button.prototype.setOpacity=function(a){this.controlRect.linkedControl.style.opacity=a;this.backgroundLeft&&(this.backgroundLeft.linkedControl.style.opacity=a);this.backgroundRight&&(this.backgroundRight.linkedControl.style.opacity=a);this.backgroundMiddle&&(this.backgroundMiddle.linkedControl.style.opacity=a);this.backgroundTopLeft&&(this.backgroundTopLeft.linkedControl.style.opacity=a);this.backgroundTopRight&&(this.backgroundTopRight.linkedControl.style.opacity=a);this.backgroundTopMiddle&&(this.backgroundTopMiddle.linkedControl.style.opacity= 34100a);this.backgroundMiddleLeft&&(this.backgroundMiddleLeft.linkedControl.style.opacity=a);this.backgroundMiddleRight&&(this.backgroundMiddleRight.linkedControl.style.opacity=a);this.backgroundMiddleMiddle&&(this.backgroundMiddleMiddle.linkedControl.style.opacity=a);this.backgroundBottomLeft&&(this.backgroundBottomLeft.linkedControl.style.opacity=a);this.backgroundBottomRight&&(this.backgroundBottomRight.linkedControl.style.opacity=a);this.backgroundBottomMiddle&&(this.backgroundBottomMiddle.linkedControl.style.opacity= 34101a)};
34102Button.prototype.setBackgroundVisible=function(a){this.backgroundLeft&&this.backgroundLeft.showControl(a);this.backgroundRight&&this.backgroundRight.showControl(a);this.backgroundMiddle&&this.backgroundMiddle.showControl(a);this.backgroundTopLeft&&this.backgroundTopLeft.showControl(a);this.backgroundTopRight&&this.backgroundTopRight.showControl(a);this.backgroundTopMiddle&&this.backgroundTopMiddle.showControl(a);this.backgroundMiddleLeft&&this.backgroundMiddleLeft.showControl(a);this.backgroundMiddleRight&&this.backgroundMiddleRight.showControl(a); 34103this.backgroundMiddleMiddle&&this.backgroundMiddleMiddle.showControl(a);this.backgroundBottomLeft&&this.backgroundBottomLeft.showControl(a);this.backgroundBottomRight&&this.backgroundBottomRight.showControl(a);this.backgroundBottomMiddle&&this.backgroundBottomMiddle.showControl(a)};Button.prototype.setVisible=function(a){this.controlRect.showControl(a);this.setBackgroundVisible(a)}; 34104Button.prototype.linkControl=function(a){this.controlRect.linkedControl=a;a.onmouseover=function(){this.updateAlphas&&(this.setOpacity(this.focusAlpha),this.controlRect.mouseOver=!0,this.linkedBackground&&this.linkedBackground.setOpacity(this.focusAlpha))}.bind(this);a.onmouseout=function(){this.updateAlphas&&(this.setOpacity(this.defaultAlpha),this.controlRect.mouseOver=!1,this.linkedBackground&&this.linkedBackground.setOpacity(this.defaultAlpha))}.bind(this)};function ByteStream(a){this.bytes=new Uint8Array(a)}ByteStream.prototype.empty=function(){return 0>=this.bytes.length};ByteStream.prototype.readCString=function(){for(var a=this.bytes,b=a.length,c=0;c<b;++c)if(0==a[c])return a=String.fromCharCode.apply(null,this.bytes.subarray(0,c)),this.bytes=this.bytes.subarray(c+1),a;return null};ByteStream.prototype.asString=function(){for(var a="",b=0;b<this.bytes.length;++b)a+=String.fromCharCode(this.bytes[b]);return a}; 34105ByteStream.prototype.readBytes=function(a){var b=this.bytes.subarray(0,a);this.bytes=this.bytes.subarray(a);return b};ByteStream.prototype.readUint32=function(){var a=this.bytes,b=a[0]|a[1]<<8|a[2]<<16|a[3]<<24;this.bytes=a.subarray(4);return b};ByteStream.prototype.readUint8=function(){var a=this.bytes,b=a[0];this.bytes=a.subarray(1);return b};ByteStream.prototype.readUint16=function(){var a=this.bytes,b=a[0]|a[1]<<8;this.bytes=a.subarray(2);return b}; 34106ByteStream.prototype.readFloat32=function(){var a=new Uint8Array(this.bytes),a=new Float32Array(a.buffer);this.bytes=this.bytes.subarray(4);return a[0]};ByteStream.prototype.seekUint32=function(a){a=this.bytes.subarray(4*a);return a[0]|a[1]<<8|a[2]<<16|a[3]<<24};ByteStream.prototype.seekFloat32=function(a){a=new Uint8Array(this.bytes.subarray(4*a));return(new Float32Array(a.buffer))[0]};ByteStream.prototype.getMatrix=function(a){return new Float32Array(this.bytes.buffer,64*a,16)};function ControlRect(a){this.name="none";this.title="frame";this.yPercent=this.xPercent=0;this.heightPercent=this.widthPercent=1;this.debugString="";this.parentControlRect=0;this.childControlRects=[];this.clicked=this.mouseDown=this.mouseOver=!1;this.localMouseYPercent=this.localMouseXPercent=0;this.enabled=this.visible=!0;this.opacity=1;this.guiScreen=a;this.id=this.callBack=this.linkedControl=0}ControlRect.prototype.getScreenWidth=function(){if(this.linkedControl)return this.guiScreen.width*this.getScreenWidthPercent()}; 34107ControlRect.prototype.getScreenHeight=function(){if(this.linkedControl)return this.guiScreen.height*this.getScreenHeightPercent()}; 34108ControlRect.prototype.updateElement=function(){var a=this.linkedControl;if(a){var b=this.guiScreen.left*(1-this.getScreenXPercent()),c=this.guiScreen.bottom*(1-this.getScreenYPercent()),d=this.guiScreen.width*this.getScreenWidthPercent(),e=this.guiScreen.height*this.getScreenHeightPercent();a.style.left=b+"px";a.style.bottom=c+"px";a.style.width=d+"px";a.style.height=e+"px"}}; 34109ControlRect.prototype.updateElement=function(){var a=this.linkedControl;if(a){var b=this.guiScreen.left*(1-this.getScreenXPercent()),c=this.guiScreen.bottom*(1-this.getScreenYPercent()),d=this.guiScreen.width*this.getScreenWidthPercent(),e=this.guiScreen.height*this.getScreenHeightPercent();a.style.left=b+"px";a.style.bottom=c+"px";a.style.width=d+"px";a.style.height=e+"px"}};ControlRect.prototype.updateChildElements=function(){this.updateElement();for(var a=0;a<this.childControlRects.length;a++)this.childControlRects[a].updateChildElements()}; 34110ControlRect.prototype.set=function(a,b,c,d){this.xPercent=a;this.yPercent=b;this.widthPercent=c;this.heightPercent=d};
34110ControlRect.prototype.linkControl=function(a){this.linkedControl=a;a.onmouseover=function(){this.mouseOver=!0}.bind(this);a.onmouseout=function(){this.mouseOver=!1}.bind(this);a.onmousedown=function(){this.mouseDown=!0}.bind(this);a.onmouseup=function(){this.mouseDown=!1}.bind(this);a.onclick=function(){this.callBack&&this.callBack(this);this.clicked=!0}.bind(this)}; 34111ControlRect.prototype.showControl=function(a){this.visible=a;this.linkedControl&&(this.linkedControl.style.display=a?"block":"none")};ControlRect.prototype.setOpacity=function(a){this.opacity=a;this.linkedControl&&(this.linkedControl.style.opacity=a)};ControlRect.prototype.hasChildControlRect=function(a){for(var b=0;b<this.childControlRects.length;b++)if(this.childControlRects[b]==a)return!0;return!1}; 34112ControlRect.prototype.registerChildControlRect=function(a){this.hasChildControlRect(a)||(this.childControlRects.push(a),a.parentControlRect=this)};ControlRect.prototype.getScreenWidthPercent=function(){var a=this.widthPercent;this.parentControlRect&&(a*=this.parentControlRect.getScreenWidthPercent());return a};ControlRect.prototype.getScreenHeightPercent=function(){var a=this.heightPercent;this.parentControlRect&&(a*=this.parentControlRect.getScreenHeightPercent());return a}; 34113ControlRect.prototype.getScreenXPercent=function(){var a=this.xPercent;this.parentControlRect&&(a*=this.parentControlRect.getScreenWidthPercent(),a+=this.parentControlRect.getScreenXPercent());return a};ControlRect.prototype.getScreenYPercent=function(){var a=this.yPercent;this.parentControlRect&&(a*=this.parentControlRect.getScreenHeightPercent(),a+=this.parentControlRect.getScreenYPercent());return a};var prepareEmbedParams=function(a){a=a||{};if(document.location.search)for(var b=document.location.search.substring(1).split("&"),c=0;c<b.length;++c){var d=b[c].split("=");a[d[0]]=d[1]}b=function(a){if(a|0)return!0;for(var c="true True TRUE yes Yes YES".split(" "),b=0;b<c.length;++b)if(a===c[b])return!0;return!1};a.width=a.width||800;a.height=a.height||600;a.autoStart=b(a.autoStart);a.pagePreset=b(a.pagePreset);a.fullFrame=b(a.fullFrame)||b(a.bare);a.fullFrame=!a.pagePreset&&a.fullFrame;return a}, 34114embed=function(a,b){var c;b=prepareEmbedParams(b);var d=b.thumbnailURL;if(b.pagePreset){c=new WebViewer(b.width,b.height,a,!!d);document.body.style.backgroundColor="#d7e4da";var e=document.createElement("div");e.style.position="relative";e.style.backgroundColor="#e4e7e4";e.style.width=b.width+12+"px";e.style.height=b.height+6+16+"px";e.style.margin="auto";e.style.boxShadow="3px 5px 12px 0px grey";document.body.appendChild(e);var f=document.createElement("div");f.style.position="relative";f.style.left= 34115"6px";f.style.top="6px";e.appendChild(f);f.appendChild(c.domRoot);if(!c.mobile){e.style.resize="both";e.style.overflow="hidden";var g=[e.style.width,e.style.height],h=function(){if(FullScreen.active())e.style.resize="none";else if(e.style.resize="both",g[0]!=e.style.width||g[1]!=e.style.height)g[0]=e.style.width,g[1]=e.style.height,c.resize(e.clientWidth-12,e.clientHeight-6-16);window.setTimeout(h,100)};h()}}else c=new WebViewer(b.fullFrame?window.innerWidth:b.width,b.fullFrame?window.innerHeight: 34116b.height,a,!!d),document.body.appendChild(c.domRoot),b.fullFrame&&(c.domRoot.style.position="absolute",c.domRoot.style.left=c.domRoot.style.top=0,window.addEventListener("resize",function(){FullScreen.active()||c.resize(window.innerWidth,window.innerHeight)}));c.ui.setThumbnailURL(d);b.autoStart&&c.loadScene();return c},fetchThumbnail=function(a,b,c,d){var e=!1,f=a+(-1==a.indexOf("?")?"?":"&")+"thumb=1",g=function(a){(a=(new Archive(a)).extract("thumbnail.jpg"))?TextureCache.parseFile(a,b,d):e?c&& 34117c():(e=!0,Network.fetchBinaryIncremental(f,g,c,394240));return 0};Network.fetchBinaryIncremental(f,g,c,65536)},marmoset="undefined"==typeof marmoset?{}:marmoset;marmoset.embed=embed;marmoset.fetchThumbnail=fetchThumbnail;function Fog(a,b){this.desc=b;this.gl=a;this.iblShader=a.shaderCache.fromURLs("fogvert.glsl","fogfrag.glsl",["#define FOG_IBL"]);var c=["#define FOG_DIR"];this.dirShader=a.shaderCache.fromURLs("fogvert.glsl","fogfrag.glsl",c);c.push("#define FOG_SHADOWS");this.dirShaderShadow=a.shaderCache.fromURLs("fogvert.glsl","fogfrag.glsl",c);c=["#define FOG_SPOT"];this.spotShader=a.shaderCache.fromURLs("fogvert.glsl","fogfrag.glsl",c);c.push("#define FOG_SHADOWS");this.spotShaderShadow=a.shaderCache.fromURLs("fogvert.glsl", 34118"fogfrag.glsl",c);c=["#define FOG_OMNI"];this.omniShaderShadow=this.omniShader=a.shaderCache.fromURLs("fogvert.glsl","fogfrag.glsl",c);this.fullscreenTriangle=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,this.fullscreenTriangle);c=new Float32Array([0,0,2,0,0,2]);a.bufferData(a.ARRAY_BUFFER,c,a.STATIC_DRAW);a.bindBuffer(a.ARRAY_BUFFER,null)} 34119Fog.prototype.draw=function(a,b){var c=this.gl,d=a.view,e=d.projectionMatrix,f=Matrix.empty();Matrix.mul(f,d.viewMatrix,d.projectionMatrix);Matrix.invert(f,d.viewProjectionMatrix);f=[e[10]+e[11],-e[14],-2*e[11]];e=[-2/e[0],-2/e[5],(1-e[8])/e[0],(1-e[9])/e[5]];c.enable(c.BLEND);c.blendFunc(c.ONE,c.ONE_MINUS_SRC_ALPHA);for(var g=0;g<a.lights.count+1;++g){var h=g-1,k=h<a.lights.shadowCount,l;l=0==g?this.iblShader:0<a.lights.spot[3*h]?k?this.spotShaderShadow:this.spotShader:0<a.lights.getLightPos(h)[3]? 34120this.omniShader:k?this.dirShaderShadow:this.dirShader;l.bind();var n=l.params;c.uniform3fv(n.uDepthToZ,f);c.uniform4fv(n.uUnproject,e);c.uniformMatrix4fv(n.uInvViewMatrix,!1,d.transform);c.uniform1f(n.uFogInvDistance,1/this.desc.distance);c.uniform1f(n.uFogOpacity,this.desc.opacity*(1-a.stripData.activeFade()));c.uniform1f(n.uFogDispersion,1-this.desc.dispersion);var m=[0,0,0];m[this.desc.type]=1;c.uniform3fv(n.uFogType,m);c.uniform3fv(n.uFogColor,this.desc.color);c.uniform1f(n.uFogIllum,0==g?this.desc.skyIllum: 34121this.desc.lightIllum);c.uniformMatrix4fv(n.uLightMatrix,!1,a.lights.invMatrix);if(0==g){h=new Float32Array(a.sky.diffuseCoefficients);for(k=4;16>k;++k)h[k]*=1-this.desc.dispersion;for(k=16;36>k;++k)h[k]*=1-this.desc.dispersion*this.desc.dispersion;c.uniform4fv(n.uFogLightSphere,h)}else{var p=a.lights.getLightPos(h),p=Matrix.mul4(Vect.empty(),a.lights.invMatrix,p[0],p[1],p[2],p[3]),m=a.lights.getLightDir(h),m=Matrix.mulVec(Vect.empty(),a.lights.invMatrix,m[0],m[1],m[2]);c.uniform4fv(n.uLightPosition, 34122p);c.uniform3fv(n.uLightColor,a.lights.getColor(h));
34122var p=0.01745329251*a.lights.spot[3*h],r=Math.cos(0.5*p);c.uniform4fv(n.uSpotParams,[-m[0],-m[1],-m[2],0<p?r*r:0]);c.uniform4fv(n.uLightAttenuation,[a.lights.parameters[3*h+0],a.lights.parameters[3*h+1],a.lights.parameters[3*h+2],r]);k&&(k=Matrix.mul(Matrix.empty(),a.lights.finalTransformBuffer.subarray(16*h),a.lights.matrix),c.uniformMatrix4fv(n.uShadowProj,!1,k),a.shadow.depthTextures[h].bind(l.samplers.uShadowMap),h=0,1<a.postRender.sampleCount&& 34123(h=a.postRender.currentSample()/a.postRender.sampleCount),c.uniform1f(n.uDitherOffset,h),c.uniform3fv(n.uAABBMin,a.bounds.min),c.uniform3fv(n.uAABBMax,a.bounds.max),h=Vect.lerp(Vect.empty(),a.bounds.min,a.bounds.max,0.5),k=Vect.distance(h,a.bounds.min),c.uniform4f(n.uCylinder,h[0],h[1],h[2],k*k))}b.bind(l.samplers.tDepth);l=l.attribs.vCoord;c.bindBuffer(c.ARRAY_BUFFER,this.fullscreenTriangle);c.enableVertexAttribArray(l);c.vertexAttribPointer(l,2,c.FLOAT,!1,0,0);c.drawArrays(c.TRIANGLES,0,3);c.disableVertexAttribArray(l); 34124c.bindBuffer(c.ARRAY_BUFFER,null)}c.disable(c.BLEND)};Fog.prototype.complete=function(){return this.iblShader.complete()&&this.dirShader.complete()&&this.dirShaderShadow.complete()&&this.spotShader.complete()&&this.spotShaderShadow.complete()&&this.omniShader.complete()&&this.omniShaderShadow.complete()};function Framebuffer(a,b){this.gl=a;this.fbo=a.createFramebuffer();a.bindFramebuffer(a.FRAMEBUFFER,this.fbo);b&&(this.width=b.width,this.height=b.height,b.color0&&(this.color0=b.color0,a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,this.color0.id,0),this.width=b.color0.desc.width,this.height=b.color0.desc.height),b.depth?(this.depth=b.depth,a.framebufferTexture2D(a.FRAMEBUFFER,a.DEPTH_ATTACHMENT,a.TEXTURE_2D,this.depth.id,0)):(this.depthBuffer=b.depthBuffer,b.createDepth&&!this.depthBuffer&& 34125(this.depthBuffer=Framebuffer.createDepthBuffer(a,this.width,this.height)),this.depthBuffer&&(a.bindRenderbuffer(a.RENDERBUFFER,this.depthBuffer),a.framebufferRenderbuffer(a.FRAMEBUFFER,a.DEPTH_ATTACHMENT,a.RENDERBUFFER,this.depthBuffer),a.bindRenderbuffer(a.RENDERBUFFER,null))));this.valid=b&&b.ignoreStatus||a.checkFramebufferStatus(a.FRAMEBUFFER)==a.FRAMEBUFFER_COMPLETE;a.bindFramebuffer(a.FRAMEBUFFER,null)} 34126Framebuffer.createDepthBuffer=function(a,b,c){var d=a.createRenderbuffer();a.bindRenderbuffer(a.RENDERBUFFER,d);a.renderbufferStorage(a.RENDERBUFFER,a.DEPTH_COMPONENT16,b,c);a.bindRenderbuffer(a.RENDERBUFFER,null);return d};Framebuffer.prototype.bind=function(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.fbo);this.gl.viewport(0,0,this.width,this.height)};Framebuffer.bindNone=function(a){a.bindFramebuffer(a.FRAMEBUFFER,null)};var FullScreen={support:function(){return!!(document.fullscreenEnabled||document.webkitFullscreenEnabled||document.mozFullScreenEnabled||document.msFullscreenEnabled)},begin:function(a,b){var c=a.requestFullscreen||a.webkitRequestFullScreen||a.mozRequestFullScreen||a.msRequestFullscreen;if(c){var d=function(){FullScreen.active()||(document.removeEventListener("fullscreenchange",d),document.removeEventListener("webkitfullscreenchange",d),document.removeEventListener("mozfullscreenchange",d),document.removeEventListener("MSFullscreenChange", 34127d));b&&b()};document.addEventListener("fullscreenchange",d);document.addEventListener("webkitfullscreenchange",d);document.addEventListener("mozfullscreenchange",d);document.addEventListener("MSFullscreenChange",d);c.bind(a)()}},end:function(){var a=document.exitFullscreen||document.webkitExitFullscreen||document.mozCancelFullScreen||document.msExitFullscreen;a&&a.bind(document)()},active:function(){return!!(document.fullscreenElement||document.webkitIsFullScreen||document.mozFullScreenElement||document.msFullscreenElement)}};function GUIManager(a){this.init=!1;this.ui=a;this.bottom=this.left=this.height=this.width=0;this.clicked=this.mouseDown=!1;this.playbackControls=0;a=1;window.devicePixelRatio&&(2<window.devicePixelRatio?a=4:1<window.devicePixelRatio&&(a=2));this.imageSetNumber=a}GUIManager.prototype.setSize=function(a,b){this.width=a;this.height=b;this.left=-a;this.bottom=-b;this.playbackControls&&this.playbackControls.resize(this)}; 34128GUIManager.prototype.setupActiveView=function(a){this.init||(this.init=!0,this.ui=a,a.viewer.scene.sceneAnimator&&(this.playbackControls=new PlaybackControls(this),this.playbackControls.resize(this)))}; 34129GUIManager.prototype.updateElement=function(a){var b=a.linkedControl;if(b){var c=this.left*(1-a.getScreenXPercent()),d=this.bottom*(1-a.getScreenYPercent()),e=this.width*a.getScreenWidthPercent();a=this.height*a.getScreenHeightPercent();b.style.left=c+"px";b.style.bottom=d+"px";b.style.width=e+"px";b.style.height=a+"px"}};function GUIRegion(a){this.debugString="GUIRegion";this.name="Default";this.controlRect=new ControlRect(a);this.yPercent=this.xPercent=0;this.heightPercent=this.widthPercent=1;this.guiScreen=a} 34130GUIRegion.prototype.addImageElement=function(a,b){var c=this.guiScreen.ui.menuCluster.contents,d=document.createElement("input");a.linkControl(d);this.guiScreen.updateElement(a);d.type="image";d.src=marmoset.dataLocale+b;d.style.position="absolute";d.style.border="none";d.style.outline="0px";d.style.zIndex="1";d.title=b;d.style.opacity=a.opacity;var e=new XMLHttpRequest;e.open("HEAD",d.src,!0);e.onload=function(a){a.appendChild(this)}.bind(d,c);e.send();return d}; 34131GUIRegion.prototype.addImage=function(a){var b=new ControlRect(this.guiScreen);this.addImageElement(b,a);return b}; 34132GUIRegion.prototype.addTextButton=function(a,b,c,d,e,f){var g=new Button(this.guiScreen);g.name="none";g.text=a;g.controlRect.set(b,c,d,e);g.controlRect.opacity=f;this.controlRect.registerChildControlRect(g.controlRect);b=this.guiScreen.ui.menuCluster.contents;c=document.createElement("text");c.style.color="white";c.style.fontFamily="Arial";c.style.fontSize=marmoset.largeUI?"14px":"12px";c.style.textShadow="2px 2px 3px #000000";b.appendChild(c);g.controlRect.linkControl(c);this.guiScreen.updateElement(g.controlRect); 34133c.type="text";c.name="text";c.style.position="absolute";c.style.border="none";c.style.outline="0px";c.style.zIndex="2";c.innerHTML=a;c.style.opacity=g.controlRect.opacity;g.linkControl(c);return g};function GUIScreen(a){this.init=!1;this.ui=a;this.bottom=this.left=this.height=this.width=0;this.clicked=this.mouseDown=!1;this.playbackControls=0;a=1;window.devicePixelRatio&&(2<window.devicePixelRatio?a=4:1<window.devicePixelRatio&&(a=2));this.imageSetNumber=a}GUIScreen.prototype.setSize=function(a,b){this.width=a;this.height=b;this.left=-a;this.bottom=-b;this.playbackControls&&this.playbackControls.resize(this)}; 34134GUIScreen.prototype.setupActiveView=function(a){this.init||(this.init=!0,this.ui=a,a.viewer.scene.sceneAnimator&&(this.playbackControls=new PlaybackControls(this),this.playbackControls.resize(this)))}; 34135GUIScreen.prototype.updateElement=function(a){var b=a.linkedControl;if(b){var c=this.left*(1-a.getScreenXPercent()),d=this.bottom*(1-a.getScreenYPercent()),e=this.width*a.getScreenWidthPercent();a=this.height*a.getScreenHeightPercent();b.style.left=c+"px";b.style.bottom=d+"px";b.style.width=e+"px";b.style.height=a+"px"}};function Input(a){this.onTap=[];this.onSingleTap=[];this.onDoubleTap=[];this.onDrag=[];this.onZoom=[];this.onPan=[];this.onPan2=[];this.onAnything=[];this.mouseDownCount=0;this.macHax=0<=navigator.platform.toUpperCase().indexOf("MAC");a&&this.attach(a)} 34136Input.prototype.attach=function(a){this.element=a;var b=function(a){for(var b=0;b<this.onAnything.length;++b)this.onAnything[b]();a.preventDefault()}.bind(this);this.mouseStates=[{pressed:!1,position:[0,0],downPosition:[0,0]},{pressed:!1,position:[0,0],downPosition:[0,0]},{pressed:!1,position:[0,0],downPosition:[0,0]}];this.lastTapPos=[0,0];
34136a=function(a){if(a.target===this.element){this.mouseDownCount++;var d=this.mouseStates[a.button];if(d){d.pressed=!0;var e=this.element.getBoundingClientRect(); 34137d.position[0]=d.downPosition[0]=a.clientX-e.left;d.position[1]=d.downPosition[1]=a.clientY-e.top;b(a)}}}.bind(this);this.element.addEventListener("mousedown",a);a=function(a){var d=this.mouseStates[a.button];if(d){var e=this.element.getBoundingClientRect(),f=a.clientX-e.left,e=a.clientY-e.top;d.pressed=!1;d.position[0]=f;d.position[1]=e;if(0==a.button&&a.target==this.element&&10>Math.abs(d.position[0]-d.downPosition[0])+Math.abs(d.position[1]-d.downPosition[1])){for(var g=0;g<this.onTap.length;++g)this.onTap[g](f, 34138e);this.needSingleClick=!0;window.setTimeout(function(a,c){if(this.needSingleClick){for(var b=0;b<this.onSingleTap.length;++b)this.onSingleTap[b](a,c);this.needSingleClick=!1}}.bind(this,f,e),301);d=!1;if(void 0!==this.doubleClickTimer&&(g=8>Math.abs(f-this.lastTapPos[0])+Math.abs(e-this.lastTapPos[1]),300>Date.now()-this.doubleClickTimer&&g))for(d=!0,this.needSingleClick=!1,g=0;g<this.onDoubleTap.length;++g)this.onDoubleTap[g](f,e);this.doubleClickTimer=Date.now();d&&(this.doubleClickTimer=-1E9); 34139this.lastTapPos[0]=f;this.lastTapPos[1]=e}}b(a)}.bind(this);this.element.addEventListener("mouseup",a);a=function(a){for(var d=!1,e=this.element.getBoundingClientRect(),f=0;3>f;++f){var g=this.mouseStates[f];if(g.pressed){var d=a.clientX-e.left,h=a.clientY-e.top,k=d-g.position[0],l=h-g.position[1];g.position[0]=d;g.position[1]=h;if(2==f&&a.altKey)for(g=0;g<this.onZoom.length;++g)this.onZoom[g](2*l);else if(1<=f||a.ctrlKey)for(g=0;g<this.onPan.length;++g)this.onPan[g](k,l);else if(0==f)if(a.shiftKey)for(g= 341400;g<this.onPan2.length;++g)this.onPan2[g](k,l);else for(g=0;g<this.onDrag.length;++g)this.onDrag[g](d,h,k,l);d=!0}}d&&b(a)}.bind(this);this.element.addEventListener("mousemove",a);a=function(a){var d=0;a.deltaY?(d=-0.4*a.deltaY,1==a.deltaMode?d*=16:2==a.deltaMode&&(d*=this.element.clientHeight)):a.wheelDelta?d=this.macHax&&120==Math.abs(a.wheelDelta)?0.08*a.wheelDelta:0.4*a.wheelDelta:a.detail&&(d=-10*a.detail);for(var e=0;e<this.onZoom.length;++e)this.onZoom[e](d);b(a)}.bind(this);this.element.addEventListener("mousewheel", 34141a);this.element.addEventListener("DOMMouseScroll",a);this.element.addEventListener("wheel",a);a=function(a){for(var b=0;b<this.mouseStates.length;++b)this.mouseStates[b].pressed=!1;a.preventDefault()}.bind(this);this.element.addEventListener("mouseleave",a);this.element.addEventListener("contextmenu",function(a){a.preventDefault()});this.touches={};this.tapPossible=!1;this.touchCountFloor=0;a=function(a){for(var d=this.element.getBoundingClientRect(),e=!1,f=0;f<a.changedTouches.length;++f)if(a.target=== 34142this.element){var g=a.changedTouches[f],e={x:g.clientX-d.left,y:g.clientY-d.top};e.startX=e.x;e.startY=e.y;this.touches[g.identifier]=e;e=!0}this.tapPossible=1==a.touches.length;for(g=d=0;g<this.touches.length;++g)d++;d>this.touchCountFloor&&(this.touchCountFloor=d);e&&b(a)}.bind(this);this.element.addEventListener("touchstart",a);a=function(a){for(var d=!1,e=0;e<a.changedTouches.length;++e){var f=a.changedTouches[e],g=this.touches[f.identifier];if(g){if(this.tapPossible){var h=this.element.getBoundingClientRect(), 34143d=f.clientX-h.left,h=f.clientY-h.top;if(24>Math.max(Math.abs(d-g.startX),Math.abs(h-g.startY))){for(e=0;e<this.onTap.length;++e)this.onTap[e](d,h);this.needSingleTap=!0;window.setTimeout(function(a,b){if(this.needSingleTap){for(var c=0;c<this.onSingleTap.length;++c)this.onSingleTap[c](a,b);this.needSingleTap=!1}}.bind(this,d,h),501);g=!1;if(void 0!==this.doubleTapTimer){var k=24>Math.max(Math.abs(d-this.lastTapPos[0]),Math.abs(h-this.lastTapPos[1])),l=500>Date.now()-this.doubleTapTimer;if(k&&l)for(g= 34144!0,e=0;e<this.onDoubleTap.length;++e)this.onDoubleTap[e](d,h)}this.doubleTapTimer=Date.now();g&&(this.doubleTapTimer=-1E9);this.lastTapPos[0]=d;this.lastTapPos[1]=h}this.tapPossible=!1}delete this.touches[f.identifier];d=!0}}for(f=e=0;f<this.touches.length;++f)e++;0>=e&&(this.touchCountFloor=0);d&&b(a)}.bind(this);this.element.addEventListener("touchend",a);this.element.addEventListener("touchcancel",a);this.element.addEventListener("touchleave",a);a=function(a){for(var d=[],e=0;e<a.touches.length;++e)a.touches[e].target=== 34145this.element&&d.push(a.touches[e]);var f=this.element.getBoundingClientRect();if(1==d.length&&1>=this.touchCountFloor){var g=d[0],h=this.touches[g.identifier];if(h){var k=g.clientX-f.left,g=g.clientY-f.top,f=k-h.x,l=g-h.y;h.x=k;h.y=g;for(e=0;e<this.onDrag.length;++e)this.onDrag[e](k,g,f,l,a.shiftKey)}}else if(2==d.length&&2>=this.touchCountFloor){if(l=d[0],e=this.touches[l.identifier],g=d[1],h=this.touches[g.identifier],e&&h){var k=l.clientX-f.left,l=l.clientY-f.top,n=g.clientX-f.left,m=g.clientY- 34146f.top,p=Math.sqrt((k-n)*(k-n)+(l-m)*(l-m)),r=Math.sqrt((e.x-h.x)*(e.x-h.x)+(e.y-h.y)*(e.y-h.y)),s=Math.abs(p-r),f=(k-e.x+n-h.x)/2,g=(l-e.y+m-h.y)/2,u=Math.sqrt(f*f+g*g);e.x=k;e.y=l;h.x=n;h.y=m;if(0<s)for(h=s/(s+u),e=0;e<this.onZoom.length;++e)this.onZoom[e](2*(p-r)*h);if(0<u)for(h=u/(s+u),e=0;e<this.onDrag.length;++e)this.onPan[e](f*h,g*h)}}
34146else if(3<=d.length){for(e=r=p=n=l=0;e<d.length;++e)g=d[e],h=this.touches[g.identifier],k=g.clientX-f.left,g=g.clientY-f.top,p+=k,r+=g,h&&(l+=h.x,n+=h.y,h.x=k, 34147h.y=g);l/=d.length;n/=d.length;p/=d.length;r/=d.length;for(e=0;e<this.onPan2.length;++e)this.onPan2[e](p-l,r-n)}0<d.length&&b(a)}.bind(this);this.element.addEventListener("touchmove",a)};function KeyFrame(a,b){a&&b?(this.frameIndex=b.frameIndex,this.value=b.value,this.interpolation=b.interpolation,this.weighIn=b.weighIn,this.weighOut=b.weighOut):(this.interpolation=this.value=this.frameIndex=0,this.weighOut=this.weighIn=1)};function Lights(a,b){this.rotation=this.shadowCount=this.count=0;this.positions=[];this.directions=[];this.matrixWeights=[];this.matrix=Matrix.identity();this.invMatrix=Matrix.identity();this.defaultmatrix=Matrix.identity();this.defaultviewmatrix=Matrix.identity();for(var c in a)this[c]=a[c];this.count=this.positions.length/4;this.count=Math.min(6,this.count);this.shadowCount=Math.min(3,this.shadowCount);this.positions=new Float32Array(this.positions);this.positionBuffer=new Float32Array(this.positions); 34148this.directions=new Float32Array(this.directions);this.directionBuffer=new Float32Array(this.directions);this.colors=new Float32Array(this.colors);this.colorsBuffer=new Float32Array(this.colors);this.modelViewBuffer=new Float32Array(16*this.shadowCount);this.projectionBuffer=new Float32Array(16*this.shadowCount);this.finalTransformBuffer=new Float32Array(16*this.shadowCount);this.inverseTransformBuffer=new Float32Array(16*this.shadowCount);this.shadowTexelPadProjections=new Float32Array(4*this.shadowCount); 34149this.shadowsNeedUpdate=new Uint8Array(this.shadowCount);for(var d=0;d<this.shadowsNeedUpdate.length;++d)this.shadowsNeedUpdate[d]=1;Matrix.rotation(this.matrix,this.rotation,1);Matrix.transpose(this.invMatrix,this.matrix);Matrix.copy(this.defaultmatrix,this.matrix);Matrix.copy(this.defaultviewmatrix,b.viewMatrix);for(d=0;d<this.count;++d){c=this.positions.subarray(4*d,4*d+4);var e=this.directions.subarray(3*d,3*d+3);1==this.matrixWeights[d]?(Matrix.mul4(c,this.matrix,c[0],c[1],c[2],c[3]),Matrix.mulVec(e, 34150this.matrix,e[0],e[1],e[2])):2==this.matrixWeights[d]&&(Matrix.mul4(c,b.viewMatrix,c[0],c[1],c[2],c[3]),Matrix.mulVec(e,b.viewMatrix,e[0],e[1],e[2]))}}Lights.prototype.getLightPos=function(a){return this.positionBuffer.subarray(4*a,4*a+4)};Lights.prototype.setLightDistance=function(a,b){0>=b&&(b=1E-5);this.parameters[3*a+2]=1/b};Lights.prototype.setLightSpotAngle=function(a,b){0>=b&&(b=1E-6);this.spot[3*a]=b;var c=Math.sin(3.1415926/180*b/2);this.spot[3*a+2]=1/(c*c)*this.spot[3*a+1]}; 34151Lights.prototype.setLightSpotSharpness=function(a,b){this.spot[3*a+1]=b;this.setLightSpotAngle(this.spot[3*a])};Lights.prototype.setLightPos=function(a,b){this.positions[4*a+0]=b[0];this.positions[4*a+1]=b[1];this.positions[4*a+2]=b[2];var c=this.positions.subarray(4*a,4*a+4);1==this.matrixWeights[a]?Matrix.mul4(c,this.defaultmatrix,b[0],b[1],b[2],c[3]):2==this.matrixWeights[a]&&Matrix.mul4(c,this.defaultviewmatrix,b[0],b[1],b[2],c[3])}; 34152Lights.prototype.setLightDir=function(a,b){this.directions[3*a+0]=b[0];this.directions[3*a+1]=b[1];this.directions[3*a+2]=b[2];var c=this.directions.subarray(3*a,3*a+3);1==this.matrixWeights[a]?Matrix.mulVec(c,this.defaultmatrix,b[0],b[1],b[2]):2==this.matrixWeights[a]&&Matrix.mulVec(c,this.defaultviewmatrix,b[0],b[1],b[2])};Lights.prototype.getLightColor=function(a){return this.colors.subarray(3*a,3*a+3)}; 34153Lights.prototype.setLightColor=function(a,b){this.colors[3*a+0]=b[0];this.colors[3*a+1]=b[1];this.colors[3*a+2]=b[2]};Lights.prototype.getLightDir=function(a){return this.directionBuffer.subarray(3*a,3*a+3)};Lights.prototype.getColor=function(a){a*=3;return[this.colors[a],this.colors[a+1],this.colors[a+2]]}; 34154Lights.prototype.update=function(a,b){var c=new Matrix.type(this.matrix);Matrix.rotation(this.matrix,this.rotation,1);Matrix.transpose(this.invMatrix,this.matrix);for(var d=0;d<this.count;++d){var e=this.positions.subarray(4*d,4*d+4),f=this.directions.subarray(3*d,3*d+3),g=this.getLightPos(d),h=this.getLightDir(d);1==this.matrixWeights[d]?(g[0]=e[0],g[1]=e[1],g[2]=e[2],g[3]=e[3],h[0]=f[0],h[1]=f[1],h[2]=f[2]):2==this.matrixWeights[d]?(Matrix.mul4(g,a.transform,e[0],e[1],e[2],e[3]),Matrix.mulVec(h, 34155a.transform,f[0],f[1],f[2]),Matrix.mul4(g,this.matrix,g[0],g[1],g[2],g[3]),Matrix.mulVec(h,this.matrix,h[0],h[1],h[2])):(Matrix.mul4(g,this.matrix,e[0],e[1],e[2],e[3]),Matrix.mulVec(h,this.matrix,f[0],f[1],f[2]));Vect.normalize(h,h)}for(var f=new Float32Array(this.finalTransformBuffer),g=Matrix.empty(),h=Matrix.empty(),k=Matrix.empty(),l=Vect.empty(),n=Vect.empty(),m=Vect.empty(),p=Vect.empty(),e=Vect.empty(),r=[],s=[],u=Matrix.create(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1),d=0;d<this.count;++d){l= 34156this.getLightPos(d);n=this.getLightDir(d);0.99<Math.abs(n[1])?Vect.set(m,1,0,0):Vect.set(m,0,1,0);Vect.cross(p,m,n);Vect.normalize(p,p);Vect.cross(m,n,p);Vect.normalize(m,m);Matrix.set(g,p[0],p[1],p[2],-Vect.dot(p,l),m[0],m[1],m[2],-Vect.dot(m,l),n[0],n[1],n[2],-Vect.dot(n,l),0,0,0,1);for(l=0;8>l;++l)e[0]=l&1?b.max[0]:b.min[0],e[1]=l&2?b.max[1]:b.min[1],e[2]=l&4?b.max[2]:b.min[2],Matrix.mulPoint(e,this.matrix,1.005*e[0],1.005*e[1],1.005*e[2]),Matrix.mulPoint(e,g,e[0],e[1],e[2]),0==l?(r[0]=s[0]=e[0], 34157r[1]=s[1]=e[1],r[2]=s[2]=e[2]):(r[0]=Math.min(r[0],e[0]),r[1]=Math.min(r[1],e[1]),r[2]=Math.min(r[2],e[2]),s[0]=Math.max(s[0],e[0]),s[1]=Math.max(s[1],e[1]),s[2]=Math.max(s[2],e[2]));var l=-r[2],n=-s[2],q=this.spot[3*d];0<q?(l=Math.min(l,1/this.parameters[3*d+2]),n=Math.max(0.04*l,n),Matrix.perspective(h,q,1,n,l),d<this.shadowCount&&(l=2*-Math.tan(0.00872664625*q),this.shadowTexelPadProjections[4*d+0]=this.modelViewBuffer[16*d+2]*l,this.shadowTexelPadProjections[4*d+1]=this.modelViewBuffer[16*d+6]* 34158l,this.shadowTexelPadProjections[4*d+2]=this.modelViewBuffer[16*d+10]*l,this.shadowTexelPadProjections[4*d+3]=this.modelViewBuffer[16*d+14]*l)):(Matrix.ortho(h,r[0],s[0],r[1],s[1],n,l),d<this.shadowCount&&(this.shadowTexelPadProjections[4*d+0]=this.shadowTexelPadProjections[4*d+1]=this.shadowTexelPadProjections[4*d+2]=0,this.shadowTexelPadProjections[4*d+3]=Math.max(s[0]-r[0],s[1]-r[1])));Matrix.mul(k,h,g);
34158Matrix.mul(k,u,k);Matrix.copyToBuffer(this.modelViewBuffer,16*d,g);Matrix.copyToBuffer(this.projectionBuffer, 3415916*d,h);Matrix.copyToBuffer(this.finalTransformBuffer,16*d,k);Matrix.invert(k,k);Matrix.copyToBuffer(this.inverseTransformBuffer,16*d,k)}e=!1;for(d=0;d<c.length;++d)if(c[d]!=this.matrix[d]){e=!0;break}for(d=0;d<this.shadowCount;d++)if(e&&1==this.matrixWeights[d])this.shadowsNeedUpdate[d]=1;else for(c=16*d;c<16*d+16;++c)if(f[c]!=this.finalTransformBuffer[c]){this.shadowsNeedUpdate[d]=1;break}}; 34160Lights.prototype.flagUpdateAnimatedLighting=function(){for(var a=0;a<this.shadowCount;a++)this.shadowsNeedUpdate[a]=1};function ListBox(a){this.name="none";this.text="default text";this.title="none";this.debugString=this.imagePath="";this.controlRect=new ControlRect(a);this.textEntries=[];this.textOffsetsX=[];this.textOffsetsY=[];this.buttons=[];this.listBoxEntryHeight=20;this.selectedItemText="";this.selectedIndex=-1;this.localPixelsY=0;this.localPixelsX=100;this.labelPixelDrop=0;this.labelPixelInset=10;this.labelTextHeight=16;this.closed=!1;this.defaultButtonText=this.spacerMiddle=this.spacerRight=this.spacerLeft= 34161this.spacerControl=0;this.listBoxButtons=[];this.listBoxRegion=new GUIRegion(a);this.guiScreen=a;this.lastMouseOverIndex=-1;this.selectionChangedCallback=0;this.debugString=""}ListBox.prototype.linkControl=function(a){this.controlRect.linkControl(a)}; 34162ListBox.prototype.spawnControl=function(a,b,c,d,e,f){var g=this.guiScreen.imageSetNumber,h="backgroundTopLE"+g+"x.png",k="backgroundTopM"+g+"x.png",l="backgroundTopRE"+g+"x.png",n="backgroundMiddleLE"+g+"x.png",m="backgroundMiddleM"+g+"x.png",p="backgroundMiddleRE"+g+"x.png",r="backgroundBottomLE"+g+"x.png",s="backgroundBottomM"+g+"x.png",u="backgroundBottomRE"+g+"x.png",q=3*g,x="backgroundLE"+g+"x.png",w="backgroundM"+g+"x.png",v="backgroundRE"+g+"x.png",t=2*g,y="spacerLE"+g+"x.png",E="spacerM"+ 34163g+"x.png",F="spacerRE"+g+"x.png",g=2*g,A=this.controlRect.guiScreen.width,B=this.controlRect.guiScreen.height;if(e){e=this.textEntries.length;var z=c;for(c=0;c<e;c++){var C=8*(this.textEntries[c]?this.textEntries[c].length:0);z<C&&(z=C)}c=z+f}e=this.textEntries.length+1;f=1/e;this.localPixelsX=c;this.listBoxEntryHeight=d;this.localPixelsY=(this.textEntries.length+1)*this.listBoxEntryHeight;c=8/this.localPixelsY;d=6/this.localPixelsX;z=4/this.localPixelsX;C=f-c/4;this.labelTextHeight=marmoset.largeUI? 3416420:16;this.labelPixelDrop=(this.listBoxEntryHeight-this.labelTextHeight)/2;this.listBoxRegion.controlRect.widthPercent=this.localPixelsX/A;this.listBoxRegion.controlRect.heightPercent=this.localPixelsY/B;this.listBoxRegion.controlRect.xPercent=a/A;this.listBoxRegion.controlRect.yPercent=b/B;this.openBackground=this.listBoxRegion.addTextButton("",0,0,1,1+c,1);this.openBackground.setBackground3x3(this.listBoxRegion,0,0,h,k,l,n,m,p,r,s,u,q,q);this.closedBackground=this.listBoxRegion.addTextButton("", 341650,0,1,f,1);this.closedBackground.setBackground3x1(this.listBoxRegion,0,0,x,w,v,t);a=this.labelPixelInset+this.textOffsetsX[0];b=this.labelPixelDrop+this.textOffsetsY[0];b/=this.localPixelsY;a/=this.localPixelsX;this.defaultButton=this.listBoxRegion.addTextButton("Selected",a,-b,1,f,0.5);this.selectedIndex=0;this.defaultButton.controlRect.linkedControl.innerHTML=this.textEntries[this.selectedIndex];this.defaultButton.linkedBackground=this.closedBackground;this.spacerControl=this.listBoxRegion.addTextButton("", 34166d,C,1-(d+z),c,1);this.spacerControl.defaultAlpha=1;this.spacerControl.setBackground3x1(this.listBoxRegion,0,0,y,E,F,g);this.spacerControl.setVisible(!1);this.spacerControl.linkedBackground=this.openBackground;for(c=1;c<e;c++)a=this.labelPixelInset+this.textOffsetsX[c-1],b=this.labelPixelDrop+this.textOffsetsY[c-1]-4,a/=this.localPixelsX,b/=this.localPixelsY,y=this.listBoxRegion.addTextButton(this.textEntries[c-1],a,f*c-b,1-a,f,0.5),this.listBoxButtons.push(y),y.linkedBackground=this.openBackground; 34167this.showList(!1);this.setupCallbacks()}; 34168ListBox.prototype.setControl=function(a,b,c,d,e,f){var g=this.controlRect.guiScreen.width,h=this.controlRect.guiScreen.height;if(e){e=this.textEntries.length;for(var k=0;k<e;k++){var l=8*(this.textEntries[k]?this.textEntries[k].length:0);c<l&&(c=l)}c+=f}this.localPixelsX=c;this.listBoxEntryHeight=d;this.localPixelsY=(this.textEntries.length+1)*this.listBoxEntryHeight;this.listBoxRegion.controlRect.widthPercent=this.localPixelsX/g;this.listBoxRegion.controlRect.heightPercent=this.localPixelsY/h;this.listBoxRegion.controlRect.xPercent= 34169a/g;this.listBoxRegion.controlRect.yPercent=b/h;this.listBoxRegion.controlRect.updateChildElements();
34169this.spacerControl.alignBackground();this.openBackground.alignBackground();this.closedBackground.alignBackground()};ListBox.prototype.addItem=function(a,b,c){this.textEntries.push(a);this.textOffsetsX.push(b);this.textOffsetsY.push(c)}; 34170ListBox.prototype.showList=function(a){for(var b=this.listBoxButtons.length,c=0;c<b;c++)this.listBoxButtons[c].setVisible(a);this.closed=!a;this.spacerControl&&this.spacerControl.setVisible(a);this.openBackground&&this.openBackground.setVisible(a);this.closedBackground&&this.closedBackground.setVisible(!a);a?(this.defaultButton.linkedBackground=this.openBackground,this.openBackground.setOpacity(1),this.closedBackground.setOpacity(0.5)):this.defaultButton.linkedBackground=this.closedBackground}; 34171ListBox.prototype.selectItem=function(a){this.selectedItemText=this.textEntries[a];this.selectedIndex=a;this.defaultButton.controlRect.linkedControl.innerHTML=this.textEntries[this.selectedIndex];a=(this.labelTextHeight-this.listBoxEntryHeight+3)/this.localPixelsY;this.defaultButton.controlRect.xPercent=(this.labelPixelInset+this.textOffsetsX[this.selectedIndex])/this.localPixelsX;this.defaultButton.controlRect.yPercent=a;this.defaultButton.controlRect.updateElement()}; 34172ListBox.prototype.setupCallbacks=function(){var a=function(a){if(this.closed){var b=this.closedBackground.controlRect.linkedControl,b=b.getBoundingClientRect(),c=a.clientX-b.left;a=a.clientY-b.top;c/=b.width;b=a/b.height;0<=c&&1>=c&&0<=b&&1>=b?this.closedBackground.setOpacity(1):this.closedBackground.setOpacity(0.5)}else b=this.openBackground.controlRect.linkedControl,b=b.getBoundingClientRect(),c=a.clientX-b.left,a=a.clientY-b.top,c/=b.width,b=a/b.height,0<=c&&1>=c&&0<=b&&1>=b?this.openBackground.setOpacity(1): 34173this.openBackground.setOpacity(0.5)}.bind(this);this.defaultButton.controlRect.linkedControl.onclick=function(){this.closed?this.showList(!0):(this.showList(this.closed),this.closedBackground.setOpacity(1),this.defaultButton.setOpacity(1))}.bind(this);for(var b=function(a){this.selectItem(a.id);this.showList(!1);this.defaultButton.setOpacity(0.5);this.selectionChangedCallback&&this.selectionChangedCallback(this)}.bind(this),c=function(a){a=this.listBoxButtons.length;for(var b=0;b<a;b++)this.listBoxButtons[b].controlRect.mouseOver&& 34174(this.selectItem(b),b=a,this.selectionChangedCallback&&this.selectionChangedCallback(this));this.showList(!1)}.bind(this),d=this.listBoxButtons.length,e=0;e<d;e++)this.listBoxButtons[e].controlRect.callBack=b,this.listBoxButtons[e].controlRect.id=e,this.listBoxButtons[e].controlRect.linkedControl.addEventListener("mousemove",a);this.guiScreen.ui.viewer.input.element.addEventListener("mousemove",a);this.openBackground.controlRect.linkedControl.addEventListener("mousemove",a);this.closedBackground.controlRect.linkedControl.addEventListener("mousemove", 34175a);this.guiScreen.ui.viewer.input.element.addEventListener("mousedown",c)};function Material(a,b,c){this.gl=a;this.name=c.name;var d={mipmap:!0,aniso:a.hints.mobile?0:4,clamp:!!c.textureWrapClamp,mirror:!!c.textureWrapMirror},e={mipmap:d.mipmap,clamp:d.clamp,mirror:d.mirror,nofilter:c.textureFilterNearest||!1};e.nofilter||(e.aniso=a.hints.mobile?2:4);this.textures={albedo:a.textureCache.fromFilesMergeAlpha(b.get(c.albedoTex),b.get(c.alphaTex),e),reflectivity:a.textureCache.fromFilesMergeAlpha(b.get(c.reflectivityTex),b.get(c.glossTex),d),normal:a.textureCache.fromFile(b.get(c.normalTex), 34176d),extras:a.textureCache.fromFilesMergeAlpha(b.get(c.extrasTex),b.get(c.extrasTexA),d)};this.extrasTexCoordRanges={};if(c.extrasTexCoordRanges)for(var f in c.extrasTexCoordRanges)this.extrasTexCoordRanges[f]=new Float32Array(c.extrasTexCoordRanges[f].scaleBias);this.textures.extras||(b=new Texture(a,{width:1,height:1}),b.loadArray(new Uint8Array([255,255,255,255])),this.textures.extras=b);var g=c.blendTint||[1,1,1];b={none:function(){a.disable(a.BLEND)},alpha:function(){a.enable(a.BLEND);a.blendFuncSeparate(a.SRC_ALPHA, 34177a.ONE_MINUS_SRC_ALPHA,a.ONE_MINUS_DST_ALPHA,a.ONE)},add:function(){a.enable(a.BLEND);a.blendColor(g[0],g[1],g[2],1);a.blendFunc(a.ONE,a.CONSTANT_COLOR)}};this.blend=b[c.blend]||b.none;this.alphaTest=c.alphaTest||0;this.usesBlending=this.blend!==b.none;this.usesRefraction=!!c.refraction;this.shadowAlphaTest=this.alphaTest;0>=this.shadowAlphaTest&&this.blend===b.alpha&&(this.shadowAlphaTest=0.5);this.castShadows=this.blend!==b.add;this.horizonOcclude=c.horizonOcclude||0;this.fresnel=new Float32Array(c.fresnel? 34178c.fresnel:[1,1,1]);this.emissiveIntensity=c.emissiveIntensity||1;d=[];e=!1;0<c.lightCount&&d.push("#define LIGHT_COUNT "+c.lightCount);0<c.shadowCount&&(f=Math.min(c.lightCount,c.shadowCount),this.usesRefraction&&8>=a.limits.textureCount&&(f=2<f?2:f),d.push("#define SHADOW_COUNT "+f));0<c.alphaTest&&d.push("#define ALPHA_TEST");this.blend===b.alpha?d.push("#define TRANSPARENCY_DITHER"):this.blend===b.none&&d.push("#define NOBLEND");a.hints.mobile&&d.push("#define MOBILE");a.ext.textureDepth&&d.push("#define SHADOW_NATIVE_DEPTH"); 34179f=function(a){return 1/(2/3*3.1415962*(a*a+a+1))};c.useSkin&&(d.push("#define SKIN"),this.skinParams=c.skinParams||{subdermisColor:[1,1,1],transColor:[1,0,0,1],fresnelColor:[0.2,0.2,0.2,0.5],fresnelOcc:1,fresnelGlossMask:1,transSky:0.5,shadowBlur:0.5,normalSmooth:0.5,transScatter:0,transDepth:0,millimeterScale:1},this.extrasTexCoordRanges.subdermisTex||d.push("#define SKIN_NO_SUBDERMIS_TEX"),this.extrasTexCoordRanges.translucencyTex||d.push("#define SKIN_NO_TRANSLUCENCY_TEX"),this.extrasTexCoordRanges.fuzzTex|| 34180d.push("#define SKIN_NO_FUZZ_TEX"),void 0===this.skinParams.version&&(this.skinParams.version=1),2==this.skinParams.version?(d.push("#define SKIN_VERSION_2"),this.skinParams.shadowBlur*=4,this.skinParams.shadowBlur=Math.min(this.skinParams.shadowBlur,40),this.skinParams.transIntegral=f(0.5*this.skinParams.transScatter),this.skinParams.fresnelIntegral=1/3.14159*(1-0.5*this.skinParams.fresnelColor[3]),this.skinParams.transSky=0):(d.push("#define SKIN_VERSION_1"),this.skinParams.shadowBlur=8*Math.min(this.skinParams.shadowBlur, 341811),this.skinParams.transDepth=0,this.skinParams.transScatter=this.skinParams.transColor[3],this.skinParams.transIntegral=1/3.14159*(1-0.5*this.skinParams.transScatter),this.skinParams.fresnelIntegral=1/3.14159*(1-0.5*this.skinParams.fresnelColor[3]),this.skinParams.transSky*=1.25,this.skinParams.transIntegral*=1.25));c.aniso&&(d.push("#define ANISO"),this.anisoParams=c.anisoParams||{strength:1,tangent:[1,0,0],integral:0.5},this.extrasTexCoordRanges.anisoTex||d.push("#define ANISO_NO_DIR_TEX"));c.microfiber&& 34182(d.push("#define MICROFIBER"),this.microfiberParams=c.microfiberParams||{fresnelColor:[0.2,0.2,0.2,0.5],fresnelOcc:1,fresnelGlossMask:1},this.microfiberParams.fresnelIntegral=1/3.14159*(1-0.5*this.microfiberParams.fresnelColor[3]),this.extrasTexCoordRanges.fuzzTex||d.push("#define MICROFIBER_NO_FUZZ_TEX"));c.refraction&&(d.push("#define REFRACTION"),this.refractionParams=c.refractionParams||{distantBackgroun
34182d:!1,tint:[1,1,1],useAlbedoTint:!1,IOR:1.5},this.extrasTexCoordRanges.refractionMaskTex||d.push("#define REFRACTION_NO_MASK_TEX")); 34183c.vertexColor&&(d.push("#define VERTEX_COLOR"),c.vertexColorsRGB&&d.push("#define VERTEX_COLOR_SRGB"),c.vertexColorAlpha&&d.push("#define VERTEX_COLOR_ALPHA"));this.horizonSmoothing=c.horizonSmoothing||0;0<this.horizonSmoothing&&d.push("#define HORIZON_SMOOTHING");c.unlitDiffuse&&d.push("#define DIFFUSE_UNLIT");this.extrasTexCoordRanges.emissiveTex&&(d.push("#define EMISSIVE"),c.emissiveSecondaryUV&&(d.push("#define EMISSIVE_SECONDARY_UV"),e=!0));this.extrasTexCoordRanges.aoTex&&(d.push("#define AMBIENT_OCCLUSION"), 34184c.aoSecondaryUV&&(d.push("#define AMBIENT_OCCLUSION_SECONDARY_UV"),e=!0));c.tangentOrthogonalize&&d.push("#define TSPACE_ORTHOGONALIZE");c.tangentNormalize&&d.push("#define TSPACE_RENORMALIZE");c.tangentGenerateBitangent&&d.push("#define TSPACE_COMPUTE_BITANGENT");e&&d.push("#define TEXCOORD_SECONDARY");this.vOffset=this.uOffset=0;d.push("#define UV_OFFSET ");this.shader=a.shaderCache.fromURLs("matvert.glsl","matfrag.glsl",d);d.push("#define STRIPVIEW");this.stripShader=a.shaderCache.fromURLs("matvert.glsl", 34185"matfrag.glsl",d);this.wireShader=a.shaderCache.fromURLs("wirevert.glsl","wirefrag.glsl");this.blend===b.alpha&&(this.prepassShader=a.shaderCache.fromURLs("alphaprepassvert.glsl","alphaprepassfrag.glsl"))} 34186Material.prototype.bind=function(a,b){if(!this.complete())return!1;var c=a.view,d=a.lights,e=a.sky,f=a.shadow,g=a.stripData.active()?this.stripShader:this.shader,h=this.skinParams,k=this.anisoParams,l=this.microfiberParams,n,m=this.gl,p=g.params,r=this.textures,s=g.samplers;g.bind();this.blend();var u=b.mesh.displayMatrix,q=Matrix.mul(Matrix.empty(),c.viewMatrix,u),x=Matrix.mul(Matrix.empty(),c.projectionMatrix,c.viewMatrix),q=Matrix.mul(Matrix.empty(),c.projectionMatrix,q),u=Matrix.mul(Matrix.empty(), 34187d.matrix,u);m.uniformMatrix4fv(p.uModelViewProjectionMatrix,!1,q);m.uniformMatrix4fv(p.uSkyMatrix,!1,u);u=Matrix.mulPoint(Vect.empty(),d.matrix,c.transform[12],c.transform[13],c.transform[14]);m.uniform3f(p.uCameraPosition,u[0],u[1],u[2]);m.uniform3fv(p.uFresnel,this.fresnel);m.uniform1f(p.uAlphaTest,this.alphaTest);m.uniform1f(p.uHorizonOcclude,this.horizonOcclude);m.uniform1f(p.uHorizonSmoothing,this.horizonSmoothing);m.uniform4fv(p.uDiffuseCoefficients,e.diffuseCoefficients);0<d.count&&(m.uniform4fv(p.uLightPositions, 34188d.positionBuffer),m.uniform3fv(p.uLightDirections,d.directionBuffer),m.uniform3fv(p.uLightColors,d.colors),m.uniform3fv(p.uLightParams,d.parameters),m.uniform3fv(p.uLightSpot,d.spot),u=0.392699*a.postRender.currentSample(),m.uniform2f(p.uShadowKernelRotation,0.5*Math.cos(u),0.5*Math.sin(u)),0<d.shadowCount&&(u=f.depthTextures[0].desc.width,m.uniform2f(p.uShadowMapSize,u,1/u),m.uniformMatrix4fv(p.uShadowMatrices,!1,d.finalTransformBuffer),m.uniformMatrix4fv(p.uInvShadowMatrices,!1,d.inverseTransformBuffer), 34189m.uniform4fv(p.uShadowTexelPadProjections,d.shadowTexelPadProjections),f.bindDepthTexture(s.tDepth0,0),f.bindDepthTexture(s.tDepth1,1),f.bindDepthTexture(s.tDepth2,2)));h&&(m.uniform3fv(p.uSubdermisColor,h.subdermisColor),m.uniform4fv(p.uTransColor,h.transColor),m.uniform1f(p.uTransScatter,h.transScatter),m.uniform4fv(p.uFresnelColor,h.fresnelColor),m.uniform1f(p.uFresnelOcc,h.fresnelOcc),m.uniform1f(p.uFresnelGlossMask,h.fresnelGlossMask),m.uniform1f(p.uFresnelIntegral,h.fresnelIntegral),m.uniform1f(p.uTransIntegral, 34190h.transIntegral),m.uniform1f(p.uSkinTransDepth,h.transDepth),m.uniform1f(p.uTransSky,h.transSky),m.uniform1f(p.uSkinShadowBlur,h.shadowBlur),m.uniform1f(p.uNormalSmooth,h.normalSmooth),(n=this.extrasTexCoordRanges.subdermisTex)&&m.uniform4fv(p.uTexRangeSubdermis,n),(n=this.extrasTexCoordRanges.translucencyTex)&&m.uniform4fv(p.uTexRangeTranslucency,n),(n=this.extrasTexCoordRanges.fuzzTex)&&m.uniform4fv(p.uTexRangeFuzz,n));l&&(m.uniform4fv(p.uFresnelColor,l.fresnelColor),m.uniform1f(p.uFresnelOcc,l.fresnelOcc), 34191m.uniform1f(p.uFresnelGlossMask,l.fresnelGlossMask),m.uniform1f(p.uFresnelIntegral,l.fresnelIntegral),(n=this.extrasTexCoordRanges.fuzzTex)&&m.uniform4fv(p.uTexRangeFuzz,n));k&&(m.uniform3fv(p.uAnisoTangent,k.tangent),m.uniform1f(p.uAnisoStrength,k.strength),m.uniform1f(p.uAnisoIntegral,k.integral),(n=this.extrasTexCoordRanges.anisoTex)&&m.uniform4fv(p.uTexRangeAniso,n));this.usesRefraction&&(a.refractionSurface&&a.refractionSurface.bind(s.tRefraction),d=Matrix.mul(Matrix.empty(),x,d.invMatrix),m.uniformMatrix4fv(p.uRefractionViewProjection, 34192!1,d),m.uniform1f(p.uRefractionRayDistance,this.refractionParams.distantBackgroun
34192d?1E10:4*b.mesh.bounds.maxExtent),m.uniform3fv(p.uRefractionTint,this.refractionParams.tint),m.uniform1f(p.uRefractionAlbedoTint,this.refractionParams.useAlbedoTint?1:0),m.uniform1f(p.uRefractionIOREntry,1/this.refractionParams.IOR),(n=this.extrasTexCoordRanges.refractionMaskTex)&&m.uniform4fv(p.uTexRangeRefraction,n));if(n=this.extrasTexCoordRanges.emissiveTex)m.uniform4fv(p.uTexRangeEmissive,n),m.uniform1f(p.uEmissiveScale, 34193this.emissiveIntensity);(n=this.extrasTexCoordRanges.aoTex)&&m.uniform4fv(p.uTexRangeAO,n);r.albedo.bind(s.tAlbedo);r.reflectivity.bind(s.tReflectivity);r.normal.bind(s.tNormal);r.extras.bind(s.tExtras);e.specularTexture.bind(s.tSkySpecular);g===this.stripShader&&(m.uniform1fv(p.uStrips,a.stripData.strips),m.uniform2f(p.uStripRes,2/c.size[0],2/c.size[1]));m.uniform2f(p.uUVOffset,this.uOffset,this.vOffset);return!0}; 34194Material.prototype.bindAlphaPrepass=function(a,b){if(!this.complete()||!this.prepassShader)return!1;var c=this.gl,d=this.prepassShader.params,e=this.prepassShader.samplers;this.prepassShader.bind();var f=Matrix.mul(Matrix.empty(),a.view.viewMatrix,b.mesh.displayMatrix),f=Matrix.mul(Matrix.empty(),a.view.projectionMatrix,f);c.uniformMatrix4fv(d.uModelViewProjectionMatrix,!1,f);c.uniform2f(d.uUVOffset,this.uOffset,this.vOffset);this.textures.albedo.bind(e.tAlbedo);return!0}; 34195Material.prototype.bindWire=function(a,b){if(!this.complete())return!1;var c=this.gl,d=this.wireShader.params,e=a.view;c.enable(c.BLEND);c.blendFunc(c.SRC_ALPHA,c.ONE_MINUS_SRC_ALPHA);c.depthMask(!1);this.wireShader.bind();var f=Matrix.mul(Matrix.empty(),a.view.viewMatrix,b.mesh.displayMatrix),f=Matrix.mul(Matrix.empty(),a.view.projectionMatrix,f);c.uniformMatrix4fv(d.uModelViewProjectionMatrix,!1,f);c.uniform4f(d.uStripParams,2/e.size[0],2/e.size[1],a.stripData.strips[3],a.stripData.strips[4]);return!0}; 34196Material.prototype.complete=function(){return this.wireShader.complete()&&this.shader.complete()&&this.stripShader.complete()&&(!this.prepassShader||this.prepassShader.complete())&&(!this.refractionShader||this.refractionShader.complete())&&this.textures.albedo.complete()&&this.textures.reflectivity.complete()&&this.textures.normal.complete()};var Matrix={type:Float32Array,create:function(a,b,c,d,e,f,g,h,k,l,n,m,p,r,s,u){var q=new Matrix.type(16);q[0]=a;q[4]=b;q[8]=c;q[12]=d;q[1]=e;q[5]=f;q[9]=g;q[13]=h;q[2]=k;q[6]=l;q[10]=n;q[14]=m;q[3]=p;q[7]=r;q[11]=s;q[15]=u;return q},empty:function(){return new Matrix.type(16)},identity:function(){var a=new Matrix.type(16);a[0]=1;a[4]=0;a[8]=0;a[12]=0;a[1]=0;a[5]=1;a[9]=0;a[13]=0;a[2]=0;a[6]=0;a[10]=1;a[14]=0;a[3]=0;a[7]=0;a[11]=0;a[15]=1;return a}
34196,set:function(a,b,c,d,e,f,g,h,k,l,n,m,p,r,s,u,q){a[0]= 34197b;a[4]=c;a[8]=d;a[12]=e;a[1]=f;a[5]=g;a[9]=h;a[13]=k;a[2]=l;a[6]=n;a[10]=m;a[14]=p;a[3]=r;a[7]=s;a[11]=u;a[15]=q},translation:function(a,b,c,d){Matrix.set(a,1,0,0,b,0,1,0,c,0,0,1,d,0,0,0,1);return a},rotation:function(a,b,c){a[0]=1;a[4]=0;a[8]=0;a[12]=0;a[1]=0;a[5]=1;a[9]=0;a[13]=0;a[2]=0;a[6]=0;a[10]=1;a[14]=0;a[3]=0;a[7]=0;a[11]=0;a[15]=1;var d=0.0174532925*b;b=Math.sin(d);d=Math.cos(d);switch(c){case 0:a[5]=d;a[9]=-b;a[6]=b;a[10]=d;break;case 1:a[0]=d;a[8]=b;a[2]=-b;a[10]=d;break;case 2:a[0]=d, 34198a[4]=-b,a[1]=b,a[5]=d}return a},mul:function(a,b,c){var d=b[0],e=b[1],f=b[2],g=b[3],h=b[4],k=b[5],l=b[6],n=b[7],m=b[8],p=b[9],r=b[10],s=b[11],u=b[12],q=b[13],x=b[14];b=b[15];var w=c[0],v=c[1],t=c[2],y=c[3];a[0]=w*d+v*h+t*m+y*u;a[1]=w*e+v*k+t*p+y*q;a[2]=w*f+v*l+t*r+y*x;a[3]=w*g+v*n+t*s+y*b;w=c[4];v=c[5];t=c[6];y=c[7];a[4]=w*d+v*h+t*m+y*u;a[5]=w*e+v*k+t*p+y*q;a[6]=w*f+v*l+t*r+y*x;a[7]=w*g+v*n+t*s+y*b;w=c[8];v=c[9];t=c[10];y=c[11];a[8]=w*d+v*h+t*m+y*u;a[9]=w*e+v*k+t*p+y*q;a[10]=w*f+v*l+t*r+y*x;a[11]= 34199w*g+v*n+t*s+y*b;w=c[12];v=c[13];t=c[14];y=c[15];a[12]=w*d+v*h+t*m+y*u;a[13]=w*e+v*k+t*p+y*q;a[14]=w*f+v*l+t*r+y*x;a[15]=w*g+v*n+t*s+y*b;return a},invert:function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],k=b[6],l=b[7],n=b[8],m=b[9],p=b[10],r=b[11],s=b[12],u=b[13],q=b[14],x=b[15],w=c*h-d*g,v=c*k-e*g,t=c*l-f*g,y=d*k-e*h,E=d*l-f*h,F=e*l-f*k,A=n*u-m*s,B=n*q-p*s,z=n*x-r*s,C=m*q-p*u,G=m*x-r*u,H=p*x-r*q,D=w*H-v*G+t*C+y*z-E*B+F*A;if(!D)return null;D=1/D;a[0]=(h*H-k*G+l*C)*D;a[1]=(e*G-d*H-f*C)*D; 34200a[2]=(u*F-q*E+x*y)*D;a[3]=(p*E-m*F-r*y)*D;a[4]=(k*z-g*H-l*B)*D;a[5]=(c*H-e*z+f*B)*D;a[6]=(q*t-s*F-x*v)*D;a[7]=(n*F-p*t+r*v)*D;a[8]=(g*G-h*z+l*A)*D;a[9]=(d*z-c*G-f*A)*D;a[10]=(s*E-u*t+x*w)*D;a[11]=(m*t-n*E-r*w)*D;a[12]=(h*B-g*C-k*A)*D;a[13]=(c*C-d*B+e*A)*D;a[14]=(u*v-s*y-q*w)*D;a[15]=(n*y-m*v+p*w)*D;return a},transpose:function(a,b){a[0]=b[0];a[4]=b[1];a[8]=b[2];a[12]=b[3];a[1]=b[4];a[5]=b[5];a[9]=b[6];a[13]=b[7];a[2]=b[8];a[6]=b[9];a[10]=b[10];a[14]=b[11];a[3]=b[12];a[7]=b[13];a[11]=b[14];a[15]=b[15]; 34201return a},mul4:function(a,b,c,d,e,f){a[0]=b[0]*c+b[4]*d+b[8]*e+b[12]*f;a[1]=b[1]*c+b[5]*d+b[9]*e+b[13]*f;a[2]=b[2]*c+b[6]*d+b[10]*e+b[14]*f;a[3]=b[3]*c+b[7]*d+b[11]*e+b[15]*f;return a},mulPoint:function(a,b,c,d,e){a[0]=b[0]*c+b[4]*d+b[8]*e+b[12];a[1]=b[1]*c+b[5]*d+b[9]*e+b[13];a[2]=b[2]*c+b[6]*d+b[10]*e+b[14];return a},mulVec:function(a,b,c,d,e){a[0]=b[0]*c+b[4]*d+b[8]*e;a[1]=b[1]*c+b[5]*d+b[9]*e;a[2]=b[2]*c+b[6]*d+b[10]*e;return a},perspective:function(a,b,c,d,e,f){f=f||0;b=1/Math.tan(0.00872664625* 34202b);a[0]=b/c;a[1]=a[2]=a[3]=0;a[5]=b;a[4]=a[6]=a[7]=0;a[8]=a[9]=0;a[10]=(e+d)/(d-e)-3.0518044E-5*f;a[11]=-1;a[14]=2*e*d/(d-e);a[12]=a[13]=a[15]=0;return a},perspectiveInfinite:function(a,b,c,d,e){e=e||0;b=1/Math.tan(0.00872664625*b);a[0]=b/c;a[1]=a[2]=a[3]=0;a[5]=b;a[4]=a[6]=a[7]=0;a[8]=a[9]=0;a[10]=a[11]=-1-3.0518044E-5*e;a[14]=-2*d;a[12]=a[13]=a[15]=0;return a},ortho:function(a,b,c,d,e,f,g,h){var k=1/(c-b),l=1/(e-d),n=1/(g-f);a[0]=k+k;a[1]=a[2]=a[3]=0;a[5]=l+l;a[4]=a[6]=a[7]=0;a[12]=-(c+b)*k;a[13]= 34203-(e+d)*l;a[10]=-(n+n)-3.0518044E-5*(h||0);a[14]=-(g+f)*n;a[8]=a[9]=a[11]=0;a[15]=1;return a},lookAt:function(a,b,c,d){var e=a.subarray(0,3),f=a.subarray(4,7),g=a.subarray(8,11);Vect.sub(g,b,c);Vect.cross(e,d,g);Vect.normalize(g,g);Vect.normalize(e,e);Vect.cross(f,g,e);Matrix.set(a,e[0],e[1],e[2],-Vect.dot(e,b),f[0],f[1],f[2],-Vect.dot(f,b),g[0],g[1],g[2],-Vect.dot(g,b),0,0,0,1)},copy:function(a,b){for(var c=0;16>c;++c)a[c]=b[c]},copyToBuffer:function(a,b,c){for(var d=0;16>d;++d)a[b+d]=c[d]}};function Mesh(a,b,c){this.gl=a;this.desc=b;var d=b.isDynamicMesh;this.numSubMeshes=this.dynamicVertexData=0;this.displayMatrix=Matrix.identity();this.name=b.name;this.modelMatrix=Matrix.identity();this.origin=b.transform?Vect.create(b.transform[12],b.transform[13],b.transform[14],1):Vect.create(0,5,0,1);this.stride=32;if(this.vertexColor=b.vertexColor)this.stride+=4;if(this.secondaryTexCoord=b.secondaryTexCoord)this.stride+=8;c=new ByteStream(c.data);this.indexCount=b.indexCount;this.indexTypeSize= 34204b.indexTypeSize;this.indexType=4==this.indexTypeSize?a.UNSIGNED_INT:a.UNSIGNED_SHORT;this.indexBuffer=a.createBuffer();a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer);var e=c.readBytes(this.indexCount*this.indexTypeSize);a.bufferData(a.ELEMENT_ARRAY_BUFFER,e,a.STATIC_DRAW);this.wireCount=b.wireCount;this.wireBuffer=a.createBuffer();a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.wireBuffer);e=c.readBytes(this.wireCount*this.indexTypeSize);a.bufferData(a.ELEMENT_ARRAY_BUFFER,e,a.STATIC_DRAW);a.bindBuffer(a.ELEMENT_ARRAY_BUFFER, 34205null);this.vertexCount=b.vertexCount;this.vertexBuffer=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffer);c=c.readBytes(this.vertexCount*this.stride);d?(this.dynamicVertexData=new Uint8Array(c),a.bufferData(a.ARRAY_BUFFER,c,a.DYNAMIC_DRAW)):a.bufferData(a.ARRAY_BUFFER,c,a.STATIC_DRAW);a.bindBuffer(a.ARRAY_BUFFER,null);this.bounds=void 0===b.minBound||void 0===b.maxBound?{min:Vect.create(-10,-10,-10,1),max:Vect.create(10,
3420510,-0,1)}:{min:Vect.create(b.minBound[0],b.minBound[1],b.minBound[2], 342061),max:Vect.create(b.maxBound[0],b.maxBound[1],b.maxBound[2],1)};this.bounds.maxExtent=Math.max(Math.max(b.maxBound[0]-b.minBound[0],b.maxBound[1]-b.minBound[1]),b.maxBound[2]-b.minBound[2]);this.bounds.averageExtent=(b.maxBound[0]-b.minBound[0]+(b.maxBound[1]-b.minBound[1])+(b.maxBound[2]-b.minBound[2]))/3};function MeshRenderable(a,b,c){this.mesh=a;this.gl=this.mesh.gl;this.indexOffset=b.firstIndex*a.indexTypeSize;this.indexCount=b.indexCount;this.wireIndexOffset=b.firstWireIndex*a.indexTypeSize;this.wireIndexCount=b.wireIndexCount;this.material=c;this.visible=!0} 34207MeshRenderable.prototype.draw=function(a){var b=this.gl;if(this.material.bind(a,this)){a=this.material.shader.attribs;var c=this.mesh.stride;this.mesh.desc.cullBackFaces?(b.enable(b.CULL_FACE),b.cullFace(b.BACK)):b.disable(b.CULL_FACE);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,this.mesh.indexBuffer);b.bindBuffer(b.ARRAY_BUFFER,this.mesh.vertexBuffer);b.enableVertexAttribArray(a.vPosition);b.enableVertexAttribArray(a.vTexCoord);b.enableVertexAttribArray(a.vTangent);b.enableVertexAttribArray(a.vBitangent); 34208b.enableVertexAttribArray(a.vNormal);var d=this.mesh.vertexColor&&void 0!==a.vColor;d&&b.enableVertexAttribArray(a.vColor);var e=this.mesh.secondaryTexCoord&&void 0!==a.vTexCoord2;e&&b.enableVertexAttribArray(a.vTexCoord2);var f=0;b.vertexAttribPointer(a.vPosition,3,b.FLOAT,!1,c,f);f+=12;b.vertexAttribPointer(a.vTexCoord,2,b.FLOAT,!1,c,f);f+=8;this.mesh.secondaryTexCoord&&(e&&b.vertexAttribPointer(a.vTexCoord2,2,b.FLOAT,!1,c,f),f+=8);b.vertexAttribPointer(a.vTangent,2,b.UNSIGNED_SHORT,!0,c,f);f+= 342094;b.vertexAttribPointer(a.vBitangent,2,b.UNSIGNED_SHORT,!0,c,f);f+=4;b.vertexAttribPointer(a.vNormal,2,b.UNSIGNED_SHORT,!0,c,f);d&&b.vertexAttribPointer(a.vColor,4,b.UNSIGNED_BYTE,!0,c,f+4);b.drawElements(b.TRIANGLES,this.indexCount,this.mesh.indexType,this.indexOffset);b.disableVertexAttribArray(a.vPosition);b.disableVertexAttribArray(a.vTexCoord);b.disableVertexAttribArray(a.vTangent);b.disableVertexAttribArray(a.vBitangent);b.disableVertexAttribArray(a.vNormal);d&&b.disableVertexAttribArray(a.vColor); 34210e&&b.disableVertexAttribArray(a.vTexCoord2)}};MeshRenderable.prototype.drawShadow=function(a){var b=this.gl;this.mesh.desc.cullBackFaces?(b.enable(b.CULL_FACE),b.cullFace(b.BACK)):b.disable(b.CULL_FACE);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,this.mesh.indexBuffer);b.bindBuffer(b.ARRAY_BUFFER,this.mesh.vertexBuffer);b.enableVertexAttribArray(a);b.vertexAttribPointer(a,3,b.FLOAT,!1,this.mesh.stride,0);b.drawElements(b.TRIANGLES,this.indexCount,this.mesh.indexType,this.indexOffset);b.disableVertexAttribArray(a)}; 34211MeshRenderable.prototype.drawAlphaShadow=function(a,b){var c=this.gl;this.mesh.desc.cullBackFaces?(c.enable(c.CULL_FACE),c.cullFace(c.BACK)):c.disable(c.CULL_FACE);c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,this.mesh.indexBuffer);c.bindBuffer(c.ARRAY_BUFFER,this.mesh.vertexBuffer);c.enableVertexAttribArray(a);c.enableVertexAttribArray(b);c.vertexAttribPointer(a,3,c.FLOAT,!1,this.mesh.stride,0);c.vertexAttribPointer(b,2,c.FLOAT,!1,this.mesh.stride,12);c.drawElements(c.TRIANGLES,this.indexCount,this.mesh.indexType, 34212this.indexOffset);c.disableVertexAttribArray(a);c.disableVertexAttribArray(b)}; 34213MeshRenderable.prototype.drawAlphaPrepass=function(a){var b=this.gl;if(this.material.bindAlphaPrepass(a,this)){a=this.material.prepassShader.attribs;var c=this.mesh.stride;this.mesh.desc.cullBackFaces?(b.enable(b.CULL_FACE),b.cullFace(b.BACK)):b.disable(b.CULL_FACE);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,this.mesh.indexBuffer);b.bindBuffer(b.ARRAY_BUFFER,this.mesh.vertexBuffer);b.enableVertexAttribArray(a.vPosition);b.enableVertexAttribArray(a.vTexCoord);b.vertexAttribPointer(a.vPosition,3,b.FLOAT,!1, 34214c,0);b.vertexAttribPointer(a.vTexCoord,2,b.FLOAT,!1,c,12);b.drawElements(b.TRIANGLES,this.indexCount,this.mesh.indexType,this.indexOffset);b.disableVertexAttribArray(a.vPosition);b.disableVertexAttribArray(a.vTexCoord)}}; 34215MeshRenderable.prototype.drawWire=function(a){var b=this.material.wireShader.attribs,c=this.gl;this.material.bindWire(a,this)&&(c.enableVertexAttribArray(b.vPosition),c.bindBuffer(c.ELEMENT_ARRAY_BUFFER,this.mesh.wireBuffer),c.bindBuffer(c.ARRAY_BUFFER,this.mesh.vertexBuffer),c.vertexAttribPointer(b.vPosition,3,c.FLOAT,!1,this.mesh.stride,0),c.drawElements(c.LINES,this.wireIndexCount,this.mesh.indexType,this.wireIndexOffset),c.disableVertexAttribArray(b.vPosition))}; 34216MeshRenderable.prototype.complete=function(){return this.material.complete()};var Network={fetchImage:function(a,b,c){var d=new Image;d.crossOrigin="Anonymous";d.onload=function(){0<d.width&&0<d.height?b(d):c&&c()};c&&(req.onerror=function(){c()});d.src=a},fetchText:function(a,b,c,d){var e=new XMLHttpRequest;e.open("GET",a,!0);e.onload=function(){200==e.status?b(e.responseText):c&&c()};c&&(e.onerror=function(){c()});d&&(e.onprogress=function(a){d(a.loaded,a.total)});e.send()},fetchBinary:function(a,b,c,d){var e=new XMLHttpRequest;e.open("GET",a,!0);e.responseType="arraybuffer"; 34217e.onload=function(){200==e.status?b(e.response):c&&c()};c&&(e.onerror=function(){c()});d&&(e.onprogress=function(a){d(a.loaded,a.total)});e.send()},fetchBinaryIncremental:function(a,b,c,d){var e=new XMLHttpRequest;e.open("HEAD",a,!0);e.onload=function(){if(200==e.status){var f=e.getResponseHeader("Accept-Ranges");if(f&&"none"!=f){var g=e.getResponseHeader("Content-Length")|0,h=function(c,e){var f=new XMLHttpRequest;f.open("GET",a,!0);f.setRequestHeader("Range","bytes="+c+"-"+e);f.responseType="arraybuffer"; 34218f.onload=function(){(206==f.status||200==f.status)&&b(f.response)&&e<g&&(c+=d,e+=d,e=e<g-1?e:g-1,h(c,e))};f.send()};h(0,d-1)}else c&&c()}else c&&c()};c&&(e.onerror=function(){c()});e.send()}};function PlaybackControls(a){this.debugString="";this.init=!1;this.speedList=this.cameraList=this.animationList=this.playButton=this.timelineSlider=this.playbackRegion=this.previousFrameButton=this.nextFrameButton=this.pauseButton=this.playButton=0;this.visible=!1;this.backgroundRegion=this.screenButton=0;this.guiScreen=a;this.playbackRegion=new GUIRegion(a);this.idealSliderWidth=650;this.totalListBoxPixelsX=0;this.minWidth=500;this.compactMode=!1;this.ui=a.ui;
34218var b="animationpause"+a.imageSetNumber+ 34219"x.png",c="animationplay"+a.imageSetNumber+"x.png",d="timelineLE"+a.imageSetNumber+"x.png",e="timelineM"+a.imageSetNumber+"x.png",f="timelineRE"+a.imageSetNumber+"x.png",g=a.ui.viewer.scene.sceneAnimator.animations.length;if(0!=g){var h=this.idealSliderWidth;this.bottomOffset=85;this.centerOffset=60;var k=a.width/2+this.centerOffset,l=k-h/2,k=k+h/2,n=l-14-32,m=k-n,p=32/a.height,r=this.bottomOffset/a.height,s=this.playbackRegion;s.controlRect.widthPercent=m/a.width;s.controlRect.heightPercent=p;s.controlRect.xPercent= 34220n/a.width;s.controlRect.yPercent=r;p=32/m;this.pauseButton=new Button(this.guiScreen);this.pauseButton.controlRect.set(0,0.125,p,0.75);this.pauseButton.controlRect.opacity=0.5;s.controlRect.registerChildControlRect(this.pauseButton.controlRect);this.pauseButton.linkControl(s.addImageElement(this.pauseButton.controlRect,b));this.playButton=new Button(this.guiScreen);this.playButton.controlRect.set(0,0.125,p,0.75);this.playButton.controlRect.opacity=0.5;s.controlRect.registerChildControlRect(this.playButton.controlRect); 34221this.playButton.linkControl(s.addImageElement(this.playButton.controlRect,c));b=h/m;m=(l-n)/m;this.timelineSlider=new TimelineSlider(this.guiScreen,s);this.timelineSlider.controlRect.set(m,0.03125,b,1);s.controlRect.registerChildControlRect(this.timelineSlider.controlRect);this.timelineSlider.setBackground3x1(s,d,e,f);this.pauseButton.controlRect.showControl(!a.ui.viewer.scene.sceneAnimator.paused);this.playButton.controlRect.showControl(a.ui.viewer.scene.sceneAnimator.paused);d=k+14;e=this.bottomOffset+ 342224;f=a.ui.viewer.scene.sceneAnimator.animations[0].cameraObjects.length;a.ui.viewer.scene.sceneAnimator.selectDefaultCamera();a.ui.viewer.scene.sceneAnimator.setViewFromSelectedCamera();this.maxListPixelsX=0;if(1<f){this.cameraList=new ListBox(a);for(m=0;m<f;m++)this.cameraList.addItem(a.ui.viewer.scene.sceneAnimator.animations[0].cameraObjects[m].name,0,0);this.cameraList.spawnControl(d,e,10,24,!0,8);this.cameraList.selectItem(a.ui.viewer.scene.sceneAnimator.selectedCameraIndex);this.maxListPixelsX= 34223this.cameraList.localPixelsX;this.totalListBoxPixelsX+=this.cameraList.localPixelsX+14}if(1<g){this.animationList=new ListBox(a);for(m=0;m<g;m++)this.animationList.addItem(a.ui.viewer.scene.sceneAnimator.animations[m].name,0,0);this.animationList.spawnControl(d,e,10,24,!0,8);this.maxListPixelsX<this.animationList.localPixelsX&&(this.maxListPixelsX=this.animationList.localPixelsX);this.totalListBoxPixelsX+=this.animationList.localPixelsX+14;this.animationList.selectItem(a.ui.viewer.scene.sceneAnimator.selectedAnimationIndex)}d= 34224n-44-14;m=k-d+this.totalListBoxPixelsX;this.speedList=new ListBox(a);this.speedList.addItem("4.0x",4,0);this.speedList.addItem("2.0x",4,0);this.speedList.addItem("1.0x",4,0);this.speedList.addItem("0.5x",4,0);this.speedList.addItem("0.25x",-2,0);this.speedList.spawnControl(d,e,44,24,!1,0);this.speedList.selectItem(2);m>a.width&&(this.idealSliderWidth=a.width-(118+(this.totalListBoxPixelsX+14))-this.centerOffset,a=0,this.cameraList&&a++,this.animationList&&a++,1==a&&(this.idealSliderWidth+=56,this.centerOffset-= 3422514),2==a&&(this.idealSliderWidth+=63,this.centerOffset-=63));this.setupCallbacks()}} 34226PlaybackControls.prototype.resize=function(a){a.ui.viewer.scene.sceneAnimator.showPlayControls||(a.width=1,a.height=1);this.compactMode=a.width<this.minWidth;var b=this.bottomOffset,c=this.bottomOffset+4,d=0;this.cameraList&&this.animationList?d+=42+this.cameraList.localPixelsX+this.animationList.localPixelsX:this.cameraList?d+=28+this.cameraList.localPixelsX:this.animationList&&(d+=28+this.animationList.localPixelsX);var e=a.width-d-72;0==d&&(e-=14);var f=116,g=f+e+14;this.compactMode&&(f=58,e+= 3422744+d,0<d&&(b+=32),!d&&(c+=32));var d=32/e,h=d+14/e,k=1-h,l=this.playbackRegion;l.controlRect.widthPercent=e/a.width;l.controlRect.heightPercent=32/a.height;l.controlRect.xPercent=f/a.width;l.controlRect.yPercent=b/a.height;this.pauseButton.controlRect.set(0,0.125,d,0.75);this.playButton.controlRect.set(0,0.125,d,0.75);this.timelineSlider.controlRect.set(h,0.03125,k,1);this.timelineSlider.setSize(e-46,32);l.controlRect.updateElement();l.controlRect.updateChildElements();this.speedList.setControl(58, 34228c,44,24,!1);this.cameraList&&(this.cameraList.setControl(g,c,10,24,!0,8),g+=this.cameraList.localPixelsX+14);this.animationList&&this.animationList.setControl(g,c,10,24,!0,8);
34228this.timelineSlider.backgroundControl.alignBackground()}; 34229PlaybackControls.prototype.setupCallbacks=function(){var a=function(a){"0.01x"==this.speedList.selectedItemText&&this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(0.01);"0.05x"==this.speedList.selectedItemText&&this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(0.05);"0.25x"==this.speedList.selectedItemText&&this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(0.25);"0.5x"==this.speedList.selectedItemText&&this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(0.5);"1.0x"==this.speedList.selectedItemText&& 34230this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(1);"2.0x"==this.speedList.selectedItemText&&this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(2);"4.0x"==this.speedList.selectedItemText&&this.ui.viewer.scene.sceneAnimator.setPlaybackSpeed(4)}.bind(this),b=function(a){this.ui.viewer.scene.sceneAnimator.selectCamera(this.cameraList.selectedIndex);this.ui.viewer.wake()}.bind(this),c=function(a){this.ui.viewer.scene.sceneAnimator.selectAnimation(this.animationList.selectedIndex);this.ui.viewer.wake()}.bind(this); 34231this.speedList&&(this.speedList.selectionChangedCallback=a);this.cameraList&&(this.cameraList.selectionChangedCallback=b);this.animationList&&(this.animationList.selectionChangedCallback=c);this.playButton.controlRect.linkedControl.onclick=function(){this.ui.viewer.scene.sceneAnimator.pause(!1);this.playButton.controlRect.showControl(!1);this.pauseButton.controlRect.showControl(!0);this.ui.viewer.wake()}.bind(this);this.pauseButton.controlRect.linkedControl.onclick=function(){this.ui.viewer.scene.sceneAnimator.pause(!0); 34232this.playButton.controlRect.showControl(!0);this.pauseButton.controlRect.showControl(!1)}.bind(this)};function PostRender(a,b,c){this.gl=a;this.desc=b;b=[];0!=this.desc.sharpen&&b.push("#define SHARPEN");(this.useBloom=0<this.desc.bloomColor[0]*this.desc.bloomColor[3]||0<this.desc.bloomColor[1]*this.desc.bloomColor[3]||0<this.desc.bloomColor[2]*this.desc.bloomColor[3])&&b.push("#define BLOOM");0!=this.desc.vignette[3]&&b.push("#define VIGNETTE");1==this.desc.saturation[0]*this.desc.saturation[3]&&1==this.desc.saturation[1]*this.desc.saturation[3]&&1==this.desc.saturation[2]*this.desc.saturation[3]|| 34233b.push("#define SATURATION");1==this.desc.contrast[0]*this.desc.contrast[3]&&1==this.desc.contrast[1]*this.desc.contrast[3]&&1==this.desc.contrast[2]*this.desc.contrast[3]&&1==this.desc.brightness[0]*this.desc.brightness[3]&&1==this.desc.brightness[1]*this.desc.brightness[3]&&1==this.desc.brightness[2]*this.desc.brightness[3]||b.push("#define CONTRAST");0!=this.desc.grain&&b.push("#define GRAIN");1==this.desc.toneMap?b.push("#define REINHARD"):2==this.desc.toneMap&&b.push("#define HEJL");this.desc.colorLUT&& 34234b.push("#define COLOR_LUT");this.sampleIndex=0;this.sampleCount=1;c&&(this.sampleCount=4,this.sampleOffsets=[[-0.5,-0.5],[0.5,-0.5],[-0.5,0.5],[0.5,0.5]]);this.aaShader=a.shaderCache.fromURLs("postvert.glsl","postaa.glsl");this.shader=a.shaderCache.fromURLs("postvert.glsl","postfrag.glsl",b);this.plainShader=a.shaderCache.fromURLs("postvert.glsl","postfrag.glsl",[]);this.fullscreenTriangle=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,this.fullscreenTriangle);c=new Float32Array([0,0,2,0,0,2]);a.bufferData(a.ARRAY_BUFFER, 34235c,a.STATIC_DRAW);a.bindBuffer(a.ARRAY_BUFFER,null);if(this.useBloom){this.bloomTextures=[];this.bloomTargets=[];for(c=0;2>c;++c)b={width:256,height:256,clamp:!0},this.bloomTextures[c]=new Texture(a,b),this.bloomTextures[c].loadArray(null,a.RGBA,a.ext.textureHalf&&a.ext.textureHalfLinear?a.ext.textureHalf.HALF_FLOAT_OES:a.UNSIGNED_BYTE),this.bloomTargets[c]=new Framebuffer(a,{width:b.width,height:b.height,color0:this.bloomTextures[c]});for(this.bloomSamples=64;this.bloomSamples+16>=a.limits.fragmentUniforms;)this.bloomSamples/= 342362;this.bloomShader=a.shaderCache.fromURLs("postvert.glsl","bloom.glsl",["#define BLOOM_SAMPLES "+this.bloomSamples]);this.shrinkShader=a.shaderCache.fromURLs("postvert.glsl","bloomshrink.glsl")}a=new Uint8Array(16384);for(c=0;16384>c;c++){b=255*Math.random();var d=255*Math.random();a[c]=0.5*(b+d)}this.noiseTexture=new Texture(this.gl,{width:128,height:128});this.noiseTexture.loadArray(a,this.gl.LUMINANCE);this.desc.colorLUT&&(a=this.desc.colorLUT,this.colorLUT=new Texture(this.gl,{width:a.length/ 342373|0,height:1,clamp:!0}),this.colorLUT.loadArray(new Uint8Array(a),this.gl.RGB));this.blackTexture=new Texture(this.gl,{width:1,height:1});this.blackTexture.loadArray(new Uint8Array([0,0,0,0]));this.bloomResult=this.blackTexture}
34238PostRender.prototype.prepareBloom=function(a){if(this.useBloom&&this.bloomShader.complete()&&this.shrinkShader.complete()){this.shrinkShader.bind();this.bloomTargets[1].bind();a.bind(this.shrinkShader.samplers.tInput);this.fillScreen(this.shrinkShader.attribs.vCoord);this.bloomShader.bind();var b=[];this.bloomTargets[0].bind();this.bloomTextures[1].bind(this.bloomShader.samplers.tInput);for(var c=0,d=0;d<this.bloomSamples;++d){var e=-1+2*d/(this.bloomSamples-1),f;f=4*e;f=Math.exp(-0.5*f*f/1)/2.50662827463; 34239c+=f;b[4*d+0]=e*this.desc.bloomSize;b[4*d+1]=0;b[4*d+2]=f;b[4*d+3]=0}for(d=0;d<this.bloomSamples;++d)b[4*d+2]/=c;this.gl.uniform4fv(this.bloomShader.params.uKernel,b);this.fillScreen(this.bloomShader.attribs.vCoord);this.bloomTargets[1].bind();this.bloomTextures[0].bind(this.bloomShader.samplers.tInput);for(d=0;d<this.bloomSamples;++d)c=b[4*d+0],c*=a.desc.width/a.desc.height,b[4*d+0]=0,b[4*d+1]=c;this.gl.uniform4fv(this.bloomShader.params.uKernel,b);this.fillScreen(this.bloomShader.attribs.vCoord); 34240this.bloomResult=this.bloomTextures[1]}else this.bloomResult=this.blackTexture}; 34241PostRender.prototype.computeParams=function(a,b){var c=this.desc,d={};d.scale=[c.contrast[0]*c.contrast[3],c.contrast[1]*c.contrast[3],c.contrast[2]*c.contrast[3]];d.bias=[c.bias[0]*c.bias[3],c.bias[1]*c.bias[3],c.bias[2]*c.bias[3]];d.bias=[-d.bias[0]*d.scale[0]+d.bias[0],-d.bias[1]*d.scale[1]+d.bias[1],-d.bias[2]*d.scale[2]+d.bias[2]];var e=[c.brightness[0]*c.brightness[3],c.brightness[1]*c.brightness[3],c.brightness[2]*c.brightness[3]];d.scale=[d.scale[0]*e[0],d.scale[1]*e[1],d.scale[2]*e[2]];d.bias= 34242[d.bias[0]*e[0],d.bias[1]*e[1],d.bias[2]*e[2]];d.saturation=[c.saturation[0]*c.saturation[3],c.saturation[1]*c.saturation[3],c.saturation[2]*c.saturation[3]];d.bloomColor=[c.bloomColor[0]*c.bloomColor[3],c.bloomColor[1]*c.bloomColor[3],c.bloomColor[2]*c.bloomColor[3]];d.sharpen=[c.sharpen,0.25*c.sharpen,c.sharpenLimit];d.sharpenKernel=[1/a,0,0,1/b];e=a>b?a:b;d.vignetteAspect=[a/e,b/e,0.5*a/e,0.5*b/e];d.vignette=[2*(1-c.vignette[0])*c.vignette[3],2*(1-c.vignette[1])*c.vignette[3],2*(1-c.vignette[2])* 34243c.vignette[3],c.vignetteCurve];var e=1/this.noiseTexture.desc.width,f=1/this.noiseTexture.desc.height,g=1-c.grainSharpness;d.grainCoord=[e*a,f*b,0.5*g*e,0.5*g*f];d.grainScaleBias=[2*c.grain,-c.grain];return d}; 34244PostRender.prototype.present=function(a,b,c,d){d||this.prepareBloom(a);1<this.sampleCount&&this.allocAABuffer(b,c);d=d?this.plainShader:this.shader;if(d.bind()){var e=this.gl,f=d.samplers,g=d.params,h=this.computeParams(b,c);a.bind(f.tInput);this.bloomResult.bind(f.tBloom);this.noiseTexture.bind(f.tGrain);this.colorLUT&&this.colorLUT.bind(f.tLUT);e.uniform3fv(g.uScale,h.scale);e.uniform3fv(g.uBias,h.bias);e.uniform3fv(g.uSaturation,h.saturation);e.uniform4fv(g.uSharpenKernel,h.sharpenKernel);e.uniform3fv(g.uSharpness, 34245h.sharpen);e.uniform3fv(g.uBloomColor,h.bloomColor);e.uniform4fv(g.uVignetteAspect,h.vignetteAspect);e.uniform4fv(g.uVignette,h.vignette);e.uniform4fv(g.uGrainCoord,h.grainCoord);e.uniform2fv(g.uGrainScaleBias,h.grainScaleBias);if(a=1<this.sampleCount&&0<=this.sampleIndex){var k=1/(1+this.sampleIndex);this.sampleIndex+=1;1>k&&(e.enable(e.BLEND),e.blendColor(k,k,k,k),e.blendFunc(e.CONSTANT_ALPHA,e.ONE_MINUS_CONSTANT_ALPHA));this.aaTarget.bind()}else Framebuffer.bindNone(e),1<this.sampleCount&&(this.sampleIndex+= 342461);e.viewport(0,0,b,c);this.fillScreen(d.attribs.vCoord);a&&(1>k&&e.disable(e.BLEND),Framebuffer.bindNone(e),this.aaShader.bind(),this.aaBuffer.bind(this.aaShader.samplers.tInput),this.fillScreen(this.aaShader.attribs.vCoord))}}; 34247PostRender.prototype.allocAABuffer=function(a,b){this.aaBuffer&&this.aaBuffer.desc.width==a&&this.aaBuffer.desc.height==b||(this.aaBuffer&&this.aaBuffer.destroy(),this.aaBuffer=new Texture(this.gl,{width:a,height:b,clamp:!0}),this.aaBuffer.loadArray(),this.aaTarget=new Framebuffer(this.gl,{color0:this.aaBuffer,ignoreStatus:!0}))}; 34248PostRender.prototype.adjustProjectionForSupersampling=function(a){if(1<this.sampleCount){var b=this.currentSample(),c=this.sampleOffsets[b][0]/a.size[0],b=this.sampleOffsets[b][1]/a.size[1],c=Matrix.translation(Matrix.empty(),c,b,0);Matrix.mul(a.projectionMatrix,c,a.projectionMatrix)}};PostRender.prototype.discardAAHistory=function(){this.sampleIndex=-1};PostRender.prototype.currentSample=function(){return(0>this.sampleIndex?0:this.sampleIndex)%this.sampleCount}; 34249PostRender.prototype.fillScreen=function(a){var b=this.gl;b.bindBuffer(b.ARRAY_BUFFER,this.fullscreenTriangle);b.enableVertexAttribArray(a);b.vertexAttribPointer(a,2,b.FLOAT,!1,0,0);b.drawArrays(b.TRIANGLES,0,3);b.disableVertexAttribArray(a);b.bindBuffer(b.ARRAY_BUFFER,null)};PostRender.prototype.blitTexture=function(a){this.aaShader.bind();
34249a.bind(this.aaShader.samplers.tInput);this.fillScreen(this.aaShader.attribs.vCoord)};function Scene(a){this.gl=a;this.name="untitled";this.meshes=[];this.meshRenderables=[];this.materials={};this.sky=this.view=null;this.selectedPartIndex=0;this.soloPart=!1;this.miscnotes="";this.nextView=null;this.viewFade=0;this.refractionSurface=this.shadow=this.stripData=this.lights=null;this.sceneAnimator=this.frameCounter=0;this.sceneLoaded=!1;this.debugString=""} 34250Scene.prototype.load=function(a){var b=this.gl,c,d=a.extract("scene.json");if(void 0!==d){if(!a.checkSignature(d))return!1;d=(new ByteStream(d.data)).asString();if(null==d||0>=d.length)return!1;try{c=JSON.parse(d)}catch(e){return console.error(e),!1}}else return!1;this.metaData=c.metaData;this.view=new View(c.mainCamera.view);this.sky=new Sky(this.gl,a,c.sky);this.lights=new Lights(c.lights,this.view);this.materialsList=[];this.materials={};for(var f in c.materials){var g=c.materials[f];g.lightCount= 34251this.lights.count;g.shadowCount=this.lights.shadowCount;d=new Material(this.gl,a,g);this.materials[g.name]=d;this.materialsList.push(d)}if(c.meshes)for(g=0;g<c.meshes.length;++g){f=c.meshes[g];f=new Mesh(this.gl,f,a.extract(f.file));this.meshes.push(f);for(var h=0;h<f.desc.subMeshes.length;++h){var k=f.desc.subMeshes[h];if(d=this.materials[k.material])f.numSubMeshes++,this.meshRenderables.push(new MeshRenderable(f,k,d))}}this.bounds=new Bounds(this.meshes);this.postRender=new PostRender(this.gl,c.mainCamera.post, 34252!0);this.shadow=new ShadowCollector(b,this.lights.shadowCount);this.cameras=c.Cameras;c.AnimData&&(this.sceneAnimator=new SceneAnimator(this,a,c.AnimData));c.fog&&(this.fog=new Fog(b,c.fog));c.shadowFloor&&(this.shadowFloor=new ShadowFloor(b,c.shadowFloor,this.shadow,this.lights));return this.sceneLoaded=!0}; 34253Scene.prototype.update=function(){this.sceneAnimator&&(this.frameCounter++,this.lights.flagUpdateAnimatedLighting(),this.sceneAnimator.drawAnimated&&(1==this.frameCounter?this.sceneAnimator.resetPlayback():this.sceneAnimator.updateAnimationPlayback()));this.lights.update(this.view,this.bounds)};Scene.prototype.collectShadows=function(a){this.shadow.collect(this,a)}; 34254Scene.prototype.draw=function(a){var b=this.gl;if(this.sceneLoaded){this.sky.setClearColor();b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT);b.enable(b.DEPTH_TEST);this.sky.draw(this);this.shadowFloor&&this.shadowFloor.draw(this);for(var c=0;c<this.meshRenderables.length;++c)this.meshRenderables[c].material.usesBlending||this.meshRenderables[c].material.usesRefraction||!this.meshRenderables[c].visible||this.meshRenderables[c].draw(this);b.enable(b.POLYGON_OFFSET_FILL);b.polygonOffset(1, 342551);b.colorMask(!1,!1,!1,!1);for(c=0;c<this.meshRenderables.length;++c)this.meshRenderables[c].drawAlphaPrepass(this);b.colorMask(!0,!0,!0,!0);b.disable(b.POLYGON_OFFSET_FILL);b.depthFunc(b.LEQUAL);b.depthMask(!1);for(c=0;c<this.meshRenderables.length;++c)this.meshRenderables[c].material.usesBlending&&this.meshRenderables[c].visible&&this.meshRenderables[c].draw(this);b.disable(b.BLEND);b.depthMask(!0);b.depthFunc(b.LESS);for(var d=!1,c=0;c<this.meshRenderables.length;++c)if(this.meshRenderables[c].material.usesRefraction){d= 34256!0;break}if(d)for(this.refractionSurface&&this.refractionSurface.desc.width==a.color0.desc.width&&this.refractionSurface.desc.height==a.color0.desc.height||(this.refractionSurface=new Texture(b,a.color0.desc),this.refractionSurface.loadArray(null,a.color0.format,a.color0.componentType),this.refractionBuffer=new Framebuffer(this.gl,{color0:this.refractionSurface})),this.refractionBuffer.bind(),this.postRender.blitTexture(a.color0),a.bind(),c=0;c<this.meshRenderables.length;++c)this.meshRenderables[c].material.usesRefraction&& 34257this.meshRenderables[c].visible&&this.meshRenderables[c].draw(this);if(this.stripData.activeWireframe()&&0<this.meshRenderables.length){for(c=0;c<this.meshRenderables.length;++c)this.meshRenderables[c].visible&&this.meshRenderables[c].drawWire(this);b.depthMask(!0)}b.disable(b.BLEND)}};
34257Scene.prototype.drawSecondary=function(a){this.fog&&this.fog.draw(this,a)}; 34258Scene.prototype.complete=function(){if(!this.sky.complete()||!this.shadow.complete()||this.fog&&!this.fog.complete()||this.shadowFloor&&!this.shadowFloor.complete())return!1;for(var a=0;a<this.meshRenderables.length;++a)if(!this.meshRenderables[a].complete())return!1;return!0};function SceneAnimator(a,b,c){this.scene=a;this.animations=[];this.skinningRigs=[];this.meshIDs=[];this.lightIDs=[];this.materialIDs=[];this.views=[];this.viewYawOffsets=[];this.viewPitchOffsets=[];this.cameraObjectIndices=[];this.cameraChildrenIndices=[];this.subMeshObjectIndices=[];this.subMeshLiveIndices=[];this.scene=a;this.selectedCameraIndex=-1;this.selectedAnimationIndex=0;this.debugString="";this.scenePlaybackSpeed=this.playbackSpeed=1;this.animationProgress=this.totalSeconds=0;this.paused= 34259this.autoAdvanceNextAnimation=!1;this.animateVisibility=this.drawAnimated=this.linkSceneObjects=this.loadSkinningRigs=this.animateMaterials=this.animateTurntables=this.enableSkinning=this.animateMeshes=this.animateLights=this.playAnimations=this.loadAnimations=!0;this.showDebugInfo=!1;this.loopCount=0;this.loopTurntables=this.lockPlayback=!1;this.fogObjectIndex=-1;this.unitScaleSkinnedMeshes=!0;this.sceneScale=c.sceneScale;this.defaultCameraGlobalIndex=c.selectedCamera;this.selectedAnimationIndex= 34260c.selectedAnimation;this.autoPlayAnims=c.autoPlayAnims;this.showPlayControls=c.showPlayControls;c.scenePlaybackSpeed&&(this.scenePlaybackSpeed=c.scenePlaybackSpeed,0==this.scenePlaybackSpeed&&(this.scenePlaybackSpeed=1));this.autoPlayAnims||(this.paused=!0);if(this.loadAnimations){if(c.meshIDs)for(var d=c.meshIDs.length,e=0;e<d;++e){var f=c.meshIDs[e].partIndex;this.meshIDs.push(f)}if(c.lightIDs)for(d=c.lightIDs.length,e=0;e<d;++e)f=c.lightIDs[e],f=f.partIndex,this.lightIDs.push(f);if(c.materialIDs)for(d= 34261c.materialIDs.length,e=0;e<d;++e)f=c.materialIDs[e],f=f.partIndex,this.materialIDs.push(f);this.numMatricesInTable=c.numMatrices;e=b.get("MatTable.bin");f=new ByteStream(e.data);e||(this.numMatricesInTable=0,this.debugString+="<br>No mattable?");if(c.skinningRigs&&this.loadSkinningRigs)for(d=c.skinningRigs.length,e=0;e<d;++e){var g=new SkinningRig(b,c.skinningRigs[e],f);""==g.debugString?this.skinningRigs.push(g):(this.debugString+="<br>Error loading skinning rig "+e+" :"+g.debugString,this.debugString+= 34262"<br>Skipping the rest",e=d)}if(c.animations)for(f=c.animations.length,e=0;e<f;++e)d=new Animation(b,c.animations[e]),this.animations.push(d);this.startMS=Date.now();f=this.animations.length;if(this.linkSceneObjects&&0!=f){for(e=0;e<f;e++)for(b=this.animations[e],d=b.animatedObjects.length,c=0;c<d;c++)g=b.animatedObjects[c],"LightSO"==g.sceneObjectType&&(g.lightIndex=this.findLightIndexByPartIndex(c),-1!=g.lightIndex?b.lightObjects.push(g):this.debugString+="<br> got light not in scene "+g.name), 34263"FogSO"==g.sceneObjectType&&(this.fogObjectIndex=c),"SubMeshSO"==g.sceneObjectType&&0==e&&(this.subMeshObjectIndices.push(c),this.subMeshLiveIndices.push(-1)),"Material"==g.sceneObjectType&&(g.materialIndex=this.findMaterialIndexByPartIndex(c),-1==g.materialIndex?this.debugString+="<br> can't find material index for object "+c:b.materialObjects.push(g)),"TurnTableSO"==g.sceneObjectType&&b.turnTableObjects.push(g),"MeshSO"==g.sceneObjectType&&(g.meshIndex=this.findMeshIndexByPartIndex(this.scene.meshes, 34264c),-1==g.meshIndex?(this.debugString+="<br> can't find mesh index for object "+c,this.logObjectInfo(c,0)):(b.meshObjects.push(g),g.mesh=this.scene.meshes[g.meshIndex],-1!=g.skinningRigIndex&&g.mesh&&g.skinningRigIndex<this.skinningRigs.length&&(g.skinningRig=this.skinningRigs[g.skinningRigIndex],g.skinningRig.isRigidSkin||(g.mesh.dynamicVertexData?g.skinningRig.useOriginalMeshVertices(g.mesh):(this.debugString+="Skinning object - but mesh is not dynamic",this.debugString+="<br>Rig index "+g.skinningRigIndex, 34265this.debugString+=" not tagged as rigid"))))),"CameraSO"==g.sceneObjectType&&b.cameraObjects.push(g);b=this.animations[0];c=b.cameraObjects.length;for(e=0;e<c;e++)if(f=b.cameraObjects[e],d=this.scene.cameras[f.name]){if(d=d.view)d=new View(d),this.cameraObjectIndices.push(f.id),this.views.push(d),this.viewYawOffsets.push(0),this.viewPitchOffsets.push(0)}else this.debugString+="<br>no camDesc for "+f.name,this.views.push(a.view);a=this.scene.meshes.length;f=this.subMeshObjectIndices.length;for(e=d= 342660;e<a;e++)for(g=this.scene.meshes[e],c=0;c<f;c++){var h=this.subMeshObjectIndices[c],k=b.animatedObjects[h],l=b.animatedObjects[k.parentIndex];l.mesh||(this.debugString+="<br>submesh parent object has no mesh?",this.debugString+="<br>obj.name "+k.name,this.debugString+="<br>parent.name "+l.name,this.debugString+="<br>submesh index "+c,this.debugString+="<br>obj.index "+h);if(l.mesh==g){for(h=0;h<g.numSubMeshes;
34266h++)this.subMeshLiveIndices[c+(g.numSubMeshes-1-h)]=d,d++;c=f}}for(e=0;e<f;e++)-1==this.subMeshLiveIndices[e]&& 34267(this.debugString+="<br>Missing mesh? Unused submesh "+e+" of "+f);this.showDebugInfo=this.stopEverything=this.runDebugMode=!1;this.selectDefaultCamera();this.findCameraChildren();this.findFixedTransforms();this.runDebugMode&&(this.setAnimationProgress(0,!0),""!=this.debugString?this.stopEverything=!0:this.checkDebug())}}else this.debugString+="<br>Skip loading animation data"} 34268SceneAnimator.prototype.logTimes=function(){this.debugString+="<br>Times";var a=this.animations[0],b=a.animatedObjects.length;this.debugString+="<br>Animation totalSeconds "+a.totalSeconds;this.debugString+="<br>Animation totalFrames "+a.totalFrames;this.debugString+="<br>Animation totalObjects "+b;for(var c=0;c<b;c++){var d=a.animatedObjects[c];this.debugString+="<br>Object: "+c;this.debugString+=" End: "+d.endTime;this.debugString+=" Length: "+d.animationLength;this.debugString+=" Frames: "+d.totalFrames}}; 34269SceneAnimator.prototype.flagAllForDebugging=function(){for(var a=this.animations.length,b=0;b<a;b++)for(var c=this.animations[b],d=c.animatedObjects.length,e=0;e<d;e++)c.animatedObjects[e].debugMe=!0}; 34270SceneAnimator.prototype.checkDebug=function(){this.debugString="<br>--------------------------------------Debug Info:";this.debugString+="<br>this.selectedAnimationIndex :"+this.selectedAnimationIndex;var a=this.animations[this.selectedAnimationIndex],b=a.animatedObjects.length;this.debugString+="<br>numAnimatedObjects :"+b;""!=a.debugString&&(this.debugString+="<br>--------------------------------------------------Got animation bug info:",this.debugString+=a.debugString,this.showDebugInfo=this.stopEverything= 34271!0,a.debugString="");for(var c=0;c<b;c++){var d=a.animatedObjects[c];if(""!=d.debugString||""!=d.animatedLocalTransform.debugString)this.debugString+="<br>--------------------------------------------------Got object bug info:",this.debugString+=d.debugString,this.debugString+=d.animatedLocalTransform.debugString,this.showDebugInfo=this.stopEverything=!0,d.debugString="",d.animatedLocalTransform.debugString="";d.skinningRig&&""!=d.skinningRig.debugString&&(this.debugString+="<br>--------------------------------------------------Got skin rig info:", 34272this.debugString+=d.skinningRig.debugString,d.skinningRig.debugString="",this.showDebugInfo=this.stopEverything=!0)}this.debugString+="<br>--------------------------------------Done Debug Info:"}; 34273SceneAnimator.prototype.logObjectInfo=function(a,b){var c=this.animations[this.selectedAnimationIndex],d=b*c.originalFPS;if(a>=c.animatedObjects.length)this.debugString+="object index "+a+" exceeds "+c.animatedObjects.length;else{var e=c.animatedObjects[a],f=c.animatedObjects[e.modelPartIndex],g=c.getObjectAnimationFramePercent(e,b),h=c.getObjectAnimationFramePercent(f,b);this.debugString="";this.debugString+="<br>Object Name: "+e.name;this.debugString+="<br>Object Type: "+e.sceneObjectType;this.debugString+= 34274"<br>Object Index: "+e.id;this.debugString+="<br>Part Index: "+e.modelPartIndex;this.debugString+="<br>Part Scale: "+e.modelPartScale;this.debugString+="<br>Mesh Index: "+e.meshIndex;this.debugString+="<br>Light Index: "+e.lightIndex;this.debugString+="<br>Deformer Index: "+e.skinningRigIndex;this.debugString+="<br>Parent Index: "+e.parentIndex;this.debugString+="<br>Scene time "+b;this.debugString+="<br>Scene framepercent "+d;this.debugString+="<br>Object looped framepercent "+g;this.debugString+= 34275"<br>Model looped framepercent "+h;this.debugString+="<br>Object Anim length "+e.animationLength;this.debugString+="<br>Object Total frames "+e.totalFrames;this.debugString+="<br>Object FPS "+e.modelPartFPS;this.debugString+="<br>Model Part Anim length "+f.animationLength;this.debugString+="<br>Model total frames "+f.totalFrames;this.debugString+="<br>Model Part FPS "+f.modelPartFPS;d=Matrix.identity();c.getWorldTransform(e.id,b,d,this.sceneScale,!0);this.debugString+=e.debugString;var c=d[0],e= 34276d[1],f=d[2],g=d[4],h=d[5],k=d[6],l=d[8],n=d[9],d=d[10];Math.sqrt(c*c+e*e+f*f);Math.sqrt(g*g+h*h+k*k);Math.sqrt(l*l+n*n+d*d)}};
34276SceneAnimator.prototype.resetPlayback=function(){this.startMS=Date.now();this.animationProgress=this.totalSeconds=0;this.setAnimationProgress(0,!0)};SceneAnimator.prototype.pause=function(a){this.paused=a;this.startMS=Date.now()-1E3*this.totalSeconds/(this.playbackSpeed*this.scenePlaybackSpeed)}; 34277SceneAnimator.prototype.setAnimationProgress=function(a,b){var c=this.animations[this.selectedAnimationIndex];this.animationProgress=a;this.totalSeconds=c.totalSeconds*this.animationProgress;this.totalSeconds-=1/c.originalFPS;0>this.totalSeconds&&(this.totalSeconds=0);this.startMS=Date.now()-1E3*this.totalSeconds/(this.playbackSpeed*this.scenePlaybackSpeed);b&&this.updateScene()}; 34278SceneAnimator.prototype.setPlaybackSpeed=function(a){this.playbackSpeed=a;this.startMS=Date.now()-1E3*this.totalSeconds/(this.playbackSpeed*this.scenePlaybackSpeed)}; 34279SceneAnimator.prototype.resetCustomView=function(){0<=this.selectedCameraIndex&&this.selectedCameraIndex<this.views.length&&(this.viewYawOffsets[this.selectedCameraIndex]=0,this.viewPitchOffsets[this.selectedCameraIndex]=0,this.scene.view.rotation[1]=this.views[this.selectedCameraIndex].rotation[1],this.scene.view.rotation[0]=this.views[this.selectedCameraIndex].rotation[0],this.setViewFromSelectedCamera())}; 34280SceneAnimator.prototype.updateUserCamera=function(){this.clearCacheForCameraChildren();if(0<=this.selectedCameraIndex&&this.selectedCameraIndex<this.views.length&&this.selectedAnimationIndex<this.animations.length){var a=this.cameraObjectIndices[this.selectedCameraIndex],b=this.animations[this.selectedAnimationIndex];if(a<b.animatedObjects.length){var c=this.views[this.selectedCameraIndex],d=this.scene.view.rotation[1],e=this.scene.view.rotation[0],f=e-c.rotation[0];this.viewYawOffsets[this.selectedCameraIndex]= 34281d-c.rotation[1];this.viewPitchOffsets[this.selectedCameraIndex]=f;c=b.animatedObjects[a];b.getObjectAnimationFramePercent(c,this.totalSeconds);var f=Matrix.identity(),g=Matrix.identity();c.useFixedWorldTransform=!1;c.useFixedLocalTransform=!1;c.animatedLocalTransform.lockTransform=!1;c.animatedLocalTransform.clearCachedTransforms();c.cachedFrame0=-1;c.cachedFrame1=-1;c.cachedFrame2=-1;c.cachedFrame3=-1;c.cachedFrameUse0=0;c.cachedFrameUse1=0;c.cachedFrameUse2=0;c.cachedFrameUse3=0;b.getWorldTransform(a, 34282this.totalSeconds,g,this.sceneScale,!1);var a=g[0],h=g[1],k=g[2],l=g[4],n=g[5],m=g[6],p=g[8],r=g[9],s=g[10],a=Math.sqrt(a*a+h*h+k*k),l=Math.sqrt(l*l+n*n+m*m),n=Math.sqrt(p*p+r*r+s*s),m=-(this.scene.view.pivot[0]-g[12]),h=-(this.scene.view.pivot[1]-g[13]),g=-(this.scene.view.pivot[2]-g[14]);0>=m*p+h*r+g*s&&(d+=180);d=Matrix.rotation(Matrix.empty(),d,1);e=Matrix.rotation(Matrix.empty(),e,0);Matrix.mul(f,d,e);e=Math.sqrt(m*m+h*h+g*g);d=this.scene.view.pivot[1]+f[9]*e;g=this.scene.view.pivot[2]+f[10]* 34283e;f[12]=this.scene.view.pivot[0]+f[8]*e;f[13]=d;f[14]=g;e=Matrix.identity();b.getWorldTransform(c.parentIndex,this.totalSeconds,e,this.sceneScale,!1);b=Matrix.identity();Matrix.invert(b,e);e=Matrix.identity();Matrix.mul(e,b,f);e[12]/=this.sceneScale;e[13]/=this.sceneScale;e[14]/=this.sceneScale;f[0]*=a;f[1]*=a;f[2]*=a;f[4]*=l;f[5]*=l;f[6]*=l;f[8]*=n;f[9]*=n;f[10]*=n;c.setFixedWorldTransform(f);c.setFixedLocalTransform(e)}}}; 34284SceneAnimator.prototype.setViewFromSelectedCamera=function(){if(0<=this.selectedCameraIndex&&this.selectedCameraIndex<this.views.length){var a=this.views[this.selectedCameraIndex],b=this.scene.view,c=this.viewYawOffsets[this.selectedCameraIndex],d=this.viewPitchOffsets[this.selectedCameraIndex];b.pivot[0]=a.pivot[0];b.pivot[1]=a.pivot[1];b.pivot[2]=a.pivot[2];b.rotation[0]=a.rotation[0]+d;b.rotation[1]=a.rotation[1]+c;b.radius=a.radius;b.nearPlane=a.nearPlane;b.fov=a.fov;b.saveResetView();b.updateProjection(); 34285b.updateView()}};SceneAnimator.prototype.selectDefaultCamera=function(){if(-1!=this.defaultCameraGlobalIndex&&0<this.animations.length)for(var a=this.animations[0],b=a.cameraObjects.length,c=0;c<b;c++)if(a.cameraObjects[c].id==this.defaultCameraGlobalIndex){this.selectedCameraIndex=c;return}this.selectedCameraIndex=0}; 34286SceneAnimator.prototype.updateAnimationPlayback=function(){if(!this.stopEverything||!this.runDebugMode){var a=this.animations[this.selectedAnimationIndex];this.updateUserCamera();if(this.paused||!this.playAnimations)this.startMS=0<this.playbackSpeed?Date.now()-1E3*this.totalSeconds/(this.playbackSpeed*this.scenePlaybackSpeed):Date.now()-1E3*this.totalSeconds,this.refreshTransformsOnly(),this.runDebugMode&&this.checkDebug(),a=this.scene.view,a.saveResetView(),a.updateProjection(),a.updateView();else{this.lockPlayback&& 342870<this.playbackSpeed&&(this.startMS=Date.now()-1E3*this.totalSeconds/(this.playbackSpeed*this.scenePlaybackSpeed));var b=(Date.now()-this.startMS)/1E3*this.playbackSpeed*this.scenePlaybackSpeed;this.totalSeconds=(Date.now()-this.startMS)/1E3*this.playbackSpeed*this.scenePlaybackSpeed;var c=b/a.totalSeconds,b=Math.floor(c),c=c-b;b!=this.loopCount&&(this.loopCount++,this.loopTurntables&&this.rolloverTurntables(),this.autoAdvanceNextAnimation&&(this.nextAnimation(),this.resetPlayback()));this.totalSeconds= 34288a.totalSeconds*c;this.animationProgress=this.totalSeconds/a.totalSeconds-Math.floor(this.totalSeconds/a.totalSeconds);this.updateScene();this.runDebugMode&&this.checkDebug()}}}; 34289SceneAnimator.prototype.updateScene=function(){this.lastSceneFramePercent=this.totalSeconds*this.animations[this.selectedAnimationIndex].originalFPS;0!=this.fogObjectIndex&&this.updateFog();this.animateTurntables&&this.updateTurntables();this.animateMeshes&&this.poseMeshes();this.animateLights&&this.updateLights();this.animateMaterials&&this.updateMaterials();this.animateVisibility&&this.updateVisibility()}; 34290SceneAnimator.prototype.findCameraChildren=function(){for(var a=this.animations[0],b=a.animatedObjects.length,c=0;c<b;c++)a.hasParentTypeInHierarchy(a.animatedObjects[c],"CameraSO")&&this.cameraChildrenIndices.push(c)}; 34291SceneAnimator.prototype.findFixedTransforms=function(){for(var a=this.animations.length,b=0;b<a;b++)for(var c=this.animations[b],d=c.animatedObjects.length,e=0;e<d;e++){var f=c.animatedObjects[e];if(!f.useFixedWorldTransform&&!c.hasAnimationInHierarchy(f))if("Material"==f.sceneObjectType)f.setFixedWorldTransform(Matrix.identity()),f.setFixedLocalTransform(Matrix.identity());else{var g=Matrix.identity(),h=Matrix.identity();c.hasParentTypeInHierarchy(f,"SceneRootSO")?(c.getWorldTransform(f.id,0,g,this.sceneScale, 34292!1),f.evaluateLocalTransformAtFramePercent(0,h,!0,!1)):(c.evaluateModelPartTransformAtFrame(f.id,0,g,!1),f.evaluateLocalTransformAtFramePercent(0,h,!1,!1));f.setFixedWorldTransform(g);f.setFixedLocalTransform(h)}}}; 34293SceneAnimator.prototype.clearCacheForCameraChildren=function(){for(var a=this.animations[this.selectedAnimationIndex],b=this.cameraChildrenIndices.length,c=0;c<b;c++){var d=a.animatedObjects[this.cameraChildrenIndices[c]];d.useFixedWorldTransform=!1;d.useFixedLocalTransform=!1;d.cachedFrame0=-10;d.cachedFrame1=-10;d.cachedFrame2=-10;d.cachedFrame3=-10;d.cachedFrameUse0=0;d.cachedFrameUse1=0;d.cachedFrameUse2=0;d.cachedFrameUse3=0;d.animatedLocalTransform.clearCachedTransforms();d.animatedLocalTransform.lockTransform= 34294!1}}; 34295SceneAnimator.prototype.refreshTransformsOnly=function(){for(var a=this.animations[this.selectedAnimationIndex],b=a.meshObjects.length,c=0;c<b;c++){var d=a.meshObjects[c];a.getWorldTransform(d.id,this.totalSeconds,d.mesh.displayMatrix,this.sceneScale,!0);if(this.enableSkinning&&d.skinningRig&&this.unitScaleSkinnedMeshes&&!d.skinningRig.isRigidSkin){var d=d.mesh.displayMatrix,e=d[0],f=d[1],g=d[2],h=d[4],k=d[5],l=d[6],n=d[8],m=d[9],p=d[10],e=Math.sqrt(e*e+f*f+g*g),h=Math.sqrt(h*h+k*k+l*l),n=Math.sqrt(n*n+ 34296m*m+p*p),n=(e+h+n)/2;d[0]/=n;d[1]/=n;d[2]/=n;d[4]/=n;d[5]/=n;d[6]/=n;d[8]/=n;d[9]/=n;d[10]/=n}}if(this.animateLights)for(b=a.lightObjects.length,c=0;c<b;c++)d=a.lightObjects[c],d.useFixedWorldTransform||(n=this.scene.lights.getLightPos(d.lightIndex),m=this.scene.lights.getLightDir(d.lightIndex),p=Matrix.identity(),a.getWorldTransform(d.id,this.totalSeconds,p,this.sceneScale,!0),m[0]=p[8],m[1]=p[9],m[2]=p[10],0!=n[3]&&(n[0]=p[12],n[1]=p[13],n[2]=p[14],this.scene.lights.setLightPos(d.lightIndex,n)), 34297this.scene.lights.setLightDir(d.lightIndex,m))};SceneAnimator.prototype.findMeshIndexByPartIndex=function(a,b){for(var c=0;c<this.meshIDs.length;++c)if(b==this.meshIDs[c])return c;return-1};SceneAnimator.prototype.findLightIndexByPartIndex=function(a){for(var b=0;b<this.lightIDs.length;b++)if(a==this.lightIDs[b])return b;return-1};SceneAnimator.prototype.findMaterialIndexByPartIndex=function(a){for(var b=0;b<this.materialIDs.length;b++)if(a==this.materialIDs[b])return b;return-1}; 34298SceneAnimator.prototype.nextAnimation=function(){this.selectedAnimationIndex++;this.selectedAnimationIndex>=this.animations.length&&(this.selectedAnimationIndex=0)};SceneAnimator.prototype.selectAnimation=function(a){0<=a&&a<this.animations.length&&(this.selectedAnimationIndex=a);this.paused&&this.setAnimationProgress(this.animationProgress,!0)};
34298SceneAnimator.prototype.selectCamera=function(a){-1!=a&&this.selectedCameraIndex!=a&&(this.selectedCameraIndex=a,this.setViewFromSelectedCamera())}; 34299SceneAnimator.prototype.getAnimatedCamera=function(){if(0<=this.selectedCameraIndex&&this.selectedAnimationIndex<this.animations.length){var a=this.animations[this.selectedAnimationIndex];if(this.selectedCameraIndex<a.cameraObjects.length)return a.cameraObjects[this.selectedCameraIndex]}}; 34300SceneAnimator.prototype.poseMeshes=function(){for(var a=this.animations[this.selectedAnimationIndex],b=a.meshObjects.length,c=0;c<b;c++){var d=a.meshObjects[c];if(this.enableSkinning&&d.skinningRig)if(d.skinningRig.isRigidSkin)a.getWorldTransform(d.id,this.totalSeconds,d.mesh.displayMatrix,this.sceneScale,!0);else{d.setupSkinningRig(a,d.modelPartIndex,this.totalSeconds,d.skinningRig);a.getWorldTransform(d.id,this.totalSeconds,d.mesh.displayMatrix,this.sceneScale,!0);var e=d.modelPartScale*this.sceneScale; 34301if(this.unitScaleSkinnedMeshes){var f=d.mesh.displayMatrix,g=f[0],h=f[1],k=f[2],l=f[4],n=f[5],m=f[6],p=f[8],r=f[9],s=f[10],g=Math.sqrt(g*g+h*h+k*k),l=Math.sqrt(l*l+n*n+m*m),p=Math.sqrt(p*p+r*r+s*s),p=(g+l+p)/2;f[0]/=p;f[1]/=p;f[2]/=p;f[4]/=p;f[5]/=p;f[6]/=p;f[8]/=p;f[9]/=p;f[10]/=p;e*=p}d.skinningRig.deformMesh(d.mesh,e)}else a.getWorldTransform(d.id,this.totalSeconds,d.mesh.displayMatrix,this.sceneScale,!0)}}; 34302SceneAnimator.prototype.updateLights=function(){for(var a=this.animations[this.selectedAnimationIndex],b=this.totalSeconds*a.originalFPS,c=a.lightObjects.length,d=0;d<c;d++){var e=a.lightObjects[d],f=this.scene.lights.getLightPos(e.lightIndex),g=this.scene.lights.getLightDir(e.lightIndex),h=this.scene.lights.getLightColor(e.lightIndex),k=Matrix.identity(),l=1;e.useFixedWorldTransform||a.getWorldTransform(e.id,this.totalSeconds,k,this.sceneScale,!0);e.redProperty&&(e.redProperty.evaluate(b,h[0],e), 34303h[0]=e.redProperty.lastValue);e.greenProperty&&(e.greenProperty.evaluate(b,h[1],e),h[1]=e.greenProperty.lastValue);e.blueProperty&&(e.blueProperty.evaluate(b,h[2],e),h[2]=e.blueProperty.lastValue);e.brightnessProperty&&(e.brightnessProperty.evaluate(b,l,e),l=e.brightnessProperty.lastValue);h[0]*=l;h[1]*=l;h[2]*=l;0!=f[3]&&(e.useFixedWorldTransform||(f[0]=k[12],f[1]=k[13],f[2]=k[14],this.scene.lights.setLightPos(e.lightIndex,f)),e.spotAngleProperty&&0<this.scene.lights.spot[3*e.lightIndex]&&(f=0,e.spotAngleProperty.evaluate(b, 34304f,e),f=e.spotAngleProperty.lastValue,this.scene.lights.setLightSpotAngle(e.lightIndex,f)),e.spotSharpnessProperty&&(f=0,e.spotSharpnessProperty.evaluate(b,f,e),f=e.spotSharpnessProperty.lastValue,this.scene.lights.setLightSpotSharpness(e.lightIndex,f)),e.distanceProperty&&(f=1,e.distanceProperty.evaluate(b,f,e),f=e.distanceProperty.lastValue*this.sceneScale,this.scene.lights.setLightDistance(e.lightIndex,f)));e.useFixedWorldTransform||(g[0]=k[8],g[1]=k[9],g[2]=k[10],this.scene.lights.setLightDir(e.lightIndex, 34305g));this.scene.lights.setLightColor(e.lightIndex,h)}};SceneAnimator.prototype.updateTurntables=function(){for(var a=this.animations[this.selectedAnimationIndex],b=this.totalSeconds*a.originalFPS,c=a.turnTableObjects.length,d=0;d<c;d++){var e=a.turnTableObjects[d];e.spinProperty.evaluate(b,0,e);e.turnTableSpin=e.turnTableSpinOffset+e.spinProperty.lastValue*this.totalSeconds}}; 34306SceneAnimator.prototype.rolloverTurntables=function(){for(var a=this.animations[this.selectedAnimationIndex],b=a.turnTableObjects.length,c=0;c<b;c++){var d=a.turnTableObjects[c];d.turnTableSpinOffset=d.turnTableSpin}}; 34307SceneAnimator.prototype.updateMaterials=function(){for(var a=this.animations[this.selectedAnimationIndex],b=this.totalSeconds*a.originalFPS,c=a.materialObjects.length,d=0;d<c;d++){var e=a.materialObjects[d];e.offsetUProperty&&(e.offsetUProperty.evaluate(b,0,e),this.scene.materialsList[e.materialIndex].uOffset=e.offsetUProperty.lastValue);e.offsetVProperty&&(e.offsetVProperty.evaluate(b,0,e),this.scene.materialsList[e.materialIndex].vOffset=e.offsetVProperty.lastValue);e.emissiveProperty&&1<e.emissiveProperty.numKeyframes&& 34308(e.emissiveProperty.evaluate(b,0,e),this.scene.materialsList[e.materialIndex].emissiveIntensity=e.emissiveProperty.lastV
34308alue)}}; 34309SceneAnimator.prototype.updateFog=function(){var a=this.animations[this.selectedAnimationIndex],b=this.totalSeconds*a.originalFPS;0<=this.fogObjectIndex&&this.fogObjectIndex<a.animatedObjects.length&&this.scene.fog&&(a=a.animatedObjects[this.fogObjectIndex],a.redProperty&&(this.scene.fog.desc.color[0]=a.redProperty.evaluate(b,this.scene.fog.desc.color[0],a)),a.greenProperty&&(this.scene.fog.desc.color[1]=a.greenProperty.evaluate(b,this.scene.fog.desc.color[1],a)),a.blueProperty&&(this.scene.fog.desc.color[2]= 34310a.blueProperty.evaluate(b,this.scene.fog.desc.color[2],a)),a.distanceProperty&&(this.scene.fog.desc.distance=a.distanceProperty.evaluate(b,this.scene.fog.desc.distance,a)),a.opacityProperty&&(this.scene.fog.desc.opacity=a.opacityProperty.evaluate(b,this.scene.fog.desc.opacity,a)),a.skyIllumProperty&&(this.scene.fog.desc.skyIllum=a.skyIllumProperty.evaluate(b,this.scene.fog.desc.skyIllum,a)),a.lightIllumProperty&&(this.scene.fog.desc.lightIllum=a.lightIllumProperty.evaluate(b,this.scene.fog.desc.lightIllum, 34311a)),a.dispersionProperty&&(this.scene.fog.desc.dispersion=a.dispersionProperty.evaluate(b,this.scene.fog.desc.dispersion,a)))}; 34312SceneAnimator.prototype.updateVisibility=function(){for(var a=this.animations[this.selectedAnimationIndex],b=this.subMeshObjectIndices.length,c=0;c<b;c++){var d=this.subMeshLiveIndices[c];if(-1!=d){var e=this.subMeshObjectIndices[c],d=this.scene.meshRenderables[d],f=a.getObjectAnimationFramePercent(a.animatedObjects[e],this.totalSeconds);d.visible=a.isVisibleAtFramePercent(e,f)}}};function Shader(a){this.gl=a;this.program=null;this.params={};this.samplers={};this.attribs={}} 34313Shader.prototype.build=function(a,b){var c=this.gl;this.program=c.createProgram();this.params={};this.samplers={};this.attribs={};var d=function(a){for(var b="",c=a.indexOf("\n"),d=0;-1!=c;)d++,b+=d+": ",b+=a.substring(0,c+1),a=a.substring(c+1,a.length),c=a.indexOf("\n");console.log(b)},e=c.createShader(c.VERTEX_SHADER);c.shaderSource(e,a);c.compileShader(e);c.getShaderParameter(e,c.COMPILE_STATUS)||(console.log(c.getShaderInfoLog(e)),marmoset.verboseErrors&&d(a));c.attachShader(this.program,e);e= 34314c.createShader(c.FRAGMENT_SHADER);c.shaderSource(e,b);c.compileShader(e);c.getShaderParameter(e,c.COMPILE_STATUS)||(console.log(c.getShaderInfoLog(e)),marmoset.verboseErrors&&d(b));c.attachShader(this.program,e);c.linkProgram(this.program);c.getProgramParameter(this.program,c.LINK_STATUS)||console.log(c.getProgramInfoLog(this.program));for(var e=c.getProgramParameter(this.program,c.ACTIVE_UNIFORMS),f=0,d=0;d<e;++d){var g=c.getActiveUniform(this.program,d),h=g.name,k=h.indexOf("[");0<=k&&(h=h.substring(0, 34315k));k=c.getUniformLocation(this.program,g.name);g.type==c.SAMPLER_2D||g.type==c.SAMPLER_CUBE?this.samplers[h]={location:k,unit:f++}:this.params[h]=k}e=c.getProgramParameter(this.program,c.ACTIVE_ATTRIBUTES);for(d=0;d<e;++d)f=c.getActiveAttrib(this.program,d),this.attribs[f.name]=c.getAttribLocation(this.program,f.name)};Shader.prototype.bind=function(){return this.program?(this.gl.useProgram(this.program),!0):!1};Shader.prototype.complete=function(){return!!this.program};function ShaderCache(a){this.gl=a;this.cache=[]}ShaderCache.prototype.fromURLs=function(a,b,c){var d="";if(c)for(var e=0;e<c.length;++e)d=c[e]+"\n"+d;c=d+":"+a+"|"+b;e=this.cache[c];if(void 0!==e)return e;var f=new Shader(this.gl),g=null,h=null,k=function(){null!=g&&null!=h&&f.build(g,h)};this.fetch(a,function(a){g=d+a;k()});this.fetch(b,function(a){h=d+a;k()});return this.cache[c]=f}; 34316ShaderCache.prototype.fetch=function(a,b){"undefined"!=typeof ShaderTable?void 0!==ShaderTable[a]?this.resolveIncludes(new String(ShaderTable[a]),b):b(""):Network.fetchText("src/shader/"+a,function(a){this.resolveIncludes(a,b)}.bind(this),function(){b("")})}; 34317ShaderCache.prototype.resolveIncludes=function(a,b){for(var c=[],d=!0,e=function(a,b,e,f,n){d=!0;c.push({offset:n,path:b.slice(1,b.length-1)});return""};d;)d=!1,a=a.replace(/#include\s((<[^>]+>)|("[^"]+"))/,e);if(0<c.length)for(var f=c.length,e=0;e<c.length;++e)this.fetch(c[e].path,function(d){this.src=d;if(0>=--f){for(d=c.length-1;0<=d;--d)a=a.substring(0,c[d].offset)+c[d].src+a.substring(c[d].offset);b(a)}}.bind(c[e]));else b(a)};function ShadowCollector(a,b){this.gl=a;this.shadowCount=b;this.nativeDepth=!!a.ext.textureDepth;this.desc=c;c=this.nativeDepth?["#define SHADOW_NATIVE_DEPTH"]:[];this.shaderSolid=a.shaderCache.fromURLs("shadowvert.glsl","shadowfrag.glsl",c);c.push("#define ALPHA_TEST 1");this.shaderAlphaTest=a.shaderCache.fromURLs("shadowvert.glsl","shadowfrag.glsl",c);this.depthTextures=[];this.depthTargets=[];if(0<this.shadowCount){var c={width:2048,height:2048,clamp:!0,mipmap:!1,nofilter:!0};a.hints.mobile&&(c.width= 34318c.height=1536);var d={width:c.width,height:c.height},e,f;this.nativeDepth?(e=a.DEPTH_COMPONENT,f=a.UNSIGNED_SHORT):(d.depthBuffer=Framebuffer.createDepthBuffer(a,c.width,c.height),e=a.RGB,f=a.UNSIGNED_BYTE);for(var g=0;g<this.shadowCount;++g)this.depthTextures[g]=new Texture(a,c),this.depthTextures[g].loadArray(null,e,f),this.nativeDepth?d.depth=this.depthTextures[g]:d.color0=this.depthTextures[g],this.depthTargets[g]=new Framebuffer(a,d)}} 34319ShadowCollector.prototype.bindDepthTexture=function(a,b){this.shadowCount>b&&this.depthTextures[b].bind(a)}; 34320ShadowCollector.prototype.collect=function(a,b){for(var c=this.gl,d=a.lights,e=d.shadowCount,f=d.modelViewBuffer,g=d.projectionBuffer,h=d.matrix,k=0!=a.sceneAnimator,l=Matrix.empty(),n=!1,m=0;m<e;++m)if(d.shadowsNeedUpdate[m]){d.shadowsNeedUpdate[m]=0;n=!0;Matrix.mul(l,f.subarray(16*m,16*(m+1)),h);Matrix.mul(l,g.subarray(16*m,16*(m+1)),l);this.depthTargets[m].bind();c.clearColor(1,1,1,1);c.clear(c.COLOR_BUFFER_BIT|c.DEPTH_BUFFER_BIT);var p=this.shaderSolid;p.bind();c.uniformMatrix4fv(p.params.uViewProjection, 34321!1,l);c.uniformMatrix4fv(p.params.uMeshTransform,!1,Matrix.identity());for(var r=0;r<a.meshRenderables.length;++r){var s=a.meshRenderables[r],u=s.material;!s.mesh.desc.castShadows||!u.castShadows||0<u.shadowAlphaTest||(k&&c.uniformMatrix4fv(p.params.uMeshTransform,!1,s.mesh.displayMatrix),s.drawShadow(p.attribs.vPosition))}p=this.shaderAlphaTest;p.bind();c.uniformMatrix4fv(p.params.uViewProjection,!1,l);c.uniformMatrix4fv(p.params.uMeshTransform,!1,Matrix.identity());for(r=0;r<a.meshRenderables.length;++r)s= 34322a.meshRenderables[r],u=s.material,s.mesh.desc.castShadows&&u.castShadows&&0<u.shadowAlphaTest&&(u.textures.albedo.bind(p.samplers.tAlbedo),k&&
34322(c.uniform2f(p.params.uUVOffset,u.uOffset,u.vOffset),c.uniformMatrix4fv(p.params.uMeshTransform,!1,s.mesh.displayMatrix)),s.drawAlphaShadow(p.attribs.vPosition,p.attribs.vTexCoord))}n&&(b.bind(),c.enable(c.CULL_FACE),c.cullFace(c.BACK))};ShadowCollector.prototype.complete=function(){return this.shaderSolid.complete()&&this.shaderAlphaTest.complete()};function ShadowFloor(a,b,c,d){this.gl=a;this.desc=b;this.lightCount=d.count;this.shadowCount=c.shadowCount;b=this.nativeDepth?["#define SHADOW_NATIVE_DEPTH"]:[];b.push("#define LIGHT_COUNT "+this.lightCount);b.push("#define SHADOW_COUNT "+this.shadowCount);a.hints.mobile&&b.push("#define MOBILE");this.shader=a.shaderCache.fromURLs("shadowfloorvert.glsl","shadowfloorfrag.glsl",b);b=new Float32Array([-1,0,-1,-1,0,1,1,0,1,-1,0,-1,1,0,1,1,0,-1]);this.quadGeom=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER, 34323this.quadGeom);a.bufferData(a.ARRAY_BUFFER,b,a.STATIC_DRAW);a.bindBuffer(a.ARRAY_BUFFER,null)} 34324ShadowFloor.prototype.draw=function(a){var b=a.view,c=a.lights,d=a.shadow,e=this.gl,f=this.shader.params,g=this.shader.samplers;this.shader.bind();b=Matrix.mul(Matrix.empty(),b.projectionMatrix,b.viewMatrix);Matrix.mul(b,b,this.desc.transform);e.uniformMatrix4fv(f.uModelViewProjectionMatrix,!1,b);b=Matrix.mul(Matrix.empty(),c.matrix,this.desc.transform);e.uniformMatrix4fv(f.uModelSkyMatrix,!1,b);0<c.count&&(e.uniform4fv(f.uLightPositions,c.positionBuffer),e.uniform3fv(f.uLightDirections,c.directionBuffer), 34325e.uniform3fv(f.uLightColors,c.colors),e.uniform3fv(f.uLightParams,c.parameters),e.uniform3fv(f.uLightSpot,c.spot),a=0.392699*a.postRender.currentSample(),e.uniform2f(f.uShadowKernelRotation,0.5*Math.cos(a),0.5*Math.sin(a)),0<c.shadowCount&&(a=d.depthTextures[0].desc.width,e.uniform2f(f.uShadowMapSize,a,1/a),e.uniformMatrix4fv(f.uShadowMatrices,!1,c.finalTransformBuffer),e.uniformMatrix4fv(f.uInvShadowMatrices,!1,c.inverseTransformBuffer),e.uniform4fv(f.uShadowTexelPadProjections,c.shadowTexelPadProjections), 34326d.bindDepthTexture(g.tDepth0,0),d.bindDepthTexture(g.tDepth1,1),d.bindDepthTexture(g.tDepth2,2)));e.uniform3f(f.uShadowCatcherParams,this.desc.simple?1:0,this.desc.alpha,this.desc.edgeFade);e.depthMask(!1);e.enable(e.BLEND);e.blendFunc(e.ZERO,e.SRC_COLOR);c=this.shader.attribs.vPosition;e.bindBuffer(e.ARRAY_BUFFER,this.quadGeom);e.enableVertexAttribArray(c);e.vertexAttribPointer(c,3,e.FLOAT,!1,0,0);e.drawArrays(e.TRIANGLES,0,6);e.disableVertexAttribArray(c);e.bindBuffer(e.ARRAY_BUFFER,null);e.disable(e.BLEND); 34327e.depthMask(!0)};ShadowFloor.prototype.complete=function(){return this.shader.complete()};function Skin(a){this.numVertices=a.vertexCount;this.vertices=new Float32Array(a.vertexCount);a.vertexBuffer||(this.numVertices=0)};function SkinningCluster(){this.associateObjectIndex=this.linkObjectIndex=this.linkMode=0;this.vertexIndices=[];this.vertexWeights=[];this.matrix=Matrix.identity();this.defaultAssociateWorldTransform=this.defaultClusterWorldTransform=this.defaultClusterBaseTransform=0;this.defaultClusterWorldTransformInvert=Matrix.identity();this.defaultAssociateWorldTransformInvert=Matrix.identity();this.debugString=""} 34328SkinningCluster.prototype.solveAdditiveClusterTransform=function(a,b,c){b=Matrix.identity();var d=Matrix.identity(),e=Matrix.identity();Matrix.mul(b,a,this.defaultClusterBaseTransform);Matrix.mul(d,this.defaultAssociateWorldTransformInvert,b);Matrix.mul(e,this.defaultAssociateWorldTransformInvert,d);Matrix.mul(c,this.defaultClusterWorldTransformInvert,e)}; 34329SkinningCluster.prototype.solveSimpleClusterTransform=function(a,b,c){var d=Matrix.identity(),e=Matrix.identity();Matrix.invert(e,b);Matrix.mul(d,e,a);Matrix.mul(c,d,this.defaultClusterBaseTransform)}; 34330SkinningCluster.prototype.solveClusterTransformAtFrame=function(a,b,c,d){if(1==this.linkMode){var e=Matrix.identity();b=Matrix.identity();a.evaluateModelPartTransformAtFrame(this.linkObjectIndex,c,e,!1);a.evaluateModelPartTransformAtFrame(this.associateObjectIndex,c,b,!1);this.solveAdditiveClusterTransform(e,b,d)}else{var e=Matrix.identity(),f=Matrix.identity();a.evaluateModelPartTransformAtFrame(this.linkObjectIndex,c,e,!1);a.evaluateModelPartTransformAtFrame(b,c,f,!1);this.solveSimpleClusterTransform(e, 34331f,d)}};function SkinningRig(a,b,c){this.debugString="";
34331this.skinningClusters=[];this.srcVFile=b.file;if(a=a.get(this.srcVFile))if(a.data){this.rigByteStream=new ByteStream(a.data);a=new Uint32Array(this.rigByteStream.bytes.buffer,0,this.rigByteStream.bytes.length/4);this.expectedNumClusters=a[0];this.expectedNumVertices=a[1];this.numClusterLinks=a[2];this.originalObjectIndex=a[3];this.isRigidSkin=a[4];this.tangentMethod=a[5];b=6+7*this.expectedNumClusters;for(var d=0;d<this.expectedNumClusters;d++){var e= 34332new SkinningCluster;this.skinningClusters.push(e);var f=6+7*d;e.linkMode=a[f+1];e.linkObjectIndex=a[f+2];e.associateObjectIndex=a[f+3];var g=a[f+5];e.defaultClusterWorldTransform=c.getMatrix(a[f+4]);e.defaultClusterBaseTransform=c.getMatrix(g);Matrix.invert(e.defaultClusterWorldTransformInvert,e.defaultClusterWorldTransform);1==e.linkMode&&(e.defaultAssociateWorldTransform=c.getMatrix(a[f+6]),Matrix.invert(e.defaultAssociateWorldTransformInvert,e.defaultAssociateWorldTransform))}c=4*b;b=c+this.expectedNumVertices; 34333a=b+2*this.numClusterLinks;b=new Uint8Array(this.rigByteStream.bytes.subarray(b));a=new Uint8Array(this.rigByteStream.bytes.subarray(a));this.linkMapCount=new Uint8Array(this.rigByteStream.bytes.buffer,c,this.expectedNumVertices);this.linkMapClusterIndices=new Uint16Array(b.buffer);this.linkMapWeights=new Float32Array(a.buffer)}else this.debugString+="<br>No data in "+this.srcVFile;else this.debugString+="<br>Error loading buffer for skinning rig "+this.srcVFile} 34334SkinningRig.prototype.unpackUnitVectors=function(a,b,c,d){for(var e=0;e<c;e++){var f=b[d*e],g=b[d*e+1],h=32768<=g;h&&(g-=32768);var f=f/32767.4*2-1,g=g/32767.4*2-1,k=1-(f*f+g*g),k=Math.sqrt(k),k=isNaN(k)?0:k;h&&(k=-k);a[3*e]=f;a[3*e+1]=g;a[3*e+2]=k}}; 34335SkinningRig.prototype.copyOriginalVertices=function(a){if(!this.unTransformedVertices)if(this.unTransformedVertices=new Float32Array(3*a.vertexCount),this.unTransformedNormals=new Float32Array(3*a.vertexCount),this.unTransformedTangents=new Float32Array(3*a.vertexCount),this.unTransformedBiTangents=new Float32Array(3*a.vertexCount),this.skinVertexWeights=new Float32Array(a.vertexCount),this.skinVertexTransform4x3=new Float32Array(12),a.dynamicVertexData){var b=new Float32Array(a.dynamicVertexData.buffer); 34336new Uint8Array(a.dynamicVertexData.buffer);var c=0,d=c,c=c+12+8;a.secondaryTexCoord&&(c+=8);var e=c,f=c+=4,c=c+4,g=a.stride/2,c=new Uint8Array(a.dynamicVertexData.subarray(c)),c=new Uint16Array(c.buffer),e=new Uint8Array(a.dynamicVertexData.subarray(e)),e=new Uint16Array(e.buffer),f=new Uint8Array(a.dynamicVertexData.subarray(f)),f=new Uint16Array(f.buffer);this.unpackUnitVectors(this.unTransformedNormals,c,a.vertexCount,g);this.unpackUnitVectors(this.unTransformedTangents,e,a.vertexCount,g);this.unpackUnitVectors(this.unTransformedBiTangents, 34337f,a.vertexCount,g);for(g=0;g<a.vertexCount;g++)f=(a.stride*g+d)/4,this.unTransformedVertices[3*g]=b[f],this.unTransformedVertices[3*g+1]=b[f+1],this.unTransformedVertices[3*g+2]=b[f+2]}else this.debugString+="<br>Can't init skinning rig - mesh buffer is not dynamic - rigid is "+this.isRigidSkin};SkinningRig.prototype.useOriginalMeshVertices=function(a){this.isRigidSkin?this.debugString+="<br>useOriginalMeshVertices for rigid skin?":this.copyOriginalVertices(a)}; 34338SkinningRig.prototype.deformMeshVertices=function(a,b){if(0!=this.skinningClusters.length&&this.unTransformedVertices){var c=a.stride/4,d=new Float32Array(a.dynamicVertexData.buffer),e=new Uint16Array(a.dynamicVertexData.buffer);new Uint8Array(a.dynamicVertexData.buffer);var f;f=20;a.secondaryTexCoord&&(f+=8);var g=f,h=f+=4;f+=4;for(var k=this.unTransformedVertices.length/3,l=0,n=0;n<k;++n){var m=n,p=(m*a.stride+g)/2,r=(m*a.stride+h)/2,s=(m*a.stride+f)/2,u=this.linkMapCount[m],q=this.skinVertexTransform4x3; 34339this.skinVertexWeights[m]=0;q[0]=0;q[1]=0;q[2]=0;q[3]=0;q[4]=0;q[5]=0;q[6]=0;q[7]=0;q[8]=0;q[9]=0;q[10]=0;q[11]=0;var x=this.linkMapWeights[l];if(1==u&&1==x){var w=this.linkMapClusterIndices[l],w=this.skinningClusters[w],v=w.matrix;q[0]=v[0];q[1]=v[1];q[2]=v[2];q[3]=v[4];q[4]=v[5];q[5]=v[6];q[6]=v[8];q[7]=v[9];q[8]=v[10];q[9]=v[12];q[10]=v[13];q[11]=v[14];this.skinVertexWeights[m]=1}else for(var t=this.skinVertexWeights[m]=0;t<u;t++)x=this.linkMapWeights[l+t],w=this.linkMapClusterIndices[l+t],w<this.skinningCluster
34339s.length&& 34340(w=this.skinningClusters[w],v=w.matrix,q[0]+=x*v[0],q[1]+=x*v[1],q[2]+=x*v[2],q[3]+=x*v[4],q[4]+=x*v[5],q[5]+=x*v[6],q[6]+=x*v[8],q[7]+=x*v[9],q[8]+=x*v[10],q[9]+=x*v[12],q[10]+=x*v[13],q[11]+=x*v[14],this.skinVertexWeights[m]+=x,1==w.linkMode&&(this.skinVertexWeights[m]=1));l+=this.linkMapCount[n];if(0<this.skinVertexWeights[m]){var y=this.unTransformedVertices[3*n+0],E=this.unTransformedVertices[3*n+1],F=this.unTransformedVertices[3*n+2],A=this.unTransformedNormals[3*n+0],B=this.unTransformedNormals[3* 34341n+1],z=this.unTransformedNormals[3*n+2],w=this.unTransformedTangents[3*n+0],v=this.unTransformedTangents[3*n+1],C=this.unTransformedTangents[3*n+2],u=this.unTransformedBiTangents[3*n+0],q=this.unTransformedBiTangents[3*n+1],x=this.unTransformedBiTangents[3*n+2],t=this.skinVertexTransform4x3,G=1;0<this.skinVertexWeights[m]&&(G=1/this.skinVertexWeights[m]);d[c*n]=G*(y*t[0]+E*t[3]+F*t[6]+t[9])*b;d[c*n+1]=G*(y*t[1]+E*t[4]+F*t[7]+t[10])*b;d[c*n+2]=G*(y*t[2]+E*t[5]+F*t[8]+t[11])*b;y=A*t[0]+B*t[3]+z*t[6]; 34342m=A*t[1]+B*t[4]+z*t[7];A=A*t[2]+B*t[5]+z*t[8];B=w*t[0]+v*t[3]+C*t[6];z=w*t[1]+v*t[4]+C*t[7];w=w*t[2]+v*t[5]+C*t[8];v=u*t[0]+q*t[3]+x*t[6];C=u*t[1]+q*t[4]+x*t[7];u=u*t[2]+q*t[5]+x*t[8];q=Math.sqrt(y*y+m*m+A*A);y/=q;m/=q;A/=q;q=32767.4*(y/2+0.5);x=32767.4*(m/2+0.5);0>A&&(x+=32768);e[s]=Math.floor(q);e[s+1]=Math.floor(x);q=Math.sqrt(B*B+z*z+w*w);B/=q;z/=q;w/=q;q=32767.4*(B/2+0.5);x=32767.4*(z/2+0.5);0>w&&(x+=32768);e[p]=Math.floor(q);e[p+1]=Math.floor(x);q=Math.sqrt(v*v+C*C+u*u);v/=q;C/=q;u/=q;q=32767.4* 34343(v/2+0.5);x=32767.4*(C/2+0.5);0>u&&(x+=32768);e[r]=Math.floor(q);e[r+1]=Math.floor(x)}else y=this.unTransformedVertices[3*n+0],E=this.unTransformedVertices[3*n+1],F=this.unTransformedVertices[3*n+2],d[c*n]=y*b,d[c*n+1]=E*b,d[c*n+2]=F*b}}}; 34344SkinningRig.prototype.deformMesh=function(a,b){if(0!=this.skinningClusters.length&&!this.isRigidSkin){this.deformMeshVertices(a,b);var c=a.gl;c.bindBuffer(c.ARRAY_BUFFER,a.vertexBuffer);c.bufferData(c.ARRAY_BUFFER,a.dynamicVertexData,c.DYNAMIC_DRAW);c.bindBuffer(c.ARRAY_BUFFER,null)}};function Sky(a,b,c){this.gl=a;var d=b.extract("sky.dat")||b.extract("sky.png");if(void 0!==d){this.specularTexture=new Texture(a,{width:256,height:2048,clamp:!0});b=d.data;for(var d=d.data.length,e=d/4,f=new Uint8Array(d),g=0,h=0;g<d;++h)f[g++]=b[h+2*e],f[g++]=b[h+e],f[g++]=b[h],f[g++]=b[h+3*e];this.specularTexture.loadArray(f)}this.diffuseCoefficients=new Float32Array(c.diffuseCoefficients);this.backgroundMode=c.backgroundMode||0;this.backgroundBrightness=c.backgroundBrightness||1;this.backgroundColor= 34345new Float32Array(c.backgroundColor);if(1<=this.backgroundMode)if(this.backgroundShader=a.shaderCache.fromURLs("skyvert.glsl",3==this.backgroundMode?"skySH.glsl":"sky.glsl",["#define SKYMODE "+this.backgroundMode]),this.vertexBuffer=a.createBuffer(),a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffer),c=1/256,b=0.5/256,d=2.8*b,e=0.5*b,c=new Float32Array([0,1,0,0.49609375+c,0.49609375+c,1,0,0,0.9921875+c,0.49609375+c,0,0,1,0.49609375+c,0.9921875+c,-1,0,0,0+c,0.49609375+c,0,0,-1,0.49609375+c,0+c,0,-1,0,0.9921875+ 34346c,0+c,0,-1,0,0.9921875+c,0.9921875+c,0,-1,0,0+c,0.9921875+c,0,-1,0,0+c,0+c,d,1-d,-d,0.5+b,0.5-b,d,1-d,d,0.5+b,0.5+b,-d,1-d,d,0.5-b,0.5+b,-d,1-d,-d,0.5-b,0.5-b,-d,0,-1+d,0.5-b,0+c+b,d,0,-1+d,0.5+b,0+c+b,1-d,0,-d,0.9921875+c-b,0.5-b,1-d,0,d,0.9921875+c-b,0.5+b,d,0,1-d,0.5+b,0.9921875+c-b,-d,0,1-d,0.5-b,0.9921875+c-b,-1+d,0,d,0+c+b,0.5+b,-1+d,0,-d,0+c+b,0.5-b,1,0,0,0.9921875+c-e,0.49609375+c,0,0,1,0.49609375+c,0.9921875+c-e,-1,0,0,0+c+e,0.49609375+c,0,0,-1,0.49609375+c,0+c+e,0,1,0,0.49609375+c-e,0.49609375+ 34347c,0,1,0,0.49609375+c,0.49609375+c-e,0,1,0,0.49609375+c+e,0.49609375+c,0,1,0,0.49609375+c,0.49609375+c+e]),a.bufferData(a.ARRAY_BUFFER,c,a.STATIC_DRAW),a.bindBuffer(a.ARRAY_BUFFER,null),this.indexBuffer=a.createBuffer(),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer),c=new Uint16Array([2,1,6,3,2,7,8,4,3,4,5,1,9,14,15,17,10,16,18,19,11,20,13,12,28,12,13,13,24,28,28,24,9,9,24,14,25,9,15,25,15,21,10,25,21,10,21,16,22,26,10,22,10,17,18,11,26,22,18,26,19,23,27,19,27,11,23,20,27,27,20,12]),this.skyIndexCount= 34348c.length,a.bufferData(a.ELEMENT_ARRAY_BUFFER,c,a.STATIC_DRAW),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,null),3==this.backgroundMode)for(this.backgroundCoefficients=new Float32Array(this.diffuseCoefficients),g=0;g<this.backgroundCoefficients.length;++g)this.backgroundCoefficients[g]*=this.backgroundBrightness;else{this.backgroundTexture=new Texture(a,{width:256,height:256,clamp:!0});c=!1;var k;a.ext.textureHalf&&a.ext.textureHalfLinear&&(this.backgroundTexture.loadArray(null,a.RGB,a.ext.textureHalf.HALF_FLOAT_OES), 34349k=new Framebuffer(a,{color0:this.backgroundTexture}),c=k.valid);!c&&a.ext.textureFloat&&a.ext.textureFloatLinear&&!a.hints.mobile&&(this.backgroundTexture.loadArray(null,a.RGB,a.FLOAT),k=new Framebuffer(a,{color0:this.backgroundTexture}),c=k.valid);c||(this.backgroundTexture.loadArray(),k=new Framebuffer(a,{color0:this.backgroundTexture}));k.bind();k=new Shader(a);k.build("precision highp float; varying vec2 tc; attribute vec4 p; void main(){ gl_Position=p; tc=vec2(0.5,0.5/8.0)*p.xy+vec2(0.5,6.5/8.0); }", 34350"precision highp float; varying vec2 tc; uniform sampler2D tex; uniform float b; void main(){vec4 s=texture2D(tex,tc); gl_FragColor.xyz=s.xyz*(b*s.w);}");k.bind();a.uniform1f(k.params.b,7*Math.sqrt(this.backgroundBrightness));this.specularTexture.bind(k.samplers.tex);c=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,c);c=new Float32Array([-1,-1,0.5,1,3,-1,0.5,1,-1,3,0.5,1]);a.bufferData(a.ARRAY_BUFFER,c,a.STATIC_DRAW);a.enableVertexAttribArray(k.attribs.p);a.vertexAttribPointer(k.attribs.p,4,a.FLOAT, 34351!1,0,0);a.drawArrays(a.TRIANGLES,0,3);a.disableVertexAttribArray(k.attribs.p)}}Sky.prototype.setClearColor=function(){if(marmoset.transparentBackgroun
34351d)this.gl.clearColor(0,0,0,0);else if(1>this.backgroundMode){var a=this.backgroundColor;this.gl.clearColor(a[0],a[1],a[2],1)}else this.gl.clearColor(0.0582,0.06772,0.07805,1)}; 34352Sky.prototype.draw=function(a){if(1>this.backgroundMode||marmoset.transparentBackground)return!1;if(this.complete()){var b=this.gl,c=this.backgroundShader,d=a.view,e=a.lights.invMatrix;c.bind();b.uniformMatrix4fv(c.params.uInverseSkyMatrix,!1,e);b.uniformMatrix4fv(c.params.uViewProjection,!1,d.viewProjectionMatrix);3==this.backgroundMode?b.uniform4fv(c.params.uSkyCoefficients,this.backgroundCoefficients):this.backgroundTexture.bind(c.samplers.tSkyTexture);a=0.07+0.94*(1-a.stripData.activeFade()); 34353b.uniform1f(c.params.uAlpha,a);b.bindBuffer(b.ARRAY_BUFFER,this.vertexBuffer);b.enableVertexAttribArray(c.attribs.vPosition);b.vertexAttribPointer(c.attribs.vPosition,3,b.FLOAT,!1,20,0);b.enableVertexAttribArray(c.attribs.vTexCoord);b.vertexAttribPointer(c.attribs.vTexCoord,2,b.FLOAT,!1,20,12);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,this.indexBuffer);1>a&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA));b.depthMask(!1);b.disable(b.DEPTH_TEST);b.drawElements(b.TRIANGLES,this.skyIndexCount, 34354b.UNSIGNED_SHORT,0);b.enable(b.DEPTH_TEST);b.depthMask(!0);1>a&&b.disable(b.BLEND);b.disableVertexAttribArray(c.attribs.vPosition);b.disableVertexAttribArray(c.attribs.vTexCoord)}};Sky.prototype.complete=function(){return this.backgroundShader&&!this.backgroundShader.complete()?!1:this.specularTexture.complete()};function StripData(){this.STRIP_NONE=-2;this.STRIP_MENU=-1;this.stripCount=5;this.strips=[0,0,0,0,0];this.labels=["Normals","Albedo","Reflectivity","Gloss","Topology"];this.stripSlant=0.25;this.selectedStrip=this.STRIP_NONE;this.animationActive=!1;this.timestamp=Date.now();this.update(!0)}StripData.expDecay=function(a,b){return Math.exp(-0.69314718/a*b)}; 34355StripData.prototype.update=function(a){var b=0.001*(Date.now()-this.timestamp);this.timestamp=Date.now();for(var c=!1,d=0;d<this.stripCount;++d){var e=0,e=this.selectedStrip==this.STRIP_MENU?-0.9+0.3*(d+1):0>this.selectedStrip||d<this.selectedStrip?-2:2;if(a)this.strips[d]=e;else{var f=e-this.strips[d],f=f*StripData.expDecay(0.05,b);this.animationActive&&(this.strips[d]=e-f);c=c||0.001<Math.abs(f)}}this.animationActive=c};StripData.prototype.active=function(){return this.selectedStrip>=this.STRIP_MENU}; 34356StripData.prototype.activeFade=function(){var a=(this.strips[this.stripCount-1]- -2)/(-0.9+0.3*this.stripCount- -2),a=1<a?1:a;return 0>a?0:a};StripData.prototype.activeWireframe=function(){return this.active()&&0.01<Math.abs(this.strips[4]-this.strips[3])};StripData.prototype.toggleMenu=function(){this.selectedStrip=this.selectedStrip==this.STRIP_MENU?this.STRIP_NONE:this.STRIP_MENU}; 34357StripData.prototype.selectStrip=function(a,b){if(this.selectedStrip==this.STRIP_MENU){var c=a+b*this.stripSlant;this.selectedStrip=this.STRIP_NONE;for(var d=0;d<this.stripCount;++d)if(c<this.strips[d]){this.selectedStrip=d;break}}else this.selectedStrip=this.STRIP_MENU};function Texture(a,b){this.gl=a;this.id=null;this.type=a.TEXTURE_2D;this.format=a.RGBA;this.componentType=a.UNSIGNED_BYTE;b=b||{};this.desc={width:b.width||1,height:b.height||1,mipmap:b.mipmap,clamp:b.clamp,mirror:b.mirror,aniso:b.aniso,nofilter:b.nofilter}} 34358Texture.prototype.loadImage=function(a,b){var c=this.gl;a&&a.width&&a.height&&(this.desc.width=a.width,this.desc.height=a.height);this.id=c.createTexture();c.bindTexture(this.type,this.id);this.format=b||c.RGBA;this.componentType=c.UNSIGNED_BYTE;c.pixelStorei(c.UNPACK_FLIP_Y_WEBGL,!0);c.texImage2D(this.type,0,this.format,this.format,this.componentType,a);this.setParams();c.bindTexture(this.type,null)}; 34359Texture.prototype.loadArray=function(a,b,c){var d=this.gl;this.id=d.createTexture();d.bindTexture(this.type,this.id);this.format=b||d.RGBA;this.componentType=c||d.UNSIGNED_BYTE;d.pixelStorei(d.UNPACK_FLIP_Y_WEBGL,!0);d.texImage2D(this.type,0,this.format,this.desc.width,this.desc.height,0,this.format,this.componentType,a||null);this.setParams();d.bindTexture(this.type,null)}; 34360Texture.prototype.setParams=function(){var a=this.gl,b=function(a){return 0<a&&0==(a&a-1)};b(this.desc.width)&&b(this.desc.height)||(this.desc.clamp=!0,this.desc.mipmap=!1);b=!this.desc.nofilter;this.desc.mipmap?(a.generateMipmap(this.type),a.texParameteri(this.type,a.TEXTURE_MIN_FILTER,b?a.LINEAR_MIPMAP_LINEAR:a.NEAREST_MIPMAP_NEAREST)):a.texParameteri(this.type,a.TEXTURE_MIN_FILTER,b?a.LINEAR:a.NEAREST);a.texParameteri(this.type,a.TEXTURE_MAG_FILTER,b?a.LINEAR:a.NEAREST);if(this.desc.clamp||this.desc.mirror)b= 34361this.desc.clamp?a.CLAMP_TO_EDGE:a.MIRRORED_REPEAT,a.texParameteri(this.type,a.TEXTURE_WRAP_S,b),a.texParameteri(this.type,a.TEXTURE_WRAP_T,b);this.desc.aniso&&a.ext.textureAniso&&a.texParameteri(this.type,a.ext.textureAniso.TEXTURE_MAX_ANISOTROPY_EXT,this.desc.aniso)};
34361Texture.prototype.rebuildMips=function(){this.desc.mipmap&&(this.gl.bindTexture(this.type,this.id),this.gl.generateMipmap(this.type))}; 34362Texture.prototype.copyColorBuffer=function(){this.gl.bindTexture(this.type,this.id);this.gl.copyTexSubImage2D(this.type,0,0,0,0,0,this.desc.width,this.desc.height)};Texture.prototype.bind=function(a){if(a){var b=this.gl;b.uniform1i(a.location,a.unit);b.activeTexture(b.TEXTURE0+a.unit);b.bindTexture(this.type,this.id)}};Texture.prototype.destroy=function(){this.gl.deleteTexture(this.id);this.id=null};Texture.prototype.complete=function(){return!!this.id};function TextureCache(a){this.gl=a;this.cache=[]}TextureCache.prototype.fromURL=function(a,b){var c=this.cache[a];if(void 0!==c)return c;var d=new Texture(this.gl,b);Network.fetchImage(a,function(a){d.loadImage(a)});return this.cache[a]=d};TextureCache.prototype.fromFile=function(a,b){if(!a)return null;var c=this.cache[a.name];if(void 0!==c)return c;var d=new Texture(this.gl,b);this.cache[a.name]=d;TextureCache.parseFile(a,function(a){d.loadImage(a);TextureCache.closeImage(a)});return d}; 34363TextureCache.prototype.fromFilesMergeAlpha=function(a,b,c){if(!b)return this.fromFile(a,c);var d=a.name+"|"+b.name,e=this.cache[d];if(void 0!==e)return e;var f=this.gl;this.blitShader||(this.blitShader=new Shader(this.gl),this.blitShader.build("precision highp float; varying vec2 c; attribute vec2 pos; void main(){ gl_Position.xy = 2.0*pos-vec2(1.0); gl_Position.zw = vec2(0.5,1.0); c=pos; }","precision highp float; varying vec2 c; uniform sampler2D tTex; void main(){ gl_FragColor=texture2D(tTex,c).rgbr; }"), 34364this.mergeVerts=f.createBuffer(),f.bindBuffer(f.ARRAY_BUFFER,this.mergeVerts),e=new Float32Array([0,0,2,0,0,2]),f.bufferData(f.ARRAY_BUFFER,e,f.STATIC_DRAW),f.bindBuffer(f.ARRAY_BUFFER,null));var g=function(a){this.blitShader.bind();a.bind(this.blitShader.samplers.tTex);f.bindBuffer(f.ARRAY_BUFFER,this.mergeVerts);f.enableVertexAttribArray(this.blitShader.attribs.pos);f.vertexAttribPointer(this.blitShader.attribs.pos,2,f.FLOAT,!1,0,0);f.drawArrays(f.TRIANGLES,0,3);f.disableVertexAttribArray(this.blitShader.attribs.pos); 34365f.bindBuffer(f.ARRAY_BUFFER,null)}.bind(this),h=new Texture(this.gl,c);this.cache[d]=h;var k=0,l=0,n=function(){if(k&&l){var a,b;l.width*l.height>k.width*k.height?(a=l.width,b=l.height):(a=k.width,b=k.height);h.desc.width=a;h.desc.height=b;if(a<=f.limits.viewportSizes[0]&&b<=f.limits.viewportSizes[1]){var c={clamp:!0};k.width==a&&k.height==b?(h.loadImage(k,f.RGBA),a=new Framebuffer(f,{color0:h,ignoreStatus:!0}),TextureCache.closeImage(k)):(b=new Texture(f,c),b.loadImage(k,f.RGB),TextureCache.closeImage(k), 34366h.loadArray(null),a=new Framebuffer(f,{color0:h,ignoreStatus:!0}),a.bind(),g(b),b.destroy());b=new Texture(f,c);b.loadImage(l,f.RGB);TextureCache.closeImage(l);a.bind();f.colorMask(!1,!1,!1,!0);g(b);f.colorMask(!0,!0,!0,!0);b.destroy();Framebuffer.bindNone(f);h.rebuildMips()}else{c=document.createElement("canvas");c.width=a;c.height=b;var d=c.getContext("2d");d.drawImage(k,0,0);TextureCache.closeImage(k);c=d.getImageData(0,0,a,b);c=new Uint8Array(c.data.buffer,c.data.byteOffset,c.data.length);d.drawImage(l, 343670,0);TextureCache.closeImage(l);d=d.getImageData(0,0,a,b).data;a=a*b*4;for(b=0;b<a;b+=4)c[b+3]=d[b];h.loadArray(c)}TextureCache.closeImage(l)}}.bind(this);TextureCache.parseFile(a,function(a){k=a;n()});TextureCache.parseFile(b,function(a){l=a;n()});return h}; 34368TextureCache.parseFile=function(a,b,c){var d=c||new Image;if("undefined"!=typeof URL&&"undefined"!=typeof URL.createObjectURL){a=new Blob([a.data],{type:a.type});var e=URL.createObjectURL(a);d.onload=function(){URL.revokeObjectURL(e);b&&b(d)};d.src=e}else{a=new Blob([a.data],{type:a.type});var f=new FileReader;f.onload=function(a){d.src=f.result};d.onload=function(){b&&b(d)};f.readAsDataURL(a)}};TextureCache.closeImage=function(a){a&&256<a.width*a.height&&(a.onload=null,a.onerror=null,a.src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D")};function TimelineSlider(a,b){this.name="none";this.debugString="";this.knobControlRect=new ControlRect(a);this.controlRect=new ControlRect(a);var c=document.createElement("div");c.id="sliderUI";c.style.position="absolute";c.style.overflow="hidden";c.style["-moz-user-select"]="none";c.style["-khtml-user-select"]="none";c.style["-webkit-user-select"]="none";c.style["-ms-user-select"]="none";
34368this.controlRect.linkedControl=c;this.backgroundControl=0;this.controlRect.registerChildControlRect(this.knobControlRect); 34369this.knobControlRect.setOpacity(0.65);this.sliderPercent=this.pixelsY=this.pixelsX=0;this.draggingSlider=!1;this.guiScreen=a;b.addImageElement(this.knobControlRect,"animationknob"+a.imageSetNumber+"x.png")} 34370TimelineSlider.prototype.setBackground3x1=function(a,b,c,d){var e=8/this.controlRect.getScreenHeight();this.backgroundControl=a.addTextButton("",0,(1-e)/2,1,e,1);this.backgroundControl.defaultAlpha=1;this.backgroundControl.setBackground3x1(a,0,0,b,c,d,4);this.backgroundControl.controlRect.xPercent=this.controlRect.xPercent;this.backgroundControl.controlRect.widthPercent=this.controlRect.widthPercent;this.controlRect.linkedControl.style.zIndex="3";this.setupCallbacks()}; 34371TimelineSlider.prototype.setSize=function(a,b){this.pixelsX=a;this.pixelsY=b;var c=24/b;this.knobWidthPercent=24/a;this.knobControlRect.xPercent=0.5-this.knobWidthPercent/2;this.knobControlRect.yPercent=(1-c)/2+-1/b;this.knobControlRect.widthPercent=this.knobWidthPercent;this.knobControlRect.heightPercent=c;this.controlRect.updateElement();this.backgroundControl.controlRect.xPercent=this.controlRect.xPercent;this.backgroundControl.controlRect.widthPercent=this.controlRect.widthPercent;this.backgroundControl.controlRect.updateElement()}; 34372TimelineSlider.prototype.setSliderPercent=function(a){0>a&&(a=0);1<a&&(a=1);this.sliderPercent=a;this.knobControlRect.xPercent=a-this.knobWidthPercent/2;this.knobControlRect.updateElement()}; 34373TimelineSlider.prototype.setupCallbacks=function(){var a=function(a){if(this.draggingSlider){var b=this.backgroundControl.controlRect.linkedControl.getBoundingClientRect();this.setSliderPercent((a.clientX-b.left)/b.width);this.guiScreen.ui.viewer.scene.sceneAnimator.setAnimationProgress(this.sliderPercent,!0);this.guiScreen.ui.viewer.scene.sceneAnimator.paused&&(this.guiScreen.ui.viewer.scene.postRender.discardAAHistory(),this.guiScreen.ui.viewer.reDrawScene())}}.bind(this),b=function(a){this.draggingSlider= 34374!0;var b=this.backgroundControl.controlRect.linkedControl.getBoundingClientRect();this.setSliderPercent((a.clientX-b.left)/b.width);this.guiScreen.ui.viewer.scene.sceneAnimator.setAnimationProgress(this.sliderPercent,!0);this.guiScreen.ui.viewer.scene.sceneAnimator.lockPlayback=!0;this.guiScreen.ui.viewer.scene.sceneAnimator.paused&&(this.guiScreen.ui.viewer.scene.postRender.discardAAHistory(),this.guiScreen.ui.viewer.reDrawScene())}.bind(this),c=function(a){this.draggingSlider=!1;this.guiScreen.ui.viewer.scene.sceneAnimator.lockPlayback= 34375!1}.bind(this);this.guiScreen.ui.viewer.input.element.addEventListener("mousemove",a);this.guiScreen.ui.viewer.input.element.addEventListener("mouseup",c);this.backgroundControl.controlRect.linkedControl.addEventListener("mousemove",a);this.backgroundControl.controlRect.linkedControl.addEventListener("mousedown",b);this.backgroundControl.controlRect.linkedControl.addEventListener("mouseup",c);this.controlRect.linkedControl.addEventListener("mouseup",c)};function UI(a){this.viewer=a;this.stripData=a.stripData;a=this.container=document.createElement("div");a.id="marmosetUI";a.style.position="absolute";a.style.overflow="hidden";a.style["-moz-user-select"]="none";a.style["-khtml-user-select"]="none";a.style["-webkit-user-select"]="none";a.style["-ms-user-select"]="none";this.viewer.domRoot.appendChild(a);this.guiScreen=new GUIScreen(this)} 34376UI.prototype.setSize=function(a,b){this.container.width=a|0;this.container.height=b|0;this.container.style.width=a+"px";this.container.style.height=b+"px";this.guiScreen.setSize(this.container.width,this.container.height)};UI.prototype.clearView=function(){for(;this.container.hasChildNodes();)this.container.removeChild(this.container.childNodes[0]);delete this.progressBar;delete this.thumbnail;delete this.fadeThumbnail;delete this.playButton;delete this.helpOverlay}; 34377UI.prototype.bindInput=function(a){a.onSingleTap.push(function(b,c){this.stripData.selectedStrip!=this.stripData.STRIP_NONE&&(b=2/a.element.clientWidth*b-1,c=1-2/a.element.clientHeight*c,this.stripData.selectStr
34377ip(b,c),this.stripData.selectedStrip==this.stripData.STRIP_MENU&&this.helpOverlay.active&&this.helpOverlay.toggle(),this.refreshUI(),this.viewer.wake())}.bind(this))};UI.sanitize=function(a){return a?a.replace(/<|>|\(|\)|$|%|=/g,""):a}; 34378UI.sanitizeURL=function(a){return a?0==a.indexOf("http://")||0==a.indexOf("https://")||0==a.indexOf("ftp://")?encodeURI(a):"http://"+encodeURI(a):a};UI.prototype.showFailure=function(a){this.container.innerHTML='<br><br><br><p style="text-align:center;color:#aaaaaa"><b>Marmoset Viewer could not initialize.</b><br><i>'+(a||"")+"</i>"}; 34379UI.prototype.showPreview=function(a){this.clearView();this.thumbnail=document.createElement("canvas");var b=this.container.width/this.container.height;this.thumbnail.height=this.viewer.mobile?200:300;this.thumbnail.width=this.thumbnail.height*b|0;this.thumbnail.style.width=this.thumbnail.style.height="100%";var b=this.thumbnail.getContext("2d"),c=b.fillStyle=b.createRadialGradient(this.thumbnail.width/2,this.thumbnail.height/2,(this.thumbnail.width+this.thumbnail.height)/2,this.thumbnail.width/2, 343800,0);c.addColorStop(0,"rgb(0,0,0)");c.addColorStop(1,"rgb(150,150,150)");b.fillStyle=c;b.fillRect(0,0,this.thumbnail.width,this.thumbnail.height);this.container.appendChild(this.thumbnail);this.playButton=document.createElement("input");this.playButton.type="image";this.playButton.src=marmoset.dataLocale+"play.png";this.playButton.style.position="absolute";this.playButton.style.left="50%";this.playButton.style.top="50%";this.playButton.style["-webkit-transform"]=this.playButton.style.transform="translate(-50%,-50%) scale(0.5,0.5)"; 34381this.playButton.style.opacity=0.5;this.playButton.style.outline="0px";this.playButton.onclick=function(){this.viewer.loadScene(this.viewer.sceneURL);this.container.removeChild(this.playButton);delete this.playButton}.bind(this);this.container.appendChild(this.playButton);a||fetchThumbnail(this.viewer.sceneURL,function(a){this.loadingImageURL||this.setThumbnail(a)}.bind(this))};UI.prototype.setThumbnailURL=function(a){(this.loadingImageURL=a)&&Network.fetchImage(this.loadingImageURL,this.setThumbnail.bind(this))}; 34382UI.prototype.setThumbnail=function(a){if(this.thumbnail)if(a.height>=this.container.height){var b=this.container.height/a.height;a.style.position="absolute";a.style.outline="0px";a.style.left="50%";a.style.top="50%";a.style["-webkit-transform"]=a.style.transform="translate(-50%,-50%) scale("+b+","+b+")";this.container.replaceChild(a,this.thumbnail);this.thumbnail=a}else{var c=this.thumbnail.getContext("2d"),d=this.thumbnail.width,e=this.thumbnail.height,b=e/a.height;c.drawImage(a,(d-a.width*b)/2, 343830,a.width*b,e);var f;try{f=c.getImageData(0,0,d,e)}catch(g){return}a=c.createImageData(d,e);for(var h=0;2>h;++h){for(var b=f.data,k=a.data,l=0,n=0;n<e;++n)for(var m=0;m<d;++m){for(var p=0,r=0,s=0,u=-2;2>=u;++u)for(var q=n+u,q=0>q?0:q>=e?e-1:q,x=-2;2>=x;++x)var w=m+x,w=0>w?0:w>=d?d-1:w,w=4*(q*d+w),p=p+b[w],r=r+b[w+1],s=s+b[w+2];k[l++]=p/25;k[l++]=r/25;k[l++]=s/25;k[l++]=255}b=f;f=a;a=b}c.putImageData(f,0,0)}}; 34384UI.prototype.showActiveView=function(){var a=this.thumbnail;this.clearView();a&&(this.fadeThumbnail=a,this.fadeThumbnail.style.opacity=1,this.container.appendChild(this.fadeThumbnail));if(!marmoset.noUserInterface){void 0===marmoset.largeUI&&(marmoset.largeUI=this.viewer.mobile);450>this.container.width&&(marmoset.largeUI=!1);var b=FullScreen.support(),b=!0,a=1;window.devicePixelRatio&&(2<window.devicePixelRatio?a=4:1<window.devicePixelRatio&&(a=2));marmoset.largeUI&&4>a&&(a*=2);var c=marmoset.largeUI? 343850.3:0.5;this.stripText=[];for(var d=0;d<this.stripData.labels.length;++d){this.stripText[d]=document.createElement("div");this.stripText[d].style.position="absolute";this.stripText[d].style.cursor="pointer";this.stripText[d].style.pointerEvents="none";this.container.appendChild(this.stripText[d]);var e=document.createElement("div");e.style.color="white";e.style.opacity=0.5;e.style.fontFamily="Arial";e.style.textShadow="2px 2px 3px #000000";e.innerHTML=this.stripData.labels[d];this.stripText[d].appendChild(e); 34386this.stripText[d].txt=e;
34386e=document.createElement("div");e.style.width="10000px";e.style.height="2px";e.style.backgroundColor="#AAAAAA";e.style.opacity=1;e.style.position="absolute";e.style.left=e.style.top="-1px";this.stripText[d].appendChild(e);this.stripText[d].line=e}this.sigCluster=document.createElement("div");this.sigCluster.style.position="absolute";this.sigCluster.style.right=marmoset.largeUI?"12px":"9px";this.sigCluster.style.left="0px";this.sigCluster.style.top="6px";this.sigCluster.style.height= 34387marmoset.largeUI?"64px":"32px";this.logo=document.createElement("div");this.logo.style.position="absolute";this.logo.style.right=marmoset.largeUI?"-4px":"1px";this.logo.style.top=marmoset.largeUI?"0px":"4px";this.logo.title="Made with Marmoset Toolbag";var f=document.createElement("input");f.type="image";f.src=marmoset.dataLocale+"logo"+a+"x.png";f.style.border="none";f.style.width=f.style.height=marmoset.largeUI?"72px":"36px";f.style.border="0px";f.style.outline="0px";f.style.opacity=c;f.onmouseover= 34388function(){this.style.opacity=1}.bind(f);f.onmouseout=function(){this.style.opacity=c}.bind(f);f.onclick=function(a){window.open("http://www.marmoset.co/viewer?utm_source=inapp&utm_medium=menu&utm_campaign=viewer","_blank");this.style.opacity=c}.bind(f,this);d=new XMLHttpRequest;d.open("HEAD",f.src,!0);d.onload=function(a){this.logo.appendChild(a)}.bind(this,f);d.send();this.sigCluster.appendChild(this.logo);d=this.viewer.scene.metaData;d.title=UI.sanitize(d.title);d.subtitle=UI.sanitize(d.subtitle); 34389d.author=UI.sanitize(d.author);d.link=UI.sanitizeURL(d.link);var g=d.title&&0<d.title.length,e=d.subtitle&&0<d.subtitle.length,f=d.author&&0<d.author.length,h=d.link&&0<d.link.length;if(g||e||f){g||(d.title="Art");var k=!g&&!e,l=document.createElement("div");l.style.position="absolute";l.style.right=marmoset.largeUI?"74px":"46px";l.style.top="5px";l.style.width="1px";l.style.height=marmoset.largeUI?k?"21px":"35px":k?"18px":"31px";l.style.opacity=0.25;l.style.backgroundColor="white";this.sigCluster.appendChild(l); 34390this.sigCluster.line=l;k=document.createElement("a");h&&(k.href=d.link);k.style.position="absolute";k.style.right=marmoset.largeUI?"86px":"58px";k.style.top="6px";k.style.textAlign="right";k.style.color="white";k.style.fontFamily="Arial";k.style.fontSize=marmoset.largeUI?"14px":"12px";k.style.textDecoration="none";k.target="_blank";l=document.createElement("font");l.style.color="#FFFFFF";l.style.opacity=0.5;l.style.textDecoration="none";l.style.textShadow="1px 1px 2px rgba(0,0,0,0.7)";l.innerHTML= 34391d.title;f&&(l.innerHTML=g&&!e?l.innerHTML+"<br>by ":l.innerHTML+" by ");k.appendChild(l);g=document.createElement("font");g.style.color="#FF0044";g.style.opacity=1;g.style.textShadow="1px 1px 2px rgba(0,0,0,0.35)";g.innerHTML=d.author;k.appendChild(g);f=document.createElement("font");f.style.color="#FFFFFF";f.style.opacity=0.5;f.style.textShadow="1px 1px 2px rgba(0,0,0,0.7)";e&&(f.innerHTML="<br>",f.innerHTML+=d.subtitle);k.appendChild(f);h&&(k.onmouseover=function(a,b,c){a.style.opacity=c.style.opacity= 343921;b.style.textDecoration="underline"}.bind(k,l,g,f),k.onmouseout=function(a,b,c){a.style.opacity=c.style.opacity=0.5;b.style.textDecoration="none"}.bind(k,l,g,f));this.sigCluster.appendChild(k);this.sigCluster.sceneTitle=k}this.container.appendChild(this.sigCluster);this.sigCluster.active=!0;this.sigCluster.toggle=function(){this.sceneTitle&&this.line&&(this.active?(this.removeChild(this.sceneTitle),this.removeChild(this.line)):(this.appendChild(this.sceneTitle),this.appendChild(this.line)));this.active= 34393!this.active}.bind(this.sigCluster);this.helpOverlay=document.createElement("div");this.helpOverlay.style.pointerEvents="none";this.container.appendChild(this.helpOverlay);this.hideSigOnHelp=d=450>this.container.width;this.hideSigOnStrips=!0;g=[8,8];d?(e=198+2*g[0],f=258+2*g[1]):(e=354+2*g[0],f=218+2*g[1]);h=document.createElement("div");h.style.position="absolute";h.style.width=h.style.height="100%";this.helpOverlay.contents=h;h=document.createElement("div");h.style.position="absolute";h.style.right= 34394marmoset.largeUI?"92px":"54px";h.style.top=d?"16px":"48px";h.style.width=e+"px";h.style.height=f+"px";this.helpOverlay.contents.appendChild(h);f=document.createElement("div");f.style.position="absolute";f.style.width="100%";f.style.height="100%";f.style.backgroundColor="black";f.style.opacity="0.65";f.style.borderRadius="16px";h.appendChild(f);f=document.createElement("input");f.type="button";f.value="x";f.style.position="absolute";f.style.color="#FFFFFF";f.style.fontWeight="bolder";f.style.backgroundColor=
34395"rgba(0,0,0,0.0)";f.style.border="0px";f.style.outline="0px";f.style.fontSize=marmoset.largeUI?"16pt":"10pt";f.style.right=marmoset.largeUI?"2px":"8px";f.style.top=marmoset.largeUI?"0px":"4px";f.style.width=f.style.height=marmoset.largeUI?"32px":"16px";f.style.pointerEvents="auto";f.style.cursor="pointer";f.onclick=function(a){this.helpOverlay.toggle();this.refreshUI()}.bind(this,f);h.appendChild(f);f=document.createElement("center");f.style.position="absolute";f.style.left=g[0]-4+"px";f.style.right= 34396g[0]+4+"px";f.style.top=f.style.bottom=g[1]+"px";f.style.paddingTop="8px";d||(f.style.paddingRight="8px");h.appendChild(f);h=f;g=(this.viewer.mobile?"M":"PC")+(2<a?4:2)+"x.png";f=document.createElement("img");f.src=marmoset.dataLocale+"helprotate"+g;f.style.width="66px";f.style.height="90px";h.appendChild(f);f=document.createElement("img");f.src=marmoset.dataLocale+"helpzoom"+g;f.style.width="66px";f.style.height="90px";h.appendChild(f);f=document.createElement("img");f.src=marmoset.dataLocale+"helpmove"+ 34397g;f.style.width="66px";f.style.height="90px";h.appendChild(f);f=document.createElement("img");f.src=marmoset.dataLocale+"helpreset"+g;f.style.width="66px";f.style.height="90px";h.appendChild(f);f=document.createElement("img");f.src=marmoset.dataLocale+"helplights"+g;f.style.position="relative";d||(f.style.left="8px");f.style.width="66px";f.style.height="90px";h.appendChild(f);g=document.createElement("a");g.href="http://www.marmoset.co/viewer?utm_source=inapp&utm_medium=menu&utm_campaign=viewer"; 34398g.target="_blank";g.style.pointerEvents="auto";h.appendChild(g);k=document.createElement("img");k.src=marmoset.dataLocale+"helpshadow.png";k.style.position="absolute";k.style.left=0.5*e-(d?65:116)+"px";k.style.bottom=d?"6px":"8px";k.style.width=d?"116px":"232px";k.style.opacity=0;g.appendChild(k);k.targetOpacity=0;g.onmouseover=function(){this.targetOpacity=0.65}.bind(k);g.onmouseout=function(){this.targetOpacity=0}.bind(k);window.setInterval(function(){this.style.opacity=0.1*this.targetOpacity+0.9* 34399this.style.opacity}.bind(k),20);f=document.createElement("img");f.src=marmoset.dataLocale+"helptitle.png";f.style.position="absolute";f.style.left=0.5*e-(d?65:116)+"px";f.style.bottom=d?"8px":"12px";f.style.width=d?"116px":"232px";g.appendChild(f);e=document.createElement("div");e.style.position="absolute";e.style.left=0;e.style.right=d?"30px":"108px";e.style.bottom=d?"-4px":"4px";e.style.textAlign="right";e.style.fontFamilly="Arial";h.appendChild(e);d=document.createElement("font");d.style.fontSize= 34400"9pt";d.style.fontFamily="Arial";e.appendChild(d);g=document.createElement("a");g.style.color="#FF0044";g.style.textDecoration="none";g.style.pointerEvents="auto";g.innerHTML="www.marmoset.co/viewer";g.href="http://www.marmoset.co/viewer?utm_source=inapp&utm_medium=menu&utm_campaign=viewer";g.target="_blank";g.onmouseover=function(a){this.style.textDecoration="underline";a.targetOpacity=0.65}.bind(g,k);g.onmouseout=function(a){this.style.textDecoration="none";a.targetOpacity=0}.bind(g,k);d.appendChild(g); 34401this.helpOverlay.active=!1;this.helpOverlay.toggle=function(a){this.active?this.removeChild(this.contents):this.appendChild(this.contents);this.active=!this.active}.bind(this.helpOverlay,this.viewer);this.menuCluster=document.createElement("div");this.menuCluster.style.position="absolute";this.menuCluster.style.right=marmoset.largeUI?"4px":"8px";this.menuCluster.style.top=marmoset.largeUI?"70px":"40px";marmoset.largeUI?(this.menuCluster.style.width="72px",this.menuCluster.style.height="64px"):(this.menuCluster.style.width= 34402"36px",this.menuCluster.style.height="36px");h=document.createElement("div");h.style.left=h.style.top="0px";h.style.width=h.style.height="100%";this.menuCluster.contents=h;this.menuCluster.appendChild(h);d=0;e=function(a,b,c,d,e){var f=document.createElement("input");f.type="image";f.src=marmoset.dataLocale+c;f.style.position="absolute";f.style.left="0px";f.style.bottom=-100*d+"%";f.style.border="none";f.style.outline="0px";f.title=b;f.style.opacity=e;marmoset.largeUI?(f.style.width="64px",f.style.height= 34403"48px"):(f.style.width="32px",f.style.height="24px");f.onmouseover=function(a){this.style.opacity=a}.bind(f,1);f.onmouseout=function(a){this.style.opacity=a}.bind(f,e);f.onmouseup=function(a){this.style.opacity=a}.bind(f,e);b=new XMLHttpRequest;b.open("HEAD",f.src,!0);b.onload=function(a){a.appendChild(this)}.bind(f,a);b.send();return f};b&&(b=e(this.menuCluster.contents,"Full Screen","fullscreen"+a+"x.png",d++,c),b.onclick=function(a){FullScreen.active()?FullScreen.end():FullScreen.begin(this.viewer.domRoot, 34404this.viewer.fullscreenChange.bind(this.viewer));a.style.opacity=c;this.refreshUI()}.bind(this,b));b=e(this.menuCluster.contents,"Layer Views","strips"+a+"x.png",d++,c);
34404b.onclick=function(a){this.stripData.toggleMenu();this.helpOverlay.active&&this.helpOverlay.toggle();this.viewer.wake();this.refreshUI()}.bind(this,b);b=e(this.menuCluster.contents,"Help","help"+a+"x.png",d++,c);b.onclick=function(a){this.stripData.selectedStrip==this.stripData.STRIP_MENU&&this.stripData.toggleMenu();this.helpOverlay.toggle(); 34405this.refreshUI()}.bind(this,b);this.guiScreen&&this.guiScreen.setupActiveView(this);this.container.appendChild(this.menuCluster);this.menuCluster.active=!0;this.menuCluster.toggle=function(){this.active?this.removeChild(this.contents):this.appendChild(this.contents);this.active=!this.active}.bind(this.menuCluster);void 0!==marmoset.hostImage&&(marmoset.hostURL&&(g=document.createElement("a"),g.href=marmoset.hostURL,g.target="_blank"),f=document.createElement("img"),f.src=marmoset.hostImage,f.style.position= 34406"absolute",f.style.top="4px",f.style.left="4px",f.style.opacity=0.65,f.style["-webkit-transform"]=f.style.transform="translate(-50%,-50%) scale(0.5,0.5) translate(50%,50%)",marmoset.hostURL?(f.onmouseover=function(){this.style.opacity=1}.bind(f),f.onmouseout=function(){this.style.opacity=0.5}.bind(f),g.appendChild(f),this.hostLogo=g):this.hostLogo=f,d=new XMLHttpRequest,d.open("HEAD",f.src,!0),d.onload=function(){this.container.appendChild(this.hostLogo)}.bind(this),d.send());this.sceneStats=document.createElement("text"); 34407this.sceneStats.style.position="absolute";this.sceneStats.style.left="9px";this.sceneStats.style.bottom="8px";this.sceneStats.style.color="gray";this.sceneStats.style.fontFamily="Arial";this.sceneStats.style.fontSize="75%";for(d=b=a=0;d<this.viewer.scene.meshes.length;++d)e=this.viewer.scene.meshes[d],a+=e.indexCount/3,b+=e.vertexCount;this.sceneStats.innerHTML="Triangles: "+(a|0).toLocaleString()+"<br>Vertices: "+(b|0).toLocaleString();marmoset.showFrameTime&&(this.frameTimer=document.createElement("text"), 34408this.frameTimer.style.position="absolute",this.frameTimer.style.left=this.frameTimer.style.top="5px",this.frameTimer.style.color="gray",this.frameTimer.style.fontSize="75%",this.container.appendChild(this.frameTimer),this.frameTimer.innerHTML="--",this.frameCount=1E20);this.animateStrips()}}; 34409UI.prototype.refreshUI=function(){if(this.sigCluster){var a=!1,b=this.stripData.selectedStrip==this.stripData.STRIP_MENU;this.hideSigOnStrips&&(a=a||b);this.hideSigOnHelp&&(a=a||this.helpOverlay.active);
34409this.sigCluster.active==a&&this.sigCluster.toggle()}}; 34410UI.prototype.signalLoadProgress=function(a,b){if(this.thumbnail){if(!this.progressBar){var c=document.createElement("div");c.style.backgroundColor="rgb(30,30,30)";c.style.opacity=0.5;c.style.position="absolute";c.style.left="20%";c.style.width="60%";c.style.bottom="30%";c.style.height="2px";this.progressBar=document.createElement("div");this.progressBar.style.backgroundColor="white";this.progressBar.style.position="absolute";this.progressBar.style.left=this.progressBar.style.bottom="0px";this.progressBar.style.height= 34411"100%";this.progressBar.style.width="0px";c.appendChild(this.progressBar);this.container.appendChild(c);this.playButton&&(this.container.removeChild(this.playButton),delete this.playButton)}this.progressBar.style.width=0>=b?(100*a/(2097152+a)|0)+"%":(100*a/b|0)+"%"}};UI.prototype.animating=function(){return!!this.fadeThumbnail||!!this.frameTimer}; 34412UI.prototype.animate=function(){this.fadeThumbnail&&(this.fadeThumbnailTimer=this.fadeThumbnailTimer||Date.now(),this.fadeThumbnail.style.opacity=1-0.0015*(Date.now()-this.fadeThumbnailTimer),0.01>this.fadeThumbnail.style.opacity&&(this.container.removeChild(this.fadeThumbnail),delete this.fadeThumbnail,delete this.fadeThumbnailTimer));if(this.frameTimer&&(this.frameCount++,60<=this.frameCount)){var a=(new Date).getTime();if(void 0!==this.frameTime){var b=(a-this.frameTime)/this.frameCount,b=Math.floor(100* 34413b)/100;this.frameTimer.innerHTML=b+" ms";this.frameTimer.style.color=32>b?"green":"red"}this.frameCount=0;this.frameTime=a}this.guiScreen&&this.guiScreen.playbackControls&&(a=this.guiScreen.playbackControls.timelineSlider,a.draggingSlider?this.viewer.scene.sceneAnimator.setAnimationProgress(a.sliderPercent,!0):a.setSliderPercent(this.viewer.scene.sceneAnimator.animationProgress));if(this.sceneStats){for(var c=b=a=0;c<this.viewer.scene.meshes.length;++c)var d=this.viewer.scene.meshes[c],a=a+d.indexCount/ 344143,b=b+d.vertexCount;this.sceneStats.innerHTML="Triangles: "+(a|0).toLocaleString()+"<br>Vertices: "+(b|0).toLocaleString();this.viewer.scene.sceneAnimator&&this.viewer.scene.sceneAnimator.showPlayControls&&(this.sceneStats.innerHTML+="<br><br><br><br>");a=!!this.sceneStats.parentElement;b=this.stripData.active()||!1;a&&!b?(this.container.removeChild(this.sceneStats),this.hostLogo&&this.container.appendChild(this.hostLogo)):!a&&b&&(this.container.appendChild(this.sceneStats),this.hostLogo&&this.container.removeChild(this.hostLogo))}this.refreshUI(); 34415if(this.stripData.animationActive||this.stripData.active())this.animateStrips(),this.stripData.animationActive&&this.viewer.wake()}; 34416UI.prototype.animateStrips=function(){if(this.stripText)for(var a=Math.atan(this.viewer.canvas.height/this.viewer.canvas.width/this.stripData.stripSlant),b=0;b<this.stripData.labels.length;++b){var c=this.stripData.strips[b],c=c-this.stripData.stripSlant,c=0.5+0.5*c;b==this.stripData.selectedStrip?(this.stripText[b].style["-ms-transform"]=this.stripText[b].style["-webkit-transform"]=this.stripText[b].style.transform="none",this.stripText[b].style.top="4px",this.stripText[b].style.left="0px",this.stripText[b].style.width= 34417"150px",this.stripText[b].txt.style.textAlign="center",this.stripText[b].txt.style.background="rgba(0, 0, 0, 0.75)",this.stripText[b].txt.style.background="-webkit-linear-gradient(left, rgba(0,0,0,0.75), rgba(0,0,0,0))",this.stripText[b].txt.style.background="-o-linear-gradient(left, rgba(0,0,0,0.75), rgba(0,0,0,0))",this.stripText[b].txt.style.background="-moz-linear-gradient(left, rgba(0,0,0,0.75), rgba(0,0,0,0))",this.stripText[b].txt.style.background="linear-gradient(left, rgba(0,0,0,0.75), rgba(0,0,0,0))", 34418this.stripText[b].txt.style.paddingLeft="32px",this.stripText[b].txt.style.paddingTop="6px",this.stripText[b].txt.style.paddingBottom="4px",this.stripText[b].txt.style.textShadow="1px 1px 2px rgba(0,0,0,0.7)",this.stripText[b].line.style.opacity=0.5,this.stripText[b].line.style.top="100%",this.stripText[b].line.style.width="100%",this.stripText[b].line.style.height="1px"):(this.stripText[b].style["-ms-transform"]=this.stripText[b].style["-webkit-transform"]=this.stripText[b].style.transform="translate(-50%, -50%) rotate("+ 34419a+"rad) translate(50%, 50%)",this.stripText[b].style.left=100*c+"%",this.stripText[b].style.top="0px",this.stripText[b].style.width="85px",this.stripText[b].txt.style.textAlign="left",this.stripText[b].txt.style.background="none",this.stripText[b].txt.style.paddingLeft="8px",this.stripText[b].txt.style.paddingTop="6px",this.stripText[b].txt.style.paddingBottom="4px",this.stripText[b].txt.style.textShadow="2px 0px 3px rgba(0,0,0,0.7)",this.stripText[b].line.style.opacity=1,this.stripText[b].line.style.top= 34420"-1px",this.stripText[b].line.style.width="10000px",this.stripText[b].line.style.height="2px")}};var Vect={type:Float32Array,create:function(a,b,c,d){var e=new Vect.type(4);e[0]=a;e[1]=b;e[2]=c;e[3]=d;return e},empty:function(){return new Vect.type(4)},set:function(a,b,c,d,e){a[0]=b;a[1]=c;a[2]=d;a[3]=e},copy:function(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3]},add:function(a,b,c){a[0]=b[0]+c[0];a[1]=b[1]+c[1];a[2]=b[2]+c[2];a[3]=b[3]+c[3];return a},sub:function(a,b,c){a[0]=b[0]-c[0];a[1]=b[1]-c[1];a[2]=b[2]-c[2];a[3]=b[3]-c[3];return a},scale:function(a,b,c){a[0]=c[0]*b;a[1]=c[1]*b;a[2]=c[2]* 34421b;a[3]=c[3]*b;return a},mul:function(a,b,c){a[0]=b[0]*c[0];a[1]=b[1]*c[1];a[2]=b[2]*c[2];a[3]=b[3]*c[3];return a},mad:function(a,b,c,d){a[0]=b[0]*c[0]+d[0];a[1]=b[1]*c[1]+d[1];a[2]=b[2]*c[2]+d[2];a[3]=b[3]*c[3]+d[3];return a},smad:function(a,b,c,d){a[0]=b*c[0]+d[0];a[1]=b*c[1]+d[1];a[2]=b*c[2]+d[2];a[3]=b*c[3]+d[3];return a},negate:function(a,b){a[0]=-b[0];a[1]=-b[1];a[2]=-b[2];return a},negate4:function(a,b){a[0]=-b[0];a[1]=-b[1];a[2]=-b[2];a[3]=-b[3];return a},length:function(a){var b=a[0],c=a[1]; 34422a=a[2];return Math.sqrt(b*b+c*c+a*a)},distance:function(a,b){var c=a[0]-b[0],d=a[1]-b[1],e=a[2]-b[2];return Math.sqrt(c*c+d*d+e*e)},dot:function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]},dot4:function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]},normalize:function(a,b){var c=b[0],d=b[1],e=b[2],f=Math.sqrt(c*c+d*d+e*e);if(0==f)return Vect.set(a,0,0,0,0);f=1/f;a[0]=c*f;a[1]=d*f;a[2]=e*f;return a},cross:function(a,b,c){a[0]=b[1]*c[2];a[0]+=-b[2]*c[1];a[1]=b[2]*c[0]-b[0]*c[2];a[2]=b[0]*c[1]- 34423b[1]*c[0];return a},lerp:function(a,b,c,d){var e=1-d;a[0]=b[0]*e+c[0]*d;a[1]=b[1]*e+c[1]*d;a[2]=b[2]*e+c[2]*d;return a},lerp4:function(a,b,c,d){var e=1-d;a[0]=b[0]*e+c[0]*d;a[1]=b[1]*e+c[1]*d;a[2]=b[2]*e+c[2]*d;a[3]=b[3]*e+c[3]*d;return a},min:function(a,b,c){a[0]=Math.min(b[0],c[0]);a[1]=Math.min(b[1],c[1]);a[2]=Math.min(b[2],c[2]);a[3]=Math.min(b[3],c[3]);return a},max:function(a,b,c){a[0]=Math.max(b[0],c[0]);a[1]=Math.max(b[1],c[1]);a[2]=Math.max(b[2],c[2]);a[3]=Math.max(b[3],c[3]);return a},projectOnPlane:function(a, 34424b,c,d){var e=Vect.empty();Vect.sub(e,b,c);c=Vect.dot(e,d);smad(a,-c,normal,b);return a}};function View(a){this.pivot=[0,0,0];this.rotation=[0,0];this.radius=1;this.nearPlane=0.3;this.fov=45;this.size=[1,1];this.transform=Matrix.empty();this.viewMatrix=Matrix.empty();this.projectionMatrix=Matrix.empty();this.viewProjectionMatrix=Matrix.empty();a?this.loadView(a,!0):(this.saveResetView(),this.updateView(),this.updateProjection())} 34425View.prototype.saveResetView=function(){this.resetDesc={angles:[this.rotation[0],this.rotation[1]],pivot:[this.pivot[0],this.pivot[1],this.pivot[2]],limits:this.limits,orbitRadius:this.radius,fov:this.fov}};View.prototype.loadView=function(a,b){a&&(this.rotation[0]=a.angles[0],this.rotation[1]=a.angles[1],this.pivot[0]=a.pivot[0],this.pivot[1]=a.pivot[1],this.pivot[2]=a.pivot[2],this.radius=a.orbitRadius,this.fov=a.fov,this.limits=a.limits,b&&this.saveResetView(),this.updateView(),this.updateProjection())}; 34426View.prototype.reset=function(){this.loadView(this.resetDesc)}; 34427View.prototype.updateView=function(){if(void 0!==this.limits){if
34427(this.limits.angles){var a=this.limits.angles.x,b=this.limits.angles.y;if(void 0!==a){var c=this.rotation[0]-a.offset,a=Math.min(Math.max(c,a.min),a.max);this.rotation[0]+=a-c}void 0!==b&&(c=this.rotation[1]-b.offset,a=Math.min(Math.max(c,b.min),b.max),this.rotation[1]+=a-c)}void 0!==this.limits.orbitRadius&&(b=this.limits.orbitRadius.min,c=this.limits.orbitRadius.max,void 0!==b&&(this.radius=Math.max(this.radius,b)),void 0!==c&&(this.radius= 34428Math.min(this.radius,c)));void 0!==this.limits.pan&&(b=this.limits.pan,c=this.resetDesc.pivot,b.x&&(this.pivot[0]=c[0]),b.y&&(this.pivot[1]=c[1]),b.z&&(this.pivot[2]=c[2]))}Matrix.translation(this.transform,0,0,this.radius);b=Matrix.rotation(Matrix.empty(),this.rotation[0],0);c=Matrix.rotation(Matrix.empty(),this.rotation[1],1);Matrix.mul(b,c,b);Matrix.mul(this.transform,b,this.transform);this.transform[12]+=this.pivot[0];this.transform[13]+=this.pivot[1];this.transform[14]+=this.pivot[2];Matrix.invert(this.viewMatrix, 34429this.transform);Matrix.mul(this.viewProjectionMatrix,this.viewMatrix,this.projectionMatrix)};View.prototype.updateProjection=function(a){Matrix.perspectiveInfinite(this.projectionMatrix,this.fov,this.size[0]/this.size[1],this.nearPlane,a);Matrix.mul(this.viewProjectionMatrix,this.projectionMatrix,this.viewMatrix)};function WebViewer(a,b,c,d){this.mobile=!!/Android|iPhone|iPod|iPad|Windows Phone|IEMobile|BlackBerry|webOS/.test(navigator.userAgent);this.mobileFast=!!/iPhone|iPad/.test(navigator.userAgent);var e;if(e=!this.mobile)a:{e=document.createElement("canvas");e.width=e.height=16;if(e=e.getContext("webgl",{})||e.getContext("experimental-webgl",{})){var f=e.getExtension("WEBGL_debug_renderer_info");if(f){e=e.getParameter(f.UNMASKED_RENDERER_WEBGL);e=!!/Intel|INTEL/.test(e);break a}}e=!1}this.desktopSlow= 34430e;this.domRoot=document.createElement("div");this.domRoot.style.width=a+"px";this.domRoot.style.height=b+"px";this.initCanvas(a,b);this.scene=this.input=null;this.sceneURL=c;this.sleepCounter=8;this.onLoad=null;this.stripData=new StripData;this.ui=new UI(this);this.ui.setSize(a,b);this.ui.showPreview(d)} 34431WebViewer.prototype.initCanvas=function(a,b){this.canvas&&this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);this.canvas=document.createElement("canvas");this.pixelRatio=window.devicePixelRatio||1;if(this.mobile){var c=this.mobileFast?1.5:1;this.pixelRatio=this.pixelRatio>c?c:this.pixelRatio}else this.desktopSlow&&(this.pixelRatio=1);this.canvas.width=a*this.pixelRatio;this.canvas.height=b*this.pixelRatio;this.canvas.style.width=a+"px";this.canvas.style.height=b+"px";this.canvas.style.position= 34432"absolute";this.domRoot.appendChild(this.canvas)}; 34433WebViewer.prototype.initGL=function(){var a={alpha:!!marmoset.transparentBackground,depth:!1,stencil:!1,antialias:!1,premultipliedAlpha:!!marmoset.transparentBackground,preserveDrawingBuffer:!1},a=this.gl=this.canvas.getContext("webgl",a)||this.canvas.getContext("experimental-webgl",a);if(!this.gl)return this.ui.showFailure('Please <a href="http://get.webgl.org/" target=_blank>check<a/> to ensure your browser has support for WebGL.'),!1;this.canvas.addEventListener("webglcontextlost",function(a){a.preventDefault()}.bind(this), 34434!1);this.canvas.addEventListener("webglcontextrestored",function(a){this.loadScene(this.sceneURL)}.bind(this),!1);a.ext={textureAniso:a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic"),textureFloat:a.getExtension("OES_texture_float"),textureFloatLinear:a.getExtension("OES_texture_float_linear"),textureHalf:a.getExtension("OES_texture_half_float"),textureHalfLinear:a.getExtension("OES_texture_half_float_linear"), 34435textureDepth:a.getExtension("WEBGL_depth_texture"),colorBufferFloat:a.getExtension("WEBGL_color_buffer_float"),colorBufferHalf:a.getExtension("EXT_color_buffer_half_float"),index32bit:a.getExtension("OES_element_index_uint"),loseContext:a.getExtension("WEBGL_lose_context"),derivatives:a.getExtension("OES_standard_derivatives"),renderInfo:a.getExtension("WEBGL_debug_renderer_info")};a.limits={textureSize:a.getParameter(a.MAX_TEXTURE_SIZE),textureCount:a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),varyings:a.getParameter(a.MAX_VARYING_VECTORS), 34436vertexAttribs:a.getParameter(a.MAX_VERTEX_ATTRIBS),vertexUniforms:a.getParameter(a.MAX_VERTEX_UNIFORM_VECTORS),fragmentUniforms:a.getParameter(a.MAX_FRAGMENT_UNIFORM_VECTORS),viewportSizes:a.getParameter(a.MAX_VIEWPORT_DIMS),vendor:a.getParameter(a.VENDOR),version:a.getParameter(a.VERSION)};a.hints={mobile:this.mobile,pixelRatio:this.pixelRatio};a.enable(a.DEPTH_TEST);a.shaderCache=new ShaderCache(a);a.textureCache=new TextureCache(a);this.allocBacking();return!0}; 34437WebViewer.prototype.allocBacking=function(){var a=this.gl,b=!1,c={width:this.canvas.width,height:this.canvas.height};this.mainColor=new Texture(a,c);this.mainDepth=null;a.ext.textureDepth&&(this.mainDepth=new Texture(a,{width:this.canvas.width,height:this.canvas.height,nofilter:!0}),this.mainDepth.loadArray(null,a.DEPTH_COMPONENT,a.UNSIGNED_INT));a.ext.textureHalf&&a.ext.textureHalfLinear&&(this.mainColor.loadArray(null,a.RGBA,a.ext.textureHalf.HALF_FLOAT_OES),this.mainBuffer=new Framebuffer(a,{color0:this.mainColor, 34438depth:this.mainDepth,createDepth:!this.mainDepth}),b=this.mainBuffer.valid);!b&&a.ext.textureFloat&&a.ext.textureFloatLinear&&!a.hints.mobile&&(this.mainColor.loadArray(null,a.RGBA,a.FLOAT),this.mainBuffer=new Framebuffer(a,{color0:this.mainColor,depth:this.mainDepth,createDepth:!this.mainDepth}),b=this.mainBuffer.valid);for(;!b;)this.mainColor=new Texture(a,c),this.mainColor.loadArray(null,a.RGBA,a.UNSIGNED_BYTE),this.mainBuffer=new Framebuffer(a,{color0:this.mainColor,depth:this.mainDepth,createDepth:!this.mainDepth}), 34439b=this.mainBuffer.valid,c.width/=2,c.height/=2,this.mainDepth&&(this.mainDepth.destroy(),this.mainDepth=null);this.mainBufferNoDepth=new Framebuffer(a,{color0:this.mainColor})}; 34440WebViewer.prototype.loadScene=function(a){this.sceneURL=a||this.sceneURL;this.scene=this.input=null;if(this.initGL()&&this.sceneURL){var b=this.ui.signalLoadProgress.bind(this.ui);a=function(a){b(1,1);this.scene=new Scene(this.gl);this.scene.stripData=this.stripData;if(this.scene.load(new Archive(a)))if(2070>=this.scene.metaData.tbVersion)this.ui.showFailure("This .mview file is from an out-of-date beta version of Toolbag. Please re-export it with the new version. Thanks!");else{if(this.bindInput(), 34441this.requestFrame(this.updateLoad.bind(this)),this.onLoad)this.onLoad()}else this.ui.showFailure("Package file could not be read or is invali
34441d.")}.bind(this);var c=function(){this.ui.showFailure("Package file ("+this.sceneURL+") could not be retrieved.")}.bind(this);Network.fetchBinary(this.sceneURL,a,c,b)}}; 34442WebViewer.prototype.unload=function(){delete this.scene;delete this.input;delete this.ui;delete this.mainColor;delete this.mainBuffer;delete this.gl;var a=this.domRoot.clientWidth,b=this.domRoot.clientHeight;this.initCanvas(a,b);this.ui=new UI(this);this.ui.setSize(a,b);this.ui.showPreview();this.cancelFrame()}; 34443WebViewer.prototype.bindInput=function(){this.input=new Input(this.ui.container);this.input.onDrag.push(function(a,b,c,d){a=1-2.2/(Math.sqrt(c*c+d*d)+2.2);b=this.scene.view;b.rotation[1]-=0.4*c*a;b.rotation[0]-=0.4*d*a;b.rotation[0]=90<b.rotation[0]?90:b.rotation[0];b.rotation[0]=-90>b.rotation[0]?-90:b.rotation[0];b.updateView();this.wake()}.bind(this));this.input.onPan.push(function(a,b){var c=this.scene.view,d=c.fov/45*0.8*(c.radius/this.domRoot.clientHeight),e=-a*d,d=b*d;c.pivot[0]+=e*c.transform[0]+ 34444d*c.transform[4];c.pivot[1]+=e*c.transform[1]+d*c.transform[5];c.pivot[2]+=e*c.transform[2]+d*c.transform[6];c.updateView();this.wake()}.bind(this));this.input.onPan2.push(function(a,b){var c=1-2.2/(Math.sqrt(a*a+b*b)+2.2);this.scene.lights.rotation-=0.4*a*c;this.wake()}.bind(this));this.input.onZoom.push(function(a){var b=this.scene.view;b.radius*=1-0.002*a;b.radius=0.001>b.radius?0.001:b.radius;b.radius=1E3<b.radius?1E3:b.radius;b.updateView();this.wake()}.bind(this));this.input.onDoubleTap.push(function(a, 34445b){this.scene.view.reset();this.scene.sceneAnimator&&this.scene.sceneAnimator.resetCustomView();this.wake()}.bind(this));this.ui.bindInput(this.input)};WebViewer.prototype.wake=function(a){a=a||16;this.sleepCounter=this.sleepCounter<a?a:this.sleepCounter;this.scene.postRender.discardAAHistory();this.requestFrame(this.update.bind(this))}; 34446WebViewer.prototype.requestFrame=function(a){var b=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;if(!this.frameRequestPending){var c=function(){this.frameRequestPending=0;a()}.bind(this);this.frameRequestPending=b(c,this.canvas)}};WebViewer.prototype.cancelFrame=function(){this.frameRequestPending&&(window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame||window.msCancelAnimationFrame)(this.frameRequestPending)}; 34447WebViewer.prototype.fullscreenChange=function(){FullScreen.active()?(this.oldRootWidth=this.domRoot.style.width,this.oldRootHeight=this.domRoot.style.height,this.domRoot.style.width="100%",this.domRoot.style.height="100%"):(this.domRoot.style.width=this.oldRootWidth,this.domRoot.style.height=this.oldRootHeight);this.wake()}; 34448WebViewer.prototype.resize=function(a,b){a&&b?(this.domRoot.style.width=a+"px",this.domRoot.style.height=b+"px"):(a=this.domRoot.clientWidth,b=this.domRoot.clientHeight);this.canvas.width=a*this.pixelRatio;this.canvas.height=b*this.pixelRatio;this.canvas.style.width=a+"px";this.canvas.style.height=b+"px";this.ui.setSize(a,b);this.allocBacking();this.wake()};WebViewer.prototype.updateLoad=function(){this.scene.complete()?this.start():this.requestFrame(this.updateLoad.bind(this));this.ui.animate()}; 34449WebViewer.prototype.start=function(){this.scene.view.updateView();this.ui.showActiveView();this.requestFrame(this.update.bind(this))};WebViewer.prototype.update=function(){var a=this.scene.sceneAnimator&&!this.scene.sceneAnimator.paused;if(0<this.sleepCounter||this.ui.animating()||a||this.stripData.animationActive)this.stripData.update(),this.ui.animate(),this.scene.update(),this.drawScene(),this.requestFrame(this.update.bind(this));a?this.scene.postRender.discardAAHistory():this.sleepCounter--}; 34450WebViewer.prototype.reDrawScene=function(){this.stripData.update();this.ui.animate();this.scene.update();this.drawScene();this.requestFrame(this.update.bind(this));this.scene.postRender.discardAAHistory()}; 34451WebViewer.prototype.drawScene=function(){this.gl.isContextLost()||(this.domRoot.clientWidth==this.canvas.clientWidth&&this.domRoot.clientHeight==this.canvas.clientHeight||this.resize(),this.scene.view.size=[this.mainBuffer.width,this.mainBuffer.height],this.scene.view.updateProjection(),this.scene.postRender.adjustProjectionForSupersampling(this.scene.view),this.scene.collectShadows(this.mainBuffer),this.mainBuffer.bind(),this.scene.draw(this.mainBuffer),this.mainDepth&&(this.mainBufferNoDepth.bind(), 34452this.scene.drawSecondary(this.mainDepth)),this.scene.postRender.present(this.mainColor,this.canvas.width,this.canvas.height,this.stripData.active()))};marmoset="undefined"==typeof marmoset?{}:marmoset;marmoset.WebViewer=WebViewer;marmoset.dataLocale=(0==window.location.protocol.indexOf("https")?"https:":"http:")+"//viewer.marmoset.co/main/data/";var ShaderTable={"alphaprepassfrag.glsl":"precision mediump float;\n#include <matdither.glsl>\nuniform sampler2D tAlbedo;varying mediump vec2 d;void main(){float e=texture2D(tAlbedo,d).a;if(e<=f(d.x)){discard;}gl_FragColor=vec4(0.0);}","alphaprepassvert.glsl":"precision highp float;uniform mat4 uModelViewProjectionMatrix;uniform vec2 uUVOffset;attribute vec3 vPosition;attribute vec2 vTexCoord;varying mediump vec2 d;vec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}void main(void){gl_Position=h(uModelViewProjectionMatrix,vPosition.xyz);d=vTexCoord+uUVOffset;}", 34453"bloom.glsl":"precision mediump float;uniform sampler2D tInput;uniform vec4 uKernel[BLOOM_SAMPLES];varying highp vec2 j;void main(void){vec3 c=vec3(0.0,0.0,0.0);for(int k=0;k<BLOOM_SAMPLES;++k){vec3 l=uKernel[k].xyz;vec3 m=texture2D(tInput,j+l.xy).xyz;m=max(m,vec3(0.0,0.0,0.0));c+=m*l.z;}gl_FragColor.xyz=c;gl_FragColor.w=0.0;}","bloomshrink.glsl":"precision highp float;uniform sampler2D tInput;varying highp vec2 j;void main(void){float o=0.25/256.0;gl_FragColor=0.25*(texture2D(tInput,j+vec2(o,o))+texture2D(tInput,j+vec2(o,-o))+texture2D(tInput,j+vec2(-o,o))+texture2D(tInput,j+vec2(-o,-o)));}", 34454"fogfrag.glsl":"precision highp float;uniform sampler2D tDepth;uniform vec3 uDepthToZ;uniform vec4 uUnproject;uniform mat4 uInvViewMatrix;uniform float uFogInvDistance;uniform float uFogOpacity;uniform float uFogDispersion;uniform vec3 uFogType;uniform vec3 uFogColor;uniform float uFogIllum;uniform mat4 uLightMatrix;\n#ifdef FOG_IBL\nuniform vec4 uFogLightSphere[9];\n#else\nuniform vec4 uSpotParams;uniform vec4 uLightPosition;uniform vec3 uLightColor;uniform vec4 uLightAttenuation;\n#ifdef FOG_SHADOWS\nuniform mat4 uShadowProj;uniform sampler2D uShadowMap;uniform float uDitherOffset;
34454uniform vec4 uCylinder;\n#endif\n#endif\nvec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}vec3 u(mat4 i,vec3 v){return i[0].xyz*v.x+i[1].xyz*v.y+i[2].xyz*v.z;}float A(float B){B*=uFogInvDistance;float C=uFogType.x*min(B,1.0)+(uFogType.y-uFogType.y/(1.0+16.0*B*B))+(uFogType.z-uFogType.z*exp(-3.0*B));return C*uFogOpacity;}\n#ifdef FOG_SHADOWS\nfloat D(vec3 E){vec4 p=h(uShadowProj,E);vec3 F=p.xyz/p.w;vec4 G=texture2D(uShadowMap,F.xy);float H=(G.x+G.y*(1.0/255.0))+G.z*(1.0/65025.0);return F.z<H || H>=1.0?1.0:0.0;}float f(vec2 I){return fract(sin(dot(I,vec2(12.9898,78.233)))*43758.5453+uDitherOffset);}void J(vec3 K,vec3 L,out float M,out float N){vec3 v=uSpotParams.xyz,p=uCylinder.xyz;vec3 O=L-dot(L,v)*v;vec3 P=(K-p)-dot(K-p,v)*v;float a=dot(O,O);float b=2.0*dot(O,P);float c=dot(P,P)-uCylinder.w;float Q=b*b-4.0*a*c;if(Q>=0.0){Q=sqrt(Q);M=(-b-Q)/(2.0*a);N=(-b+Q)/(2.0*a);}else {M=N=0.0;}}\n#endif\nvarying vec2 j;void main(void){vec3 R=uInvViewMatrix[3].xyz;float H=texture2D(tDepth,j).x;H=min(H,0.9999);vec3 S;S.z=uDepthToZ.y/(uDepthToZ.z*H+uDepthToZ.x);S.xy=S.z*(j*uUnproject.xy+uUnproject.zw);S=h(uInvViewMatrix,S).xyz;vec3 T;T.xy=(j*uUnproject.xy+uUnproject.zw);T.z=1.0;T=normalize(u(uInvViewMatrix,-T).xyz);vec3 U=uFogColor;\n#if defined(FOG_IBL)\nvec3 G=u(uLightMatrix,T);vec3 V=uFogLightSphere[0].xyz;V+=uFogLightSphere[1].xyz*G.y;V+=uFogLightSphere[2].xyz*G.z;V+=uFogLightSphere[3].xyz*G.x;vec3 swz=G.yyz*G.xzx;V+=uFogLightSphere[4].xyz*swz.x;V+=uFogLightSphere[5].xyz*swz.y;V+=uFogLightSphere[7].xyz*swz.z;vec3 sqr=G*G;V+=uFogLightSphere[6].xyz*(3.0*sqr.z-1.0);V+=uFogLightSphere[8].xyz*(sqr.x-sqr.y);U=mix(U,U*V,uFogIllum);float C=A(length(S-R));gl_FragColor.xyz=U*C;gl_FragColor.w=C;return;\n#else\n#if defined(FOG_SPOT) || defined(FOG_OMNI)\nfloat W=0.0,X=0.0;{float r=1.0/(uLightAttenuation.z);float a=1.0;float b=2.0*dot(T,R-uLightPosition.xyz);float c=dot(uLightPosition.xyz,uLightPosition.xyz)+dot(R,R)+-2.0*dot(uLightPosition.xyz,R)+-r*r;float Q=b*b-4.0*a*c;if(Q>=0.0){Q=sqrt(Q);W=(-b-Q)/(2.0*a);X=(-b+Q)/(2.0*a);}}\n#if defined(FOG_SPOT)\n{float Y=uSpotParams.w,Z=1.0-Y;vec3 v=T;vec3 dc=uSpotParams.xyz;vec3 dd=R-uLightPosition.xyz;vec3 de=v-dot(v,dc)*dc,df=dd-dot(dd,dc)*dc;float a=Y*dot(de,de)-Z*dot(v,dc)*dot(v,dc);float b=2.0*Y*dot(de,df)-2.0*Z*dot(v,dc)*dot(dd,dc);float c=Y*dot(df,df)-Z*dot(dd,dc)*dot(dd,dc);float Q=b*b-4.0*a*c;if(Q>=0.0){float dh=(-b-sqrt(Q))/(2.0*a);float di=(-b+sqrt(Q))/(2.0*a);if(di<dh){float de=dh;dh=di;di=de;}bool dj=dot(-uLightPosition.xyz+R+T*dh,uSpotParams.xyz)<=0.0;bool dk=dot(-uLightPosition.xyz+R+T*di,uSpotParams.xyz)<=0.0;if(!dj ||!dk){if(dj){dh=di;di=X;}else if(dk){di=dh;dh=W;}W=max(W,dh);X=min(X,di);}else {X=W=0.0;}}else {X=W=0.0;}}\n#endif\nfloat tx=dot(T,S-R);W=clamp(W,0.0,tx);X=clamp(X,0.0,tx);float dl=0.0;if(X>W){\n#ifdef FOG_SHADOWS\n#ifdef MOBILE\n#define SAMPLES 16\n#else\n#define SAMPLES 32\n#endif\nfloat dm=f(j)*(X-W)/float(SAMPLES-2);\n#else\n#define SAMPLES 8\nfloat dm=0.0;\n#endif\nfor(int k=0;k<SAMPLES;++k){float t=W+(X-W)*float(k)/float(SAMPLES-1);vec3 p=R+(t+dm)*T;float a=clamp(length(p-uLightPosition.xyz)*uLightAttenuation.z,0.0,1.0);a=1.0+uLightAttenuation.x*a+uLightAttenuation.y*a*a;\n#ifdef FOG_SHADOWS\na*=D(p);\n#endif\ndl+=a-a*A(t);}dl*=1.0/float(SAMPLES);dl*=(X-W)*uLightAttenuation.z;dl*=A(X-W);}U*=dl*uFogIllum;\n#elif defined(FOG_DIR)\nfloat C=A(dot(T,S-R));\n#ifdef FOG_SHADOWS\nfloat W,X;J(R,T,W,X);float tx=dot(T,S-R);W=clamp(W,0.0,tx);X=clamp(X,0.0,tx);if(X>W){\n#ifdef MOBILE\n#define SAMPLES 16\n#else\n#define SAMPLES 32\n#endif\nfloat dl=0.0;float dm=f(j)*(X-W)/float(SAMPLES-2);float dn=(X-W)*(1.0/float(SAMPLES));for(int k=0;k<SAMPLES;++k){float t=W+float(k)*dn+dm;vec3 p=R+t*T;float s=D(p);C-=(1.0-s)*(A(t+dn)-A(t));}}\n#endif\nfloat du=0.5+0.5*dot(T,-uSpotParams.xyz);du=1.0+uFogDispersion*(2.0*du*du-1.0);U*=(0.1*C)*(du*uFogIllum);\n#endif\ngl_FragColor.xyz=U*uLightColor;gl_FragColor.w=0.0;\n#endif\n}", 34455"fogvert.glsl":"precision highp float;attribute vec2 vCoord;varying vec2 j;void main(void){j=vCoord;gl_Position.xy=2.0*vCoord-vec2(1.0,1.0);gl_Position.zw=vec2(0.0,1.0);}","matdither.glsl":"float f(highp float I){highp float G=0.5*fract(gl_FragCoord.x*0.5)+0.5*fract(gl_FragCoord.y*0.5);return 0.4+0.6*fract(G+3.141592e6*I);}","matfrag.glsl":"\n#extension GL_OES_standard_derivatives : enable\nprecision mediump float;varying highp vec3 dv;varying mediump vec2 d;varying mediump vec3 dA;varying mediump vec3 dB;varying mediump vec3 dC;\n#ifdef VERTEX_COLOR\nvarying lowp vec4 dD;\n#endif\n#ifdef TEXCOORD_SECONDARY\nvarying mediump vec2 dE;\n#endif\nuniform sampler2D tAlbedo;uniform sampler2D tReflectivity;uniform sampler2D tNormal;uniform sampler2D tExtras;uniform sampler2D tSkySpecular;\n#ifdef REFRACTION\nuniform sampler2D tRefraction;\n#endif\nuniform vec4 uDiffuseCoefficients[9];uniform vec3 uCameraPosition;uniform float uAlphaTest;uniform vec3 uFresnel;uniform float uHorizonOcclude;uniform float uHorizonSmoothing;\n#ifdef EMISSIVE\nuniform float uEmissiveScale;uniform vec4 uTexRangeEmissive;\n#endif\n#ifdef AMBIENT_OCCLUSION\nuniform vec4 uTexRangeAO;\n#endif\n#ifdef REFRACTION\nuniform float uRefractionIOREntry;uniform float uRefractionRayDistance;uniform vec3 uRefractionTint;uniform float uRefractionAlbedoTint;uniform mat4 uRefractionViewProjection;uniform vec4 uTexRangeRefraction;\n#endif\n#ifdef LIGHT_COUNT\nuniform vec4 uLightPositions[LIGHT_COUNT];uniform vec3 uLightDirections[LIGHT_COUNT];uniform vec3 uLightColors[LIGHT_COUNT];uniform vec3 uLightParams[LIGHT_COUNT];uniform vec3 uLightSpot[LIGHT_COUNT];\n#endif\n#ifdef ANISO\nuniform float uAnisoStrength;uniform vec3 uAnisoTangent;uniform float uAnisoIntegral;uniform vec4 uTexRangeAniso;\n#endif\n#define saturate(x) clamp( x, 0.0, 1.0 )\n#include <matsampling.glsl>\n#include <matlighting.glsl>\n#include <matshadows.glsl>\n#include <matskin.glsl>\n#include <matmicrofiber.glsl>\n#include <matstrips.glsl>\n#ifdef TRANSPARENCY_DITHER\n#include <matdither.glsl>\n#endif\nvoid main(void){vec4 m=texture2D(tAlbedo,d);vec3 dF=dG(m.xyz);float e=m.w;\n#ifdef VERTEX_COLOR\n{vec3 dH=dD.xyz;\n#ifdef VERTEX_COLOR_SRGB\ndH=dH*(dH*(dH*0.305306011+vec3(0.682171111))+vec3(0.012522878));\n#endif\ndF*=dH;\n#ifdef VERTEX_COLOR_ALPHA\ne*=dD.w;\n#endif\n}\n#endif\n#ifdef ALPHA_TEST\nif(e<uAlphaTest){discard;}\n#endif\n#ifdef TRANSPARENCY_DITHER\ne=(e>f(d.x))?1.0:e;\n#endif\nvec3 dI=dJ(texture2D(tNormal,d).xyz);\n#ifdef ANISO\n#ifdef ANISO_NO_DIR_TEX\nvec3 dK=dL(uAnisoTangent);\n#else\nm=dM(d,uTexRangeAniso);vec3 dK=2.0*m.xyz-vec3(1.0);dK=dL(dK);\n#endif\ndK=dK-dI*dot(dK,dI);dK=normalize(dK);vec3 dN=dK*uAnisoStrength;\n#endif\nvec3 dO=normalize(uCameraPosition-dv);m=texture2D(tReflectivity,d);vec3 dP=dG(m.xyz);float dQ=m.w;float dR=dQ;\n#ifdef HORIZON_SMOOTHING\nfloat dS=dot(dO,dI);dS=uHorizonSmoothing-dS*uHorizonSmoothing;dQ=mix(dQ,1.0,dS*dS);\n#endif\n#ifdef STRIPVIEW\ndT dU;dV(dU,dQ,dP);\n#endif\nfloat dW=1.0;\n#ifdef AMBIENT_OCCLUSION\n#ifdef AMBIENT_OCCLUSION_SECONDARY_UV\ndW=dM(dE,uTexRangeAO).x;\n#else\ndW=dM(d,uTexRangeAO).x;\n#endif\ndW*=dW;\n#endif\n#if defined(SKIN)\ndX dY;dZ(dY);dY.ec*=dW;
34455\n#elif defined(MICROFIBER)\ned ee;ef(ee,dI);ee.eh*=dW;\n#else\nvec3 ei=ej(dI);ei*=dW;\n#endif\nvec3 ek=reflect(-dO,dI);\n#ifdef ANISO\nvec3 rt=ek-(0.5*dN*dot(ek,dK));vec3 el=em(rt,mix(dQ,0.5*dQ,uAnisoStrength));\n#else\nvec3 el=em(ek,dQ);\n#endif\nel*=en(ek,dC);\n#ifdef LIGHT_COUNT\nhighp float eo=10.0/log2(dQ*0.968+0.03);eo*=eo;float eu=eo*(1.0/(8.0*3.1415926))+(4.0/(8.0*3.1415926));eu=min(eu,1.0e3);\n#ifdef SHADOW_COUNT\nev eA;\n#ifdef SKIN\n#ifdef SKIN_VERSION_1\neB(eA,SHADOW_KERNEL+SHADOW_KERNEL*dY.eC);\n#else\neD eE;float eF=SHADOW_KERNEL+SHADOW_KERNEL*dY.eC;eG(eE,eF);eB(eA,eF);\n#endif\n#else\neB(eA,SHADOW_KERNEL);\n#endif\n#endif\n#ifdef ANISO\neu*=uAnisoIntegral;\n#endif\nfor(int k=0;k<LIGHT_COUNT;++k){vec3 eH=uLightPositions[k].xyz-dv*uLightPositions[k].w;float eI=inversesqrt(dot(eH,eH));eH*=eI;float a=saturate(uLightParams[k].z/eI);a=1.0+a*(uLightParams[k].x+uLightParams[k].y*a);float s=saturate(dot(eH,uLightDirections[k]));s=saturate(uLightSpot[k].y-uLightSpot[k].z*(1.0-s*s));vec3 eJ=(a*s)*uLightColors[k].xyz;\n#if defined(SKIN)\n#ifdef SHADOW_COUNT\n#ifdef SKIN_VERSION_1\neK(dY,eA.eL[k],1.0,eH,dI,eJ);\n#else\neK(dY,eA.eL[k],eE.eE[k],eH,dI,eJ);\n#endif\n#else\neK(dY,1.0,0.0,eH,dI,eJ);\n#endif\n#elif defined(MICROFIBER)\n#ifdef SHADOW_COUNT\neM(ee,eA.eL[k],eH,dI,eJ);\n#else\neM(ee,1.0,eH,dI,eJ);\n#endif\n#else\nfloat eN=saturate((1.0/3.1415926)*dot(eH,dI));\n#ifdef SHADOW_COUNT\neN*=eA.eL[k];\n#endif\nei+=eN*eJ;\n#endif\nvec3 eO=eH+dO;\n#ifdef ANISO\neO=eO-(dN*dot(eO,dK));\n#endif\neO=normalize(eO);float eP=eu*pow(saturate(dot(eO,dI)),eo);\n#ifdef SHADOW_COUNT\neP*=eA.eL[k];\n#endif\nel+=eP*eJ;}\n#endif\n#if defined(SKIN)\nvec3 ei,diff_extra;eQ(ei,diff_extra,dY,dO,dI,dQ);\n#elif defined(MICROFIBER)\nvec3 ei,diff_extra;eR(ei,diff_extra,ee,dO,dI,dQ);\n#endif\nvec3 eS=eT(dO,dI,dP,dQ*dQ);el*=eS;\n#ifdef REFRACTION\nvec4 eU;{vec3 G=refract(-dO,dI,uRefractionIOREntry);G=dv+G*uRefractionRayDistance;vec4 eV=uRefractionViewProjection[0]*G.x+(uRefractionViewProjection[1]*G.y+(uRefractionViewProjection[2]*G.z+uRefractionViewProjection[3]));vec2 c=eV.xy/eV.w;c=0.5*c+vec2(0.5,0.5);vec2 i=mod(floor(c),2.0);c=fract(c);c.x=i.x>0.0?1.0-c.x:c.x;c.y=i.y>0.0?1.0-c.y:c.y;eU.rgb=texture2D(tRefraction,c).xyz;eU.rgb=mix(eU.rgb,eU.rgb*dF,uRefractionAlbedoTint);eU.rgb=eU.rgb-eU.rgb*eS;eU.rgb*=uRefractionTint;\n#ifdef REFRACTION_NO_MASK_TEX\neU.a=1.0;\n#else\neU.a=dM(d,uTexRangeRefraction).x;\n#endif\n}\n#endif\n#ifdef DIFFUSE_UNLIT\ngl_FragColor.xyz=dF;\n#else\ngl_FragColor.xyz=ei*dF;\n#endif\n#ifdef REFRACTION\ngl_FragColor.xyz=mix(gl_FragColor.xyz,eU.rgb,eU.a);\n#endif\ngl_FragColor.xyz+=el;\n#if defined(SKIN) || defined(MICROFIBER)\ngl_FragColor.xyz+=diff_extra;\n#endif\n#ifdef EMISSIVE\n#ifdef EMISSIVE_SECONDARY_UV\nvec2 eW=dE;\n#else\nvec2 eW=d;\n#endif\ngl_FragColor.xyz+=uEmissiveScale*dG(dM(eW,uTexRangeEmissive).xyz);\n#endif\n#ifdef STRIPVIEW\ngl_FragColor.xyz=eX(dU,dI,dF,dP,dR,ei,el,gl_FragColor.xyz);\n#endif\n#ifdef NOBLEND\ngl_FragColor.w=1.0;\n#else\ngl_FragColor.w=e;\n#endif\n}", 34456"matlighting.glsl":"vec3 eY(vec3 eZ,float fc){return exp(-0.5*fc/(eZ*eZ))/(eZ*2.5066283);}vec3 fd(vec3 eZ){return vec3(1.0,1.0,1.0)/(eZ*2.5066283);}vec3 fe(vec3 ff){return vec3(-0.5,-0.5,-0.5)/(ff);}vec3 fh(vec3 fi,float fc){return exp(fi*fc);}\n#define SAMPLE_COUNT 21.0\n#define SAMPLE_HALF 10.0\n#define GAUSS_SPREAD 0.05\nvec3 fj(float fk,float fl,vec3 fm){vec3 fn=vec3(fl,fl,fl);fn=0.8*fn+vec3(0.2);vec3 fo=cos(fn*3.14159);vec3 fu=cos(fn*3.14159*0.5);fu*=fu;fu*=fu;fu*=fu;fn=fn+0.05*fo*fu*fm;fu*=fu;fu*=fu;fu*=fu;fn=fn+0.1*fo*fu*fm;fn=saturate(fn);fn*=fn*1.2;return fn;}vec3 fv(vec3 fm){return vec3(1.0,1.0,1.0)/3.1415926;}float fA(float fk,float fm){return saturate(-fk*fm+fk+fm);}vec3 fB(float fk,vec3 fm){return saturate(-fk*fm+vec3(fk)+fm);}float fC(float fm){return-0.31830988618379*fm+0.31830988618379;}vec3 fD(vec3 fm){return-0.31830988618379*fm+vec3(0.31830988618379);}vec3 eT(vec3 dO,vec3 dI,vec3 dP,float fE){float C=1.0-saturate(dot(dO,dI));float fF=C*C;C*=fF*fF;C*=fE;return(dP-C*dP)+C*uFresnel;}vec2 fG(vec2 fH,vec2 fm){fH=1.0-fH;vec2 fI=fH*fH;fI*=fI;fH=mix(fI,fH*0.4,fm);return fH;}vec3 ej(vec3 fJ){\n#define c(n) uDiffuseCoefficients[n].xyz\nvec3 G=(c(0)+fJ.y*((c(1)+c(4)*fJ.x)+c(5)*fJ.z))+fJ.x*(c(3)+c(7)*fJ.z)+c(2)*fJ.z;\n#undef c\nvec3 sqr=fJ*fJ;G+=uDiffuseCoefficients[6].xyz*(3.0*sqr.z-1.0);G+=uDiffuseCoefficients[8].xyz*(sqr.x-sqr.y);return G;}void fK(inout vec3 fL,inout vec3 fM,inout vec3 fN,vec3 fJ){fL=uDiffuseCoefficients[0].xyz;fM=uDiffuseCoefficients[1].xyz*fJ.y;fM+=uDiffuseCoefficients[2].xyz*fJ.z;fM+=uDiffuseCoefficients[3].xyz*fJ.x;vec3 swz=fJ.yyz*fJ.xzx;fN=uDiffuseCoefficients[4].xyz*swz.x;fN+=uDiffuseCoefficients[5].xyz*swz.y;fN+=uDiffuseCoefficients[7].xyz*swz.z;vec3 sqr=fJ*fJ;fN+=uDiffuseCoefficients[6].xyz*(3.0*sqr.z-1.0);fN+=uDiffuseCoefficients[8].xyz*(sqr.x-sqr.y);}vec3 fO(vec3 fL,vec3 fM,vec3 fN,vec3 fP,float fm){fP=mix(vec3(1.0),fP,fm);return(fL+fM*fP.x)+fN*fP.z;}vec3 fQ(vec3 fL,vec3 fM,vec3 fN,vec3 fP,vec3 fR){vec3 fS=mix(vec3(1.0),fP.yyy,fR);vec3 fT=mix(vec3(1.0),fP.zzz,fR);
34456return(fL+fM*fS)+fN*fT;}vec3 em(vec3 fJ,float dQ){fJ/=dot(vec3(1.0),abs(fJ));vec2 fU=abs(fJ.zx)-vec2(1.0,1.0);vec2 fV=vec2(fJ.x<0.0?fU.x:-fU.x,fJ.z<0.0?fU.y:-fU.y);vec2 fW=(fJ.y<0.0)?fV:fJ.xz;fW=vec2(0.5*(254.0/256.0),0.125*0.5*(254.0/256.0))*fW+vec2(0.5,0.125*0.5);float fX=fract(7.0*dQ);fW.y+=0.125*(7.0*dQ-fX);vec2 fY=fW+vec2(0.0,0.125);vec4 fZ=mix(texture2D(tSkySpecular,fW),texture2D(tSkySpecular,fY),fX);vec3 r=fZ.xyz*(7.0*fZ.w);return r*r;}float en(vec3 fJ,vec3 hc){float hd=dot(fJ,hc);hd=saturate(1.0+uHorizonOcclude*hd);return hd*hd;}", 34457"matmicrofiber.glsl":"\n#ifdef MICROFIBER\nuniform vec4 uTexRangeFuzz;uniform vec4 uFresnelColor;uniform float uFresnelIntegral;uniform float uFresnelOcc;uniform float uFresnelGlossMask;struct ed{vec3 eh;vec3 eN;vec3 he;vec3 hf;vec3 hh;};void ef(out ed s,vec3 dI){s.eh=s.eN=ej(dI);s.he=vec3(0.0);s.hf=uFresnelColor.rgb;s.hh=uFresnelColor.aaa*vec3(1.0,0.5,0.25);\n#ifndef MICROFIBER_NO_FUZZ_TEX\nvec4 m=dM(d,uTexRangeFuzz);s.hf*=dG(m.rgb);\n#endif\n}void eM(inout ed s,float hi,vec3 eH,vec3 dI,vec3 eJ){float fk=dot(eH,dI);float eN=saturate((1.0/3.1415926)*fk);float hj=fA(fk,s.hh.z);\n#ifdef SHADOW_COUNT\neN*=hi;float hk=mix(1.0,hi,uFresnelOcc);float he=hj*hk;\n#else \nfloat he=hj;\n#endif\ns.he=he*eJ+s.he;s.eN=eN*eJ+s.eN;}void eR(out vec3 ei,out vec3 diff_extra,inout ed s,vec3 dO,vec3 dI,float dQ){s.he*=uFresnelIntegral;float fH=dot(dO,dI);vec2 hl=fG(vec2(fH,fH),s.hh.xy);s.he=s.eh*hl.x+(s.he*hl.y);s.he*=s.hf;float hm=saturate(1.0+-uFresnelGlossMask*dQ);s.he*=hm*hm;ei=s.eN;diff_extra=s.he;}\n#endif\n", 34458"matsampling.glsl":"vec3 dG(vec3 c){return c*c;}vec3 dJ(vec3 n){vec3 hn=dA;vec3 ho=dB;vec3 hu=gl_FrontFacing?dC:-dC;\n#ifdef TSPACE_RENORMALIZE\nhu=normalize(hu);\n#endif\n#ifdef TSPACE_ORTHOGONALIZE\nhn-=dot(hn,hu)*hu;\n#endif\n#ifdef TSPACE_RENORMALIZE\nhn=normalize(hn);\n#endif\n#ifdef TSPACE_ORTHOGONALIZE\nho=(ho-dot(ho,hu)*hu)-dot(ho,hn)*hn;\n#endif\n#ifdef TSPACE_RENORMALIZE\nho=normalize(ho);\n#endif\n#ifdef TSPACE_COMPUTE_BITANGENT\nvec3 hv=cross(hu,hn);ho=dot(hv,ho)<0.0?-hv:hv;\n#endif\nn=2.0*n-vec3(1.0);return normalize(hn*n.x+ho*n.y+hu*n.z);}vec3 dL(vec3 t){vec3 hu=gl_FrontFacing?dC:-dC;return normalize(dA*t.x+dB*t.y+hu*t.z);}vec4 dM(vec2 hA,vec4 hB){\n#if GL_OES_standard_derivatives\nvec2 hC=fract(hA);vec2 hD=fwidth(hC);float hE=(hD.x+hD.y)>0.5?-6.0:0.0;return texture2D(tExtras,hC*hB.xy+hB.zw,hE);\n#else\nreturn texture2D(tExtras,fract(hA)*hB.xy+hB.zw);\n#endif\n}vec3 hF(sampler2D hG,vec2 hH,float hI){vec3 n=texture2D(hG,hH,hI*2.5).xyz;return dJ(n);}", 34459"matshadows.glsl":"\n#ifdef SHADOW_COUNT\n#ifdef MOBILE\n#define SHADOW_KERNEL (4.0/1536.0)\n#else\n#define SHADOW_KERNEL (4.0/2048.0)\n#endif\nhighp vec4 h(highp mat4 i,highp vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}uniform sampler2D tDepth0;\n#if SHADOW_COUNT > 1\nuniform sampler2D tDepth1;\n#if SHADOW_COUNT > 2\nuniform sampler2D tDepth2;\n#endif\n#endif\nuniform highp vec2 uShadowKernelRotation;uniform highp vec2 uShadowMapSize;uniform highp mat4 uShadowMatrices[SHADOW_COUNT];uniform highp vec4 uShadowTexelPadProjections[SHADOW_COUNT];\n#ifndef MOBILE\nuniform highp mat4 uInvShadowMatrices[SHADOW_COUNT];\n#endif\nhighp float hJ(highp vec3 G){\n#ifdef SHADOW_NATIVE_DEPTH\nreturn G.x;\n#else\nreturn(G.x+G.y*(1.0/255.0))+G.z*(1.0/65025.0);\n#endif\n}\n#ifndef SHADOW_COMPARE\n#define SHADOW_COMPARE(a,b) ((a) < (b) ? 1.0 : 0.0)\n#endif\n#ifndef SHADOW_CLIP\n#define SHADOW_CLIP(c,v) v\n#endif\nfloat hK(sampler2D hL,highp vec2 hA,highp float H){\n#ifndef MOBILE\nhighp vec2 c=hA*uShadowMapSize.x;highp vec2 a=floor(c)*uShadowMapSize.y,b=ceil(c)*uShadowMapSize.y;highp vec4 eE;eE.x=hJ(texture2D(hL,a).xyz);eE.y=hJ(texture2D(hL,vec2(b.x,a.y)).xyz);eE.z=hJ(texture2D(hL,vec2(a.x,b.y)).xyz);eE.w=hJ(texture2D(hL,b).xyz);highp vec4 hM;hM.x=SHADOW_COMPARE(H,eE.x);hM.y=SHADOW_COMPARE(H,eE.y);hM.z=SHADOW_COMPARE(H,eE.z);hM.w=SHADOW_COMPARE(H,eE.w);highp vec2 w=c-a*uShadowMapSize.x;vec2 s=(w.y*hM.zw+hM.xy)-w.y*hM.xy;return(w.x*s.y+s.x)-w.x*s.x;\n#else\nhighp float G=hJ(texture2D(hL,hA.xy).xyz);return SHADOW_COMPARE(H,G);\n#endif\n}highp float hN(sampler2D hL,highp vec3 hA,float hO){highp vec2 l=uShadowKernelRotation*hO;float s;s=hK(hL,hA.xy+l,hA.z);s+=hK(hL,hA.xy-l,hA.z);s+=hK(hL,hA.xy+vec2(-l.y,l.x),hA.z);s+=hK(hL,hA.xy+vec2(l.y,-l.x),hA.z);s*=0.25;return s*s;}struct ev{float eL[LIGHT_COUNT];};void eB(out ev ss,float hO){highp vec3 hP[SHADOW_COUNT];vec3 hu=gl_FrontFacing?dC:-dC;for(int k=0;k<SHADOW_COUNT;++k){vec4 hQ=uShadowTexelPadProjections[k];
34459float hR=hQ.x*dv.x+(hQ.y*dv.y+(hQ.z*dv.z+hQ.w));\n#ifdef MOBILE\nhR*=.001+hO;\n#else\nhR*=.0005+0.5*hO;\n#endif\nhighp vec4 hS=h(uShadowMatrices[k],dv+hR*hu);hP[k]=hS.xyz/hS.w;}float m;\n#if SHADOW_COUNT > 0\nm=hN(tDepth0,hP[0],hO);ss.eL[0]=SHADOW_CLIP(hP[0].xy,m);\n#endif\n#if SHADOW_COUNT > 1\nm=hN(tDepth1,hP[1],hO);ss.eL[1]=SHADOW_CLIP(hP[1].xy,m);\n#endif\n#if SHADOW_COUNT > 2\nm=hN(tDepth2,hP[2],hO);ss.eL[2]=SHADOW_CLIP(hP[2].xy,m);\n#endif\nfor(int k=SHADOW_COUNT;k<LIGHT_COUNT;++k){ss.eL[k]=1.0;}}struct eD{highp float eE[LIGHT_COUNT];};\n#ifdef MOBILE\nvoid eG(out eD ss,float hO){for(int k=0;k<LIGHT_COUNT;++k){ss.eE[k]=1.0;}}\n#else\nhighp vec4 hT(sampler2D hL,highp vec2 hA,highp mat4 hU){highp vec4 E;E.xy=hA;\n#ifndef MOBILE\nhighp vec2 c=hA*uShadowMapSize.x;highp vec2 a=floor(c)*uShadowMapSize.y,b=ceil(c)*uShadowMapSize.y;highp vec4 hM;hM.x=hJ(texture2D(hL,a).xyz);hM.y=hJ(texture2D(hL,vec2(b.x,a.y)).xyz);hM.z=hJ(texture2D(hL,vec2(a.x,b.y)).xyz);hM.w=hJ(texture2D(hL,b).xyz);highp vec2 w=c-a*uShadowMapSize.x;vec2 s=(w.y*hM.zw+hM.xy)-w.y*hM.xy;E.z=(w.x*s.y+s.x)-w.x*s.x;\n#else \nE.z=hJ(texture2D(hL,hA.xy).xyz);\n#endif\nE=h(hU,E.xyz);E.xyz/=E.w;return E;}void eG(out eD ss,float hO){highp vec3 hV[SHADOW_COUNT];vec3 hu=gl_FrontFacing?dC:-dC;hu*=0.6;for(int k=0;k<SHADOW_COUNT;++k){vec4 hQ=uShadowTexelPadProjections[k];float hR=hQ.x*dv.x+(hQ.y*dv.y+(hQ.z*dv.z+hQ.w));\n#ifdef MOBILE\nhR*=.001+hO;\n#else\nhR*=.0005+0.5*hO;\n#endif\nhighp vec4 hS=h(uShadowMatrices[k],dv-hR*hu);hV[k]=hS.xyz/hS.w;}highp vec4 hW;\n#if SHADOW_COUNT > 0\nhW=hT(tDepth0,hV[0].xy,uInvShadowMatrices[0]);ss.eE[0]=length(dv.xyz-hW.xyz);\n#endif\n#if SHADOW_COUNT > 1\nhW=hT(tDepth1,hV[1].xy,uInvShadowMatrices[1]);ss.eE[1]=length(dv.xyz-hW.xyz);\n#endif\n#if SHADOW_COUNT > 2\nhW=hT(tDepth2,hV[2].xy,uInvShadowMatrices[2]);ss.eE[2]=length(dv.xyz-hW.xyz);\n#endif\nfor(int k=SHADOW_COUNT;k<LIGHT_COUNT;++k){ss.eE[k]=1.0;}}\n#endif\n#endif\n", 34460"matskin.glsl":"\n#ifdef SKIN\n#ifndef SKIN_NO_SUBDERMIS_TEX\nuniform vec4 uTexRangeSubdermis;\n#endif\n#ifndef SKIN_NO_TRANSLUCENCY_TEX\nuniform vec4 uTexRangeTranslucency;\n#endif\n#ifndef SKIN_NO_FUZZ_TEX\nuniform vec4 uTexRangeFuzz;\n#endif\nuniform vec4 uTransColor;uniform vec4 uFresnelColor;uniform vec3 uSubdermisColor;uniform float uTransScatter;uniform float uFresnelOcc;uniform float uFresnelGlossMask;uniform float uTransSky;uniform float uFresnelIntegral;uniform float uTransIntegral;uniform float uSkinTransDepth;uniform float uSkinShadowBlur;uniform float uNormalSmooth;struct dX{vec3 hX;vec3 hY,hZ,ic,he;vec3 ec,eh,id;vec3 ie;vec3 ih;vec3 ii;vec3 ij;float ik;float il;float im;float eC;};void dZ(out dX s){vec4 m;\n#ifdef SKIN_NO_SUBDERMIS_TEX\ns.hX=uSubdermisColor;s.im=1.0;\n#else \nm=dM(d,uTexRangeSubdermis);s.hX=dG(m.xyz);s.im=m.w*m.w;\n#endif\ns.ij=uTransColor.rgb;s.ik=uTransScatter;\n#ifdef SKIN_VERSION_1\ns.eC=uSkinShadowBlur*s.im;\n#else \ns.il=max(max(s.ij.r,s.ij.g),s.ij.b)*uTransColor.a;float io=max(s.hX.r,max(s.hX.g,s.hX.b));io=1.0-io;io*=io;io*=io;io*=io;io=1.0-(io*io);s.im*=io;s.eC=uSkinShadowBlur*s.im*dot(s.hX.rgb,vec3(0.333,0.334,0.333));\n#endif\n#ifndef SKIN_NO_TRANSLUCENCY_TEX\nm=dM(d,uTexRangeTranslucency);s.ij*=dG(m.xyz);\n#endif\ns.ie=hF(tNormal,d,uNormalSmooth*s.im);vec3 iu,iv,iA;fK(iu,iv,iA,s.ie);s.eh=s.hY=iu+iv+iA;\n#ifdef SKIN_VERSION_1 \ns.ec=fQ(iu,iv,iA,vec3(1.0,0.6667,0.25),s.hX);\n#else\ns.ec=fQ(iu,iv,iA,vec3(1.0,0.6667,0.25),s.hX*0.2+vec3(0.1));\n#endif\n#ifdef SKIN_VERSION_1\nvec3 iB,iC,iD;fK(iB,iC,iD,-s.ie);s.id=fO(iB,iC,iD,vec3(1.0,0.4444,0.0625),s.ik);s.id*=uTransSky;\n#else \ns.id=vec3(0.0);\n#endif\ns.hZ=s.ic=s.he=vec3(0.0);s.hX*=0.5;s.ik*=0.5;s.ih=uFresnelColor.rgb;s.ii=uFresnelColor.aaa*vec3(1.0,0.5,0.25);\n#ifndef SKIN_NO_FUZZ_TEX\nm=dM(d,uTexRangeFuzz);s.ih*=dG(m.rgb);\n#endif\n}void eK(inout dX s,float iE,float iF,vec3 eH,vec3 dI,vec3 eJ){float fk=dot(eH,dI);float fl=dot(eH,s.ie);float eN=saturate((1.0/3.1415926)*fk);float hi=iE*iE;hi*=hi;hi=saturate(6.0*hi);\n#ifdef SKIN_VERSION_1 \nvec3 iG=fB(fl,s.hX);\n#else \nvec3 iG=fj(fk,fl,s.hX);\n#endif\nfloat iH=fA(-fl,s.ik);vec3 ic=vec3(iH*iH);\n#ifdef SKIN_VERSION_1\n#ifdef SHADOW_COUNT\nvec3 iI=vec3(iE);float iJ=saturate(hi-2.0*(iE*iE));iI+=iJ*s.hX;float iK=iE;\n#endif\n#else\n#ifdef SHADOW_COUNT\nvec3 iI;highp vec3 iL=(0.995*s.hX)+vec3(0.005,0.005,0.005);highp vec3 iM=vec3(1.0)-iL;iL=mix(iL,iM,iE);float iN=sqrt(iE);vec3 iO=2.0*vec3(1.0-iN);iN=1.0-iN;iN=(1.0-iN*iN);iI=saturate(pow(iL*iN,iO));highp float iP=0.35/(uSkinTransDepth+0.001);highp float iQ=saturate(iF*iP);
34460iQ=saturate(1.0-iQ);iQ*=iQ;highp vec3 iR=vec3((-3.0*iQ)+3.15);highp vec3 iS=(0.9975*s.ij)+vec3(0.0025,0.0025,0.0025);highp float io=saturate(10.0*dot(iS,iS));vec3 iK=pow(iS*iQ,iR)*io;\n#else \nic=vec3(0.0);\n#endif\n#endif\nfloat hj=fA(fl,s.ii.z);\n#ifdef SHADOW_COUNT\nvec3 hk=mix(vec3(1.0),iI,uFresnelOcc);vec3 he=hj*hk;\n#else\nvec3 he=vec3(hj);\n#endif\n#ifdef SHADOW_COUNT\niG*=iI;eN*=hi;ic*=iK;\n#endif\ns.he=he*eJ+s.he;s.ic=ic*eJ+s.ic;s.hZ=iG*eJ+s.hZ;s.hY=eN*eJ+s.hY;}void eQ(out vec3 ei,out vec3 diff_extra,inout dX s,vec3 dO,vec3 dI,float dQ){s.he*=uFresnelIntegral;float fH=dot(dO,dI);vec2 hl=fG(vec2(fH,fH),s.ii.xy);s.he=s.eh*hl.x+(s.he*hl.y);s.he*=s.ih;float hm=saturate(1.0+-uFresnelGlossMask*dQ);s.he*=hm*hm;s.ic=s.ic*uTransIntegral;\n#ifdef SKIN_VERSION_1\ns.hZ=(s.hZ*fD(s.hX))+s.ec;\n#else\ns.hZ=(s.hZ*fv(s.hX))+s.ec;\n#endif\nei=mix(s.hY,s.hZ,s.im);\n#ifdef SKIN_VERSION_1\ns.ic=(s.ic+s.id)*s.ij;diff_extra=(s.he+s.ic)*s.im;\n#else\nei+=s.ic*s.il;diff_extra=s.he*s.im;\n#endif\n}\n#endif\n", 34461"matstrips.glsl":"\n#ifdef STRIPVIEW\nuniform float uStrips[5];uniform vec2 uStripRes;struct dT{float io[5];float bg;};void dV(out dT iT,inout float dQ,inout vec3 dP){highp vec2 hA=gl_FragCoord.xy*uStripRes-vec2(1.0,1.0);hA.x+=0.25*hA.y;iT.io[0]=step(hA.x,uStrips[0]);iT.io[1]=step(hA.x,uStrips[1]);iT.io[2]=step(hA.x,uStrips[2]);iT.io[3]=step(hA.x,uStrips[3]);iT.io[4]=step(hA.x,uStrips[4]);iT.bg=1.0-iT.io[4];iT.io[4]-=iT.io[3];iT.io[3]-=iT.io[2];iT.io[2]-=iT.io[1];iT.io[1]-=iT.io[0];bool iU=iT.io[4]>0.0;dQ=iU?0.5:dQ;dP=iU?vec3(0.1):dP;}vec3 eX(dT iT,vec3 dI,vec3 dF,vec3 dP,float dQ,vec3 ei,vec3 el,vec3 iV){return iT.io[0]*(dI*0.5+vec3(0.5))+iT.io[1]*dF+iT.io[2]*dP+vec3(iT.io[3]*dQ)+iT.io[4]*(vec3(0.12)+0.3*ei+el)+iT.bg*iV;}\n#endif\n", 34462"matvert.glsl":"precision highp float;uniform mat4 uModelViewProjectionMatrix;uniform mat4 uSkyMatrix;uniform vec2 uUVOffset;attribute vec3 vPosition;attribute vec2 vTexCoord;attribute vec2 vTangent;attribute vec2 vBitangent;attribute vec2 vNormal;\n#ifdef VERTEX_COLOR\nattribute vec4 vColor;\n#endif\n#ifdef TEXCOORD_SECONDARY\nattribute vec2 vTexCoord2;\n#endif\nvarying highp vec3 dv;varying mediump vec2 d;varying mediump vec3 dA;varying mediump vec3 dB;varying mediump vec3 dC;\n#ifdef VERTEX_COLOR\nvarying lowp vec4 dD;\n#endif\n#ifdef TEXCOORD_SECONDARY\nvarying mediump vec2 dE;\n#endif\nvec3 iW(vec2 v){bool iX=(v.y>(32767.1/65535.0));v.y=iX?(v.y-(32768.0/65535.0)):v.y;vec3 r;r.xy=(2.0*65535.0/32767.0)*v-vec2(1.0);r.z=sqrt(clamp(1.0-dot(r.xy,r.xy),0.0,1.0));r.z=iX?-r.z:r.z;return r;}vec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}vec3 u(mat4 i,vec3 v){return i[0].xyz*v.x+i[1].xyz*v.y+i[2].xyz*v.z;}void main(void){gl_Position=h(uModelViewProjectionMatrix,vPosition.xyz);d=vTexCoord+uUVOffset;dA=u(uSkyMatrix,iW(vTangent));dB=u(uSkyMatrix,iW(vBitangent));dC=u(uSkyMatrix,iW(vNormal));dv=h(uSkyMatrix,vPosition.xyz).xyz;\n#ifdef VERTEX_COLOR\ndD=vColor;\n#endif\n#ifdef TEXCOORD_SECONDARY\ndE=vTexCoord2;\n#endif\n}", 34463"postaa.glsl":"precision mediump float;uniform sampler2D tInput;varying vec2 j;void main(void){gl_FragColor=texture2D(tInput,j);}","postfrag.glsl":"precision mediump float;uniform sampler2D tInput;\n#ifdef BLOOM\nuniform sampler2D tBloom;\n#endif\n#ifdef GRAIN\nuniform sampler2D tGrain;\n#endif\n#ifdef COLOR_LUT\nuniform sampler2D tLUT;\n#endif\nuniform vec3 uScale;uniform vec3 uBias;uniform vec3 uSaturation;uniform vec4 uSharpenKernel;uniform vec3 uSharpness;uniform vec3 uBloomColor;uniform vec4 uVignetteAspect;uniform vec4 uVignette;uniform vec4 uGrainCoord;uniform vec2 uGrainScaleBias;varying vec2 j;vec3 iY(vec3 c){vec3 iZ=sqrt(c);return(iZ-iZ*c)+c*(0.4672*c+vec3(0.5328));}void main(void){vec4 jc=texture2D(tInput,j);vec3 c=jc.xyz;\n#ifdef SHARPEN\nvec3 hM=texture2D(tInput,j+uSharpenKernel.xy).xyz;hM+=texture2D(tInput,j-uSharpenKernel.xy).xyz;hM+=texture2D(tInput,j+uSharpenKernel.zw).xyz;hM+=texture2D(tInput,j-uSharpenKernel.zw).xyz;vec3 jd=uSharpness.x*c-uSharpness.y*hM;c+=clamp(jd,-uSharpness.z,uSharpness.z);\n#endif\n#ifdef BLOOM\nc+=uBloomColor*texture2D(tBloom,j).xyz;\n#endif\n#ifdef VIGNETTE\nvec2 je=j*uVignetteAspect.xy-uVignetteAspect.zw;vec3 v=clamp(vec3(1.0,1.0,1.0)-uVignette.xyz*dot(je,je),0.0,1.0);vec3 jf=v*v;jf*=v;c*=mix(v,jf,uVignette.w);\n#endif\n#ifdef SATURATION\nfloat gray=dot(c,vec3(0.3,0.59,0.11));c=mix(vec3(gray,gray,gray),c,uSaturation);\n#endif\n#ifdef CONTRAST\nc=c*uScale+uBias;\n#endif\n#ifdef GRAIN\nfloat jh=uGrainScaleBias.x*texture2D(tGrain,j*uGrainCoord.xy+uGrainCoord.zw).x+uGrainScaleBias.y;c+=c*jh;\n#endif\n#ifdef REINHARD\n{c*=1.8;float ji=dot(c,vec3(0.3333));c=clamp(c/(1.0+ji),0.0,1.0);}\n#elif defined(HEJL)\n{const highp float jj=0.22,jk=0.3,jl=.1,jm=0.2,jn=.01,jo=0.3;const highp float ju=1.25;highp vec3 eO=max(vec3(0.0),c-vec3(.004));c=(eO*((ju*jj)*eO+ju*vec3(jl*jk,jl*jk,jl*jk))+ju*vec3(jm*jn,jm*jn,jm*jn))/(eO*(jj*eO+vec3(jk,jk,jk))+vec3(jm*jo,jm*jo,jm*jo))-ju*vec3(jn/jo,jn/jo,jn/jo);}\n#endif\n#ifdef COLOR_LUT\nc=clamp(c,0.0,1.0);c=(255.0/256.0)*c+vec3(0.5/256.0);c.x=texture2D(tLUT,c.xx).x;c.y=texture2D(tLUT,c.yy).y;c.z=texture2D(tLUT,c.zz).z;c*=c;\n#endif\ngl_FragColor.xyz=iY(c);gl_FragColor.w=jc.w;}", 34464"postvert.glsl":"precision highp float;attribute vec2 vCoord;varying vec2 j;void main(void){j=vCoord;gl_Position.xy=2.0*vCoord-vec2(1.0,1.0);gl_Position.zw=vec2(0.0,1.0);}","shadowfloorfrag.glsl":"precision mediump float;varying highp vec3 dv;varying mediump vec2 jv;varying mediump vec3 dC;uniform vec3 uShadowCatcherParams;\n#ifdef LIGHT_COUNT\nuniform vec4 uLightPositions[LIGHT_COUNT];uniform vec3 uLightDirections[LIGHT_COUNT];uniform vec3 uLightColors[LIGHT_COUNT];uniform vec3 uLightParams[LIGHT_COUNT];uniform vec3 uLightSpot[LIGHT_COUNT];\n#endif\n#define saturate(x) clamp( x, 0.0, 1.0 )\n#define SHADOW_COMPARE(a,b) ((a) < (b) || (b) >= 1.0 ? 1.0 : 0.0)\n#define SHADOW_CLIP(c,v) ((c.x<0.0 || c.x>1.0 || c.y<0.0 || c.y>1.0) ? 1.0 : v)\n#include <matshadows.glsl>\nvoid main(void){ev eA;eB(eA,SHADOW_KERNEL);vec3 jA=vec3(0.0,0.0,0.0);vec3 jB=vec3(0.0,0.0,0.0);for(int k=0;k<SHADOW_COUNT;++k){vec3 eH=uLightPositions[k].xyz-dv*uLightPositions[k].w;float eI=inversesqrt(dot(eH,eH));eH*=eI;float a=saturate(uLightParams[k].z/eI);a=1.0+a*(uLightParams[k].x+uLightParams[k].y*a);float s=saturate(dot(eH,uLightDirections[k]));s=saturate(uLightSpot[k].y-uLightSpot[k].z*(1.0-s*s));vec3 jC=mix(uLightColors[k].xyz,vec3(1.0,1.0,1.0),uShadowCatcherParams.x);vec3 jD=(a*s)*jC;jD*=saturate(dot(eH,dC));jB+=jD;jA+=jD*eA.eL[k];}float jE=1.0e-4;vec3 r=(jA+jE)/(jB+jE);float jF=saturate(dot(jv,jv))*uShadowCatcherParams.z;r=mix(r,vec3(1.0,1.0,1.0),jF);r=mix(vec3(1.0,1.0,1.0),r,uShadowCatcherParams.y);gl_FragColor.xyz=r;gl_FragColor.w=1.0;}", 34465"shadowfloorvert.glsl":"precision highp float;uniform mat4 uModelViewProjectionMatrix;uniform mat4 uModelSkyMatrix;uniform float uScale;attribute vec3 vPosition;varying highp vec3 dv;varying mediump vec2 jv;varying mediump vec3 dC;vec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}void main(void){jv=vPosition.xz;dC=normalize(uModelSkyMatrix[1].xyz);dv=h(uModelSkyMatrix,vPosition).xyz;gl_Position=h(uModelViewProjectionMatrix,vPosition);}","shadowfrag.glsl":"precision highp float;varying vec2 jG;\n#ifdef ALPHA_TEST\nvarying mediump vec2 d;uniform sampler2D tAlbedo;
34465\n#endif\nvec3 jH(float v){vec4 jI=vec4(1.0,255.0,65025.0,16581375.0)*v;jI=fract(jI);jI.xyz-=jI.yzw*(1.0/255.0);return jI.xyz;}void main(void){\n#ifdef ALPHA_TEST\nfloat e=texture2D(tAlbedo,d).a;if(e<0.5){discard;}\n#endif\n#ifdef SHADOW_NATIVE_DEPTH\ngl_FragColor.xyz=vec3(0.0,0.0,0.0);\n#else\ngl_FragColor.xyz=jH((jG.x/jG.y)*0.5+0.5);\n#endif\ngl_FragColor.w=0.0;}", 34466"shadowvert.glsl":"precision highp float;attribute vec3 vPosition;attribute vec2 vTexCoord;uniform mat4 uMeshTransform;uniform mat4 uViewProjection;varying vec2 jG;\n#ifdef ALPHA_TEST\nvarying mediump vec2 d;uniform vec2 uUVOffset;\n#endif\nvec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}void main(void){vec3 p=h(uMeshTransform,vPosition).xyz;gl_Position=h(uViewProjection,p);jG=gl_Position.zw;\n#ifdef ALPHA_TEST\nd=vTexCoord+uUVOffset;\n#endif\n}","sky.glsl":"precision highp float;uniform sampler2D tSkyTexture;uniform float uAlpha;varying vec2 d;void main(void){vec3 r=texture2D(tSkyTexture,d).xyz;gl_FragColor.xyz=r*r;gl_FragColor.w=uAlpha;}", 34467"skySH.glsl":"precision mediump float;uniform vec4 uSkyCoefficients[9];uniform float uAlpha;varying vec3 jJ;void main(void){vec3 G=normalize(jJ);vec3 r=uSkyCoefficients[0].xyz;r+=uSkyCoefficients[1].xyz*G.y;r+=uSkyCoefficients[2].xyz*G.z;r+=uSkyCoefficients[3].xyz*G.x;vec3 swz=G.yyz*G.xzx;r+=uSkyCoefficients[4].xyz*swz.x;r+=uSkyCoefficients[5].xyz*swz.y;r+=uSkyCoefficients[7].xyz*swz.z;vec3 sqr=G*G;r+=uSkyCoefficients[6].xyz*(3.0*sqr.z-1.0);r+=uSkyCoefficients[8].xyz*(sqr.x-sqr.y);gl_FragColor.xyz=r;gl_FragColor.w=uAlpha;}", 34468"skyvert.glsl":"precision highp float;uniform mat4 uInverseSkyMatrix;uniform mat4 uViewProjection;attribute vec3 vPosition;attribute vec2 vTexCoord;\n#if SKYMODE == 3\nvarying vec3 jJ;\n#else\nvarying vec2 d;\n#endif\nvec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}vec4 u(mat4 i,vec3 v){return i[0]*v.x+i[1]*v.y+i[2]*v.z;}void main(void){vec3 p=h(uInverseSkyMatrix,vPosition).xyz;gl_Position=u(uViewProjection,p);gl_Position.z-=(1.0/65535.0)*gl_Position.w;\n#if SKYMODE == 3\njJ=vPosition;jJ.xy+=1e-20*vTexCoord;\n#else\nd=vTexCoord;\n#endif\n}", 34469"wirefrag.glsl":"precision highp float;uniform vec4 uStripParams;void main(void){vec2 c=gl_FragCoord.xy*uStripParams.xy-vec2(1.0,1.0);c.x+=0.25*c.y;float a=c.x<uStripParams.z?0.0:0.9;a=c.x<uStripParams.w?a:0.0;gl_FragColor=vec4(0.0,0.0,0.0,a);}","wirevert.glsl":"precision highp float;uniform mat4 uModelViewProjectionMatrix;attribute vec3 vPosition;vec4 h(mat4 i,vec3 p){return i[0]*p.x+(i[1]*p.y+(i[2]*p.z+i[3]));}void main(void){gl_Position=h(uModelViewProjectionMatrix,vPosition);gl_Position.z+=-0.00005*gl_Position.w;}", 34470nil:""};})(marmoset); 34471(function() { 34472 if (App.Widgets == null) { 34473 App.Widgets = {}; 34474 } 34475 34476}).call(this); 34477(function() { 34478 App.Widgets.AnchorsManager = (function() { 34479 function AnchorsManager() {} 34480 34481 AnchorsManager.prototype.initialize = function() { 34482 if (location.hash) { 34483 return setTimeout(function() { 34484 var allowToJumpTo; 34485 allowToJumpTo = ['#tab-comments']; 34486 if (_.include(location.hash, '#tab-') && !_.include(allowToJumpTo, location.hash)) { 34487 return window.scrollTo(0, 0); 34488 } 34489 }, 1); 34490 } 34491 }; 34492 34493 return AnchorsManager; 34494 34495 })(); 34496 34497}).call(this); 34498(function() { 34499 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 34500 34501 App.Widgets.AuthControl = (function() { 34502 function AuthControl() { 34503 this.onModalClick = bind(this.onModalClick, this); 34504 this.requestAuthControl = bind(this.requestAuthControl, this); 34505 } 34506 34507 AuthControl.prototype.initialize = function() { 34508 var $notificationBar; 34509 $(document).on('click', '.js-modal', this.onModalClick); 34510 if (App.config.isSupportSession) { 34511 $notificationBar = $(JST["support/notification_bar"]({ 34512 username: App.config.username 34513 })); 34514 return $notificationBar.insertAfter('.notification-bar'); 34515 } else { 34516 return $(document).on('click', '.js-auth-control', this.requestAuthControl); 34517 } 34518 }; 34519 34520 AuthControl.prototype.requestAuthControl = function(event) { 34521 if (App.config.userSignedIn) { 34522 return; 34523 } 34524 event.preventDefault(); 34525 event.stopPropagation(); 34526 return App.events.publish('app:login:open'); 34527 }; 34528 34529 AuthControl.prototype.onModalClick = function(event) { 34530 var modalId; 34531 event.preventDefault(); 34532 if ($(this).hasClass('js-auth-control') && !App.config.userSignedIn) { 34533 return; 34534 } 34535 modalId = $(event.currentTarget).attr('href') || $(event.currentTarget).data('href'); 34536 return $(modalId).makeMeModal(); 34537 }; 34538 34539 return AuthControl; 34540 34541 })(); 34542 34543}).call(this); 34544(function() { 34545 App.Widgets.AutoDisableLink = (function() { 34546 function AutoDisableLink() {} 34547 34548 AutoDisableLink.prototype.initialize = function() { 34549 return $(document).on('click', '.js-auto-disable-link', function(event) { 34550 var linkOrButton; 34551 linkOrButton = $(this); 34552 if (linkOrButton.attr('disabled')) { 34553 event.stopPropagation(); 34554 return event.preventDefault(); 34555 } else { 34556 return setTimeout(function() { 34557 return linkOrButton.attr('disabled', true); 34558 }, 100); 34559 } 34560 }); 34561 }; 34562 34563 return AutoDisableLink; 34564 34565 })(); 34566 34567}).call(this); 34568(function() { 34569 App.Widgets.BackendEvents = (function() { 34570 function BackendEvents() {} 34571 34572 BackendEvents.prototype.initialize = function() { 34573 return this.pushGTMEventsToDataLayer(); 34574 }; 34575 34576 BackendEvents.prototype.pushGTMEventsToDataLayer = function() { 34577 var e, i, len; 34578 for (i = 0, len = customDataLayer.length; i < len; i++) { 34579 e = customDataLayer[i]; 34580 dataLayer.push(e); 34581 } 34582 return true; 34583 }; 34584 34585 return BackendEvents; 34586 34587 })(); 34588 34589}).call(this); 34590(function() { 34591 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 34592 34593 App.Widgets.BuyButton = (function() { 34594 function BuyButton() { 34595 this.onJsOrderClicked = bind(this.onJsOrderClicked, this); 34596 } 34597 34598 BuyButton.prototype.initialize = function() { 34599 return this.bindEvents(); 34600 }; 34601 34602 BuyButton.prototype.bindEvents = function() { 34603 return $(document).on('click', '.js-order', this.onJsOrderClicked); 34604 }; 34605 34606 BuyButton.prototype.onJsOrderClicked = function(event) { 34607 mute(event); 34608 return this.addToCart($(event.currentTarget), "/api/internal/cg/items", { 34609 kind: 'cg' 34610 }, function(response) { 34611 return true; 34612 }); 34613 }; 34614 34615 BuyButton.prototype.addToCart = function(button, path, data, callback) { 34616 var itemId; 34617 if (data == null) { 34618 data = {}; 34619 } 34620 button.attr('disabled', true); 34621 itemId = button.data('id'); 34622 data.offer_id = button.data('offer-id'); 34623 data.meta_source = button.data('meta-source'); 34624 data.meta_referrer = document.referrer != null ? document.referrer : location.href;
34625 return $.ajax(path + "/" + itemId + "/cart_items?locale=" + I18n.locale, { 34626 data: data, 34627 method: 'POST', 34628 error: function(jqXHR) { 34629 App.events.publish("app:notification:flash:error", jqXHR.responseJSON.errors.detail); 34630 return button.attr('disabled', false); 34631 }, 34632 success: function(data) { 34633 var message; 34634 message = data.included[0].attributes.title + " " + (I18n.t('navigation.item_add_message')); 34635 App.events.publish('app:cart:added', data); 34636 App.events.publish('app:cart:add', data.data.attributes.kind); 34637 App.events.publish("app:notification:flash:success", message); 34638 if (typeof callback === "function") { 34639 callback(data); 34640 } 34641 return button.attr('disabled', false); 34642 } 34643 }); 34644 }; 34645 34646 return BuyButton; 34647 34648 })(); 34649 34650}).call(this); 34651(function() { 34652 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 34653 34654 App.Widgets.Comments = (function() { 34655 Comments.prototype.$el = null; 34656 34657 function Comments(options) { 34658 this.remove = bind(this.remove, this); 34659 this.replyTo = bind(this.replyTo, this); 34660 this.edit = bind(this.edit, this); 34661 if (options == null) { 34662 return; 34663 } 34664 this.options = options; 34665 this.$el = options.el; 34666 } 34667 34668 Comments.prototype.initialize = function() { 34669 var data; 34670 if (!((this.$el != null) && this.$el.exists())) { 34671 this.$el = $(".comments"); 34672 } 34673 data = this.$el.data(); 34674 if (!data) { 34675 return; 34676 } 34677 this.commentableType = data.commentable_type; 34678 this.commentableId = data.commentable_id; 34679 this.initPlugins(); 34680 this.initNewCommentForm(); 34681 this.bindEvents(); 34682 return this.showButtons(); 34683 }; 34684 34685 Comments.prototype.bindEvents = function() { 34686 this.$el.find('.comment .js-reply').on('click', this.replyTo); 34687 this.$el.find('.comment .js-edit').on('click', this.edit); 34688 return this.$el.find('.comment .js-remove').on('click', this.remove); 34689 }; 34690 34691 Comments.prototype.edit = function(e) { 34692 var $el, comment; 34693 $el = $(e.currentTarget).closest(".comment").addClass('is-edited'); 34694 comment = new App.Backbone.Models.Comment({ 34695 id: $el.data('id') 34696 }); 34697 return comment.fetch({ 34698 success: (function(_this) { 34699 return function() { 34700 var editForm; 34701 editForm = new App.Backbone.Views.Comments.Form({ 34702 model: comment 34703 }).render(); 34704 $el.html(editForm.el); 34705 return App.events.once('app:comment:posted', function() { 34706 return $el.removeClass('is-edited'); 34707 }); 34708 }; 34709 })(this) 34710 }); 34711 }; 34712 34713 Comments.prototype.replyTo = function(e) { 34714 var $el, newComment, newCommentContainer, newCommentDepth, newForm; 34715 $el = $(e.currentTarget).parents('.comment'); 34716 newComment = new App.Backbone.Models.Comment({ 34717 parent_id: $el.data('id'), 34718 commentable_type: this.commentableType, 34719 commentable_id: this.commentableId 34720 }); 34721 newForm = new App.Backbone.Views.Comments.Form({ 34722 model: newComment 34723 }).render(); 34724 newCommentContainer = $('<article class="comment"></article>'); 34725 newCommentDepth = 1; 34726 newCommentContainer.addClass("comment--depth-" + newCommentDepth); 34727 newCommentContainer.html(newForm.el); 34728 return $(newCommentContainer).insertAfter($el); 34729 }; 34730 34731 Comments.prototype.remove = function(e) { 34732 var $el, comment; 34733 $el = $(e.currentTarget).closest('.comment'); 34734 comment = new App.Backbone.Models.Comment({ 34735 id: $el.data('id') 34736 }); 34737 comment.destroy(); 34738 $el.nextUntil('.comment--depth-0').hide('slow'); 34739 return $el.hide('slow'); 34740 }; 34741 34742 Comments.prototype.initNewCommentForm = function() { 34743 var newComment, newForm; 34744 newComment = new App.Backbone.Models.Comment({ 34745 commentable_type: this.commentableType, 34746 commentable_id: this.commentableId 34747 }); 34748 newForm = new App.Backbone.Views.Comments.Form({ 34749 model: newComment 34750 }).render(); 34751 if ((this.options != null) && this.options.placement === 'append') { 34752 return this.$el.append(newForm.el); 34753 } else { 34754 return this.$el.prepend(newForm.el); 34755 } 34756 }; 34757 34758 Comments.prototype.initPlugins = function() { 34759 return this.$el.find(".timeago").timeago(); 34760 }; 34761 34762 Comments.prototype.showButtons = function() { 34763 return this.$el.find('.comment').each(function(i, el) { 34764 var $comment; 34765 $comment = $(el); 34766 if (App.config.userId === $comment.data('author-id')) { 34767 $comment.find(".comment__actions .js-edit").removeClass('is-hidden'); 34768 } else { 34769 $comment.find(".comment__actions .js-reply").removeClass('is-hidden'); 34770 } 34771 if (App.config.isAdmin) { 34772 return $comment.find(".comment__actions .js-remove").removeClass('is-hidden'); 34773 } 34774 }); 34775 }; 34776 34777 return Comments; 34778 34779 })(); 34780 34781}).call(this); 34782(function() { 34783 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 34784 34785 App.Widgets.CookiesPolicy = (function() { 34786 function CookiesPolicy() { 34787 this.closeCookiesModal = bind(this.closeCookiesModal, this); 34788 this.closeCookiesPolicy = bind(this.closeCookiesPolicy, this); 34789 this.acceptCookiesPolicy = bind(this.acceptCookiesPolicy, this); 34790 } 34791 34792 CookiesPolicy.prototype.initialize = function() { 34793 var cookieEnabled, noticeAlreadyExists; 34794 if (gon.cookies_map == null) { 34795 return; 34796 } 34797 if (App.config.environment === 'test') { 34798 return; 34799 } 34800 cookieEnabled = navigator.cookieEnabled;
34801 noticeAlreadyExists = $('.js-inline-cookies'); 34802 if (!cookieEnabled) { 34803 document.cookie = 'testcookie'; 34804 cookieEnabled = document.cookie.indexOf('testcookie') !== -1; 34805 } 34806 if (!(cookieEnabled || App.config.userIsABot)) { 34807 this.showDisabledCookiesModal(); 34808 } 34809 if (!(Cookies.get(gon.cookies_map.cookies_policy_closed) || noticeAlreadyExists)) { 34810 return this.setupUserInteractionListener(); 34811 } 34812 }; 34813 34814 CookiesPolicy.prototype.showNotificationBar = function() { 34815 this.$notificationBar = $(JST["cookies_policy/notification_bar"]()); 34816 $('body').prepend(this.$notificationBar); 34817 this.$notificationBar.find('.js-cookies-policy-accept').on('click', this.acceptCookiesPolicy); 34818 return this.$notificationBar.find('.js-cookies-policy-close').on('click', this.closeCookiesPolicy); 34819 }; 34820 34821 CookiesPolicy.prototype.acceptCookiesPolicy = function() { 34822 this.$notificationBar.hide(); 34823 return Cookies.set(gon.cookies_map.cookies_policy_closed, true, { 34824 expires: 365, 34825 path: '/' 34826 }); 34827 }; 34828 34829 CookiesPolicy.prototype.closeCookiesPolicy = function() { 34830 this.$notificationBar.hide(); 34831 return Cookies.set(gon.cookies_map.cookies_policy_closed, true, { 34832 path: '/' 34833 }); 34834 }; 34835 34836 CookiesPolicy.prototype.showDisabledCookiesModal = function() { 34837 this.$disabledCookiesModal = $(JST["cookies_policy/disabled_cookies_modal"]()); 34838 $('body').prepend(this.$disabledCookiesModal); 34839 return this.$disabledCookiesModal.find('.js-close-modal').on('click', this.closeCookiesModal); 34840 }; 34841 34842 CookiesPolicy.prototype.closeCookiesModal = function() { 34843 return this.$disabledCookiesModal.hide(); 34844 }; 34845 34846 CookiesPolicy.prototype.setupUserInteractionListener = function() { 34847 if (window.setupUserInteractionListener) { 34848 return window.setupUserInteractionListener((function(_this) { 34849 return function() { 34850 return _this.showNotificationBar(); 34851 }; 34852 })(this)); 34853 } else { 34854 this.userHasInteracted = false; 34855 this.handleUserInteraction = (function(_this) { 34856 return function() { 34857 if (_this.userHasInteracted) { 34858 return; 34859 } 34860 _this.userHasInteracted = true; 34861 _this.removeInteractionListeners(); 34862 return _this.showNotificationBar(); 34863 }; 34864 })(this); 34865 $(document).on('click.cookiesPolicy', this.handleUserInteraction); 34866 $(document).on('scroll.cookiesPolicy', this.handleUserInteraction); 34867 $(document).on('keydown.cookiesPolicy', this.handleUserInteraction); 34868 $(document).on('touchstart.cookiesPolicy', this.handleUserInteraction); 34869 return $(document).on('mousemove.cookiesPolicy', this.handleUserInteraction); 34870 } 34871 }; 34872 34873 CookiesPolicy.prototype.removeInteractionListeners = function() { 34874 $(document).off('click.cookiesPolicy'); 34875 $(document).off('scroll.cookiesPolicy'); 34876 $(document).off('keydown.cookiesPolicy'); 34877 $(document).off('touchstart.cookiesPolicy'); 34878 return $(document).off('mousemove.cookiesPolicy'); 34879 }; 34880 34881 return CookiesPolicy; 34882 34883 })(); 34884 34885}).call(this); 34886/** 34887 * @license countdown.js v2.3.3 http://countdownjs.org 34888 * Copyright (c)2006-2012 Stephen M. McKamey. 34889 * Licensed under The MIT License. 34890 */ 34891/*jshint bitwise:false */ 34892 34893/** 34894 * @public 34895 * @type {Object|null} 34896 */ 34897 34898var module; 34899 34900/** 34901 * API entry 34902 * @public 34903 * @param {function(Object)|Date|number} start the starting date 34904 * @param {function(Object)|Date|number} end the ending date 34905 * @param {number} units the units to populate 34906 * @return {Object|number} 34907 */ 34908var countdown = ( 34909 34910 /** 34911 * @param {Object} module CommonJS Module 34912 */ 34913 function(module) { 34914 /*jshint smarttabs:true */ 34915 34916 'use strict'; 34917 34918 /** 34919 * @private 34920 * @const 34921 * @type {number} 34922 */ 34923 var MILLISECONDS = 0x001; 34924 34925 /** 34926 * @private 34927 * @const 34928 * @type {number} 34929 */ 34930 var SECONDS = 0x002; 34931 34932 /** 34933 * @private 34934 * @const 34935 * @type {number} 34936 */ 34937 var MINUTES = 0x004; 34938 34939 /** 34940 * @private 34941 * @const 34942 * @type {number} 34943 */ 34944 var HOURS = 0x008; 34945 34946 /** 34947 * @private 34948 * @const 34949 * @type {number} 34950 */ 34951 var DAYS = 0x010; 34952 34953 /** 34954 * @private 34955 * @const 34956 * @type {number} 34957 */ 34958 var WEEKS = 0x020; 34959 34960 /** 34961 * @private 34962 * @const 34963 * @type {number} 34964 */ 34965 var MONTHS = 0x040; 34966 34967 /** 34968 * @private 34969 * @const 34970 * @type {number} 34971 */ 34972 var YEARS = 0x080; 34973 34974 /** 34975 * @private 34976 * @const 34977 * @type {number} 34978 */ 34979 var DECADES = 0x100; 34980 34981 /** 34982 * @private 34983 * @const 34984 * @type {number} 34985 */ 34986 var CENTURIES = 0x200; 34987 34988 /** 34989 * @private 34990 * @const 34991 * @type {number} 34992 */ 34993 var MILLENNIA = 0x400; 34994 34995 /** 34996 * @private 34997 * @const 34998 * @type {number} 34999 */ 35000 var DEFAULTS = YEARS|MONTHS|DAYS|HOURS|MINUTES|SECONDS; 35001 35002 /** 35003 * @private 35004 * @const 35005 * @type {number} 35006 */ 35007 var MILLISECONDS_PER_SECOND = 1000; 35008 35009 /** 35010 * @private 35011 * @const 35012 * @type {number} 35013 */ 35014 var SECONDS_PER_MINUTE = 60; 35015 35016 /** 35017 * @private 35018 * @const 35019 * @type {number} 35020 */ 35021 var MINUTES_PER_HOUR = 60; 35022 35023 /** 35024 * @private 35025 * @const 35026 * @type {number} 35027 */ 35028 var HOURS_PER_DAY = 24; 35029 35030 /** 35031 * @private 35032 * @const 35033 * @type {number} 35034 */ 35035 var MILLISECONDS_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND; 35036 35037 /** 35038 * @private 35039 * @const 35040 * @type {number} 35041 */ 35042 var DAYS_PER_WEEK = 7; 35043 35044 /** 35045 * @private 35046 * @const 35047 * @type {number} 35048 */ 35049 var MONTHS_PER_YEAR = 12; 35050 35051 /** 35052 * @private 35053 * @const 35054 * @type {number} 35055 */ 35056 var YEARS_PER_DECADE = 10; 35057 35058 /** 35059 * @private 35060 * @const 35061 * @type {number} 35062 */ 35063 var DECADES_PER_CENTURY = 10; 35064 35065 /** 35066 * @private 35067 * @const 35068 * @type {number} 35069 */ 35070 var CENTURIES_PER_MILLENNIUM = 10; 35071 35072 /** 35073 * @private 35074 * @param {number} x number 35075 * @return {number} 35076 */
35077 var ceil = Math.ceil; 35078 35079 /** 35080 * @private 35081 * @param {number} x number 35082 * @return {number} 35083 */ 35084 var floor = Math.floor; 35085 35086 /** 35087 * @private 35088 * @param {Date} ref reference date 35089 * @param {number} shift number of months to shift 35090 * @return {number} number of days shifted 35091 */ 35092 function borrowMonths(ref, shift) { 35093 var prevTime = ref.getTime(); 35094 35095 // increment month by shift 35096 ref.setUTCMonth( ref.getUTCMonth() + shift ); 35097 35098 // this is the trickiest since months vary in length 35099 return Math.round( (ref.getTime() - prevTime) / MILLISECONDS_PER_DAY ); 35100 } 35101 35102 /** 35103 * @private 35104 * @param {Date} ref reference date 35105 * @return {number} number of days 35106 */ 35107 function daysPerMonth(ref) { 35108 var a = ref.getTime(); 35109 35110 // increment month by 1 35111 var b = new Date(a); 35112 b.setUTCMonth( ref.getUTCMonth() + 1 ); 35113 35114 // this is the trickiest since months vary in length 35115 return Math.round( (b.getTime() - a) / MILLISECONDS_PER_DAY ); 35116 } 35117 35118 /** 35119 * @private 35120 * @param {Date} ref reference date 35121 * @return {number} number of days 35122 */ 35123 function daysPerYear(ref) { 35124 var a = ref.getTime(); 35125 35126 // increment year by 1 35127 var b = new Date(a); 35128 b.setUTCFullYear( ref.getUTCFullYear() + 1 ); 35129 35130 // this is the trickiest since years (periodically) vary in length 35131 return Math.round( (b.getTime() - a) / MILLISECONDS_PER_DAY ); 35132 } 35133 35134 /** 35135 * @private 35136 * @const 35137 * @type {number} 35138 */ 35139 var LABEL_MILLISECONDS = 0; 35140 35141 /** 35142 * @private 35143 * @const 35144 * @type {number} 35145 */ 35146 var LABEL_SECONDS = 1; 35147 35148 /** 35149 * @private 35150 * @const 35151 * @type {number} 35152 */ 35153 var LABEL_MINUTES = 2; 35154 35155 /** 35156 * @private 35157 * @const 35158 * @type {number} 35159 */ 35160 var LABEL_HOURS = 3; 35161 35162 /** 35163 * @private 35164 * @const 35165 * @type {number} 35166 */ 35167 var LABEL_DAYS = 4; 35168 35169 /** 35170 * @private 35171 * @const 35172 * @type {number} 35173 */ 35174 var LABEL_WEEKS = 5; 35175 35176 /** 35177 * @private 35178 * @const 35179 * @type {number} 35180 */ 35181 var LABEL_MONTHS = 6; 35182 35183 /** 35184 * @private 35185 * @const 35186 * @type {number} 35187 */ 35188 var LABEL_YEARS = 7; 35189 35190 /** 35191 * @private 35192 * @const 35193 * @type {number} 35194 */ 35195 var LABEL_DECADES = 8; 35196 35197 /** 35198 * @private 35199 * @const 35200 * @type {number} 35201 */ 35202 var LABEL_CENTURIES = 9; 35203 35204 /** 35205 * @private 35206 * @const 35207 * @type {number} 35208 */ 35209 var LABEL_MILLENNIA = 10; 35210 35211 /** 35212 * @private 35213 * @const 35214 * @type {Array} 35215 */ 35216 var LABELS_SINGLUAR; 35217 35218 /** 35219 * @private 35220 * @const 35221 * @type {Array} 35222 */ 35223 var LABELS_PLURAL; 35224 35225 /** 35226 * @private 35227 * @param {number} value 35228 * @param {number} unit unit index into label list 35229 * @return {string} 35230 */ 35231 function plurality(value, unit) { 35232 return value+' '+((value === 1) ? LABELS_SINGLUAR[unit] : LABELS_PLURAL[unit]); 35233 } 35234 35235 /** 35236 * Formats the entries as English labels 35237 * 35238 * @private 35239 * @param {Timespan} ts 35240 * @return {Array} 35241 */ 35242 var formatList; 35243 35244 /** 35245 * Timespan representation of a duration of time 35246 * 35247 * @private 35248 * @this {Timespan} 35249 * @constructor 35250 */ 35251 function Timespan() {} 35252 35253 /** 35254 * Formats the Timespan as a sentance 35255 * 35256 * @private 35257 * @return {string} 35258 */ 35259 Timespan.prototype.toString = function() { 35260 var label = formatList(this); 35261 35262 var count = label.length; 35263 if (!count) { 35264 return ''; 35265 } 35266 if (count > 1) { 35267 label[count-1] = 'and '+label[count-1]; 35268 } 35269 return label.join(', '); 35270 }; 35271 35272 /** 35273 * Formats the Timespan as HTML 35274 * 35275 * @private 35276 * @param {string} tag HTML tag name to wrap each value 35277 * @return {string} 35278 */ 35279 Timespan.prototype.toHTML = function(tag) { 35280 tag = tag || 'span'; 35281 var label = formatList(this); 35282 35283 var count = label.length; 35284 if (!count) { 35285 return ''; 35286 } 35287 for (var i=0; i<count; i++) { 35288 // wrap each unit in tag 35289 label[i] = '<'+tag+'>'+label[i]+'</'+tag+'>'; 35290 } 35291 if (--count) { 35292 label[count] = 'and '+label[count]; 35293 } 35294 return label.join(', '); 35295 }; 35296 35297 /** 35298 * Formats the entries as English labels 35299 * 35300 * @private 35301 * @param {Timespan} ts 35302 * @return {Array} 35303 */ 35304 formatList = function(ts) { 35305 var list = []; 35306 35307 var value = ts.millennia; 35308 if (value) { 35309 list.push(plurality(value, LABEL_MILLENNIA)); 35310 } 35311 35312 value = ts.centuries; 35313 if (value) { 35314 list.push(plurality(value, LABEL_CENTURIES)); 35315 } 35316 35317 value = ts.decades; 35318 if (value) { 35319 list.push(plurality(value, LABEL_DECADES)); 35320 } 35321 35322 value = ts.years; 35323 if (value) { 35324 list.push(plurality(value, LABEL_YEARS)); 35325 } 35326 35327 value = ts.months; 35328 if (value) { 35329 list.push(plurality(value, LABEL_MONTHS)); 35330 } 35331 35332 value = ts.weeks; 35333 if (value) { 35334 list.push(plurality(value, LABEL_WEEKS)); 35335 } 35336 35337 value = ts.days; 35338 if (value) { 35339 list.push(plurality(value, LABEL_DAYS)); 35340 } 35341 35342 value = ts.hours; 35343 if (value) { 35344 list.push(plurality(value, LABEL_HOURS)); 35345 } 35346 35347 value = ts.minutes; 35348 if (value) { 35349 list.push(plurality(value, LABEL_MINUTES)); 35350 } 35351 35352 value = ts.seconds; 35353 if (value) { 35354 list.push(plurality(value, LABEL_SECONDS)); 35355 } 35356 35357 value = ts.milliseconds; 35358 if (value) { 35359 list.push(plurality(value, LABEL_MILLISECONDS)); 35360 } 35361 35362 return list; 35363 }; 35364 35365 /** 35366 * Borrow any underflow units, carry any overflow units 35367 * 35368 * @private 35369 * @param {Timespan} ts 35370 * @param {string} toUnit 35371 */ 35372 function rippleRounded(ts, toUnit) { 35373 switch (toUnit) { 35374 case 'seconds': 35375 if (ts.seconds !== SECONDS_PER_MINUTE || isNaN(ts.minutes)) { 35376 return; 35377 } 35378 // ripple seconds up to minutes 35379 ts.minutes++; 35380 ts.seconds = 0; 35381 35382 /* falls through */ 35383 case 'minutes': 35384 if (ts.minutes !== MINUTES_PER_HOUR || isNaN(ts.hours)) { 35385 return; 35386 } 35387 // ripple minutes up to hours 35388 ts.hours++; 35389 ts.minutes = 0; 35390 35391 /* falls through */ 35392 case 'hours': 35393 if (ts.hours !== HOURS_PER_DAY || isNaN(ts.days)) { 35394 return; 35395 } 35396 // ripple hours up to days 35397 ts.days++; 35398 ts.hours = 0; 35399 35400 /* falls through */ 35401 case 'days': 35402 if (ts.days !== DAYS_PER_WEEK || isNaN(ts.weeks)) { 35403 return; 35404 } 35405 // ripple days up to weeks 35406 ts.weeks++; 35407 ts.days = 0; 35408 35409 /* falls through */ 35410 case 'weeks': 35411 if (ts.weeks !== daysPerMonth(ts.refMonth)/DAYS_PER_WEEK || isNaN(ts.months)) { 35412 return; 35413 } 35414 // ripple weeks up to months 35415 ts.months++; 35416 ts.weeks = 0; 35417 35418 /* falls through */ 35419 case 'months': 35420 if (ts.months !== MONTHS_PER_YEAR || isNaN(ts.years)) { 35421 return; 35422 } 35423 // ripple months up to years 35424 ts.years++; 35425 ts.months = 0; 35426 35427 /* falls through */ 35428 case 'years': 35429 if (ts.years !== YEARS_PER_DECADE || isNaN(ts.decades)) { 35430 return; 35431 } 35432 // ripple years up to decades 35433 ts.decades++; 35434 ts.years = 0; 35435 35436 /* falls through */ 35437 case 'decades': 35438 if (ts.decades !== DECADES_PER_CENTURY || isNaN(ts.centuries)) { 35439 return; 35440 } 35441 // ripple decades up to centuries 35442 ts.centuries++; 35443 ts.decades = 0; 35444 35445 /* falls through */ 35446 case 'centuries': 35447 if (ts.centuries !== CENTURIES_PER_MILLENNIUM || isNaN(ts.millennia)) { 35448 return; 35449 } 35450 // ripple centuries up to millennia 35451 ts.millennia++; 35452 ts.centuries = 0; 35453 /* falls through */ 35454 } 35455 } 35456 35457 /** 35458 * Ripple up partial units one place 35459 * 35460 * @private 35461 * @param {Timespan} ts timespan 35462 * @param {number} frac accumulated fractional value 35463 * @param {string} fromUnit source unit name 35464 * @param {string} toUnit target unit name 35465 * @param {number} conversion multiplier between units 35466 * @param {number} digits max number of decimal digits to output 35467 * @return {number} new fractional value 35468 */ 35469 function fraction(ts, frac, fromUnit, toUnit, conversion, digits) { 35470 if (ts[fromUnit] >= 0) { 35471 frac += ts[fromUnit]; 35472 delete ts[fromUnit]; 35473 } 35474 35475 frac /= conversion; 35476 if (frac + 1 <= 1) { 35477 // drop if below machine epsilon 35478 return 0; 35479 } 35480 35481 if (ts[toUnit] >= 0) { 35482 // ensure does not have more than specified number of digits 35483 ts[toUnit] = +(ts[toUnit] + frac).toFixed(digits); 35484 rippleRounded(ts, toUnit); 35485 return 0; 35486 } 35487 35488 return frac; 35489 } 35490 35491 /** 35492 * Ripple up partial units to next existing 35493 * 35494 * @private 35495 * @param {Timespan} ts 35496 * @param {number} digits max number of decimal digits to output 35497 */ 35498 function fractional(ts, digits) { 35499 var frac = fraction(ts, 0, 'milliseconds', 'seconds', MILLISECONDS_PER_SECOND, digits); 35500 if (!frac) { return; } 35501 35502 frac = fraction(ts, frac, 'seconds', 'minutes', SECONDS_PER_MINUTE, digits); 35503 if (!frac) { return; } 35504 35505 frac = fraction(ts, frac, 'minutes', 'hours', MINUTES_PER_HOUR, digits); 35506 if (!frac) { return; } 35507 35508 frac = fraction(ts, frac, 'hours', 'days', HOURS_PER_DAY, digits); 35509 if (!frac) { return; } 35510 35511 frac = fraction(ts, frac, 'days', 'weeks', DAYS_PER_WEEK, digits); 35512 if (!frac) { return; } 35513 35514 frac = fraction(ts, frac, 'weeks', 'months', daysPerMonth(ts.refMonth)/DAYS_PER_WEEK, digits); 35515 if (!frac) { return; } 35516 35517 frac = fraction(ts, frac, 'months', 'years', daysPerYear(ts.refMonth)/daysPerMonth(ts.refMonth), digits); 35518 if (!frac) { return; } 35519 35520 frac = fraction(ts, frac, 'years', 'decades', YEARS_PER_DECADE, digits); 35521 if (!frac) { return; } 35522 35523 frac = fraction(ts, frac, 'decades', 'centuries', DECADES_PER_CENTURY, digits); 35524 if (!frac) { return; } 35525 35526 frac = fraction(ts, frac, 'centuries', 'millennia', CENTURIES_PER_MILLENNIUM, digits); 35527 35528 // should never reach this with remaining fractional value 35529 if (frac) { throw new Error('Fractional unit overflow'); } 35530 } 35531 35532 /** 35533 * Borrow any underflow units, carry any overflow units 35534 * 35535 * @private 35536 * @param {Timespan} ts 35537 */ 35538 function ripple(ts) { 35539 var x; 35540 35541 if (ts.milliseconds < 0) { 35542 // ripple seconds down to milliseconds 35543 x = ceil(-ts.milliseconds / MILLISECONDS_PER_SECOND); 35544 ts.seconds -= x; 35545 ts.milliseconds += x * MILLISECONDS_PER_SECOND; 35546 35547 } else if (ts.milliseconds >= MILLISECONDS_PER_SECOND) { 35548 // ripple milliseconds up to seconds 35549 ts.seconds += floor(ts.milliseconds / MILLISECONDS_PER_SECOND); 35550 ts.milliseconds %= MILLISECONDS_PER_SECOND; 35551 } 35552 35553 if (ts.seconds < 0) { 35554 // ripple minutes down to seconds 35555 x = ceil(-ts.seconds / SECONDS_PER_MINUTE); 35556 ts.minutes -= x; 35557 ts.seconds += x * SECONDS_PER_MINUTE; 35558 35559 } else if (ts.seconds >= SECONDS_PER_MINUTE) { 35560 // ripple seconds up to minutes 35561 ts.minutes += floor(ts.seconds / SECONDS_PER_MINUTE); 35562 ts.seconds %= SECONDS_PER_MINUTE; 35563 } 35564 35565 if (ts.minutes < 0) { 35566 // ripple hours down to minutes 35567 x = ceil(-ts.minutes / MINUTES_PER_HOUR); 35568 ts.hours -= x; 35569 ts.minutes += x * MINUTES_PER_HOUR; 35570 35571 } else if (ts.minutes >= MINUTES_PER_HOUR) { 35572 // ripple minutes up to hours 35573 ts.hours += floor(ts.minutes / MINUTES_PER_HOUR); 35574 ts.minutes %= MINUTES_PER_HOUR; 35575 } 35576 35577 if (ts.hours < 0) { 35578 // ripple days down to hours 35579 x = ceil(-ts.hours / HOURS_PER_DAY); 35580 ts.days -= x; 35581 ts.hours += x * HOURS_PER_DAY; 35582 35583 } else if (ts.hours >= HOURS_PER_DAY) { 35584 // ripple hours up to days 35585 ts.days += floor(ts.hours / HOURS_PER_DAY); 35586 ts.hours %= HOURS_PER_DAY; 35587 } 35588 35589 while (ts.days < 0) { 35590 // NOTE: never actually seen this loop more than once 35591 35592 // ripple months down to days 35593 ts.months--; 35594 ts.days += borrowMonths(ts.refMonth, 1); 35595 } 35596 35597 // weeks is always zero here 35598 35599 if (ts.days >= DAYS_PER_WEEK) { 35600 // ripple days up to weeks 35601 ts.weeks += floor(ts.days / DAYS_PER_WEEK); 35602 ts.days %= DAYS_PER_WEEK; 35603 } 35604 35605 if (ts.months < 0) { 35606 // ripple years down to months 35607 x = ceil(-ts.months / MONTHS_PER_YEAR); 35608 ts.years -= x; 35609 ts.months += x * MONTHS_PER_YEAR; 35610 35611 } else if (ts.months >= MONTHS_PER_YEAR) { 35612 // ripple months up to years 35613 ts.years += floor(ts.months / MONTHS_PER_YEAR); 35614 ts.months %= MONTHS_PER_YEAR; 35615 } 35616 35617 // years is always non-negative here 35618 // decades, centuries and millennia are always zero here 35619 35620 if (ts.years >= YEARS_PER_DECADE) { 35621 // ripple years up to decades 35622 ts.decades += floor(ts.years / YEARS_PER_DECADE); 35623 ts.years %= YEARS_PER_DECADE; 35624 35625 if (ts.decades >= DECADES_PER_CENTURY) { 35626 // ripple decades up to centuries 35627 ts.centuries += floor(ts.decades
35627 / DECADES_PER_CENTURY); 35628 ts.decades %= DECADES_PER_CENTURY; 35629 35630 if (ts.centuries >= CENTURIES_PER_MILLENNIUM) { 35631 // ripple centuries up to millennia 35632 ts.millennia += floor(ts.centuries / CENTURIES_PER_MILLENNIUM); 35633 ts.centuries %= CENTURIES_PER_MILLENNIUM; 35634 } 35635 } 35636 } 35637 } 35638 35639 /** 35640 * Remove any units not requested 35641 * 35642 * @private 35643 * @param {Timespan} ts 35644 * @param {number} units the units to populate 35645 * @param {number} max number of labels to output 35646 * @param {number} digits max number of decimal digits to output 35647 */ 35648 function pruneUnits(ts, units, max, digits) { 35649 var count = 0; 35650 35651 // Calc from largest unit to smallest to prevent underflow 35652 if (!(units & MILLENNIA) || (count >= max)) { 35653 // ripple millennia down to centuries 35654 ts.centuries += ts.millennia * CENTURIES_PER_MILLENNIUM; 35655 delete ts.millennia; 35656 35657 } else if (ts.millennia) { 35658 count++; 35659 } 35660 35661 if (!(units & CENTURIES) || (count >= max)) { 35662 // ripple centuries down to decades 35663 ts.decades += ts.centuries * DECADES_PER_CENTURY; 35664 delete ts.centuries; 35665 35666 } else if (ts.centuries) { 35667 count++; 35668 } 35669 35670 if (!(units & DECADES) || (count >= max)) { 35671 // ripple decades down to years 35672 ts.years += ts.decades * YEARS_PER_DECADE; 35673 delete ts.decades; 35674 35675 } else if (ts.decades) { 35676 count++; 35677 } 35678 35679 if (!(units & YEARS) || (count >= max)) { 35680 // ripple years down to months 35681 ts.months += ts.years * MONTHS_PER_YEAR; 35682 delete ts.years; 35683 35684 } else if (ts.years) { 35685 count++; 35686 } 35687 35688 if (!(units & MONTHS) || (count >= max)) { 35689 // ripple months down to days 35690 if (ts.months) { 35691 ts.days += borrowMonths(ts.refMonth, ts.months); 35692 } 35693 delete ts.months; 35694 35695 if (ts.days >= DAYS_PER_WEEK) { 35696 // ripple day overflow back up to weeks 35697 ts.weeks += floor(ts.days / DAYS_PER_WEEK); 35698 ts.days %= DAYS_PER_WEEK; 35699 } 35700 35701 } else if (ts.months) { 35702 count++; 35703 } 35704 35705 if (!(units & WEEKS) || (count >= max)) { 35706 // ripple weeks down to days 35707 ts.days += ts.weeks * DAYS_PER_WEEK; 35708 delete ts.weeks; 35709 35710 } else if (ts.weeks) { 35711 count++; 35712 } 35713 35714 if (!(units & DAYS) || (count >= max)) { 35715 //ripple days down to hours 35716 ts.hours += ts.days * HOURS_PER_DAY; 35717 delete ts.days; 35718 35719 } else if (ts.days) { 35720 count++; 35721 } 35722 35723 if (!(units & HOURS) || (count >= max)) { 35724 // ripple hours down to minutes 35725 ts.minutes += ts.hours * MINUTES_PER_HOUR; 35726 delete ts.hours; 35727 35728 } else if (ts.hours) { 35729 count++; 35730 } 35731 35732 if (!(units & MINUTES) || (count >= max)) { 35733 // ripple minutes down to seconds 35734 ts.seconds += ts.minutes * SECONDS_PER_MINUTE; 35735 delete ts.minutes; 35736 35737 } else if (ts.minutes) { 35738 count++; 35739 } 35740 35741 if (!(units & SECONDS) || (count >= max)) { 35742 // ripple seconds down to milliseconds 35743 ts.milliseconds += ts.seconds * MILLISECONDS_PER_SECOND; 35744 delete ts.seconds; 35745 35746 } else if (ts.seconds) { 35747 count++; 35748 } 35749 35750 // nothing to ripple milliseconds down to 35751 // so ripple back up to smallest existing unit as a fractional value 35752 if (!(units & MILLISECONDS) || (count >= max)) { 35753 fractional(ts, digits); 35754 } 35755 } 35756 35757 /** 35758 * Populates the Timespan object 35759 * 35760 * @private 35761 * @param {Timespan} ts 35762 * @param {Date} start the starting date 35763 * @param {Date} end the ending date 35764 * @param {number} units the units to populate 35765 * @param {number} max number of labels to output 35766 * @param {number} digits max number of decimal digits to output 35767 */ 35768 function populate(ts, start, end, units, max, digits) { 35769 ts.start = start; 35770 ts.end = end; 35771 ts.units = units; 35772 35773 ts.value = end.getTime() - start.getTime(); 35774 if (ts.value < 0) { 35775 // swap if reversed 35776 var temp = end; 35777 end = start; 35778 start = temp; 35779 } 35780 35781 // reference month for determining days in month 35782 ts.refMonth = new Date(start.getFullYear(), start.getMonth(), 15); 35783 try { 35784 // reset to initial deltas 35785 ts.millennia = 0; 35786 ts.centuries = 0; 35787 ts.decades = 0; 35788 ts.years = end.getUTCFullYear() - start.getUTCFullYear(); 35789 ts.months = end.getUTCMonth() - start.getUTCMonth(); 35790 ts.weeks = 0; 35791 ts.days = end.getUTCDate() - start.getUTCDate(); 35792 ts.hours = end.getUTCHours() - start.getUTCHours(); 35793 ts.minutes = end.getUTCMinutes() - start.getUTCMinutes(); 35794 ts.seconds = end.getUTCSeconds() - start.getUTCSeconds(); 35795 ts.milliseconds = end.getUTCMilliseconds() - start.getUTCMilliseconds(); 35796 35797 ripple(ts); 35798 pruneUnits(ts, units, max, digits); 35799 35800 } finally { 35801 delete ts.refMonth; 35802 } 35803 35804 return ts; 35805 } 35806 35807 /** 35808 * Determine an appropriate refresh rate based upon units 35809 * 35810 * @private 35811 * @param {number} units the units to populate 35812 * @return {number} milliseconds to delay 35813 */
35814 function getDelay(units) { 35815 if (units & MILLISECONDS) { 35816 // refresh very quickly 35817 return MILLISECONDS_PER_SECOND / 30; //30Hz 35818 } 35819 35820 if (units & SECONDS) { 35821 // refresh every second 35822 return MILLISECONDS_PER_SECOND; //1Hz 35823 } 35824 35825 if (units & MINUTES) { 35826 // refresh every minute 35827 return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE; 35828 } 35829 35830 if (units & HOURS) { 35831 // refresh hourly 35832 return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR; 35833 } 35834 35835 if (units & DAYS) { 35836 // refresh daily 35837 return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY; 35838 } 35839 35840 // refresh the rest weekly 35841 return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * DAYS_PER_WEEK; 35842 } 35843 35844 /** 35845 * API entry point 35846 * 35847 * @public 35848 * @param {Date|number|null|function(Timespan,number)} start the starting date 35849 * @param {Date|number|null|function(Timespan,number)} end the ending date 35850 * @param {number} units the units to populate 35851 * @param {number} max number of labels to output 35852 * @param {number} digits max number of decimal digits to output 35853 * @return {Timespan|number} 35854 */ 35855 function countdown(start, end, units, max, digits) { 35856 var callback; 35857 35858 // ensure some units or use defaults 35859 units = +units || DEFAULTS; 35860 // max must be positive 35861 max = (max > 0) ? max : NaN; 35862 // clamp digits to an integer between [0, 20] 35863 digits = (digits > 0) ? (digits < 20) ? Math.round(digits) : 20 : 0; 35864 35865 // ensure start date 35866 if ('function' === typeof start) { 35867 callback = start; 35868 start = null; 35869 35870 } else if (!(start instanceof Date)) { 35871 start = (start !== null && isFinite(start)) ? new Date(start) : null; 35872 } 35873 35874 // ensure end date 35875 if ('function' === typeof end) { 35876 callback = end; 35877 end = null; 35878 35879 } else if (!(end instanceof Date)) { 35880 end = (end !== null && isFinite(end)) ? new Date(end) : null; 35881 } 35882 35883 if (!start && !end) { 35884 // used for unit testing 35885 return new Timespan(); 35886 } 35887 35888 if (!callback) { 35889 return populate(new Timespan(), /** @type{Date} */(start||new Date()), /** @type{Date} */(end||new Date()), units, max, digits); 35890 } 35891 35892 // base delay off units 35893 var delay = getDelay(units), 35894 timerId, 35895 fn = function() { 35896 callback( 35897 populate(new Timespan(), /** @type{Date} */(start||new Date()), /** @type{Date} */(end||new Date()), units, max, digits), 35898 timerId 35899 ); 35900 }; 35901 35902 fn(); 35903 return (timerId = setInterval(fn, delay)); 35904 } 35905 35906 /** 35907 * @public 35908 * @const 35909 * @type {number} 35910 */ 35911 countdown.MILLISECONDS = MILLISECONDS; 35912 35913 /** 35914 * @public 35915 * @const 35916 * @type {number} 35917 */ 35918 countdown.SECONDS = SECONDS; 35919 35920 /** 35921 * @public 35922 * @const 35923 * @type {number} 35924 */ 35925 countdown.MINUTES = MINUTES; 35926 35927 /** 35928 * @public 35929 * @const 35930 * @type {number} 35931 */ 35932 countdown.HOURS = HOURS; 35933 35934 /** 35935 * @public 35936 * @const 35937 * @type {number} 35938 */ 35939 countdown.DAYS = DAYS; 35940 35941 /** 35942 * @public 35943 * @const 35944 * @type {number} 35945 */ 35946 countdown.WEEKS = WEEKS; 35947 35948 /** 35949 * @public 35950 * @const 35951 * @type {number} 35952 */ 35953 countdown.MONTHS = MONTHS; 35954 35955 /** 35956 * @public 35957 * @const 35958 * @type {number} 35959 */ 35960 countdown.YEARS = YEARS; 35961 35962 /** 35963 * @public 35964 * @const 35965 * @type {number} 35966 */ 35967 countdown.DECADES = DECADES; 35968 35969 /** 35970 * @public 35971 * @const 35972 * @type {number} 35973 */ 35974 countdown.CENTURIES = CENTURIES; 35975 35976 /** 35977 * @public 35978 * @const 35979 * @type {number} 35980 */ 35981 countdown.MILLENNIA = MILLENNIA; 35982 35983 /** 35984 * @public 35985 * @const 35986 * @type {number} 35987 */ 35988 countdown.DEFAULTS = DEFAULTS; 35989 35990 /** 35991 * @public 35992 * @const 35993 * @type {number} 35994 */ 35995 countdown.ALL = MILLENNIA|CENTURIES|DECADES|YEARS|MONTHS|WEEKS|DAYS|HOURS|MINUTES|SECONDS|MILLISECONDS; 35996 35997 /** 35998 * Override the unit labels 35999 * @public 36000 * @param {string|Array} singular a pipe ('|') delimited list of singular unit name overrides 36001 * @param {string|Array} plural a pipe ('|') delimited list of plural unit name overrides 36002 */ 36003 var setLabels = countdown.setLabels = function(singular, plural) { 36004 singular = singular || []; 36005 if (singular.split) { 36006 singular = singular.split('|'); 36007 } 36008 plural = plural || []; 36009 if (plural.split) { 36010 plural = plural.split('|'); 36011 } 36012 36013 for (var i=LABEL_MILLISECONDS; i<=LABEL_MILLENNIA; i++) { 36014 // override any specified units 36015 LABELS_SINGLUAR[i] = singular[i] || LABELS_SINGLUAR[i]; 36016 LABELS_PLURAL[i] = plural[i] || LABELS_PLURAL[i]; 36017 } 36018 }; 36019 36020 /** 36021 * Revert to the default unit labels 36022 * @public 36023 */ 36024 var resetLabels = countdown.resetLabels = function() { 36025 LABELS_SINGLUAR = 'millisecond|second|minute|hour|day|week|month|year|decade|century|millennium'.split('|'); 36026 LABELS_PLURAL = 'milliseconds|seconds|minutes|hours|days|weeks|months|years|decades|centuries|millennia'.split('|'); 36027 }; 36028 36029 resetLabels(); 36030 36031 if (module && module.exports) { 36032 module.exports = countdown; 36033 } 36034 36035 return countdown; 36036 36037 })(module); 36038(function() { 36039 App.Widgets.Countdown = (function() { 36040 function Countdown() {} 36041 36042 Countdown.prototype.initialize = function() { 36043 this.$el = $('.js-countdown'); 36044 return this.$el.each(function(index, el) { 36045 var time, utc; 36046 utc = $(el).data('timestamp'); 36047 time = parseDate(utc); 36048 return countdown(time, (function(_this) { 36049 return function(ts) { 36050 $(el).find('.countdown__months').text(ts.months + "M"); 36051 $(el).find('.countdown__days').text(ts.days + "d"); 36052 $(el).find('.countdown__hours').text(ts.hours + "h"); 36053 $(el).find('.countdown__minutes').text(ts.minutes + "m"); 36054 return $(el).find('.countdown__seconds').text(ts.seconds + "s"); 36055 }; 36056 })(this)); 36057 }); 36058 }; 36059 36060 return Countdown; 36061 36062 })(); 36063 36064}).call(this); 36065(function() { 36066 App.Widgets.CreditsUsedInfoTooltip = (function() { 36067 function CreditsUsedInfoTooltip() {} 36068 36069 CreditsUsedInfoTooltip.prototype.initialize = function() { 36070 this.numberFormat = '$0.00'; 36071 this.$tooltip = $('.js-credits-used-info-tooltip'); 36072 if (this.$tooltip.length > 0) { 36073 return this.initTooltip(); 36074 } 36075 }; 36076 36077 CreditsUsedInfoTooltip.prototype.initTooltip = function() { 36078 var bonusCartCreditsUsed, bonusCreditsTitle, cartValue, content, storeCreditsUsed, temporaryCreditsActive, temporaryCreditsUsed, totalCreditsUsed; 36079 storeCreditsUsed = this.$tooltip.data('store-credits-used'); 36080 bonusCartCreditsUsed = this.$tooltip.data('bonus-credits-used'); 36081 cartValue = this.$tooltip.data('cart-value'); 36082 temporaryCreditsActive = this.$tooltip.data('temporary-credits-active'); 36083 temporaryCreditsUsed = this.$tooltip.data('temporary-credits-used'); 36084 bonusCreditsTitle = this.$tooltip.data('bonus-credits-title'); 36085 totalCreditsUsed = this.$tooltip.data('total-credits-used'); 36086 if (totalCreditsUsed > 0) { 36087 content = I18n.t('tooltips.common_credits_used_tooltip_html', { 36088 storeCreditsUsedText: this.storeCreditsUsedText(storeCreditsUsed), 36089 temporaryCreditsUsedText: this.temporaryCreditsUsedText(temporaryCreditsActive, bonusCreditsTitle, temporaryCreditsUsed), 36090 totalCreditsUsed: numeral(totalCreditsUsed).format(this.numberFormat) 36091 }); 36092 } else { 36093 content = I18n.t('tooltips.no_credits_used_html'); 36094 } 36095 return this.$tooltip.tooltipster({ 36096 theme: 'tooltip--light tooltip--popover tooltip--spaced', 36097 animation: 'grow', 36098 contentAsHTML: true, 36099 content: content, 36100 interactive: true, 36101 maxWidth: 350 36102 }); 36103 }; 36104 36105 CreditsUsedInfoTooltip.prototype.storeCreditsUsedText = function(storeCreditsUsed) { 36106 if (storeCreditsUsed > 0) { 36107 return I18n.t('tooltips.store_credits_used_html', {
36108 storeCreditsUsed: numeral(storeCreditsUsed).format(this.numberFormat) 36109 }); 36110 } else { 36111 return ''; 36112 } 36113 }; 36114 36115 CreditsUsedInfoTooltip.prototype.temporaryCreditsUsedText = function(temporaryCreditsActive, bonusCreditsTitle, temporaryCreditsUsed) { 36116 if (temporaryCreditsActive) { 36117 return I18n.t('tooltips.temporary_credits_used_html', { 36118 bonusCreditsTitle: bonusCreditsTitle, 36119 temporaryCreditsUsed: numeral(temporaryCreditsUsed).format(this.numberFormat) 36120 }); 36121 } else { 36122 return ''; 36123 } 36124 }; 36125 36126 return CreditsUsedInfoTooltip; 36127 36128 })(); 36129 36130}).call(this); 36131(function() { 36132 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 36133 36134 App.Widgets.CustomItemRequest = (function() { 36135 function CustomItemRequest() { 36136 this.onPriceRangeUpdate = bind(this.onPriceRangeUpdate, this); 36137 this.onPriceRangeChanged = bind(this.onPriceRangeChanged, this); 36138 this.initPriceRangeFilter = bind(this.initPriceRangeFilter, this); 36139 this.prefillCheckboxesInformation = bind(this.prefillCheckboxesInformation, this); 36140 this.showOrHideNotRelatedTo3dPrintInformation = bind(this.showOrHideNotRelatedTo3dPrintInformation, this); 36141 this.resetSelectedPrice = bind(this.resetSelectedPrice, this); 36142 this.onFormSubmitComplete = bind(this.onFormSubmitComplete, this); 36143 this.initValidation = bind(this.initValidation, this); 36144 this.onModalClosedEvent = bind(this.onModalClosedEvent, this); 36145 this.hideOnClickOutside = bind(this.hideOnClickOutside, this); 36146 this.bindCustomEvents = bind(this.bindCustomEvents, this); 36147 this.parseSearchForm = bind(this.parseSearchForm, this); 36148 this.initRequestModal = bind(this.initRequestModal, this); 36149 } 36150 36151 CustomItemRequest.prototype.maxPrice = 500; 36152 36153 CustomItemRequest.prototype.filterCheckboxes = ['print_ready', 'low_poly', 'animated', 'pbr', 'rigged', 'collection']; 36154 36155 CustomItemRequest.prototype.initialize = function() { 36156 return this.bindEvents(); 36157 }; 36158 36159 CustomItemRequest.prototype.bindEvents = function() { 36160 return $(document).on('click', '.js-request-custom-item', this.initRequestModal); 36161 }; 36162 36163 CustomItemRequest.prototype.initRequestModal = function() { 36164 this.$modal = $(JST["modals/custom_item_request_modal"](this.parseSearchForm())); 36165 $('body').append(this.$modal); 36166 this.$form = this.$modal.find('.js-request-form'); 36167 this.$checkboxesWithout3dPrint = this.$modal.find('input[type=checkbox]:not(#print_ready_request)'); 36168 this.$checkboxesContainersWithout3dPrint = this.$checkboxesWithout3dPrint.closest('.checkbox-block'); 36169 this.$polygonsRow = this.$modal.find('.js-polygons-row'); 36170 this.prefillCheckboxesInformation(); 36171 this.initPriceRangeFilter($('#price-range-request')); 36172 this.$modal.makeMeModal(); 36173 this.bindCustomEvents(); 36174 return this.initValidation(); 36175 }; 36176 36177 CustomItemRequest.prototype.parseSearchForm = function() { 36178 var authenticityToken, data, formats, licenses, polygons, price, searchQuery, selectedFormatsArr, selectedLicensesArr, selectedPolygons, selectedPriceRange; 36179 selectedPriceRange = $.parseJSON($('input[name=price]')[0].value) || { 36180 from: 0, 36181 to: this.maxPrice 36182 }; 36183 price = '$' + selectedPriceRange.from + '-' + selectedPriceRange.to; 36184 selectedFormatsArr = $('.active-filters__item[data-filter="file_types"]').toArray(); 36185 formats = selectedFormatsArr.map(function(el) { 36186 return $.trim(el.textContent); 36187 }); 36188 selectedPolygons = $('.active-filters__item[data-filter="polygons"]')[0] || []; 36189 polygons = $.trim(selectedPolygons.textContent); 36190 selectedLicensesArr = $('.active-filters__item[data-filter="licenses"]').toArray(); 36191 licenses = selectedLicensesArr.map(function(el) { 36192 return $.trim(el.textContent); 36193 }); 36194 searchQuery = $('input[name=keywords]')[0].value; 36195 authenticityToken = $('meta[name="csrf-token"]').attr('content'); 36196 return data = { 36197 signedIn: App.config.userSignedIn, 36198 price: price, 36199 formats: formats, 36200 polygons: polygons, 36201 licenses: licenses, 36202 keywords: searchQuery, 36203 authenticityToken: authenticityToken 36204 }; 36205 }; 36206 36207 CustomItemRequest.prototype.bindCustomEvents = function() { 36208 this.$modal.on('click', '.js-modal-close', this.onModalClosedEvent); 36209 this.$modal.on('click', '.js-reset-price', this.resetSelectedPrice); 36210 this.$modal.on('click', 'input#print_ready_request', this.showOrHideNotRelatedTo3dPrintInformation); 36211 this.$form.on('ajax:complete', this.onFormSubmitComplete);
36212 return this.hideOnClickOutside('#modal-request-custom-item', 'modal-backdrop'); 36213 }; 36214 36215 CustomItemRequest.prototype.hideOnClickOutside = function(selector, backdrop) { 36216 return $(document).click((function(_this) { 36217 return function(event) { 36218 if ($(selector).is(':visible') && $(event.target).hasClass(backdrop)) { 36219 return _this.onModalClosedEvent(); 36220 } 36221 }; 36222 })(this)); 36223 }; 36224 36225 CustomItemRequest.prototype.onModalClosedEvent = function() { 36226 this.$modal.makeMeModal('close'); 36227 return this.$modal.remove(); 36228 }; 36229 36230 CustomItemRequest.prototype.validationSettings = function() { 36231 return { 36232 rules: { 36233 'custom_model_request[deadline]': { 36234 required: true 36235 }, 36236 'custom_model_request[email]': { 36237 required: true, 36238 email: true 36239 }, 36240 'custom_model_request[details]': { 36241 maxlength: 255 36242 } 36243 } 36244 }; 36245 }; 36246 36247 CustomItemRequest.prototype.initValidation = function() { 36248 return this.$form.validate(this.validationSettings()); 36249 }; 36250 36251 CustomItemRequest.prototype.onFormSubmitComplete = function() { 36252 this.$modal.find('.modal-light__body').addClass('is-invisible'); 36253 return this.$modal.find('.js-success-screen').removeClass('is-hidden'); 36254 }; 36255 36256 CustomItemRequest.prototype.resetSelectedPrice = function() { 36257 return $('#price-range-request')[0].noUiSlider.set([0, this.maxPrice]); 36258 }; 36259 36260 CustomItemRequest.prototype.showOrHideNotRelatedTo3dPrintInformation = function() { 36261 if ($('input#print_ready_request').is(':checked')) { 36262 this.$checkboxesContainersWithout3dPrint.remove(); 36263 return this.$polygonsRow.remove(); 36264 } else { 36265 this.$modal.find('.js-checkboxes-container').append(this.$checkboxesContainersWithout3dPrint); 36266 return this.$modal.find('.js-polygons-container').append(this.$polygonsRow); 36267 } 36268 }; 36269 36270 CustomItemRequest.prototype.prefillCheckboxesInformation = function() { 36271 var checkboxName, i, len, ref; 36272 ref = this.filterCheckboxes; 36273 for (i = 0, len = ref.length; i < len; i++) { 36274 checkboxName = ref[i]; 36275 if ($("input[name=" + checkboxName + "]").is(':checked')) { 36276 $("input#" + checkboxName + "_request").prop('checked', true); 36277 } 36278 } 36279 return this.showOrHideNotRelatedTo3dPrintInformation(); 36280 }; 36281 36282 CustomItemRequest.prototype.initPriceRangeFilter = function($priceRequest) { 36283 var ref, startRange; 36284 $priceRequest.tooltipster({ 36285 theme: 'tooltip--light', 36286 animation: 'grow', 36287 delay: 0, 36288 autoClose: true, 36289 trigger: 'custom', 36290 updateAnimation: false, 36291 timer: 500 36292 }); 36293 startRange = (ref = JSON.parse($('#price').val())) != null ? ref : { 36294 from: 0, 36295 to: this.maxPrice 36296 }; 36297 noUiSlider.create($priceRequest[0], { 36298 start: [startRange.from, startRange.to], 36299 connect: true, 36300 step: 1, 36301 range: { 36302 'min': 0, 36303 'max': this.maxPrice 36304 } 36305 }); 36306 $priceRequest[0].noUiSlider.on('change', this.onPriceRangeChanged); 36307 $priceRequest[0].noUiSlider.on('set', this.onPriceRangeChanged); 36308 return $priceRequest[0].noUiSlider.on('update', (function(_this) { 36309 return function(values, handle) { 36310 return _this.onPriceRangeUpdate(values, handle, $priceRequest); 36311 }; 36312 })(this)); 36313 }; 36314 36315 CustomItemRequest.prototype.onPriceRangeChanged = function(values) { 36316 var from, to, updatedPrice; 36317 from = parseInt(values[0]); 36318 to = parseInt(values[1]); 36319 updatedPrice = '$' + from + '-' + to; 36320 this.$modal.find('.js-price-input').val(updatedPrice); 36321 return this.$modal.find('.js-price-filter').text(updatedPrice); 36322 }; 36323 36324 CustomItemRequest.prototype.onPriceRangeUpdate = function(values, handle, $priceRequest) { 36325 var value; 36326 value = values[handle]; 36327 if ($priceRequest.priceRangeChangeCounter == null) { 36328 $priceRequest.priceRangeChangeCounter = 0; 36329 } 36330 $priceRequest.priceRangeChangeCounter += 1; 36331 if ($priceRequest.priceRangeChangeCounter < 10) { 36332 return; 36333 } 36334 if (+value === this.maxPrice) { 36335 value = this.maxPrice + " or more"; 36336 } 36337 return $priceRequest.tooltipster('content', "$" + value).tooltipster('show'); 36338 }; 36339 36340 return CustomItemRequest; 36341 36342 })(); 36343 36344}).call(this); 36345(function() { 36346 App.Widgets.CVCTooltip = (function() { 36347 function CVCTooltip() {} 36348 36349 CVCTooltip.prototype.initialize = function() { 36350 this.$tooltip = $('.js-cvc-tooltip'); 36351 if (this.$tooltip.length > 0) { 36352 return this.initTooltip(); 36353 } 36354 }; 36355 36356 CVCTooltip.prototype.initTooltip = function() { 36357 var content; 36358 content = "Last three digits on the back of your credit card"; 36359 return this.$tooltip.tooltipster({ 36360 theme: 'tooltip--light tooltip--popover u-text-center', 36361 animation: 'grow', 36362 contentAsHTML: true, 36363 content: content, 36364 position: 'top', 36365 interactive: true, 36366 maxWidth: 400 36367 }); 36368 }; 36369 36370 return CVCTooltip; 36371 36372 })(); 36373 36374}).call(this); 36375/*rateYo V2.3.2, A simple and flexible star rating plugin
36376prashanth pamidi (https://github.com/prrashi)*/ 36377 36378!function(a){"use strict";function b(){var a=!1;return function(b){(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(b)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(b.substr(0,4)))&&(a=!0)}(navigator.userAgent||navigator.vendor||window.opera),a}function c(a,b,c){return a===b?a=b:a===c&&(a=c),a}function d(a,b,c){if(!(a>=b&&a<=c))throw Error("Invalid Rating, expected value between "+b+" and "+c);return a}function e(a){return void 0!==a}function f(a,b,c){var d=c/100*(b-a);return d=Math.round(a+d).toString(16),1===d.length&&(d="0"+d),d}function g(a,b,c){if(!a||!b)return null;c=e(c)?c:0,a=q(a),b=q(b);var d=f(a.r,b.r,c),g=f(a.b,b.b,c);return"#"+d+f(a.g,b.g,c)+g}function h(f,i){function k(a){e(a)||(a=i.rating),Z=a;var b=a/P,c=b*R;b>1&&(c+=(Math.ceil(b)-1)*T),r(i.ratedFill),c=i.rtl?100-c:c,c<0?c=0:c>100&&(c=100),X.css("width",c+"%")}function l(){U=Q*i.numStars+S*(i.numStars-1),R=Q/U*100,T=S/U*100,f.width(U),k()}function n(a){var b=i.starWidth=a;return Q=window.parseFloat(i.starWidth.replace("px","")),W.find("svg").attr({width:i.starWidth,height:b}),X.find("svg").attr({width:i.starWidth,height:b}),l(),f}function p(a){return i.spacing=a,S=parseFloat(i.spacing.replace("px","")),W.find("svg:not(:first-child)").css({"margin-left":a}),X.find("svg:not(:first-child)").css({"margin-left":a}),l(),f}function q(a){return i.normalFill=a,(i.rtl?X:W).find("svg").attr({fill:i.normalFill}),f}function r(a){if(i.multiColor){var b=Z-Y,c=b/i.maxValue*100,d=i.multiColor||{};a=g(d.startColor||o.startColor,d.endColor||o.endColor,c)}else _=a;return i.ratedFill=a,(i.rtl?W:X).find("svg").attr({fill:i.ratedFill}),f}function s(a){a=!!a,i.rtl=a,q(i.normalFill),k()}function t(a){i.multiColor=a,r(a?a:_)}function u(b){i.numStars=b,P=i.maxValue/i.numStars,W.empty(),X.empty();for(var c=0;c<i.numStars;c++)W.append(a(i.starSvg||m)),X.append(a(i.starSvg||m));return n(i.starWidth),q(i.normalFill),p(i.spacing),k(),f}function v(a){return i.maxValue=a,P=i.maxValue/i.numStars,i.rating>a&&C(a),k(),f}function w(a){return i.precision=a,C(i.rating),f}function x(a){return i.halfStar=a,f}function y(a){return i.fullStar=a,f}function z(a){var b=a%P,c=P/2,d=i.halfStar,e=i.fullStar;return e||d?(e||d&&b>c?a+=P-b:(a-=b,b>0&&(a+=c)),a):a}function A(a){var b=W.offset(),c=b.left,d=c+W.width(),e=i.maxValue,f=a.pageX,g=0;if(f<c)g=Y;else if(f>d)g=e;else{var h=(f-c)/(d-c);if(S>0){h*=100;for(var j=h;j>0;)j>R?(g+=P,j-=R+T):(g+=j/R*P,j=0)}else g=h*i.maxValue;g=z(g)}return i.rtl&&(g=e-g),parseFloat(g)}function B(a){return i.readOnly=a,f.attr("readonly",!0),N(),a||(f.removeAttr("readonly"),M()),f}function C(a){var b=a,e=i.maxValue;return"string"==typeof b&&("%"===b[b.length-1]&&(b=b.substr(0,b.length-1),e=100,v(e)),b=parseFloat(b)),d(b,Y,e),b=parseFloat(b.toFixed(i.precision)),c(parseFloat(b),Y,e),i.rating=b,k(),$&&f.trigger("rateyo.set",{rating:b}),f}function D(a){return i.onInit=a,f}function E(a){return i.onSet=a,f}function F(a){return i.onChange=a,f}function G(a){var b=A(a).toFixed(i.precision),d=i.maxValue;b=c(parseFloat(b),Y,d),k(b),f.trigger("rateyo.change",{rating:b})}function H(){b()||(k(),f.trigger("rateyo.change",{rating:i.rating}))}function I(a){var b=A(a).toFixed(i.precision);b=parseFloat(b),O.rating(b)}function J(a,b){i.onInit&&"function"==typeof i.onInit&&i.onInit.apply(this,[b.rating,O])}function K(a,b){i.onChange&&"function"==typeof i.onChange&&i.onChange.apply(this,[b.rating,O])}function L(a,b){i.onSet&&"function"==typeof i.onSet&&i.onSet.apply(this,[b.rating,O])}function M(){f.on("mousemove",G).on("mouseenter",G).on("mouseleave",H).on("click",I).on("rateyo.init",J).on("rateyo.change",K).on("rateyo.set",L
36378)}function N(){f.off("mousemove",G).off("mouseenter",G).off("mouseleave",H).off("click",I).off("rateyo.init",J).off("rateyo.change",K).off("rateyo.set",L)}this.node=f.get(0);var O=this;f.empty().addClass("jq-ry-container");var P,Q,R,S,T,U,V=a("<div/>").addClass("jq-ry-group-wrapper").appendTo(f),W=a("<div/>").addClass("jq-ry-normal-group").addClass("jq-ry-group").appendTo(V),X=a("<div/>").addClass("jq-ry-rated-group").addClass("jq-ry-group").appendTo(V),Y=0,Z=i.rating,$=!1,_=i.ratedFill;this.rating=function(a){return e(a)?(C(a),f):i.rating},this.destroy=function(){return i.readOnly||N(),h.prototype.collection=j(f.get(0),this.collection),f.removeClass("jq-ry-container").children().remove(),f},this.method=function(a){if(!a)throw Error("Method name not specified!");if(!e(this[a]))throw Error("Method "+a+" doesn't exist!");var b=Array.prototype.slice.apply(arguments,[]),c=b.slice(1);return this[a].apply(this,c)},this.option=function(a,b){if(!e(a))return i;var c;switch(a){case"starWidth":c=n;break;case"numStars":c=u;break;case"normalFill":c=q;break;case"ratedFill":c=r;break;case"multiColor":c=t;break;case"maxValue":c=v;break;case"precision":c=w;break;case"rating":c=C;break;case"halfStar":c=x;break;case"fullStar":c=y;break;case"readOnly":c=B;break;case"spacing":c=p;break;case"rtl":c=s;break;case"onInit":c=D;break;case"onSet":c=E;break;case"onChange":c=F;break;default:throw Error("No such option as "+a)}return e(b)?c(b):i[a]},u(i.numStars),B(i.readOnly),i.rtl&&s(i.rtl),this.collection.push(this),this.rating(i.rating,!0),$=!0,f.trigger("rateyo.init",{rating:i.rating})}function i(b,c){var d;return a.each(c,function(){if(b===this.node)return d=this,!1}),d}function j(b,c){return a.each(c,function(a){if(b===this.node){var d=c.slice(0,a),e=c.slice(a+1,c.length);return c=d.concat(e),!1}}),c}function k(b){var c=h.prototype.collection,d=a(this);if(0===d.length)return d;var e=Array.prototype.slice.apply(arguments,[]);if(0===e.length)b=e[0]={};else{if(1!==e.length||"object"!=typeof e[0]){if(e.length>=1&&"string"==typeof e[0]){var f=e[0],g=e.slice(1),j=[];return a.each(d,function(a,b){var d=i(b,c);if(!d)throw Error("Trying to set options before even initialization");var e=d[f];if(!e)throw Error("Method "+f+" does not exist!");var h=e.apply(d,g);j.push(h)}),j=1===j.length?j[0]:j}throw Error("Invalid Arguments")}b=e[0]}return b=a.extend({},n,b),a.each(d,function(){var d=i(this,c);if(d)return d;var e=a(this),f={},g=a.extend({},b);return a.each(e.data(),function(a,b){if(0===a.indexOf("rateyo")){var c=a.replace(/^rateyo/,"");c=c[0].toLowerCase()+c.slice(1),f[c]=b,delete g[c]}}),new h(a(this),a.extend({},f,g))})}function l(){return k.apply(this,Array.prototype.slice.apply(arguments,[]))}var m='<?xml version="1.0" encoding="utf-8"?><svg version="1.1"xmlns="http://www.w3.org/2000/svg"viewBox="0 12.705 512 486.59"x="0px" y="0px"xml:space="preserve"><polygon points="256.814,12.705 317.205,198.566 512.631,198.566 354.529,313.435 414.918,499.295 256.814,384.427 98.713,499.295 159.102,313.435 1,198.566 196.426,198.566 "/></svg>',n={starWidth:"32px",normalFill:"gray",ratedFill:"#f39c12",numStars:5,maxValue:5,precision:1,rating:0,fullStar:!1,halfStar:!1,readOnly:!1,spacing:"0px",rtl:!1,multiColor:null,onInit:null,onChange:null,onSet:null,starSvg:null},o={startColor:"#c0392b",endColor:"#f1c40f"},p=/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i,q=function(a){if(!p.test(a))return null;var b=p.exec(a);return{r:parseInt(b[1],16),g:parseInt(b[2],16),b:parseInt(b[3],16)}};h.prototype.collection=[],window.RateYo=h,a.fn.rateYo=l}(window.jQuery); 36379(function() { 36380 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 36381 36382 App.Widgets.Downloads = (function() { 36383 var isUpdatingRating; 36384 36385 function Downloads() { 36386 this.onClientFeedbackQuestionPreviousClick = bind(this.onClientFeedbackQuestionPreviousClick, this); 36387 this.prepareNewClientFeedbackForm = bind(this.prepareNewClientFeedbackForm, this); 36388 this.onClientFeedbackSet = bind(this.onClientFeedbackSet, this); 36389 this.onClientFeedbackSubmit = bind(this.onClientFeedbackSubmit, this); 36390 this.onClientFeedbackUpadate = bind(this.onClientFeedbackUpadate, this); 36391 this.onDownloadClick = bind(this.onDownloadClick, this); 36392 } 36393 36394 isUpdatingRating = false;
36395 36396 Downloads.prototype.clientFeedbacks = { 36397 old: {} 36398 }; 36399 36400 Downloads.prototype.initialize = function() { 36401 return $(document).on('click', '.js-download', this.onDownloadClick); 36402 }; 36403 36404 Downloads.prototype.initRatingStars = function() { 36405 return $('.js-rating-stars').rateYo({ 36406 starWidth: '35px', 36407 fullStar: true, 36408 onSet: this.onClientFeedbackSet 36409 }); 36410 }; 36411 36412 Downloads.prototype.onDownloadClick = function(e) { 36413 var $el; 36414 $el = $(e.currentTarget); 36415 this.$modal = $($el.data('target')); 36416 $el.addClass('is-disabled'); 36417 return $.ajax({ 36418 url: $el.data('href'), 36419 complete: (function(_this) { 36420 return function(response) { 36421 if (response.status !== 200) { 36422 window.sendErrorToSentry(new Error('Download error'), { 36423 tags: { 36424 section: 'Purchase download' 36425 }, 36426 extra: response 36427 }); 36428 } 36429 $el.removeClass('is-disabled'); 36430 if (!ReactRailsUJS) { 36431 window.sendErrorToSentry(new Error('Uninitialised ReactRailsUJS in download modal!'), { 36432 tags: { 36433 section: 'Purchase download Component initialize' 36434 }, 36435 extra: response 36436 }); 36437 } 36438 if (response.success) { 36439 _this.$modal.find('.js-downloads-list').html(response.responseText); 36440 } 36441 if (!_this.$modal.hasClass('js-react-modal')) { 36442 _this.$modal.makeMeModal(); 36443 } 36444 ReactRailsUJS.mountComponents(); 36445 _this.initRatingStars(); 36446 $('.js-client-feedback-next').on('click', _this.onClientFeedbackQuestionNextClick); 36447 return $('.js-client-feedback-previous').on('click', _this.onClientFeedbackQuestionPreviousClick); 36448 }; 36449 })(this) 36450 }); 36451 }; 36452 36453 Downloads.prototype.onClientFeedbackUpadate = function() { 36454 return $.ajax({ 36455 url: '/client_feedbacks/' + this.clientFeedbacks.old.old_feedback_id, 36456 method: 'PUT', 36457 data: { 36458 client_feedback: this.clientFeedbacks.old 36459 }, 36460 complete: (function(_this) { 36461 return function(response) { 36462 return _this.prepareNewClientFeedbackForm(response.responseJSON.next_feedback_question); 36463 }; 36464 })(this) 36465 }); 36466 }; 36467 36468 Downloads.prototype.onClientFeedbackSubmit = function() { 36469 return $.ajax({ 36470 url: '/client_feedbacks', 36471 method: 'POST', 36472 data: { 36473 client_feedback: this.clientFeedbacks.old 36474 }, 36475 complete: (function(_this) { 36476 return function(response) { 36477 return _this.prepareNewClientFeedbackForm(response.responseJSON.next_feedback_question); 36478 }; 36479 })(this) 36480 }); 36481 }; 36482 36483 Downloads.prototype.onClientFeedbackSet = function(rating) { 36484 $('.js-rating-field').val(rating); 36485 $('.js-client-feedback').fadeOut(); 36486 this.clientFeedbacks.old.rating = $('.js-rating-field')[0].value; 36487 this.clientFeedbacks.old.question = $('.js-client-feedback-question').text(); 36488 this.clientFeedbacks.old.client_feedback_question_id = $('#client-feedback-question')[0].value; 36489 this.clientFeedbacks.old.info = { 36490 good_value: $('.js-good-value').text(), 36491 bad_value: $('.js-bad-value').text() 36492 }; 36493 if (this.isUpdatingRating) { 36494 this.onClientFeedbackUpadate(); 36495 } else { 36496 this.onClientFeedbackSubmit(); 36497 } 36498 return this.isUpdatingRating = false; 36499 }; 36500 36501 Downloads.prototype.prepareNewClientFeedbackForm = function(newFeedbackQuestion) { 36502 if (newFeedbackQuestion.id) { 36503 this.clientFeedbacks.old.feedback_id = newFeedbackQuestion.old_feedback_id; 36504 $('.js-good-value').text(newFeedbackQuestion.info.good_value); 36505 $('.js-bad-value').text(newFeedbackQuestion.info.bad_value); 36506 $('.js-client-feedback-question').text(newFeedbackQuestion.question); 36507 $('#client-feedback-question').val(newFeedbackQuestion.id); 36508 $('.js-rating-field').val(0); 36509 $('.js-client-feedback-answered').fadeOut(); 36510 $('.js-client-feedback-answered').removeClass('is-hidden'); 36511 return $('.js-client-feedback-answered').fadeIn(); 36512 } 36513 }; 36514 36515 Downloads.prototype.onClientFeedbackQuestionNextClick = function() { 36516 $('.js-client-feedback-answered').fadeOut(); 36517 return setTimeout(function() { 36518 return $('.js-client-feedback').fadeIn(); 36519 }, 400); 36520 }; 36521 36522 Downloads.prototype.onClientFeedbackQuestionPreviousClick = function() { 36523 this.isUpdatingRating = true; 36524 $('.js-good-value').text(this.clientFeedbacks.old.info.good_value); 36525 $('.js-bad-value').text(this.clientFeedbacks.old.info.bad_value); 36526 $('.js-client-feedback-question').text(this.clientFeedbacks.old.question); 36527 $('.js-rating-field').val(this.clientFeedbacks.old.rating); 36528 $('#client-feedback-question').val(this.clientFeedbacks.old.client_feedback_question_id); 36529 $('.js-client-feedback-answered').fadeOut(); 36530 return setTimeout(function() { 36531 return $('.js-client-feedback').fadeIn(); 36532 }, 400); 36533 }; 36534 36535 return Downloads; 36536 36537 })(); 36538 36539}).call(this); 36540(function() { 36541 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 36542 36543 App.Widgets.Follow = (function() { 36544 function Follow() { 36545 this.onAjaxSuccess = bind(this.onAjaxSuccess, this); 36546 this.onAjaxBefore = bind(this.onAjaxBefore, this); 36547 } 36548 36549 Follow.prototype.initialize = function() { 36550 this.$el = $('.js-follow'); 36551 this.$form = $('.user-follow-form'); 36552 return this.bindEvents(); 36553 }; 36554 36555 Follow.prototype.bindEvents = function() { 36556 this.$form.on('ajax:before', this.onAjaxBefore); 36557 return this.$form.on('ajax:success', this.onAjaxSuccess); 36558 }; 36559 36560 Follow.prototype.showFollow = function() { 36561 var $icon; 36562 this.$el.find('span').text('Follow'); 36563 $icon = this.$el.find('.fa'); 36564 $icon.removeClass('fa-check-circle').addClass('fa-plus-circle'); 36565 this.$el.data('method', 'post'); 36566 this.$el.attr('href', this.$el.data('follow-url')); 36567 return this.$el.addClass('button--alt'); 36568 }; 36569 36570 Follow.prototype.showUnfollow = function() { 36571 var $icon; 36572 this.$el.find('span').text('Following'); 36573 $icon = this.$el.find('.fa'); 36574 $icon.removeClass('fa-plus-circle').addClass('fa-check-circle'); 36575 this.$el.data('method', 'delete'); 36576 this.$el.attr('href', this.$el.data('unfollow-url')); 36577 return this.$el.removeClass('button--alt'); 36578 }; 36579 36580 Follow.prototype.onAjaxBefore = function() { 36581 this.$el.addClass('is-disabled'); 36582 if (App.config.userSignedIn) { 36583 return; 36584 } 36585 this.$el.removeClass('is-disabled'); 36586 return false;
36587 }; 36588 36589 Follow.prototype.onAjaxSuccess = function() { 36590 this.$el.removeClass('is-disabled'); 36591 if (this.$el.data('method') === 'post') { 36592 return this.showUnfollow(); 36593 } else { 36594 return this.showFollow(); 36595 } 36596 }; 36597 36598 return Follow; 36599 36600 })(); 36601 36602}).call(this); 36603(function() { 36604 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 36605 36606 App.Widgets.FreeDownloadLink = (function() { 36607 function FreeDownloadLink() { 36608 this.handleSocialShare = bind(this.handleSocialShare, this); 36609 this.bindSocialSharingEvents = bind(this.bindSocialSharingEvents, this); 36610 } 36611 36612 FreeDownloadLink.prototype.lastDownloadLink = null; 36613 36614 FreeDownloadLink.prototype.initialize = function() { 36615 this.$modal = $('#modal-free-download'); 36616 return this.bindEvents(); 36617 }; 36618 36619 FreeDownloadLink.prototype.bindEvents = function() { 36620 App.events.subscribe('twitter:tweet', this.handleSocialShare); 36621 App.events.subscribe('twitter:follow', this.handleSocialShare); 36622 App.events.subscribe('facebook:share', this.handleSocialShare); 36623 return App.events.subscribe('facebook:like', this.handleSocialShare); 36624 }; 36625 36626 FreeDownloadLink.prototype.bindSocialSharingEvents = function() { 36627 FB.init({ 36628 appId: App.config.facebookAppId, 36629 xfbml: true, 36630 version: 'v2.4' 36631 }); 36632 twttr.ready(function(twttr) { 36633 twttr.events.bind('tweet', function() { 36634 return App.events.publish('twitter:tweet', 'twitter#tweet'); 36635 }); 36636 return twttr.events.bind('follow', function() { 36637 return App.events.publish('twitter:follow', 'twitter#follow'); 36638 }); 36639 }); 36640 FB.Event.subscribe('edge.create', function() { 36641 return App.events.publish('facebook:like', 'facebook#like'); 36642 }); 36643 return $('.js-facebook-share').on('click', this.shareOnFacebook); 36644 }; 36645 36646 FreeDownloadLink.prototype.shareOnFacebook = function(event) { 36647 mute(event); 36648 return FB.ui({ 36649 method: 'share', 36650 href: $('.js-facebook-share').attr('data-href') 36651 }, function(response) { 36652 if (response && !response.error_message) { 36653 return App.events.publish('facebook:share', 'facebook#share'); 36654 } 36655 }); 36656 }; 36657 36658 FreeDownloadLink.prototype.handleSocialShare = function(social_network) { 36659 $('#modal-free-download').makeMeModal('close'); 36660 return $.ajax({ 36661 url: '/users/update_bonus_downloads', 36662 type: 'POST', 36663 data: { 36664 origin: social_network 36665 }, 36666 success: (function(_this) { 36667 return function(data) { 36668 if (data.success) { 36669 App.events.publish('app:notification:success', "Thank you! Now you can download " + data.bonus_free_downloads + " new free models!"); 36670 return window.location = _this.lastDownloadLink; 36671 } else { 36672 return App.events.publish('app:notification:error', 'Could not record your social share.'); 36673 } 36674 }; 36675 })(this) 36676 }); 36677 }; 36678 36679 return FreeDownloadLink; 36680 36681 })(); 36682 36683}).call(this); 36684(function() { 36685 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 36686 36687 App.Widgets.Likes = (function() { 36688 function Likes() { 36689 this.onLikeBind = bind(this.onLikeBind, this); 36690 } 36691 36692 Likes.prototype.initialize = function() { 36693 this.setButtonVisibility(); 36694 return this.bindEvents(); 36695 }; 36696 36697 Likes.prototype.setButtonVisibility = function() { 36698 var $el; 36699 $el = $('.js-like-control'); 36700 if ($el.lenght === 0) { 36701 return; 36702 } 36703 if (App.config.userSignedIn) { 36704 $el.removeClass('is-disabled'); 36705 } 36706 if (gon.is_liked) { 36707 $el.find('.button--like__text').text('Liked'); 36708 return $el.addClass('is-active'); 36709 } else { 36710 return $el.find('.button--like__text').text('Like'); 36711 } 36712 }; 36713 36714 Likes.prototype.bindEvents = function() { 36715 App.events.subscribe('app:likes:like', this.onLike); 36716 App.events.subscribe('app:likes:default:trigger', this.updateUI); 36717 App.events.subscribe('app:likes:default:trigger', this.sync); 36718 App.events.subscribe('app:likes:error', this.likeError); 36719 App.events.subscribe('app:likes:bind', this.onLikeBind); 36720 return App.events.publish('app:likes:bind', $('body')); 36721 }; 36722 36723 Likes.prototype.onLike = function(id, type) { 36724 if (!App.config.userSignedIn) { 36725 return; 36726 } 36727 return $.get('/api/internal/likes/valid_like', function(response) { 36728 if (response) { 36729 return App.events.publish('app:likes:default:trigger', id, type); 36730 } else { 36731 return App.events.publish('app:likes:error'); 36732 } 36733 }); 36734 }; 36735 36736 Likes.prototype.updateUI = function(id, type) { 36737 var $el; 36738 $el = $(".js-like[data-item-id=" + id + "][data-item-type=" + type + "]"); 36739 this.$itemLikesCounter = $el.find('.js-likes-counter'); 36740 if (!$el.hasClass('is-active')) { 36741 $el.addClass('is-active'); 36742 $el.find('.like-button__text').text('You like this'); 36743 $el.find('.button--like__text').text('Liked'); 36744 $el.find('.like-button__counter, .js-likes-counter').eq(0).text(parseInt($el.find('.like-button__counter, .js-likes-counter').eq(0).text(), 10) + 1); 36745 return this.$itemLikesCounter.text(parseInt($el.find('.like-button__counter, .js-likes-counter').eq(0).text(), 10)); 36746 } else { 36747 $el.find('.like-button__text').text('Like this'); 36748 $el.find('.button--like__text').text('Like'); 36749 $el.removeClass('is-active'); 36750 $el.find('.like-button__counter, .js-likes-counter').eq(0).text(parseInt($el.find('.like-button__counter, .js-likes-counter').eq(0).text(), 10) - 1); 36751 return this.$itemLikesCounter.text(parseInt($el.find('.like-button__counter, .js-likes-counter').eq(0).text(), 10)); 36752 } 36753 }; 36754 36755 Likes.prototype.sync = function(id, type) { 36756 return $.post('/api/internal/likes/like', { 36757 like: { 36758 likeable_id: id, 36759 likeable_type: type 36760 } 36761 }); 36762 }; 36763 36764 Likes.prototype.likeError = function() { 36765 return App.events.publish('app:notification:flash:error', I18n.t('likes.like_failure')); 36766 }; 36767 36768 Likes.prototype.onLikeClick = function(e) { 36769 var $el; 36770 $el = $(e.currentTarget); 36771 return App.events.publish('app:likes:like', $el.attr('data-item-id'), $el.attr('data-item-type')); 36772 }; 36773 36774 Likes.prototype.onLikeBind = function($scope) { 36775 return $scope.find('.js-like').on('click', this.onLikeClick); 36776 }; 36777 36778 return Likes; 36779 36780 })(); 36781 36782}).call(this); 36783(function() { 36784 App.Widgets.LinkFaker = (function() { 36785 function LinkFaker() {} 36786 36787 LinkFaker.prototype.initialize = function() { 36788 return this.bindEvents(); 36789 }; 36790 36791 LinkFaker.prototype.bindEvents = function() { 36792 return $('.js-acts-as-link').on('click', this.onClick); 36793 }; 36794 36795 LinkFaker.prototype.onClick = function(e) { 36796 var $el; 36797 e.preventDefault(); 36798 $el = $(e.currentTarget); 36799 return window.location = $el.data('url'); 36800 }; 36801 36802 return LinkFaker; 36803 36804 })(); 36805 36806}).call(this); 36807(function() { 36808 App.Widgets.LoyaltyLevelProgressInfoTooltip = (function() { 36809 function LoyaltyLevelProgressInfoTooltip() {} 36810 36811 LoyaltyLevelProgressInfoTooltip.prototype.initialize = function() { 36812 this.$infoTooltip = $('.js-loyalty-level-info-tooltip'); 36813 this.$currentLevelTooltip = $('.js-current-level-tooltip'); 36814 this.$nextLevelTooltip = $('.js-next-level-tooltip'); 36815 if (this.$infoTooltip.length > 0) { 36816 this.initInfoTooltip(); 36817 } 36818 if (this.$currentLevelTooltip.length > 0) { 36819 this.initCurrentLevelTooltip(); 36820 } 36821 if (this.$nextLevelTooltip.length > 0) { 36822 return this.initNextLevelTooltip(); 36823 } 36824 }; 36825 36826 LoyaltyLevelProgressInfoTooltip.prototype.initInfoTooltip = function() { 36827 var infoTooltipMessage; 36828 infoTooltipMessage = I18n.t('tooltips.buyer_loyalty_program_html', { 36829 buyer_loyalty_rate: $('.js-buyer-loyalty-rate-value').text() 36830 }); 36831 return this.$infoTooltip.tooltipster({ 36832 theme: 'tooltip--light tooltip--popover u-text-center', 36833 animation: 'grow', 36834 contentAsHTML: true, 36835 content: infoTooltipMessage, 36836 maxWidth: 520 36837 }); 36838 }; 36839 36840 LoyaltyLevelProgressInfoTooltip.prototype.initCurrentLevelTooltip = function() { 36841 var currentLevelTooltipMessage; 36842 currentLevelTooltipMessage = I18n.t('tooltips.buyer_loyalty_program_current_level_html', { 36843 total_price_paid: $('.js-price-paid').text(), 36844 buyer_loyalty_rate: $('.js-buyer-loyalty-rate-value').text() 36845 }); 36846 return this.$currentLevelTooltip.tooltipster({ 36847 theme: 'tooltip--light tooltip--popover u-text-center', 36848 animation: 'grow', 36849 contentAsHTML: true, 36850 content: currentLevelTooltipMessage, 36851 maxWidth: 300 36852 }); 36853 }; 36854 36855 LoyaltyLevelProgressInfoTooltip.prototype.initNextLevelTooltip = function() { 36856 var nextLevelTooltipMessage; 36857 nextLevelTooltipMessage = I18n.t('tooltips.buyer_loyalty_program_next_level_html', { 36858 next_lvl_expenses: $('.js-next-lvl-expenses').text(), 36859 next_lvl_expenses_rate: $('.js-next-lvl-expenses-rate').text(), 36860 left_until_next_lvl: $('.js-next-lvl-expenses').text().match(/\d+/) - $('.js-price-paid').text().match(/\d+/) 36861 }); 36862 return this.$nextLevelTooltip.tooltipster({ 36863 theme: 'tooltip--light tooltip--popover u-text-center', 36864 animation: 'grow', 36865 contentAsHTML: true, 36866 content: nextLevelTooltipMessage, 36867 maxWidth: 250 36868 }); 36869 }; 36870 36871 return LoyaltyLevelProgressInfoTooltip; 36872 36873 })(); 36874 36875}).call(this); 36876/* Notify.js - http://notifyjs.com/ Copyright (c) 2015 MIT */ 36877 36878(function (factory) { 36879 // UMD start 36880 // https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js 36881 if (typeof define === 'function' && define.amd) { 36882 // AMD. Register as an anonymous module. 36883 define(['jquery'], factory); 36884 } else if (typeof module === 'object' && module.exports) { 36885 // Node/CommonJS 36886 module.exports = function( root, jQuery ) { 36887 if ( jQuery === undefined ) { 36888 // require('jQuery') returns a factory that requires window to 36889 // build a jQuery instance, we normalize how we use modules 36890 // that require this pattern but the window provided is a noop 36891 // if it's defined (how jquery works) 36892 if ( typeof window !== 'undefined' ) { 36893 jQuery = require('jquery'); 36894 } 36895 else { 36896 jQuery = require('jquery')(root); 36897 } 36898 } 36899 factory(jQuery); 36900 return jQuery; 36901 }; 36902 } else { 36903 // Browser globals 36904 factory(jQuery); 36905 } 36906}(function ($) { 36907 //IE8 indexOf polyfill 36908 var indexOf = [].indexOf || function(item) { 36909 for (var i = 0, l = this.length; i < l; i++) { 36910 if (i in this && this[i] === item) { 36911 return i; 36912 } 36913 } 36914 return -1; 36915 }; 36916 36917 var pluginName = "notify"; 36918 var pluginClassName = pluginName + "js"; 36919 var blankFieldName = pluginName + "!blank"; 36920 36921 var positions = { 36922 t: "top", 36923 m: "middle", 36924 b: "bottom", 36925 l: "left", 36926 c: "center", 36927 r: "right" 36928 }; 36929 var hAligns = ["l", "c", "r"]; 36930 var vAligns = ["t", "m", "b"]; 36931 var mainPositions = ["t", "b", "l", "r"]; 36932 var opposites = { 36933 t: "b", 36934 m: null, 36935 b: "t", 36936 l: "r", 36937 c: null, 36938 r: "l" 36939 }; 36940 36941 var parsePosition = function(str) { 36942 var pos; 36943 pos = []; 36944 $.each(str.split(/\W+/), function(i, word) { 36945 var w; 36946 w = word.toLowerCase().charAt(0); 36947 if (positions[w]) { 36948 return pos.push(w); 36949 } 36950 }); 36951 return pos; 36952 }; 36953 36954 var styles = {}; 36955 36956 var coreStyle = { 36957 name: "core", 36958 html: "<div class=\"" + pluginClassName + "-wrapper\">\n <div class=\"" + pluginClassName + "-arrow\"></div>\n <div class=\"" + pluginClassName + "-container\"></div>\n</div>", 36959 css: "." + pluginClassName + "-corner {\n position: fixed;\n margin: 5px;\n z-index: 1050;\n}\n\n." + pluginClassName + "-corner ." + pluginClassName + "-wrapper,\n." + pluginClassName + "-corner ." + pluginClassName + "-container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n margin: 3px;\n}\n\n." + pluginClassName + "-wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n}\n\n." + pluginClassName + "-container {\n display: none;\n z-index: 1;\n position: absolute;\n}\n\n." + pluginClassName + "-hidable {\n cursor: pointer;\n}\n\n[data-notify-text],[data-notify-html] {\n position: relative;\n}\n\n." + pluginClassName + "-arrow {\n position: absolute;\n z-index: 2;\n width: 0;\n height: 0;\n}" 36960 }; 36961 36962 var stylePrefixes = { 36963 "border-radius": ["-webkit-", "-moz-"] 36964 }; 36965 36966 var getStyle = function(name) { 36967 return styles[name]; 36968 }; 36969 36970 var removeStyle = function(name) { 36971 if (!name) { 36972 throw "Missing Style name"; 36973 } 36974 if (styles[name]) { 36975 delete styles[name]; 36976 } 36977 }; 36978 36979 var addStyle = function(name, def) { 36980 if (!name) { 36981 throw "Missing Style name"; 36982 } 36983 if (!def) { 36984 throw "Missing Style definition"; 36985 } 36986 if (!def.html) { 36987 throw "Missing Style HTML"; 36988 } 36989 //remove existing style 36990 var existing = styles[name]; 36991 if (existing && existing.cssElem) { 36992 if (window.console) {
36993 console.warn(pluginName + ": overwriting style '" + name + "'"); 36994 } 36995 styles[name].cssElem.remove(); 36996 } 36997 def.name = name; 36998 styles[name] = def; 36999 var cssText = ""; 37000 if (def.classes) { 37001 $.each(def.classes, function(className, props) { 37002 cssText += "." + pluginClassName + "-" + def.name + "-" + className + " {\n"; 37003 $.each(props, function(name, val) { 37004 if (stylePrefixes[name]) { 37005 $.each(stylePrefixes[name], function(i, prefix) { 37006 return cssText += " " + prefix + name + ": " + val + ";\n"; 37007 }); 37008 } 37009 return cssText += " " + name + ": " + val + ";\n"; 37010 }); 37011 return cssText += "}\n"; 37012 }); 37013 } 37014 if (def.css) { 37015 cssText += "/* styles for " + def.name + " */\n" + def.css; 37016 } 37017 if (cssText) { 37018 def.cssElem = insertCSS(cssText); 37019 def.cssElem.attr("id", "notify-" + def.name); 37020 } 37021 var fields = {}; 37022 var elem = $(def.html); 37023 findFields("html", elem, fields); 37024 findFields("text", elem, fields); 37025 def.fields = fields; 37026 }; 37027 37028 var insertCSS = function(cssText) { 37029 var e, elem, error; 37030 elem = createElem("style"); 37031 elem.attr("type", 'text/css'); 37032 $("head").append(elem); 37033 try { 37034 elem.html(cssText); 37035 } catch (_) { 37036 elem[0].styleSheet.cssText = cssText; 37037 } 37038 return elem; 37039 }; 37040 37041 var findFields = function(type, elem, fields) { 37042 var attr; 37043 if (type !== "html") { 37044 type = "text"; 37045 } 37046 attr = "data-notify-" + type; 37047 return find(elem, "[" + attr + "]").each(function() { 37048 var name; 37049 name = $(this).attr(attr); 37050 if (!name) { 37051 name = blankFieldName; 37052 } 37053 fields[name] = type; 37054 }); 37055 }; 37056 37057 var find = function(elem, selector) { 37058 if (elem.is(selector)) { 37059 return elem; 37060 } else { 37061 return elem.find(selector); 37062 } 37063 }; 37064 37065 var pluginOptions = { 37066 clickToHide: true, 37067 autoHide: true, 37068 autoHideDelay: 5000, 37069 arrowShow: true, 37070 arrowSize: 5, 37071 breakNewLines: true, 37072 elementPosition: "bottom", 37073 globalPosition: "top right", 37074 style: "bootstrap", 37075 className: "error", 37076 showAnimation: "slideDown", 37077 showDuration: 400, 37078 hideAnimation: "slideUp", 37079 hideDuration: 200, 37080 gap: 5 37081 }; 37082 37083 var inherit = function(a, b) { 37084 var F; 37085 F = function() {}; 37086 F.prototype = a; 37087 return $.extend(true, new F(), b); 37088 }; 37089 37090 var defaults = function(opts) { 37091 return $.extend(pluginOptions, opts); 37092 }; 37093 37094 var createElem = function(tag) { 37095 return $("<" + tag + "></" + tag + ">"); 37096 }; 37097 37098 var globalAnchors = {}; 37099 37100 var getAnchorElement = function(element) { 37101 var radios; 37102 if (element.is('[type=radio]')) { 37103 radios = element.parents('form:first').find('[type=radio]').filter(function(i, e) { 37104 return $(e).attr("name") === element.attr("name"); 37105 }); 37106 element = radios.first(); 37107 } 37108 return element; 37109 }; 37110 37111 var incr = function(obj, pos, val) { 37112 var opp, temp; 37113 if (typeof val === "string") { 37114 val = parseInt(val, 10); 37115 } else if (typeof val !== "number") { 37116 return; 37117 } 37118 if (isNaN(val)) { 37119 return; 37120 } 37121 opp = positions[opposites[pos.charAt(0)]]; 37122 temp = pos; 37123 if (obj[opp] !== undefined) { 37124 pos = positions[opp.charAt(0)]; 37125 val = -val; 37126 } 37127 if (obj[pos] === undefined) { 37128 obj[pos] = val; 37129 } else { 37130 obj[pos] += val; 37131 } 37132 return null; 37133 }; 37134 37135 var realign = function(alignment, inner, outer) { 37136 if (alignment === "l" || alignment === "t") { 37137 return 0; 37138 } else if (alignment === "c" || alignment === "m") { 37139 return outer / 2 - inner / 2; 37140 } else if (alignment === "r" || alignment === "b") { 37141 return outer - inner; 37142 } 37143 throw "Invalid alignment"; 37144 }; 37145 37146 var encode = function(text) { 37147 encode.e = encode.e || createElem("div"); 37148 return encode.e.text(text).html(); 37149 }; 37150 37151 function Notification(elem, data, options) { 37152 if (typeof options === "string") { 37153 options = { 37154 className: options 37155 }; 37156 } 37157 this.options = inherit(pluginOptions, $.isPlainObject(options) ? options : {}); 37158 this.loadHTML(); 37159 this.wrapper = $(coreStyle.html); 37160 if (this.options.clickToHide) { 37161 this.wrapper.addClass(pluginClassName + "-hidable"); 37162 } 37163 this.wrapper.data(pluginClassName, this); 37164 this.arrow = this.wrapper.find("." + pluginClassName + "-arrow"); 37165 this.container = this.wrapper.find("." + pluginClassName + "-container"); 37166 this.container.append(this.userContainer); 37167 if (elem && elem.length) { 37168 this.elementType = elem.attr("type"); 37169 this.originalElement = elem; 37170 this.elem = getAnchorElement(elem); 37171 this.elem.data(pluginClassName, this); 37172 this.elem.before(this.wrapper); 37173 } 37174 this.container.hide(); 37175 this.run(data); 37176 } 37177 37178 Notification.prototype.loadHTML = function() { 37179 var style;
37180 style = this.getStyle(); 37181 this.userContainer = $(style.html); 37182 this.userFields = style.fields; 37183 }; 37184 37185 Notification.prototype.show = function(show, userCallback) { 37186 var args, callback, elems, fn, hidden; 37187 callback = (function(_this) { 37188 return function() { 37189 if (!show && !_this.elem) { 37190 _this.destroy(); 37191 } 37192 if (userCallback) { 37193 return userCallback(); 37194 } 37195 }; 37196 })(this); 37197 hidden = this.container.parent().parents(':hidden').length > 0; 37198 elems = this.container.add(this.arrow); 37199 args = []; 37200 if (hidden && show) { 37201 fn = "show"; 37202 } else if (hidden && !show) { 37203 fn = "hide"; 37204 } else if (!hidden && show) { 37205 fn = this.options.showAnimation; 37206 args.push(this.options.showDuration); 37207 } else if (!hidden && !show) { 37208 fn = this.options.hideAnimation; 37209 args.push(this.options.hideDuration); 37210 } else { 37211 return callback(); 37212 } 37213 args.push(callback); 37214 return elems[fn].apply(elems, args); 37215 }; 37216 37217 Notification.prototype.setGlobalPosition = function() { 37218 var p = this.getPosition(); 37219 var pMain = p[0]; 37220 var pAlign = p[1]; 37221 var main = positions[pMain]; 37222 var align = positions[pAlign]; 37223 var key = pMain + "|" + pAlign; 37224 var anchor = globalAnchors[key]; 37225 if (!anchor || !document.body.contains(anchor[0])) { 37226 anchor = globalAnchors[key] = createElem("div"); 37227 var css = {}; 37228 css[main] = 0; 37229 if (align === "middle") { 37230 css.top = '45%'; 37231 } else if (align === "center") { 37232 css.left = '45%'; 37233 } else { 37234 css[align] = 0; 37235 } 37236 anchor.css(css).addClass(pluginClassName + "-corner"); 37237 $("body").append(anchor); 37238 } 37239 return anchor.prepend(this.wrapper); 37240 }; 37241 37242 Notification.prototype.setElementPosition = function() { 37243 var arrowColor, arrowCss, arrowSize, color, contH, contW, css, elemH, elemIH, elemIW, elemPos, elemW, gap, j, k, len, len1, mainFull, margin, opp, oppFull, pAlign, pArrow, pMain, pos, posFull, position, ref, wrapPos; 37244 position = this.getPosition(); 37245 pMain = position[0]; 37246 pAlign = position[1]; 37247 pArrow = position[2]; 37248 elemPos = this.elem.position(); 37249 elemH = this.elem.outerHeight(); 37250 elemW = this.elem.outerWidth();
37251 elemIH = this.elem.innerHeight(); 37252 elemIW = this.elem.innerWidth(); 37253 wrapPos = this.wrapper.position(); 37254 contH = this.container.height(); 37255 contW = this.container.width(); 37256 mainFull = positions[pMain]; 37257 opp = opposites[pMain]; 37258 oppFull = positions[opp]; 37259 css = {}; 37260 css[oppFull] = pMain === "b" ? elemH : pMain === "r" ? elemW : 0; 37261 incr(css, "top", elemPos.top - wrapPos.top); 37262 incr(css, "left", elemPos.left - wrapPos.left); 37263 ref = ["top", "left"]; 37264 for (j = 0, len = ref.length; j < len; j++) { 37265 pos = ref[j]; 37266 margin = parseInt(this.elem.css("margin-" + pos), 10); 37267 if (margin) { 37268 incr(css, pos, margin); 37269 } 37270 } 37271 gap = Math.max(0, this.options.gap - (this.options.arrowShow ? arrowSize : 0)); 37272 incr(css, oppFull, gap); 37273 if (!this.options.arrowShow) { 37274 this.arrow.hide(); 37275 } else { 37276 arrowSize = this.options.arrowSize; 37277 arrowCss = $.extend({}, css); 37278 arrowColor = this.userContainer.css("border-color") || this.userContainer.css("border-top-color") || this.userContainer.css("background-color") || "white"; 37279 for (k = 0, len1 = mainPositions.length; k < len1; k++) { 37280 pos = mainPositions[k]; 37281 posFull = positions[pos]; 37282 if (pos === opp) { 37283 continue; 37284 } 37285 color = posFull === mainFull ? arrowColor : "transparent"; 37286 arrowCss["border-" + posFull] = arrowSize + "px solid " + color; 37287 } 37288 incr(css, positions[opp], arrowSize); 37289 if (indexOf.call(mainPositions, pAlign) >= 0) { 37290 incr(arrowCss, positions[pAlign], arrowSize * 2); 37291 } 37292 } 37293 if (indexOf.call(vAligns, pMain) >= 0) { 37294 incr(css, "left", realign(pAlign, contW, elemW)); 37295 if (arrowCss) { 37296 incr(arrowCss, "left", realign(pAlign, arrowSize, elemIW)); 37297 } 37298 } else if (indexOf.call(hAligns, pMain) >= 0) { 37299 incr(css, "top", realign(pAlign, contH, elemH)); 37300 if (arrowCss) { 37301 incr(arrowCss, "top", realign(pAlign, arrowSize, elemIH)); 37302 } 37303 } 37304 if (this.container.is(":visible")) { 37305 css.display = "block"; 37306 } 37307 this.container.removeAttr("style").css(css); 37308 if (arrowCss) { 37309 return this.arrow.removeAttr("style").css(arrowCss); 37310 } 37311 }; 37312 37313 Notification.prototype.getPosition = function() { 37314 var pos, ref, ref1, ref2, ref3, ref4, ref5, text; 37315 text = this.options.position || (this.elem ? this.options.elementPosition : this.options.globalPosition); 37316 pos = parsePosition(text); 37317 if (pos.length === 0) { 37318 pos[0] = "b"; 37319 } 37320 if (ref = pos[0], indexOf.call(mainPositions, ref) < 0) { 37321 throw "Must be one of [" + mainPositions + "]"; 37322 } 37323 if (pos.length === 1 || ((ref1 = pos[0], indexOf.call(vAligns, ref1) >= 0) && (ref2 = pos[1], indexOf.call(hAligns, ref2) < 0)) || ((ref3 = pos[0], indexOf.call(hAligns, ref3) >= 0) && (ref4 = pos[1], indexOf.call(vAligns, ref4) < 0))) { 37324 pos[1] = (ref5 = pos[0], indexOf.call(hAligns, ref5) >= 0) ? "m" : "l"; 37325 } 37326 if (pos.length === 2) { 37327 pos[2] = pos[1]; 37328 } 37329 return pos; 37330 }; 37331 37332 Notification.prototype.getStyle = function(name) { 37333 var style; 37334 if (!name) { 37335 name = this.options.style; 37336 } 37337 if (!name) { 37338 name = "default"; 37339 } 37340 style = styles[name]; 37341 if (!style) { 37342 throw "Missing style: " + name; 37343 } 37344 return style; 37345 }; 37346 37347 Notification.prototype.updateClasses = function() { 37348 var classes, style; 37349 classes = ["base"]; 37350 if ($.isArray(this.options.className)) { 37351 classes = classes.concat(this.options.className); 37352 } else if (this.options.className) { 37353 classes.push(this.options.className); 37354 } 37355 style = this.getStyle(); 37356 classes = $.map(classes, function(n) { 37357 return pluginClassName + "-" + style.name + "-" + n; 37358 }).join(" "); 37359 return this.userContainer.attr("class", classes); 37360 }; 37361 37362 Notification.prototype.run = function(data, options) { 37363 var d, datas, name, type, value; 37364 if ($.isPlainObject(options)) { 37365 $.extend(this.options, options); 37366 } else if ($.type(options) === "string") { 37367 this.options.className = options; 37368 } 37369 if (this.container && !data) { 37370 this.show(false); 37371 return; 37372 } else if (!this.container && !data) { 37373 return; 37374 } 37375 datas = {}; 37376 if ($.isPlainObject(data)) { 37377 datas = data; 37378 } else { 37379 datas[blankFieldName] = data; 37380 } 37381 for (name in datas) { 37382 d = datas[name]; 37383 type = this.userFields[name]; 37384 if (!type) { 37385 continue; 37386 } 37387 if (type === "text") { 37388 d = encode(d); 37389 if (this.options.breakNewLines) { 37390 d = d.replace(/\n/g, '<br/>'); 37391 } 37392 } 37393 value = name === blankFieldName ? '' : '=' + name; 37394 find(this.userContainer, "[data-notify-" + type + value + "]").html(d); 37395 } 37396 this.updateClasses(); 37397 if (this.elem) { 37398 this.setElementPosition(); 37399 } else { 37400 this.setGlobalPosition(); 37401 } 37402 this.show(true); 37403 if (this.options.autoHide) { 37404 clearTimeout(this.autohideTimer); 37405 this.autohideTimer = setTimeout(this.show.bind(this, false), this.options.autoHideDelay); 37406 } 37407 }; 37408 37409 Notification.prototype.destroy = function() { 37410 this.wrapper.data(pluginClassName, null); 37411 this.wrapper.remove(); 37412 }; 37413 37414 $[pluginName] = function(elem, data, options) { 37415 if ((elem && elem.nodeName) || elem.jquery) { 37416 $(elem)[pluginName](data, options); 37417 } else { 37418 options = data; 37419 data = elem; 37420 new Notification(null, data, options); 37421 } 37422 return elem; 37423 }; 37424 37425 $.fn[pluginName] = function(data, options) { 37426 $(this).each(function() { 37427 var prev = getAnchorElement($(this)).data(pluginClassName); 37428 if (prev) { 37429 prev.destroy(); 37430 } 37431 var curr = new Notification($(this), data, options); 37432 }); 37433 return this; 37434 }; 37435 37436 $.extend($[pluginName], { 37437 defaults: defaults, 37438 addStyle: addStyle, 37439 removeStyle: removeStyle, 37440 pluginOptions: pluginOptions,
37441 getStyle: getStyle, 37442 insertCSS: insertCSS 37443 }); 37444 37445 //always include the default bootstrap style 37446 addStyle("bootstrap", { 37447 html: "<div>\n<span data-notify-text></span>\n</div>", 37448 classes: { 37449 base: { 37450 "font-weight": "bold", 37451 "padding": "8px 15px 8px 14px", 37452 "text-shadow": "0 1px 0 rgba(255, 255, 255, 0.5)", 37453 "background-color": "#fcf8e3", 37454 "border": "1px solid #fbeed5", 37455 "border-radius": "4px", 37456 "white-space": "nowrap", 37457 "padding-left": "25px", 37458 "background-repeat": "no-repeat", 37459 "background-position": "3px 7px" 37460 }, 37461 error: { 37462 "color": "#B94A48", 37463 "background-color": "#F2DEDE", 37464 "border-color": "#EED3D7", 37465 "background-image": "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtRJREFUeNqkVc1u00AQHq+dOD+0poIQfkIjalW0SEGqRMuRnHos3DjwAH0ArlyQeANOOSMeAA5VjyBxKBQhgSpVUKKQNGloFdw4cWw2jtfMOna6JOUArDTazXi/b3dm55socPqQhFka++aHBsI8GsopRJERNFlY88FCEk9Yiwf8RhgRyaHFQpPHCDmZG5oX2ui2yilkcTT1AcDsbYC1NMAyOi7zTX2Agx7A9luAl88BauiiQ/cJaZQfIpAlngDcvZZMrl8vFPK5+XktrWlx3/ehZ5r9+t6e+WVnp1pxnNIjgBe4/6dAysQc8dsmHwPcW9C0h3fW1hans1ltwJhy0GxK7XZbUlMp5Ww2eyan6+ft/f2FAqXGK4CvQk5HueFz7D6GOZtIrK+srupdx1GRBBqNBtzc2AiMr7nPplRdKhb1q6q6zjFhrklEFOUutoQ50xcX86ZlqaZpQrfbBdu2R6/G19zX6XSgh6RX5ubyHCM8nqSID6ICrGiZjGYYxojEsiw4PDwMSL5VKsC8Yf4VRYFzMzMaxwjlJSlCyAQ9l0CW44PBADzXhe7xMdi9HtTrdYjFYkDQL0cn4Xdq2/EAE+InCnvADTf2eah4Sx9vExQjkqXT6aAERICMewd/UAp/IeYANM2joxt+q5VI+ieq2i0Wg3l6DNzHwTERPgo1ko7XBXj3vdlsT2F+UuhIhYkp7u7CarkcrFOCtR3H5JiwbAIeImjT/YQKKBtGjRFCU5IUgFRe7fF4cCNVIPMYo3VKqxwjyNAXNepuopyqnld602qVsfRpEkkz+GFL1wPj6ySXBpJtWVa5xlhpcyhBNwpZHmtX8AGgfIExo0ZpzkWVTBGiXCSEaHh62/PoR0p/vHaczxXGnj4bSo+G78lELU80h1uogBwWLf5YlsPmgDEd4M236xjm+8nm4IuE/9u+/PH2JXZfbwz4zw1WbO+SQPpXfwG/BBgAhCNZiSb/pOQAAAAASUVORK5CYII=)" 37466 }, 37467 success: { 37468 "color": "#468847", 37469 "background-color": "#DFF0D8", 37470 "border-color": "#D6E9C6", 37471 "background-image": "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAutJREFUeNq0lctPE0Ecx38zu/RFS1EryqtgJFA08YCiMZIAQQ4eRG8eDGdPJiYeTIwHTfwPiAcvXIwXLwoXPaDxkWgQ6islKlJLSQWLUraPLTv7Gme32zoF9KSTfLO7v53vZ3d/M7/fIth+IO6INt2jjoA7bjHCJoAlzCRw59YwHYjBnfMPqAKWQYKjGkfCJqAF0xwZjipQtA3MxeSG87VhOOYegVrUCy7UZM9S6TLIdAamySTclZdYhFhRHloGYg7mgZv1Zzztvgud7V1tbQ2twYA34LJmF4p5dXF1KTufnE+SxeJtuCZNsLDCQU0+RyKTF27Unw101l8e6hns3u0PBalORVVVkcaEKBJDgV3+cGM4tKKmI+ohlIGnygKX00rSBfszz/n2uXv81wd6+rt1orsZCHRdr1Imk2F2Kob3hutSxW8thsd8AXNaln9D7CTfA6O+0UgkMuwVvEFFUbbAcrkcTA8+AtOk8E6KiQiDmMFSDqZItAzEVQviRkdDdaFgPp8HSZKAEAL5Qh7Sq2lIJBJwv2scUqkUnKoZgNhcDKhKg5aH+1IkcouCAdFGAQsuWZYhOjwFHQ96oagWgRoUov1T9kRBEODAwxM2QtEUl+Wp+Ln9VRo6BcMw4ErHRYjH4/B26AlQoQQTRdHWwcd9AH57+UAXddvDD37DmrBBV34WfqiXPl61g+vr6xA9zsGeM9gOdsNXkgpEtTwVvwOklXLKm6+/p5ezwk4B+j6droBs2CsGa/gNs6RIxazl4Tc25mpTgw/apPR1LYlNRFAzgsOxkyXYLIM1V8NMwyAkJSctD1eGVKiq5wWjSPdjmeTkiKvVW4f2YPHWl3GAVq6ymcyCTgovM3FzyRiDe2TaKcEKsLpJvNHjZgPNqEtyi6mZIm4SRFyLMUsONSSdkPeFtY1n0mczoY3BHTLhwPRy9/lzcziCw9ACI+yql0VLzcGAZbYSM5CCSZg1/9oc/nn7+i8N9p/8An4JMADxhH+xHfuiKwAAAABJRU5ErkJggg==)" 37472 }, 37473 info: { 37474 "color": "#3A87AD", 37475 "background-color": "#D9EDF7", 37476 "border-color": "#BCE8F1", 37477 "background-image": "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QYFAhkSsdes/QAAA8dJREFUOMvVlGtMW2UYx//POaWHXg6lLaW0ypAtw1UCgbniNOLcVOLmAjHZolOYlxmTGXVZdAnRfXQm+7SoU4mXaOaiZsEpC9FkiQs6Z6bdCnNYruM6KNBw6YWewzl9z+sHImEWv+vz7XmT95f/+3/+7wP814v+efDOV3/SoX3lHAA+6ODeUFfMfjOWMADgdk+eEKz0pF7aQdMAcOKLLjrcVMVX3xdWN29/GhYP7SvnP0cWfS8caSkfHZsPE9Fgnt02JNutQ0QYHB2dDz9/pKX8QjjuO9xUxd/66HdxTeCHZ3rojQObGQBcuNjfplkD3b19Y/6MrimSaKgSMmpGU5WevmE/swa6Oy73tQHA0Rdr2Mmv/6A1n9w9suQ7097Z9lM4FlTgTDrzZTu4StXVfpiI48rVcUDM5cmEksrFnHxfpTtU/3BFQzCQF/2bYVoNbH7zmItbSoMj40JSzmMyX5qDvriA7QdrIIpA+3cdsMpu0nXI8cV0MtKXCPZev+gCEM1S2NHPvWfP/hL+7FSr3+0p5RBEyhEN5JCKYr8XnASMT0xBNyzQGQeI8fjsGD39RMPk7se2bd5ZtTyoFYXftF6y37gx7NeUtJJOTFlAHDZLDuILU3j3+H5oOrD3yWbIztugaAzg
37477nBKJuBLpGfQrS8wO4FZgV+c1IxaLgWVU0tMLEETCos4xMzEIv9cJXQcyagIwigDGwJgOAtHAwAhisQUjy0ORGERiELgG4iakkzo4MYAxcM5hAMi1WWG1yYCJIcMUaBkVRLdGeSU2995TLWzcUAzONJ7J6FBVBYIggMzmFbvdBV44Corg8vjhzC+EJEl8U1kJtgYrhCzgc/vvTwXKSib1paRFVRVORDAJAsw5FuTaJEhWM2SHB3mOAlhkNxwuLzeJsGwqWzf5TFNdKgtY5qHp6ZFf67Y/sAVadCaVY5YACDDb3Oi4NIjLnWMw2QthCBIsVhsUTU9tvXsjeq9+X1d75/KEs4LNOfcdf/+HthMnvwxOD0wmHaXr7ZItn2wuH2SnBzbZAbPJwpPx+VQuzcm7dgRCB57a1uBzUDRL4bfnI0RE0eaXd9W89mpjqHZnUI5Hh2l2dkZZUhOqpi2qSmpOmZ64Tuu9qlz/SEXo6MEHa3wOip46F1n7633eekV8ds8Wxjn37Wl63VVa+ej5oeEZ/82ZBETJjpJ1Rbij2D3Z/1trXUvLsblCK0XfOx0SX2kMsn9dX+d+7Kf6h8o4AIykuffjT8L20LU+w4AZd5VvEPY+XpWqLV327HR7DzXuDnD8r+ovkBehJ8i+y8YAAAAASUVORK5CYII=)" 37478 }, 37479 warn: { 37480 "color": "#C09853", 37481 "background-color": "#FCF8E3", 37482 "border-color": "#FBEED5", 37483 "background-image": "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABJlBMVEXr6eb/2oD/wi7/xjr/0mP/ykf/tQD/vBj/3o7/uQ//vyL/twebhgD/4pzX1K3z8e349vK6tHCilCWbiQymn0jGworr6dXQza3HxcKkn1vWvV/5uRfk4dXZ1bD18+/52YebiAmyr5S9mhCzrWq5t6ufjRH54aLs0oS+qD751XqPhAybhwXsujG3sm+Zk0PTwG6Shg+PhhObhwOPgQL4zV2nlyrf27uLfgCPhRHu7OmLgAafkyiWkD3l49ibiAfTs0C+lgCniwD4sgDJxqOilzDWowWFfAH08uebig6qpFHBvH/aw26FfQTQzsvy8OyEfz20r3jAvaKbhgG9q0nc2LbZxXanoUu/u5WSggCtp1anpJKdmFz/zlX/1nGJiYmuq5Dx7+sAAADoPUZSAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfdBgUBGhh4aah5AAAAlklEQVQY02NgoBIIE8EUcwn1FkIXM1Tj5dDUQhPU502Mi7XXQxGz5uVIjGOJUUUW81HnYEyMi2HVcUOICQZzMMYmxrEyMylJwgUt5BljWRLjmJm4pI1hYp5SQLGYxDgmLnZOVxuooClIDKgXKMbN5ggV1ACLJcaBxNgcoiGCBiZwdWxOETBDrTyEFey0jYJ4eHjMGWgEAIpRFRCUt08qAAAAAElFTkSuQmCC)" 37484 } 37485 } 37486 }); 37487 37488 $(function() { 37489 insertCSS(coreStyle.css).attr("id", "core-notify"); 37490 $(document).on("click", "." + pluginClassName + "-hidable", function(e) { 37491 $(this).trigger("notify-hide"); 37492 }); 37493 $(document).on("notify-hide", "." + pluginClassName + "-wrapper", function(e) { 37494 var elem = $(this).data(pluginClassName); 37495 if(elem) { 37496 elem.show(false); 37497 } 37498 }); 37499 }); 37500 37501})); 37502(function() { 37503 App.Widgets.Notification = (function() { 37504 function Notification() {} 37505 37506 Notification.prototype.initialize = function() { 37507 this.$el = $(".notification-bar"); 37508 this.doOptOut = 0; 37509 if ($.notify) { 37510 $.notify.addStyle('custom', { 37511 html: '<div>' + '<div class="notification-icon js-notification-content" />' + '<div class="notification-content notifyjs-notification-text js-notification-content" data-notify-html />' + '<div class="notification-close-icon js-close-notification" />' + '</div>' 37512 }); 37513 } 37514 App.events.subscribe('app:notification:flash:success', (function(_this) { 37515 return function(message, autohide, handleOptOut) { 37516 if (handleOptOut && handleOptOut.optOutCallback) { 37517 _this.doOptOut = handleOptOut.optOutCallback; 37518 } 37519 return _this.spawn(message, 'success', autohide); 37520 }; 37521 })(this)); 37522 App.events.subscribe('app:notification:flash:error', (function(_this) { 37523 return function(message, autohide) { 37524 return _this.spawn(message, 'error', autohide); 37525 }; 37526 })(this)); 37527 App.events.subscribe("app:notification:flash:warning", (function(_this) { 37528 return function(message) { 37529 return _this.spawn(message, 'warning'); 37530 }; 37531 })(this)); 37532 App.events.subscribe('app:notification:flash:info', (function(_this) { 37533 return function(message) { 37534 return _this.spawn(message, 'info'); 37535 }; 37536 })(this)); 37537 App.events.subscribe('app:notification:success', (function(_this) { 37538 return function(message) { 37539 return _this.spawn(message, 'success', false); 37540 }; 37541 })(this)); 37542 App.events.subscribe('app:notification:error', (function(_this) { 37543 return function(message) { 37544 return _this.spawn(message, 'error', false); 37545 }; 37546 })(this)); 37547 App.events.subscribe('app:notification:warning', (function(_this) { 37548 return function(message) { 37549 return _this.spawn(message, 'warning', false); 37550 }; 37551 })(this));
37552 App.events.subscribe('app:notification:info', (function(_this) { 37553 return function(message) { 37554 return _this.spawn(message, 'info', false); 37555 }; 37556 })(this)); 37557 if (this.$el.hasClass('js-active-notification')) { 37558 this.spawn(this.$el.text(), 'error', false); 37559 } 37560 return this.triggerGonNotifications(); 37561 }; 37562 37563 Notification.prototype.spawn = function(message, type, autohide) { 37564 var $corner, topOffset; 37565 if (autohide == null) { 37566 autohide = true; 37567 } 37568 if (autohide) { 37569 $.notify(message, { 37570 style: 'custom', 37571 className: type, 37572 autoHide: true, 37573 autoHideDelay: 7000, 37574 showDuration: 200 37575 }); 37576 } else { 37577 $.notify(message, { 37578 style: 'custom', 37579 className: type, 37580 autoHide: false, 37581 showDuration: 200 37582 }); 37583 } 37584 $corner = $('.notifyjs-corner'); 37585 topOffset = $('.wayfinder-container').height(); 37586 return $corner.css('top', topOffset); 37587 }; 37588 37589 Notification.prototype.triggerGonNotifications = function() { 37590 if (gon.js_success_message != null) { 37591 App.events.publish('app:notification:flash:success', gon.js_success_message, gon.autohide); 37592 } 37593 if (gon.js_error_message != null) { 37594 return App.events.publish('app:notification:flash:error', gon.js_error_message, gon.autohide); 37595 } 37596 }; 37597 37598 return Notification; 37599 37600 })(); 37601 37602}).call(this); 37603(function() { 37604 App.Widgets.PaymentAgreement = (function() { 37605 function PaymentAgreement() {} 37606 37607 PaymentAgreement.prototype.initialize = function() { 37608 if ((typeof BarsOrdering !== "undefined" && BarsOrdering !== null) && BarsOrdering('renderSignAgreementNotification')) { 37609 return this.showNotificationBar(); 37610 } 37611 }; 37612 37613 PaymentAgreement.prototype.showNotificationBar = function() { 37614 var $notificationBar; 37615 $notificationBar = $(JST["payment_agreement/notification_bar"]()); 37616 return $('body').prepend($notificationBar); 37617 }; 37618 37619 return PaymentAgreement; 37620 37621 })(); 37622 37623}).call(this); 37624(function() { 37625 App.Widgets.Pinger = (function() { 37626 function Pinger() {} 37627 37628 Pinger.prototype.initialize = function() { 37629 if (App.config.environment !== 'test') { 37630 this.ping(); 37631 return setTimeout(this.ping, App.config.userPingInterval); 37632 } 37633 }; 37634 37635 Pinger.prototype.ping = function() { 37636 if (!App.config.userSignedIn) { 37637 return; 37638 } 37639 return $.post("/api/internal/users/ping"); 37640 }; 37641 37642 return Pinger; 37643 37644 })(); 37645 37646}).call(this); 37647(function() { 37648 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 37649 37650 App.Widgets.PopoverBox = (function() { 37651 function PopoverBox() { 37652 this.onTriggerClick = bind(this.onTriggerClick, this); 37653 this.onOutsideClick = bind(this.onOutsideClick, this); 37654 this.open = bind(this.open, this); 37655 this.position = bind(this.position, this); 37656 } 37657 37658 PopoverBox.prototype.options = { 37659 animationDuration: 400, 37660 easing: 'easeInOutCirc' 37661 }; 37662 37663 PopoverBox.prototype.$target = null; 37664 37665 PopoverBox.prototype.$el = null; 37666 37667 PopoverBox.prototype.initialize = function() { 37668 if (!this.$el.exists) { 37669 return; 37670 } 37671 return this.bindEvents(); 37672 }; 37673 37674 PopoverBox.prototype.bindEvents = function() { 37675 $(window).on('resize', this.position); 37676 this.$target.on('click', this.onTriggerClick); 37677 return this.$target.add(this.$el).hideOnOutsideClick(this.onOutsideClick); 37678 }; 37679 37680 PopoverBox.prototype.position = function() { 37681 var offset; 37682 offset = this.$target.offset(); 37683 if (!offset) { 37684 return; 37685 } 37686 return this.$el.css({ 37687 top: offset.top + this.$target.height(), 37688 left: offset.left - this.$el.width() + this.$target.width() 37689 }); 37690 }; 37691 37692 PopoverBox.prototype.toggle = function() { 37693 if (this.$target.hasClass('is-active')) { 37694 this.hideCallback(); 37695 } else { 37696 this.position(); 37697 this.openCallback(); 37698 } 37699 this.$target.toggleClass('is-active'); 37700 return this.$el.slideToggle(this.options).promise().done((function(_this) { 37701 return function() { 37702 return _this.$el.toggleClass('is-active'); 37703 }; 37704 })(this)); 37705 }; 37706 37707 PopoverBox.prototype.hide = function() { 37708 if (!this.$target.hasClass('is-active')) { 37709 return; 37710 } 37711 this.hideCallback(); 37712 this.$target.removeClass('is-active'); 37713 return this.$el.slideUp(this.options).promise().done((function(_this) { 37714 return function() { 37715 return _this.$el.removeClass('is-active'); 37716 }; 37717 })(this)); 37718 }; 37719 37720 PopoverBox.prototype.open = function() { 37721 if (this.$target.hasClass('is-active')) { 37722 return; 37723 } 37724 this.position(); 37725 this.openCallback(); 37726 return this.$el.slideDown(this.options).promise().done((function(_this) { 37727 return function() { 37728 _this.$el.addClass('is-active'); 37729 return _this.$target.addClass('is-active'); 37730 }; 37731 })(this)); 37732 }; 37733 37734 PopoverBox.prototype.onOutsideClick = function(e) { 37735 if (e != null) { 37736 if (typeof e.preventDefault === "function") { 37737 e.preventDefault(); 37738 } 37739 } 37740 return this.hide(); 37741 }; 37742 37743 PopoverBox.prototype.onTriggerClick = function(e) { 37744 e.preventDefault(); 37745 return this.toggle(); 37746 }; 37747 37748 PopoverBox.prototype.openCallback = function() {}; 37749 37750 PopoverBox.prototype.hideCallback = function() {}; 37751 37752 return PopoverBox; 37753 37754 })(); 37755 37756}).call(this); 37757(function() { 37758 App.Widgets.PostalCodeTooltip = (function() { 37759 function PostalCodeTooltip() {} 37760 37761 PostalCodeTooltip.prototype.initialize = function() { 37762 this.$tooltip = $('.js-postal-code-tooltip'); 37763 if (this.$tooltip.length > 0) { 37764 return this.initTooltip(); 37765 } 37766 }; 37767 37768 PostalCodeTooltip.prototype.initTooltip = function() { 37769 var content;
vendor: 10,914 bytes, lines 37770-38214
37770 content = "Some banks require address information in order to approve transactions. We recommend providing postal code and\ncountry as it may help to successfully authorize your payment."; 37771 return this.$tooltip.tooltipster({ 37772 theme: 'tooltip--light tooltip--popover u-text-center', 37773 animation: 'grow', 37774 contentAsHTML: true, 37775 content: content, 37776 position: 'top', 37777 interactive: true, 37778 maxWidth: 400 37779 }); 37780 }; 37781 37782 return PostalCodeTooltip; 37783 37784 })(); 37785 37786}).call(this); 37787(function() { 37788 App.Widgets.PotentialBuyerManager = (function() { 37789 function PotentialBuyerManager() {} 37790 37791 PotentialBuyerManager.prototype.initialize = function() { 37792 return setTimeout(function() { 37793 if (App.config.userIsPotentialBuyer) { 37794 return hj('trigger', 'UserIsPotentialBuyer'); 37795 } 37796 }, 2000); 37797 }; 37798 37799 return PotentialBuyerManager; 37800 37801 })(); 37802 37803}).call(this); 37804/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress 37805 * @license MIT */ 37806 37807 37808;(function(root, factory) { 37809 37810 if (typeof define === 'function' && define.amd) { 37811 define(factory); 37812 } else if (typeof exports === 'object') { 37813 module.exports = factory(); 37814 } else { 37815 root.NProgress = factory(); 37816 } 37817 37818})(this, function() { 37819 var NProgress = {}; 37820 37821 NProgress.version = '0.2.0'; 37822 37823 var Settings = NProgress.settings = { 37824 minimum: 0.08, 37825 easing: 'ease', 37826 positionUsing: '', 37827 speed: 200, 37828 trickle: true, 37829 trickleRate: 0.02, 37830 trickleSpeed: 800, 37831 showSpinner: true, 37832 barSelector: '[role="bar"]', 37833 spinnerSelector: '[role="spinner"]', 37834 parent: 'body', 37835 template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>' 37836 }; 37837 37838 /** 37839 * Updates configuration. 37840 * 37841 * NProgress.configure({ 37842 * minimum: 0.1 37843 * }); 37844 */ 37845 NProgress.configure = function(options) { 37846 var key, value; 37847 for (key in options) { 37848 value = options[key]; 37849 if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; 37850 } 37851 37852 return this; 37853 }; 37854 37855 /** 37856 * Last number. 37857 */ 37858 37859 NProgress.status = null; 37860 37861 /** 37862 * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. 37863 * 37864 * NProgress.set(0.4); 37865 * NProgress.set(1.0); 37866 */ 37867 37868 NProgress.set = function(n) { 37869 var started = NProgress.isStarted(); 37870 37871 n = clamp(n, Settings.minimum, 1); 37872 NProgress.status = (n === 1 ? null : n); 37873 37874 var progress = NProgress.render(!started), 37875 bar = progress.querySelector(Settings.barSelector), 37876 speed = Settings.speed, 37877 ease = Settings.easing; 37878 37879 progress.offsetWidth; /* Repaint */ 37880 37881 queue(function(next) { 37882 // Set positionUsing if it hasn't already been set 37883 if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); 37884 37885 // Add transition 37886 css(bar, barPositionCSS(n, speed, ease)); 37887 37888 if (n === 1) { 37889 // Fade out 37890 css(progress, { 37891 transition: 'none', 37892 opacity: 1 37893 }); 37894 progress.offsetWidth; /* Repaint */ 37895 37896 setTimeout(function() { 37897 css(progress, { 37898 transition: 'all ' + speed + 'ms linear', 37899 opacity: 0 37900 }); 37901 setTimeout(function() { 37902 NProgress.remove(); 37903 next(); 37904 }, speed); 37905 }, speed); 37906 } else { 37907 setTimeout(next, speed); 37908 } 37909 }); 37910 37911 return this; 37912 }; 37913 37914 NProgress.isStarted = function() { 37915 return typeof NProgress.status === 'number'; 37916 }; 37917 37918 /** 37919 * Shows the progress bar. 37920 * This is the same as setting the status to 0%, except that it doesn't go backwards. 37921 * 37922 * NProgress.start(); 37923 * 37924 */ 37925 NProgress.start = function() { 37926 if (!NProgress.status) NProgress.set(0); 37927 37928 var work = function() { 37929 setTimeout(function() { 37930 if (!NProgress.status) return; 37931 NProgress.trickle(); 37932 work(); 37933 }, Settings.trickleSpeed); 37934 }; 37935 37936 if (Settings.trickle) work(); 37937 37938 return this; 37939 }; 37940 37941 /** 37942 * Hides the progress bar. 37943 * This is the *sort of* the same as setting the status to 100%, with the 37944 * difference being `done()` makes some placebo effect of some realistic motion. 37945 * 37946 * NProgress.done(); 37947 * 37948 * If `true` is passed, it will show the progress bar even if its hidden. 37949 * 37950 * NProgress.done(true); 37951 */ 37952 37953 NProgress.done = function(force) { 37954 if (!force && !NProgress.status) return this; 37955 37956 return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); 37957 }; 37958 37959 /** 37960 * Increments by a random amount. 37961 */ 37962 37963 NProgress.inc = function(amount) { 37964 var n = NProgress.status; 37965 37966 if (!n) { 37967 return NProgress.start(); 37968 } else { 37969 if (typeof amount !== 'number') { 37970 amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95); 37971 } 37972 37973 n = clamp(n + amount, 0, 0.994); 37974 return NProgress.set(n); 37975 } 37976 }; 37977 37978 NProgress.trickle = function() { 37979 return NProgress.inc(Math.random() * Settings.trickleRate); 37980 }; 37981 37982 /** 37983 * Waits for all supplied jQuery promises and 37984 * increases the progress as the promises resolve. 37985 * 37986 * @param $promise jQUery Promise 37987 */ 37988 (function() { 37989 var initial = 0, current = 0; 37990 37991 NProgress.promise = function($promise) { 37992 if (!$promise || $promise.state() === "resolved") { 37993 return this; 37994 } 37995 37996 if (current === 0) { 37997 NProgress.start(); 37998 } 37999 38000 initial++; 38001 current++; 38002 38003 $promise.always(function() { 38004 current--; 38005 if (current === 0) { 38006 initial = 0; 38007 NProgress.done(); 38008 } else { 38009 NProgress.set((initial - current) / initial); 38010 } 38011 }); 38012 38013 return this; 38014 }; 38015 38016 })(); 38017 38018 /** 38019 * (Internal) renders the progress bar markup based on the `template` 38020 * setting. 38021 */ 38022 38023 NProgress.render = function(fromStart) { 38024 if (NProgress.isRendered()) return document.getElementById('nprogress'); 38025 38026 addClass(document.documentElement, 'nprogress-busy'); 38027 38028 var progress = document.createElement('div'); 38029 progress.id = 'nprogress'; 38030 progress.innerHTML = Settings.template; 38031 38032 var bar = progress.querySelector(Settings.barSelector), 38033 perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), 38034 parent = document.querySelector(Settings.parent), 38035 spinner; 38036 38037 css(bar, { 38038 transition: 'all 0 linear', 38039 transform: 'translate3d(' + perc + '%,0,0)' 38040 }); 38041 38042 if (!Settings.showSpinner) { 38043 spinner = progress.querySelector(Settings.spinnerSelector); 38044 spinner && removeElement(spinner); 38045 } 38046 38047 if (parent != document.body) { 38048 addClass(parent, 'nprogress-custom-parent'); 38049 } 38050 38051 parent.appendChild(progress); 38052 return progress; 38053 }; 38054 38055 /** 38056 * Removes the element. Opposite of render(). 38057 */ 38058 38059 NProgress.remove = function() { 38060 removeClass(document.documentElement, 'nprogress-busy'); 38061 removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent'); 38062 var progress = document.getElementById('nprogress'); 38063 progress && removeElement(progress); 38064 }; 38065 38066 /** 38067 * Checks if the progress bar is rendered. 38068 */ 38069 38070 NProgress.isRendered = function() { 38071 return !!document.getElementById('nprogress'); 38072 }; 38073 38074 /** 38075 * Determine which positioning CSS rule to use. 38076 */ 38077 38078 NProgress.getPositioningCSS = function() { 38079 // Sniff on document.body.style 38080 var bodyStyle = document.body.style; 38081 38082 // Sniff prefixes 38083 var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' : 38084 ('MozTransform' in bodyStyle) ? 'Moz' : 38085 ('msTransform' in bodyStyle) ? 'ms' : 38086 ('OTransform' in bodyStyle) ? 'O' : ''; 38087 38088 if (vendorPrefix + 'Perspective' in bodyStyle) { 38089 // Modern browsers with 3D support, e.g. Webkit, IE10 38090 return 'translate3d'; 38091 } else if (vendorPrefix + 'Transform' in bodyStyle) { 38092 // Browsers without 3D support, e.g. IE9 38093 return 'translate'; 38094 } else { 38095 // Browsers without translate() support, e.g. IE7-8 38096 return 'margin'; 38097 } 38098 }; 38099 38100 /** 38101 * Helpers 38102 */ 38103 38104 function clamp(n, min, max) { 38105 if (n < min) return min; 38106 if (n > max) return max; 38107 return n; 38108 } 38109 38110 /** 38111 * (Internal) converts a percentage (`0..1`) to a bar translateX 38112 * percentage (`-100%..0%`). 38113 */ 38114 38115 function toBarPerc(n) { 38116 return (-1 + n) * 100; 38117 } 38118 38119 38120 /** 38121 * (Internal) returns the correct CSS for changing the bar's 38122 * position given an n percentage, and speed and ease from Settings 38123 */ 38124 38125 function barPositionCSS(n, speed, ease) { 38126 var barCSS; 38127 38128 if (Settings.positionUsing === 'translate3d') { 38129 barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' }; 38130 } else if (Settings.positionUsing === 'translate') { 38131 barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' }; 38132 } else { 38133 barCSS = { 'margin-left': toBarPerc(n)+'%' }; 38134 } 38135 38136 barCSS.transition = 'all '+speed+'ms '+ease; 38137 38138 return barCSS; 38139 } 38140 38141 /** 38142 * (Internal) Queues a function to be executed. 38143 */ 38144 38145 var queue = (function() { 38146 var pending = []; 38147 38148 function next() { 38149 var fn = pending.shift(); 38150 if (fn) { 38151 fn(next); 38152 } 38153 } 38154 38155 return function(fn) { 38156 pending.push(fn); 38157 if (pending.length == 1) next(); 38158 }; 38159 })(); 38160 38161 /** 38162 * (Internal) Applies css properties to an element, similar to the jQuery 38163 * css method. 38164 * 38165 * While this helper does assist with vendor prefixed property names, it 38166 * does not perform any manipulation of values prior to setting styles. 38167 */ 38168 38169 var css = (function() { 38170 var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ], 38171 cssProps = {}; 38172 38173 function camelCase(string) { 38174 return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { 38175 return letter.toUpperCase(); 38176 }); 38177 } 38178 38179 function getVendorProp(name) { 38180 var style = document.body.style; 38181 if (name in style) return name; 38182 38183 var i = cssPrefixes.length, 38184 capName = name.charAt(0).toUpperCase() + name.slice(1), 38185 vendorName; 38186 while (i--) { 38187 vendorName = cssPrefixes[i] + capName; 38188 if (vendorName in style) return vendorName; 38189 } 38190 38191 return name; 38192 } 38193 38194 function getStyleProp(name) { 38195 name = camelCase(name); 38196 return cssProps[name] || (cssProps[name] = getVendorProp(name)); 38197 } 38198 38199 function applyCss(element, prop, value) { 38200 prop = getStyleProp(prop); 38201 element.style[prop] = value; 38202 } 38203 38204 return function(element, properties) { 38205 var args = arguments, 38206 prop, 38207 value; 38208 38209 if (args.length == 2) { 38210 for (prop in properties) { 38211 value = properties[prop]; 38212 if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); 38213 } 38214 } else {
38215 applyCss(element, args[1], args[2]); 38216 } 38217 } 38218 })(); 38219 38220 /** 38221 * (Internal) Determines if an element or space separated list of class names contains a class name. 38222 */ 38223 38224 function hasClass(element, name) { 38225 var list = typeof element == 'string' ? element : classList(element); 38226 return list.indexOf(' ' + name + ' ') >= 0; 38227 } 38228 38229 /** 38230 * (Internal) Adds a class to an element. 38231 */ 38232 38233 function addClass(element, name) { 38234 var oldList = classList(element), 38235 newList = oldList + name; 38236 38237 if (hasClass(oldList, name)) return; 38238 38239 // Trim the opening space. 38240 element.className = newList.substring(1); 38241 } 38242 38243 /** 38244 * (Internal) Removes a class from an element. 38245 */ 38246 38247 function removeClass(element, name) { 38248 var oldList = classList(element), 38249 newList; 38250 38251 if (!hasClass(element, name)) return; 38252 38253 // Replace the class name. 38254 newList = oldList.replace(' ' + name + ' ', ' '); 38255 38256 // Trim the opening and closing spaces. 38257 element.className = newList.substring(1, newList.length - 1); 38258 } 38259 38260 /** 38261 * (Internal) Gets a space separated list of the class names on the element. 38262 * The list is wrapped with a single space on each end to facilitate finding 38263 * matches within the list. 38264 */ 38265 38266 function classList(element) { 38267 return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' '); 38268 } 38269 38270 /** 38271 * (Internal) Removes an element from the DOM. 38272 */ 38273 38274 function removeElement(element) { 38275 element && element.parentNode && element.parentNode.removeChild(element); 38276 } 38277 38278 return NProgress; 38279}); 38280(function() { 38281 App.Widgets.ProgressBar = (function() { 38282 function ProgressBar() {} 38283 38284 ProgressBar.prototype.initialize = function() { 38285 this.bindEvents(); 38286 return this.configProgress(); 38287 }; 38288 38289 ProgressBar.prototype.bindEvents = function() { 38290 App.events.subscribe('app:progress:start', this.startProgress); 38291 return App.events.subscribe('app:progress:finish', this.finishProgress); 38292 }; 38293 38294 ProgressBar.prototype.configProgress = function() { 38295 return NProgress.configure({ 38296 ease: 'ease', 38297 trickleSpeed: 100 38298 }); 38299 }; 38300 38301 ProgressBar.prototype.startProgress = function() { 38302 return NProgress.start(); 38303 }; 38304 38305 ProgressBar.prototype.finishProgress = function() { 38306 return NProgress.done(); 38307 }; 38308 38309 return ProgressBar; 38310 38311 })(); 38312 38313}).call(this); 38314(function() { 38315 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 38316 38317 App.Widgets.ReportContent = (function() { 38318 function ReportContent() { 38319 this.sendReport = bind(this.sendReport, this); 38320 } 38321 38322 ReportContent.prototype.initialize = function() { 38323 this.$el = $('#modal-report-content'); 38324 return this.bindEvents(); 38325 }; 38326 38327 ReportContent.prototype.bindEvents = function() { 38328 $('.report-content').on('click', (function(_this) { 38329 return function(e) { 38330 return _this.btn = e.target; 38331 }; 38332 })(this)); 38333 return this.$el.find('#report-content').on('click', this.sendReport); 38334 }; 38335 38336 ReportContent.prototype.sendReport = function() { 38337 var data; 38338 data = { 38339 report: { 38340 category: this.$el.find('#report-category').val(), 38341 report: this.$el.find('#report-content-message').val(), 38342 content_type: $(this.btn).data('report-type'), 38343 content_id: $(this.btn).data('report-id') 38344 } 38345 }; 38346 return $.post("/api/internal/content_reports", data, (function(_this) { 38347 return function(response) { 38348 if (response.success) { 38349 App.events.publish("app:notification:flash:success", response.message); 38350 return _this.$el.makeMeModal('close'); 38351 } else { 38352 return App.events.publish("app:notification:flash:error", response.message); 38353 } 38354 }; 38355 })(this)); 38356 }; 38357 38358 return ReportContent; 38359 38360 })(); 38361 38362}).call(this); 38363(function() { 38364 Cookies.set('screen_width', window.innerWidth); 38365 38366}).call(this); 38367(function() { 38368 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 38369 38370 App.Widgets.SearchItems = (function() { 38371 function SearchItems() { 38372 this.onSearchFormSubmit = bind(this.onSearchFormSubmit, this); 38373 this.onFieldClick = bind(this.onFieldClick, this); 38374 this.onLostFocus = bind(this.onLostFocus, this); 38375 this.onFieldFocus = bind(this.onFieldFocus, this); 38376 this.onSearchResults = bind(this.onSearchResults, this); 38377 this.updateActiveElementOnHover = bind(this.updateActiveElementOnHover, this); 38378 this.onSearchResultsHover = bind(this.onSearchResultsHover, this); 38379 this.onArrowNavigation = bind(this.onArrowNavigation, this); 38380 this.onSearchFieldChange = bind(this.onSearchFieldChange, this); 38381 this.updateLastKeyPressed = bind(this.updateLastKeyPressed, this); 38382 } 38383 38384 SearchItems.prototype.endPoint = '/api/internal/items/live_search.json'; 38385 38386 SearchItems.prototype.lastKeyPressed = null; 38387 38388 SearchItems.prototype.activeElementIndex = null; 38389 38390 SearchItems.prototype.enterKeyCode = 13; 38391 38392 SearchItems.prototype.leftArrowKeyCode = 37; 38393 38394 SearchItems.prototype.upArrowKeyCode = 38; 38395 38396 SearchItems.prototype.rightArrowKeyCode = 39; 38397 38398 SearchItems.prototype.downArrowKeyCode = 40; 38399 38400 SearchItems.prototype.formerKeywords = ''; 38401 38402 SearchItems.prototype.options = { 38403 threshold: 200, 38404 minLength: 1, 38405 animationSpeed: 100 38406 }; 38407 38408 SearchItems.prototype.initialize = function() { 38409 var onSearchFieldChangeThrottled; 38410 this.$productListWrapper = $('#products-list .content-box-wrapper'); 38411 this.elements = { 38412 $searchContainer: $('.site-search'), 38413 $searchSuggestions: $('.js-search-suggestions'), 38414 $searchField: $('.js-search-suggestion-trigger'), 38415 $searchResultsContainer: $('.js-search-results-container'), 38416 $searchResults: $('.js-search-results'), 38417 $queries: $('.js-search-top-queries'), 38418 $searchForm: $('#search-form') 38419 }; 38420 this.elements.$searchSuggestions.hide().removeClass('is-hidden'); 38421 this.elements.$searchResultsContainer.hide().removeClass('is-hidden'); 38422 onSearchFieldChangeThrottled = _.throttle(this.onSearchFieldChange, this.options.threshold); 38423 this.elements.$searchField.on('keydown', this.updateLastKeyPressed); 38424 this.elements.$searchField.on('keyup', onSearchFieldChangeThrottled); 38425 this.elements.$searchField.on('focus', this.onFieldFocus); 38426 this.elements.$searchField.on('click', this.onFieldClick); 38427 this.elements.$searchSuggestions.hideOnOutsideClick(this.onLostFocus); 38428 this.elements.$searchForm.submit(this.onSearchFormSubmit); 38429 return App.events.subscribe('browser:filters:changed', (function(_this) { 38430 return function() { 38431 return _this.hideSuggestions(); 38432 }; 38433 })(this)); 38434 }; 38435 38436 SearchItems.prototype.updateLastKeyPressed = function(e) { 38437 var $activeElementLink, newKeyword; 38438 this.lastKeyPressed = e.keyCode; 38439 if (this.lastKeyPressed === this.upArrowKeyCode || this.lastKeyPressed === this.downArrowKeyCode) { 38440 e.preventDefault(); 38441 this.onArrowNavigation(); 38442 } 38443 if (this.lastKeyPressed === this.enterKeyCode && this.elements.$searchResults.find('li.is-active').length !== 0) { 38444 e.preventDefault(); 38445 $activeElementLink = this.elements.$searchResults.find('li.is-active a'); 38446 if (App.Backbone.Routers.ItemsSearch.instance) { 38447 newKeyword = $activeElementLink.data('keyword'); 38448 return App.Backbone.Routers.ItemsSearch.instance.applyFilter('keywords', newKeyword, { 38449 reload: true 38450 }); 38451 } else { 38452 return window.location = $activeElementLink.attr('href'); 38453 } 38454 } 38455 }; 38456 38457 SearchItems.prototype.search = function(query) { 38458 this.elements.$searchContainer.find('.js-search-submit').addClass('is-loading'); 38459 this.formerKeywords = query; 38460 return $.get(this.endPoint, { 38461 query: query 38462 }, this.onSearchResults); 38463 }; 38464 38465 SearchItems.prototype.showSuggestions = function() { 38466 if (this.elements.$searchField.val().length > 0) { 38467 this.showResults(); 38468 } else { 38469 this.showQueries(); 38470 } 38471 return this.elements.$searchSuggestions.fadeIn(this.options.animationSpeed); 38472 }; 38473 38474 SearchItems.prototype.hideSuggestions = function() { 38475 return this.elements.$searchSuggestions.fadeOut(this.options.animationSpeed); 38476 }; 38477 38478 SearchItems.prototype.showQueries = function() { 38479 this.elements.$queries.show(); 38480 return this.elements.$searchResultsContainer.hide(); 38481 }; 38482 38483 SearchItems.prototype.showResults = function() { 38484 this.elements.$queries.hide(); 38485 return this.elements.$searchResultsContainer.show(); 38486 }; 38487 38488 SearchItems.prototype.onSearchFieldChange = function(e) { 38489 var keywords; 38490 keywords = this.elements.$searchField.val(); 38491 if (_.contains([this.leftArrowKeyCode, this.upArrowKeyCode, this.rightArrowKeyCode, this.downArrowKeyCode], e.keyCode)) { 38492 return; 38493 } 38494 if (this.formerKeywords === keywords) { 38495 return; 38496 } 38497 if (keywords.length >= this.options.minLength) { 38498 return this.search(keywords); 38499 } else if (keywords.length === 0) { 38500 this.formerKeywords = ''; 38501 return this.showQueries(); 38502 } else { 38503 return this.hideSuggestions(); 38504 } 38505 }; 38506 38507 SearchItems.prototype.onArrowNavigation = function() { 38508 this.$activeElement = this.elements.$searchResults.find('li.is-active'); 38509 this.activeElementIndex = this.$activeElement.index(); 38510 this.lastElementIndex = this.elements.$searchResults.find('li').length - 1; 38511 if (this.lastKeyPressed === this.downArrowKeyCode) { 38512 this.activeElementIndex += 1; 38513 } else if (this.$activeElement.length === 0) { 38514 this.activeElementIndex = this.lastElementIndex; 38515 } else { 38516 this.activeElementIndex -= 1; 38517 } 38518 return this.updateActiveElement(); 38519 }; 38520 38521 SearchItems.prototype.onSearchResultsHover = function() { 38522 return this.elements.$searchResults.find('li').on('mouseenter', this.updateActiveElementOnHover); 38523 }; 38524 38525 SearchItems.prototype.updateActiveElementOnHover = function(e) { 38526 this.activeElementIndex = $(e.currentTarget).index(); 38527 return this.updateActiveElement(); 38528 }; 38529 38530 SearchItems.prototype.updateActiveElement = function() { 38531 this.elements.$searchResults.find('li').removeClass('is-active'); 38532 if (this.activeElementIndex == null) { 38533 return; 38534 } 38535 return $(this.elements.$searchResults.find('li')[this.activeElementIndex]).addClass('is-active'); 38536 }; 38537 38538 SearchItems.prototype.onSearchResults = function(phrases) { 38539 var $container, pattern, searchQuery; 38540 this.elements.$searchContainer.find('.js-search-submit').removeClass('is-loading'); 38541 if (_.size(phrases) > 0 && this.lastKeyPressed !== this.enterKeyCode) { 38542 this.showSuggestions(); 38543 } else { 38544 this.hideSuggestions(); 38545 } 38546 searchQuery = this.elements.$searchForm.find('.js-search-suggestion-trigger').val(); 38547 searchQuery = searchQuery.replace(/[ \t]+$/, ""); 38548 pattern = new RegExp('(' + searchQuery + ')', 'gi'); 38549 $container = this.elements.$searchSuggestions.find('.js-search-results'); 38550 $container.html('');
38551 _(phrases).forEach(function(phraseDetails) { 38552 var counts, phrase, phraseHtml, view, viewData; 38553 phrase = phraseDetails[0], counts = phraseDetails[1]; 38554 phraseHtml = phrase.replace(pattern, '<strong>$&</strong>'); 38555 viewData = { 38556 suggestion: phrase, 38557 suggestionHtml: phraseHtml, 38558 cgCount: counts.cg, 38559 lowpolyCount: counts.lowpoly, 38560 total: counts.total, 38561 thumbnailUrl: counts.thumbnailUrl, 38562 abGroup: counts.abGroup 38563 }; 38564 view = new App.Backbone.Views.SearchSuggestionViewV2({ 38565 data: viewData 38566 }); 38567 return view.render().$el.appendTo($container); 38568 }); 38569 return this.onSearchResultsHover(); 38570 }; 38571 38572 SearchItems.prototype.onFieldFocus = function() { 38573 if (this.elements.$searchField.val().length === 0) { 38574 return this.showSuggestions(); 38575 } 38576 }; 38577 38578 SearchItems.prototype.onLostFocus = function(e) { 38579 if ($(e.target).hasClass('js-search-suggestion-trigger')) { 38580 return; 38581 } 38582 return this.hideSuggestions(); 38583 }; 38584 38585 SearchItems.prototype.onFieldClick = function() { 38586 this.activeElementIndex = null; 38587 return this.updateActiveElement(); 38588 }; 38589 38590 SearchItems.prototype.onSearchFormSubmit = function(e) { 38591 if (this.$productListWrapper.length !== 0) { 38592 return this.$productListWrapper.addClass('is-updating-with-spinner spinner--top is-fixed'); 38593 } 38594 }; 38595 38596 return SearchItems; 38597 38598 })(); 38599 38600}).call(this); 38601(function() { 38602 App.Widgets.StoreCreditsInfoTooltip = (function() { 38603 function StoreCreditsInfoTooltip() {} 38604 38605 StoreCreditsInfoTooltip.prototype.initialize = function() { 38606 this.$tooltip = $('.js-new-store-credits-info-tooltip'); 38607 if (this.$tooltip.length > 0) { 38608 return this.initTooltip(); 38609 } 38610 }; 38611 38612 StoreCreditsInfoTooltip.prototype.initTooltip = function() { 38613 var content, storeCreditsComming; 38614 storeCreditsComming = this.$tooltip.data('store-credits-earned'); 38615 content = "You will get " + storeCreditsComming + " CGTrader credits if you complete this purchase. <br/>\n<a href=\"https://www.cgtrader.com/pages/cgtrader-loyalty-discounts\" target='_blank'>More information</a>"; 38616 return this.$tooltip.tooltipster({ 38617 theme: 'tooltip--light tooltip--popover u-text-center', 38618 animation: 'grow', 38619 contentAsHTML: true, 38620 content: content, 38621 interactive: true, 38622 maxWidth: 220 38623 }); 38624 }; 38625 38626 return StoreCreditsInfoTooltip; 38627 38628 })(); 38629 38630}).call(this); 38631(function() { 38632 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 38633 38634 App.Widgets.TipForDesigner = (function() { 38635 function TipForDesigner() { 38636 this.closeTip = bind(this.closeTip, this); 38637 } 38638 38639 TipForDesigner.prototype.initialize = function() { 38640 if ((typeof BarsOrdering !== "undefined" && BarsOrdering !== null) && BarsOrdering('tipForDesigner')) { 38641 return this.showNotificationBar(); 38642 } 38643 }; 38644 38645 TipForDesigner.prototype.showNotificationBar = function() { 38646 this.$notificationBar = $(JST["tip_for_designer/notification_bar"]({ 38647 body: App.config.tipForDesigner 38648 })); 38649 $('body').prepend(this.$notificationBar); 38650 return this.$notificationBar.find('.js-tip-close').on('click', this.closeTip); 38651 }; 38652 38653 TipForDesigner.prototype.closeTip = function() { 38654 return this.$notificationBar.hide(); 38655 }; 38656 38657 return TipForDesigner; 38658 38659 })(); 38660 38661}).call(this); 38662(function() { 38663 App.Widgets.TopNavigation = (function() { 38664 function TopNavigation() {} 38665 38666 TopNavigation.prototype.initialize = function() { 38667 if (!($("input[autofocus]").length > 0)) { 38668 return this.autoFocusSearch(); 38669 } 38670 }; 38671 38672 TopNavigation.prototype.autoFocusSearch = function() { 38673 var currentValue; 38674 if ($('.site-search .site-search__field').length > 1) { 38675 return; 38676 } 38677 currentValue = $('.site-search .site-search__field').val(); 38678 return $('.site-search input').focus().val('').val(currentValue); 38679 }; 38680 38681 return TopNavigation; 38682 38683 })(); 38684 38685}).call(this); 38686(function() { 38687 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 38688 38689 App.Widgets.TranslationsNotice = (function() { 38690 function TranslationsNotice() { 38691 this.handleClose = bind(this.handleClose, this); 38692 this.show = bind(this.show, this); 38693 this.reposition = bind(this.reposition, this); 38694 } 38695 38696 TranslationsNotice.prototype.initialize = function() { 38697 $('.notice').on('click', (function(_this) { 38698 return function() { 38699 return setTimeout(_this.reposition, 50); 38700 }; 38701 })(this)); 38702 if (I18n.locale !== I18n.defaultLocale) { 38703 this.show(); 38704 return this.reposition(); 38705 } 38706 }; 38707 38708 TranslationsNotice.prototype.reposition = function() { 38709 var highestNoticeHeight; 38710 if (!this.$bar) { 38711 return; 38712 }
38713 highestNoticeHeight = 0; 38714 if (this.bottom == null) { 38715 this.bottom = 0; 38716 } 38717 $('.notice:visible').not('.notice-translation').each((function(_this) { 38718 return function(index, el) { 38719 var height; 38720 height = $(el).outerHeight(); 38721 highestNoticeHeight = Math.max(height, highestNoticeHeight); 38722 return _this.bottom = parseInt($(el).css('bottom').replace('px', ''), 10); 38723 }; 38724 })(this)); 38725 if ($('.actions-bar').css('position') === 'fixed') { 38726 this.bottom += 42; 38727 } 38728 return this.$bar.css('bottom', highestNoticeHeight + this.bottom); 38729 }; 38730 38731 TranslationsNotice.prototype.show = function() { 38732 var href; 38733 if ((typeof localStorage !== "undefined" && localStorage !== null ? localStorage.getItem('notice-translation') : void 0) === 'closed') { 38734 return; 38735 } 38736 this.$bar = $(JST["translations_notice/notification_bar"]()); 38737 href = $('link[hreflang="en"]').attr('href') || '/'; 38738 this.$bar.find('a').attr('href', href); 38739 $('body').append(this.$bar); 38740 return this.$bar.find('.close-notice').on('click', this.handleClose); 38741 }; 38742 38743 TranslationsNotice.prototype.handleClose = function() { 38744 this.$bar.remove(); 38745 return typeof localStorage !== "undefined" && localStorage !== null ? localStorage.setItem('notice-translation', 'closed') : void 0; 38746 }; 38747 38748 return TranslationsNotice; 38749 38750 })(); 38751 38752}).call(this); 38753(function() { 38754 App.Widgets.UserSubscriptionsModal = (function() { 38755 function UserSubscriptionsModal() {} 38756 38757 UserSubscriptionsModal.prototype.initialize = function() { 38758 if (App.config.showUserSubscriptionsModal) { 38759 return this.showUserSubscriptionsModal(); 38760 } 38761 }; 38762 38763 UserSubscriptionsModal.prototype.showUserSubscriptionsModal = function() { 38764 if (this.userSubscriptionsModal == null) { 38765 this.userSubscriptionsModal = new App.Backbone.Views.Modals.UserSubscriptionsView(); 38766 } 38767 return this.userSubscriptionsModal.render(); 38768 }; 38769 38770 return UserSubscriptionsModal; 38771 38772 })(); 38773 38774}).call(this); 38775(function() { 38776 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 38777 38778 App.Widgets.V2WishLists = (function() { 38779 function V2WishLists() { 38780 this.wishListId = bind(this.wishListId, this); 38781 this.createDefaultWishList = bind(this.createDefaultWishList, this); 38782 this.onCreateListItemFailure = bind(this.onCreateListItemFailure, this); 38783 this.addToFirstWishList = bind(this.addToFirstWishList, this); 38784 this.addToWishList = bind(this.addToWishList, this); 38785 this.onAddClick = bind(this.onAddClick, this); 38786 } 38787 38788 V2WishLists.prototype.initialize = function() { 38789 var button, i, len, ref, results; 38790 this.$addToWishListButtons = $('.js-add-to-wish-list'); 38791 ref = this.$addToWishListButtons; 38792 results = []; 38793 for (i = 0, len = ref.length; i < len; i++) { 38794 button = ref[i]; 38795 results.push((function(_this) { 38796 return function(button) { 38797 var buttonInstance; 38798 buttonInstance = $(button); 38799 return buttonInstance.on("click", function() { 38800 return _this.onAddClick(buttonInstance); 38801 }); 38802 }; 38803 })(this)(button)); 38804 } 38805 return results; 38806 }; 38807 38808 V2WishLists.prototype.onAddClick = function(buttonInstance) { 38809 if (!App.config.userSignedIn) { 38810 return; 38811 } 38812 if (this.wishLists == null) { 38813 this.wishLists = new App.Backbone.Collections.WishListsCollection(); 38814 } 38815 return this.wishLists.fetch({ 38816 reset: true, 38817 success: (function(_this) { 38818 return function(collection, response) { 38819 return _this.addToWishList(buttonInstance, collection, response); 38820 }; 38821 })(this) 38822 }); 38823 }; 38824 38825 V2WishLists.prototype.addToWishList = function(buttonInstance, collection, response) { 38826 buttonInstance.closest('.cgt-item-card').addClass('is-updating'); 38827 buttonInstance.closest('.js-cart-item').addClass('is-updating'); 38828 if (response.data && response.data.id) { 38829 return this.addToFirstWishList(buttonInstance); 38830 } else { 38831 return this.createDefaultWishList(); 38832 } 38833 }; 38834 38835 V2WishLists.prototype.addToFirstWishList = function(buttonInstance) { 38836 var itemId, wishListItem; 38837 itemId = buttonInstance.data('item-id'); 38838 wishListItem = new App.Backbone.Models.WishListItem({ 38839 data: { 38840 type: 'wishListItems', 38841 attributes: { 38842 wish_list_id: this.wishListId(), 38843 item_id: itemId 38844 } 38845 } 38846 }); 38847 return wishListItem.save({}, { 38848 error: (function(_this) { 38849 return function(model, response) { 38850 return _this.onCreateListItemFailure(model, response, buttonInstance); 38851 }; 38852 })(this), 38853 success: (function(_this) { 38854 return function() { 38855 return _this.onCreateWishListItemSuccess(buttonInstance); 38856 }; 38857 })(this) 38858 }); 38859 }; 38860 38861 V2WishLists.prototype.onCreateWishListItemSuccess = function(buttonInstance) { 38862 var path; 38863 path = "/api/internal/" + (buttonInstance.data('item-type')) + "/items/" + (buttonInstance.data('item-id')) + "/cart_items/" + (buttonInstance.data('cart-item-id')); 38864 return $.ajax({ 38865 url: path, 38866 type: 'DELETE', 38867 success: function() { 38868 App.events.publish("app:notification:flash:success", 'Model was successfully added to wishlist!'); 38869 return window.location.reload(); 38870 } 38871 }); 38872 }; 38873 38874 V2WishLists.prototype.onCreateListItemFailure = function(model, response, buttonInstance) { 38875 App.events.publish("app:notification:flash:error", this.parseErrorMessages(response.responseJSON.errors)); 38876 return buttonInstance.closest('.cgt-item-card').removeClass('is-updating'); 38877 }; 38878 38879 V2WishLists.prototype.createDefaultWishList = function() { 38880 return this.wishLists.create({ 38881 data: { 38882 type: 'wishLists', 38883 attributes: { 38884 title: 'Default' 38885 } 38886 } 38887 }, { 38888 success: this.addToFirstWishList 38889 }); 38890 }; 38891 38892 V2WishLists.prototype.wishListId = function() { 38893 return this.wishLists.first().id || this.wishLists.first().attributes.data.id; 38894 }; 38895 38896 V2WishLists.prototype.parseErrorMessages = function(errors) { 38897 var attribute, error, errorMessages, parts; 38898 errorMessages = []; 38899 for (error in errors) { 38900 parts = errors[error].source.pointer.split('/'); 38901 attribute = parts[parts.length - 1]; 38902 errorMessages.push(attribute + " " + errors[error].detail); 38903 } 38904 return errorMessages.join('.'); 38905 }; 38906 38907 return V2WishLists; 38908 38909 })(); 38910 38911}).call(this); 38912(function() { 38913 App.Widgets.VatTaxTooltip = (function() { 38914 function VatTaxTooltip() {} 38915 38916 VatTaxTooltip.prototype.initialize = function() { 38917 this.$tooltip = $('.js-vat-tax-tooltip'); 38918 if (this.$tooltip.length > 0) { 38919 return this.initTooltip(); 38920 } 38921 }; 38922 38923 VatTaxTooltip.prototype.initTooltip = function() { 38924 var content; 38925 content = "Value Added Tax (VAT), also known as Sales tax or Goods <br/>\nand services tax (GST), is a tax applied at the point of sale <br/>\nto the end buyer and paid to the government of the buyerâs country."; 38926 return this.$tooltip.tooltipster({ 38927 theme: 'tooltip--light tooltip--popover u-text-center', 38928 animation: 'grow', 38929 contentAsHTML: true, 38930 content: content, 38931 position: 'left', 38932 interactive: true, 38933 maxWidth: 400 38934 }); 38935 }; 38936 38937 return VatTaxTooltip; 38938 38939 })(); 38940 38941}).call(this); 38942(function() { 38943 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 38944 38945 App.Widgets.WishLists = (function() { 38946 function WishLists() { 38947 this.wishListId = bind(this.wishListId, this); 38948 this.createDefaultWishList = bind(this.createDefaultWishList, this); 38949 this.onCreateListItemFailure = bind(this.onCreateListItemFailure, this); 38950 this.onCreateWishListItemSuccess = bind(this.onCreateWishListItemSuccess, this); 38951 this.addToFirstWishList = bind(this.addToFirstWishList, this); 38952 this.addToWishList = bind(this.addToWishList, this); 38953 this.onRemoveClick = bind(this.onRemoveClick, this); 38954 this.onAddClick = bind(this.onAddClick, this); 38955 } 38956 38957 WishLists.prototype.initialize = function() {
38958 this.$addToWishListButton = $('.js-add-to-wish-list'); 38959 this.$removeFromWishListButton = $('.js-remove-from-wish-list'); 38960 this.$removeFromWishListButton.on('click', this.onRemoveClick); 38961 this.$addToWishListButton.on('click', this.onAddClick); 38962 if (gon.in_the_wish_list) { 38963 return this.$removeFromWishListButton.removeClass('is-hidden'); 38964 } else { 38965 return this.$addToWishListButton.removeClass('is-hidden'); 38966 } 38967 }; 38968 38969 WishLists.prototype.onAddClick = function() { 38970 if (!App.config.userSignedIn) { 38971 return; 38972 } 38973 if (this.wishLists == null) { 38974 this.wishLists = new App.Backbone.Collections.WishListsCollection(); 38975 } 38976 return this.wishLists.fetch({ 38977 reset: true, 38978 success: this.addToWishList 38979 }); 38980 }; 38981 38982 WishLists.prototype.onRemoveClick = function() { 38983 if (!App.config.userSignedIn) { 38984 return; 38985 } 38986 return $.ajax({ 38987 url: "/api/internal/wish-lists/" + (this.$removeFromWishListButton.data('wish-list-id')) + "/items/0", 38988 type: 'DELETE', 38989 data: { 38990 item_ids: this.$removeFromWishListButton.data('item-id') 38991 }, 38992 success: (function(_this) { 38993 return function() { 38994 App.events.publish("app:notification:flash:success", 'Model was successfully removed from wishlist!'); 38995 return _this.updateRemoveLinks(); 38996 }; 38997 })(this) 38998 }); 38999 }; 39000 39001 WishLists.prototype.addToWishList = function(collection, response) { 39002 if (response.data.length > 0) { 39003 return this.addToFirstWishList(); 39004 } else { 39005 return this.createDefaultWishList(); 39006 } 39007 }; 39008 39009 WishLists.prototype.addToFirstWishList = function() { 39010 var itemId, wishListItem; 39011 itemId = this.$addToWishListButton.data('item-id'); 39012 wishListItem = new App.Backbone.Models.WishListItem({ 39013 data: { 39014 type: 'wishListItems', 39015 attributes: { 39016 wish_list_id: this.wishListId(), 39017 item_id: itemId 39018 } 39019 } 39020 }); 39021 return wishListItem.save({}, { 39022 success: this.onCreateWishListItemSuccess, 39023 error: this.onCreateListItemFailure 39024 }); 39025 }; 39026 39027 WishLists.prototype.onCreateWishListItemSuccess = function() { 39028 this.$removeFromWishListButton.data('wish-list-id', this.wishListId()); 39029 App.events.publish("app:notification:flash:success", 'Model was successfully added to wishlist!'); 39030 return this.updateCreateLinks(); 39031 }; 39032 39033 WishLists.prototype.onCreateListItemFailure = function(model, response) { 39034 return App.events.publish("app:notification:flash:error", this.parseErrorMessages(response.responseJSON.errors)); 39035 }; 39036 39037 WishLists.prototype.updateCreateLinks = function() { 39038 this.$addToWishListButton.addClass('is-hidden'); 39039 return this.$removeFromWishListButton.removeClass('is-hidden'); 39040 }; 39041 39042 WishLists.prototype.updateRemoveLinks = function() { 39043 this.$removeFromWishListButton.addClass('is-hidden'); 39044 return this.$addToWishListButton.removeClass('is-hidden'); 39045 }; 39046 39047 WishLists.prototype.createDefaultWishList = function() { 39048 return this.wishLists.create({ 39049 data: { 39050 type: 'wishLists', 39051 attributes: { 39052 title: 'Default' 39053 } 39054 } 39055 }, { 39056 success: this.addToFirstWishList 39057 }); 39058 }; 39059 39060 WishLists.prototype.wishListId = function() { 39061 return this.wishLists.first().id || this.wishLists.first().attributes.data.id; 39062 }; 39063 39064 WishLists.prototype.parseErrorMessages = function(errors) { 39065 var attribute, error, errorMessages, parts; 39066 errorMessages = []; 39067 for (error in errors) { 39068 parts = errors[error].source.pointer.split('/'); 39069 attribute = parts[parts.length - 1]; 39070 errorMessages.push(attribute.capitalizeFirst + " " + errors[error].detail); 39071 } 39072 return errorMessages.join('.'); 39073 }; 39074 39075 return WishLists; 39076 39077 })(); 39078 39079}).call(this); 39080(function() { 39081 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 39082 hasProp = {}.hasOwnProperty; 39083 39084 App.Pages.ApiLandingPageDevelopers = (function(superClass) { 39085 extend(ApiLandingPageDevelopers, superClass); 39086 39087 function ApiLandingPageDevelopers() { 39088 return ApiLandingPageDevelopers.__super__.constructor.apply(this, arguments); 39089 } 39090 39091 ApiLandingPageDevelopers.prototype.initialize = function() { 39092 this.$form = $('#api-access-request'); 39093 return this.initValidation(); 39094 }; 39095 39096 ApiLandingPageDevelopers.prototype.validationSettings = function() { 39097 return { 39098 rules: { 39099 'api_access_request[name]': { 39100 required: true 39101 }, 39102 'api_access_request[email]': { 39103 required: true, 39104 email: true 39105 }, 39106 'api_access_request[use_case]': { 39107 required: true 39108 } 39109 } 39110 }; 39111 }; 39112 39113 ApiLandingPageDevelopers.prototype.initValidation = function() { 39114 return this.$form.validate(this.validationSettings()); 39115 }; 39116 39117 return ApiLandingPageDevelopers; 39118 39119 })(App.Core.Page); 39120 39121}).call(this); 39122(function() { 39123 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 39124 hasProp = {}.hasOwnProperty; 39125 39126 App.Pages.ArsenalIndex = (function(superClass) { 39127 extend(ArsenalIndex, superClass); 39128 39129 function ArsenalIndex() { 39130 return ArsenalIndex.__super__.constructor.apply(this, arguments); 39131 } 39132 39133 ArsenalIndex.prototype.initialize = function() { 39134 this.bindEvents(); 39135 return $(document).ready((function(_this) { 39136 return function() { 39137 var hash, i, len, results, sectionHashes; 39138 sectionHashes = [ 39139 { 39140 link: '#lets-talk', 39141 anchor: '#lets-talk' 39142 }, { 39143 link: '#arsenal-pricing', 39144 anchor: '#arsenal-pricing-anchor' 39145 }, { 39146 link: '#fatboy', 39147 anchor: '#fatboy-anchor' 39148 }, { 39149 link: '#garten-und-freizeit', 39150 anchor: '#garten-und-freizeit-anchor' 39151 } 39152 ]; 39153 results = []; 39154 for (i = 0, len = sectionHashes.length; i < len; i++) { 39155 hash = sectionHashes[i]; 39156 if (window.location.hash === hash.link) { 39157 results.push(_this.onLinkClick(null, 2000, hash.anchor)); 39158 } else { 39159 results.push(void 0); 39160 } 39161 } 39162 return results; 39163 }; 39164 })(this)); 39165 }; 39166 39167 ArsenalIndex.prototype.bindEvents = function() { 39168 return $('.js-arsenal-scroll').on('click', (function(_this) { 39169 return function(e) { 39170 return _this.onLinkClick(e, 2000, '#lets-talk'); 39171 }; 39172 })(this)); 39173 }; 39174 39175 ArsenalIndex.prototype.onLinkClick = function(e, timeout, target) { 39176 if (e) { 39177 e.preventDefault(); 39178 } 39179 return $([document.documentElement, document.body]).animate({ 39180 scrollTop: $(target).offset().top 39181 }, timeout); 39182 }; 39183 39184 return ArsenalIndex; 39185 39186 })(App.Core.Page); 39187 39188}).call(this); 39189/*!
vendor: 5,735 bytes, lines 39190-39402
39190 * fancyBox - jQuery Plugin 39191 * version: 2.1.5 (Fri, 14 Jun 2013) 39192 * @requires jQuery v1.6 or later 39193 * 39194 * Examples at http://fancyapps.com/fancybox/ 39195 * License: www.fancyapps.com/fancybox/#license 39196 * 39197 * Copyright 2012 Janis Skarnelis - [email protected] 39198 * 39199 */ 39200 39201 39202(function (window, document, $, undefined) { 39203 "use strict"; 39204 39205 var H = $("html"), 39206 W = $(window), 39207 D = $(document), 39208 F = $.fancybox = function () { 39209 F.open.apply( this, arguments ); 39210 }, 39211 IE = navigator.userAgent.match(/msie/i), 39212 didUpdate = null, 39213 isTouch = document.createTouch !== undefined, 39214 39215 isQuery = function(obj) { 39216 return obj && obj.hasOwnProperty && obj instanceof $; 39217 }, 39218 isString = function(str) { 39219 return str && $.type(str) === "string"; 39220 }, 39221 isPercentage = function(str) { 39222 return isString(str) && str.indexOf('%') > 0; 39223 }, 39224 isScrollable = function(el) { 39225 return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight))); 39226 }, 39227 getScalar = function(orig, dim) { 39228 var value = parseInt(orig, 10) || 0; 39229 39230 if (dim && isPercentage(orig)) { 39231 value = F.getViewport()[ dim ] / 100 * value; 39232 } 39233 39234 return Math.ceil(value); 39235 }, 39236 getValue = function(value, dim) { 39237 return getScalar(value, dim) + 'px'; 39238 }; 39239 39240 $.extend(F, { 39241 // The current version of fancyBox 39242 version: '2.1.5', 39243 39244 defaults: { 39245 padding : 15, 39246 margin : 20, 39247 39248 width : 800, 39249 height : 600, 39250 minWidth : 100, 39251 minHeight : 100, 39252 maxWidth : 9999, 39253 maxHeight : 9999, 39254 pixelRatio: 1, // Set to 2 for retina display support 39255 39256 autoSize : true, 39257 autoHeight : false, 39258 autoWidth : false, 39259 39260 autoResize : true, 39261 autoCenter : !isTouch, 39262 fitToView : true, 39263 aspectRatio : false, 39264 topRatio : 0.5, 39265 leftRatio : 0.5, 39266 39267 scrolling : 'auto', // 'auto', 'yes' or 'no' 39268 wrapCSS : '', 39269 39270 arrows : true, 39271 closeBtn : true, 39272 closeClick : false, 39273 nextClick : false, 39274 mouseWheel : true, 39275 autoPlay : false, 39276 playSpeed : 3000, 39277 preload : 3, 39278 modal : false, 39279 loop : true, 39280 39281 ajax : { 39282 dataType : 'html', 39283 headers : { 'X-fancyBox': true } 39284 }, 39285 iframe : { 39286 scrolling : 'auto', 39287 preload : true 39288 }, 39289 swf : { 39290 wmode: 'transparent', 39291 allowfullscreen : 'true', 39292 allowscriptaccess : 'always' 39293 }, 39294 39295 keys : { 39296 next : { 39297 13 : 'left', // enter 39298 34 : 'up', // page down 39299 39 : 'left', // right arrow 39300 40 : 'up' // down arrow 39301 }, 39302 prev : { 39303 8 : 'right', // backspace 39304 33 : 'down', // page up 39305 37 : 'right', // left arrow 39306 38 : 'down' // up arrow 39307 }, 39308 close : [27], // escape key 39309 play : [32], // space - start/stop slideshow 39310 toggle : [70] // letter "f" - toggle fullscreen 39311 }, 39312 39313 direction : { 39314 next : 'left', 39315 prev : 'right' 39316 }, 39317 39318 scrollOutside : true, 39319 39320 // Override some properties 39321 index : 0, 39322 type : null, 39323 href : null, 39324 content : null, 39325 title : null, 39326 39327 // HTML templates 39328 tpl: { 39329 wrap : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>', 39330 image : '<img class="fancybox-image" src="{href}" alt="" />', 39331 iframe : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>', 39332 error : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>', 39333 closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>', 39334 next : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>', 39335 prev : '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>' 39336 }, 39337 39338 // Properties for each animation type 39339 // Opening fancyBox 39340 openEffect : 'fade', // 'elastic', 'fade' or 'none' 39341 openSpeed : 250, 39342 openEasing : 'swing', 39343 openOpacity : true, 39344 openMethod : 'zoomIn', 39345 39346 // Closing fancyBox 39347 closeEffect : 'fade', // 'elastic', 'fade' or 'none' 39348 closeSpeed : 250, 39349 closeEasing : 'swing', 39350 closeOpacity : true, 39351 closeMethod : 'zoomOut', 39352 39353 // Changing next gallery item 39354 nextEffect : 'elastic', // 'elastic', 'fade' or 'none' 39355 nextSpeed : 250, 39356 nextEasing : 'swing', 39357 nextMethod : 'changeIn', 39358 39359 // Changing previous gallery item 39360 prevEffect : 'elastic', // 'elastic', 'fade' or 'none' 39361 prevSpeed : 250, 39362 prevEasing : 'swing', 39363 prevMethod : 'changeOut', 39364 39365 // Enable default helpers 39366 helpers : { 39367 overlay : true, 39368 title : true 39369 }, 39370 39371 // Callbacks 39372 onCancel : $.noop, // If canceling 39373 beforeLoad : $.noop, // Before loading 39374 afterLoad : $.noop, // After loading 39375 beforeShow : $.noop, // Before changing in current item 39376 afterShow : $.noop, // After opening 39377 beforeChange : $.noop, // Before changing gallery item 39378 beforeClose : $.noop, // Before closing 39379 afterClose : $.noop // After closing 39380 }, 39381 39382 //Current state 39383 group : {}, // Selected group 39384 opts : {}, // Group options 39385 previous : null, // Previous element 39386 coming : null, // Element being loaded 39387 current : null, // Currently loaded element 39388 isActive : false, // Is activated 39389 isOpen : false, // Is currently open 39390 isOpened : false, // Have been fully opened at least once 39391 39392 wrap : null, 39393 skin : null, 39394 outer : null, 39395 inner : null, 39396 39397 player : { 39398 timer : null, 39399 isActive : false 39400 }, 39401 39402 // Loaders
vendor: 12,016 bytes, lines 39403-39950
39403 ajaxLoad : null, 39404 imgPreload : null, 39405 39406 // Some collections 39407 transitions : {}, 39408 helpers : {}, 39409 39410 /* 39411 * Static methods 39412 */ 39413 39414 open: function (group, opts) { 39415 if (!group) { 39416 return; 39417 } 39418 39419 if (!$.isPlainObject(opts)) { 39420 opts = {}; 39421 } 39422 39423 // Close if already active 39424 if (false === F.close(true)) { 39425 return; 39426 } 39427 39428 // Normalize group 39429 if (!$.isArray(group)) { 39430 group = isQuery(group) ? $(group).get() : [group]; 39431 } 39432 39433 // Recheck if the type of each element is `object` and set content type (image, ajax, etc) 39434 $.each(group, function(i, element) { 39435 var obj = {}, 39436 href, 39437 title, 39438 content, 39439 type, 39440 rez, 39441 hrefParts, 39442 selector; 39443 39444 if ($.type(element) === "object") { 39445 // Check if is DOM element 39446 if (element.nodeType) { 39447 element = $(element); 39448 } 39449 39450 if (isQuery(element)) { 39451 obj = { 39452 href : element.data('fancybox-href') || element.attr('href'), 39453 title : element.data('fancybox-title') || element.attr('title'), 39454 isDom : true, 39455 element : element 39456 }; 39457 39458 if ($.metadata) { 39459 $.extend(true, obj, element.metadata()); 39460 } 39461 39462 } else { 39463 obj = element; 39464 } 39465 } 39466 39467 href = opts.href || obj.href || (isString(element) ? element : null); 39468 title = opts.title !== undefined ? opts.title : obj.title || ''; 39469 39470 content = opts.content || obj.content; 39471 type = content ? 'html' : (opts.type || obj.type); 39472 39473 if (!type && obj.isDom) { 39474 type = element.data('fancybox-type'); 39475 39476 if (!type) { 39477 rez = element.prop('class').match(/fancybox\.(\w+)/); 39478 type = rez ? rez[1] : null; 39479 } 39480 } 39481 39482 if (isString(href)) { 39483 // Try to guess the content type 39484 if (!type) { 39485 if (F.isImage(href)) { 39486 type = 'image'; 39487 39488 } else if (F.isSWF(href)) { 39489 type = 'swf'; 39490 39491 } else if (href.charAt(0) === '#') { 39492 type = 'inline'; 39493 39494 } else if (isString(element)) { 39495 type = 'html'; 39496 content = element; 39497 } 39498 } 39499 39500 // Split url into two pieces with source url and content selector, e.g, 39501 // "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id" 39502 if (type === 'ajax') { 39503 hrefParts = href.split(/\s+/, 2); 39504 href = hrefParts.shift(); 39505 selector = hrefParts.shift(); 39506 } 39507 } 39508 39509 if (!content) { 39510 if (type === 'inline') { 39511 if (href) { 39512 content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7 39513 39514 } else if (obj.isDom) { 39515 content = element; 39516 } 39517 39518 } else if (type === 'html') { 39519 content = href; 39520 39521 } else if (!type && !href && obj.isDom) { 39522 type = 'inline'; 39523 content = element; 39524 } 39525 } 39526 39527 $.extend(obj, { 39528 href : href, 39529 type : type, 39530 content : content, 39531 title : title, 39532 selector : selector 39533 }); 39534 39535 group[ i ] = obj; 39536 }); 39537 39538 // Extend the defaults 39539 F.opts = $.extend(true, {}, F.defaults, opts); 39540 39541 // All options are merged recursive except keys 39542 if (opts.keys !== undefined) { 39543 F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; 39544 } 39545 39546 F.group = group; 39547 39548 return F._start(F.opts.index); 39549 }, 39550 39551 // Cancel image loading or abort ajax request 39552 cancel: function () { 39553 var coming = F.coming; 39554 39555 if (!coming || false === F.trigger('onCancel')) { 39556 return; 39557 } 39558 39559 F.hideLoading(); 39560 39561 if (F.ajaxLoad) { 39562 F.ajaxLoad.abort(); 39563 } 39564 39565 F.ajaxLoad = null; 39566 39567 if (F.imgPreload) { 39568 F.imgPreload.onload = F.imgPreload.onerror = null; 39569 } 39570 39571 if (coming.wrap) { 39572 coming.wrap.stop(true, true).trigger('onReset').remove(); 39573 } 39574 39575 F.coming = null; 39576 39577 // If the first item has been canceled, then clear everything 39578 if (!F.current) { 39579 F._afterZoomOut( coming ); 39580 } 39581 }, 39582 39583 // Start closing animation if is open; remove immediately if opening/closing 39584 close: function (event) { 39585 F.cancel(); 39586 39587 if (false === F.trigger('beforeClose')) { 39588 return; 39589 } 39590 39591 F.unbindEvents(); 39592 39593 if (!F.isActive) { 39594 return; 39595 } 39596 39597 if (!F.isOpen || event === true) { 39598 $('.fancybox-wrap').stop(true).trigger('onReset').remove(); 39599 39600 F._afterZoomOut(); 39601 39602 } else { 39603 F.isOpen = F.isOpened = false; 39604 F.isClosing = true; 39605 39606 $('.fancybox-item, .fancybox-nav').remove(); 39607 39608 F.wrap.stop(true, true).removeClass('fancybox-opened'); 39609 39610 F.transitions[ F.current.closeMethod ](); 39611 } 39612 }, 39613 39614 // Manage slideshow: 39615 // $.fancybox.play(); - toggle slideshow 39616 // $.fancybox.play( true ); - start 39617 // $.fancybox.play( false ); - stop 39618 play: function ( action ) { 39619 var clear = function () { 39620 clearTimeout(F.player.timer); 39621 }, 39622 set = function () { 39623 clear(); 39624 39625 if (F.current && F.player.isActive) { 39626 F.player.timer = setTimeout(F.next, F.current.playSpeed); 39627 } 39628 }, 39629 stop = function () { 39630 clear(); 39631 39632 D.unbind('.player'); 39633 39634 F.player.isActive = false; 39635 39636 F.trigger('onPlayEnd'); 39637 }, 39638 start = function () { 39639 if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { 39640 F.player.isActive = true; 39641 39642 D.bind({ 39643 'onCancel.player beforeClose.player' : stop, 39644 'onUpdate.player' : set, 39645 'beforeLoad.player' : clear 39646 }); 39647 39648 set(); 39649 39650 F.trigger('onPlayStart'); 39651 } 39652 }; 39653 39654 if (action === true || (!F.player.isActive && action !== false)) { 39655 start(); 39656 } else { 39657 stop(); 39658 } 39659 }, 39660 39661 // Navigate to next gallery item 39662 next: function ( direction ) { 39663 var current = F.current; 39664 39665 if (current) { 39666 if (!isString(direction)) { 39667 direction = current.direction.next; 39668 } 39669 39670 F.jumpto(current.index + 1, direction, 'next'); 39671 } 39672 }, 39673 39674 // Navigate to previous gallery item 39675 prev: function ( direction ) { 39676 var current = F.current; 39677 39678 if (current) { 39679 if (!isString(direction)) { 39680 direction = current.direction.prev; 39681 } 39682 39683 F.jumpto(current.index - 1, direction, 'prev'); 39684 } 39685 }, 39686 39687 // Navigate to gallery item by index 39688 jumpto: function ( index, direction, router ) { 39689 var current = F.current; 39690 39691 if (!current) { 39692 return; 39693 } 39694 39695 index = getScalar(index); 39696 39697 F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ]; 39698 F.router = router || 'jumpto'; 39699 39700 if (current.loop) { 39701 if (index < 0) { 39702 index = current.group.length + (index % current.group.length); 39703 } 39704 39705 index = index % current.group.length; 39706 } 39707 39708 if (current.group[ index ] !== undefined) { 39709 F.cancel(); 39710 39711 F._start(index); 39712 } 39713 }, 39714 39715 // Center inside viewport and toggle position type to fixed or absolute if needed 39716 reposition: function (e, onlyAbsolute) { 39717 var current = F.current, 39718 wrap = current ? current.wrap : null, 39719 pos; 39720 39721 if (wrap) { 39722 pos = F._getPosition(onlyAbsolute); 39723 39724 if (e && e.type === 'scroll') { 39725 delete pos.position; 39726 39727 wrap.stop(true, true).animate(pos, 200); 39728 39729 } else { 39730 wrap.css(pos); 39731 39732 current.pos = $.extend({}, current.dim, pos); 39733 } 39734 } 39735 }, 39736 39737 update: function (e) { 39738 var type = (e && e.type), 39739 anyway = !type || type === 'orientationchange'; 39740 39741 if (anyway) { 39742 clearTimeout(didUpdate); 39743 39744 didUpdate = null; 39745 } 39746 39747 if (!F.isOpen || didUpdate) { 39748 return; 39749 } 39750 39751 didUpdate = setTimeout(function() { 39752 var current = F.current; 39753 39754 if (!current || F.isClosing) { 39755 return; 39756 } 39757 39758 F.wrap.removeClass('fancybox-tmp'); 39759 39760 if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) { 39761 F._setDimension(); 39762 } 39763 39764 if (!(type === 'scroll' && current.canShrink)) { 39765 F.reposition(e); 39766 } 39767 39768 F.trigger('onUpdate'); 39769 39770 didUpdate = null; 39771 39772 }, (anyway && !isTouch ? 0 : 300)); 39773 }, 39774 39775 // Shrink content to fit inside viewport or restore if resized 39776 toggle: function ( action ) { 39777 if (F.isOpen) { 39778 F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView; 39779 39780 // Help browser to restore document dimensions 39781 if (isTouch) { 39782 F.wrap.removeAttr('style').addClass('fancybox-tmp'); 39783 39784 F.trigger('onUpdate'); 39785 } 39786 39787 F.update(); 39788 } 39789 }, 39790 39791 hideLoading: function () { 39792 D.unbind('.loading'); 39793 39794 $('#fancybox-loading').remove(); 39795 }, 39796 39797 showLoading: function () { 39798 var el, viewport; 39799 39800 F.hideLoading(); 39801 39802 el = $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body'); 39803 39804 // If user will press the escape-button, the request will be canceled 39805 D.bind('keydown.loading', function(e) { 39806 if ((e.which || e.keyCode) === 27) { 39807 e.preventDefault(); 39808 39809 F.cancel(); 39810 } 39811 }); 39812 39813 if (!F.defaults.fixed) { 39814 viewport = F.getViewport(); 39815 39816 el.css({ 39817 position : 'absolute', 39818 top : (viewport.h * 0.5) + viewport.y, 39819 left : (viewport.w * 0.5) + viewport.x 39820 }); 39821 } 39822 }, 39823 39824 getViewport: function () { 39825 var locked = (F.current && F.current.locked) || false, 39826 rez = { 39827 x: W.scrollLeft(), 39828 y: W.scrollTop() 39829 }; 39830 39831 if (locked) { 39832 rez.w = locked[0].clientWidth; 39833 rez.h = locked[0].clientHeight; 39834 39835 } else { 39836 // See http://bugs.jquery.com/ticket/6724 39837 rez.w = isTouch && window.innerWidth ? window.innerWidth : W.width(); 39838 rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height(); 39839 } 39840 39841 return rez; 39842 }, 39843 39844 // Unbind the keyboard / clicking actions 39845 unbindEvents: function () { 39846 if (F.wrap && isQuery(F.wrap)) { 39847 F.wrap.unbind('.fb'); 39848 } 39849 39850 D.unbind('.fb'); 39851 W.unbind('.fb'); 39852 }, 39853 39854 bindEvents: function () { 39855 var current = F.current, 39856 keys; 39857 39858 if (!current) { 39859 return; 39860 } 39861 39862 // Changing document height on iOS devices triggers a 'resize' event, 39863 // that can change document height... repeating infinitely 39864 W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update); 39865 39866 keys = current.keys; 39867 39868 if (keys) { 39869 D.bind('keydown.fb', function (e) { 39870 var code = e.which || e.keyCode, 39871 target = e.target || e.srcElement; 39872 39873 // Skip esc key if loading, because showLoading will cancel preloading 39874 if (code === 27 && F.coming) { 39875 return false; 39876 } 39877 39878 // Ignore key combinations and key events within form elements 39879 if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { 39880 $.each(keys, function(i, val) { 39881 if (current.group.length > 1 && val[ code ] !== undefined) { 39882 F[ i ]( val[ code ] ); 39883 39884 e.preventDefault(); 39885 return false; 39886 } 39887 39888 if ($.inArray(code, val) > -1) { 39889 F[ i ] (); 39890 39891 e.preventDefault(); 39892 return false; 39893 } 39894 }); 39895 } 39896 }); 39897 } 39898 39899 if ($.fn.mousewheel && current.mouseWheel) { 39900 F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) { 39901 var target = e.target || null, 39902 parent = $(target), 39903 canScroll = false; 39904 39905 while (parent.length) { 39906 if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) { 39907 break; 39908 } 39909 39910 canScroll = isScrollable( parent[0] ); 39911 parent = $(parent).parent(); 39912 } 39913 39914 if (delta !== 0 && !canScroll) { 39915 if (F.group.length > 1 && !current.canShrink) { 39916 if (deltaY > 0 || deltaX > 0) { 39917 F.prev( deltaY > 0 ? 'down' : 'left' ); 39918 39919 } else if (deltaY < 0 || deltaX < 0) { 39920 F.next( deltaY < 0 ? 'up' : 'right' ); 39921 } 39922 39923 e.preventDefault(); 39924 } 39925 } 39926 }); 39927 } 39928 }, 39929 39930 trigger: function (event, o) { 39931 var ret, obj = o || F.coming || F.current; 39932 39933 if (!obj) { 39934 return; 39935 } 39936 39937 if ($.isFunction( obj[event] )) { 39938 ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); 39939 } 39940 39941 if (ret === false) { 39942 return false; 39943 } 39944 39945 if (obj.helpers) { 39946 $.each(obj.helpers, function (helper, opts) { 39947 if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) { 39948 F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj); 39949 } 39950 });
vendor: 7,983 bytes, lines 39950-40306
39950 39951 } 39952 39953 D.trigger(event); 39954 }, 39955 39956 isImage: function (str) { 39957 return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i); 39958 }, 39959 39960 isSWF: function (str) { 39961 return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); 39962 }, 39963 39964 _start: function (index) { 39965 var coming = {}, 39966 obj, 39967 href, 39968 type, 39969 margin, 39970 padding; 39971 39972 index = getScalar( index ); 39973 obj = F.group[ index ] || null; 39974 39975 if (!obj) { 39976 return false; 39977 } 39978 39979 coming = $.extend(true, {}, F.opts, obj); 39980 39981 // Convert margin and padding properties to array - top, right, bottom, left 39982 margin = coming.margin; 39983 padding = coming.padding; 39984 39985 if ($.type(margin) === 'number') { 39986 coming.margin = [margin, margin, margin, margin]; 39987 } 39988 39989 if ($.type(padding) === 'number') { 39990 coming.padding = [padding, padding, padding, padding]; 39991 } 39992 39993 // 'modal' propery is just a shortcut 39994 if (coming.modal) { 39995 $.extend(true, coming, { 39996 closeBtn : false, 39997 closeClick : false, 39998 nextClick : false, 39999 arrows : false, 40000 mouseWheel : false, 40001 keys : null, 40002 helpers: { 40003 overlay : { 40004 closeClick : false 40005 } 40006 } 40007 }); 40008 } 40009 40010 // 'autoSize' property is a shortcut, too 40011 if (coming.autoSize) { 40012 coming.autoWidth = coming.autoHeight = true; 40013 } 40014 40015 if (coming.width === 'auto') { 40016 coming.autoWidth = true; 40017 } 40018 40019 if (coming.height === 'auto') { 40020 coming.autoHeight = true; 40021 } 40022 40023 /* 40024 * Add reference to the group, so it`s possible to access from callbacks, example: 40025 * afterLoad : function() { 40026 * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); 40027 * } 40028 */ 40029 40030 coming.group = F.group; 40031 coming.index = index; 40032 40033 // Give a chance for callback or helpers to update coming item (type, title, etc) 40034 F.coming = coming; 40035 40036 if (false === F.trigger('beforeLoad')) { 40037 F.coming = null; 40038 40039 return; 40040 } 40041 40042 type = coming.type; 40043 href = coming.href; 40044 40045 if (!type) { 40046 F.coming = null; 40047 40048 //If we can not determine content type then drop silently or display next/prev item if looping through gallery 40049 if (F.current && F.router && F.router !== 'jumpto') { 40050 F.current.index = index; 40051 40052 return F[ F.router ]( F.direction ); 40053 } 40054 40055 return false; 40056 } 40057 40058 F.isActive = true; 40059 40060 if (type === 'image' || type === 'swf') { 40061 coming.autoHeight = coming.autoWidth = false; 40062 coming.scrolling = 'visible'; 40063 } 40064 40065 if (type === 'image') { 40066 coming.aspectRatio = true; 40067 } 40068 40069 if (type === 'iframe' && isTouch) { 40070 coming.scrolling = 'scroll'; 40071 } 40072 40073 // Build the neccessary markup 40074 coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' ); 40075 40076 $.extend(coming, { 40077 skin : $('.fancybox-skin', coming.wrap), 40078 outer : $('.fancybox-outer', coming.wrap), 40079 inner : $('.fancybox-inner', coming.wrap) 40080 }); 40081 40082 $.each(["Top", "Right", "Bottom", "Left"], function(i, v) { 40083 coming.skin.css('padding' + v, getValue(coming.padding[ i ])); 40084 }); 40085 40086 F.trigger('onReady'); 40087 40088 // Check before try to load; 'inline' and 'html' types need content, others - href 40089 if (type === 'inline' || type === 'html') { 40090 if (!coming.content || !coming.content.length) { 40091 return F._error( 'content' ); 40092 } 40093 40094 } else if (!href) { 40095 return F._error( 'href' ); 40096 } 40097 40098 if (type === 'image') { 40099 F._loadImage(); 40100 40101 } else if (type === 'ajax') { 40102 F._loadAjax(); 40103 40104 } else if (type === 'iframe') { 40105 F._loadIframe(); 40106 40107 } else { 40108 F._afterLoad(); 40109 } 40110 }, 40111 40112 _error: function ( type ) { 40113 $.extend(F.coming, { 40114 type : 'html', 40115 autoWidth : true, 40116 autoHeight : true, 40117 minWidth : 0, 40118 minHeight : 0, 40119 scrolling : 'no', 40120 hasError : type, 40121 content : F.coming.tpl.error 40122 }); 40123 40124 F._afterLoad(); 40125 }, 40126 40127 _loadImage: function () { 40128 // Reset preload image so it is later possible to check "complete" property 40129 var img = F.imgPreload = new Image(); 40130 40131 img.onload = function () { 40132 this.onload = this.onerror = null; 40133 40134 F.coming.width = this.width / F.opts.pixelRatio; 40135 F.coming.height = this.height / F.opts.pixelRatio; 40136 40137 F._afterLoad(); 40138 }; 40139 40140 img.onerror = function () { 40141 this.onload = this.onerror = null; 40142 40143 F._error( 'image' ); 40144 }; 40145 40146 img.src = F.coming.href; 40147 40148 if (img.complete !== true) { 40149 F.showLoading(); 40150 } 40151 }, 40152 40153 _loadAjax: function () { 40154 var coming = F.coming; 40155 40156 F.showLoading(); 40157 40158 F.ajaxLoad = $.ajax($.extend({}, coming.ajax, { 40159 url: coming.href, 40160 error: function (jqXHR, textStatus) { 40161 if (F.coming && textStatus !== 'abort') { 40162 F._error( 'ajax', jqXHR ); 40163 40164 } else { 40165 F.hideLoading(); 40166 } 40167 }, 40168 success: function (data, textStatus) { 40169 if (textStatus === 'success') { 40170 coming.content = data; 40171 40172 F._afterLoad(); 40173 } 40174 } 40175 })); 40176 }, 40177 40178 _loadIframe: function() { 40179 var coming = F.coming, 40180 iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime())) 40181 .attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling) 40182 .attr('src', coming.href); 40183 40184 // This helps IE 40185 $(coming.wrap).bind('onReset', function () { 40186 try { 40187 $(this).find('iframe').hide().attr('src', '//about:blank').end().empty(); 40188 } catch (e) {} 40189 }); 40190 40191 if (coming.iframe.preload) { 40192 F.showLoading(); 40193 40194 iframe.one('load', function() { 40195 $(this).data('ready', 1); 40196 40197 // iOS will lose scrolling if we resize 40198 if (!isTouch) { 40199 $(this).bind('load.fb', F.update); 40200 } 40201 40202 // Without this trick: 40203 // - iframe won't scroll on iOS devices 40204 // - IE7 sometimes displays empty iframe 40205 $(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show(); 40206 40207 F._afterLoad(); 40208 }); 40209 } 40210 40211 coming.content = iframe.appendTo( coming.inner ); 40212 40213 if (!coming.iframe.preload) { 40214 F._afterLoad(); 40215 } 40216 }, 40217 40218 _preloadImages: function() { 40219 var group = F.group, 40220 current = F.current, 40221 len = group.length, 40222 cnt = current.preload ? Math.min(current.preload, len - 1) : 0, 40223 item, 40224 i; 40225 40226 for (i = 1; i <= cnt; i += 1) { 40227 item = group[ (current.index + i ) % len ]; 40228 40229 if (item.type === 'image' && item.href) { 40230 new Image().src = item.href; 40231 } 40232 } 40233 }, 40234 40235 _afterLoad: function () { 40236 var coming = F.coming, 40237 previous = F.current, 40238 placeholder = 'fancybox-placeholder', 40239 current, 40240 content, 40241 type, 40242 scrolling, 40243 href, 40244 embed; 40245 40246 F.hideLoading(); 40247 40248 if (!coming || F.isActive === false) { 40249 return; 40250 } 40251 40252 if (false === F.trigger('afterLoad', coming, previous)) { 40253 coming.wrap.stop(true).trigger('onReset').remove(); 40254 40255 F.coming = null; 40256 40257 return; 40258 } 40259 40260 if (previous) { 40261 F.trigger('beforeChange', previous); 40262 40263 previous.wrap.stop(true).removeClass('fancybox-opened') 40264 .find('.fancybox-item, .fancybox-nav') 40265 .remove(); 40266 } 40267 40268 F.unbindEvents(); 40269 40270 current = coming; 40271 content = coming.content; 40272 type = coming.type; 40273 scrolling = coming.scrolling; 40274 40275 $.extend(F, { 40276 wrap : current.wrap, 40277 skin : current.skin, 40278 outer : current.outer, 40279 inner : current.inner, 40280 current : current, 40281 previous : previous 40282 }); 40283 40284 href = current.href; 40285 40286 switch (type) { 40287 case 'inline': 40288 case 'ajax': 40289 case 'html': 40290 if (current.selector) { 40291 content = $('<div>').html(content).find(current.selector); 40292 40293 } else if (isQuery(content)) { 40294 if (!content.data(placeholder)) { 40295 content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() ); 40296 } 40297 40298 content = content.show().detach(); 40299 40300 current.wrap.bind('onReset', function () { 40301 if ($(this).find(content).length) { 40302 content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false); 40303 } 40304 }); 40305 } 40306
vendor: 14,989 bytes, lines 40306-40878
40306 break; 40307 40308 case 'image': 40309 content = current.tpl.image.replace('{href}', href); 40310 break; 40311 40312 case 'swf': 40313 content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>'; 40314 embed = ''; 40315 40316 $.each(current.swf, function(name, val) { 40317 content += '<param name="' + name + '" value="' + val + '"></param>'; 40318 embed += ' ' + name + '="' + val + '"'; 40319 }); 40320 40321 content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>'; 40322 break; 40323 } 40324 40325 if (!(isQuery(content) && content.parent().is(current.inner))) { 40326 current.inner.append( content ); 40327 } 40328 40329 // Give a chance for helpers or callbacks to update elements 40330 F.trigger('beforeShow'); 40331 40332 // Set scrolling before calculating dimensions 40333 current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling)); 40334 40335 // Set initial dimensions and start position 40336 F._setDimension(); 40337 40338 F.reposition(); 40339 40340 F.isOpen = false; 40341 F.coming = null; 40342 40343 F.bindEvents(); 40344 40345 if (!F.isOpened) { 40346 $('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove(); 40347 40348 } else if (previous.prevMethod) { 40349 F.transitions[ previous.prevMethod ](); 40350 } 40351 40352 F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ](); 40353 40354 F._preloadImages(); 40355 }, 40356 40357 _setDimension: function () { 40358 var viewport = F.getViewport(), 40359 steps = 0, 40360 canShrink = false, 40361 canExpand = false, 40362 wrap = F.wrap, 40363 skin = F.skin, 40364 inner = F.inner, 40365 current = F.current, 40366 width = current.width, 40367 height = current.height, 40368 minWidth = current.minWidth, 40369 minHeight = current.minHeight, 40370 maxWidth = current.maxWidth, 40371 maxHeight = current.maxHeight, 40372 scrolling = current.scrolling, 40373 scrollOut = current.scrollOutside ? current.scrollbarWidth : 0, 40374 margin = current.margin, 40375 wMargin = getScalar(margin[1] + margin[3]), 40376 hMargin = getScalar(margin[0] + margin[2]), 40377 wPadding, 40378 hPadding, 40379 wSpace, 40380 hSpace, 40381 origWidth, 40382 origHeight, 40383 origMaxWidth, 40384 origMaxHeight, 40385 ratio, 40386 width_, 40387 height_, 40388 maxWidth_, 40389 maxHeight_, 40390 iframe, 40391 body; 40392 40393 // Reset dimensions so we could re-check actual size 40394 wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp'); 40395 40396 wPadding = getScalar(skin.outerWidth(true) - skin.width()); 40397 hPadding = getScalar(skin.outerHeight(true) - skin.height()); 40398 40399 // Any space between content and viewport (margin, padding, border, title) 40400 wSpace = wMargin + wPadding; 40401 hSpace = hMargin + hPadding; 40402 40403 origWidth = isPercentage(width) ? (viewport.w - wSpace) * getScalar(width) / 100 : width; 40404 origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height; 40405 40406 if (current.type === 'iframe') { 40407 iframe = current.content; 40408 40409 if (current.autoHeight && iframe.data('ready') === 1) { 40410 try { 40411 if (iframe[0].contentWindow.document.location) { 40412 inner.width( origWidth ).height(9999); 40413 40414 body = iframe.contents().find('body'); 40415 40416 if (scrollOut) { 40417 body.css('overflow-x', 'hidden'); 40418 } 40419 40420 origHeight = body.outerHeight(true); 40421 } 40422 40423 } catch (e) {} 40424 } 40425 40426 } else if (current.autoWidth || current.autoHeight) { 40427 inner.addClass( 'fancybox-tmp' ); 40428 40429 // Set width or height in case we need to calculate only one dimension 40430 if (!current.autoWidth) { 40431 inner.width( origWidth ); 40432 } 40433 40434 if (!current.autoHeight) { 40435 inner.height( origHeight ); 40436 } 40437 40438 if (current.autoWidth) { 40439 origWidth = inner.width(); 40440 } 40441 40442 if (current.autoHeight) { 40443 origHeight = inner.height(); 40444 } 40445 40446 inner.removeClass( 'fancybox-tmp' ); 40447 } 40448 40449 width = getScalar( origWidth ); 40450 height = getScalar( origHeight ); 40451 40452 ratio = origWidth / origHeight; 40453 40454 // Calculations for the content 40455 minWidth = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth); 40456 maxWidth = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth); 40457 40458 minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight); 40459 maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight); 40460 40461 // These will be used to determine if wrap can fit in the viewport 40462 origMaxWidth = maxWidth; 40463 origMaxHeight = maxHeight; 40464 40465 if (current.fitToView) { 40466 maxWidth = Math.min(viewport.w - wSpace, maxWidth); 40467 maxHeight = Math.min(viewport.h - hSpace, maxHeight); 40468 } 40469 40470 maxWidth_ = viewport.w - wMargin; 40471 maxHeight_ = viewport.h - hMargin; 40472 40473 if (current.aspectRatio) { 40474 if (width > maxWidth) { 40475 width = maxWidth; 40476 height = getScalar(width / ratio); 40477 } 40478 40479 if (height > maxHeight) { 40480 height = maxHeight; 40481 width = getScalar(height * ratio); 40482 } 40483 40484 if (width < minWidth) { 40485 width = minWidth; 40486 height = getScalar(width / ratio); 40487 } 40488 40489 if (height < minHeight) { 40490 height = minHeight; 40491 width = getScalar(height * ratio); 40492 } 40493 40494 } else { 40495 width = Math.max(minWidth, Math.min(width, maxWidth)); 40496 40497 if (current.autoHeight && current.type !== 'iframe') { 40498 inner.width( width ); 40499 40500 height = inner.height(); 40501 } 40502 40503 height = Math.max(minHeight, Math.min(height, maxHeight)); 40504 } 40505 40506 // Try to fit inside viewport (including the title) 40507 if (current.fitToView) { 40508 inner.width( width ).height( height ); 40509 40510 wrap.width( width + wPadding ); 40511 40512 // Real wrap dimensions 40513 width_ = wrap.width(); 40514 height_ = wrap.height(); 40515 40516 if (current.aspectRatio) { 40517 while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) { 40518 if (steps++ > 19) { 40519 break; 40520 } 40521 40522 height = Math.max(minHeight, Math.min(maxHeight, height - 10)); 40523 width = getScalar(height * ratio); 40524 40525 if (width < minWidth) { 40526 width = minWidth; 40527 height = getScalar(width / ratio); 40528 } 40529 40530 if (width > maxWidth) { 40531 width = maxWidth; 40532 height = getScalar(width / ratio); 40533 } 40534 40535 inner.width( width ).height( height ); 40536 40537 wrap.width( width + wPadding ); 40538 40539 width_ = wrap.width(); 40540 height_ = wrap.height(); 40541 } 40542 40543 } else { 40544 width = Math.max(minWidth, Math.min(width, width - (width_ - maxWidth_))); 40545 height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_))); 40546 } 40547 } 40548 40549 if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) { 40550 width += scrollOut; 40551 } 40552 40553 inner.width( width ).height( height ); 40554 40555 wrap.width( width + wPadding ); 40556 40557 width_ = wrap.width(); 40558 height_ = wrap.height(); 40559 40560 canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight; 40561 canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight)); 40562 40563 $.extend(current, { 40564 dim : { 40565 width : getValue( width_ ), 40566 height : getValue( height_ ) 40567 }, 40568 origWidth : origWidth, 40569 origHeight : origHeight, 40570 canShrink : canShrink, 40571 canExpand : canExpand, 40572 wPadding : wPadding, 40573 hPadding : hPadding, 40574 wrapSpace : height_ - skin.outerHeight(true), 40575 skinSpace : skin.height() - height 40576 }); 40577 40578 if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) { 40579 inner.height('auto'); 40580 } 40581 }, 40582 40583 _getPosition: function (onlyAbsolute) { 40584 var current = F.current, 40585 viewport = F.getViewport(), 40586 margin = current.margin, 40587 width = F.wrap.width() + margin[1] + margin[3], 40588 height = F.wrap.height() + margin[0] + margin[2], 40589 rez = { 40590 position: 'absolute', 40591 top : margin[0], 40592 left : margin[3] 40593 }; 40594 40595 if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { 40596 rez.position = 'fixed'; 40597 40598 } else if (!current.locked) { 40599 rez.top += viewport.y; 40600 rez.left += viewport.x; 40601 } 40602 40603 rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))); 40604 rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * current.leftRatio))); 40605 40606 return rez; 40607 }, 40608 40609 _afterZoomIn: function () { 40610 var current = F.current; 40611 40612 if (!current) { 40613 return; 40614 } 40615 40616 F.isOpen = F.isOpened = true; 40617 40618 F.wrap.css('overflow', 'visible').addClass('fancybox-opened'); 40619 40620 F.update(); 40621 40622 // Assign a click event 40623 if ( current.closeClick || (current.nextClick && F.group.length > 1) ) { 40624 F.inner.css('cursor', 'pointer').bind('click.fb', function(e) { 40625 if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { 40626 e.preventDefault(); 40627 40628 F[ current.closeClick ? 'close' : 'next' ](); 40629 } 40630 }); 40631 } 40632 40633 // Create a close button 40634 if (current.closeBtn) { 40635 $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) { 40636 e.preventDefault(); 40637 40638 F.close(); 40639 }); 40640 } 40641 40642 // Create navigation arrows 40643 if (current.arrows && F.group.length > 1) { 40644 if (current.loop || current.index > 0) { 40645 $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); 40646 } 40647 40648 if (current.loop || current.index < F.group.length - 1) { 40649 $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); 40650 } 40651 } 40652 40653 F.trigger('afterShow'); 40654 40655 // Stop the slideshow if this is the last item 40656 if (!current.loop && current.index === current.group.length - 1) { 40657 F.play( false ); 40658 40659 } else if (F.opts.autoPlay && !F.player.isActive) { 40660 F.opts.autoPlay = false; 40661 40662 F.play(); 40663 } 40664 }, 40665 40666 _afterZoomOut: function ( obj ) { 40667 obj = obj || F.current; 40668 40669 $('.fancybox-wrap').trigger('onReset').remove(); 40670 40671 $.extend(F, { 40672 group : {}, 40673 opts : {}, 40674 router : false, 40675 current : null, 40676 isActive : false, 40677 isOpened : false, 40678 isOpen : false, 40679 isClosing : false, 40680 wrap : null, 40681 skin : null, 40682 outer : null, 40683 inner : null 40684 }); 40685 40686 F.trigger('afterClose', obj); 40687 } 40688 }); 40689 40690 /* 40691 * Default transitions 40692 */ 40693 40694 F.transitions = { 40695 getOrigPosition: function () { 40696 var current = F.current, 40697 element = current.element, 40698 orig = current.orig, 40699 pos = {}, 40700 width = 50, 40701 height = 50, 40702 hPadding = current.hPadding, 40703 wPadding = current.wPadding, 40704 viewport = F.getViewport(); 40705 40706 if (!orig && current.isDom && element.is(':visible')) { 40707 orig = element.find('img:first'); 40708 40709 if (!orig.length) { 40710 orig = element; 40711 } 40712 } 40713 40714 if (isQuery(orig)) { 40715 pos = orig.offset(); 40716 40717 if (orig.is('img')) { 40718 width = orig.outerWidth(); 40719 height = orig.outerHeight(); 40720 } 40721 40722 } else { 40723 pos.top = viewport.y + (viewport.h - height) * current.topRatio; 40724 pos.left = viewport.x + (viewport.w - width) * current.leftRatio; 40725 } 40726 40727 if (F.wrap.css('position') === 'fixed' || current.locked) { 40728 pos.top -= viewport.y; 40729 pos.left -= viewport.x; 40730 } 40731 40732 pos = { 40733 top : getValue(pos.top - hPadding * current.topRatio), 40734 left : getValue(pos.left - wPadding * current.leftRatio), 40735 width : getValue(width + wPadding), 40736 height : getValue(height + hPadding) 40737 }; 40738 40739 return pos; 40740 }, 40741 40742 step: function (now, fx) { 40743 var ratio, 40744 padding, 40745 value, 40746 prop = fx.prop, 40747 current = F.current, 40748 wrapSpace = current.wrapSpace, 40749 skinSpace = current.skinSpace; 40750 40751 if (prop === 'width' || prop === 'height') { 40752 ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start); 40753 40754 if (F.isClosing) { 40755 ratio = 1 - ratio; 40756 } 40757 40758 padding = prop === 'width' ? current.wPadding : current.hPadding; 40759 value = now - padding; 40760 40761 F.skin[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) ) ); 40762 F.inner[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) ); 40763 } 40764 }, 40765 40766 zoomIn: function () { 40767 var current = F.current, 40768 startPos = current.pos, 40769 effect = current.openEffect, 40770 elastic = effect === 'elastic', 40771 endPos = $.extend({opacity : 1}, startPos); 40772 40773 // Remove "position" property that breaks older IE 40774 delete endPos.position; 40775 40776 if (elastic) { 40777 startPos = this.getOrigPosition(); 40778 40779 if (current.openOpacity) { 40780 startPos.opacity = 0.1; 40781 } 40782 40783 } else if (effect === 'fade') { 40784 startPos.opacity = 0.1; 40785 } 40786 40787 F.wrap.css(startPos).animate(endPos, { 40788 duration : effect === 'none' ? 0 : current.openSpeed, 40789 easing : current.openEasing, 40790 step : elastic ? this.step : null, 40791 complete : F._afterZoomIn 40792 }); 40793 }, 40794 40795 zoomOut: function () { 40796 var current = F.current, 40797 effect = current.closeEffect, 40798 elastic = effect === 'elastic', 40799 endPos = {opacity : 0.1}; 40800 40801 if (elastic) { 40802 endPos = this.getOrigPosition(); 40803 40804 if (current.closeOpacity) { 40805 endPos.opacity = 0.1; 40806 } 40807 } 40808 40809 F.wrap.animate(endPos, { 40810 duration : effect === 'none' ? 0 : current.closeSpeed, 40811 easing : current.closeEasing, 40812 step : elastic ? this.step : null, 40813 complete : F._afterZoomOut 40814 }); 40815 }, 40816 40817 changeIn: function () { 40818 var current = F.current, 40819 effect = current.nextEffect, 40820 startPos = current.pos, 40821 endPos = { opacity : 1 }, 40822 direction = F.direction, 40823 distance = 200, 40824 field; 40825 40826 startPos.opacity = 0.1; 40827 40828 if (effect === 'elastic') { 40829 field = direction === 'down' || direction === 'up' ? 'top' : 'left'; 40830 40831 if (direction === 'down' || direction === 'right') { 40832 startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance); 40833 endPos[ field ] = '+=' + distance + 'px'; 40834 40835 } else { 40836 startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance); 40837 endPos[ field ] = '-=' + distance + 'px'; 40838 } 40839 } 40840 40841 // Workaround for http://bugs.jquery.com/ticket/12273 40842 if (effect === 'none') { 40843 F._afterZoomIn(); 40844 40845 } else { 40846 F.wrap.css(startPos).animate(endPos, { 40847 duration : current.nextSpeed, 40848 easing : current.nextEasing, 40849 complete : F._afterZoomIn 40850 }); 40851 } 40852 }, 40853 40854 changeOut: function () { 40855 var previous = F.previous, 40856 effect = previous.prevEffect, 40857 endPos = { opacity : 0.1 }, 40858 direction = F.direction, 40859 distance = 200; 40860 40861 if (effect === 'elastic') { 40862 endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px'; 40863 } 40864 40865 previous.wrap.animate(endPos, { 40866 duration : effect === 'none' ? 0 : previous.prevSpeed, 40867 easing : previous.prevEasing, 40868 complete : function () { 40869 $(this).trigger('onReset').remove(); 40870 } 40871 }); 40872 } 40873 }; 40874 40875 /* 40876 * Overlay helper 40877 */ 40878
40879 F.helpers.overlay = { 40880 defaults : { 40881 closeClick : true, // if true, fancyBox will be closed when user clicks on the overlay 40882 speedOut : 200, // duration of fadeOut animation 40883 showEarly : true, // indicates if should be opened immediately or wait until the content is ready 40884 css : {}, // custom CSS properties 40885 locked : !isTouch, // if true, the content will be locked into overlay 40886 fixed : true // if false, the overlay CSS position property will not be set to "fixed" 40887 }, 40888 40889 overlay : null, // current handle 40890 fixed : false, // indicates if the overlay has position "fixed" 40891 el : $('html'), // element that contains "the lock" 40892 40893 // Public methods 40894 create : function(opts) { 40895 opts = $.extend({}, this.defaults, opts); 40896 40897 if (this.overlay) { 40898 this.close(); 40899 } 40900 40901 this.overlay = $('<div class="fancybox-overlay"></div>').appendTo( F.coming ? F.coming.parent : opts.parent ); 40902 this.fixed = false; 40903 40904 if (opts.fixed && F.defaults.fixed) { 40905 this.overlay.addClass('fancybox-overlay-fixed'); 40906 40907 this.fixed = true; 40908 } 40909 }, 40910 40911 open : function(opts) { 40912 var that = this; 40913 40914 opts = $.extend({}, this.defaults, opts); 40915 40916 if (this.overlay) { 40917 this.overlay.unbind('.overlay').width('auto').height('auto'); 40918 40919 } else { 40920 this.create(opts); 40921 } 40922 40923 if (!this.fixed) { 40924 W.bind('resize.overlay', $.proxy( this.update, this) ); 40925 40926 this.update(); 40927 } 40928 40929 if (opts.closeClick) { 40930 this.overlay.bind('click.overlay', function(e) { 40931 if ($(e.target).hasClass('fancybox-overlay')) { 40932 if (F.isActive) { 40933 F.close(); 40934 } else { 40935 that.close(); 40936 } 40937 40938 return false; 40939 } 40940 }); 40941 } 40942 40943 this.overlay.css( opts.css ).show(); 40944 }, 40945 40946 close : function() { 40947 var scrollV, scrollH; 40948 40949 W.unbind('resize.overlay'); 40950 40951 if (this.el.hasClass('fancybox-lock')) { 40952 $('.fancybox-margin').removeClass('fancybox-margin'); 40953 40954 scrollV = W.scrollTop(); 40955 scrollH = W.scrollLeft(); 40956 40957 this.el.removeClass('fancybox-lock'); 40958 40959 W.scrollTop( scrollV ).scrollLeft( scrollH ); 40960 } 40961 40962 $('.fancybox-overlay').remove().hide(); 40963 40964 $.extend(this, { 40965 overlay : null, 40966 fixed : false 40967 }); 40968 }, 40969 40970 // Private, callbacks 40971 40972 update : function () { 40973 var width = '100%', offsetWidth; 40974 40975 // Reset width/height so it will not mess 40976 this.overlay.width(width).height('100%'); 40977 40978 // jQuery does not return reliable result for IE 40979 if (IE) { 40980 offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); 40981 40982 if (D.width() > offsetWidth) { 40983 width = D.width(); 40984 } 40985 40986 } else if (D.width() > W.width()) { 40987 width = D.width(); 40988 } 40989 40990 this.overlay.width(width).height(D.height()); 40991 }, 40992 40993 // This is where we can manipulate DOM, because later it would cause iframes to reload 40994 onReady : function (opts, obj) { 40995 var overlay = this.overlay; 40996 40997 $('.fancybox-overlay').stop(true, true); 40998 40999 if (!overlay) { 41000 this.create(opts); 41001 } 41002 41003 if (opts.locked && this.fixed && obj.fixed) { 41004 if (!overlay) { 41005 this.margin = D.height() > W.height() ? $('html').css('margin-right').replace("px", "") : false; 41006 } 41007 41008 obj.locked = this.overlay.append( obj.wrap ); 41009 obj.fixed = false; 41010 } 41011 41012 if (opts.showEarly === true) { 41013 this.beforeShow.apply(this, arguments); 41014 } 41015 }, 41016 41017 beforeShow : function(opts, obj) { 41018 var scrollV, scrollH; 41019 41020 if (obj.locked) { 41021 if (this.margin !== false) { 41022 $('*').filter(function(){ 41023 return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") ); 41024 }).addClass('fancybox-margin'); 41025 41026 this.el.addClass('fancybox-margin'); 41027 } 41028 41029 scrollV = W.scrollTop(); 41030 scrollH = W.scrollLeft(); 41031 41032 this.el.addClass('fancybox-lock'); 41033 41034 W.scrollTop( scrollV ).scrollLeft( scrollH ); 41035 } 41036 41037 this.open(opts); 41038 }, 41039 41040 onUpdate : function() { 41041 if (!this.fixed) { 41042 this.update(); 41043 } 41044 }, 41045 41046 afterClose: function (opts) { 41047 // Remove overlay if exists and fancyBox is not opening 41048 // (e.g., it is not being open using afterClose callback) 41049 //if (this.overlay && !F.isActive) { 41050 if (this.overlay && !F.coming) { 41051 this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this )); 41052 } 41053 } 41054 }; 41055 41056 /* 41057 * Title helper 41058 */ 41059 41060 F.helpers.title = { 41061 defaults : { 41062 type : 'float', // 'float', 'inside', 'outside' or 'over', 41063 position : 'bottom' // 'top' or 'bottom' 41064 }, 41065 41066 beforeShow: function (opts) { 41067 var current = F.current, 41068 text = current.title, 41069 type = opts.type, 41070 title, 41071 target; 41072 41073 if ($.isFunction(text)) { 41074 text = text.call(current.element, current); 41075 } 41076 41077 if (!isString(text) || $.trim(text) === '') { 41078 return; 41079 } 41080 41081 title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">
41081' + text + '</div>'); 41082 41083 switch (type) { 41084 case 'inside': 41085 target = F.skin; 41086 break; 41087 41088 case 'outside': 41089 target = F.wrap; 41090 break; 41091 41092 case 'over': 41093 target = F.inner; 41094 break; 41095 41096 default: // 'float' 41097 target = F.skin; 41098 41099 title.appendTo('body'); 41100 41101 if (IE) { 41102 title.width( title.width() ); 41103 } 41104 41105 title.wrapInner('<span class="child"></span>'); 41106 41107 //Increase bottom margin so this title will also fit into viewport 41108 F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) ); 41109 break; 41110 } 41111 41112 title[ (opts.position === 'top' ? 'prependTo' : 'appendTo') ](target); 41113 } 41114 }; 41115 41116 // jQuery plugin initialization 41117 $.fn.fancybox = function (options) { 41118 var index, 41119 that = $(this), 41120 selector = this.selector || '', 41121 run = function(e) { 41122 var what = $(this).blur(), idx = index, relType, relVal; 41123 41124 if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) { 41125 relType = options.groupAttr || 'data-fancybox-group'; 41126 relVal = what.attr(relType); 41127 41128 if (!relVal) { 41129 relType = 'rel'; 41130 relVal = what.get(0)[ relType ]; 41131 } 41132 41133 if (relVal && relVal !== '' && relVal !== 'nofollow') { 41134 what = selector.length ? $(selector) : that; 41135 what = what.filter('[' + relType + '="' + relVal + '"]'); 41136 idx = what.index(this); 41137 } 41138 41139 options.index = idx; 41140 41141 // Stop an event from bubbling if everything is fine 41142 if (F.open(what, options) !== false) { 41143 e.preventDefault(); 41144 } 41145 } 41146 }; 41147 41148 options = options || {}; 41149 index = options.index || 0; 41150 41151 if (!selector || options.live === false) { 41152 that.unbind('click.fb-start').bind('click.fb-start', run); 41153 41154 } else { 41155 D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run); 41156 } 41157 41158 this.filter('[data-fancybox-start=1]').trigger('click'); 41159 41160 return this; 41161 }; 41162 41163 // Tests that need a body at doc ready 41164 D.ready(function() { 41165 var w1, w2; 41166 41167 if ( $.scrollbarWidth === undefined ) { 41168 // http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth 41169 $.scrollbarWidth = function() { 41170 var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'), 41171 child = parent.children(), 41172 width = child.innerWidth() - child.height( 99 ).innerWidth(); 41173 41174 parent.remove(); 41175 41176 return width; 41177 }; 41178 } 41179 41180 if ( $.support.fixedPosition === undefined ) { 41181 $.support.fixedPosition = (function() { 41182 var elem = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'), 41183 fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 ); 41184 41185 elem.remove(); 41186 41187 return fixed; 41188 }()); 41189 } 41190 41191 $.extend(F.defaults, { 41192 scrollbarWidth : $.scrollbarWidth(), 41193 fixed : $.support.fixedPosition, 41194 parent : $('body') 41195 }); 41196 41197 //Get real width of page scroll-bar 41198 w1 = $(window).width(); 41199 41200 H.addClass('fancybox-lock-test'); 41201 41202 w2 = $(window).width(); 41203 41204 H.removeClass('fancybox-lock-test'); 41205 41206 $("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head"); 41207 }); 41208 41209}(window, document, jQuery)); 41210(function() { 41211 var base, 41212 bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 41213 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 41214 hasProp = {}.hasOwnProperty; 41215 41216 if ((base = App.Pages).Blog == null) { 41217 base.Blog = {}; 41218 } 41219 41220 App.Pages.Blog.PostsShow = (function(superClass) { 41221 extend(PostsShow, superClass); 41222 41223 function PostsShow() { 41224 this.onNextQuestionClick = bind(this.onNextQuestionClick, this); 41225 this.onAnswerClick = bind(this.onAnswerClick, this); 41226 return PostsShow.__super__.constructor.apply(this, arguments); 41227 } 41228 41229 PostsShow.prototype.widgets = ['comments']; 41230 41231 PostsShow.prototype.initialize = function() { 41232 this.initPlugins(); 41233 if ($('.quiz').length !== 0) { 41234 return this.initQuiz(); 41235 } 41236 }; 41237 41238 PostsShow.prototype.initPlugins = function() { 41239 return $('img.with-preview').fancybox({ 41240 autoScale: true, 41241 padding: 0, 41242 closeClick: true, 41243 beforeLoad: function() { 41244 var url; 41245 url = $(this.element).data('target'); 41246 return this.href = url; 41247 }, 41248 afterClose: function() { 41249 return $(this.element).show(); 41250 } 41251 }); 41252 }; 41253 41254 PostsShow.prototype.initQuiz = function() { 41255 var baseUrl; 41256 this.currentQuestion = 0; 41257 this.answers = {}; 41258 this.answerCounter = { 41259 correct: 0, 41260 failed: 0 41261 }; 41262 this.quizId = $('.quiz').data('id'); 41263 baseUrl = "https://" + location.host; 41264 $("a[href^='http:']:not([href*='" + baseUrl + "']), a[href^='https:']:not([href*='" + baseUrl + "']), a[href$='.pdf']:not([href*='" + baseUrl + "']), a[href$='.pdf']").on('click', this.onLinkClick); 41265 $('.js-quiz-trigger').on('click', this.onQuizClick); 41266 $('.js-quiz-answer').on('click', this.onAnswerClick); 41267 $('.js-quiz-continue').on('click', this.onNextQuestionClick); 41268 return $('.quiz-entry.is-init').imagesLoaded(function() { 41269 return $('.quiz-entry__actions').css('top', $('.quiz-entry.is-init').height() / 2); 41270 }); 41271 }; 41272 41273 PostsShow.prototype.answerCorrect = function(answer) { 41274 return gon.quiz[this.currentQuestion].answer === answer; 41275 }; 41276 41277 PostsShow.prototype.onQuizClick = function(e) { 41278 $('.quiz').fadeIn(); 41279 $('body').addClass('is-quiz'); 41280 App.events.publish('app:element:focus', $('.quiz-entry.is-init')); 41281 $('.quiz-entry.is-init').addClass('is-active').removeClass('is-init'); 41282 return e.preventDefault(); 41283 }; 41284 41285 PostsShow.prototype.onAnswerClick = function(e) { 41286 var $el, $text, answer; 41287 $el = $(e.currentTarget); 41288 answer = parseInt($el.data('answer'), 10); 41289 $text = $('.quiz-entry.is-active .quiz-entry__text'); 41290 if (this.answerCorrect(answer)) { 41291 $text.html("<b class='quiz-entry__success'><i>" + (this.currentQuestion + 1) + ".</i> 110%!</b> " + gon.quiz[this.currentQuestion].success_text).addClass('is-success'); 41292 this.answers[this.currentQuestion] = 1; 41293 this.answerCounter.correct++; 41294 } else { 41295 $text.html("<b class='quiz-entry__fail'><i>" + (this.currentQuestion + 1) + ".</i> Gotcha!</b> " + gon.quiz[this.currentQuestion].fail_text).addClass('is-fail'); 41296 this.answers[this.currentQuestion] = 0; 41297 this.answerCounter.failed++; 41298 } 41299 $('.js-answer-buttons').fadeOut().promise().done(function() { 41300 var offset; 41301 offset = $('.quiz-entry.is-active').height() >= $(window).height() ? $('.quiz-entry.is-active').height() - $(window).height() : 0; 41302 $('html, body').animate({ 41303 scrollTop: $('.quiz-entry.is-active').offset().top + $text.height() + offset + $('.quiz-actions').outerHeight() * 2 41304 }, 600); 41305 return $('.js-quiz-continue').hide().removeClass('is-hidden').fadeIn(); 41306 }); 41307 return e.preventDefault(); 41308 }; 41309 41310 PostsShow.prototype.onNextQuestionClick = function(e) { 41311 this.currentQuestion++; 41312 $('.js-quiz-continue').fadeOut().promise().done((function(_this) { 41313 return function() { 41314 var $current, $next, $summary; 41315 $current = $('.quiz-entry.is-active'); 41316 $next = $current.next(); 41317 if ($next.length > 0) { 41318 $current.removeClass('is-active').addClass('is-answered'); 41319 $next.addClass('is-active'); 41320 if ($next.next().length === 0) { 41321 $('.js-quiz-continue').text('View quiz results'); 41322 } 41323 $('.js-answer-buttons').fadeIn(); 41324 return App.events.publish('app:element:focus', $next); 41325 } else { 41326 $summary = $('.quiz-summary'); 41327 $summary.find('.js-quiz-correct').text(_this.answerCounter.correct); 41328 $summary.find('.js-quiz-total').text(_this.answerCounter.correct + _this.answerCounter.failed); 41329 return $summary.hide().removeClass('is-hidden').fadeIn().promise().done(function() { 41330 App.Mediator.publish('app:element:focus', $summary); 41331 return $('body').removeClass('is-quiz'); 41332 }); 41333 } 41334 }; 41335 })(this)); 41336 return e.preventDefault(); 41337 }; 41338 41339 PostsShow.prototype.onLinkClick = function(e) { 41340 return $(this).attr('target', '_blank'); 41341 }; 41342 41343 return PostsShow; 41344 41345 })(App.Core.Page); 41346 41347}).call(this); 41348/* 41349 * jQuery EasyTabs plugin 3.2.0 41350 * 41351 * Copyright (c) 2010-2011 Steve Schwartz (JangoSteve) 41352 * 41353 * Dual licensed under the MIT and GPL licenses: 41354 * http://www.opensource.org/licenses/mit-license.php 41355 * http://www.gnu.org/licenses/gpl.html 41356 * 41357 * Date: Thu May 09 17:30:00 2013 -0500 41358 */ 41359 41360( function($) { 41361 41362 $.easytabs = function(container, options) { 41363 41364 // Attach to plugin anything that should be available via 41365 // the $container.data('easytabs') object 41366 var plugin = this, 41367 $container = $(container), 41368 41369 defaults = { 41370 animate: true, 41371 panelActiveClass: "active", 41372 tabActiveClass: "active", 41373 defaultTab: "li:first-child",
41374 animationSpeed: "normal", 41375 tabs: "> ul > li", 41376 updateHash: true, 41377 cycle: false, 41378 collapsible: false, 41379 collapsedClass: "collapsed", 41380 collapsedByDefault: true, 41381 uiTabs: false, 41382 transitionIn: 'fadeIn', 41383 transitionOut: 'fadeOut', 41384 transitionInEasing: 'swing', 41385 transitionOutEasing: 'swing', 41386 transitionCollapse: 'slideUp', 41387 transitionUncollapse: 'slideDown', 41388 transitionCollapseEasing: 'swing', 41389 transitionUncollapseEasing: 'swing', 41390 containerClass: "", 41391 tabsClass: "", 41392 tabClass: "", 41393 panelClass: "", 41394 cache: true, 41395 event: 'click', 41396 panelContext: $container 41397 }, 41398 41399 // Internal instance variables 41400 // (not available via easytabs object) 41401 $defaultTab, 41402 $defaultTabLink, 41403 transitions, 41404 lastHash, 41405 skipUpdateToHash, 41406 animationSpeeds = { 41407 fast: 200, 41408 normal: 400, 41409 slow: 600 41410 }, 41411 41412 // Shorthand variable so that we don't need to call 41413 // plugin.settings throughout the plugin code 41414 settings; 41415 41416 // ============================================================= 41417 // Functions available via easytabs object 41418 // ============================================================= 41419 41420 plugin.init = function() { 41421 41422 plugin.settings = settings = $.extend({}, defaults, options); 41423 settings.bind_str = settings.event+".easytabs"; 41424 41425 // Add jQuery UI's crazy class names to markup, 41426 // so that markup will match theme CSS 41427 if ( settings.uiTabs ) { 41428 settings.tabActiveClass = 'ui-tabs-selected'; 41429 settings.containerClass = 'ui-tabs ui-widget ui-widget-content ui-corner-all'; 41430 settings.tabsClass = 'ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'; 41431 settings.tabClass = 'ui-state-default ui-corner-top'; 41432 settings.panelClass = 'ui-tabs-panel ui-widget-content ui-corner-bottom'; 41433 } 41434 41435 // If collapsible is true and defaultTab specified, assume user wants defaultTab showing (not collapsed) 41436 if ( settings.collapsible && options.defaultTab !== undefined && options.collpasedByDefault === undefined ) { 41437 settings.collapsedByDefault = false;
41438 } 41439 41440 // Convert 'normal', 'fast', and 'slow' animation speed settings to their respective speed in milliseconds 41441 if ( typeof(settings.animationSpeed) === 'string' ) { 41442 settings.animationSpeed = animationSpeeds[settings.animationSpeed]; 41443 } 41444 41445 $('a.anchor').remove().prependTo('body'); 41446 41447 // Store easytabs object on container so we can easily set 41448 // properties throughout 41449 $container.data('easytabs', {}); 41450 41451 plugin.setTransitions(); 41452 41453 plugin.getTabs(); 41454 41455 addClasses(); 41456 41457 setDefaultTab(); 41458 41459 bindToTabClicks(); 41460 41461 initHashChange(); 41462 41463 initCycle(); 41464 41465 // Append data-easytabs HTML attribute to make easy to query for 41466 // easytabs instances via CSS pseudo-selector 41467 $container.attr('data-easytabs', true); 41468 }; 41469 41470 // Set transitions for switching between tabs based on options. 41471 // Could be used to update transitions if settings are changes. 41472 plugin.setTransitions = function() { 41473 transitions = ( settings.animate ) ? { 41474 show: settings.transitionIn, 41475 hide: settings.transitionOut, 41476 speed: settings.animationSpeed, 41477 collapse: settings.transitionCollapse, 41478 uncollapse: settings.transitionUncollapse, 41479 halfSpeed: settings.animationSpeed / 2 41480 } : 41481 { 41482 show: "show", 41483 hide: "hide", 41484 speed: 0, 41485 collapse: "hide", 41486 uncollapse: "show", 41487 halfSpeed: 0 41488 }; 41489 }; 41490 41491 // Find and instantiate tabs and panels. 41492 // Could be used to reset tab and panel collection if markup is 41493 // modified. 41494 plugin.getTabs = function() { 41495 var $matchingPanel; 41496 41497 // Find the initial set of elements matching the setting.tabs 41498 // CSS selector within the container 41499 plugin.tabs = $container.find(settings.tabs), 41500 41501 // Instantiate panels as empty jquery object 41502 plugin.panels = $(), 41503 41504 plugin.tabs.each(function(){ 41505 var $tab = $(this), 41506 $a = $tab.children('a'), 41507 41508 // targetId is the ID of the panel, which is either the 41509 // `href` attribute for non-ajax tabs, or in the 41510 // `data-target` attribute for ajax tabs since the `href` is 41511 // the ajax URL 41512 targetId = $tab.children('a').data('target'); 41513 41514 $tab.data('easytabs', {}); 41515 41516 // If the tab has a `data-target` attribute, and is thus an ajax tab 41517 if ( targetId !== undefined && targetId !== null ) { 41518 $tab.data('easytabs').ajax = $a.attr('href'); 41519 } else { 41520 targetId = $a.attr('href'); 41521 } 41522 targetId = targetId.match(/#([^\?]+)/)[1]; 41523 41524 $matchingPanel = settings.panelContext.find("#" + targetId); 41525 41526 // If tab has a matching panel, add it to panels 41527 if ( $matchingPanel.length ) { 41528 41529 // Store panel height before hiding 41530 $matchingPanel.data('easytabs', { 41531 position: $matchingPanel.css('position'), 41532 visibility: $matchingPanel.css('visibility') 41533 }); 41534 41535 // Don't hide panel if it's active (allows `getTabs` to be called manually to re-instantiate tab collection) 41536 $matchingPanel.not(settings.panelActiveClass).hide(); 41537 41538 plugin.panels = plugin.panels.add($matchingPanel); 41539 41540 $tab.data('easytabs').panel = $matchingPanel; 41541 41542 // Otherwise, remove tab from tabs collection 41543 } else { 41544 plugin.tabs = plugin.tabs.not($tab); 41545 if ('console' in window) { 41546 console.warn('Warning: tab without matching panel for selector \'#' + targetId +'\' removed from set'); 41547 } 41548 } 41549 }); 41550 }; 41551 41552 // Select tab and fire callback 41553 plugin.selectTab = function($clicked, callback) { 41554 var url = window.location, 41555 hash = url.hash.match(/^[^\?]*/)[0], 41556 $targetPanel = $clicked.parent().data('easytabs').panel, 41557 ajaxUrl = $clicked.parent().data('easytabs').ajax; 41558 41559 // Tab is collapsible and active => toggle collapsed state 41560 if( settings.collapsible && ! skipUpdateToHash && ($clicked.hasClass(settings.tabActiveClass) || $clicked.hasClass(settings.collapsedClass)) ) { 41561 plugin.toggleTabCollapse($clicked, $targetPanel, ajaxUrl, callback); 41562 41563 // Tab is not active and panel is not active => select tab 41564 } else if( ! $clicked.hasClass(settings.tabActiveClass) || ! $targetPanel.hasClass(settings.panelActiveClass) ){ 41565 activateTab($clicked, $targetPanel, ajaxUrl, callback); 41566 41567 // Cache is disabled => reload (e.g reload an ajax tab). 41568 } else if ( ! settings.cache ){ 41569 activateTab($clicked, $targetPanel, ajaxUrl, callback); 41570 } 41571 41572 }; 41573
41574 // Toggle tab collapsed state and fire callback 41575 plugin.toggleTabCollapse = function($clicked, $targetPanel, ajaxUrl, callback) { 41576 plugin.panels.stop(true,true); 41577 41578 if( fire($container,"easytabs:before", [$clicked, $targetPanel, settings]) ){ 41579 plugin.tabs.filter("." + settings.tabActiveClass).removeClass(settings.tabActiveClass).children().removeClass(settings.tabActiveClass); 41580 41581 // If panel is collapsed, uncollapse it 41582 if( $clicked.hasClass(settings.collapsedClass) ){ 41583 41584 // If ajax panel and not already cached 41585 if( ajaxUrl && (!settings.cache || !$clicked.parent().data('easytabs').cached) ) { 41586 $container.trigger('easytabs:ajax:beforeSend', [$clicked, $targetPanel]); 41587 41588 $targetPanel.load(ajaxUrl, function(response, status, xhr){ 41589 $clicked.parent().data('easytabs').cached = true; 41590 $container.trigger('easytabs:ajax:complete', [$clicked, $targetPanel, response, status, xhr]); 41591 }); 41592 } 41593 41594 // Update CSS classes of tab and panel 41595 $clicked.parent() 41596 .removeClass(settings.collapsedClass) 41597 .addClass(settings.tabActiveClass) 41598 .children() 41599 .removeClass(settings.collapsedClass) 41600 .addClass(settings.tabActiveClass); 41601 41602 $targetPanel 41603 .addClass(settings.panelActiveClass) 41604 [transitions.uncollapse](transitions.speed, settings.transitionUncollapseEasing, function(){ 41605 $container.trigger('easytabs:midTransition', [$clicked, $targetPanel, settings]); 41606 if(typeof callback == 'function') callback(); 41607 }); 41608 41609 // Otherwise, collapse it 41610 } else { 41611 41612 // Update CSS classes of tab and panel 41613 $clicked.addClass(settings.collapsedClass) 41614 .parent() 41615 .addClass(settings.collapsedClass); 41616 41617 $targetPanel 41618 .removeClass(settings.panelActiveClass) 41619 [transitions.collapse](transitions.speed, settings.transitionCollapseEasing, function(){ 41620 $container.trigger("easytabs:midTransition", [$clicked, $targetPanel, settings]); 41621 if(typeof callback == 'function') callback(); 41622 }); 41623 } 41624 } 41625 }; 41626 41627 41628 // Find tab with target panel matching value 41629 plugin.matchTab = function(hash) { 41630 return plugin.tabs.find("[href='" + hash + "'],[data-target='" + hash + "']").first(); 41631 }; 41632 41633 // Find panel with `id` matching value 41634 plugin.matchInPanel = function(hash) { 41635 return ( hash && plugin.validId(hash) ? plugin.panels.filter(':has(' + hash + ')').first() : [] ); 41636 }; 41637 41638 // Make sure hash is a valid id value (admittedly strict in that HTML5 allows almost anything without a space) 41639 // but jQuery has issues with such id values anyway, so we can afford to be strict here. 41640 plugin.validId = function(id) { 41641 return id.substr(1).match(/^[A-Za-z][A-Za-z0-9\-_:\.]*$/); 41642 }; 41643 41644 // Select matching tab when URL hash changes 41645 plugin.selectTabFromHashChange = function() { 41646 var hash = window.location.hash.match(/^[^\?]*/)[0], 41647 $tab = plugin.matchTab(hash), 41648 $panel; 41649 41650 if ( settings.updateHash ) { 41651 41652 // If hash directly matches tab 41653 if( $tab.length ){ 41654 skipUpdateToHash = true; 41655 plugin.selectTab( $tab ); 41656 41657 } else { 41658 $panel = plugin.matchInPanel(hash); 41659 41660 // If panel contains element matching hash 41661 if ( $panel.length ) { 41662 hash = '#' + $panel.attr('id'); 41663 $tab = plugin.matchTab(hash); 41664 skipUpdateToHash = true; 41665 plugin.selectTab( $tab ); 41666 41667 // If default tab is not active... 41668 } else if ( ! $defaultTab.hasClass(settings.tabActiveClass) && ! settings.cycle ) { 41669 41670 // ...and hash is blank or matches a parent of the tab container or 41671 // if the last tab (before the hash updated) was one of the other tabs in this container. 41672 if ( hash === '' || plugin.matchTab(lastHash).length || $container.closest(hash).length ) { 41673 skipUpdateToHash = true; 41674 plugin.selectTab( $defaultTabLink ); 41675 } 41676 } 41677 } 41678 } 41679 }; 41680 41681 // Cycle through tabs 41682 plugin.cycleTabs = function(tabNumber){ 41683 if(settings.cycle){ 41684 tabNumber = tabNumber % plugin.tabs.length; 41685 $tab = $( plugin.tabs[tabNumber] ).children("a").first(); 41686 skipUpdateToHash = true; 41687 plugin.selectTab( $tab, function() { 41688 setTimeout(function(){ plugin.cycleTabs(tabNumber + 1); }, settings.cycle); 41689 }); 41690 } 41691 }; 41692 41693 // Convenient public methods 41694 plugin.publicMethods = { 41695 select: function(tabSelector){ 41696 var $tab; 41697 41698 // Find tab container that matches selector (like 'li#tab-one' which contains tab link) 41699 if ( ($tab = plugin.tabs.filter(tabSelector)).length === 0 ) { 41700 41701 // Find direct tab link that matches href (like 'a[href="#panel-1"]') 41702 if ( ($tab = plugin.tabs.find("a[href='" + tabSelector + "']")).length === 0 ) { 41703 41704 // Find direct tab link that matches selector (like 'a#tab-1') 41705 if ( ($tab = plugin.tabs.find("a" + tabSelector)).length === 0 ) { 41706 41707 // Find direct tab link that matches data-target (lik 'a[data-target="#panel-1"]') 41708 if ( ($tab = plugin.tabs.find("[data-target='" + tabSelector + "']")).length === 0 ) { 41709 41710 // Find direct tab link that ends in the matching href (like 'a[href$="#panel-1"]', which would also match http://example.com/currentpage/#panel-1) 41711 if ( ($tab = plugin.tabs.find("a[href$='" + tabSelector + "']")).length === 0 ) { 41712 41713 $.error('Tab \'' + tabSelector + '\' does not exist in tab set'); 41714 } 41715 } 41716 } 41717 } 41718 } else { 41719 // Select the child tab link, since the first option finds the tab container (like <li>) 41720 $tab = $tab.children("a").first(); 41721 } 41722 plugin.selectTab($tab); 41723 } 41724 }; 41725 41726 // ============================================================= 41727 // Private functions 41728 // ============================================================= 41729 41730 // Triggers an event on an element and returns the event result 41731 var fire = function(obj, name, data) { 41732 var event = $.Event(name); 41733 obj.trigger(event, data); 41734 return event.result !== false; 41735 } 41736 41737 // Add CSS classes to markup (if specified), called by init 41738 var addClasses = function() { 41739 $container.addClass(settings.containerClass); 41740 plugin.tabs.parent().addClass(settings.tabsClass); 41741 plugin.tabs.addClass(settings.tabClass); 41742 plugin.panels.addClass(settings.panelClass); 41743 }; 41744 41745 // Set the default tab, whether from hash (bookmarked) or option, 41746 // called by init 41747 var setDefaultTab = function(){ 41748 var hash = window.location.hash.match(/^[^\?]*/)[0], 41749 $selectedTab = plugin.matchTab(hash).parent(), 41750 $panel; 41751 41752 // If hash directly matches one of the tabs, active on page-load 41753 if( $selectedTab.length === 1 ){ 41754 $defaultTab = $selectedTab; 41755 settings.cycle = false;
41756 41757 } else { 41758 $panel = plugin.matchInPanel(hash); 41759 41760 // If one of the panels contains the element matching the hash, 41761 // make it active on page-load 41762 if ( $panel.length ) { 41763 hash = '#' + $panel.attr('id'); 41764 $defaultTab = plugin.matchTab(hash).parent(); 41765 41766 // Otherwise, make the default tab the one that's active on page-load 41767 } else { 41768 $defaultTab = plugin.tabs.parent().find(settings.defaultTab); 41769 if ( $defaultTab.length === 0 ) { 41770 $.error("The specified default tab ('" + settings.defaultTab + "') could not be found in the tab set ('" + settings.tabs + "') out of " + plugin.tabs.length + " tabs."); 41771 } 41772 } 41773 } 41774 41775 $defaultTabLink = $defaultTab.children("a").first(); 41776 41777 activateDefaultTab($selectedTab); 41778 }; 41779 41780 // Activate defaultTab (or collapse by default), called by setDefaultTab 41781 var activateDefaultTab = function($selectedTab) { 41782 var defaultPanel, 41783 defaultAjaxUrl; 41784 41785 if ( settings.collapsible && $selectedTab.length === 0 && settings.collapsedByDefault ) { 41786 $defaultTab 41787 .addClass(settings.collapsedClass) 41788 .children() 41789 .addClass(settings.collapsedClass); 41790 41791 } else { 41792 41793 defaultPanel = $( $defaultTab.data('easytabs').panel ); 41794 defaultAjaxUrl = $defaultTab.data('easytabs').ajax; 41795 41796 if ( defaultAjaxUrl && (!settings.cache || !$defaultTab.data('easytabs').cached) ) { 41797 $container.trigger('easytabs:ajax:beforeSend', [$defaultTabLink, defaultPanel]); 41798 defaultPanel.load(defaultAjaxUrl, function(response, status, xhr){ 41799 $defaultTab.data('easytabs').cached = true; 41800 $container.trigger('easytabs:ajax:complete', [$defaultTabLink, defaultPanel, response, status, xhr]); 41801 }); 41802 } 41803 41804 $defaultTab.data('easytabs').panel 41805 .show() 41806 .addClass(settings.panelActiveClass); 41807 41808 $defaultTab 41809 .addClass(settings.tabActiveClass) 41810 .children() 41811 .addClass(settings.tabActiveClass); 41812 } 41813 41814 // Fire event when the plugin is initialised 41815 $container.trigger("easytabs:initialised", [$defaultTabLink, defaultPanel]); 41816 }; 41817 41818 // Bind tab-select funtionality to namespaced click event, called by 41819 // init 41820 var bindToTabClicks = function() { 41821 plugin.tabs.children("a").bind(settings.bind_str, function(e) { 41822 41823 // Stop cycling when a tab is clicked 41824 settings.cycle = false; 41825 41826 // Hash will be updated when tab is clicked, 41827 // don't cause tab to re-select when hash-change event is fired 41828 skipUpdateToHash = false; 41829 41830 // Select the panel for the clicked tab 41831 plugin.selectTab( $(this) ); 41832 41833 // Don't follow the link to the anchor 41834 e.preventDefault ? e.preventDefault() : e.returnValue = false; 41835 }); 41836 }; 41837 41838 // Activate a given tab/panel, called from plugin.selectTab: 41839 // 41840 // * fire `easytabs:before` hook 41841 // * get ajax if new tab is an uncached ajax tab 41842 // * animate out previously-active panel 41843 // * fire `easytabs:midTransition` hook 41844 // * update URL hash 41845 // * animate in newly-active panel 41846 // * update CSS classes for inactive and active tabs/panels 41847 // 41848 // TODO: This could probably be broken out into many more modular 41849 // functions 41850 var activateTab = function($clicked, $targetPanel, ajaxUrl, callback) { 41851 plugin.panels.stop(true,true); 41852 41853 if( fire($container,"easytabs:before", [$clicked, $targetPanel, settings]) ){ 41854 var $visiblePanel = plugin.panels.filter(":visible"), 41855 $panelContainer = $targetPanel.parent(), 41856 targetHeight, 41857 visibleHeight, 41858 heightDifference, 41859 showPanel, 41860 hash = window.location.hash.match(/^[^\?]*/)[0]; 41861 41862 if (settings.animate) { 41863 targetHeight = getHeightForHidden($targetPanel); 41864 visibleHeight = $visiblePanel.length ? setAndReturnHeight($visiblePanel) : 0; 41865 heightDifference = targetHeight - visibleHeight; 41866 } 41867 41868 // Set lastHash to help indicate if defaultTab should be 41869 // activated across multiple tab instances. 41870 lastHash = hash; 41871 41872 // TODO: Move this function elsewhere 41873 showPanel = function() { 41874 // At this point, the previous panel is hidden, and the new one will be selected 41875 $container.trigger("easytabs:midTransition", [$clicked, $targetPanel, settings]); 41876 41877 // Gracefully animate between panels of differing heights, start height change animation *after* panel change if panel needs to contract, 41878 // so that there is no chance of making the visible panel overflowing the height of the target panel 41879 if (settings.animate && settings.transitionIn == 'fadeIn') { 41880 if (heightDifference < 0) 41881 $panelContainer.animate({ 41882 height: $panelContainer.height() + heightDifference 41883 }, transitions.halfSpeed ).css({ 'min-height': '' }); 41884 } 41885 41886 if ( settings.updateHash && ! skipUpdateToHash ) { 41887 //window.location = url.toString().replace((url.pathname + hash), (url.pathname + $clicked.attr("href"))); 41888 // Not sure why this behaves so differently, but it's more straight forward and seems to have less side-effects 41889 window.location.hash = '#' + $targetPanel.attr('id'); 41890 } else { 41891 skipUpdateToHash = false;
41892 } 41893 41894 $targetPanel 41895 [transitions.show](transitions.speed, settings.transitionInEasing, function(){ 41896 $panelContainer.css({height: '', 'min-height': ''}); // After the transition, unset the height 41897 $container.trigger("easytabs:after", [$clicked, $targetPanel, settings]); 41898 // callback only gets called if selectTab actually does something, since it's inside the if block 41899 if(typeof callback == 'function'){ 41900 callback(); 41901 } 41902 }); 41903 }; 41904 41905 if ( ajaxUrl && (!settings.cache || !$clicked.parent().data('easytabs').cached) ) { 41906 $container.trigger('easytabs:ajax:beforeSend', [$clicked, $targetPanel]); 41907 $targetPanel.load(ajaxUrl, function(response, status, xhr){ 41908 $clicked.parent().data('easytabs').cached = true; 41909 $container.trigger('easytabs:ajax:complete', [$clicked, $targetPanel, response, status, xhr]); 41910 }); 41911 } 41912 41913 // Gracefully animate between panels of differing heights, start height change animation *before* panel change if panel needs to expand, 41914 // so that there is no chance of making the target panel overflowing the height of the visible panel 41915 if( settings.animate && settings.transitionOut == 'fadeOut' ) { 41916 if( heightDifference > 0 ) { 41917 $panelContainer.animate({ 41918 height: ( $panelContainer.height() + heightDifference ) 41919 }, transitions.halfSpeed ); 41920 } else { 41921 // Prevent height jumping before height transition is triggered at midTransition 41922 $panelContainer.css({ 'min-height': $panelContainer.height() }); 41923 } 41924 } 41925 41926 // Change the active tab *first* to provide immediate feedback when the user clicks 41927 plugin.tabs.filter("." + settings.tabActiveClass).removeClass(settings.tabActiveClass).children().removeClass(settings.tabActiveClass); 41928 plugin.tabs.filter("." + settings.collapsedClass).removeClass(settings.collapsedClass).children().removeClass(settings.collapsedClass); 41929 $clicked.parent().addClass(settings.tabActiveClass).children().addClass(settings.tabActiveClass); 41930 41931 plugin.panels.filter("." + settings.panelActiveClass).removeClass(settings.panelActiveClass); 41932 $targetPanel.addClass(settings.panelActiveClass); 41933 41934 if( $visiblePanel.length ) { 41935 $visiblePanel 41936 [transitions.hide](transitions.speed, settings.transitionOutEasing, showPanel); 41937 } else { 41938 $targetPanel 41939 [transitions.uncollapse](transitions.speed, settings.transitionUncollapseEasing, showPanel); 41940 } 41941 } 41942 }; 41943 41944 // Get heights of panels to enable animation between panels of 41945 // differing heights, called by activateTab 41946 var getHeightForHidden = function($targetPanel){ 41947 41948 if ( $targetPanel.data('easytabs') && $targetPanel.data('easytabs').lastHeight ) { 41949 return $targetPanel.data('easytabs').lastHeight; 41950 } 41951 41952 // this is the only property easytabs changes, so we need to grab its value on each tab change 41953 var display = $targetPanel.css('display'), 41954 outerCloak, 41955 height; 41956 41957 // Workaround with wrapping height, because firefox returns wrong 41958 // height if element itself has absolute positioning. 41959 // but try/catch block needed for IE7 and IE8 because they throw 41960 // an "Unspecified error" when trying to create an element 41961 // with the css position set. 41962 try { 41963 outerCloak = $('<div></div>', {'position': 'absolute', 'visibility': 'hidden', 'overflow': 'hidden'}); 41964 } catch (e) { 41965 outerCloak = $('<div></div>', {'visibility': 'hidden', 'overflow': 'hidden'}); 41966 } 41967 height = $targetPanel 41968 .wrap(outerCloak) 41969 .css({'position':'relative','visibility':'hidden','display':'block'}) 41970 .outerHeight(); 41971 41972 $targetPanel.unwrap(); 41973 41974 // Return element to previous state 41975 $targetPanel.css({ 41976 position: $targetPanel.data('easytabs').position, 41977 visibility: $targetPanel.data('easytabs').visibility, 41978 display: display 41979 }); 41980 41981 // Cache height 41982 $targetPanel.data('easytabs').lastHeight = height; 41983 41984 return height; 41985 }; 41986 41987 // Since the height of the visible panel may have been manipulated due to interaction, 41988 // we want to re-cache the visible height on each tab change, called 41989 // by activateTab 41990 var setAndReturnHeight = function($visiblePanel) { 41991 var height = $visiblePanel.outerHeight(); 41992 41993 if( $visiblePanel.data('easytabs') ) { 41994 $visiblePanel.data('easytabs').lastHeight = height; 41995 } else { 41996 $visiblePanel.data('easytabs', {lastHeight: height}); 41997 } 41998 return height; 41999 }; 42000
42001 // Setup hash-change callback for forward- and back-button 42002 // functionality, called by init 42003 var initHashChange = function(){ 42004 42005 // enabling back-button with jquery.hashchange plugin 42006 // http://benalman.com/projects/jquery-hashchange-plugin/ 42007 if(typeof $(window).hashchange === 'function'){ 42008 $(window).hashchange( function(){ 42009 plugin.selectTabFromHashChange(); 42010 }); 42011 } else if ($.address && typeof $.address.change === 'function') { // back-button with jquery.address plugin http://www.asual.com/jquery/address/docs/ 42012 $.address.change( function(){ 42013 plugin.selectTabFromHashChange(); 42014 }); 42015 } 42016 }; 42017 42018 // Begin cycling if set in options, called by init 42019 var initCycle = function(){ 42020 var tabNumber; 42021 if (settings.cycle) { 42022 tabNumber = plugin.tabs.index($defaultTab); 42023 setTimeout( function(){ plugin.cycleTabs(tabNumber + 1); }, settings.cycle); 42024 } 42025 }; 42026 42027 42028 plugin.init(); 42029 42030 }; 42031 42032 $.fn.easytabs = function(options) { 42033 var args = arguments; 42034 42035 return this.each(function() { 42036 var $this = $(this), 42037 plugin = $this.data('easytabs'); 42038 42039 // Initialization was called with $(el).easytabs( { options } ); 42040 if (undefined === plugin) { 42041 plugin = new $.easytabs(this, options); 42042 $this.data('easytabs', plugin); 42043 } 42044 42045 // User called public method 42046 if ( plugin.publicMethods[options] ){ 42047 return plugin.publicMethods[options](Array.prototype.slice.call( args, 1 )); 42048 } 42049 }); 42050 }; 42051 42052})(jQuery); 42053(function() { 42054 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42055 hasProp = {}.hasOwnProperty; 42056 42057 App.Pages.BloggingContestIndex = (function(superClass) { 42058 extend(BloggingContestIndex, superClass); 42059 42060 function BloggingContestIndex() { 42061 return BloggingContestIndex.__super__.constructor.apply(this, arguments); 42062 } 42063 42064 BloggingContestIndex.prototype.initialize = function() { 42065 this.initTabs(); 42066 this.$submissionForm = $('#blogging-contest-form'); 42067 $('.js-scroll-to-form').on('click', this.scrollToSubmissionForm); 42068 return this.initValidation(); 42069 }; 42070 42071 BloggingContestIndex.prototype.initTabs = function() { 42072 return $('.js-blogging-contest-easytabs').easytabs({ 42073 animate: true, 42074 animationSpeed: 250, 42075 panelActiveClass: 'is-active', 42076 panelContext: $('.js-blogging-contest-sections'), 42077 tabActiveClass: 'is-active' 42078 }); 42079 }; 42080 42081 BloggingContestIndex.prototype.scrollToSubmissionForm = function() { 42082 $('.js-blogging-contest-easytabs').easytabs('select', '#section-submission'); 42083 return setTimeout(function() { 42084 return $('body').scrollTo('#section-submission'); 42085 }, 250); 42086 }; 42087 42088 BloggingContestIndex.prototype.validationSettings = function() { 42089 return { 42090 rules: { 42091 'blogging_contest_application[name]': { 42092 required: true 42093 }, 42094 'blogging_contest_application[surname]': { 42095 required: true 42096 }, 42097 'blogging_contest_application[email]': { 42098 required: true, 42099 email: true 42100 }, 42101 'blogging_contest_application[country]': { 42102 required: true 42103 }, 42104 'blogging_contest_application[post_link]': { 42105 required: true 42106 } 42107 } 42108 }; 42109 }; 42110 42111 BloggingContestIndex.prototype.initValidation = function() { 42112 return this.$submissionForm.validate(this.validationSettings()); 42113 }; 42114 42115 return BloggingContestIndex; 42116 42117 })(App.Core.Page); 42118 42119}).call(this);
42120/*! sly 1.6.1 - 8th Aug 2015 | https://github.com/darsain/sly */ 42121 42122!function(a,b,c){"use strict";function d(b,p,q){function K(c){var d=0,e=Gb.length;if(yb.old=a.extend({},yb),wb=tb?0:ub[rb.horizontal?"width":"height"](),Bb=zb[rb.horizontal?"width":"height"](),xb=tb?b:vb[rb.horizontal?"outerWidth":"outerHeight"](),Gb.length=0,yb.start=0,yb.end=H(xb-wb,0),Rb){d=Ib.length,Hb=vb.children(rb.itemSelector),Ib.length=0;var f,g=j(vb,rb.horizontal?"paddingLeft":"paddingTop"),h=j(vb,rb.horizontal?"paddingRight":"paddingBottom"),i="border-box"===a(Hb).css("boxSizing"),l="none"!==Hb.css("float"),m=0,n=Hb.length-1;xb=0,Hb.each(function(b,c){var d=a(c),e=c.getBoundingClientRect(),i=G(rb.horizontal?e.width||e.right-e.left:e.height||e.bottom-e.top),k=j(d,rb.horizontal?"marginLeft":"marginTop"),o=j(d,rb.horizontal?"marginRight":"marginBottom"),p=i+k+o,q=!k||!o,r={};r.el=c,r.size=q?i:p,r.half=r.size/2,r.start=xb+(q?k:0),r.center=r.start-G(wb/2-r.size/2),r.end=r.start-wb+r.size,b||(xb+=g),xb+=p,rb.horizontal||l||o&&k&&b>0&&(xb-=I(k,o)),b===n&&(r.end+=h,xb+=h,m=q?o:0),Ib.push(r),f=r}),vb[0].style[rb.horizontal?"width":"height"]=(i?xb:xb-g-h)+"px",xb-=m,Ib.length?(yb.start=Ib[0][Pb?"center":"start"],yb.end=Pb?f.center:xb>wb?f.end:yb.start):yb.start=yb.end=0}if(yb.center=G(yb.end/2+yb.start/2),V(),Ab.length&&Bb>0&&(rb.dynamicHandle?(Cb=yb.start===yb.end?Bb:G(Bb*wb/xb),Cb=k(Cb,rb.minHandleSize,Bb),Ab[0].style[rb.horizontal?"width":"height"]=Cb+"px"):Cb=Ab[rb.horizontal?"outerWidth":"outerHeight"](),Db.end=Bb-Cb,ec||N()),!tb&&wb>0){var o=yb.start,p="";if(Rb)a.each(Ib,function(a,b){Pb?Gb.push(b.center):b.start+b.size>o&&o<=yb.end&&(o=b.start,Gb.push(o),o+=wb,o>yb.end&&o<yb.end+wb&&Gb.push(yb.end))});else for(;o-wb<yb.end;)Gb.push(o),o+=wb;if(Eb[0]&&e!==Gb.length){for(var q=0;q<Gb.length;q++)p+=rb.pageBuilder.call(sb,q);Fb=Eb.html(p).children(),Fb.eq(Jb.activePage).addClass(rb.activeClass)}}if(Jb.slideeSize=xb,Jb.frameSize=wb,Jb.sbSize=Bb,Jb.handleSize=Cb,Rb){c&&null!=rb.startAt&&(T(rb.startAt),sb[Qb?"toCenter":"toStart"](rb.startAt));var r=Ib[Jb.activeItem];L(Qb&&r?r.center:k(yb.dest,yb.start,yb.end))}else c?null!=rb.startAt&&L(rb.startAt,1):L(k(yb.dest,yb.start,yb.end));ob("load")}function L(a,b,c){if(Rb&&cc.released&&!c){var d=U(a),e=a>yb.start&&a<yb.end;Qb?(e&&(a=Ib[d.centerItem].center),Pb&&rb.activateMiddle&&T(d.centerItem)):e&&(a=Ib[d.firstItem].start)}cc.init&&cc.slidee&&rb.elasticBounds?a>yb.end?a=yb.end+(a-yb.end)/6:a<yb.start&&(a=yb.start+(a-yb.start)/6):a=k(a,yb.start,yb.end),ac.start=+new Date,ac.time=0,ac.from=yb.cur,ac.to=a,ac.delta=a-yb.cur,ac.tweesing=cc.tweese||cc.init&&!cc.slidee,ac.immediate=!ac.tweesing&&(b||cc.init&&cc.slidee||!rb.speed),cc.tweese=0,a!==yb.dest&&(yb.dest=a,ob("change"),ec||M()),Z(),V(),W(),O()}function M(){if(sb.initialized){if(!ec)return ec=t(M),void(cc.released&&ob("moveStart"));ac.immediate?yb.cur=ac.to:ac.tweesing?(ac.tweeseDelta=ac.to-yb.cur,D(ac.tweeseDelta)<.1?yb.cur=ac.to:yb.cur+=ac.tweeseDelta*(cc.released?rb.swingSpeed:rb.syncSpeed)):(ac.time=I(+new Date-ac.start,rb.speed),yb.cur=ac.from+ac.delta*a.easing[rb.easing](ac.time/rb.speed,ac.time,0,1,rb.speed)),ac.to===yb.cur?(yb.cur=ac.to,cc.tweese=ec=0):ec=t(M),ob("move"),tb||(m?vb[0].style[m]=n+(rb.horizontal?"translateX":"translateY")+"("+-yb.cur+"px)":vb[0].style[rb.horizontal?"left":"top"]=-G(yb.cur)+"px"),!ec&&cc.released&&ob("moveEnd"),N()}}function N(){Ab.length&&(Db.cur=yb.start===yb.end?0:((cc.init&&!cc.slidee?yb.dest:yb.cur)-yb.start)/(yb.end-yb.start)*Db.end,Db.cur=k(G(Db.cur),Db.start,Db.end),_b.hPos!==Db.cur&&(_b.hPos=Db.cur,m?Ab[0].style[m]=n+(rb.horizontal?"translateX":"translateY")+"("+Db.cur+"px)":Ab[0].style[rb.horizontal?"left":"top"]=Db.cur+"px"))}function O(){Fb[0]&&_b.page!==Jb.activePage&&(_b.page=Jb.activePage,Fb.removeClass(rb.activeClass).eq(Jb.activePage).addClass(rb.activeClass),ob("activePage",_b.page))}function P(){bc.speed&&yb.cur!==(bc.speed>0?yb.end:yb.start)||sb.stop(),hc=cc.init?t(P):0,bc.now=+new Date,bc.pos=yb.cur+(bc.now-bc.lastTime)/1e3*bc.speed,L(cc.init?bc.pos:G(bc.pos)),cc.init||yb.cur!==yb.dest||ob("moveEnd"),bc.lastTime=bc.now}function Q(a,b,d){if("boolean"===e(b)&&(d=b,b=c),b===c)L(yb[a],d);else{if(Qb&&"center"!==a)return;var f=sb.getPos(b);f&&L(f[a],d,!Qb)}}function R(a){return null!=a?i(a)?a>=0&&a<Ib.length?a:-1:Hb.index(a):-1}function S(a){return R(i(a)&&0>a?a+Ib.length:a)}function T(a,b){var c=R(a);return!Rb||0>c?!1:((_b.active!==c||b)&&(Hb.eq(Jb.activeItem).removeClass(rb.activeClass),Hb.eq(c).addClass(rb.activeClass),_b.active=Jb.activeItem=c,W(),ob("active",c)),c)}
42122function U(a){a=k(i(a)?a:yb.dest,yb.start,yb.end);var b={},c=Pb?0:wb/2;if(!tb)for(var d=0,e=Gb.length;e>d;d++){if(a>=yb.end||d===Gb.length-1){b.activePage=Gb.length-1;break}if(a<=Gb[d]+c){b.activePage=d;break}}if(Rb){for(var f=!1,g=!1,h=!1,j=0,l=Ib.length;l>j;j++)if(f===!1&&a<=Ib[j].start+Ib[j].half&&(f=j),h===!1&&a<=Ib[j].center+Ib[j].half&&(h=j),j===l-1||a<=Ib[j].end+Ib[j].half){g=j;break}b.firstItem=i(f)?f:0,b.centerItem=i(h)?h:b.firstItem,b.lastItem=i(g)?g:b.centerItem}return b}function V(b){a.extend(Jb,U(b))}function W(){var a=yb.dest<=yb.start,b=yb.dest>=yb.end,c=(a?1:0)|(b?2:0);if(_b.slideePosState!==c&&(_b.slideePosState=c,Yb.is("button,input")&&Yb.prop("disabled",a),Zb.is("button,input")&&Zb.prop("disabled",b),Yb.add(Vb)[a?"addClass":"removeClass"](rb.disabledClass),Zb.add(Ub)[b?"addClass":"removeClass"](rb.disabledClass)),_b.fwdbwdState!==c&&cc.released&&(_b.fwdbwdState=c,Vb.is("button,input")&&Vb.prop("disabled",a),Ub.is("button,input")&&Ub.prop("disabled",b)),Rb&&null!=Jb.activeItem){var d=0===Jb.activeItem,e=Jb.activeItem>=Ib.length-1,f=(d?1:0)|(e?2:0);_b.itemsButtonState!==f&&(_b.itemsButtonState=f,Wb.is("button,input")&&Wb.prop("disabled",d),Xb.is("button,input")&&Xb.prop("disabled",e),Wb[d?"addClass":"removeClass"](rb.disabledClass),Xb[e?"addClass":"removeClass"](rb.disabledClass))}}function X(a,b,c){if(a=S(a),b=S(b),a>-1&&b>-1&&a!==b&&(!c||b!==a-1)&&(c||b!==a+1)){Hb.eq(a)[c?"insertAfter":"insertBefore"](Ib[b].el);var d=b>a?a:c?b:b-1,e=a>b?a:c?b+1:b,f=a>b;null!=Jb.activeItem&&(a===Jb.activeItem?_b.active=Jb.activeItem=c?f?b+1:b:f?b:b-1:Jb.activeItem>d&&Jb.activeItem<e&&(_b.active=Jb.activeItem+=f?1:-1)),K()}}function Y(a,b){for(var c=0,d=$b[a].length;d>c;c++)if($b[a][c]===b)return c;return-1}function Z(){cc.released&&!sb.isPaused&&sb.resume()}function $(a){return G(k(a,Db.start,Db.end)/Db.end*(yb.end-yb.start))+yb.start}function _(){cc.history[0]=cc.history[1],cc.history[1]=cc.history[2],cc.history[2]=cc.history[3],cc.history[3]=cc.delta}function ab(a){cc.released=0,cc.source=a,cc.slidee="slidee"===a}function bb(b){var c="touchstart"===b.type,d=b.data.source,e="slidee"===d;cc.init||!c&&eb(b.target)||("handle"!==d||rb.dragHandle&&Db.start!==Db.end)&&(!e||(c?rb.touchDragging:rb.mouseDragging&&b.which<2))&&(c||f(b),ab(d),cc.init=0,cc.$source=a(b.target),cc.touch=c,cc.pointer=c?b.originalEvent.touches[0]:b,cc.initX=cc.pointer.pageX,cc.initY=cc.pointer.pageY,cc.initPos=e?yb.cur:Db.cur,cc.start=+new Date,cc.time=0,cc.path=0,cc.delta=0,cc.locked=0,cc.history=[0,0,0,0],cc.pathToLock=e?c?30:10:0,u.on(c?x:w,cb),sb.pause(1),(e?vb:Ab).addClass(rb.draggedClass),ob("moveStart"),e&&(fc=setInterval(_,10)))}function cb(a){if(cc.released="mouseup"===a.type||"touchend"===a.type,cc.pointer=cc.touch?a.originalEvent[cc.released?"changedTouches":"touches"][0]:a,cc.pathX=cc.pointer.pageX-cc.initX,cc.pathY=cc.pointer.pageY-cc.initY,cc.path=E(F(cc.pathX,2)+F(cc.pathY,2)),cc.delta=rb.horizontal?cc.pathX:cc.pathY,cc.released||!(cc.path<1)){if
42122(!cc.init){if(cc.path<rb.dragThreshold)return cc.released?db():c;if(!(rb.horizontal?D(cc.pathX)>D(cc.pathY):D(cc.pathX)<D(cc.pathY)))return db();cc.init=1}f(a),!cc.locked&&cc.path>cc.pathToLock&&cc.slidee&&(cc.locked=1,cc.$source.on(z,g)),cc.released&&(db(),rb.releaseSwing&&cc.slidee&&(cc.swing=(cc.delta-cc.history[0])/40*300,cc.delta+=cc.swing,cc.tweese=D(cc.swing)>10)),L(cc.slidee?G(cc.initPos-cc.delta):$(cc.initPos+cc.delta))}}function db(){clearInterval(fc),cc.released=!0,u.off(cc.touch?x:w,cb),(cc.slidee?vb:Ab).removeClass(rb.draggedClass),setTimeout(function(){cc.$source.off(z,g)}),yb.cur===yb.dest&&cc.init&&ob("moveEnd"),sb.resume(1),cc.init=0}function eb(b){return~a.inArray(b.nodeName,B)||a(b).is(rb.interactive)}function fb(){sb.stop(),u.off("mouseup",fb)}function gb(a){switch(f(a),this){case Ub[0]:case Vb[0]:sb.moveBy(Ub.is(this)?rb.moveBy:-rb.moveBy),u.on("mouseup",fb);break;case Wb[0]:sb.prev();break;case Xb[0]:sb.next();break;case Yb[0]:sb.prevPage();break;case Zb[0]:sb.nextPage()}}function hb(a){return dc.curDelta=(rb.horizontal?a.deltaY||a.deltaX:a.deltaY)||-a.wheelDelta,dc.curDelta/=1===a.deltaMode?3:100,Rb?(o=+new Date,dc.last<o-dc.resetTime&&(dc.delta=0),dc.last=o,dc.delta+=dc.curDelta,D(dc.delta)<1?dc.finalDelta=0:(dc.finalDelta=G(dc.delta/1),dc.delta%=1),dc.finalDelta):dc.curDelta}function ib(a){a.originalEvent[r]=sb;var b=+new Date;if(J+rb.scrollHijack>b&&Sb[0]!==document&&Sb[0]!==window)return void(J=b);if(rb.scrollBy&&yb.start!==yb.end){var c=hb(a.originalEvent);(rb.scrollTrap||c>0&&yb.dest<yb.end||0>c&&yb.dest>yb.start)&&f(a,1),sb.slideBy(rb.scrollBy*c)}}function jb(a){rb.clickBar&&a.target===zb[0]&&(f(a),L($((rb.horizontal?a.pageX-zb.offset().left:a.pageY-zb.offset().top)-Cb/2)))}function kb(a){if(rb.keyboardNavBy)switch(a.which){case rb.horizontal?37:38:f(a),sb["pages"===rb.keyboardNavBy?"prevPage":"prev"]();break;case rb.horizontal?39:40:f(a),sb["pages"===rb.keyboardNavBy?"nextPage":"next"]()}}function lb(a){return eb(this)?void(a.originalEvent[r+"ignore"]=!0):void(this.parentNode!==vb[0]||a.originalEvent[r+"ignore"]||sb.activate(this))}function mb(){this.parentNode===Eb[0]&&sb.activatePage(Fb.index(this))}function nb(a){rb.pauseOnHover&&sb["mouseenter"===a.type?"pause":"resume"](2)}function ob(a,b){if($b[a]){for(qb=$b[a].length,C.length=0,pb=0;qb>pb;pb++)C.push($b[a][pb]);for(pb=0;qb>pb;pb++)C[pb].call(sb,a,b)}}if(!(this instanceof d))return new d(b,p,q);var pb,qb,rb=a.extend({},d.defaults,p),sb=this,tb=i(b),ub=a(b),vb=rb.slidee?a(rb.slidee).eq(0):ub.children().eq(0),wb=0,xb=0,yb={start:0,center:0,end:0,cur:0,dest:0},zb=a(rb.scrollBar).eq(0),Ab=zb.children().eq(0),Bb=0,Cb=0,Db={start:0,end:0,cur:0},Eb=a(rb.pagesBar),Fb=0,Gb=[],Hb=0,Ib=[],Jb={firstItem:0,lastItem:0,centerItem:0,activeItem:null,activePage:0},Kb=new l(ub[0]),Lb=new l(vb[0]),Mb=new l(zb[0]),Nb=new l(Ab[0]),Ob="basic"===rb.itemNav,Pb="forceCentered"===rb.itemNav,Qb="centered"===rb.itemNav||Pb,Rb=!tb&&(Ob||Qb||Pb),Sb=rb.scrollSource?a(rb.scrollSource):ub,Tb=rb.dragSource?a(rb.dragSource):ub,Ub=a(rb.forward),Vb=a(rb.backward),Wb=a(rb.prev),Xb=a(rb.next),Yb=a(rb.prevPage),Zb=a(rb.nextPage),$b={},_b={},ac={},bc={},cc={released:1},dc={last:0,delta:0,resetTime:200},ec=0,fc=0,gc=0,hc=0;tb||(b=ub[0]),sb.initialized=0,sb.frame=b,sb.slidee=vb[0],sb.pos=yb,sb.rel=Jb,sb.items=Ib,sb.pages=Gb,sb.isPaused=0,sb.options=rb,sb.dragging=cc,sb.reload=function(){K()},sb.getPos=function(a){if(Rb){var b=R(a);return-1!==b?Ib[b]:!1}var c=vb.find(a).eq(0);if(c[0]){var d=rb.horizontal?c.offset().left-vb.offset().left:c.offset().top-vb.offset().top,e=c[rb.horizontal?"outerWidth":"outerHeight"]();return{start:d,center:d-wb/2+e/2,end:d-wb+e,size:e}}return!1},sb.moveBy=function(a){bc.speed=a,!cc.init&&bc.speed&&yb.cur!==(bc.speed>0?yb.end:yb.start)&&(bc.lastTime=+new Date,bc.startPos=yb.cur,ab("button"),cc.init=1,ob("moveStart"),s(hc),P())},sb.stop=function(){"button"===cc.source&&(cc.init=0,cc.released=1)},sb.prev=function(){sb.activate(null==Jb.activeItem?0:Jb.activeItem-1)},sb.next=function(){sb.activate(null==Jb.activeItem?0:Jb.activeItem+1)},sb.prevPage=function(){sb.activatePage(Jb.activePage-1)},sb.nextPage=function(){sb.activatePage(Jb.activePage+1)},sb.slideBy=function(a,b){a&&(Rb?sb[Qb?"toCenter":"toStart"](k((Qb?Jb.centerItem:Jb.firstItem)+rb.scrollBy*a,0,Ib.length)):L(yb.dest+a,b))},sb.slideTo=function(a,b){L(a,b)},sb.toStart=function(a,b){Q("start",a,b)},sb.toEnd=function(a,b){Q("end",a,b)},sb.toCenter=function(a,b){Q("center",a,b)},sb.getIndex=R,sb.activate=function(a,b){var c=T(a);rb.smart&&c!==!1&&(Qb?sb.toCenter(c,b):c>=Jb.lastItem?sb.toStart(c,b):c<=Jb.firstItem?sb.toEnd(c,b):Z())},sb.activatePage=function(a,b){i(a)&&L(Gb[k(a,0,Gb.length-1)],b)},sb.resume=function(a){rb.cycleBy&&rb.cycleInterval&&("items"!==rb.cycleBy||Ib[0]&&null!=Jb.activeItem)&&!(a<sb.isPau
42122sed)&&(sb.isPaused=0,gc?gc=clearTimeout(gc):ob("resume"),gc=setTimeout(function(){switch(ob("cycle"),rb.cycleBy){case"items":sb.activate(Jb.activeItem>=Ib.length-1?0:Jb.activeItem+1);break;case"pages":sb.activatePage(Jb.activePage>=Gb.length-1?0:Jb.activePage+1)}},rb.cycleInterval))},sb.pause=function(a){a<sb.isPaused||(sb.isPaused=a||100,gc&&(gc=clearTimeout(gc),ob("pause")))},sb.toggle=function(){sb[gc?"pause":"resume"]()},sb.set=function(b,c){a.isPlainObject(b)?a.extend(rb,b):rb.hasOwnProperty(b)&&(rb[b]=c)},sb.add=function(b,c){var d=a(b);Rb?(null==c||!Ib[0]||c>=Ib.length?d.appendTo(vb):Ib.length&&d.insertBefore(Ib[c].el),null!=Jb.activeItem&&c<=Jb.activeItem&&(_b.active=Jb.activeItem+=d.length)):vb.append(d),K()},sb.remove=function(b){if(Rb){var c=S(b);if(c>-1){Hb.eq(c).remove();var d=c===Jb.activeItem;null!=Jb.activeItem&&c<Jb.activeItem&&(_b.active=--Jb.activeItem),K(),d&&(_b.active=null,sb.activate(Jb.activeItem))}}else a(b).remove(),K()},sb.moveAfter=function(a,b){X(a,b,1)},sb.moveBefore=function(a,b){X(a,b)},sb.on=function(a,b){if("object"===e(a))for(var c in a)a.hasOwnProperty(c)&&sb.on(c,a[c]);else if("function"===e(b))for(var d=a.split(" "),f=0,g=d.length;g>f;f++)$b[d[f]]=$b[d[f]]||[],-1===Y(d[f],b)&&$b[d[f]].push(b);else if("array"===e(b))for(var h=0,i=b.length;i>h;h++)sb.on(a,b[h])},sb.one=function(a,b){function c(){b.apply(sb,arguments),sb.off(a,c)}sb.on(a,c)},sb.off=function(a,b){if(b instanceof Array)for(var c=0,d=b.length;d>c;c++)sb.off(a,b[c]);else for(var e=a.split(" "),f=0,g=e.length;g>f;f++)if($b[e[f]]=$b[e[f]]||[],null==b)$b[e[f]].length=0;else{var h=Y(e[f],b);-1!==h&&$b[e[f]].splice(h,1)}}
42122,sb.destroy=function(){return d.removeInstance(b),Sb.add(Ab).add(zb).add(Eb).add(Ub).add(Vb).add(Wb).add(Xb).add(Yb).add(Zb).off("."+r),u.off("keydown",kb),Wb.add(Xb).add(Yb).add(Zb).removeClass(rb.disabledClass),Hb&&null!=Jb.activeItem&&Hb.eq(Jb.activeItem).removeClass(rb.activeClass),Eb.empty(),tb||(ub.off("."+r),Kb.restore(),Lb.restore(),Mb.restore(),Nb.restore(),a.removeData(b,r)),Ib.length=Gb.length=0,_b={},sb.initialized=0,sb},sb.init=function(){if(!sb.initialized){if(d.getInstance(b))throw new Error("There is already a Sly instance on this element");d.storeInstance(b,sb),sb.on(q);var a=["overflow","position"],c=["position","webkitTransform","msTransform","transform","left","top","width","height"];Kb.save.apply(Kb,a),Mb.save.apply(Mb,a),Lb.save.apply(Lb,c),Nb.save.apply(Nb,c);var e=Ab;return tb||(e=e.add(vb),ub.css("overflow","hidden"),m||"static"!==ub.css("position")||ub.css("position","relative")),m?n&&e.css(m,n):("static"===zb.css("position")&&zb.css("position","relative"),e.css({position:"absolute"})),rb.forward&&Ub.on(A,gb),rb.backward&&Vb.on(A,gb),rb.prev&&Wb.on(z,gb),rb.next&&Xb.on(z,gb),rb.prevPage&&Yb.on(z,gb),rb.nextPage&&Zb.on(z,gb),Sb.on(y,ib),zb[0]&&zb.on(z,jb),Rb&&rb.activateOn&&ub.on(rb.activateOn+"."+r,"*",lb),Eb[0]&&rb.activatePageOn&&Eb.on(rb.activatePageOn+"."+r,"*",mb),Tb.on(v,{source:"slidee"},bb),Ab&&Ab.on(v,{source:"handle"},bb),u.on("keydown",kb),tb||(ub.on("mouseenter."+r+" mouseleave."+r,nb),ub.on("scroll."+r,h)),sb.initialized=1,K(!0),rb.cycleBy&&!tb&&sb[rb.startPaused?"pause":"resume"](),sb}}}function e(a){return null==a?String(a):"object"==typeof a||"function"==typeof a?Object.prototype.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase()||"object":typeof a}function f(a,b){a.preventDefault(),b&&a.stopPropagation()}function g(b){f(b,1),a(this).off(b.type,g)}function h(){this.scrollLeft=0,this.scrollTop=0}function i(a){return!isNaN(parseFloat(a))&&isFinite(a)}function j(a,b){return 0|G(String(a.css(b)).replace(/[^\-0-9.]/g,""))}function k(a,b,c){return b>a?b:a>c?c:a}function l(a){var b={};return b.style={},b.save=function(){if(a&&a.nodeType){for(var c=0;c<arguments.length;c++)b.style[arguments[c]]=a.style[arguments[c]];return b}},b.restore=function(){if(a&&a.nodeType){for(var c in b.style)b.style.hasOwnProperty(c)&&(a.style[c]=b.style[c]);return b}},b}var m,n,o,p="sly",q="Sly",r=p,s=b.cancelAnimationFrame||b.cancelRequestAnimationFrame,t=b.requestAnimationFrame,u=a(document),v="touchstart."+r+" mousedown."+r,w="mousemove."+r+" mouseup."+r,x="touchmove."+r+" touchend."+r,y=(document.implementation.hasFeature("Event.wheel","3.0")?"wheel.":"mousewheel.")+r,z="click."+r,A="mousedown."+r,B=["INPUT","SELECT","BUTTON","TEXTAREA"],C=[],D=Math.abs,E=Math.sqrt,F=Math.pow,G=Math.round,H=Math.max,I=Math.min,J=0;u.on(y,function(a){var b=a.originalEvent[r],c=+new Date;(!b||b.options.scrollHijack<c-J)&&(J=c)}),d.getInstance=function(b){return a.data(b,r)},d.storeInstance=function(b,c){return a.data(b,r,c)},d.removeInstance=function(b){return a.removeData(b,r)},function(a){function b(a){var b=(new Date).getTime(),d=Math.max(0,16-(b-c)),e=setTimeout(a,d);return c=b,e}t=a.requestAnimationFrame||a.webkitRequestAnimationFrame||b;var c=(new Date).getTime(),d=a.cancelAnimationFrame||a.webkitCancelAnimationFrame||a.clearTimeout;s=function(b){d.call(a,b)}}(window),function(){function a(a){for(var d=0,e=b.length;e>d;d++){var f=b[d]?b[d]+a.charAt(0).toUpperCase()+a.slice(1):a;if(null!=c.style[f])return f}}var b=["","Webkit","Moz","ms","O"],c=document.createElement("div");m=a("transform"),n=a("perspective")?"translateZ(0) ":""}(),b[q]=d,a.fn[p]=function(b,c){var f,g;return a.isPlainObject(b)||(("string"===e(b)||b===!1)&&(f=b===!1?"destroy":b,g=Array.prototype.slice.call(arguments,1)),b={}),this.each(function(a,e){var h=d.getInstance(e);h||f?h&&f&&h[f]&&h[f].apply(h,g):h=new d(e,b,c).init()})},d.defaults={slidee:null,horizontal:!1,itemNav:null,itemSelector:null,smart:!1,activateOn:null,activateMiddle:!1,scrollSource:null,scrollBy:0,scrollHijack:300,scrollTrap:!1,dragSource:null,mouseDragging:!1,touchDragging:!1,releaseSwing:!1,swingSpeed:.2,elasticBounds:!1,dragThreshold:3,interactive:null,scrollBar:null,dragHandle:!1,dynamicHandle:!1,minHandleSize:50,clickBar:!1,syncSpeed:.5,pagesBar:null,activatePageOn:null,pageBuilder:function(a){return"<li>"+(a+1)+"</li>"},forward:null,backward:null,prev:null,next:null,prevPage:null,nextPage:null,cycleBy:null,cycleInterval:5e3,pauseOnHover:!1,startPaused:!1,moveBy:300,speed:0,easing:"swing",startAt:null,keyboardNavBy:null,draggedClass:"dragged",activeClass:"active",disabledClass:"disabled"}}(jQuery,window); 42123(function() { 42124 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 42125 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42126 hasProp = {}.hasOwnProperty; 42127 42128 App.Pages.BuyersLandingPageIndex = (function(superClass) { 42129 extend(BuyersLandingPageIndex, superClass); 42130 42131 function BuyersLandingPageIndex() { 42132 this.resizeSly = bind(this.resizeSly, this); 42133 return BuyersLandingPageIndex.__super__.constructor.apply(this, arguments); 42134 } 42135 42136 BuyersLandingPageIndex.prototype.widgets = ['loyaltyLevelProgressInfoTooltip', 'downloads', 'categoriesContainerTracking']; 42137 42138 BuyersLandingPageIndex.prototype.initialize = function() { 42139 this.initializeTooltips(); 42140 this.initCartItemsList(); 42141 this.bindEvents(); 42142 this.bindGTMEvents(); 42143 return App.events.subscribe('app:cart:updated', this.onCartUpdated); 42144 }; 42145 42146 BuyersLandingPageIndex.prototype.initCartItemsList = function() { 42147 this.cartSly = new Sly('.js-cart-list', { 42148 horizontal: true, 42149 itemNav: 'basic', 42150 smart: true, 42151 itemSelector: '.js-cart-list .grid__col', 42152 startAt: 0, 42153 mouseDragging: true, 42154 releaseSwing: true, 42155 touchDragging: false, 42156 swingSpeed: 0.1, 42157 nextPage: $('.js-cart-preview-next'), 42158 prevPage: $('.js-cart-preview-prev'), 42159 disabledClass: 'is-disabled', 42160 draggedClass: 'is-dragged' 42161 }); 42162 this.cartSly.on('load', (function(_this) { 42163 return function() { 42164 if (_this.cartSly.pos.start === _this.cartSly.pos.end) { 42165 return $('.grid__col').addClass('is-short-grid'); 42166 } else { 42167 return $('.grid__col').removeClass('is-short-grid'); 42168 } 42169 }; 42170 })(this)); 42171 if ($('.grid__col').length !== 0) { 42172 return this.cartSly.init(); 42173 } 42174 }; 42175 42176 BuyersLandingPageIndex.prototype.bindEvents = function() { 42177 return $(window).on('resize', this.resizeSly); 42178 }; 42179 42180 BuyersLandingPageIndex.prototype.resizeSly = function() { 42181 return this.cartSly.reload(); 42182 }; 42183 42184 BuyersLandingPageIndex.prototype.onCartUpdated = function(cart) { 42185 return $('.js-store-credits-left').text(numeral(cart.meta.storeCreditsLeft).format('$0.00')); 42186 }; 42187 42188 BuyersLandingPageIndex.prototype.initializeTooltips = function() { 42189 var $bonusCreditsTooltip, $cgtCreditsInfoTooltip, $proTipTooltip, $saleCampaignTooltip; 42190 $bonusCreditsTooltip = $('.js-bonus-credits-tooltip'); 42191 $cgtCreditsInfoTooltip = $('.js-cgtrader-credits-info-tooltip'); 42192 $proTipTooltip = $('.js-pro-tip-tooltip'); 42193 $saleCampaignTooltip = $('.js-sale-campaign-tooltip');
42194 if ($saleCampaignTooltip.length > 0) { 42195 this.initTooltip(I18n.translate('tooltips.buyers_sign_in_page.sale_campaign_tooltip_html'), $saleCampaignTooltip, 'Tooltip in important message (sale off)'); 42196 } 42197 if ($proTipTooltip.length > 0) { 42198 this.initTooltip(I18n.translate('tooltips.buyers_sign_in_page.pro_tip_tooltip_html'), $proTipTooltip, 'Tooltip in pro tip'); 42199 } 42200 if ($cgtCreditsInfoTooltip.length > 0) { 42201 this.initTooltip(I18n.translate('tooltips.buyers_sign_in_page.cgtrader_credits_tooltip_html'), $cgtCreditsInfoTooltip, 'Tooltip in credit count'); 42202 } 42203 if ($bonusCreditsTooltip.length > 0) { 42204 return this.initTooltip(I18n.translate('tooltips.buyers_sign_in_page.bonus_credits_tooltip_html'), $bonusCreditsTooltip, 'Tooltip in important message (bonus credits)'); 42205 } 42206 }; 42207 42208 BuyersLandingPageIndex.prototype.initTooltip = function(content, $tooltip, eventLabel) { 42209 return $tooltip.tooltipster({ 42210 theme: 'tooltip--light tooltip--popover u-text-center', 42211 animation: 'grow', 42212 contentAsHTML: true, 42213 content: content, 42214 interactive: true, 42215 maxWidth: 460 42216 }); 42217 }; 42218 42219 BuyersLandingPageIndex.prototype.bindGTMEvents = function() { 42220 this.$cartSection = $('.js-cart-section'); 42221 this.$purchasesList = $('.js-purchases-list'); 42222 this.$noPurchasesView = $('.js-no-purchases-view'); 42223 this.$publishedJobInfo = $('.js-published-job-info'); 42224 this.$noJobsView = $('.js-no-jobs-view'); 42225 if (this.$cartSection.length !== 0) { 42226 this.trackEvent('Cart items', 'Impressions'); 42227 } 42228 if (this.$purchasesList.length !== 0) { 42229 this.trackEvent('Purchases', 'One + purchases'); 42230 } 42231 if (this.$noPurchasesView.length !== 0) { 42232 this.trackEvent('Purchases', 'No purchases'); 42233 } 42234 if (this.$publishedJobInfo.length !== 0) { 42235 this.trackEvent('3D Jobs', 'One + jobs published'); 42236 } 42237 if (this.$noJobsView.length !== 0) { 42238 return this.trackEvent('3D Jobs', 'No jobs published'); 42239 } 42240 }; 42241 42242 return BuyersLandingPageIndex; 42243 42244 })(App.Core.Page); 42245 42246}).call(this); 42247(function() { 42248 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42249 hasProp = {}.hasOwnProperty; 42250 42251 App.Pages.CategoriesIndex = (function(superClass) { 42252 extend(CategoriesIndex, superClass); 42253 42254 function CategoriesIndex() { 42255 return CategoriesIndex.__super__.constructor.apply(this, arguments); 42256 } 42257 42258 CategoriesIndex.prototype.initialize = function() { 42259 return this.bindEvents(); 42260 }; 42261 42262 CategoriesIndex.prototype.bindEvents = function() { 42263 return $('.js-category-image').on('click', this.onThumbnailClick); 42264 }; 42265 42266 CategoriesIndex.prototype.onThumbnailClick = function(e) { 42267 var $target; 42268 e.stopPropagation(); 42269 $target = $(e.currentTarget).parents('.category').find('.category__title a'); 42270 return window.location = $target.attr('href'); 42271 }; 42272 42273 return CategoriesIndex; 42274 42275 })(App.Core.Page); 42276 42277}).call(this); 42278var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(e,t){"object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.LazyLoad=t()}(this,function(){"use strict";var e={elements_selector:"img",container:window,threshold:300,throttle:150,data_src:"src",data_srcset:"srcset",class_loading:"loading",class_loaded:"loaded",class_error:"error",class_initial:"initial",skip_invisible:!0,callback_load:null,callback_error:null,callback_set:null,callback_processed:null,callback_enter:null},t=!("onscroll"in window)||/glebot/.test(navigator.userAgent),n=function(e,t){e&&e(t)}
42278,o=function(e){return e.getBoundingClientRect().top+window.pageYOffset-e.ownerDocument.documentElement.clientTop},i=function(e,t,n){return(t===window?window.innerHeight+window.pageYOffset:o(t)+t.offsetHeight)<=o(e)-n},s=function(e){return e.getBoundingClientRect().left+window.pageXOffset-e.ownerDocument.documentElement.clientLeft},r=function(e,t,n){var o=window.innerWidth;return(t===window?o+window.pageXOffset:s(t)+o)<=s(e)-n},l=function(e,t,n){return(t===window?window.pageYOffset:o(t))>=o(e)+n+e.offsetHeight},a=function(e,t,n){return(t===window?window.pageXOffset:s(t))>=s(e)+n+e.offsetWidth},c=function(e,t,n){return!(i(e,t,n)||l(e,t,n)||r(e,t,n)||a(e,t,n))},u=function(e,t){var n,o=new e(t);try{n=new CustomEvent("LazyLoad::Initialized",{detail:{instance:o}})}catch(e){(n=document.createEvent("CustomEvent")).initCustomEvent("LazyLoad::Initialized",!1,!1,{instance:o})}window.dispatchEvent(n)},d=function(e,t){return e.getAttribute("data-"+t)},h=function(e,t,n){return e.setAttribute("data-"+t,n)},_=function(e,t){var n=e.parentNode;if("PICTURE"===n.tagName)for(var o=0;o<n.children.length;o++){var i=n.children[o];if("SOURCE"===i.tagName){var s=d(i,t);s&&i.setAttribute("srcset",s)}}},f=function(e,t,n){var o=e.tagName,i=d(e,n);if("IMG"===o){_(e,t);var s=d(e,t);return s&&e.setAttribute("srcset",s),void(i&&e.setAttribute("src",i))}"IFRAME"!==o?i&&(e.style.backgroundImage='url("'+i+'")'):i&&e.setAttribute("src",i)},p="classList"in document.createElement("p"),m=function(e,t){p?e.classList.add(t):e.className+=(e.className?" ":"")+t},g=function(e,t){p?e.classList.remove(t):e.className=e.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},v=function(t){this._settings=_extends({},e,t),this._queryOriginNode=this._settings.container===window?document:this._settings.container,this._previousLoopTime=0,this._loopTimeout=null,this._boundHandleScroll=this.handleScroll.bind(this),this._isFirstLoop=!0,window.addEventListener("resize",this._boundHandleScroll),this.update()};v.prototype={_reveal:function(e){var t=this._settings,o=function o(){t&&(e.removeEventListener("load",i),e.removeEventListener("error",o),g(e,t.class_loading),m(e,t.class_error),n(t.callback_error,e))},i=function i(){t&&(g(e,t.class_loading),m(e,t.class_loaded),e.removeEventListener("load",i),e.removeEventListener("error",o),n(t.callback_load,e))};n(t.callback_enter,e),"IMG"!==e.tagName&&"IFRAME"!==e.tagName||(e.addEventListener("load",i),e.addEventListener("error",o),m(e,t.class_loading)),f(e,t.data_srcset,t.data_src),n(t.callback_set,e)},_loopThroughElements:function(){var e=this._settings,o=this._elements,i=o?o.length:0,s=void 0,r=[],l=this._isFirstLoop;for(s=0;s<i;s++){var a=o[s];e.skip_invisible&&null===a.offsetParent||(t||c(a,e.container,e.threshold))&&(l&&m(a,e.class_initial),this._reveal(a),r.push(s),h(a,"was-processed",!0))}for(;r.length;)o.splice(r.pop(),1),n(e.callback_processed,o.length);0===i&&this._stopScrollHandler(),l&&(this._isFirstLoop=!1)},_purgeElements:function(){var e=this._elements,t=e.length,n=void 0,o=[];for(n=0;n<t;n++){var i=e[n];d(i,"was-processed")&&o.push(n)}for(;o.length>0;)e.splice(o.pop(),1)},_startScrollHandler:function(){this._isHandlingScroll||(this._isHandlingScroll=!0,this._settings.container.addEventListener("scroll",this._boundHandleScroll))},_stopScrollHandler:function(){this._isHandlingScroll&&(this._isHandlingScroll=!1,this._settings.container.removeEventListener("scroll",this._boundHandleScroll))},handleScroll:function(){var e=this._settings.throttle;if(0!==e){var t=Date.now(),n=e-(t-this._previousLoopTime);n<=0||n>e?(this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._previousLoopTime=t,this._loopThroughElements()):this._loopTimeout||(this._loopTimeout=setTimeout(function(){this._previousLoopTime=Date.now(),this._loopTimeout=null,this._loopThroughElements()}.bind(this),n))}else this._loopThroughElements()},update:function(){this._elements=Array.prototype.slice.call(this._queryOriginNode.querySelectorAll(this._settings.elements_selector)),this._purgeElements(),this._loopThroughElements(),this._startScrollHandler()},destroy:function(){window.removeEventListener("resize",this._boundHandleScroll),this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._stopScrollHandler(),this._elements=null,this._queryOriginNode=null,this._settings=null}};var w=window.lazyLoadOptions;return w&&function(e,t){var n=t.length;if(n)for(var o=0;o<n;o++)u(e,t[o]);else u(e,t)}(v,w),v}); 42279(function() { 42280 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42281 hasProp = {}.hasOwnProperty; 42282 42283 App.Pages.ChallengesCorona = (function(superClass) { 42284 extend(ChallengesCorona, superClass); 42285 42286 function ChallengesCorona() { 42287 return ChallengesCorona.__super__.constructor.apply(this, arguments); 42288 } 42289 42290 ChallengesCorona.prototype.initialize = function() { 42291 this.bindPerPageSelectors();
42292 return new LazyLoad({ 42293 elements_selector: '.js-lazy-img' 42294 }); 42295 }; 42296 42297 ChallengesCorona.prototype.bindPerPageSelectors = function() { 42298 return $(document).on('click', '.js-per-page', (function(_this) { 42299 return function(event) { 42300 var $perPageLink, params; 42301 mute(event); 42302 $perPageLink = $(event.currentTarget); 42303 $perPageLink.parents('.product-filters-footer__page-size').find('.is-active').removeClass('is-active'); 42304 $perPageLink.parent().addClass('is-active'); 42305 Cookies.set(_this.paginationCookieKey(), $perPageLink.text()); 42306 Cookies.set(gon.cookies_map.per_page_changed, true); 42307 params = new URLSearchParams(location.search); 42308 params.set('page', '1'); 42309 return window.location.search = params.toString(); 42310 }; 42311 })(this)); 42312 }; 42313 42314 ChallengesCorona.prototype.paginationCookieKey = function() { 42315 if (_.isEmpty($.deparam((window.location.search || "").replace(/^\?/, '')).keywords)) { 42316 return gon.cookies_map.items_listing_per_page; 42317 } else { 42318 return gon.cookies_map.items_search_per_page; 42319 } 42320 }; 42321 42322 return ChallengesCorona; 42323 42324 })(App.Core.Page); 42325 42326}).call(this); 42327(function() { 42328 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42329 hasProp = {}.hasOwnProperty; 42330 42331 App.Pages.ChallengesIndex = (function(superClass) { 42332 extend(ChallengesIndex, superClass); 42333 42334 function ChallengesIndex() { 42335 return ChallengesIndex.__super__.constructor.apply(this, arguments); 42336 } 42337 42338 ChallengesIndex.prototype.widgets = ['linkFaker']; 42339 42340 return ChallengesIndex; 42341 42342 })(App.Core.Page); 42343 42344}).call(this); 42345(function() { 42346 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42347 hasProp = {}.hasOwnProperty; 42348 42349 App.Pages.ChallengesShow = (function(superClass) { 42350 extend(ChallengesShow, superClass); 42351 42352 function ChallengesShow() { 42353 return ChallengesShow.__super__.constructor.apply(this, arguments); 42354 } 42355 42356 ChallengesShow.prototype.widgets = ['countdown', 'linkFaker']; 42357 42358 ChallengesShow.prototype.initialize = function() { 42359 return this.initTabs(); 42360 }; 42361 42362 ChallengesShow.prototype.initTabs = function() { 42363 var defaultTab, entryTab; 42364 entryTab = $('.challenge-tabs > ul > li > a[href="#section-entries"]'); 42365 defaultTab = entryTab.length ? entryTab.first().parent() : $('.challenge-tabs > ul > li').first(); 42366 return $('.challenge-tabs').easytabs({ 42367 animate: true, 42368 panelActiveClass: 'is-active', 42369 panelContext: $('.challenge-sections'), 42370 tabActiveClass: 'is-active', 42371 defaultTab: defaultTab 42372 }); 42373 }; 42374 42375 return ChallengesShow; 42376 42377 })(App.Core.Page); 42378 42379}).call(this); 42380(function() { 42381 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 42382 hasProp = {}.hasOwnProperty; 42383 42384 App.Pages.CheckoutOrderProcessingScreen = (function(superClass) { 42385 extend(CheckoutOrderProcessingScreen, superClass); 42386 42387 function CheckoutOrderProcessingScreen() { 42388 return CheckoutOrderProcessingScreen.__super__.constructor.apply(this, arguments); 42389 } 42390 42391 CheckoutOrderProcessingScreen.prototype.initialize = function() { 42392 return this.startPolling(); 42393 }; 42394 42395 CheckoutOrderProcessingScreen.prototype.startPolling = function() { 42396 var orderID; 42397 orderID = $('.js-loader-container').data('id'); 42398 return setInterval((function(_this) { 42399 return function() { 42400 return _this.checkStatus(orderID); 42401 }; 42402 })(this), 3000); 42403 }; 42404 42405 CheckoutOrderProcessingScreen.prototype.checkStatus = function(id) { 42406 var that; 42407 that = this; 42408 return $.ajax({ 42409 url: '/cg/checkout/check-order-status/' + id, 42410 success: function(response) { 42411 if (response.success) { 42412 return window.location = response.return_url; 42413 } 42414 } 42415 }); 42416 }; 42417 42418 return CheckoutOrderProcessingScreen; 42419 42420 })(App.Core.Page); 42421 42422}).call(this); 42423// Generated by CoffeeScript 1.7.1 42424(function() {
42425 var cardFromNumber, cardFromType, cards, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardNumber, formatExpiry, formatForwardExpiry, formatForwardSlashAndSpace, hasTextSelected, luhnCheck, reFormatCVC, reFormatCardNumber, reFormatExpiry, reFormatNumeric, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric, setCardType, 42426 __slice = [].slice, 42427 __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 42428 42429 $.payment = {}; 42430 42431 $.payment.fn = {}; 42432 42433 $.fn.payment = function() { 42434 var args, method; 42435 method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 42436 return $.payment.fn[method].apply(this, args); 42437 }; 42438 42439 defaultFormat = /(\d{1,4})/g; 42440 42441 $.payment.cards = cards = [ 42442 { 42443 type: 'visaelectron', 42444 pattern: /^4(026|17500|405|508|844|91[37])/, 42445 format: defaultFormat, 42446 length: [16], 42447 cvcLength: [3], 42448 luhn: true 42449 }, { 42450 type: 'maestro', 42451 pattern: /^(5(018|0[23]|[68])|6(39|7))/, 42452 format: defaultFormat, 42453 length: [12, 13, 14, 15, 16, 17, 18, 19], 42454 cvcLength: [3], 42455 luhn: true 42456 }, { 42457 type: 'forbrugsforeningen', 42458 pattern: /^600/, 42459 format: defaultFormat, 42460 length: [16], 42461 cvcLength: [3], 42462 luhn: true 42463 }, { 42464 type: 'dankort', 42465 pattern: /^5019/, 42466 format: defaultFormat, 42467 length: [16], 42468 cvcLength: [3], 42469 luhn: true 42470 }, { 42471 type: 'visa', 42472 pattern: /^4/, 42473 format: defaultFormat, 42474 length: [13, 16], 42475 cvcLength: [3], 42476 luhn: true 42477 }, { 42478 type: 'mastercard', 42479 pattern: /^(5[0-5]|2[2-7])/, 42480 format: defaultFormat, 42481 length: [16], 42482 cvcLength: [3], 42483 luhn: true 42484 }, { 42485 type: 'amex', 42486 pattern: /^3[47]/, 42487 format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/, 42488 length: [15], 42489 cvcLength: [3, 4], 42490 luhn: true 42491 }, { 42492 type: 'dinersclub', 42493 pattern: /^3[0689]/, 42494 format: /(\d{1,4})(\d{1,6})?(\d{1,4})?/, 42495 length: [14], 42496 cvcLength: [3], 42497 luhn: true 42498 }, { 42499 type: 'discover', 42500 pattern: /^6([045]|22)/, 42501 format: defaultFormat, 42502 length: [16], 42503 cvcLength: [3], 42504 luhn: true 42505 }, { 42506 type: 'unionpay', 42507 pattern: /^(62|88)/, 42508 format: defaultFormat, 42509 length: [16, 17, 18, 19], 42510 cvcLength: [3], 42511 luhn: false 42512 }, {
42513 type: 'jcb', 42514 pattern: /^35/, 42515 format: defaultFormat, 42516 length: [16], 42517 cvcLength: [3], 42518 luhn: true 42519 } 42520 ]; 42521 42522 cardFromNumber = function(num) { 42523 var card, _i, _len; 42524 num = (num + '').replace(/\D/g, ''); 42525 for (_i = 0, _len = cards.length; _i < _len; _i++) { 42526 card = cards[_i]; 42527 if (card.pattern.test(num)) { 42528 return card; 42529 } 42530 } 42531 }; 42532 42533 cardFromType = function(type) { 42534 var card, _i, _len; 42535 for (_i = 0, _len = cards.length; _i < _len; _i++) { 42536 card = cards[_i]; 42537 if (card.type === type) { 42538 return card; 42539 } 42540 } 42541 }; 42542 42543 luhnCheck = function(num) { 42544 var digit, digits, odd, sum, _i, _len; 42545 odd = true; 42546 sum = 0; 42547 digits = (num + '').split('').reverse(); 42548 for (_i = 0, _len = digits.length; _i < _len; _i++) { 42549 digit = digits[_i]; 42550 digit = parseInt(digit, 10); 42551 if ((odd = !odd)) { 42552 digit *= 2; 42553 } 42554 if (digit > 9) { 42555 digit -= 9; 42556 } 42557 sum += digit; 42558 } 42559 return sum % 10 === 0; 42560 }; 42561 42562 hasTextSelected = function($target) { 42563 var _ref; 42564 if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== $target.prop('selectionEnd')) { 42565 return true; 42566 } 42567 if ((typeof document !== "undefined" && document !== null ? (_ref = document.selection) != null ? _ref.createRange : void 0 : void 0) != null) { 42568 if (document.selection.createRange().text) { 42569 return true; 42570 } 42571 } 42572 return false; 42573 }; 42574 42575 reFormatNumeric = function(e) { 42576 return setTimeout(function() { 42577 var $target, value; 42578 $target = $(e.currentTarget); 42579 value = $target.val(); 42580 value = value.replace(/\D/g, ''); 42581 return $target.val(value); 42582 }); 42583 }; 42584 42585 reFormatCardNumber = function(e) { 42586 return setTimeout(function() { 42587 var $target, value; 42588 $target = $(e.currentTarget); 42589 value = $target.val(); 42590 value = $.payment.formatCardNumber(value); 42591 return $target.val(value); 42592 }); 42593 }; 42594 42595 formatCardNumber = function(e) { 42596 var $target, card, digit, length, re, upperLength, value; 42597 digit = String.fromCharCode(e.which); 42598 if (!/^\d+$/.test(digit)) { 42599 return; 42600 } 42601 $target = $(e.currentTarget); 42602 value = $target.val(); 42603 card = cardFromNumber(value + digit); 42604 length = (value.replace(/\D/g, '') + digit).length; 42605 upperLength = 16; 42606 if (card) { 42607 upperLength = card.length[card.length.length - 1]; 42608 } 42609 if (length >= upperLength) { 42610 return; 42611 } 42612 if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { 42613 return; 42614 } 42615 if (card && card.type === 'amex') { 42616 re = /^(\d{4}|\d{4}\s\d{6})$/; 42617 } else { 42618 re = /(?:^|\s)(\d{4})$/; 42619 } 42620 if (re.test(value)) { 42621 e.preventDefault(); 42622 return setTimeout(function() { 42623 return $target.val(value + ' ' + digit); 42624 }); 42625 } else if (re.test(value + digit)) { 42626 e.preventDefault(); 42627 return setTimeout(function() { 42628 return $target.val(value + digit + ' '); 42629 }); 42630 } 42631 }; 42632 42633 formatBackCardNumber = function(e) { 42634 var $target, value; 42635 $target = $(e.currentTarget); 42636 value = $target.val(); 42637 if (e.which !== 8) { 42638 return; 42639 } 42640 if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { 42641 return; 42642 } 42643 if (/\d\s$/.test(value)) { 42644 e.preventDefault(); 42645 return setTimeout(function() { 42646 return $target.val(value.replace(/\d\s$/, '')); 42647 }); 42648 } else if (/\s\d?$/.test(value)) { 42649 e.preventDefault(); 42650 return setTimeout(function() { 42651 return $target.val(value.replace(/\d$/, '')); 42652 }); 42653 } 42654 }; 42655 42656 reFormatExpiry = function(e) { 42657 return setTimeout(function() { 42658 var $target, value; 42659 $target = $(e.currentTarget); 42660 value = $target.val(); 42661 value = $.payment.formatExpiry(value); 42662 return $target.val(value); 42663 }); 42664 }; 42665 42666 formatExpiry = function(e) { 42667 var $target, digit, val; 42668 digit = String.fromCharCode(e.which); 42669 if (!/^\d+$/.test(digit)) { 42670 return; 42671 } 42672 $target = $(e.currentTarget); 42673 val = $target.val() + digit; 42674 if (/^\d$/.test(val) && (val !== '0' && val !== '1')) { 42675 e.preventDefault(); 42676 return setTimeout(function() { 42677 return $target.val("0" + val + " / "); 42678 }); 42679 } else if (/^\d\d$/.test(val)) { 42680 e.preventDefault(); 42681 return setTimeout(function() { 42682 return $target.val("" + val + " / "); 42683 }); 42684 } 42685 }; 42686 42687 formatForwardExpiry = function(e) { 42688 var $target, digit, val; 42689 digit = String.fromCharCode(e.which); 42690 if (!/^\d+$/.test(digit)) { 42691 return; 42692 } 42693 $target = $(e.currentTarget); 42694 val = $target.val(); 42695 if (/^\d\d$/.test(val)) { 42696 return $target.val("" + val + " / "); 42697 } 42698 }; 42699 42700 formatForwardSlashAndSpace = function(e) { 42701 var $target, val, which; 42702 which = String.fromCharCode(e.which); 42703 if (!(which === '/' || which === ' ')) { 42704 return; 42705 } 42706 $target = $(e.currentTarget); 42707 val = $target.val(); 42708 if (/^\d$/.test(val) && val !== '0') { 42709 return $target.val("0" + val + " / "); 42710 } 42711 }; 42712 42713 formatBackExpiry = function(e) { 42714 var $target, value; 42715 $target = $(e.currentTarget); 42716 value = $target.val(); 42717 if (e.which !== 8) { 42718 return; 42719 } 42720 if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { 42721 return; 42722 } 42723 if (/\d\s\/\s$/.test(value)) { 42724 e.preventDefault(); 42725 return setTimeout(function() { 42726 return $target.val(value.replace(/\d\s\/\s$/, '')); 42727 }); 42728 } 42729 }; 42730 42731 reFormatCVC = function(e) { 42732 return setTimeout(function() { 42733 var $target, value; 42734 $target = $(e.currentTarget); 42735 value = $target.val(); 42736 value = value.replace(/\D/g, '').slice(0, 4); 42737 return $target.val(value); 42738 }); 42739 }; 42740 42741 restrictNumeric = function(e) { 42742 var input; 42743 if (e.metaKey || e.ctrlKey) { 42744 return true; 42745 } 42746 if (e.which === 32) { 42747 return false;
42748 } 42749 if (e.which === 0) { 42750 return true; 42751 } 42752 if (e.which < 33) { 42753 return true; 42754 } 42755 input = String.fromCharCode(e.which); 42756 return !!/[\d\s]/.test(input); 42757 }; 42758 42759 restrictCardNumber = function(e) { 42760 var $target, card, digit, value; 42761 $target = $(e.currentTarget); 42762 digit = String.fromCharCode(e.which); 42763 if (!/^\d+$/.test(digit)) { 42764 return; 42765 } 42766 if (hasTextSelected($target)) { 42767 return; 42768 } 42769 value = ($target.val() + digit).replace(/\D/g, ''); 42770 card = cardFromNumber(value); 42771 if (card) { 42772 return value.length <= card.length[card.length.length - 1]; 42773 } else { 42774 return value.length <= 16; 42775 } 42776 }; 42777 42778 restrictExpiry = function(e) { 42779 var $target, digit, value; 42780 $target = $(e.currentTarget); 42781 digit = String.fromCharCode(e.which); 42782 if (!/^\d+$/.test(digit)) { 42783 return; 42784 } 42785 if (hasTextSelected($target)) { 42786 return; 42787 } 42788 value = $target.val() + digit; 42789 value = value.replace(/\D/g, ''); 42790 if (value.length > 6) { 42791 return false; 42792 } 42793 }; 42794 42795 restrictCVC = function(e) { 42796 var $target, digit, val; 42797 $target = $(e.currentTarget); 42798 digit = String.fromCharCode(e.which); 42799 if (!/^\d+$/.test(digit)) { 42800 return; 42801 } 42802 if (hasTextSelected($target)) { 42803 return; 42804 } 42805 val = $target.val() + digit; 42806 return val.length <= 4; 42807 }; 42808 42809 setCardType = function(e) { 42810 var $target, allTypes, card, cardType, val; 42811 $target = $(e.currentTarget); 42812 val = $target.val(); 42813 cardType = $.payment.cardType(val) || 'unknown'; 42814 if (!$target.hasClass(cardType)) { 42815 allTypes = (function() { 42816 var _i, _len, _results; 42817 _results = []; 42818 for (_i = 0, _len = cards.length; _i < _len; _i++) { 42819 card = cards[_i]; 42820 _results.push(card.type); 42821 } 42822 return _results; 42823 })(); 42824 $target.removeClass('unknown'); 42825 $target.removeClass(allTypes.join(' ')); 42826 $target.addClass(cardType); 42827 $target.toggleClass('identified', cardType !== 'unknown'); 42828 return $target.trigger('payment.cardType', cardType); 42829 } 42830 }; 42831 42832 $.payment.fn.formatCardCVC = function() { 42833 this.on('keypress', restrictNumeric); 42834 this.on('keypress', restrictCVC); 42835 this.on('paste', reFormatCVC); 42836 this.on('change', reFormatCVC); 42837 this.on('input', reFormatCVC); 42838 return this; 42839 }; 42840 42841 $.payment.fn.formatCardExpiry = function() { 42842 this.on('keypress', restrictNumeric); 42843 this.on('keypress', restrictExpiry); 42844 this.on('keypress', formatExpiry); 42845 this.on('keypress', formatForwardSlashAndSpace); 42846 this.on('keypress', formatForwardExpiry); 42847 this.on('keydown', formatBackExpiry); 42848 this.on('change', reFormatExpiry); 42849 this.on('input', reFormatExpiry); 42850 return this; 42851 }; 42852 42853 $.payment.fn.formatCardNumber = function() { 42854 this.on('keypress', restrictNumeric); 42855 this.on('keypress', restrictCardNumber); 42856 this.on('keypress', formatCardNumber); 42857 this.on('keydown', formatBackCardNumber); 42858 this.on('keyup', setCardType); 42859 this.on('paste', reFormatCardNumber); 42860 this.on('change', reFormatCardNumber); 42861 this.on('input', reFormatCardNumber); 42862 this.on('input', setCardType); 42863 return this; 42864 }; 42865 42866 $.payment.fn.restrictNumeric = function() { 42867 this.on('keypress', restrictNumeric); 42868 this.on('paste', reFormatNumeric); 42869 this.on('change', reFormatNumeric); 42870 this.on('input', reFormatNumeric); 42871 return this; 42872 }; 42873 42874 $.payment.fn.cardExpiryVal = function() { 42875 return $.payment.cardExpiryVal($(this).val()); 42876 }; 42877 42878 $.payment.cardExpiryVal = function(value) { 42879 var month, prefix, year, _ref; 42880 value = value.replace(/\s/g, ''); 42881 _ref = value.split('/', 2), month = _ref[0], year = _ref[1]; 42882 if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) { 42883 prefix = (new Date).getFullYear(); 42884 prefix = prefix.toString().slice(0, 2); 42885 year = prefix + year; 42886 } 42887 month = parseInt(month, 10); 42888 year = parseInt(year, 10); 42889 return { 42890 month: month, 42891 year: year 42892 }; 42893 }; 42894 42895 $.payment.validateCardNumber = function(num) { 42896 var card, _ref; 42897 num = (num + '').replace(/\s+|-/g, ''); 42898 if (!/^\d+$/.test(num)) { 42899 return false;
42900 } 42901 card = cardFromNumber(num); 42902 if (!card) { 42903 return false; 42904 } 42905 return (_ref = num.length, __indexOf.call(card.length, _ref) >= 0) && (card.luhn === false || luhnCheck(num)); 42906 }; 42907 42908 $.payment.validateCardExpiry = function(month, year) { 42909 var currentTime, expiry, _ref; 42910 if (typeof month === 'object' && 'month' in month) { 42911 _ref = month, month = _ref.month, year = _ref.year; 42912 } 42913 if (!(month && year)) { 42914 return false; 42915 } 42916 month = $.trim(month); 42917 year = $.trim(year); 42918 if (!/^\d+$/.test(month)) { 42919 return false; 42920 } 42921 if (!/^\d+$/.test(year)) { 42922 return false; 42923 } 42924 if (!((1 <= month && month <= 12))) { 42925 return false; 42926 } 42927 if (year.length === 2) { 42928 if (year < 70) { 42929 year = "20" + year; 42930 } else { 42931 year = "19" + year; 42932 } 42933 } 42934 if (year.length !== 4) { 42935 return false; 42936 } 42937 expiry = new Date(year, month); 42938 currentTime = new Date; 42939 expiry.setMonth(expiry.getMonth() - 1); 42940 expiry.setMonth(expiry.getMonth() + 1, 1); 42941 return expiry > currentTime; 42942 }; 42943 42944 $.payment.validateCardCVC = function(cvc, type) { 42945 var card, _ref; 42946 cvc = $.trim(cvc); 42947 if (!/^\d+$/.test(cvc)) { 42948 return false; 42949 } 42950 card = cardFromType(type); 42951 if (card != null) { 42952 return _ref = cvc.length, __indexOf.call(card.cvcLength, _ref) >= 0; 42953 } else { 42954 return cvc.length >= 3 && cvc.length <= 4; 42955 } 42956 }; 42957 42958 $.payment.cardType = function(num) { 42959 var _ref; 42960 if (!num) { 42961 return null; 42962 } 42963 return ((_ref = cardFromNumber(num)) != null ? _ref.type : void 0) || null; 42964 }; 42965 42966 $.payment.formatCardNumber = function(num) { 42967 var card, groups, upperLength, _ref; 42968 num = num.replace(/\D/g, ''); 42969 card = cardFromNumber(num); 42970 if (!card) { 42971 return num; 42972 } 42973 upperLength = card.length[card.length.length - 1]; 42974 num = num.slice(0, upperLength); 42975 if (card.format.global) { 42976 return (_ref = num.match(card.format)) != null ? _ref.join(' ') : void 0; 42977 } else { 42978 groups = card.format.exec(num); 42979 if (groups == null) { 42980 return; 42981 } 42982 groups.shift(); 42983 groups = $.grep(groups, function(n) { 42984 return n; 42985 }); 42986 return groups.join(' '); 42987 } 42988 }; 42989 42990 $.payment.formatExpiry = function(expiry) { 42991 var mon, parts, sep, year; 42992 parts = expiry.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/); 42993 if (!parts) { 42994 return ''; 42995 } 42996 mon = parts[1] || ''; 42997 sep = parts[2] || ''; 42998 year = parts[3] || ''; 42999 if (year.length > 0) { 43000 sep = ' / '; 43001 } else if (sep === ' /') { 43002 mon = mon.substring(0, 1); 43003 sep = ''; 43004 } else if (mon.length === 2 || sep.length > 0) { 43005 sep = ' / '; 43006 } else if (mon.length === 1 && (mon !== '0' && mon !== '1')) { 43007 mon = "0" + mon; 43008 sep = ' / '; 43009 } 43010 return mon + sep + year; 43011 }; 43012 43013}).call(this); 43014(function() { 43015 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 43016 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 43017 hasProp = {}.hasOwnProperty; 43018 43019 App.Pages.CheckoutPayment = (function(superClass) { 43020 var prepareTrackViewItemList; 43021 43022 extend(CheckoutPayment, superClass); 43023 43024 function CheckoutPayment() { 43025 this.checkFormValidation = bind(this.checkFormValidation, this); 43026 this.openRequiredTab = bind(this.openRequiredTab, this); 43027 this.openGuestModal = bind(this.openGuestModal, this); 43028 this.switchTab = bind(this.switchTab, this); 43029 this.onCountrySelect = bind(this.onCountrySelect, this); 43030 this.onV2CompanyToggle = bind(this.onV2CompanyToggle, this); 43031 this.onCompanyToggle = bind(this.onCompanyToggle, this); 43032 this.onDiscountTriggerV3 = bind(this.onDiscountTriggerV3, this); 43033 this.onDiscountTriggerV2 = bind(this.onDiscountTriggerV2, this); 43034 this.onDiscountTrigger = bind(this.onDiscountTrigger, this); 43035 this.trackCartRemove = bind(this.trackCartRemove, this); 43036 this.handleRequestInvoiceError = bind(this.handleRequestInvoiceError, this); 43037 this.handleRequestInvoiceSuccess = bind(this.handleRequestInvoiceSuccess, this); 43038 this.handleCartShareError = bind(this.handleCartShareError, this); 43039 this.handleCartShareSuccess = bind(this.handleCartShareSuccess, this); 43040 this.bindRequestInvoiceFormEvents = bind(this.bindRequestInvoiceFormEvents, this); 43041 this.bindShareableCartFormEvents = bind(this.bindShareableCartFormEvents, this); 43042 this.initRequestInvoiceValidation = bind(this.initRequestInvoiceValidation, this); 43043 this.initShareCartValidation = bind(this.initShareCartValidation, this); 43044 this.openRequestInvoiceModal = bind(this.openRequestInvoiceModal, this); 43045 this.openShareableCartModal = bind(this.openShareableCartModal, this); 43046 this.bindShareableCartModal = bind(this.bindShareableCartModal, this); 43047 this.bindRequestInvoiceModal = bind(this.bindRequestInvoiceModal, this); 43048 return CheckoutPayment.__super__.constructor.apply(this, arguments); 43049 } 43050 43051 CheckoutPayment.prototype.widgets = ['storeCreditsInfoTooltip', 'vatTaxTooltip', 'creditsUsedInfoTooltip', 'postalCodeTooltip', 'CVCTooltip', 'V2WishLists']; 43052 43053 CheckoutPayment.prototype.initialize = function() { 43054 this.cacheDom(); 43055 this.$discountForm = $('.checkout-discount-form').find('form'); 43056 this.initEditCartTrigger(); 43057 this.bindShareableCartModal(); 43058 this.bindRequestInvoiceModal(); 43059 this.bindSpinnerForItemRemove(); 43060 this.bindCheckoutClick(); 43061 this.disableItemOnRemove(); 43062 this.bindSpinnerForPaypalPurchase(); 43063 this.handleCouponPurchase(); 43064 this.initDiscountTrigger(); 43065 this.initDiscountTriggerV2(); 43066 this.initDiscountTriggerV3(); 43067 this.initValidation(); 43068 this.initBuyerType(); 43069 this.initCountrySelection(); 43070 if (gon.edit_cart) { 43071 this.initEditCartMode(); 43072 } 43073 this.bindApplyCompanyInformation(); 43074 this.initShareCartValidation(); 43075 this.initRequestInvoiceValidation(); 43076 this.bindTabClick(); 43077 this.bindGuestModalOpen(); 43078 this.openRequiredTab(); 43079 return this.initStreetAddressCounter(); 43080 }; 43081 43082 CheckoutPayment.prototype.cacheDom = function() {
43083 this.$shareCartModal = $("#modal-share-cart"); 43084 return this.$requestInvoiceModal = $("#modal-request-invoice"); 43085 }; 43086 43087 CheckoutPayment.prototype.bindRequestInvoiceModal = function() { 43088 if (!(this.$requestInvoiceModal.length > 0)) { 43089 return; 43090 } 43091 this.$requestForm = this.$requestInvoiceModal.find('#request-invoice-form'); 43092 return $('.js-checkout-request-invoice').on('click', this.openRequestInvoiceModal); 43093 }; 43094 43095 CheckoutPayment.prototype.bindShareableCartModal = function() { 43096 if (!(this.$shareCartModal.length > 0)) { 43097 return; 43098 } 43099 this.$shareForm = this.$shareCartModal.find('#share-cart-form'); 43100 return $('.js-checkout-cart-share').on('click', this.openShareableCartModal); 43101 }; 43102 43103 CheckoutPayment.prototype.openShareableCartModal = function() { 43104 this.$shareCartModal.makeMeModal(); 43105 return this.bindShareableCartFormEvents(); 43106 }; 43107 43108 CheckoutPayment.prototype.openRequestInvoiceModal = function() { 43109 this.$requestInvoiceModal.makeMeModal(); 43110 return this.bindRequestInvoiceFormEvents(); 43111 }; 43112 43113 CheckoutPayment.prototype.shareCartValidationSettings = function() { 43114 return { 43115 focusInvalid: false, 43116 rules: { 43117 email: { 43118 required: true, 43119 email: true 43120 } 43121 } 43122 }; 43123 }; 43124 43125 CheckoutPayment.prototype.requestInvoiceValidationSettings = function() { 43126 return { 43127 focusInvalid: false, 43128 rules: { 43129 email: { 43130 required: true, 43131 email: true 43132 }, 43133 message: { 43134 required: true 43135 } 43136 } 43137 }; 43138 }; 43139 43140 CheckoutPayment.prototype.initShareCartValidation = function() { 43141 if (this.$shareForm) { 43142 return this.$shareForm.validate(this.shareCartValidationSettings()); 43143 } 43144 }; 43145 43146 CheckoutPayment.prototype.initRequestInvoiceValidation = function() { 43147 if (this.$requestForm) { 43148 return this.$requestForm.validate(this.requestInvoiceValidationSettings()); 43149 } 43150 }; 43151 43152 CheckoutPayment.prototype.bindShareableCartFormEvents = function() { 43153 this.$shareForm.off('ajax:success').on('ajax:success', this.handleCartShareSuccess); 43154 return this.$shareForm.off('ajax:error').on('ajax:error', this.handleCartShareError); 43155 }; 43156 43157 CheckoutPayment.prototype.bindRequestInvoiceFormEvents = function() { 43158 this.$requestForm.off('ajax:success').on('ajax:success', this.handleRequestInvoiceSuccess); 43159 return this.$requestForm.off('ajax:error').on('ajax:error', this.handleRequestInvoiceError); 43160 }; 43161 43162 CheckoutPayment.prototype.handleCartShareSuccess = function(e, data, status, xhr) { 43163 if (data.success) { 43164 App.events.publish('app:notification:flash:success', data.message); 43165 } else { 43166 App.events.publish('app:notification:flash:error', data.message); 43167 } 43168 return this.$shareCartModal.makeMeModal('close'); 43169 }; 43170 43171 CheckoutPayment.prototype.handleCartShareError = function() { 43172 App.events.publish('app:notification:flash:error', 'Oops. Something went wrong.'); 43173 return this.$shareCartModal.makeMeModal('close'); 43174 }; 43175 43176 CheckoutPayment.prototype.handleRequestInvoiceSuccess = function(e, data, status, xhr) { 43177 if (data.success) { 43178 App.events.publish('app:notification:flash:success', data.message); 43179 } else { 43180 App.events.publish('app:notification:flash:error', data.message); 43181 } 43182 return this.$requestInvoiceModal.makeMeModal('close'); 43183 }; 43184 43185 CheckoutPayment.prototype.handleRequestInvoiceError = function() { 43186 App.events.publish('app:notification:flash:error', 'Oops. Something went wrong.'); 43187 return this.$requestInvoiceModal.makeMeModal('close'); 43188 }; 43189 43190 CheckoutPayment.prototype.bindApplyCompanyInformation = function() { 43191 return $('.js-apply-company-information').on('click', (function(_this) { 43192 return function() { 43193 $('.js-company-details').addClass('is-updating-with-spinner'); 43194 return $('.js-apply-company-information-hidden-field').val(true); 43195 }; 43196 })(this)); 43197 }; 43198 43199 CheckoutPayment.prototype.bindCheckoutClick = function() { 43200 var element; 43201 element = $('.js-checkout-click'); 43202 element.on("auxclick", function(event) { 43203 var data, list; 43204 if (event.button === 1) { 43205 list = []; 43206 for (data in gon.cart_items) { 43207 list.push(prepareTrackViewItemList(gon.cart_items[data])); 43208 continue; 43209 } 43210 if (window.dataLayer && list.length > 0) { 43211 return window.dataLayer.push({ 43212 event: 'begin_checkout', 43213 ecommerce: { 43214 currency: 'USD', 43215 value: gon.cart.value, 43216 items: list 43217 } 43218 }); 43219 } 43220 } 43221 }); 43222 return element.on('click', function(e) { 43223 var data, list; 43224 list = []; 43225 for (data in gon.cart_items) { 43226 list.push(prepareTrackViewItemList(gon.cart_items[data])); 43227 continue; 43228 } 43229 if (window.dataLayer && list.length > 0) { 43230 return window.dataLayer.push({ 43231 event: 'begin_checkout', 43232 ecommerce: { 43233 currency: 'USD', 43234 value: gon.cart.value, 43235 items: list 43236 } 43237 }); 43238 } 43239 }); 43240 }; 43241 43242 CheckoutPayment.prototype.bindSpinnerForItemRemove = function() { 43243 return $('.js-remove-from-cart').on('click', function(e) { 43244 return $(e.currentTarget).closest('.product-list__item').addClass('is-updating-with-spinner spinner--horizontal'); 43245 }); 43246 }; 43247 43248 CheckoutPayment.prototype.trackCartRemove = function(e) { 43249 var items, obj, targetObj; 43250 if (window.dataLayer) { 43251 targetObj = ((function() { 43252 var i, len, ref, results; 43253 ref = gon.cart_items; 43254 results = []; 43255 for (i = 0, len = ref.length; i < len; i++) { 43256 obj = ref[i]; 43257 if (obj.id === $(e.currentTarget).data('itemId')) { 43258 results.push(obj); 43259 } 43260 } 43261 return results; 43262 })())[0]; 43263 items = prepareTrackViewItemList(targetObj); 43264 return window.dataLayer.push({ 43265 event: 'remove_from_cart', 43266 user_id: App.config.userId || '', 43267 ecommerce: { 43268 currency: 'USD', 43269 value: items.price, 43270 items: items 43271 }, 43272 _clear: true 43273 }); 43274 } 43275 }; 43276 43277 CheckoutPayment.prototype.disableItemOnRemove = function() { 43278 var that; 43279 that = this; 43280 return $('.js-v2-remove-from-cart').on('click', function(e) { 43281 that.trackCartRemove(e); 43282 $(e.currentTarget).closest('.cgt-item-card').addClass('is-updating'); 43283 return App.events.publish("app:notification:flash:success", 'Item was removed from cart'); 43284 }); 43285 }; 43286 43287 CheckoutPayment.prototype.bindSpinnerForPaypalPurchase = function() { 43288 var that; 43289 that = this; 43290 return $('.js-payment-confirmation').on('click', function() { 43291 that.trackOtpPayClick('paypal'); 43292 return $('.js-payment-methods').addClass('is-updating-with-spinner'); 43293 }); 43294 }; 43295 43296 CheckoutPayment.prototype.handleCouponPurchase = function() { 43297 var that; 43298 that = this; 43299 return $('.js-payment-confirmation-v2').on('click', function() { 43300 that.trackOtpPayClick('coupon'); 43301 return $('.js-payment-coupon-form-v2 form').submit(); 43302 }); 43303 }; 43304 43305 CheckoutPayment.prototype.initEditCartMode = function() { 43306 $('.js-checkout-cart-edit').remove(); 43307 return $('.js-remove-from-cart').show(); 43308 }; 43309 43310 CheckoutPayment.prototype.initEditCartTrigger = function() { 43311 return $('.js-checkout-cart-edit').on('click', this.onEditCartTrigger); 43312 }; 43313 43314 CheckoutPayment.prototype.initDiscountTrigger = function() { 43315 return $('.checkout-content').on('click', '.checkout-discount-form-trigger', this.onDiscountTrigger); 43316 }; 43317 43318 CheckoutPayment.prototype.initDiscountTriggerV2 = function() { 43319 $('.js-checkout-apply-enterprise-coupon').on('change', this.onDiscountTriggerV2); 43320 return $('.js-coupon-form-toggle').on('click', this.toggleCouponForm); 43321 }; 43322 43323 CheckoutPayment.prototype.initDiscountTriggerV3 = function() { 43324 return $('.js-business-account-apply').on('change', this.onDiscountTriggerV3); 43325 }; 43326 43327 CheckoutPayment.prototype.validationSettings = function() { 43328 return { 43329 focusInvalid: false, 43330 rules: { 43331 coupon_code: { 43332 required: true 43333 } 43334 }, 43335 messages: { 43336 coupon_code: { 43337 required: "Discount code can't be blank" 43338 } 43339 }, 43340 errorPlacement: function(error, element) { 43341 if (element.attr('name') === 'coupon_code') { 43342 return error.insertAfter('.js-checkout-payment-apply-coupon'); 43343 } else { 43344 return error.insertAfter(element); 43345 } 43346 } 43347 }; 43348 }; 43349 43350 CheckoutPayment.prototype.initValidation = function() { 43351 return this.$discountForm.validate(this.validationSettings()); 43352 }; 43353 43354 CheckoutPayment.prototype.initBuyerType = function() {
43355 $('.js-checkout-vat-company-details-toggle').on('change', this.onCompanyToggle); 43356 $('.js-company-details-toggle').on('change', this.onV2CompanyToggle); 43357 this.$buyerType = $('#buyer_type'); 43358 this.$companyForm = $('.billing-address-container'); 43359 this.$v2CompanyForm = $('.js-company-details-card'); 43360 this.$companyAlert = $('.js-company-alert'); 43361 this.$v2PaymentForm = $('.js-adyen-form-container, .js-braintree-form-container'); 43362 if ($('.js-checkout-vat-company-details-toggle').is(':checked')) { 43363 this.$companyForm.hide().removeClass('is-hidden').slideDown(); 43364 } 43365 if ($('.js-company-details-toggle').is(':checked')) { 43366 this.$v2CompanyForm.removeClass('is-collapsed'); 43367 if (this.$companyAlert.data('errors')) { 43368 return this.$v2PaymentForm.addClass('is-disabled'); 43369 } 43370 } 43371 }; 43372 43373 CheckoutPayment.prototype.initCountrySelection = function() { 43374 this.$countrySelectField = $('#billing_address_country'); 43375 this.$usStateSelectField = $('.us-state-selector'); 43376 this.$canadaStateSelectField = $('.ca-state-selector'); 43377 this.$indiaStateSelectField = $('.in-state-selector'); 43378 if (this.$countrySelectField.val() !== 'us') { 43379 this.$usStateSelectField.addClass('is-hidden'); 43380 } 43381 if (this.$countrySelectField.val() !== 'ca') { 43382 this.$canadaStateSelectField.addClass('is-hidden'); 43383 } 43384 if (this.$countrySelectField.val() !== 'in') { 43385 this.$indiaStateSelectField.addClass('is-hidden'); 43386 } 43387 return this.$countrySelectField.on('change', this.onCountrySelect); 43388 }; 43389 43390 CheckoutPayment.prototype.onEditCartTrigger = function() { 43391 $('.js-checkout-cart-edit').remove(); 43392 return $('.js-remove-from-cart').show(); 43393 }; 43394 43395 CheckoutPayment.prototype.onDiscountTrigger = function(e) { 43396 var $el; 43397 $el = $(e.currentTarget); 43398 return $el.fadeOut().promise().done(function() { 43399 return $('.checkout-discount-form').fadeIn(); 43400 }); 43401 }; 43402 43403 CheckoutPayment.prototype.onDiscountTriggerV2 = function(e) { 43404 if (e.currentTarget.checked) { 43405 return $('.js-checkout-enterprise-coupon-form').submit(); 43406 } 43407 }; 43408 43409 CheckoutPayment.prototype.onDiscountTriggerV3 = function(e) { 43410 if (e.currentTarget.checked) { 43411 return $('.js-checkout-business-account-form').submit(); 43412 } 43413 }; 43414 43415 CheckoutPayment.prototype.toggleCouponForm = function() { 43416 return $('.js-coupon-form').toggleClass('is-collapsed'); 43417 }; 43418 43419 CheckoutPayment.prototype.onCompanyToggle = function() { 43420 if (this.$companyForm.hasClass('is-hidden')) { 43421 return this.buyerIsCompany(); 43422 } else { 43423 $('.js-company-details').addClass('is-updating-with-spinner'); 43424 return this.buyerIsPerson(); 43425 } 43426 }; 43427 43428 CheckoutPayment.prototype.onV2CompanyToggle = function() { 43429 if (this.$v2CompanyForm.hasClass('is-collapsed')) { 43430 return this.buyerIsCompany(); 43431 } else { 43432 return this.buyerIsPerson(); 43433 } 43434 }; 43435 43436 CheckoutPayment.prototype.onCountrySelect = function() { 43437 this.$usStateSelectField.addClass('is-hidden'); 43438 this.$canadaStateSelectField.addClass('is-hidden'); 43439 this.$indiaStateSelectField.addClass('is-hidden'); 43440 if (this.$countrySelectField.val() === 'us') { 43441 this.$usStateSelectField.removeClass('is-hidden'); 43442 } 43443 if (this.$countrySelectField.val() === 'ca') { 43444 this.$canadaStateSelectField.removeClass('is-hidden'); 43445 } 43446 if (this.$countrySelectField.val() === 'in') { 43447 return this.$indiaStateSelectField.removeClass('is-hidden'); 43448 } 43449 }; 43450 43451 CheckoutPayment.prototype.buyerIsCompany = function() { 43452 var value; 43453 this.$buyerType.val('business'); 43454 this.$companyForm.hide().removeClass('is-hidden').slideDown(); 43455 this.$v2CompanyForm.removeClass('is-collapsed'); 43456 value = $('.js-apply-company-information-hidden-field').val(); 43457 if (!!value) { 43458 this.checkFormValidation(); 43459 } 43460 if (this.$companyAlert.data('errors')) { 43461 return this.$v2PaymentForm.addClass('is-disabled'); 43462 } 43463 }; 43464 43465 CheckoutPayment.prototype.buyerIsPerson = function() { 43466 this.$buyerType.val('person'); 43467 $('.js-apply-company-information').click(); 43468 this.$v2CompanyForm.addClass('is-collapsed'); 43469 this.$companyAlert.addClass('is-alert-row-hidden'); 43470 return this.$v2PaymentForm.removeClass('is-disabled'); 43471 }; 43472 43473 CheckoutPayment.prototype.bindTabClick = function() { 43474 return $('.js-tab').on('click', this.switchTab); 43475 }; 43476 43477 CheckoutPayment.prototype.bindGuestModalOpen = function() { 43478 return $('.js-guest-checkout-click').on('click', this.openGuestModal); 43479 }; 43480 43481 CheckoutPayment.prototype.switchTab = function(e) { 43482 e.preventDefault(); 43483 e.stopPropagation(); 43484 this.$tab = $(e.currentTarget); 43485 if (this.$tab.hasClass('cgt-tab--active')) { 43486 43487 } else { 43488 this.hideTabs(); 43489 this.displayTab(this.$tab.data("tab")); 43490 if (e.target.dataset['tab'] === 'payment') { 43491 return this.trackCartToPayment(); 43492 } 43493 } 43494 }; 43495 43496 CheckoutPayment.prototype.openGuestModal = function(e) { 43497 e.preventDefault(); 43498 e.stopPropagation(); 43499 return App.events.publish('app:guest:modal:open', e); 43500 }; 43501 43502 CheckoutPayment.prototype.trackCartToPayment = function() { 43503 return $.ajax({ 43504 url: '/cg/checkout/track-cart-to-payment-step', 43505 type: 'PUT' 43506 }); 43507 }; 43508 43509 CheckoutPayment.prototype.trackCartToLogin = function() { 43510 return $.ajax({ 43511 url: '/cg/checkout/track-cart-to-login-step', 43512 type: 'PUT' 43513 }); 43514 }; 43515 43516 CheckoutPayment.prototype.trackPaymentVisit = function() { 43517 return $.ajax({ 43518 url: '/cg/checkout/track-payment-visit', 43519 type: 'PUT' 43520 }); 43521 }; 43522 43523 CheckoutPayment.prototype.trackCartVisit = function() { 43524 var data, list; 43525 if (gon.cart_items) { 43526 list = []; 43527 for (data in gon.cart_items) { 43528 list.push(prepareTrackViewItemList(gon.cart_items[data])); 43529 continue; 43530 } 43531 if (window.dataLayer && list.length > 0) { 43532 return window.dataLayer.push({ 43533 event: 'view_cart', 43534 ecommerce: { 43535 currency: 'USD', 43536 value: gon.cart.value, 43537 items: list 43538 } 43539 }); 43540 } 43541 } 43542 }; 43543 43544 CheckoutPayment.prototype.trackOtpCheckoutViewed = function() { 43545 var checkoutSource, eventPayload; 43546 checkoutSource = gon.is_buy_now ? 'buy_now' : 'cart'; 43547 eventPayload = { 43548 name: 'one_time_purchase_checkout_viewed', 43549 eventData: { 43550 event_source: checkoutSource 43551 } 43552 }; 43553 if (window.customEventTracker) { 43554 return window.customEventTracker(eventPayload); 43555 } else { 43556 return App.events.subscribe('app:tracking:load', function() { 43557 return window.customEventTracker(eventPayload); 43558 }); 43559 } 43560 }; 43561 43562 CheckoutPayment.prototype.trackOtpPayClick = function(paymentMethod) { 43563 var checkoutSource, eventPayload; 43564 checkoutSource = gon.is_buy_now ? 'buy_now' : 'cart'; 43565 eventPayload = { 43566 name: 'one_time_purchase_pay_click', 43567 eventData: { 43568 event_source: checkoutSource, 43569 payment_method: paymentMethod 43570 } 43571 }; 43572 if (window.customEventTracker) { 43573 return window.customEventTracker(eventPayload); 43574 } 43575 }; 43576 43577 CheckoutPayment.prototype.openRequiredTab = function() { 43578 var error, requestedTab; 43579 requestedTab = App.config.viewerId ? window.location.hash === '#cart' ? '#cart' : '#payment' : window.location.hash === '#cart' ? '#cart' : ($('body').addClass('show-payment'), App.events.publish('app:guest:modal:required'), '#cart');
43580 try { 43581 if (!App.config.viewerId) { 43582 this.removeReactModalClass(); 43583 } 43584 } catch (error1) { 43585 error = error1; 43586 window.Sentry.captureException(error); 43587 } 43588 try { 43589 return this.displayTab(requestedTab.replace('#', '')); 43590 } catch (error1) { 43591 error = error1; 43592 return window.Sentry.captureException(error); 43593 } 43594 }; 43595 43596 CheckoutPayment.prototype.hideTabs = function() { 43597 $('.cgt-tab-content.is-active').removeClass('is-active'); 43598 return $('.cgt-tab.cgt-tab--active').removeClass('cgt-tab--active'); 43599 }; 43600 43601 CheckoutPayment.prototype.displayTab = function(tab) { 43602 if (!tab) { 43603 window.Sentry.captureException(new Error('No tab value provided to "displayTab" function!')); 43604 } 43605 if (tab === 'payment') { 43606 this.trackPaymentVisit(); 43607 this.trackOtpCheckoutViewed(); 43608 } 43609 if (tab === 'cart') { 43610 this.trackCartVisit(); 43611 } 43612 window.location.hash = tab; 43613 $('.js-loader-container').hide(); 43614 $('.cgt-tab[data-tab=' + tab + ']').addClass('cgt-tab--active'); 43615 return $('#' + tab).addClass('is-active'); 43616 }; 43617 43618 CheckoutPayment.prototype.removeReactModalClass = function() { 43619 var removeClass; 43620 return removeClass = setInterval(function() { 43621 if ($('body').hasClass('ReactModal__Body--open')) { 43622 $('body').removeClass('ReactModal__Body--open'); 43623 return clearInterval(removeClass); 43624 } 43625 }, 500); 43626 }; 43627 43628 CheckoutPayment.prototype.checkFormValidation = function() { 43629 this.$v2PaymentForm.addClass('is-disabled'); 43630 return this.$companyAlert.removeClass('is-alert-row-hidden'); 43631 }; 43632 43633 CheckoutPayment.prototype.initStreetAddressCounter = function() { 43634 var $count, $counter, $input, maxLength, updateCounter, warningThreshold;
43635 $input = $('.js-street-address-input'); 43636 $counter = $('.js-street-address-counter'); 43637 $count = $('.js-street-address-count'); 43638 maxLength = 200; 43639 warningThreshold = 180; 43640 updateCounter = function() { 43641 var length, ref; 43642 length = ((ref = $input.val()) != null ? ref.length : void 0) || 0; 43643 $count.text(length); 43644 $counter.removeClass('street-address-counter--warning street-address-counter--danger'); 43645 if (length >= maxLength) { 43646 return $counter.addClass('street-address-counter--danger'); 43647 } else if (length >= warningThreshold) { 43648 return $counter.addClass('street-address-counter--warning'); 43649 } 43650 }; 43651 $input.on('input', updateCounter); 43652 return updateCounter(); 43653 }; 43654 43655 prepareTrackViewItemList = function(attributes) { 43656 var searchQuery, trackable_attributes; 43657 searchQuery = attributes.searchQuery; 43658 trackable_attributes = { 43659 item_id: String(attributes.id), 43660 item_name: attributes.title, 43661 affiliation: attributes.affiliation, 43662 currency: 'USD', 43663 index: parseInt(attributes.index) || null, 43664 item_brand: attributes.authorUsername, 43665 item_category: attributes.category, 43666 item_category2: attributes.subcategory, 43667 item_category3: attributes.itemCategory3, 43668 item_category4: attributes.itemCategory4, 43669 item_category5: attributes.itemCategory5, 43670 item_list_id: searchQuery, 43671 item_list_name: searchQuery, 43672 item_variant: attributes.productType, 43673 location_id: attributes.locationId && attributes.locationId.join('_'), 43674 price: parseFloat(attributes.price), 43675 quantity: 1, 43676 discount: parseFloat(attributes.discount) || 0 43677 }; 43678 return trackable_attributes; 43679 }; 43680 43681 return CheckoutPayment; 43682 43683 })(App.Core.Page); 43684 43685}).call(this); 43686(function() { 43687 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 43688 hasProp = {}.hasOwnProperty; 43689 43690 App.Pages.CheckoutPlaceOrder = (function(superClass) { 43691 extend(CheckoutPlaceOrder, superClass); 43692 43693 function CheckoutPlaceOrder() { 43694 return CheckoutPlaceOrder.__super__.constructor.apply(this, arguments); 43695 } 43696 43697 return CheckoutPlaceOrder; 43698 43699 })(App.Pages.CheckoutPayment); 43700 43701}).call(this); 43702(function() { 43703 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 43704 hasProp = {}.hasOwnProperty; 43705 43706 App.Pages.CommunityIndex = (function(superClass) { 43707 extend(CommunityIndex, superClass); 43708 43709 function CommunityIndex() { 43710 return CommunityIndex.__super__.constructor.apply(this, arguments); 43711 } 43712 43713 CommunityIndex.prototype.widgets = ['linkFaker']; 43714 43715 CommunityIndex.prototype.initialize = function() { 43716 this.bindEvents(); 43717 return new LazyLoad({ 43718 elements_selector: '.js-lazy-img' 43719 }); 43720 }; 43721 43722 CommunityIndex.prototype.bindEvents = function() { 43723 return $('.js-header-block').hover(this.onHeaderBlockHover, this.onHeaderBlockHoverOut); 43724 }; 43725 43726 CommunityIndex.prototype.onHeaderBlockHover = function(e) { 43727 var $target; 43728 $target = $($(e.currentTarget).data('target')); 43729 return $target.addClass('is-hover'); 43730 }; 43731 43732 CommunityIndex.prototype.onHeaderBlockHoverOut = function(e) { 43733 var $target; 43734 $target = $($(e.currentTarget).data('target')); 43735 return $target.removeClass('is-hover'); 43736 }; 43737 43738 return CommunityIndex; 43739 43740 })(App.Core.Page); 43741 43742}).call(this); 43743/*! 43744 * hoverIntent r7 // 2013.03.11 // jQuery 1.9.1+ 43745 * http://cherne.net/brian/resources/jquery.hoverIntent.html 43746 * 43747 * You may use hoverIntent under the terms of the MIT license. Basically that 43748 * means you are free to use hoverIntent as long as this header is left intact. 43749 * Copyright 2007, 2013 Brian Cherne 43750 */ 43751 43752/* hoverIntent is similar to jQuery's built-in "hover" method except that 43753 * instead of firing the handlerIn function immediately, hoverIntent checks 43754 * to see if the user's mouse has slowed down (beneath the sensitivity 43755 * threshold) before firing the event. The handlerOut function is only 43756 * called after a matching handlerIn. 43757 * 43758 * // basic usage ... just like .hover() 43759 * .hoverIntent( handlerIn, handlerOut ) 43760 * .hoverIntent( handlerInOut ) 43761 * 43762 * // basic usage ... with event delegation! 43763 * .hoverIntent( handlerIn, handlerOut, selector ) 43764 * .hoverIntent( handlerInOut, selector ) 43765 * 43766 * // using a basic configuration object 43767 * .hoverIntent( config ) 43768 * 43769 * @param handlerIn function OR configuration object 43770 * @param handlerOut function OR selector for delegation OR undefined 43771 * @param selector selector OR undefined 43772 * @author Brian Cherne <brian(at)cherne(dot)net> 43773 */ 43774 43775(function($) { 43776 $.fn.hoverIntent = function(handlerIn,handlerOut,selector) { 43777 43778 // default configuration values 43779 var cfg = { 43780 interval: 100, 43781 sensitivity: 7, 43782 timeout: 0 43783 }; 43784
43785 if ( typeof handlerIn === "object" ) { 43786 cfg = $.extend(cfg, handlerIn ); 43787 } else if ($.isFunction(handlerOut)) { 43788 cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } ); 43789 } else { 43790 cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } ); 43791 } 43792 43793 // instantiate variables 43794 // cX, cY = current X and Y position of mouse, updated by mousemove event 43795 // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval 43796 var cX, cY, pX, pY; 43797 43798 // A private function for getting mouse position 43799 var track = function(ev) { 43800 cX = ev.pageX; 43801 cY = ev.pageY; 43802 }; 43803 43804 // A private function for comparing current and previous mouse position 43805 var compare = function(ev,ob) { 43806 ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); 43807 // compare mouse positions to see if they've crossed the threshold 43808 if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) { 43809 $(ob).off("mousemove.hoverIntent",track); 43810 // set hoverIntent state to true (so mouseOut can be called) 43811 ob.hoverIntent_s = 1; 43812 return cfg.over.apply(ob,[ev]); 43813 } else { 43814 // set previous coordinates for next time 43815 pX = cX; pY = cY; 43816 // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs) 43817 ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval ); 43818 } 43819 }; 43820 43821 // A private function for delaying the mouseOut function 43822 var delay = function(ev,ob) { 43823 ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); 43824 ob.hoverIntent_s = 0; 43825 return cfg.out.apply(ob,[ev]); 43826 }; 43827 43828 // A private function for handling mouse 'hovering' 43829 var handleHover = function(e) { 43830 // copy objects to be passed into t (required for event object to be passed in IE) 43831 var ev = jQuery.extend({},e); 43832 var ob = this; 43833 43834 // cancel hoverIntent timer if it exists 43835 if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); } 43836 43837 // if e.type == "mouseenter" 43838 if (e.type == "mouseenter") { 43839 // set "previous" X and Y position based on initial entry point 43840 pX = ev.pageX; pY = ev.pageY; 43841 // update "current" X and Y position based on mousemove 43842 $(ob).on("mousemove.hoverIntent",track); 43843 // start polling interval (self-calling timeout) to compare mouse coordinates over time 43844 if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );} 43845 43846 // else e.type == "mouseleave" 43847 } else { 43848 // unbind expensive mousemove event 43849 $(ob).off("mousemove.hoverIntent",track); 43850 // if hoverIntent state is true, then call the mouseOut function after the specified delay 43851 if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );} 43852 } 43853 }; 43854 43855 // listen for mouseenter and mouseleave 43856 return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector); 43857 }; 43858})(jQuery); 43859 43860/* 43861 By Osvaldas Valutis, www.osvaldas.info 43862 Available for use under the MIT License 43863*/ 43864 43865 43866;( function( $, window, document, undefined ) 43867{ 43868 'use strict'; 43869 43870 var cssTransitionSupport = function() 43871 { 43872 var s = document.body || document.documentElement, s = s.style; 43873 if( s.WebkitTransition == '' ) return '-webkit-'; 43874 if( s.MozTransition == '' ) return '-moz-'; 43875 if( s.OTransition == '' ) return '-o-'; 43876 if( s.transition == '' ) return ''; 43877 return false; 43878 }, 43879 43880 isCssTransitionSupport = cssTransitionSupport() === false ? false : true, 43881 43882 cssTransitionTranslateX = function( element, positionX, speed ) 43883 { 43884 var options = {}, prefix = cssTransitionSupport(); 43885 options[ prefix + 'transform' ] = 'translateX(' + positionX + ')'; 43886 options[ prefix + 'transition' ] = prefix + 'transform ' + speed + 's linear'; 43887 element.css( options ); 43888 }, 43889 43890 hasTouch = ( 'ontouchstart' in window ), 43891 hasPointers = window.navigator.pointerEnabled || window.navigator.msPointerEnabled, 43892 wasTouched = function( event ) 43893 { 43894 if( hasTouch ) 43895 return true; 43896 43897 if( !hasPointers || typeof event === 'undefined' || typeof event.pointerType === 'undefined' ) 43898 return false;
43899 43900 if( typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined' ) 43901 { 43902 if( event.MSPOINTER_TYPE_MOUSE != event.pointerType ) 43903 return true; 43904 } 43905 else 43906 if( event.pointerType != 'mouse' ) 43907 return true; 43908 43909 return false; 43910 }; 43911 43912 $.fn.imageLightbox = function( options ) 43913 { 43914 var options = $.extend( 43915 { 43916 selector: 'id="imagelightbox"', 43917 allowedTypes: 'png|jpg|jpeg|gif', 43918 animationSpeed: 250, 43919 preloadNext: true, 43920 enableKeyboard: true, 43921 quitOnEnd: false, 43922 quitOnImgClick: false, 43923 quitOnDocClick: true, 43924 onStart: false, 43925 onEnd: false, 43926 onLoadStart: false, 43927 onLoadEnd: false 43928 }, 43929 options ), 43930 43931 targets = $([]), 43932 target = $(), 43933 image = $(), 43934 imageWidth = 0, 43935 imageHeight = 0, 43936 swipeDiff = 0, 43937 inProgress = false, 43938 43939 isTargetValid = function( element ) 43940 { 43941 return $( element ).prop( 'tagName' ).toLowerCase() == 'a' && ( new RegExp( '\.(' + options.allowedTypes + ')$', 'i' ) ).test( $( element ).attr( 'href' ) ); 43942 }, 43943 43944 setImage = function() 43945 { 43946 if( !image.length ) return false; 43947 43948 var screenWidth = $( window ).width() * 0.8, 43949 screenHeight = $( window ).height() * 0.9, 43950 tmpImage = new Image(); 43951 43952 tmpImage.src = image.attr( 'src' ); 43953 tmpImage.onload = function() 43954 { 43955 imageWidth = tmpImage.width; 43956 imageHeight = tmpImage.height; 43957 43958 if( imageWidth > screenWidth || imageHeight > screenHeight ) 43959 { 43960 var ratio = imageWidth / imageHeight > screenWidth / screenHeight ? imageWidth / screenWidth : imageHeight / screenHeight; 43961 imageWidth /= ratio; 43962 imageHeight /= ratio; 43963 } 43964 43965 image.css( 43966 { 43967 'width': imageWidth + 'px', 43968 'height': imageHeight + 'px', 43969 'top': ( $( window ).height() - imageHeight ) / 2 + 'px', 43970 'left': ( $( window ).width() - imageWidth ) / 2 + 'px' 43971 }); 43972 }; 43973 }, 43974 43975 loadImage = function( direction ) 43976 { 43977 if( inProgress ) return false; 43978 43979 direction = typeof direction === 'undefined' ? false : direction == 'left' ? 1 : -1; 43980 43981 if( image.length ) 43982 { 43983 if( direction !== false && ( targets.length < 2 || ( options.quitOnEnd === true && ( ( direction === -1 && targets.index( target ) == 0 ) || ( direction === 1 && targets.index( target ) == targets.length - 1 ) ) ) ) ) 43984 { 43985 quitLightbox(); 43986 return false; 43987 } 43988 var params = { 'opacity': 0 }; 43989 if( isCssTransitionSupport ) cssTransitionTranslateX( image, ( 100 * direction ) - swipeDiff + 'px', options.animationSpeed / 1000 ); 43990 else params.left = parseInt( image.css( 'left' ) ) + 100 * direction + 'px'; 43991 image.animate( params, options.animationSpeed, function(){ removeImage(); }); 43992 swipeDiff = 0; 43993 } 43994 43995 inProgress = true; 43996 if( options.onLoadStart !== false ) options.onLoadStart(); 43997 43998 setTimeout( function() 43999 { 44000 image = $( '<img ' + options.selector + ' />' ) 44001 .attr( 'src', target.attr( 'href' ) ) 44002 .load( function() 44003 { 44004 image.appendTo( 'body' ); 44005 setImage(); 44006 44007 var params = { 'opacity': 1 }; 44008 44009 image.css( 'opacity', 0 ); 44010 if( isCssTransitionSupport ) 44011 { 44012 cssTransitionTranslateX( image, -100 * direction + 'px', 0 ); 44013 setTimeout( function(){ cssTransitionTranslateX( image, 0 + 'px', options.animationSpeed / 1000 ) }, 50 ); 44014 } 44015 else 44016 { 44017 var imagePosLeft = parseInt( image.css( 'left' ) ); 44018 params.left = imagePosLeft + 'px'; 44019 image.css( 'left', imagePosLeft - 100 * direction + 'px' ); 44020 } 44021 44022 image.animate( params, options.animationSpeed, function() 44023 { 44024 inProgress = false; 44025 if( options.onLoadEnd !== false ) options.onLoadEnd(); 44026 }); 44027 if( options.preloadNext ) 44028 { 44029 var nextTarget = targets.eq( targets.index( target ) + 1 ); 44030 if( !nextTarget.length ) nextTarget = targets.eq( 0 ); 44031 $( '<img />' ).attr( 'src', nextTarget.attr( 'href' ) ).load(); 44032 } 44033 }) 44034 .error( function() 44035 { 44036 if( options.onLoadEnd !== false ) options.onLoadEnd(); 44037 }) 44038 44039 var swipeStart = 0, 44040 swipeEnd = 0, 44041 imagePosLeft = 0; 44042 44043 image.on( hasPointers ? 'pointerup MSPointerUp' : 'click', function( e ) 44044 { 44045 e.preventDefault(); 44046 if( options.quitOnImgClick ) 44047 { 44048 quitLightbox(); 44049 return false;
44050 } 44051 if( wasTouched( e.originalEvent ) ) return true; 44052 var posX = ( e.pageX || e.originalEvent.pageX ) - e.target.offsetLeft; 44053 target = targets.eq( targets.index( target ) - ( imageWidth / 2 > posX ? 1 : -1 ) ); 44054 if( !target.length ) target = targets.eq( imageWidth / 2 > posX ? targets.length : 0 ); 44055 loadImage( imageWidth / 2 > posX ? 'left' : 'right' ); 44056 }) 44057 .on( 'touchstart pointerdown MSPointerDown', function( e ) 44058 { 44059 if( !wasTouched( e.originalEvent ) || options.quitOnImgClick ) return true; 44060 if( isCssTransitionSupport ) imagePosLeft = parseInt( image.css( 'left' ) ); 44061 swipeStart = e.originalEvent.pageX || e.originalEvent.touches[ 0 ].pageX; 44062 }) 44063 .on( 'touchmove pointermove MSPointerMove', function( e ) 44064 { 44065 if( !wasTouched( e.originalEvent ) || options.quitOnImgClick ) return true; 44066 e.preventDefault(); 44067 swipeEnd = e.originalEvent.pageX || e.originalEvent.touches[ 0 ].pageX; 44068 swipeDiff = swipeStart - swipeEnd; 44069 if( isCssTransitionSupport ) cssTransitionTranslateX( image, -swipeDiff + 'px', 0 ); 44070 else image.css( 'left', imagePosLeft - swipeDiff + 'px' ); 44071 }) 44072 .on( 'touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel', function( e ) 44073 { 44074 if( !wasTouched( e.originalEvent ) || options.quitOnImgClick ) return true; 44075 if( Math.abs( swipeDiff ) > 50 ) 44076 { 44077 target = targets.eq( targets.index( target ) - ( swipeDiff < 0 ? 1 : -1 ) ); 44078 if( !target.length ) target = targets.eq( swipeDiff < 0 ? targets.length : 0 ); 44079 loadImage( swipeDiff > 0 ? 'right' : 'left' ); 44080 } 44081 else 44082 { 44083 if( isCssTransitionSupport ) cssTransitionTranslateX( image, 0 + 'px', options.animationSpeed / 1000 ); 44084 else image.animate({ 'left': imagePosLeft + 'px' }, options.animationSpeed / 2 ); 44085 } 44086 }); 44087 44088 }, options.animationSpeed + 100 ); 44089 }, 44090 44091 removeImage = function() 44092 { 44093 if( !image.length ) return false; 44094 image.remove(); 44095 image = $(); 44096 }, 44097 44098 quitLightbox = function() 44099 { 44100 if( !image.length ) return false; 44101 image.animate({ 'opacity': 0 }, options.animationSpeed, function() 44102 { 44103 removeImage(); 44104 inProgress = false; 44105 if( options.onEnd !== false ) options.onEnd(); 44106 }); 44107 }; 44108 44109 $( window ).on( 'resize', setImage ); 44110 44111 if( options.quitOnDocClick ) 44112 { 44113 $( document ).on( hasTouch ? 'touchend' : 'click', function( e ) 44114 { 44115 if( image.length && !$( e.target ).is( image ) ) quitLightbox(); 44116 }) 44117 } 44118 44119 if( options.enableKeyboard ) 44120 { 44121 $( document ).on( 'keyup', function( e ) 44122 { 44123 if( !image.length ) return true; 44124 e.preventDefault(); 44125 if( e.keyCode == 27 ) quitLightbox(); 44126 if( !inProgress && ( e.keyCode == 37 || e.keyCode == 39 ) ) 44127 { 44128 target = targets.eq( targets.index( target ) - ( e.keyCode == 37 ? 1 : -1 ) ); 44129 if( !target.length ) target = targets.eq( e.keyCode == 37 ? targets.length : 0 ); 44130 loadImage( e.keyCode == 37 ? 'left' : 'right' ); 44131 } 44132 }); 44133 } 44134 44135 $( document ).on( 'click', this.selector, function( e ) 44136 { 44137 if( !isTargetValid( this ) ) return true; 44138 e.preventDefault(); 44139 if( inProgress ) return false; 44140 inProgress = false; 44141 if( options.onStart !== false ) options.onStart(); 44142 target = $( this ); 44143 loadImage(); 44144 }); 44145 44146 this.each( function() 44147 { 44148 if( !isTargetValid( this ) ) return true; 44149 targets = targets.add( $( this ) ); 44150 }); 44151 44152 this.switchImageLightbox = function( index ) 44153 { 44154 var tmpTarget = targets.eq( index ); 44155 if( tmpTarget.length ) 44156 { 44157 var currentIndex = targets.index( target ); 44158 target = tmpTarget; 44159 loadImage( index < currentIndex ? 'left' : 'right' ); 44160 } 44161 return this; 44162 }; 44163 44164 this.quitImageLightbox = function() 44165 { 44166 quitLightbox(); 44167 return this; 44168 }; 44169 44170 return this; 44171 }; 44172})( jQuery, window, document ); 44173(function() { 44174 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 44175 44176 App.Pages.CommunityRatingsNew = (function() { 44177 function CommunityRatingsNew() { 44178 this.displayInfo = bind(this.displayInfo, this); 44179 this.onTabClickSetCookie = bind(this.onTabClickSetCookie, this); 44180 this.onSkipLinkClick = bind(this.onSkipLinkClick, this); 44181 this.onTypeSelectorClick = bind(this.onTypeSelectorClick, this); 44182 this.onRadioClick = bind(this.onRadioClick, this); 44183 this.onRadioCheck = bind(this.onRadioCheck, this); 44184 } 44185 44186 CommunityRatingsNew.prototype.initialize = function() { 44187 this.handlers = this.eventHandlers(); 44188 this.ratingTab = Cookies.get('rating_tab') ? Cookies.get('rating_tab') : '#tab-points'; 44189 this.$radios = $('.js-rating-values input'); 44190 this.$previewImages = $('.js-preview-images'); 44191 this.$skipLink = $('.js-skip'); 44192 this.$typeSelectors = $('.js-type-select :radio'); 44193 this.$ratingForm = $('.js-rating-values').closest('form'); 44194 this.$usersTabs = $('#users-tabs ul li'); 44195 this.$ratingButton = $('.js-cast-rating'); 44196 this.bindEvents(); 44197 this.initPreview(); 44198 this.initTabs(); 44199 return this.displayInfo(); 44200 }; 44201 44202 CommunityRatingsNew.prototype.bindEvents = function() { 44203 this.$radios.on('change', this.onRadioCheck); 44204 this.$radios.on('click', this.onRadioClick); 44205 this.$typeSelectors.on('change', this.onTypeSelectorClick); 44206 this.$skipLink.on('click', this.onSkipLinkClick); 44207 this.$usersTabs.on('click', this.onTabClickSetCookie); 44208 return this.$ratingButton.on('click', this.showUpdatingSpinner); 44209 }; 44210 44211 CommunityRatingsNew.prototype.initPreview = function() { 44212 App.events.subscribe('app:preview:change', this.handlers.previewItemChange); 44213 $('.product-thumbs li a').imageLightbox({ 44214 onStart: function() { 44215 return $('body').append('<div class="product-slideshow-overlay is-hidden"></div>').find('.product-slideshow-overlay').hide().removeClass('is-hidden').fadeIn({ 44216 duration: 600,
44217 easing: 'easeInOutCirc' 44218 }); 44219 }, 44220 onEnd: function() { 44221 return $('.product-slideshow-overlay').fadeOut({ 44222 duration: 800, 44223 easing: 'easeInOutCirc' 44224 }).promise().then(function() { 44225 return $(this).remove(); 44226 }); 44227 } 44228 }); 44229 if (!$('.product-thumbs').exists()) { 44230 return; 44231 } 44232 this.sly = new Sly('.product-thumbs', { 44233 horizontal: true, 44234 itemNav: 'basic', 44235 smart: true, 44236 itemSelector: '.product-thumbs li', 44237 startAt: 0, 44238 mouseDragging: true, 44239 releaseSwing: true, 44240 touchDragging: false, 44241 swingSpeed: 0.1, 44242 scrollBar: $('.js-thumb-scrollbar'), 44243 dragHandle: true, 44244 clickBar: true, 44245 dynamicHandle: true, 44246 next: $('.js-preview-next'), 44247 prev: $('.js-preview-prev'), 44248 draggedClass: 'is-dragged', 44249 activeClass: 'is-active', 44250 disabledClass: 'is-disabled' 44251 }); 44252 this.sly.on('load', (function(_this) { 44253 return function() { 44254 if (_this.sly.pos.start === _this.sly.pos.end) { 44255 $('.js-thumb-scrollbar').hide(); 44256 return $('.product-thumb-navigation__item').addClass('navigation-without-scrollbar'); 44257 } else { 44258 $('.js-thumb-scrollbar').show(); 44259 return $('.product-thumb-navigation__item').removeClass('navigation-without-scrollbar'); 44260 } 44261 }; 44262 })(this)); 44263 this.sly.init(); 44264 if (this.$previewImages.children().length <= 1) { 44265 $('.product-preview__navigation').hide(); 44266 } 44267 $('.product-thumbs li').on('click', this.handlers.thumbClick); 44268 $('.product-thumbs li').hoverIntent(this.handlers.thumbHover, this.handlers.thumbHoverOut); 44269 return $('.js-preview-next, .js-preview-prev').on('click', this.handlers.previewNavClick); 44270 }; 44271 44272 CommunityRatingsNew.prototype.initTabs = function() { 44273 return $('#users-tabs').easytabs({ 44274 animate: true, 44275 panelActiveClass: 'is-active', 44276 tabActiveClass: 'is-active', 44277 updateDash: false, 44278 defaultTab: $("#users-tabs > ul > li > a[href='" + this.ratingTab + "']").first().parent() 44279 }); 44280 }; 44281 44282 CommunityRatingsNew.prototype.setRating = function($input) { 44283 $('.js-value-label').removeClass('is-active'); 44284 if ($input.prop('checked')) { 44285 $('.js-rate-value').val($input.val()); 44286 $input.parents('.rating-action__value').find('.js-value-label').addClass('is-active'); 44287 } 44288 return this.$ratingButton.prop('disabled', false); 44289 }; 44290 44291 CommunityRatingsNew.prototype.onRadioCheck = function(e) { 44292 var $el; 44293 $el = $(e.currentTarget); 44294 return this.setRating($el); 44295 }; 44296 44297 CommunityRatingsNew.prototype.onRadioClick = function(e) { 44298 var $el; 44299 $el = $(e.currentTarget); 44300 $el.attr('checked', 'checked'); 44301 return this.setRating($el); 44302 }; 44303 44304 CommunityRatingsNew.prototype.onTypeSelectorClick = function(e) { 44305 var $el; 44306 if (document.querySelector('input[name="product_type"]:checked')) { 44307 $el = $(e.currentTarget); 44308 $el.attr('checked', 'checked'); 44309 $el.closest('form').submit(); 44310 return this.showUpdatingSpinner(); 44311 } 44312 }; 44313 44314 CommunityRatingsNew.prototype.onSkipLinkClick = function(e) { 44315 e.preventDefault(); 44316 $('.js-skipped-value').val(1); 44317 return this.$ratingForm.submit(); 44318 }; 44319 44320 CommunityRatingsNew.prototype.onTabClickSetCookie = function(e) { 44321 return Cookies.set('rating_tab', e.target.hash); 44322 }; 44323 44324 CommunityRatingsNew.prototype.showUpdatingSpinner = function() { 44325 return $('.js-rating-content').addClass('is-updating-with-spinner'); 44326 }; 44327 44328 CommunityRatingsNew.prototype.eventHandlers = function() { 44329 return { 44330 thumbHover: function(e) { 44331 if ($(this).hasClass('is-active')) { 44332 return; 44333 } 44334 return $('.product-thumbs li').not(this).not('.is-active').addClass('is-disabled'); 44335 }, 44336 thumbHoverOut: function(e) { 44337 return $('.product-thumbs li').removeClass('is-disabled'); 44338 }, 44339 thumbClick: (function(_this) { 44340 return function(e) { 44341 var $el, $target; 44342 e.preventDefault(); 44343 e.stopPropagation(); 44344 $el = $(e.currentTarget); 44345 $target = _this.$previewImages.find("li:eq(" + ($el.index()) + ")"); 44346 return App.events.publish('app:preview:change', $target, 'auto'); 44347 }; 44348 })(this), 44349 previewNavClick: (function(_this) { 44350 return function(e) { 44351 var $active, $el, $target, direction; 44352 $el = $(e.currentTarget); 44353 $active = _this.$previewImages.find('.is-active'); 44354 if ($(e.currentTarget).hasClass('js-preview-next')) { 44355 $target = $active.next();
44356 direction = 'next'; 44357 if ($el.data('trigger') === 'manual') { 44358 _this.sly.next(); 44359 } 44360 } else { 44361 $target = $active.prev(); 44362 direction = 'prev'; 44363 if ($el.data('trigger') === 'manual') { 44364 _this.sly.prev(); 44365 } 44366 } 44367 if ($target.length === 0) { 44368 return; 44369 } 44370 return App.events.publish('app:preview:change', $target, direction); 44371 }; 44372 })(this), 44373 previewItemChange: (function(_this) { 44374 return function($target, direction) { 44375 var $active; 44376 $active = _this.$previewImages.find('.is-active'); 44377 if (direction === 'auto') { 44378 direction = 'next'; 44379 _this.sly.activate($target.index()); 44380 } 44381 $active.removeClass('is-active'); 44382 return $target.addClass('is-active'); 44383 }; 44384 })(this) 44385 }; 44386 }; 44387 44388 CommunityRatingsNew.prototype.displayInfo = function() { 44389 if ($('#modal-info')) { 44390 return $('#modal-info').makeMeModal(); 44391 } 44392 }; 44393 44394 return CommunityRatingsNew; 44395 44396 })(); 44397 44398}).call(this); 44399/* 44400 Redactor v9.1.6 44401 Updated: Oct 16, 2013 44402 44403 http://imperavi.com/redactor/ 44404 44405 Copyright (c) 2009-2013, Imperavi LLC. 44406 License: http://imperavi.com/redactor/license/ 44407 44408 Usage: $('#content').redactor(); 44409*/ 44410 44411 44412(function($) 44413{ 44414 var uuid = 0; 44415 44416 "use strict"; 44417 44418 var Range = function(range) 44419 { 44420 this[0] = range.startOffset; 44421 this[1] = range.endOffset; 44422 44423 this.range = range; 44424 44425 return this; 44426 }; 44427 44428 Range.prototype.equals = function() 44429 { 44430 return this[0] === this[1]; 44431 }; 44432 44433 // Plugin 44434 $.fn.redactor = function(options) 44435 { 44436 var val = []; 44437 var args = Array.prototype.slice.call(arguments, 1); 44438 44439 if (typeof options === 'string') 44440 { 44441 this.each(function() 44442 { 44443 var instance = $.data(this, 'redactor'); 44444 if (typeof instance !== 'undefined' && $.isFunction(instance[options])) 44445 { 44446 var methodVal = instance[options].apply(instance, args); 44447 if (methodVal !== undefined && methodVal !== instance) val.push(methodVal); 44448 } 44449 else return $.error('No such method "' + options + '" for Redactor'); 44450 }); 44451 } 44452 else 44453 { 44454 this.each(function() 44455 { 44456 if (!$.data(this, 'redactor')) $.data(this, 'redactor', Redactor(this, options)); 44457 }); 44458 } 44459 44460 if (val.length === 0) return this; 44461 else if (val.length === 1) return val[0]; 44462 else return val; 44463 44464 }; 44465 44466 // Initialization 44467 function Redactor(el, options) 44468 { 44469 return new Redactor.prototype.init(el, options); 44470 } 44471 44472 $.Redactor = Redactor; 44473 $.Redactor.VERSION = '9.1.6'; 44474 $.Redactor.opts = { 44475 44476 // settings 44477 rangy: false, 44478 44479 iframe: false, 44480 fullpage: false, 44481 css: false, // url 44482 44483 lang: 'en', 44484 direction: 'ltr', // ltr or rtl 44485 44486 placeholder: false, 44487 44488 wym: false, 44489 mobile: true, 44490 cleanup: true, 44491 tidyHtml: true, 44492 pastePlainText: false, 44493 removeEmptyTags: true, 44494 templateVars: false, 44495 xhtml: false, 44496 44497 visual: true, 44498 focus: false, 44499 tabindex: false, 44500 autoresize: true, 44501 minHeight: false, 44502 shortcuts: true, 44503 44504 autosave: false, // false or url 44505 autosaveInterval: 60, // seconds 44506 44507 plugins: false, // array 44508 44509 linkAnchor: true, 44510 linkEmail: true, 44511 linkProtocol: 'http://', 44512 linkNofollow: false, 44513 linkSize: 50, 44514 44515 imageFloatMargin: '10px', 44516 imageGetJson: false, // url (ex. /folder/images.json ) or false 44517 44518 imageUpload: false, // url 44519 imageUploadParam: 'file', // input name 44520 fileUpload: false, // url 44521 fileUploadParam: 'file', // input name 44522 clipboardUpload: true, // or false 44523 clipboardUploadUrl: false, // url 44524 dragUpload: true, // false 44525 44526 dnbImageTypes: ['image/png', 'image/jpeg', 'image/gif'], // or false 44527 44528 s3: false, 44529 uploadFields: false, 44530 44531 observeImages: true, 44532 observeLinks: true, 44533 44534 modalOverlay: true, 44535 44536 tabSpaces: false, // true or number of spaces 44537 tabFocus: true, 44538 44539 air: false, 44540 airButtons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent'], 44541 44542 toolbar: true, 44543 toolbarFixed: false, 44544 toolbarFixedTarget: document,
44545 toolbarFixedTopOffset: 0, // pixels 44546 toolbarFixedBox: false, 44547 toolbarExternal: false, // ID selector 44548 buttonSource: true, 44549 44550 buttonSeparator: '<li class="redactor_separator"></li>', 44551 44552 buttonsCustom: {}, 44553 buttonsAdd: [], 44554 buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'image', 'video', 'file', 'table', 'link', '|', 'alignment', '|', 'horizontalrule'], // 'underline', 'alignleft', 'aligncenter', 'alignright', 'justify' 44555 44556 activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist', 'alignleft', 'aligncenter', 'alignright', 'justify', 'table'], 44557 activeButtonsStates: { 44558 b: 'bold', 44559 strong: 'bold', 44560 i: 'italic', 44561 em: 'italic', 44562 del: 'deleted', 44563 strike: 'deleted', 44564 ul: 'unorderedlist', 44565 ol: 'orderedlist', 44566 u: 'underline', 44567 tr: 'table', 44568 td: 'table', 44569 table: 'table' 44570 }, 44571 activeButtonsAdd: false, // object, ex.: { tag: 'buttonName' } 44572 44573 formattingTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], 44574 44575 linebreaks: false, 44576 paragraphy: true, 44577 convertDivs: true, 44578 convertLinks: true, 44579 convertImageLinks: false, 44580 convertVideoLinks: false, 44581 formattingPre: false, 44582 phpTags: false, 44583 44584 allowedTags: false, 44585 deniedTags: ['html', 'head', 'link', 'body', 'meta', 'script', 'style', 'applet'], 44586 44587 boldTag: 'strong', 44588 italicTag: 'em', 44589 44590 // private 44591 indentValue: 20, 44592 buffer: [], 44593 rebuffer: [], 44594 textareamode: false, 44595 emptyHtml: '<p>​</p>', 44596 invisibleSpace: '​', 44597 rBlockTest: /^(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)$/i, 44598 alignmentTags: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DD', 'DL', 'DT', 'DIV', 'TD', 44599 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'ADDRESS', 'SECTION', 44600 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE'], 44601 ownLine: ['area', 'body', 'head', 'hr', 'i?frame', 'link', 'meta', 'noscript', 'style', 'script', 'table', 'tbody', 'thead', 'tfoot'], 44602 contOwnLine: ['li', 'dt', 'dt', 'h[1-6]', 'option', 'script'], 44603 newLevel: ['blockquote', 'div', 'dl', 'fieldset', 'form', 'frameset', 'map', 'ol', 'p', 'pre', 'select', 'td', 'th', 'tr', 'ul'], 44604 blockLevelElements: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DD', 'DL', 'DT', 'DIV', 'LI', 44605 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'PRE', 'ADDRESS', 'SECTION', 44606 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE', 'TD'], 44607 // lang 44608 langs: { 44609 en: { 44610 html: 'HTML', 44611 video: 'Insert Video', 44612 image: 'Insert Image', 44613 table: 'Table', 44614 link: 'Link', 44615 link_insert: 'Insert link', 44616 link_edit: 'Edit link', 44617 unlink: 'Unlink', 44618 formatting: 'Formatting', 44619 paragraph: 'Normal text', 44620 quote: 'Quote', 44621 code: 'Code', 44622 header1: 'Header 1', 44623 header2: 'Header 2', 44624 header3: 'Header 3', 44625 header4: 'Header 4', 44626 header5: 'Header 5', 44627 bold: 'Bold', 44628 italic: 'Italic', 44629 fontcolor: 'Font Color', 44630 backcolor: 'Back Color', 44631 unorderedlist: 'Unordered List', 44632 orderedlist: 'Ordered List', 44633 outdent: 'Outdent', 44634 indent: 'Indent', 44635 cancel: 'Cancel', 44636 insert: 'Insert', 44637 save: 'Save', 44638 _delete: 'Delete', 44639 insert_table: 'Insert Table', 44640 insert_row_above: 'Add Row Above', 44641 insert_row_below: 'Add Row Below', 44642 insert_column_left: 'Add Column Left', 44643 insert_column_right: 'Add Column Right', 44644 delete_column: 'Delete Column', 44645 delete_row: 'Delete Row', 44646 delete_table: 'Delete Table', 44647 rows: 'Rows', 44648 columns: 'Columns', 44649 add_head: 'Add Head', 44650 delete_head: 'Delete Head', 44651 title: 'Title', 44652 image_position: 'Position', 44653 none: 'None', 44654 left: 'Left', 44655 right: 'Right', 44656 image_web_link: 'Image Web Link', 44657 text: 'Text', 44658 mailto: 'Email', 44659 web: 'URL', 44660 video_html_code: 'Video Embed Code', 44661 file: 'Insert File', 44662 upload: 'Upload', 44663 download: 'Download', 44664 choose: 'Choose', 44665 or_choose: 'Or choose', 44666 drop_file_here: 'Drop file here', 44667 align_left: 'Align text to the left',
44668 align_center: 'Center text', 44669 align_right: 'Align text to the right', 44670 align_justify: 'Justify text', 44671 horizontalrule: 'Insert Horizontal Rule', 44672 deleted: 'Deleted', 44673 anchor: 'Anchor', 44674 link_new_tab: 'Open link in new tab', 44675 underline: 'Underline', 44676 alignment: 'Alignment', 44677 filename: 'Name (optional)', 44678 edit: 'Edit' 44679 } 44680 } 44681 }; 44682 44683 // Functionality 44684 Redactor.fn = $.Redactor.prototype = { 44685 44686 keyCode: { 44687 BACKSPACE: 8, 44688 DELETE: 46, 44689 DOWN: 40, 44690 ENTER: 13, 44691 ESC: 27, 44692 TAB: 9, 44693 CTRL: 17, 44694 META: 91, 44695 LEFT: 37, 44696 LEFT_WIN: 91 44697 }, 44698 44699 // Initialization 44700 init: function(el, options) 44701 { 44702 44703 this.rtePaste = false; 44704 this.$element = this.$source = $(el); 44705 this.uuid = uuid++; 44706 44707 // clonning options 44708 var opts = $.extend(true, {}, $.Redactor.opts); 44709 44710 // current settings 44711 this.opts = $.extend( 44712 {}, 44713 opts, 44714 this.$element.data(), 44715 options 44716 ); 44717 44718 this.start = true; 44719 this.dropdowns = []; 44720 44721 // get sizes 44722 this.sourceHeight = this.$source.css('height'); 44723 this.sourceWidth = this.$source.css('width'); 44724 44725 // dependency of the editor modes 44726 if (this.opts.fullpage) this.opts.iframe = true; 44727 if (this.opts.linebreaks) this.opts.paragraphy = false; 44728 if (this.opts.paragraphy) this.opts.linebreaks = false; 44729 if (this.opts.toolbarFixedBox) this.opts.toolbarFixed = true; 44730 44731 // the alias for iframe mode 44732 this.document = document; 44733 this.window = window; 44734 44735 // selection saved 44736 this.savedSel = false; 44737 44738 // clean setup 44739 this.cleanlineBefore = new RegExp('^<(/?' + this.opts.ownLine.join('|/?' ) + '|' + this.opts.contOwnLine.join('|') + ')[ >]'); 44740 this.cleanlineAfter = new RegExp('^<(br|/?' + this.opts.ownLine.join('|/?' ) + '|/' + this.opts.contOwnLine.join('|/') + ')[ >]'); 44741 this.cleannewLevel = new RegExp('^</?(' + this.opts.newLevel.join('|' ) + ')[ >]'); 44742 44743 // block level 44744 this.rTestBlock = new RegExp('^(' + this.opts.blockLevelElements.join('|' ) + ')$', 'i'); 44745 44746 // setup formatting permissions 44747 if (this.opts.linebreaks === false) 44748 { 44749 if (this.opts.allowedTags !== false && $.inArray('p', this.opts.allowedTags) === '-1') this.opts.allowedTags.push('p'); 44750 44751 if (this.opts.deniedTags !== false) 44752 { 44753 var pos = $.inArray('p', this.opts.deniedTags); 44754 if (pos !== '-1') this.opts.deniedTags.splice(pos, pos); 44755 } 44756 } 44757 44758 // ie & opera 44759 if (this.browser('msie') || this.browser('opera')) 44760 { 44761 this.opts.buttons = this.removeFromArrayByValue(this.opts.buttons, 'horizontalrule'); 44762 } 44763 44764 // load lang 44765 this.opts.curLang = this.opts.langs[this.opts.lang]; 44766 44767 // Build 44768 this.buildStart(); 44769 44770 }, 44771 toolbarInit: function(lang) 44772 { 44773 return { 44774 html: 44775 { 44776 title: lang.html, 44777 func: 'toggle' 44778 }, 44779 formatting: 44780 { 44781 title: lang.formatting, 44782 func: 'show', 44783 dropdown: 44784 { 44785 p: 44786 { 44787 title: lang.paragraph, 44788 func: 'formatBlocks' 44789 }, 44790 blockquote: 44791 { 44792 title: lang.quote, 44793 func: 'formatQuote', 44794 className: 'redactor_format_blockquote' 44795 }, 44796 pre: 44797 { 44798 title: lang.code, 44799 func: 'formatBlocks', 44800 className: 'redactor_format_pre' 44801 }, 44802 h1: 44803 { 44804 title: lang.header1, 44805 func: 'formatBlocks', 44806 className: 'redactor_format_h1' 44807 }, 44808 h2: 44809 { 44810 title: lang.header2, 44811 func: 'formatBlocks', 44812 className: 'redactor_format_h2' 44813 }, 44814 h3: 44815 { 44816 title: lang.header3, 44817 func: 'formatBlocks', 44818 className: 'redactor_format_h3' 44819 }, 44820 h4: 44821 { 44822 title: lang.header4, 44823 func: 'formatBlocks', 44824 className: 'redactor_format_h4' 44825 }, 44826 h5: 44827 { 44828 title: lang.header5, 44829 func: 'formatBlocks', 44830 className: 'redactor_format_h5' 44831 } 44832 } 44833 }, 44834 bold: 44835 { 44836 title: lang.bold, 44837 exec: 'bold' 44838 }, 44839 italic: 44840 { 44841 title: lang.italic, 44842 exec: 'italic' 44843 }, 44844 deleted: 44845 { 44846 title: lang.deleted, 44847 exec: 'strikethrough' 44848 }, 44849 underline: 44850 { 44851 title: lang.underline, 44852 exec: 'underline' 44853 }, 44854 unorderedlist: 44855 { 44856 title: '• ' + lang.unorderedlist, 44857 exec: 'insertunorderedlist' 44858 }, 44859 orderedlist: 44860 { 44861 title: '1. ' + lang.orderedlist, 44862 exec: 'insertorderedlist' 44863 },
44864 outdent: 44865 { 44866 title: '< ' + lang.outdent, 44867 func: 'indentingOutdent' 44868 }, 44869 indent: 44870 { 44871 title: '> ' + lang.indent, 44872 func: 'indentingIndent' 44873 }, 44874 image: 44875 { 44876 title: lang.image, 44877 func: 'imageShow' 44878 }, 44879 video: 44880 { 44881 title: lang.video, 44882 func: 'videoShow' 44883 }, 44884 file: 44885 { 44886 title: lang.file, 44887 func: 'fileShow' 44888 }, 44889 table: 44890 { 44891 title: lang.table, 44892 func: 'show', 44893 dropdown: 44894 { 44895 insert_table: 44896 { 44897 title: lang.insert_table, 44898 func: 'tableShow' 44899 }, 44900 separator_drop1: 44901 { 44902 name: 'separator' 44903 }, 44904 insert_row_above: 44905 { 44906 title: lang.insert_row_above, 44907 func: 'tableAddRowAbove' 44908 }, 44909 insert_row_below: 44910 { 44911 title: lang.insert_row_below, 44912 func: 'tableAddRowBelow' 44913 }, 44914 insert_column_left: 44915 { 44916 title: lang.insert_column_left, 44917 func: 'tableAddColumnLeft' 44918 }, 44919 insert_column_right: 44920 { 44921 title: lang.insert_column_right, 44922 func: 'tableAddColumnRight' 44923 }, 44924 separator_drop2: 44925 { 44926 name: 'separator' 44927 }, 44928 add_head: 44929 { 44930 title: lang.add_head, 44931 func: 'tableAddHead' 44932 }, 44933 delete_head: 44934 { 44935 title: lang.delete_head, 44936 func: 'tableDeleteHead' 44937 }, 44938 separator_drop3: 44939 { 44940 name: 'separator' 44941 }, 44942 delete_column: 44943 { 44944 title: lang.delete_column, 44945 func: 'tableDeleteColumn' 44946 }, 44947 delete_row: 44948 { 44949 title: lang.delete_row, 44950 func: 'tableDeleteRow' 44951 }, 44952 delete_table: 44953 { 44954 title: lang.delete_table, 44955 func: 'tableDeleteTable' 44956 } 44957 } 44958 }, 44959 link: { 44960 title: lang.link, 44961 func: 'show', 44962 dropdown: 44963 { 44964 link: 44965 { 44966 title: lang.link_insert, 44967 func: 'linkShow' 44968 }, 44969 unlink: 44970 { 44971 title: lang.unlink, 44972 exec: 'unlink' 44973 } 44974 } 44975 }, 44976 fontcolor: 44977 { 44978 title: lang.fontcolor, 44979 func: 'show' 44980 }, 44981 backcolor: 44982 { 44983 title: lang.backcolor, 44984 func: 'show' 44985 }, 44986 alignment: 44987 { 44988 title: lang.alignment, 44989 func: 'show', 44990 dropdown: 44991 { 44992 alignleft: 44993 { 44994 title: lang.align_left, 44995 func: 'alignmentLeft' 44996 }, 44997 aligncenter: 44998 { 44999 title: lang.align_center, 45000 func: 'alignmentCenter' 45001 }, 45002 alignright: 45003 { 45004 title: lang.align_right, 45005 func: 'alignmentRight' 45006 }, 45007 justify: 45008 { 45009 title: lang.align_justify, 45010 func: 'alignmentJustify' 45011 } 45012 } 45013 }, 45014 alignleft: 45015 { 45016 title: lang.align_left, 45017 func: 'alignmentLeft' 45018 }, 45019 aligncenter: 45020 { 45021 title: lang.align_center, 45022 func: 'alignmentCenter' 45023 }, 45024 alignright: 45025 { 45026 title: lang.align_right, 45027 func: 'alignmentRight' 45028 }, 45029 justify: 45030 { 45031 title: lang.align_justify, 45032 func: 'alignmentJustify' 45033 }, 45034 horizontalrule: 45035 { 45036 exec: 'inserthorizontalrule', 45037 title: lang.horizontalrule 45038 } 45039 45040 } 45041 }, 45042 45043 // CALLBACKS 45044 callback: function(type, event, data) 45045 { 45046 var callback = this.opts[ type + 'Callback' ]; 45047 if ($.isFunction(callback)) 45048 { 45049 if (event === false) return callback.call(this, data); 45050 else return callback.call(this, event, data); 45051 } 45052 else return data; 45053 }, 45054 45055 45056 // DESTROY 45057 destroy: function() 45058 { 45059 clearInterval(this.autosaveInterval); 45060 45061 $(window).off('.redactor'); 45062 this.$source.off('redactor-textarea'); 45063 this.$element.off('.redactor').removeData('redactor'); 45064 45065 var html = this.get(); 45066 45067 if (this.opts.textareamode) 45068 { 45069 this.$box.after(this.$source); 45070 this.$box.remove(); 45071 this.$source.val(html).show(); 45072 } 45073 else 45074 { 45075 var $elem = this.$editor; 45076 if (this.opts.iframe) $elem = this.$element; 45077 45078 this.$box.after($elem); 45079 this.$box.remove(); 45080 45081 $elem.removeClass('redactor_editor').removeClass('redactor_editor_wym').removeAttr('contenteditable').html(html).show(); 45082 } 45083 45084 if (this.opts.air) 45085 { 45086 $('#redactor_air_' + this.uuid).remove(); 45087 } 45088 }, 45089 45090 // API GET 45091 getObject: function() 45092 { 45093 return $.extend({}, this); 45094 }, 45095 getEditor: function() 45096 { 45097 return this.$editor; 45098 }, 45099 getBox: function() 45100 { 45101 return this.$box; 45102 }, 45103 getIframe: function() 45104 { 45105 return (this.opts.iframe) ? this.$frame : false;
45106 }, 45107 getToolbar: function() 45108 { 45109 return this.$toolbar; 45110 }, 45111 45112 45113 // CODE GET & SET 45114 get: function() 45115 { 45116 return this.$source.val(); 45117 }, 45118 getCodeIframe: function() 45119 { 45120 this.$editor.removeAttr('contenteditable').removeAttr('dir'); 45121 var html = this.outerHtml(this.$frame.contents().children()); 45122 this.$editor.attr({ 'contenteditable': true, 'dir': this.opts.direction }); 45123 45124 return html; 45125 }, 45126 set: function(html, strip, placeholderRemove) 45127 { 45128 html = html.toString(); 45129 45130 if (this.opts.fullpage) this.setCodeIframe(html); 45131 else this.setEditor(html, strip); 45132 45133 if (placeholderRemove !== false) this.placeholderRemove(); 45134 }, 45135 setEditor: function(html, strip) 45136 { 45137 if (strip !== false) 45138 { 45139 html = this.cleanSavePreCode(html); 45140 html = this.cleanStripTags(html); 45141 html = this.cleanConvertProtected(html); 45142 html = this.cleanConvertInlineTags(html); 45143 45144 if (this.opts.linebreaks === false) html = this.cleanConverters(html); 45145 else html = html.replace(/<p(.*?)>([\w\W]*?)<\/p>/gi, '$2<br>'); 45146 } 45147 45148 html = this.cleanEmpty(html); 45149 45150 this.$editor.html(html); 45151 45152 // set no editable 45153 this.setNonEditable(); 45154 this.setSpansVerified(); 45155 this.sync(); 45156 }, 45157 setCodeIframe: function(html) 45158 { 45159 var doc = this.iframePage(); 45160 this.$frame[0].src = "about:blank"; 45161 45162 html = this.cleanConvertProtected(html); 45163 html = this.cleanConvertInlineTags(html); 45164 html = this.cleanRemoveSpaces(html); 45165 45166 doc.open(); 45167 doc.write(html); 45168 doc.close(); 45169 45170 // redefine editor for fullpage mode 45171 if (this.opts.fullpage) 45172 { 45173 this.$editor = this.$frame.contents().find('body').attr({ 'contenteditable': true, 'dir': this.opts.direction }); 45174 } 45175 45176 // set no editable 45177 this.setNonEditable(); 45178 this.setSpansVerified(); 45179 this.sync(); 45180 45181 }, 45182 setFullpageOnInit: function(html) 45183 { 45184 html = this.cleanSavePreCode(html, true); 45185 html = this.cleanConverters(html); 45186 html = this.cleanEmpty(html); 45187 45188 // set code 45189 this.$editor.html(html); 45190 45191 // set no editable 45192 this.setNonEditable(); 45193 this.setSpansVerified(); 45194 this.sync(); 45195 }, 45196 setSpansVerified: function() 45197 { 45198 var spans = this.$editor.find('span'); 45199 var replacementTag = 'inline'; 45200 45201 $.each(spans, function() { 45202 var outer = this.outerHTML; 45203 45204 // Replace opening tag 45205 var regex = new RegExp('<' + this.tagName, 'i'); 45206 var newTag = outer.replace(regex, '<' + replacementTag); 45207 45208 // Replace closing tag 45209 regex = new RegExp('</' + this.tagName, 'i'); 45210 newTag = newTag.replace(regex, '</' + replacementTag); 45211 45212 $(this).replaceWith(newTag); 45213 }); 45214 45215 }, 45216 setSpansVerifiedHtml: function(html) 45217 { 45218 html = html.replace(/<span(.*?)>/, '<inline$1>'); 45219 return html.replace(/<\/span>/, '</inline>'); 45220 }, 45221 setNonEditable: function() 45222 { 45223 this.$editor.find('.noneditable').attr('contenteditable', false); 45224 }, 45225 45226 // SYNC 45227 sync: function() 45228 { 45229 var html = ''; 45230 45231 this.cleanUnverified(); 45232 45233 if (this.opts.fullpage) html = this.getCodeIframe(); 45234 else html = this.$editor.html(); 45235 45236 html = this.syncClean(html); 45237 //html = this.cleanRemoveSpaces(html); 45238 html = this.cleanRemoveEmptyTags(html); 45239 45240 // fix second level up ul, ol 45241 html = html.replace(/<\/li><(ul|ol)>([\w\W]*?)<\/(ul|ol)>/gi, '<$1>$2</$1></li>'); 45242 45243 if ($.trim(html) === '<br>') html = ''; 45244 45245 // xhtml 45246 if (this.opts.xhtml) 45247 { 45248 var xhtmlTags = ['br', 'hr', 'img', 'link', 'input', 'meta']; 45249 $.each(xhtmlTags, function(i,s) 45250 { 45251 html = html.replace(new RegExp('<' + s + '(.*?[^\/$]?)>', 'gi'), '<' + s + '$1 />'); 45252 }); 45253 45254 } 45255 45256 // before callback 45257 html = this.callback('syncBefore', false, html); 45258 45259 this.$source.val(html); 45260 45261 // onchange & after callback 45262 this.callback('syncAfter', false, html); 45263 45264 if (this.start === false) 45265 { 45266 this.callback('change', false, html); 45267 } 45268 45269 }, 45270 syncClean: function(html) 45271 { 45272 if (!this.opts.fullpage) html = this.cleanStripTags(html); 45273 45274 html = $.trim(html); 45275 45276 // removeplaceholder 45277 html = this.placeholderRemoveFromCode(html); 45278 45279 // remove space 45280 html = html.replace(/​/gi, ''); 45281 html = html.replace(/​/gi, ''); 45282 html = html.replace(/ /gi, ' '); 45283 45284 // link nofollow 45285 if (this.opts.linkNofollow) 45286 { 45287 html = html.replace(/<a(.*?)rel="nofollow"(.*?)>
45287/gi, '<a$1$2>'); 45288 html = html.replace(/<a(.*?)>/gi, '<a$1 rel="nofollow">'); 45289 } 45290 45291 // php code fix 45292 html = html.replace('<!--?php', '<?php'); 45293 html = html.replace('?-->', '?>'); 45294 45295 // revert no editable 45296 html = html.replace(/<(.*?)class="noeditable"(.*?) contenteditable="false"(.*?)>/gi, '<$1class="noeditable"$2$3>'); 45297 45298 html = html.replace(/ data-tagblock=""/gi, ''); 45299 html = html.replace(/<br\s?\/?>\n?<\/(P|H[1-6]|LI|ADDRESS|SECTION|HEADER|FOOTER|ASIDE|ARTICLE)>/gi, '</$1>'); 45300 45301 // remove image resize 45302 html = html.replace(/<span(.*?)id="redactor-image-box"(.*?)>([\w\W]*?)<img(.*?)><\/span>/i, '$3<img$4>'); 45303 html = html.replace(/<span(.*?)id="redactor-image-resizer"(.*?)>(.*?)<\/span>/i, ''); 45304 html = html.replace(/<span(.*?)id="redactor-image-editter"(.*?)>(.*?)<\/span>/i, ''); 45305 45306 // remove spans 45307 html = html.replace(/<span(.*?)>([\w\W]*?)<\/span>/gi, '$2'); 45308 html = html.replace(/<inline(.*?)>([\w\W]*?)<\/inline>/gi, '<span$1>$2</span>'); 45309 45310 // amp fix 45311 html = html.replace(/&/gi, '&'); 45312 45313 html = this.cleanReConvertProtected(html); 45314 45315 return html; 45316 }, 45317 45318 45319 // BUILD 45320 buildStart: function() 45321 { 45322 // content 45323 this.content = ''; 45324 45325 // container 45326 this.$box = $('<div class="redactor_box" />'); 45327 45328 // textarea test 45329 if (this.$source[0].tagName === 'TEXTAREA') this.opts.textareamode = true; 45330 45331 // mobile 45332 if (this.opts.mobile === false && this.isMobile()) 45333 { 45334 this.buildMobile(); 45335 } 45336 else 45337 { 45338 // get the content at the start 45339 this.buildContent(); 45340 45341 if (this.opts.iframe) 45342 { 45343 // build as iframe 45344 this.opts.autoresize = false; 45345 this.iframeStart(); 45346 } 45347 else if (this.opts.textareamode) this.buildFromTextarea(); 45348 else this.buildFromElement(); 45349 45350 // options and final setup 45351 if (!this.opts.iframe) 45352 { 45353 this.buildOptions(); 45354 this.buildAfter(); 45355 } 45356 } 45357 }, 45358 buildMobile: function() 45359 { 45360 if (!this.opts.textareamode) 45361 { 45362 this.$editor = this.$source; 45363 this.$editor.hide(); 45364 this.$source = this.buildCodearea(this.$editor); 45365 this.$source.val(this.content); 45366 } 45367 45368 this.$box.insertAfter(this.$source).append(this.$source); 45369 }, 45370 buildContent: function() 45371 { 45372 if (this.opts.textareamode) this.content = $.trim(this.$source.val()); 45373 else this.content = $.trim(this.$source.html()); 45374 }, 45375 buildFromTextarea: function() 45376 { 45377 this.$editor = $('<div />'); 45378 this.$box.insertAfter(this.$source).append(this.$editor).append(this.$source); 45379 45380 // enable 45381 this.buildAddClasses(this.$editor); 45382 this.buildEnable(); 45383 }, 45384 buildFromElement: function() 45385 { 45386 this.$editor = this.$source; 45387 this.$source = this.buildCodearea(this.$editor); 45388 this.$box.insertAfter(this.$editor).append(this.$editor).append(this.$source); 45389 45390 // enable 45391 this.buildEnable(); 45392 }, 45393 buildCodearea: function($source) 45394 { 45395 return $('<textarea />').attr('name', $source.attr('id')).css('height', this.sourceHeight); 45396 }, 45397 buildAddClasses: function(el) 45398 { 45399 // append textarea classes to editable layer 45400 $.each(this.$source.get(0).className.split(/\s+/), function(i,s) 45401 { 45402 el.addClass('redactor_' + s); 45403 }); 45404 }, 45405 buildEnable: function() 45406 { 45407 this.$editor.addClass('redactor_editor').attr({ 'contenteditable': true, 'dir': this.opts.direction }); 45408 this.$source.attr('dir', this.opts.direction).hide(); 45409 45410 // set code 45411 this.set(this.content, true, false); 45412 }, 45413 buildOptions: function() 45414 { 45415 var $source = this.$editor; 45416 if (this.opts.iframe) $source = this.$frame; 45417 45418 // options 45419 if (this.opts.tabindex) $source.attr('tabindex', this.opts.tabindex); 45420 if (this.opts.minHeight) $source.css('min-height', this.opts.minHeight + 'px'); 45421 if (this.opts.wym) this.$editor.addClass('redactor_editor_wym'); 45422 if (!this.opts.autoresize) $source.css('height', this.sourceHeight); 45423 }, 45424 buildAfter: function() 45425 { 45426 this.start = false;
45427 45428 // load toolbar 45429 if (this.opts.toolbar) 45430 { 45431 this.opts.toolbar = this.toolbarInit(this.opts.curLang); 45432 this.toolbarBuild(); 45433 } 45434 45435 // modal templates 45436 this.modalTemplatesInit(); 45437 45438 // plugins 45439 this.buildPlugins(); 45440 45441 // enter, tab, etc. 45442 this.buildBindKeyboard(); 45443 45444 // autosave 45445 if (this.opts.autosave) this.autosave(); 45446 45447 // observers 45448 setTimeout($.proxy(this.observeStart, this), 4); 45449 45450 // FF fix 45451 if (this.browser('mozilla')) 45452 { 45453 try { 45454 this.document.execCommand('enableObjectResizing', false, false); 45455 this.document.execCommand('enableInlineTableEditing', false, false); 45456 } catch (e) {} 45457 } 45458 45459 // focus 45460 if (this.opts.focus) setTimeout($.proxy(this.focus, this), 100); 45461 45462 // code mode 45463 if (!this.opts.visual) 45464 { 45465 setTimeout($.proxy(function() 45466 { 45467 this.opts.visual = true; 45468 this.toggle(false); 45469 45470 }, this), 200); 45471 } 45472 45473 // init callback 45474 this.callback('init'); 45475 }, 45476 buildBindKeyboard: function() 45477 { 45478 if (this.opts.dragUpload) 45479 { 45480 this.$editor.on('drop.redactor', $.proxy(this.buildEventDrop, this)); 45481 } 45482 45483 this.$editor.on('paste.redactor', $.proxy(this.buildEventPaste, this)); 45484 this.$editor.on('keydown.redactor', $.proxy(this.buildEventKeydown, this)); 45485 this.$editor.on('keyup.redactor', $.proxy(this.buildEventKeyup, this)); 45486 45487 45488 45489 // textarea callback 45490 if ($.isFunction(this.opts.textareaKeydownCallback)) 45491 { 45492 this.$source.on('keydown.redactor-textarea', $.proxy(this.opts.textareaKeydownCallback, this)); 45493 } 45494 45495 // focus callback 45496 if ($.isFunction(this.opts.focusCallback)) 45497 { 45498 this.$editor.on('focus.redactor', $.proxy(this.opts.focusCallback, this)); 45499 } 45500 45501 var clickedElement; 45502 $(document).mousedown(function(e) { 45503 clickedElement = $(e.target); 45504 }); 45505 45506 // blur callback 45507 this.$editor.on('blur.redactor', $.proxy(function(e) 45508 { 45509 if (!$(clickedElement).hasClass('redactor_toolbar') && $(clickedElement).parents('.redactor_toolbar').size() == 0) 45510 { 45511 this.selectall = false; 45512 if ($.isFunction(this.opts.blurCallback)) this.callback('blur', e); 45513 } 45514 }, this)); 45515 45516 }, 45517 buildEventDrop: function(e) 45518 { 45519 e = e.originalEvent || e; 45520 45521 if (window.FormData === undefined || !e.dataTransfer) return true; 45522 45523 var length = e.dataTransfer.files.length; 45524 if (length == 0) return true; 45525 45526 e.preventDefault(); 45527 45528 var file = e.dataTransfer.files[0]; 45529 45530 if (this.opts.dnbImageTypes !== false && this.opts.dnbImageTypes.indexOf(file.type) == -1) 45531 { 45532 return true; 45533 } 45534 45535 this.bufferSet(); 45536 45537 var progress = $('<div id="redactor-progress-drag" class="redactor-progress redactor-progress-striped"><div id="redactor-progress-bar" class="redactor-progress-bar" style="width: 100%;"></div></div>'); 45538 $(document.body).append(progress); 45539 45540 this.dragUploadAjax(this.opts.imageUpload, file, true, progress, e, this.opts.imageUploadParam); 45541 45542 }, 45543 buildEventPaste: function(e) 45544 { 45545 var oldsafari = false; 45546 if (this.browser('webkit') && navigator.userAgent.indexOf('Chrome') === -1) 45547 { 45548 var arr = this.browser('version').split('.'); 45549 if (arr[0] < 536) oldsafari = true; 45550 } 45551 45552 if (oldsafari) return true; 45553 45554 // paste except opera (not webkit) 45555 if (this.browser('opera')) return true; 45556 45557 // clipboard upload 45558 if (this.opts.clipboardUpload && this.buildEventClipboardUpload(e)) return true; 45559 45560 if (this.opts.cleanup) 45561 { 45562 this.rtePaste = true; 45563 45564 this.selectionSave(); 45565 45566 if (!this.selectall) 45567 { 45568 if (this.opts.autoresize === true ) 45569 { 45570 this.$editor.height(this.$editor.height()); 45571 this.saveScroll = this.document.body.scrollTop; 45572 } 45573 else 45574 { 45575 this.saveScroll = this.$editor.scrollTop(); 45576 } 45577 } 45578 45579 var frag = this.extractContent(); 45580 45581 setTimeout($.proxy(function() 45582 { 45583 var pastedFrag = this.extractContent(); 45584 this.$editor.append(frag); 45585 45586 this.selectionRestore(); 45587 45588 var html = this.getFragmentHtml(pastedFrag); 45589 this.pasteClean(html); 45590 45591 if (this.opts.autoresize === true) this.$editor.css('height', 'auto'); 45592 45593 }, this), 1); 45594 } 45595 }, 45596 buildEventClipboardUpload: function(e) 45597 { 45598 var event = e.originalEvent || e; 45599 this.clipboardFilePaste = false;
45600 45601 if (typeof(event.clipboardData) === 'undefined') return false; 45602 if (event.clipboardData.items) 45603 { 45604 var file = event.clipboardData.items[0].getAsFile(); 45605 if (file !== null) 45606 { 45607 this.bufferSet(); 45608 this.clipboardFilePaste = true; 45609 45610 var reader = new FileReader(); 45611 reader.onload = $.proxy(this.pasteClipboardUpload, this); 45612 reader.readAsDataURL(file); 45613 45614 return true; 45615 } 45616 } 45617 45618 return false; 45619 45620 }, 45621 buildEventKeydown: function(e) 45622 { 45623 if (this.rtePaste) return false; 45624 45625 var key = e.which; 45626 var ctrl = e.ctrlKey || e.metaKey; 45627 var parent = this.getParent(); 45628 var current = this.getCurrent(); 45629 var block = this.getBlock(); 45630 var pre = false; 45631 45632 this.callback('keydown', e); 45633 45634 this.imageResizeHide(false); 45635 45636 // pre & down 45637 if ((parent && $(parent).get(0).tagName === 'PRE') || (current && $(current).get(0).tagName === 'PRE')) 45638 { 45639 pre = true; 45640 if (key === this.keyCode.DOWN) this.insertAfterLastElement(block); 45641 } 45642 45643 // down 45644 if (key === this.keyCode.DOWN) 45645 { 45646 if (parent && $(parent).get(0).tagName === 'BLOCKQUOTE') this.insertAfterLastElement(parent); 45647 if (current && $(current).get(0).tagName === 'BLOCKQUOTE') this.insertAfterLastElement(current); 45648 } 45649 45650 // shortcuts setup 45651 if (ctrl && !e.shiftKey) this.shortcuts(e, key); 45652 45653 // buffer setup 45654 if (ctrl && key === 90 && !e.shiftKey && !e.altKey) // z key 45655 { 45656 e.preventDefault(); 45657 if (this.opts.buffer.length) this.bufferUndo(); 45658 else this.document.execCommand('undo', false, false); 45659 return; 45660 } 45661 // undo 45662 else if (ctrl && key === 90 && e.shiftKey && !e.altKey) 45663 { 45664 e.preventDefault(); 45665 if (this.opts.rebuffer.length != 0) this.bufferRedo(); 45666 else this.document.execCommand('redo', false, false); 45667 return; 45668 } 45669 45670 // select all 45671 if (ctrl && key === 65) this.selectall = true; 45672 else if (key != this.keyCode.LEFT_WIN && !ctrl) this.selectall = false; 45673 45674 // enter 45675 if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey ) 45676 { 45677 // In ie, opera in the tables are created paragraphs, fix it. 45678 if (parent.nodeType == 1 && (parent.tagName == 'TD' || parent.tagName == 'TH')) 45679 { 45680 e.preventDefault(); 45681 this.bufferSet(); 45682 this.insertNode(document.createElement('br')); 45683 this.callback('enter', e); 45684 return false; 45685 } 45686 45687 // pre 45688 if (pre === true) return this.buildEventKeydownPre(e, current); 45689 else 45690 { 45691 if (!this.opts.linebreaks) 45692 { 45693 // replace div to p 45694 if (block && this.opts.rBlockTest.test(block.tagName)) 45695 { 45696 // hit enter 45697 this.bufferSet(); 45698 45699 setTimeout($.proxy(function() 45700 { 45701 var blockElem = this.getBlock(); 45702 if (blockElem.tagName === 'DIV' && !$(blockElem).hasClass('redactor_editor')) 45703 { 45704 var node = $('<p>' + this.opts.invisibleSpace + '</p>'); 45705 $(blockElem).replaceWith(node); 45706 this.selectionStart(node); 45707 } 45708 45709 }, this), 1); 45710 } 45711 else if (block === false) 45712 { 45713 // hit enter 45714 this.bufferSet(); 45715 45716 var node = $('<p>' + this.opts.invisibleSpace + '</p>'); 45717 this.insertNode(node[0]); 45718 this.selectionStart(node); 45719 this.callback('enter', e); 45720 return false; 45721 } 45722 45723 } 45724 45725 if (this.opts.linebreaks) 45726 { 45727 // replace div to br 45728 if (block && this.opts.rBlockTest.test(block.tagName)) 45729 { 45730 // hit enter 45731 this.bufferSet(); 45732 45733 setTimeout($.proxy(function() 45734 { 45735 var blockElem = this.getBlock(); 45736 if ((blockElem.tagName === 'DIV' || blockElem.tagName === 'P') && !$(blockElem).hasClass('redactor_editor')) 45737 { 45738 this.replaceLineBreak(blockElem); 45739 } 45740 45741 }, this), 1); 45742 } 45743 else 45744 { 45745 return this.buildEventKeydownInsertLineBreak(e); 45746 } 45747 } 45748 45749 // blockquote, figcaption 45750 if (block.tagName == 'BLOCKQUOTE' || block.tagName == 'FIGCAPTION') 45751 { 45752 return this.buildEventKeydownInsertLineBreak(e); 45753 } 45754 45755 } 45756 45757 this.callback('enter', e); 45758 } 45759 else if (key === this.keyCode.ENTER && (e.ctrlKey || e.shiftKey)) // Shift+Enter or Ctrl+Enter 45760 { 45761 this.bufferSet(); 45762 45763 e.preventDefault(); 45764 this.insertLineBreak(); 45765 } 45766 45767 // tab 45768 if (key === this.keyCode.TAB && this.opts.shortcuts) return this.buildEventKeydownTab(e, pre); 45769
45770 // delete zero-width space before the removing 45771 if (key === this.keyCode.BACKSPACE) this.buildEventKeydownBackspace(current); 45772 45773 }, 45774 buildEventKeydownPre: function(e, current) 45775 { 45776 e.preventDefault(); 45777 this.bufferSet(); 45778 var html = $(current).parent().text(); 45779 this.insertNode(document.createTextNode('\n')); 45780 if (html.search(/\s$/) == -1) 45781 { 45782 this.insertNode(document.createTextNode('\n')); 45783 } 45784 45785 this.sync(); 45786 this.callback('enter', e); 45787 return false; 45788 }, 45789 buildEventKeydownTab: function(e, pre) 45790 { 45791 if (!this.opts.tabFocus) return true; 45792 if (this.isEmpty(this.get())) return true; 45793 45794 e.preventDefault(); 45795 45796 if (pre === true && !e.shiftKey) 45797 { 45798 this.bufferSet(); 45799 this.insertNode(document.createTextNode('\t')); 45800 this.sync(); 45801 return false; 45802 45803 } 45804 else if (this.opts.tabSpaces !== false) 45805 { 45806 this.bufferSet(); 45807 this.insertNode(document.createTextNode(Array(this.opts.tabSpaces + 1).join('\u00a0'))); 45808 this.sync(); 45809 return false; 45810 } 45811 else 45812 { 45813 if (!e.shiftKey) this.indentingIndent(); 45814 else this.indentingOutdent(); 45815 } 45816 45817 return false; 45818 }, 45819 buildEventKeydownBackspace: function(current) 45820 { 45821 if (typeof current.tagName !== 'undefined' && /^(H[1-6])$/i.test(current.tagName)) 45822 { 45823 var node; 45824 if (this.opts.linebreaks === false) node = $('<p>' + this.opts.invisibleSpace + '</p>'); 45825 else node = $('<br>' + this.opts.invisibleSpace); 45826 45827 $(current).replaceWith(node); 45828 this.selectionStart(node); 45829 } 45830 45831 if (typeof current.nodeValue !== 'undefined' && current.nodeValue !== null) 45832 {
45833 //var value = $.trim(current.nodeValue.replace(/[^\u0000-\u1C7F]/g, '')); 45834 if (current.remove && current.nodeType === 3 && current.nodeValue.match(/[^/\u200B]/g) == null) 45835 { 45836 current.remove(); 45837 } 45838 } 45839 }, 45840 buildEventKeydownInsertLineBreak: function(e) 45841 { 45842 this.bufferSet(); 45843 e.preventDefault(); 45844 this.insertLineBreak(); 45845 this.callback('enter', e); 45846 return; 45847 }, 45848 buildEventKeyup: function(e) 45849 { 45850 if (this.rtePaste) return false; 45851 45852 var key = e.which; 45853 var parent = this.getParent(); 45854 var current = this.getCurrent(); 45855 45856 // replace to p before / after the table or body 45857 if (!this.opts.linebreaks && current.nodeType == 3 && (parent == false || parent.tagName == 'BODY')) 45858 { 45859 var node = $('<p>').append($(current).clone()); 45860 $(current).replaceWith(node); 45861 var next = $(node).next(); 45862 if (typeof(next[0]) !== 'undefined' && next[0].tagName == 'BR') 45863 { 45864 next.remove(); 45865 } 45866 this.selectionEnd(node); 45867 } 45868 45869 // convert links 45870 if ((this.opts.convertLinks || this.opts.convertImageLinks || this.opts.convertVideoLinks) && key === this.keyCode.ENTER) 45871 { 45872 this.buildEventKeyupConverters(); 45873 } 45874 45875 // if empty 45876 if (this.opts.linebreaks === false && (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE)) 45877 { 45878 return this.formatEmpty(e); 45879 } 45880 45881 this.callback('keyup', e); 45882 this.sync(); 45883 }, 45884 buildEventKeyupConverters: function() 45885 { 45886 this.formatLinkify(this.opts.linkProtocol, this.opts.convertLinks, this.opts.convertImageLinks, this.opts.convertVideoLinks, this.opts.linkSize); 45887 45888 setTimeout($.proxy(function() 45889 { 45890 if (this.opts.convertImageLinks) this.observeImages(); 45891 if (this.opts.observeLinks) this.observeLinks(); 45892 }, this), 5); 45893 }, 45894 buildPlugins: function() 45895 { 45896 if (!this.opts.plugins ) return; 45897 45898 $.each(this.opts.plugins, $.proxy(function(i, s) 45899 { 45900 if (RedactorPlugins[s]) 45901 { 45902 $.extend(this, RedactorPlugins[s]); 45903 if ($.isFunction( RedactorPlugins[ s ].init)) this.init(); 45904 } 45905 45906 }, this )); 45907 }, 45908 45909 // IFRAME 45910 iframeStart: function() 45911 { 45912 this.iframeCreate(); 45913 45914 if (this.opts.textareamode) this.iframeAppend(this.$source); 45915 else 45916 { 45917 this.$sourceOld = this.$source.hide(); 45918 this.$source = this.buildCodearea(this.$sourceOld); 45919 this.iframeAppend(this.$sourceOld); 45920 } 45921 }, 45922 iframeAppend: function(el) 45923 { 45924 this.$source.attr('dir', this.opts.direction).hide(); 45925 this.$box.insertAfter(el).append(this.$frame).append(this.$source); 45926 }, 45927 iframeCreate: function() 45928 { 45929 this.$frame = $('<iframe style="width: 100%;" frameborder="0" />').one('load', $.proxy(function() 45930 { 45931 if (this.opts.fullpage) 45932 { 45933 this.iframePage(); 45934 45935 if (this.content === '') this.content = this.opts.invisibleSpace; 45936 45937 this.$frame.contents()[0].write(this.content); 45938 this.$frame.contents()[0].close(); 45939 45940 var timer = setInterval($.proxy(function() 45941 { 45942 if (this.$frame.contents().find('body').html()) 45943 { 45944 clearInterval(timer); 45945 this.iframeLoad(); 45946 } 45947 45948 }, this), 0); 45949 } 45950 else this.iframeLoad(); 45951 45952 }, this)); 45953 }, 45954 iframeDoc: function() 45955 { 45956 return this.$frame[0].contentWindow.document; 45957 }, 45958 iframePage: function() 45959 { 45960 var doc = this.iframeDoc(); 45961 if (doc.documentElement) doc.removeChild(doc.documentElement); 45962 45963 return doc; 45964 }, 45965 iframeAddCss: function(css) 45966 { 45967 css = css || this.opts.css; 45968 45969 if (this.isString(css)) 45970 { 45971 this.$frame.contents().find('head').append('<link rel="stylesheet" href="' + css + '" />'); 45972 } 45973 45974 if ($.isArray(css)) 45975 { 45976 $.each(css, $.proxy(function(i, url) 45977 { 45978 this.iframeAddCss(url); 45979 45980 }, this)); 45981 } 45982 }, 45983 iframeLoad: function() 45984 { 45985 this.$editor = this.$frame.contents().find('body').attr({ 'contenteditable': true, 'dir': this.opts.direction }); 45986 45987 // set document & window 45988 if (this.$editor[0]) 45989 { 45990 this.document = this.$editor[0].ownerDocument; 45991 this.window = this.document.defaultView || window; 45992 } 45993 45994 // iframe css 45995 this.iframeAddCss(); 45996 45997 if (this.opts.fullpage) this.setFullpageOnInit(this.$editor.html()); 45998 else this.set(this.content, true, false); 45999 46000 this.buildOptions(); 46001 this.buildAfter(); 46002 }, 46003 46004 // PLACEHOLDER 46005 placeholderStart: function(html) 46006 { 46007 if (this.isEmpty(html)) 46008 { 46009 if (this.$element.attr('placeholder')) this.opts.placeholder = this.$element.attr('placeholder'); 46010 if (this.opts.placeholder === '') this.opts.placeholder = false;
46011 46012 if (this.opts.placeholder !== false) 46013 { 46014 this.opts.focus = false; 46015 this.$editor.one('focus.redactor_placeholder', $.proxy(this.placeholderFocus, this)); 46016 46017 return $('<span class="redactor_placeholder" data-redactor="verified">').attr('contenteditable', false).text(this.opts.placeholder); 46018 } 46019 } 46020 46021 return false; 46022 }, 46023 placeholderFocus: function() 46024 { 46025 this.$editor.find('span.redactor_placeholder').remove(); 46026 46027 var html = ''; 46028 if (this.opts.linebreaks === false) html = this.opts.emptyHtml; 46029 46030 this.$editor.off('focus.redactor_placeholder'); 46031 this.$editor.html(html); 46032 46033 if (this.opts.linebreaks === false) 46034 { 46035 // place the cursor inside emptyHtml 46036 this.selectionStart(this.$editor.children()[0]); 46037 } 46038 else 46039 { 46040 this.focus(); 46041 } 46042 46043 this.sync(); 46044 }, 46045 placeholderRemove: function() 46046 { 46047 this.opts.placeholder = false; 46048 this.$editor.find('span.redactor_placeholder').remove(); 46049 this.$editor.off('focus.redactor_placeholder'); 46050 }, 46051 placeholderRemoveFromCode: function(html) 46052 { 46053 return html.replace(/<span class="redactor_placeholder"(.*?)>(.*?)<\/span>/i, ''); 46054 }, 46055 46056 // SHORTCUTS 46057 shortcuts: function(e, key) 46058 { 46059 46060 if (!this.opts.shortcuts) return; 46061 46062 if (!e.altKey) 46063 { 46064 if (key === 77) this.shortcutsLoad(e, 'removeFormat'); // Ctrl + m 46065 else if (key === 66) this.shortcutsLoad(e, 'bold'); // Ctrl + b 46066 else if (key === 73) this.shortcutsLoad(e, 'italic'); // Ctrl + i 46067 46068 else if (key === 74) this.shortcutsLoad(e, 'insertunorderedlist'); // Ctrl + j 46069 else if (key === 75) this.shortcutsLoad(e, 'insertorderedlist'); // Ctrl + k 46070 46071 else if (key === 72) this.shortcutsLoad(e, 'superscript'); // Ctrl + h 46072 else if (key === 76) this.shortcutsLoad(e, 'subscript'); // Ctrl + l 46073 } 46074 else 46075 { 46076 if (key === 48) this.shortcutsLoadFormat(e, 'p'); // ctrl + alt + 0 46077 else if (key === 49) this.shortcutsLoadFormat(e, 'h1'); // ctrl + alt + 1 46078 else if (key === 50) this.shortcutsLoadFormat(e, 'h2'); // ctrl + alt + 2 46079 else if (key === 51) this.shortcutsLoadFormat(e, 'h3'); // ctrl + alt + 3 46080 else if (key === 52) this.shortcutsLoadFormat(e, 'h4'); // ctrl + alt + 4 46081 else if (key === 53) this.shortcutsLoadFormat(e, 'h5'); // ctrl + alt + 5 46082 else if (key === 54) this.shortcutsLoadFormat(e, 'h6'); // ctrl + alt + 6 46083 46084 } 46085 46086 }, 46087 shortcutsLoad: function(e, cmd) 46088 { 46089 e.preventDefault(); 46090 this.execCommand(cmd, false); 46091 }, 46092 shortcutsLoadFormat: function(e, cmd) 46093 { 46094 e.preventDefault(); 46095 this.formatBlocks(cmd); 46096 }, 46097 46098 // FOCUS 46099 focus: function() 46100 { 46101 if (!this.browser('opera')) this.window.setTimeout($.proxy(this.focusSet, this, true), 1); 46102 else this.$editor.focus(); 46103 }, 46104 focusEnd: function() 46105 { 46106 this.focusSet(); 46107 }, 46108 focusSet: function(collapse) 46109 { 46110 this.$editor.focus(); 46111 46112 var range = this.getRange(); 46113 range.selectNodeContents(this.$editor[0]); 46114 46115 // collapse - controls the position of focus: the beginning (true), at the end (false). 46116 range.collapse(collapse || false); 46117 46118 var sel = this.getSelection(); 46119 sel.removeAllRanges(); 46120 sel.addRange(range); 46121 }, 46122 46123 // TOGGLE 46124 toggle: function(direct) 46125 { 46126 if (this.opts.visual) this.toggleCode(direct); 46127 else this.toggleVisual(); 46128 }, 46129 toggleVisual: function() 46130 { 46131 var html = this.$source.hide().val(); 46132 46133 if (typeof this.modified !== 'undefined') 46134 { 46135 this.modified = this.cleanRemoveSpaces(this.modified, false) !== this.cleanRemoveSpaces(html, false); 46136 } 46137 46138 if (this.modified) 46139 { 46140 // don't remove the iframe even if cleared all. 46141 if (this.opts.fullpage && html === '') this.setFullpageOnInit(html); 46142 else 46143 { 46144 this.set(html); 46145 if (this.opts.fullpage) this.buildBindKeyboard(); 46146 } 46147 } 46148 46149 if (this.opts.iframe) this.$frame.show(); 46150 else this.$editor.show(); 46151 46152 if (this.opts.fullpage) this.$editor.attr('contenteditable', true ); 46153 46154 this.$source.off('keydown.redactor-textarea-indenting'); 46155 46156 this.$editor.focus(); 46157 this.selectionRestore(); 46158 46159 this.observeStart(); 46160 this.buttonActiveVisual(); 46161 this.buttonInactive('html'); 46162 this.opts.visual = true; 46163 }, 46164 toggleCode: function(direct) 46165 { 46166 if (direct !== false) this.selectionSave(); 46167 46168 var height = null; 46169 if (this.opts.iframe) 46170 { 46171 height = this.$frame.height(); 46172 if (this.opts.fullpage) this.$editor.removeAttr('contenteditable'); 46173 this.$frame.hide(); 46174 } 46175 else 46176 {
46177 height = this.$editor.innerHeight(); 46178 this.$editor.hide(); 46179 } 46180 46181 var html = this.$source.val(); 46182 46183 // tidy html 46184 if (html !== '' && this.opts.tidyHtml) 46185 { 46186 this.$source.val(this.cleanHtml(html)); 46187 } 46188 46189 this.modified = html; 46190 46191 this.$source.height(height).show().focus(); 46192 46193 // textarea indenting 46194 this.$source.on('keydown.redactor-textarea-indenting', this.textareaIndenting); 46195 46196 this.buttonInactiveVisual(); 46197 this.buttonActive('html'); 46198 this.opts.visual = false; 46199 }, 46200 textareaIndenting: function(e) 46201 { 46202 if (e.keyCode === 9) 46203 { 46204 var $el = $(this); 46205 var start = $el.get(0).selectionStart; 46206 $el.val($el.val().substring(0, start) + "\t" + $el.val().substring($el.get(0).selectionEnd)); 46207 $el.get(0).selectionStart = $el.get(0).selectionEnd = start + 1; 46208 return false; 46209 } 46210 }, 46211 46212 // AUTOSAVE 46213 autosave: function() 46214 { 46215 var savedHtml = false; 46216 this.autosaveInterval = setInterval($.proxy(function() 46217 { 46218 var html = this.get(); 46219 if (savedHtml !== html) 46220 { 46221 $.ajax({ 46222 url: this.opts.autosave, 46223 type: 'post', 46224 data: this.$source.attr('name') + '=' + escape(encodeURIComponent(html)), 46225 success: $.proxy(function(data) 46226 { 46227 this.callback('autosave', false, data); 46228 savedHtml = html; 46229 46230 }, this) 46231 }); 46232 } 46233 }, this), this.opts.autosaveInterval*1000); 46234 }, 46235 46236 // TOOLBAR 46237 toolbarBuild: function() 46238 { 46239 // extend buttons 46240 if (this.opts.air) 46241 { 46242 this.opts.buttons = this.opts.airButtons; 46243 } 46244 else 46245 { 46246 if (!this.opts.buttonSource) 46247 { 46248 var index = this.opts.buttons.indexOf('html'), next = this.opts.buttons[index + 1]; 46249 this.opts.buttons.splice(index, 1); 46250 if (next === '|') this.opts.buttons.splice(index, 1); 46251 } 46252 } 46253 46254 $.extend(this.opts.toolbar, this.opts.buttonsCustom); 46255 $.each(this.opts.buttonsAdd, $.proxy(function(i, s) 46256 { 46257 this.opts.buttons.push(s); 46258 46259 }, this)); 46260 46261 // formatting tags 46262 if (this.opts.toolbar) 46263 { 46264 $.each(this.opts.toolbar.formatting.dropdown, $.proxy(function (i, s) 46265 { 46266 if ($.inArray(i, this.opts.formattingTags ) == '-1') delete this.opts.toolbar.formatting.dropdown[i]; 46267 46268 }, this)); 46269 } 46270 46271 // if no buttons don't create a toolbar 46272 if (this.opts.buttons.length === 0) return false; 46273 46274 // air enable 46275 this.airEnable(); 46276 46277 // toolbar build 46278 this.$toolbar = $('<ul>').addClass('redactor_toolbar').attr('id', 'redactor_toolbar_' + this.uuid); 46279 46280 if (this.opts.air) 46281 { 46282 // air box 46283 this.$air = $('<div class="redactor_air">').attr('id', 'redactor_air_' + this.uuid).hide(); 46284 this.$air.append(this.$toolbar); 46285 $('body').append(this.$air); 46286 } 46287 else 46288 { 46289 if (this.opts.toolbarExternal) $(this.opts.toolbarExternal).html(this.$toolbar); 46290 else this.$box.prepend(this.$toolbar); 46291 } 46292 46293 $.each(this.opts.buttons, $.proxy(function(i, btnName) 46294 { 46295 // separator 46296 if ( btnName === '|' ) this.$toolbar.append($(this.opts.buttonSeparator)); 46297 else if(this.opts.toolbar[btnName]) 46298 { 46299 var btnObject = this.opts.toolbar[btnName]; 46300 if (this.opts.fileUpload === false && btnName === 'file') return true; 46301 this.$toolbar.append( $('<li>').append(this.buttonBuild(btnName, btnObject))); 46302 } 46303 46304 }, this)); 46305 46306 this.$toolbar.find('a').attr('tabindex', '-1'); 46307 46308 // fixed 46309 if (this.opts.toolbarFixed) 46310 { 46311 this.toolbarObserveScroll(); 46312 $(this.opts.toolbarFixedTarget).on('scroll.redactor', $.proxy(this.toolbarObserveScroll, this)); 46313 } 46314 46315 // buttons response 46316 if (this.opts.activeButtons) 46317 { 46318 var buttonActiveObserver = $.proxy(this.buttonActiveObserver, this); 46319 this.$editor.on('mouseup.redactor keyup.redactor', buttonActiveObserver); 46320 } 46321 }, 46322 toolbarObserveScroll: function() 46323 { 46324 var scrollTop = $(this.opts.toolbarFixedTarget).scrollTop(); 46325 var boxTop = this.$box.offset().top; 46326 var left = 0; 46327 46328 var end = boxTop + this.$box.height() + 40; 46329 46330 if (scrollTop > boxTop) 46331 { 46332 var width = '100%'; 46333 if (this.opts.toolbarFixedBox) 46334 { 46335 left = this.$box.offset().left; 46336 width = this.$box.innerWidth(); 46337 this.$toolbar.addClass('toolbar_fixed_box'); 46338 } 46339 46340 this.toolbarFixed = true; 46341 this.$toolbar.css({ 46342 position: 'fixed', 46343 width: width, 46344 zIndex: 1005,
46345 top: this.opts.toolbarFixedTopOffset + 'px', 46346 left: left 46347 }); 46348 46349 if (scrollTop < end) this.$toolbar.css('visibility', 'visible'); 46350 else this.$toolbar.css('visibility', 'hidden'); 46351 } 46352 else 46353 { 46354 this.toolbarFixed = false; 46355 this.$toolbar.css({ 46356 position: 'relative', 46357 width: 'auto', 46358 top: 0, 46359 left: left 46360 }); 46361 46362 if (this.opts.toolbarFixedBox) this.$toolbar.removeClass('toolbar_fixed_box'); 46363 } 46364 }, 46365 46366 // AIR 46367 airEnable: function() 46368 { 46369 if (!this.opts.air) return; 46370 46371 this.$editor.on('mouseup.redactor keyup.redactor', this, $.proxy(function(e) 46372 { 46373 var text = this.getSelectionText(); 46374 46375 if (e.type === 'mouseup' && text != '') this.airShow(e); 46376 if (e.type === 'keyup' && e.shiftKey && text != '') 46377 { 46378 var $focusElem = $(this.getElement(this.getSelection().focusNode)), offset = $focusElem.offset(); 46379 offset.height = $focusElem.height(); 46380 this.airShow(offset, true); 46381 } 46382 46383 }, this)); 46384 }, 46385 airShow: function (e, keyboard) 46386 { 46387 if (!this.opts.air) return; 46388 46389 var left, top; 46390 $('.redactor_air').hide(); 46391 46392 if (keyboard) 46393 { 46394 left = e.left; 46395 top = e.top + e.height + 14; 46396 46397 if (this.opts.iframe) 46398 { 46399 top += this.$box.position().top - $(this.document).scrollTop(); 46400 left += this.$box.position().left; 46401 } 46402 } 46403 else 46404 { 46405 var width = this.$air.innerWidth(); 46406 46407 left = e.clientX; 46408 if ($(this.document).width() < (left + width)) left -= width; 46409 46410 top = e.clientY + 14; 46411 if (this.opts.iframe) 46412 { 46413 top += this.$box.position().top; 46414 left += this.$box.position().left; 46415 } 46416 else top += $( this.document ).scrollTop(); 46417 } 46418 46419 this.$air.css({ 46420 left: left + 'px', 46421 top: top + 'px' 46422 }).show(); 46423 46424 this.airBindHide(); 46425 }, 46426 airBindHide: function() 46427 { 46428 if (!this.opts.air) return; 46429 46430 var hideHandler = $.proxy(function(doc) 46431 { 46432 $(doc).on('mousedown.redactor', $.proxy(function(e) 46433 { 46434 if ($( e.target ).closest(this.$toolbar).length === 0) 46435 { 46436 this.$air.fadeOut(100); 46437 this.selectionRemove(); 46438 $(doc).off(e); 46439 } 46440 46441 }, this)).on('keydown.redactor', $.proxy(function(e) 46442 { 46443 if (e.which === this.keyCode.ESC) 46444 { 46445 this.getSelection().collapseToStart(); 46446 } 46447 46448 this.$air.fadeOut(100); 46449 $(doc).off(e); 46450 46451 }, this)); 46452 }, this); 46453 46454 // Hide the toolbar at events in all documents (iframe) 46455 hideHandler(document); 46456 if (this.opts.iframe) hideHandler(this.document); 46457 }, 46458 airBindMousemoveHide: function() 46459 { 46460 if (!this.opts.air) return; 46461 46462 var hideHandler = $.proxy(function(doc) 46463 { 46464 $(doc).on('mousemove.redactor', $.proxy(function(e) 46465 { 46466 if ($( e.target ).closest(this.$toolbar).length === 0) 46467 { 46468 this.$air.fadeOut(100); 46469 $(doc).off(e); 46470 } 46471 46472 }, this)); 46473 }, this); 46474 46475 // Hide the toolbar at events in all documents (iframe) 46476 hideHandler(document); 46477 if (this.opts.iframe) hideHandler(this.document); 46478 }, 46479 46480 // DROPDOWNS 46481 dropdownBuild: function($dropdown, dropdownObject) 46482 { 46483 $.each(dropdownObject, $.proxy(function(btnName, btnObject) 46484 { 46485 if (!btnObject.className) btnObject.className = ''; 46486 46487 var $item; 46488 if (btnObject.name === 'separator') $item = $('<a class="redactor_separator_drop">'); 46489 else 46490 { 46491 $item = $('<a href="#" class="' + btnObject.className + ' redactor_dropdown_' + btnName + '">' + btnObject.title + '</a>'); 46492 $item.on('click', $.proxy(function(e) 46493 { 46494 if (e.preventDefault) e.preventDefault(); 46495 if (this.browser('msie')) e.returnValue = false; 46496 46497 if (btnObject.callback) btnObject.callback.call(this, btnName, $item, btnObject, e); 46498 if (btnObject.exec) this.execCommand(btnObject.exec, btnName); 46499 if (btnObject.func) this[btnObject.func](btnName); 46500 46501 this.buttonActiveObserver(); 46502 if (this.opts.air) this.$air.fadeOut(100); 46503 46504 }, this)); 46505 } 46506 46507 $dropdown.append($item); 46508 46509 }, this)); 46510 }, 46511 dropdownShow: function(e, key) 46512 { 46513 if (!this.opts.visual) 46514 { 46515 e.preventDefault(); 46516 return false; 46517 } 46518 46519 var $dropdown = this.$toolbar.find('.redactor_dropdown_box_' + key); 46520 var $button = this.buttonGet(key); 46521 46522 if ($button.hasClass('dropact')) this.dropdownHideAll(); 46523 else 46524 {
46525 this.dropdownHideAll(); 46526 46527 this.buttonActive(key); 46528 $button.addClass('dropact'); 46529 46530 var keyPosition = $button.position(); 46531 if (this.toolbarFixed) 46532 { 46533 keyPosition = $button.offset(); 46534 } 46535 46536 // fix right placement 46537 var dropdownWidth = $dropdown.width(); 46538 if ((keyPosition.left + dropdownWidth) > $(document).width()) 46539 { 46540 keyPosition.left -= dropdownWidth; 46541 } 46542 46543 var left = keyPosition.left + 'px'; 46544 var btnHeight = 29; 46545 46546 var position = 'absolute'; 46547 var top = btnHeight + 'px'; 46548 46549 if (this.opts.toolbarFixed && this.toolbarFixed) position = 'fixed'; 46550 else if (!this.opts.air) top = keyPosition.top + btnHeight + 'px'; 46551 46552 $dropdown.css({ position: position, left: left, top: top }).show(); 46553 } 46554 46555 46556 var hdlHideDropDown = $.proxy(function(e) 46557 { 46558 this.dropdownHide(e, $dropdown); 46559 46560 }, this); 46561 46562 $(document).one('click', hdlHideDropDown); 46563 this.$editor.one('click', hdlHideDropDown); 46564 46565 e.stopPropagation(); 46566 }, 46567 dropdownHideAll: function() 46568 { 46569 this.$toolbar.find('a.dropact').removeClass('redactor_act').removeClass('dropact'); 46570 $('.redactor_dropdown').hide(); 46571 }, 46572 dropdownHide: function (e, $dropdown) 46573 { 46574 if (!$(e.target).hasClass('dropact')) 46575 { 46576 $dropdown.removeClass('dropact'); 46577 this.dropdownHideAll(); 46578 } 46579 }, 46580 46581 // BUTTONS 46582 buttonBuild: function(btnName, btnObject) 46583 { 46584 var $button = $('<a href="javascript:;" title="' + btnObject.title + '" tabindex="-1" class="redactor_btn redactor_btn_' + btnName + '"></a>'); 46585 46586 $button.on('click', $.proxy(function(e) 46587 { 46588 if (e.preventDefault) e.preventDefault(); 46589 if (this.browser('msie')) e.returnValue = false; 46590 46591 if ($button.hasClass('redactor_button_disabled')) return false; 46592 46593 if (this.isFocused() === false && !btnObject.exec) 46594 { 46595 this.$editor.focus(); 46596 } 46597 46598 if (btnObject.exec) 46599 { 46600 this.$editor.focus(); 46601 this.execCommand(btnObject.exec, btnName); 46602 this.airBindMousemoveHide(); 46603 46604 } 46605 else if (btnObject.func && btnObject.func !== 'show') 46606 { 46607 this[btnObject.func](btnName); 46608 this.airBindMousemoveHide(); 46609 46610 } 46611 else if (btnObject.callback) 46612 { 46613 btnObject.callback.call(this, btnName, $button, btnObject, e); 46614 this.airBindMousemoveHide(); 46615 46616 } 46617 else if (btnObject.dropdown) 46618 { 46619 this.dropdownShow(e, btnName); 46620 } 46621 46622 this.buttonActiveObserver(false, btnName); 46623 46624 }, this)); 46625 46626 // dropdown 46627 if (btnObject.dropdown) 46628 { 46629 var $dropdown = $('<div class="redactor_dropdown redactor_dropdown_box_' + btnName + '" style="display: none;">'); 46630 $dropdown.appendTo(this.$toolbar); 46631 this.dropdownBuild($dropdown, btnObject.dropdown); 46632 } 46633 46634 return $button; 46635 }, 46636 buttonGet: function(key) 46637 { 46638 if (!this.opts.toolbar) return false; 46639 return $(this.$toolbar.find('a.redactor_btn_' + key)); 46640 }, 46641 buttonActiveToggle: function(key) 46642 { 46643 var btn = this.buttonGet(key); 46644 46645 if (btn.hasClass('redactor_act')) btn.removeClass('redactor_act'); 46646 else btn.addClass('redactor_act'); 46647 }, 46648 buttonActive: function(key) 46649 { 46650 this.buttonGet(key).addClass('redactor_act'); 46651 }, 46652 buttonInactive: function(key) 46653 { 46654 this.buttonGet(key).removeClass('redactor_act'); 46655 }, 46656 buttonInactiveAll: function(btnName) 46657 { 46658 $.each(this.opts.toolbar, $.proxy(function(k) 46659 { 46660 if (k != btnName) this.buttonInactive(k); 46661 46662 }, this)); 46663 }, 46664 buttonActiveVisual: function() 46665 { 46666 this.$toolbar.find('a.redactor_btn').not('a.redactor_btn_html').removeClass('redactor_button_disabled'); 46667 }, 46668 buttonInactiveVisual: function() 46669 { 46670 this.$toolbar.find('a.redactor_btn').not('a.redactor_btn_html').addClass('redactor_button_disabled'); 46671 }, 46672 buttonChangeIcon: function (key, classname) 46673 { 46674 this.buttonGet(key).addClass('redactor_btn_' + classname); 46675 }, 46676 buttonRemoveIcon: function(key, classname) 46677 { 46678 this.buttonGet(key).removeClass('redactor_btn_' + classname); 46679 }, 46680 buttonAddSeparator: function() 46681 { 46682 this.$toolbar.append($(this.opts.buttonSeparator)); 46683 }, 46684 buttonAddSeparatorAfter: function(key) 46685 { 46686 this.buttonGet(key).parent().after($(this.opts.buttonSeparator)); 46687 }, 46688 buttonAddSeparatorBefore: function(key) 46689 { 46690 this.buttonGet(key).parent().before($(this.opts.buttonSeparator)); 46691 }, 46692 buttonRemoveSeparatorAfter: function(key) 46693 { 46694 this.buttonGet(key).parent().next().remove(); 46695 }, 46696 buttonRemoveSeparatorBefore: function(key) 46697 { 46698 this.buttonGet(key).parent().prev().remove(); 46699 }, 46700 buttonSetRight: function(key) 46701 { 46702 if (!this.opts.toolbar) return; 46703 this.buttonGet(key).parent().addClass('redactor_btn_right'); 46704 }, 46705 buttonSetLeft: function(key) 46706 { 46707 if (!this.opts.toolbar) return; 46708 this.buttonGet(key).parent().removeClass('redactor_btn_right'); 46709 }, 46710 buttonAdd: function(key, title, callback, dropdown) 46711 { 46712 if (!this.opts.toolbar) return; 46713 var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); 46714 this.$toolbar.append( $('<li>').append(btn)); 46715 }, 46716 buttonAddFirst: function(key, title, callback, dropdown) 46717 { 46718 if (!this.opts.toolbar) return; 46719 var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown });
46720 this.$toolbar.prepend($('<li>').append(btn)); 46721 }, 46722 buttonAddAfter: function(afterkey, key, title, callback, dropdown) 46723 { 46724 if (!this.opts.toolbar) return; 46725 var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); 46726 var $btn = this.buttonGet(afterkey); 46727 46728 if ($btn.size() !== 0) $btn.parent().after($('<li>').append(btn)); 46729 else this.$toolbar.append($('<li>').append(btn)); 46730 }, 46731 buttonAddBefore: function(beforekey, key, title, callback, dropdown) 46732 { 46733 if (!this.opts.toolbar) return; 46734 var btn = this.buttonBuild(key, { title: title, callback: callback, dropdown: dropdown }); 46735 var $btn = this.buttonGet(beforekey); 46736 46737 if ($btn.size() !== 0) $btn.parent().before($('<li>').append(btn)); 46738 else this.$toolbar.append($('<li>').append(btn)); 46739 }, 46740 buttonRemove: function (key, separator) 46741 { 46742 var $btn = this.buttonGet(key); 46743 if (separator) $btn.parent().next().remove(); 46744 $btn.parent().removeClass('redactor_btn_right'); 46745 $btn.remove(); 46746 }, 46747 buttonActiveObserver: function(e, btnName) 46748 { 46749 var parent = this.getParent(); 46750 this.buttonInactiveAll(btnName); 46751 46752 if (e === false && btnName !== 'html') 46753 { 46754 if ($.inArray(btnName, this.opts.activeButtons) != -1) 46755 { 46756 this.buttonActiveToggle(btnName); 46757 } 46758 return; 46759 } 46760 46761 if (parent && parent.tagName === 'A') this.$toolbar.find('a.redactor_dropdown_link').text(this.opts.curLang.link_edit); 46762 else this.$toolbar.find('a.redactor_dropdown_link').text(this.opts.curLang.link_insert); 46763 46764 if (this.opts.activeButtonsAdd) 46765 { 46766 $.each(this.opts.activeButtonsAdd, $.proxy(function(i,s) 46767 { 46768 this.opts.activeButtons.push(s); 46769 46770 }, this)); 46771 46772 $.extend(this.opts.activeButtonsStates, this.opts.activeButtonsAdd); 46773 } 46774 46775 $.each(this.opts.activeButtonsStates, $.proxy(function(key, value) 46776 { 46777 if ($(parent).closest(key, this.$editor.get()[0]).length != 0) 46778 { 46779 this.buttonActive(value); 46780 } 46781 46782 }, this)); 46783 46784 var $parent = $(parent).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]); 46785 if ($parent.length) 46786 { 46787 var align = $parent.css('text-align'); 46788 46789 switch (align) 46790 { 46791 case 'right': 46792 this.buttonActive('alignright'); 46793 break; 46794 case 'center': 46795 this.buttonActive('aligncenter'); 46796 break; 46797 case 'justify': 46798 this.buttonActive('justify'); 46799 break; 46800 default: 46801 this.buttonActive('alignleft'); 46802 break; 46803 } 46804 } 46805 }, 46806 46807 // EXEC 46808 exec: function(cmd, param, sync) 46809 { 46810 if (cmd === 'formatblock' && this.browser('msie')) param = '<' + param + '>'; 46811 46812 if (cmd === 'inserthtml' && this.browser('msie')) 46813 { 46814 this.$editor.focus(); 46815 this.document.selection.createRange().pasteHTML(param); 46816 } 46817 else 46818 { 46819 this.document.execCommand(cmd, false, param); 46820 } 46821 46822 if (sync !== false) this.sync(); 46823 this.callback('execCommand', cmd, param); 46824 }, 46825 execCommand: function(cmd, param, sync) 46826 { 46827 if (!this.opts.visual) 46828 { 46829 this.$source.focus(); 46830 return false; 46831 } 46832 46833 if (cmd === 'inserthtml') 46834 { 46835 this.insertHtml(param, sync); 46836 this.callback('execCommand', cmd, param); 46837 return; 46838 } 46839 46840 // stop formatting pre 46841 if (this.currentOrParentIs('PRE') && !this.opts.formattingPre) 46842 { 46843 return false; 46844 } 46845 46846 if (cmd === 'insertunorderedlist' || cmd === 'insertorderedlist') 46847 { 46848 this.bufferSet(); 46849 46850 var parent = this.getParent(); 46851 var $list = $(parent).closest('ol, ul'); 46852 var remove = false; 46853 46854 if ($list.length) 46855 { 46856 remove = true; 46857 var listTag = $list[0].tagName; 46858 if ((cmd === 'insertunorderedlist' && listTag === 'OL') 46859 || (cmd === 'insertorderedlist' && listTag === 'UL')) 46860 { 46861 remove = false; 46862 } 46863 } 46864 46865 this.selectionSave(); 46866 46867 // remove lists 46868 if (remove) 46869 { 46870 var nodes = this.getNodes(); 46871 var elems = this.getBlocks(nodes); 46872 46873 if (typeof nodes[0] != 'undefined' && nodes.length > 1 && nodes[0].nodeType == 3) 46874 { 46875 // fix the adding the first li to the array 46876 elems.unshift(this.getBlock()); 46877 } 46878 46879 var data = '', replaced = ''; 46880 $.each(elems, $.proxy(function(i,s) 46881 { 46882 if (s.tagName == 'LI') 46883 { 46884 var $s = $(s); 46885 var cloned = $s.clone(); 46886 cloned.find('ul', 'ol').remove(); 46887 46888 if (this.opts.linebreaks === false) data += this.outerHtml($('<p>').append(cloned.contents())); 46889 else data += cloned.html() + '<br>'; 46890 46891 if (i == 0) 46892 { 46893 $s.addClass('redactor-replaced').empty(); 46894 replaced = this.outerHtml($s); 46895 } 46896 else $s.remove(); 46897 } 46898 46899 }, this)); 46900 46901 html = this.$editor.html().replace(replaced, '</' + listTag + '>' + data + '<' + listTag + '>'); 46902 46903 this.$editor.html(html); 46904 this.$editor.find(listTag + ':empty').remove(); 46905 46906 } 46907 46908 // insert lists 46909 else 46910 { 46911 this.document.execCommand(cmd); 46912 46913 var parent = this.getParent(); 46914 var $list = $(parent).closest('ol, ul'); 46915 46916 if ($list.length) 46917 { 46918 if ((this.browser('msie') || this.browser('mozilla')) && parent.tagName !== 'LI') 46919 { 46920 $(parent).replaceWith($(parent).html()); 46921 } 46922 46923 var $listParent = $list.parent(); 46924 if (this.isParentRedactor($listParent) && this.nodeTestBlocks($listParent[0])) 46925 { 46926 $listParent.replaceWith($listParent.contents()); 46927 } 46928 } 46929 46930 if (this.browser('mozilla')) this.$editor.focus(); 46931 46932 } 46933 46934 this.selectionRestore(); 46935 46936 this.sync(); 46937 this.callback('execCommand', cmd, param); 46938 return; 46939 } 46940 46941 if (cmd === 'unlink') 46942 { 46943 this.bufferSet(); 46944 46945 var link = this.currentOrParentIs('A'); 46946 if (link) 46947 { 46948 $(link).replaceWith($(link).text()); 46949 46950 this.sync(); 46951 this.callback('execCommand', cmd, param); 46952 return; 46953 } 46954 } 46955 46956 this.exec(cmd, param, sync); 46957 46958 if (cmd === 'inserthorizontalrule') 46959 { 46960 this.$editor.find('hr').removeAttr('id'); 46961 } 46962 }, 46963 46964 // INDENTING 46965 indentingIndent: function() 46966 { 46967 this.indentingStart('indent'); 46968 }, 46969 indentingOutdent: function() 46970 { 46971 this.indentingStart('outdent'); 46972 }, 46973 indentingStart: function(cmd) 46974 { 46975 this.bufferSet(); 46976 46977 if (cmd === 'indent') 46978 { 46979 var block = this.getBlock(); 46980 46981 this.selectionSave(); 46982 46983 if (block && block.tagName == 'LI') 46984 { 46985 // li 46986 var parent = this.getParent(); 46987 46988 var $list = $(parent).closest('ol, ul'); 46989 var listTag = $list[0].tagName; 46990 46991 var elems = this.getBlocks(); 46992 46993 $.each(elems, function(i,s) 46994 { 46995 if (s.tagName == 'LI') 46996 { 46997 var $prev = $(s).prev(); 46998 if ($prev.size() != 0 && $prev[0].tagName == 'LI') 46999 { 47000 var $childList = $prev.children('ul, ol'); 47001 if ($childList.size() == 0) 47002 { 47003 $prev.append($('<' + listTag + '>').append(s)); 47004 } 47005 else $childList.append(s); 47006 } 47007 } 47008 }); 47009 } 47010 // linebreaks 47011 else if (block === false && this.opts.linebreaks === true) 47012 { 47013 this.exec('formatBlock', 'blockquote'); 47014 var newblock = this.getBlock(); 47015 var block = $('<div data-tagblock="">').html($(newblock).html()); 47016 $(newblock).replaceWith(block); 47017 47018 var left = this.normalize($(block).css('margin-left')) + this.opts.indentValue; 47019 $(block).css('margin-left', left + 'px'); 47020 } 47021 else 47022 { 47023 // all block tags 47024 var elements = this.getBlocks(); 47025 $.each(elements, $.proxy(function(i, elem) 47026 { 47027 var $el = false;
47028 47029 if (elem.tagName === 'TD') return; 47030 47031 if ($.inArray(elem.tagName, this.opts.alignmentTags) !== -1) 47032 { 47033 $el = $(elem); 47034 } 47035 else 47036 { 47037 $el = $(elem).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]); 47038 } 47039 47040 var left = this.normalize($el.css('margin-left')) + this.opts.indentValue; 47041 $el.css('margin-left', left + 'px'); 47042 47043 }, this)); 47044 } 47045 47046 this.selectionRestore(); 47047 47048 } 47049 // outdent 47050 else 47051 { 47052 this.selectionSave(); 47053 47054 var block = this.getBlock(); 47055 if (block && block.tagName == 'LI') 47056 { 47057 // li 47058 var elems = this.getBlocks(); 47059 var index = 0; 47060 47061 this.insideOutdent(block, index, elems); 47062 } 47063 else 47064 { 47065 // all block tags 47066 var elements = this.getBlocks(); 47067 $.each(elements, $.proxy(function(i, elem) 47068 { 47069 var $el = false; 47070 47071 if ($.inArray(elem.tagName, this.opts.alignmentTags) !== -1) 47072 { 47073 $el = $(elem); 47074 } 47075 else 47076 { 47077 $el = $(elem).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]); 47078 } 47079 47080 var left = this.normalize($el.css('margin-left')) - this.opts.indentValue; 47081 if (left <= 0) 47082 { 47083 // linebreaks 47084 if (this.opts.linebreaks === true && typeof($el.data('tagblock')) !== 'undefined') 47085 { 47086 $el.replaceWith($el.html()); 47087 } 47088 // all block tags 47089 else 47090 { 47091 $el.css('margin-left', ''); 47092 this.removeEmptyAttr($el, 'style'); 47093 } 47094 } 47095 else 47096 { 47097 $el.css('margin-left', left + 'px'); 47098 } 47099 47100 }, this)); 47101 } 47102 47103 47104 this.selectionRestore(); 47105 } 47106 47107 this.sync(); 47108 47109 }, 47110 insideOutdent: function (li, index, elems) 47111 { 47112 if (li && li.tagName == 'LI') 47113 { 47114 var $parent = $(li).parent().parent(); 47115 if ($parent.size() != 0 && $parent[0].tagName == 'LI') 47116 { 47117 $parent.after(li); 47118 } 47119 else 47120 { 47121 if (typeof elems[index] != 'undefined') 47122 { 47123 li = elems[index]; 47124 index++; 47125 47126 this.insideOutdent(li, index, elems); 47127 } 47128 else 47129 { 47130 this.execCommand('insertunorderedlist'); 47131 } 47132 } 47133 } 47134 }, 47135 47136 // ALIGNMENT 47137 alignmentLeft: function() 47138 { 47139 this.alignmentSet('', 'JustifyLeft'); 47140 }, 47141 alignmentRight: function() 47142 { 47143 this.alignmentSet('right', 'JustifyRight'); 47144 }, 47145 alignmentCenter: function() 47146 { 47147 this.alignmentSet('center', 'JustifyCenter'); 47148 }, 47149 alignmentJustify: function() 47150 { 47151 this.alignmentSet('justify', 'JustifyFull'); 47152 }, 47153 alignmentSet: function(type, cmd) 47154 { 47155 this.bufferSet(); 47156 47157 if (this.oldIE()) 47158 { 47159 this.document.execCommand(cmd, false, false); 47160 return true; 47161 } 47162 47163 this.selectionSave(); 47164 47165 var block = this.getBlock(); 47166 if (!block && this.opts.linebreaks) 47167 { 47168 // one element 47169 this.exec('formatBlock', 'blockquote'); 47170 var newblock = this.getBlock(); 47171 var block = $('<div data-tagblock="">').html($(newblock).html()); 47172 $(newblock).replaceWith(block); 47173 47174 $(block).css('text-align', type); 47175 this.removeEmptyAttr(block, 'style'); 47176 47177 if (type == '' && typeof($(block).data('tagblock')) !== 'undefined') 47178 { 47179 $(block).replaceWith($(block).html()); 47180 } 47181 } 47182 else 47183 { 47184 var elements = this.getBlocks(); 47185 $.each(elements, $.proxy(function(i, elem) 47186 { 47187 var $el = false; 47188 47189 if ($.inArray(elem.tagName, this.opts.alignmentTags) !== -1) 47190 { 47191 $el = $(elem); 47192 } 47193 else 47194 { 47195 $el = $(elem).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]); 47196 } 47197 47198 if ($el) 47199 { 47200 $el.css('text-align', type); 47201 this.removeEmptyAttr($el, 'style'); 47202 } 47203 47204 }, this)); 47205 } 47206 47207 this.selectionRestore(); 47208 47209 this.sync(); 47210 }, 47211 47212 // CLEAN 47213 cleanEmpty: function(html) 47214 { 47215 var ph = this.placeholderStart(html); 47216 if (ph !== false) return ph; 47217 47218 if (this.opts.linebreaks === false) 47219 { 47220 if (html === '') html = this.opts.emptyHtml; 47221 else if (html.search(/^<hr\s?\/?>$/gi) !== -1) html = '<hr>' + this.opts.emptyHtml; 47222 } 47223 47224 return html; 47225 }, 47226 cleanConverters: function(html) 47227 { 47228 // convert div to p 47229 if (this.opts.convertDivs) html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>'); 47230 if (this.opts.paragraphy) html = this.cleanParagraphy(html); 47231 47232 return html; 47233 }, 47234 cleanConvertProtected: function(html) 47235 { 47236 if (this.opts.templateVars) 47237 { 47238 html = html.replace(/\{\{(.*?)\}\}/gi, '<!-- template double $1 -->'); 47239 html = html.replace(/\{(.*?)\}/gi, '<!-- template $1 -->'); 47240 } 47241 47242 html = html.replace(/<script(.*?)>([\w\W]*?)<\/script>/gi, '<title type="text/javascript" style="display: none;" class="redactor-script-tag"$1>$2</title>'); 47243 html = html.replace(/<style(.*?)>([\w\W]*?)<\/style>/gi, '<section$1 style="display: none;" rel="redactor-style-tag">$2</section>'); 47244 html = html.replace(/<form(.*?)>([\w\W]*?)<\/form>/gi, '<section$1 rel="redactor-form-tag">$2</section>'); 47245 47246 // php tags convertation 47247 if (this.opts.phpTags) html = html.replace(/<\?php([\w\W]*?)\?>/gi, '<section style="display: none;" rel="redactor-php-tag">$1</section>'); 47248 else html = html.replace(/<\?php([\w\W]*?)\?>/gi, ''); 47249 47250 return html; 47251 }, 47252 cleanReConvertProtected: function(html) 47253 { 47254 if (this.opts.templateVars) 47255 { 47256 html = html.replace(/<!-- template double (.*?) -->/gi, '{{$1}}'); 47257 html = html.replace(/<!-- template (.*?) -->/gi, '{$1}'); 47258 } 47259 47260 html = html.replace(/<title type="text\/javascript" style="display: none;" class="redactor-script-tag"(.*?)>([\w\W]*?)<\/title>/gi, '<script$1 type="text/javascript">$2</script>'); 47261 html = html.replace(/<section(.*?) style="display: none;" rel="redactor-style-tag">([\w\W]*?)<\/section>/gi, '<style$1>$2</style>'); 47262 html = html.replace(/<section(.*?)rel="redactor-form-tag"(.*?)>([\w\W]*?)<\/section>/gi, '<form$1$2>$3</form>'); 47263 47264 // php tags convertation 47265 if (this.opts.phpTags) html = html.replace(/<section style="display: none;" rel="redactor-php-tag">([\w\W]*?)<\/section>/gi, '<?php\r\n$1\r\n?>'); 47266 47267 return html; 47268 }, 47269 cleanRemoveSpaces: function(html, buffer) 47270 { 47271 if (buffer !== false) 47272 { 47273 var buffer = [] 47274 var matches = html.match(/<(pre|style|script|title)(.*?)>
47274([\w\W]*?)<\/(pre|style|script|title)>/gi); 47275 if (matches === null) matches = []; 47276 47277 if (this.opts.phpTags) 47278 { 47279 var phpMatches = html.match(/<\?php([\w\W]*?)\?>/gi); 47280 if (phpMatches) matches = $.merge(matches, phpMatches); 47281 } 47282 47283 if (matches) 47284 { 47285 $.each(matches, function(i, s) 47286 { 47287 html = html.replace(s, 'buffer_' + i); 47288 buffer.push(s); 47289 }); 47290 } 47291 } 47292 47293 html = html.replace(/\n/g, ' '); 47294 html = html.replace(/[\t]*/g, ''); 47295 html = html.replace(/\n\s*\n/g, "\n"); 47296 html = html.replace(/^[\s\n]*/g, ' '); 47297 html = html.replace(/[\s\n]*$/g, ' '); 47298 html = html.replace( />\s{2,}</g, '> <'); // between inline tags can be only one space 47299 47300 html = this.cleanReplacer(html, buffer); 47301 47302 html = html.replace(/\n\n/g, "\n"); 47303 47304 return html; 47305 }, 47306 cleanReplacer: function(html, buffer) 47307 { 47308 if (buffer === false) return html; 47309 47310 $.each(buffer, function(i,s) 47311 { 47312 html = html.replace('buffer_' + i, s); 47313 }); 47314 47315 return html; 47316 }, 47317 cleanRemoveEmptyTags: function(html) 47318 { 47319 html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1'); 47320 47321 // remove zero width-space 47322 html = html.replace(/[\u200B-\u200D\uFEFF]/g, ''); 47323 47324 var etagsInline = ["<b>\\s*</b>", "<b> </b>", "<em>\\s*</em>"] 47325 var etags = ["<pre></pre>", "<blockquote>\\s*</blockquote>", "<dd></dd>", "<dt></dt>", "<ul></ul>", "<ol></ol>", "<li></li>", "<table></table>", "<tr></tr>", "<span>\\s*<span>", "<span> <span>", "<p>\\s*</p>", "<p></p>", "<p> </p>", "<p>\\s*<br>\\s*</p>", "<div>\\s*</div>", "<div>\\s*<br>\\s*</div>"]; 47326 47327 if (this.opts.removeEmptyTags) 47328 { 47329 etags = etags.concat(etagsInline); 47330 } 47331 else etags = etagsInline; 47332 47333 var len = etags.length; 47334 for (var i = 0; i < len; ++i) 47335 { 47336 html = html.replace(new RegExp(etags[i], 'gi'), ""); 47337 } 47338 47339 return html; 47340 }, 47341 cleanParagraphy: function(html) 47342 { 47343 html = $.trim(html); 47344 47345 if (this.opts.linebreaks === true) return html; 47346 if (html === '' || html === '<p></p>') return this.opts.emptyHtml; 47347 47348 html = html + "\n"; 47349 47350 47351 var safes = []; 47352 var matches = html.match(/<(table|div|pre|object)(.*?)>([\w\W]*?)<\/(table|div|pre|object)>/gi); 47353 if (!matches) matches = []; 47354 47355 var commentsMatches = html.match(/<!--([\w\W]*?)-->/gi); 47356 if (commentsMatches) matches = $.merge(matches, commentsMatches); 47357 47358 if (this.opts.phpTags) 47359 { 47360 var phpMatches = html.match(/<section(.*?)rel="redactor-php-tag">([\w\W]*?)<\/section>/gi); 47361 if (phpMatches) matches = $.merge(matches, phpMatches); 47362 } 47363 47364 if (matches) 47365 { 47366 $.each(matches, function(i,s) 47367 { 47368 safes[i] = s; 47369 html = html.replace(s, '{replace' + i + '}\n'); 47370 }); 47371 } 47372 47373 html = html.replace(/<br \/>\s*<br \/>/gi, "\n\n"); 47374 47375 function R(str, mod, r) 47376 { 47377 return html.replace(new RegExp(str, mod), r); 47378 } 47379 47380 var blocks = '(comment|html|body|head|title|meta|style|script|link|iframe|table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)'; 47381 47382 html = R('(<' + blocks + '[^>]*>)', 'gi', "\n$1"); 47383 html = R('(</' + blocks + '>)', 'gi', "$1\n\n"); 47384 html = R("\r\n", 'g', "\n"); 47385 html = R("\r", 'g', "\n"); 47386 html = R("/\n\n+/", 'g', "\n\n"); 47387 47388 var htmls = html.split(new RegExp('\n\s*\n', 'g'), -1); 47389 47390 html = ''; 47391 for (var i in htmls) 47392 { 47393 if (htmls.hasOwnProperty(i)) 47394 { 47395 if (htmls[i].search('{replace') == -1) 47396 { 47397 html += '<p>' + htmls[i].replace(/^\n+|\n+$/g, "") + "</p>"; 47398 } 47399 else html += htmls[i]; 47400 } 47401 } 47402 47403 // blockquote 47404 if (html.search(/<blockquote/gi) !== -1) 47405 { 47406 $.each(html.match(/<blockquote(.*?)>([\w\W]*?)<\/blockquote>/gi), function(i,s) 47407 { 47408 var str = ''; 47409 str = s.replace('<p>', ''); 47410 str = str.replace('</p>', '<br>'); 47411 html = html.replace(s, str); 47412 }); 47413 } 47414 47415 html = R('<p>\s*</p>', 'gi', ''); 47416 html = R('<p>([^<]+)</(div|address|form)>', 'gi', "<p>$1</p></$2>"); 47417 html = R('<p>\s*(</?' + blocks + '[^>]*>)\s*</p>', 'gi', "$1"); 47418 html = R("<p>(<li.+?)</p>", 'gi', "$1"); 47419 html = R('<p>\s*(</?' + blocks + '[^>]*>)', 'gi', "$1"); 47420 47421 html = R('(</?' + blocks + '[^>]*>)\s*</p>', 'gi', "$1"); 47422 html = R('(</?' + blocks + '[^>]*>)\s*<br />', 'gi', "$1"); 47423 html = R('<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)', 'gi', '$1'); 47424 html = R("\n</p>", 'gi', '</p>'); 47425 47426 html = R('<li><p>
47426', 'gi', '<li>'); 47427 html = R('</p></li>', 'gi', '</li>'); 47428 html = R('</li><p>', 'gi', '</li>'); 47429 //html = R('</ul><p>(.*?)</li>', 'gi', '</ul></li>'); 47430 /* html = R('</ol><p>', 'gi', '</ol>'); */ 47431 html = R('<p>\t?\n?<p>', 'gi', '<p>'); 47432 html = R('</dt><p>', 'gi', '</dt>'); 47433 html = R('</dd><p>', 'gi', '</dd>'); 47434 html = R('<br></p></blockquote>', 'gi', '</blockquote>'); 47435 html = R('<p>\t*</p>', 'gi', ''); 47436 47437 47438 // restore safes 47439 $.each(safes, function(i,s) 47440 { 47441 html = html.replace('{replace' + i + '}', s); 47442 }); 47443 47444 return $.trim(html); 47445 }, 47446 cleanConvertInlineTags: function(html) 47447 { 47448 var boldTag = 'strong'; 47449 if (this.opts.boldTag === 'b') boldTag = 'b'; 47450 47451 var italicTag = 'em'; 47452 if (this.opts.italicTag === 'i') italicTag = 'i'; 47453 47454 html = html.replace(/<span style="font-style: italic;">([\w\W]*?)<\/span>/gi, '<' + italicTag + '>$1</' + italicTag + '>'); 47455 html = html.replace(/<span style="font-weight: bold;">([\w\W]*?)<\/span>/gi, '<' + boldTag + '>$1</' + boldTag + '>'); 47456 47457 // bold, italic, del 47458 if (this.opts.boldTag === 'strong') html = html.replace(/<b>([\w\W]*?)<\/b>/gi, '<strong>$1</strong>'); 47459 else html = html.replace(/<strong>([\w\W]*?)<\/strong>/gi, '<b>$1</b>'); 47460 47461 if (this.opts.italicTag === 'em') html = html.replace(/<i>([\w\W]*?)<\/i>/gi, '<em>$1</em>'); 47462 else html = html.replace(/<em>([\w\W]*?)<\/em>/gi, '<i>$1</i>'); 47463 47464 html = html.replace(/<strike>([\w\W]*?)<\/strike>/gi, '<del>$1</del>'); 47465 47466 return html; 47467 }, 47468 cleanStripTags: function(html) 47469 { 47470 if (html == '' || typeof html == 'undefined') return html; 47471 47472 var allowed = false; 47473 if (this.opts.allowedTags !== false) allowed = true; 47474 47475 var arr = allowed === true ? this.opts.allowedTags : this.opts.deniedTags; 47476 47477 var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi; 47478 html = html.replace(tags, function ($0, $1) 47479 { 47480 if (allowed === true) return $.inArray($1.toLowerCase(), arr) > '-1' ? $0 : ''; 47481 else return $.inArray($1.toLowerCase(), arr) > '-1' ? '' : $0; 47482 }); 47483 47484 html = this.cleanConvertInlineTags(html); 47485 47486 return html; 47487 47488 }, 47489 cleanSavePreCode: function(html, encode) 47490 { 47491 var pre = html.match(/<(pre|code)(.*?)>([\w\W]*?)<\/(pre|code)>/gi); 47492 if (pre !== null) 47493 { 47494 $.each(pre, $.proxy(function(i,s) 47495 { 47496 var arr = s.match(/<(pre|code)(.*?)>([\w\W]*?)<\/(pre|code)>/i); 47497 47498 arr[3] = arr[3].replace(/ /g, ' '); 47499 if (encode !== false) arr[3] = this.cleanEncodeEntities(arr[3]); 47500 47501 html = html.replace(s, '<' + arr[1] + arr[2] + '>' + arr[3] + '</' + arr[1] + '>'); 47502 47503 }, this)); 47504 } 47505 47506 return html; 47507 }, 47508 cleanEncodeEntities: function(str) 47509 { 47510 str = String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 47511 return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 47512 }, 47513 cleanUnverified: function() 47514 { 47515 // label, abbr, mark, meter, code, q, dfn, ins, time, kbd, var 47516 var $elem = this.$editor.find('li, img, a, b, strong, sub, sup, i, em, u, small, strike, del, span, cite'); 47517 47518 $elem.filter('[style*="background-color: transparent;"][style*="line-height"]') 47519 .css('background-color', '') 47520 .css('line-height', ''); 47521 47522 $elem.filter('[style*="background-color: transparent;"]') 47523 .css('background-color', ''); 47524 47525 $elem.css('line-height', ''); 47526 47527 $.each($elem, $.proxy(function(i,s) 47528 { 47529 this.removeEmptyAttr(s, 'style'); 47530 }, this)); 47531 47532 // When we paste text in Safari is wrapping inserted div (remove it) 47533 this.$editor.find('div[style="text-align: -webkit-auto;"]').contents().unwrap(); 47534 }, 47535 cleanHtml: function(code) 47536 { 47537 var i = 0, 47538 codeLength = code.length, 47539 point = 0, 47540 start = null, 47541 end = null, 47542 tag = '', 47543 out = '', 47544 cont = ''; 47545 47546 this.cleanlevel = 0; 47547 47548 for (; i < codeLength; i++) 47549 { 47550 point = i; 47551 47552 // if no more tags, copy and exit 47553 if (-1 == code.substr(i).indexOf( '<' )) 47554 { 47555 out += code.substr(i); 47556 47557 return this.cleanFinish(out); 47558 } 47559 47560 // copy verbatim until a tag 47561 while (point < codeLength && code.charAt(point) != '<') 47562 { 47563 point++; 47564 } 47565 47566 if (i != point) 47567 { 47568 cont = code.substr(i, point - i); 47569 if (!cont.match(/^\s{2,}$/g)) 47570 { 47571 if ('\n' == out.charAt(out.length - 1)) out += this.cleanGetTabs(); 47572 else if ('\n' == cont.charAt(0)) 47573 { 47574 out += '\n' + this.cleanGetTabs(); 47575 cont = cont.replace(/^\s+/, ''); 47576 } 47577 47578 out += cont; 47579 } 47580 47581 if (cont.match(/\n/)) out += '\n' + this.cleanGetTabs(); 47582 } 47583 47584 start = point; 47585 47586 // find the end of the tag 47587 while (point < codeLength && '>' != code.charAt(point)) 47588 { 47589 point++; 47590 } 47591 47592 tag = code.substr(start, point - start); 47593 i = point; 47594 47595 var t; 47596 47597 if ('!--' == tag.substr(1, 3)) 47598 { 47599 if (!tag.match(/--$/)) 47600 { 47601 while ('-->' != code.substr(point, 3)) 47602 { 47603 point++; 47604 } 47605 point += 2; 47606 tag = code.substr(start, point - start); 47607 i = point; 47608 } 47609 47610 if ('\n' != out.charAt(out.length - 1)) out += '\n'; 47611 47612 out += this.cleanGetTabs(); 47613 out += tag + '>\n'; 47614 } 47615 else if ('!' == tag[1]) 47616 { 47617 out = this.placeTag(tag + '>', out); 47618 } 47619 else if ('?' == tag[1]) 47620 { 47621 out += tag + '>\n'; 47622 } 47623 else if (t = tag.match(/^<(script|style|pre)/i)) 47624 { 47625 t[1] = t[1].toLowerCase(); 47626 tag = this.cleanTag(tag); 47627 out = this.placeTag(tag, out); 47628 end = String(code.substr(i + 1)).toLowerCase().indexOf('</' + t[1]); 47629 47630 if (end) 47631 { 47632 cont = code.substr(i + 1, end); 47633 i += end; 47634 out += cont; 47635 } 47636 } 47637 else 47638 { 47639 tag = this.cleanTag(tag); 47640 out = this.placeTag(tag, out); 47641 } 47642 } 47643 47644 return this.cleanFinish( out ); 47645 }, 47646 cleanGetTabs: function() 47647 { 47648 var s = ''; 47649 for ( var j = 0; j < this.cleanlevel; j++ ) 47650 { 47651 s += '\t'; 47652 } 47653 47654 return s; 47655 }, 47656 cleanFinish: function(code) 47657 {
47658 code = code.replace( /\n\s*\n/g, '\n' ); 47659 code = code.replace( /^[\s\n]*/, '' ); 47660 code = code.replace( /[\s\n]*$/, '' ); 47661 code = code.replace( /<script(.*?)>\n<\/script>/gi, '<script$1></script>' ); 47662 47663 this.cleanlevel = 0; 47664 47665 return code; 47666 }, 47667 cleanTag: function (tag) 47668 { 47669 var tagout = ''; 47670 tag = tag.replace(/\n/g, ' '); 47671 tag = tag.replace(/\s{2,}/g, ' '); 47672 tag = tag.replace(/^\s+|\s+$/g, ' '); 47673 47674 var suffix = ''; 47675 if (tag.match(/\/$/)) 47676 { 47677 suffix = '/'; 47678 tag = tag.replace(/\/+$/, ''); 47679 } 47680 47681 var m; 47682 while (m = /\s*([^= ]+)(?:=((['"']).*?\3|[^ ]+))?/.exec(tag)) 47683 { 47684 if (m[2]) tagout += m[1].toLowerCase() + '=' + m[2]; 47685 else if (m[1]) tagout += m[1].toLowerCase(); 47686 47687 tagout += ' '; 47688 tag = tag.substr(m[0].length); 47689 } 47690 47691 return tagout.replace(/\s*$/, '') + suffix + '>'; 47692 }, 47693 placeTag: function (tag, out) 47694 { 47695 var nl = tag.match(this.cleannewLevel); 47696 if (tag.match(this.cleanlineBefore) || nl) 47697 { 47698 out = out.replace(/\s*$/, ''); 47699 out += '\n'; 47700 } 47701 47702 if (nl && '/' == tag.charAt(1)) this.cleanlevel--; 47703 if ('\n' == out.charAt(out.length - 1)) out += this.cleanGetTabs(); 47704 if (nl && '/' != tag.charAt(1)) this.cleanlevel++; 47705 47706 out += tag; 47707 47708 if (tag.match(this.cleanlineAfter) || tag.match(this.cleannewLevel)) 47709 { 47710 out = out.replace(/ *$/, ''); 47711 out += '\n'; 47712 } 47713 47714 return out; 47715 }, 47716 47717 // FORMAT 47718 formatEmpty: function(e) 47719 { 47720 var html = $.trim(this.$editor.html()); 47721 47722 html = html.replace(/<br\s?\/?>/i, ''); 47723 var thtml = html.replace(/<p>\s?<\/p>/gi, ''); 47724 47725 if (html === '' || thtml === '') 47726 { 47727 e.preventDefault(); 47728 47729 var node = $(this.opts.emptyHtml).get(0); 47730 this.$editor.html(node); 47731 this.focus(); 47732 } 47733 47734 this.sync(); 47735 }, 47736 formatBlocks: function(tag) 47737 { 47738 this.bufferSet(); 47739 47740 var nodes = this.getBlocks(); 47741 this.selectionSave(); 47742 47743 $.each(nodes, $.proxy(function(i, node) 47744 { 47745 if (node.tagName !== 'LI') 47746 { 47747 this.formatBlock(tag, node); 47748 } 47749 47750 }, this)); 47751 47752 this.selectionRestore(); 47753 this.sync(); 47754 }, 47755 formatBlock: function(tag, block) 47756 { 47757 if (block === false) block = this.getBlock(); 47758 if (block === false) 47759 { 47760 if (this.opts.linebreaks === true) this.execCommand('formatblock', tag); 47761 return true; 47762 } 47763 47764 var contents = ''; 47765 if (tag !== 'pre') 47766 { 47767 contents = $(block).contents(); 47768 } 47769 else 47770 { 47771 //contents = this.cleanEncodeEntities($(block).text()); 47772 contents = $(block).html(); 47773 if ($.trim(contents) === '') 47774 { 47775 contents = '<span id="selection-marker-1"></span>'; 47776 } 47777 } 47778 47779 if (block.tagName === 'PRE') tag = 'p'; 47780 47781 if (this.opts.linebreaks === true && tag === 'p') 47782 { 47783 $(block).replaceWith($('<div>').append(contents).html() + '<br>'); 47784 } 47785 else 47786 { 47787 var node = $('<' + tag + '>').append(contents); 47788 $(block).replaceWith(node); 47789 } 47790 }, 47791 formatChangeTag: function(fromElement, toTagName, save) 47792 { 47793 if (save !== false) this.selectionSave(); 47794 47795 var newElement = $('<' + toTagName + '/>'); 47796 $(fromElement).replaceWith(function() { return newElement.append($(this).contents()); }); 47797 47798 if (save !== false) this.selectionRestore(); 47799 47800 return newElement; 47801 }, 47802 47803 // QUOTE 47804 formatQuote: function() 47805 { 47806 this.bufferSet(); 47807 47808 if (this.opts.linebreaks === false) 47809 { 47810 this.selectionSave(); 47811 47812 var blocks = this.getBlocks(); 47813 if (blocks) 47814 { 47815 $.each(blocks, $.proxy(function(i,s) 47816 { 47817 if (s.tagName === 'BLOCKQUOTE') 47818 { 47819 this.formatBlock('p', s, false); 47820 } 47821 else if (s.tagName !== 'LI') 47822 { 47823 this.formatBlock('blockquote', s, false); 47824 } 47825 47826 }, this)); 47827 } 47828 47829 this.selectionRestore(); 47830 } 47831 // linebreaks 47832 else 47833 { 47834 var block = this.getBlock(); 47835 if (block.tagName === 'BLOCKQUOTE') 47836 { 47837 this.selectionSave(); 47838 47839 $(block).replaceWith($(block).html() + '<br>'); 47840 47841 this.selectionRestore(); 47842 } 47843 else 47844 { 47845 var wrapper = this.selectionWrap('blockquote'); 47846 var html = $(wrapper).html(); 47847 47848 var blocksElemsRemove = ['ul', 'ol', 'table', 'tr', 'tbody', 'thead', 'tfoot', 'dl']; 47849 $.each(blocksElemsRemove, function(i,s) 47850 { 47851 html = html.replace(new RegExp('<' + s + '(.*?)>', 'gi'), ''); 47852 html = html.replace(new RegExp('</' + s + '>', 'gi'), ''); 47853 }); 47854 47855 var blocksElems = this.opts.blockLevelElements; 47856 blocksElems.push('td'); 47857 $.each(blocksElems, function(i,s) 47858 { 47859 html = html.replace(new RegExp('<' + s + '(.*?)>', 'gi'), ''); 47860 html = html.replace(new RegExp('</' + s + '>', 'gi'), '<br>'); 47861 }); 47862 47863 $(wrapper).html(html); 47864 this.selectionElement(wrapper); 47865 var next = $(wrapper).next(); 47866 if (next.size() != 0 && next[0].tagName === 'BR') 47867 { 47868 next.remove(); 47869 } 47870 } 47871 } 47872 47873 this.sync(); 47874 }, 47875 47876 // BLOCK 47877 blockRemoveAttr: function(attr, value) 47878 { 47879 var nodes = this.getBlocks(); 47880 $(nodes).removeAttr(attr); 47881 47882 this.sync(); 47883 }, 47884 blockSetAttr: function(attr, value) 47885 { 47886 var nodes = this.getBlocks(); 47887 $(nodes).attr(attr, value); 47888 47889 this.sync(); 47890 }, 47891 blockRemoveStyle: function(rule) 47892 { 47893 var nodes = this.getBlocks(); 47894 $(nodes).css(rule, ''); 47895 this.removeEmptyAttr(nodes, 'style'); 47896 47897 this.sync(); 47898 }, 47899 blockSetStyle: function (rule, value) 47900 { 47901 var nodes = this.getBlocks(); 47902 $(nodes).css(rule, value); 47903 47904 this.sync(); 47905 }, 47906 blockRemoveClass: function(className) 47907 { 47908 var nodes = this.getBlocks(); 47909 $(nodes).removeClass(className); 47910 this.removeEmptyAttr(nodes, 'class'); 47911 47912 this.sync(); 47913 }, 47914 blockSetClass: function(className) 47915 { 47916 var nodes = this.getBlocks(); 47917 $(nodes).addClass(className); 47918 47919 this.sync(); 47920 }, 47921 47922 // INLINE 47923 inlineRemoveClass: function(className) 47924 { 47925 this.selectionSave(); 47926 47927 this.inlineEachNodes(function(node) 47928 { 47929 $(node).removeClass(className); 47930 this.removeEmptyAttr(node, 'class'); 47931 }); 47932 47933 this.selectionRestore(); 47934 this.sync(); 47935 }, 47936 47937 inlineSetClass: function(className) 47938 { 47939 var current = this.getCurrent(); 47940 if (!$(current).hasClass(className)) this.inlineMethods('addClass', className); 47941 }, 47942 inlineRemoveStyle: function (rule) 47943 { 47944 this.selectionSave(); 47945 47946 this.inlineEachNodes(function(node) 47947 { 47948 $(node).css(rule, ''); 47949 this.removeEmptyAttr(node, 'style'); 47950 }); 47951 47952 this.selectionRestore(); 47953 this.sync(); 47954 }, 47955 inlineSetStyle: function(rule, value) 47956 { 47957 this.inlineMethods('css', rule, value); 47958 }, 47959 inlineRemoveAttr: function (attr) 47960 { 47961 this.selectionSave(); 47962 47963 var range = this.getRange(), node = this.getElement(), nodes = this.getNodes(); 47964 47965 if (range.collapsed || range.startContainer === range.endContainer && node) 47966 { 47967 nodes = $( node ); 47968 } 47969 47970 $(nodes).removeAttr(attr); 47971 47972 this.inlineUnwrapSpan(); 47973 47974 this.selectionRestore(); 47975 this.sync(); 47976 }, 47977 inlineSetAttr: function(attr, value) 47978 { 47979 this.inlineMethods('attr', attr, value ); 47980 }, 47981 inlineMethods: function(type, attr, value) 47982 { 47983 this.bufferSet(); 47984 this.selectionSave(); 47985 47986 var range = this.getRange() 47987 var el = this.getElement(); 47988 47989 if ((range.collapsed || range.startContainer === range.endContainer) && el && !this.nodeTestBlocks(el)) 47990 { 47991 $(el)[type](attr, value); 47992 } 47993 else 47994 {
47995 this.document.execCommand('fontSize', false, 4 ); 47996 47997 var fonts = this.$editor.find('font'); 47998 $.each(fonts, $.proxy(function(i, s) 47999 { 48000 this.inlineSetMethods(type, s, attr, value); 48001 48002 }, this)); 48003 } 48004 48005 this.selectionRestore(); 48006 48007 this.sync(); 48008 }, 48009 inlineSetMethods: function(type, s, attr, value) 48010 { 48011 var parent = $(s).parent(), el; 48012 48013 if (parent && parent[0].tagName === 'INLINE' && parent[0].attributes.length != 0) 48014 { 48015 el = parent; 48016 $(s).replaceWith($(s).html()); 48017 } 48018 else 48019 { 48020 el = $('<inline>').append($(s).contents()); 48021 $(s).replaceWith(el); 48022 } 48023 48024 $(el)[type](attr, value); 48025 48026 return el; 48027 }, 48028 // Sort elements and execute callback 48029 inlineEachNodes: function(callback) 48030 { 48031 var range = this.getRange(), 48032 node = this.getElement(), 48033 nodes = this.getNodes(), 48034 collapsed; 48035 48036 if (range.collapsed || range.startContainer === range.endContainer && node) 48037 { 48038 nodes = $(node); 48039 collapsed = true; 48040 } 48041 48042 $.each(nodes, $.proxy(function(i, node) 48043 { 48044 if (!collapsed && node.tagName !== 'INLINE') 48045 { 48046 if (node.parentNode.tagName === 'INLINE' && !$(node.parentNode).hasClass('redactor_editor')) 48047 { 48048 node = node.parentNode; 48049 } 48050 else return; 48051 } 48052 callback.call(this, node); 48053 48054 }, this ) ); 48055 }, 48056 inlineUnwrapSpan: function() 48057 { 48058 var $spans = this.$editor.find('inline'); 48059 48060 $.each($spans, $.proxy(function(i, span) 48061 { 48062 var $span = $(span); 48063 48064 if ($span.attr('class') === undefined && $span.attr('style') === undefined) 48065 { 48066 $span.contents().unwrap(); 48067 } 48068 48069 }, this)); 48070 }, 48071 inlineFormat: function(tag) 48072 { 48073 this.selectionSave(); 48074 48075 this.document.execCommand('fontSize', false, 4 ); 48076 48077 var fonts = this.$editor.find('font'); 48078 var last; 48079 $.each(fonts, function(i, s) 48080 { 48081 var el = $('<' + tag + '/>').append($(s).contents()); 48082 $(s).replaceWith(el); 48083 last = el; 48084 }); 48085 48086 this.selectionRestore(); 48087 48088 this.sync(); 48089 }, 48090 inlineRemoveFormat: function(tag) 48091 { 48092 this.selectionSave(); 48093 48094 var utag = tag.toUpperCase(); 48095 var nodes = this.getNodes(); 48096 var parent = $(this.getParent()).parent(); 48097 48098 $.each(nodes, function(i, s) 48099 { 48100 if (s.tagName === utag) this.inlineRemoveFormatReplace(s); 48101 }); 48102 48103 if (parent && parent[0].tagName === utag) this.inlineRemoveFormatReplace(parent); 48104 48105 this.selectionRestore(); 48106 this.sync(); 48107 }, 48108 inlineRemoveFormatReplace: function(el) 48109 { 48110 $(el).replaceWith($(el).contents()); 48111 }, 48112 48113 // INSERT 48114 insertHtml: function (html, sync) 48115 { 48116 var current = this.getCurrent(); 48117 var parent = current.parentNode; 48118 48119 this.$editor.focus(); 48120 48121 this.bufferSet(); 48122 48123 var $html = $('<div>').append($.parseHTML(html)); 48124 html = $html.html(); 48125 48126 html = this.cleanRemoveEmptyTags(html); 48127 48128 // Update value 48129 $html = $('<div>').append($.parseHTML(html)); 48130 48131 var currBlock = this.getBlock(); 48132 48133 if ($html.contents().length == 1) 48134 { 48135 var htmlTagName = $html.contents()[0].tagName; 48136 48137 // If the inserted and received text tags match 48138 if (htmlTagName != 'P' && htmlTagName == currBlock.tagName || htmlTagName == 'PRE') 48139 { 48140 html = $html.text(); 48141 $html = $('<div>').append(html); 48142 } 48143 } 48144 48145 // add text in a paragraph 48146 if (!this.opts.linebreaks && $html.contents().length == 1 && $html.contents()[0].nodeType == 3 48147 && (this.getRangeSelectedNodes().length > 2 || (!current || current.tagName == 'BODY' && !parent || parent.tagName == 'HTML'))) 48148 { 48149 html = '<p>' + html + '</p>'; 48150 } 48151 48152 html = this.setSpansVerifiedHtml(html); 48153 48154 if ($html.contents().length > 1 && currBlock 48155 || $html.contents().is('p, :header, ul, ol, div, table, blockquote, pre, address, section, header, footer, aside, article')) 48156 { 48157 if (this.browser('msie')) this.document.selection.createRange().pasteHTML(html); 48158 else this.document.execCommand('inserthtml', false, html); 48159 } 48160 else this.insertHtmlAdvanced(html, false); 48161 48162 if (this.selectall) 48163 { 48164 this.window.setTimeout($.proxy(function() 48165 { 48166 if (!this.opts.linebreaks) this.selectionEnd(this.$editor.contents().last()); 48167 else this.focusEnd(); 48168 48169 }, this), 1); 48170 } 48171 48172 this.observeStart(); 48173 48174 // set no editable 48175 this.setNonEditable(); 48176 48177 if (sync !== false) this.sync(); 48178 }, 48179 insertHtmlAdvanced: function(html, sync) 48180 {
48181 var sel = this.getSelection(); 48182 48183 if (sel.getRangeAt && sel.rangeCount) 48184 { 48185 var range = sel.getRangeAt(0); 48186 range.deleteContents(); 48187 48188 var el = this.document.createElement('div'); 48189 el.innerHTML = html; 48190 var frag = this.document.createDocumentFragment(), node, lastNode; 48191 while ((node = el.firstChild)) 48192 { 48193 lastNode = frag.appendChild(node); 48194 } 48195 48196 range.insertNode(frag); 48197 48198 if (lastNode) 48199 { 48200 range = range.cloneRange(); 48201 range.setStartAfter(lastNode); 48202 range.collapse(true); 48203 sel.removeAllRanges(); 48204 sel.addRange(range); 48205 } 48206 } 48207 48208 if (sync !== false) 48209 { 48210 this.sync(); 48211 } 48212 48213 }, 48214 insertText: function(html) 48215 { 48216 var $html = $($.parseHTML(html)); 48217 48218 if ($html.length) html = $html.text(); 48219 48220 this.$editor.focus(); 48221 48222 if (this.browser('msie')) this.document.selection.createRange().pasteHTML(html); 48223 else this.document.execCommand('inserthtml', false, html); 48224 48225 this.sync(); 48226 }, 48227 insertNode: function(node) 48228 { 48229 node = node[0] || node; 48230 var sel = this.getSelection(); 48231 if (sel.getRangeAt && sel.rangeCount) 48232 { 48233 // with delete contents 48234 range = sel.getRangeAt(0); 48235 range.deleteContents(); 48236 range.insertNode(node); 48237 range.setEndAfter(node); 48238 range.setStartAfter(node); 48239 sel.removeAllRanges(); 48240 sel.addRange(range); 48241 } 48242 }, 48243 insertNodeToCaretPositionFromPoint: function(e, node) 48244 { 48245 var range; 48246 var x = e.clientX, y = e.clientY; 48247 if (this.document.caretPositionFromPoint) 48248 { 48249 var pos = this.document.caretPositionFromPoint(x, y); 48250 range = this.getRange(); 48251 range.setStart(pos.offsetNode, pos.offset); 48252 range.collapse(true); 48253 range.insertNode(node); 48254 } 48255 else if (this.document.caretRangeFromPoint) 48256 { 48257 range = this.document.caretRangeFromPoint(x, y); 48258 range.insertNode(node); 48259 } 48260 else if (typeof document.body.createTextRange != "undefined") 48261 { 48262 range = this.document.body.createTextRange(); 48263 range.moveToPoint(x, y); 48264 var endRange = range.duplicate(); 48265 endRange.moveToPoint(x, y); 48266 range.setEndPoint("EndToEnd", endRange); 48267 range.select(); 48268 } 48269 48270 }, 48271 insertAfterLastElement: function(element) 48272 { 48273 if (this.isEndOfElement()) 48274 { 48275 48276 if ($($.trim(this.$editor.html())).get(0) != $.trim(element) 48277 && this.$editor.contents().last()[0] !== element) return false; 48278 48279 this.bufferSet(); 48280 48281 if (this.opts.linebreaks === false) 48282 { 48283 var node = $(this.opts.emptyHtml); 48284 $(element).after(node); 48285 this.selectionStart(node); 48286 } 48287 else 48288 { 48289 var node = $('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>', this.document)[0]; 48290 $(element).after(node); 48291 $(node).after(this.opts.invisibleSpace); 48292 this.selectionRestore(); 48293 } 48294 } 48295 }, 48296 insertLineBreak: function() 48297 { 48298 this.selectionSave(); 48299 this.$editor.find('#selection-marker-1').before('<br>' + (this.browser('webkit') ? this.opts.invisibleSpace : '')); 48300 this.selectionRestore(); 48301 }, 48302 insertDoubleLineBreak: function() 48303 { 48304 this.selectionSave(); 48305 this.$editor.find('#selection-marker-1').before('<br><br>' + (this.browser('webkit') ? this.opts.invisibleSpace : '')); 48306 this.selectionRestore(); 48307 }, 48308 replaceLineBreak: function(element) 48309 { 48310 //var node = this.document.createTextNode('\uFEFF'); 48311 var node = $('<br>' + this.opts.invisibleSpace); 48312 $(element).replaceWith(node); 48313 this.selectionStart(node); 48314 }, 48315 48316 // PASTE 48317 pasteClean: function(html) 48318 { 48319 html = this.callback('pasteBefore', false, html); 48320 48321 if (this.opts.pastePlainText) 48322 { 48323 var tmp = this.document.createElement('div'); 48324 48325 html = html.replace(/<br>|<\/H[1-6]>|<\/p>|<\/div>/gi, '\n'); 48326 48327 tmp.innerHTML = html; 48328 html = tmp.textContent || tmp.innerText; 48329 48330 html = $.trim(html); 48331 html = html.replace('\n', '<br>'); 48332 html = this.cleanParagraphy(html); 48333 48334 this.pasteInsert(html); 48335 return false; 48336 } 48337 48338 // clean up pre 48339 if (this.currentOrParentIs('PRE')) 48340 { 48341 html = this.pastePre(html); 48342 this.pasteInsert(html); 48343 return true; 48344 } 48345 48346 48347 // ms word list 48348 html = html.replace(/<p(.*?)class="MsoListParagraphCxSpFirst"([\w\W]*?)<\/p>/gi, '<ul><li$2</li>'); 48349 html = html.replace(/<p(.*?)class="MsoListParagraphCxSpMiddle"([\w\W]*?)<\/p>/gi, '<li$2</li>'); 48350 html = html.replace(/<p(.*?)class="MsoListParagraphCxSpLast"([\w\W]*?)<\/p>/gi, '<li$2</li></ul>'); 48351 // one line 48352 html = html.replace(/<p(.*?)class="MsoListParagraph"([\w\W]*?)<\/p>/gi, '<ul><li$2</li></ul>'); 48353 // remove ms word's bullet 48354 html = html.replace(/·/g, ''); 48355 48356 // remove comments and php tags 48357 html = html.replace(/<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi, ''); 48358 48359 // remove nbsp 48360 html = html.replace(/( ){2,}/gi, ' '); 48361 html = html.replace(/ /gi, ' '); 48362 48363 // remove google docs marker 48364 html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2"); 48365 html = html.replace(/<b(.*?)id="docs-internal-guid(.*?)">([\w\W]*?)<\/b>/gi, "$3"); 48366 48367 // strip tags 48368 html = this.cleanStripTags(html); 48369 48370 // prevert 48371 html = html.replace(/<td><\/td>/gi, '[td]'); 48372 html = html.replace(/<td> <\/td>/gi, '[td]'); 48373 html = html.replace(/<td><br><\/td>/gi, '[td]'); 48374 html = html.replace(/<td(.*?)colspan="(.*?)"(.*?)>([\w\W]*?)<\/td>/gi, '[td colspan="$2"]$4[/td]'); 48375 html = html.replace(/<a(.*?)href="(.*?)"(.*?)>([\w\W]*?)<\/a>/gi, '[a href="$2"]$4[/a]'); 48376 html = html.replace(/<iframe(.*?)>([\w\W]*?)<\/iframe>/gi, '[iframe$1]$2[/iframe]'); 48377 html = html.replace(/<video(.*?)>([\w\W]*?)<\/video>/gi, '[video$1]$2[/video]'); 48378 html = html.replace(/<audio(.*?)>([\w\W]*?)<\/audio>/gi, '[audio$1]$2[/audio]'); 48379 html = html.replace(/<embed(.*?)>([\w\W]*?)<\/embed>/gi, '[embed$1]$2[/embed]'); 48380 html = html.replace(/<object(.*?)>([\w\W]*?)<\/object>/gi, '[object$1]$2[/object]'); 48381 html = html.replace(/<param(.*?)>/gi, '[param$1]'); 48382 html = html.replace(/<img(.*?)>/gi, '[img$1]'); 48383 48384 // remove classes 48385 html = html.replace(/ class="(.*?)"/gi, ''); 48386 48387 // remove all attributes 48388 html = html.replace(/<(\w+)([\w\W]*?)>/gi, '<$1>'); 48389 48390 // remove empty 48391 html = html.replace(/<[^\/>][^>]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); 48392 html = html.replace(/<div>\s*?\t*?\n*?(<ul>|<ol>|<p>)/gi, '$1'); 48393 48394 // revert 48395 html = html.replace(/\[td colspan="(.*?)"\]([\w\W]*?)\[\/td\]/gi, '<td colspan="$1">$2</td>'); 48396 html = html.replace(/\[td\]/gi, '<td> </td>'); 48397 html = html.replace(/\[a href="(.*?)"\]([\w\W]*?)\[\/a\]/gi, '<a href="$1">$2</a>'); 48398 html = html.replace(/\[iframe(.*?)\]([\w\W]*?)\[\/iframe\]/gi, '<iframe$1>$2</iframe>'); 48399 html = html.replace(/\[video(.*?)\]([\w\W]*?)\[\/video\]/gi, '<video$1>$2</video>'); 48400 html = html.replace(/\[audio(.*?)\]([\w\W]*?)\[\/audio\]/gi, '<audio$1>$2</audio>'); 48401 html = html.replace(/\[embed(.*?)\]([\w\W]*?)\[\/embed\]/gi, '<embed$1>$2</embed>'); 48402 html = html.replace(/\[object(.*?)\]([\w\W]*?)\[\/object\]/gi, '<object$1>$2</object>'); 48403 html = html.replace(/\[param(.*?)\]/gi, '<param$1>'); 48404 html = html.replace(/\[img(.*?)\]/gi, '<img$1>'); 48405 48406 // convert div to p 48407 if (this.opts.convertDivs) 48408 { 48409 html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p>$2</p>'); 48410 html = html.replace(/<\/div><p>/gi, '<p>'); 48411 html = html.replace(/<\/p><\/div>/gi, '</p>'); 48412 } 48413 48414 if (this.currentOrParentIs('LI')) 48415 { 48416 html = html.replace(/<p>([\w\W]*?)<\/p>/gi, '$1<br>'); 48417 } 48418 else 48419 {
48420 html = this.cleanParagraphy(html); 48421 } 48422 48423 48424 // remove span 48425 html = html.replace(/<span(.*?)>([\w\W]*?)<\/span>/gi, '$2'); 48426 48427 // remove empty 48428 html = html.replace(/<img>/gi, ''); 48429 html = html.replace(/<[^\/>][^>][^img|param|source]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); 48430 48431 html = html.replace(/\n{3,}/gi, '\n'); 48432 48433 // remove dirty p 48434 html = html.replace(/<p><p>/gi, '<p>'); 48435 html = html.replace(/<\/p><\/p>/gi, '</p>'); 48436 48437 html = html.replace(/<li>(\s*|\t*|\n*)<p>/gi, '<li>'); 48438 html = html.replace(/<\/p>(\s*|\t*|\n*)<\/li>/gi, '</li>'); 48439 48440 if (this.opts.linebreaks === true) 48441 { 48442 html = html.replace(/<p(.*?)>([\w\W]*?)<\/p>/gi, '$2<br>'); 48443 } 48444 48445 // remove empty finally 48446 html = html.replace(/<[^\/>][^>][^img|param|source]*>(\s*|\t*|\n*| |<br>)<\/[^>]+>/gi, ''); 48447 48448 // remove safari local images 48449 html = html.replace(/<img src="webkit-fake-url\:\/\/(.*?)"(.*?)>/gi, ''); 48450 48451 // remove p in td 48452 html = html.replace(/<td(.*?)>(\s*|\t*|\n*)<p>([\w\W]*?)<\/p>(\s*|\t*|\n*)<\/td>/gi, '<td$1>$3</td>'); 48453 48454 // remove divs 48455 html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2'); 48456 html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2'); 48457 48458 // FF specific 48459 this.pasteClipboardMozilla = false; 48460 if (this.browser('mozilla')) 48461 { 48462 if (this.opts.clipboardUpload) 48463 { 48464 var matches = html.match(/<img src="data:image(.*?)"(.*?)>/gi); 48465 if (matches !== null) 48466 { 48467 this.pasteClipboardMozilla = matches; 48468 for (k in matches) 48469 { 48470 var img = matches[k].replace('<img', '<img data-mozilla-paste-image="' + k + '" '); 48471 html = html.replace(matches[k], img); 48472 } 48473 } 48474 } 48475 48476 // FF fix 48477 while (/<br>$/gi.test(html)) 48478 { 48479 html = html.replace(/<br>$/gi, ''); 48480 } 48481 } 48482 48483 // bullets again 48484 html = html.replace(/<p>â¢([\w\W]*?)<\/p>/gi, '<li>$1</li>'); 48485 48486 // ie inserts a blank font tags when pasting 48487 while (/<font>([\w\W]*?)<\/font>/gi.test(html)) 48488 { 48489 html = html.replace(/<font>([\w\W]*?)<\/font>/gi, '$1'); 48490 } 48491 48492 48493 this.pasteInsert(html); 48494 48495 }, 48496 pastePre: function(s) 48497 { 48498 s = s.replace(/<br>|<\/H[1-6]>|<\/p>|<\/div>/gi, '\n'); 48499 48500 var tmp = this.document.createElement('div'); 48501 tmp.innerHTML = s; 48502 return this.cleanEncodeEntities(tmp.textContent || tmp.innerText); 48503 }, 48504 pasteInsert: function(html) 48505 { 48506 if (this.selectall) 48507 { 48508 if (!this.opts.linebreaks) this.$editor.html(this.opts.emptyHtml); 48509 else this.$editor.html(''); 48510 48511 this.$editor.focus(); 48512 } 48513 48514 html = this.callback('pasteAfter', false, html); 48515 48516 this.insertHtml(html); 48517 48518 this.selectall = false; 48519 setTimeout($.proxy(function() 48520 { 48521 this.rtePaste = false; 48522 48523 // FF specific 48524 if (this.browser('mozilla')) 48525 { 48526 this.$editor.find('p:empty').remove() 48527 } 48528 if (this.pasteClipboardMozilla !== false) 48529 { 48530 this.pasteClipboardUploadMozilla(); 48531 } 48532 48533 }, this), 100); 48534 48535 if (this.opts.autoresize) $(this.document.body).scrollTop(this.saveScroll); 48536 else this.$editor.scrollTop(this.saveScroll); 48537 }, 48538 pasteClipboardUploadMozilla: function() 48539 { 48540 var imgs = this.$editor.find('img[data-mozilla-paste-image]'); 48541 $.each(imgs, $.proxy(function(i,s) 48542 { 48543 var $s = $(s); 48544 var arr = s.src.split(","); 48545 var data = arr[1]; // raw base64 48546 var contentType = arr[0].split(";")[0].split(":")[1]; 48547 48548 $.post(this.opts.clipboardUploadUrl, { 48549 contentType: contentType, 48550 data: data 48551 }, 48552 $.proxy(function(data) 48553 { 48554 var json = (typeof data === 'string' ? $.parseJSON(data) : data); 48555 $s.attr('src', json.filelink); 48556 $s.removeAttr('data-mozilla-paste-image'); 48557 48558 this.sync(); 48559 48560 // upload callback 48561 this.callback('imageUpload', $s, json); 48562 48563 }, this)); 48564 48565 }, this)); 48566 }, 48567 pasteClipboardUpload: function(e) 48568 { 48569 var result = e.target.result; 48570 var arr = result.split(","); 48571 var data = arr[1]; // raw base64 48572 var contentType = arr[0].split(";")[0].split(":")[1]; 48573 48574 if (this.opts.clipboardUpload) 48575 { 48576 $.post(this.opts.clipboardUploadUrl, { 48577 contentType: contentType, 48578 data: data 48579 }, 48580 $.proxy(function(data) 48581 { 48582 var json = (typeof data === 'string' ? $.parseJSON(data) : data); 48583 48584 var html = '<img src="' + json.filelink + '" id="clipboard-image-marker" />'; 48585 this.execCommand('inserthtml', html, false); 48586 48587 var image = $(this.$editor.find('img#clipboard-image-marker')); 48588 48589 if (image.length) image.removeAttr('id'); 48590 else image = false;
48591 48592 this.sync(); 48593 48594 // upload callback 48595 if (image) 48596 { 48597 this.callback('imageUpload', image, json); 48598 } 48599 48600 48601 }, this)); 48602 } 48603 else 48604 { 48605 this.insertHtml('<img src="' + result + '" />'); 48606 } 48607 }, 48608 48609 // BUFFER 48610 bufferSet: function(html) 48611 { 48612 if (html !== undefined) this.opts.buffer.push(html); 48613 else 48614 { 48615 this.selectionSave(); 48616 this.opts.buffer.push(this.$editor.html()); 48617 this.selectionRemoveMarkers('buffer'); 48618 } 48619 }, 48620 bufferUndo: function() 48621 { 48622 if (this.opts.buffer.length === 0) 48623 { 48624 this.$editor.focus(); 48625 return; 48626 } 48627 48628 // rebuffer 48629 this.selectionSave(); 48630 this.opts.rebuffer.push(this.$editor.html()); 48631 this.selectionRestore(false, true); 48632 48633 this.$editor.html(this.opts.buffer.pop()); 48634 48635 this.selectionRestore(); 48636 setTimeout($.proxy(this.observeStart, this), 100); 48637 }, 48638 bufferRedo: function() 48639 { 48640 if (this.opts.rebuffer.length === 0) 48641 { 48642 this.$editor.focus(); 48643 return false; 48644 } 48645 48646 // buffer 48647 this.selectionSave(); 48648 this.opts.buffer.push(this.$editor.html()); 48649 this.selectionRestore(false, true); 48650 48651 this.$editor.html(this.opts.rebuffer.pop()); 48652 this.selectionRestore(true); 48653 setTimeout($.proxy(this.observeStart, this), 4); 48654 }, 48655 48656 // OBSERVE 48657 observeStart: function() 48658 { 48659 this.observeImages(); 48660 48661 if (this.opts.observeLinks) this.observeLinks(); 48662 }, 48663 observeLinks: function() 48664 { 48665 this.$editor.find('a').on('click', $.proxy(this.linkObserver, this)); 48666 this.$editor.on('click.redactor', $.proxy(function(e) 48667 { 48668 this.linkObserverTooltipClose(e); 48669 48670 }, this)); 48671 }, 48672 observeImages: function() 48673 { 48674 if (this.opts.observeImages === false) return false; 48675 48676 this.$editor.find('img').each($.proxy(function(i, elem) 48677 { 48678 $(elem).addClass('with-preview'); 48679 $(elem).attr('data-target', elem.src.replace('large_', '')); 48680 48681 if (this.browser('msie')) $(elem).attr('unselectable', 'on'); 48682 this.imageResize(elem); 48683 48684 }, this)); 48685 }, 48686 linkObserver: function(e) 48687 { 48688 var $link = $(e.target); 48689 var pos = $link.offset(); 48690 if (this.opts.iframe) 48691 { 48692 var posFrame = this.$frame.offset(); 48693 pos.top = posFrame.top + (pos.top - $(this.document).scrollTop()); 48694 pos.left += posFrame.left; 48695 } 48696 48697 var tooltip = $('<span class="redactor-link-tooltip"></span>'); 48698 48699 var href = $link.attr('href'); 48700 if (href.length > 24) href = href.substring(0,24) + '...'; 48701 48702 var aLink = $('<a href="' + $link.attr('href') + '" target="_blank">' + href + '</a>').on('click', $.proxy(function(e) 48703 { 48704 this.linkObserverTooltipClose(false); 48705 }, this)); 48706 48707 var aEdit = $('<a href="#">' + this.opts.curLang.edit + '</a>').on('click', $.proxy(function(e) 48708 { 48709 e.preventDefault(); 48710 this.linkShow(); 48711 this.linkObserverTooltipClose(false); 48712 48713 }, this)); 48714 48715 var aUnlink = $('<a href="#">' + this.opts.curLang.unlink + '</a>').on('click', $.proxy(function(e) 48716 { 48717 e.preventDefault(); 48718 this.execCommand('unlink'); 48719 this.linkObserverTooltipClose(false); 48720 48721 }, this)); 48722 48723 48724 tooltip.append(aLink); 48725 tooltip.append(' | '); 48726 tooltip.append(aEdit); 48727 tooltip.append(' | '); 48728 tooltip.append(aUnlink); 48729 tooltip.css({ 48730 top: (pos.top + 20) + 'px', 48731 left: pos.left + 'px' 48732 }); 48733 48734 $('.redactor-link-tooltip').remove(); 48735 $('body').append(tooltip); 48736 }, 48737 linkObserverTooltipClose: function(e) 48738 { 48739 if (e !== false && e.target.tagName == 'A') return false; 48740 $('.redactor-link-tooltip').remove(); 48741 }, 48742 48743 // SELECTION 48744 getSelection: function() 48745 { 48746 if (!this.opts.rangy) return this.document.getSelection(); 48747 else // rangy 48748 { 48749 if (!this.opts.iframe) return rangy.getSelection(); 48750 else return rangy.getSelection(this.$frame[0]); 48751 } 48752 }, 48753 getRange: function() 48754 { 48755 if (!this.opts.rangy) 48756 { 48757 if (this.document.getSelection) 48758 { 48759 var sel = this.getSelection(); 48760 if (sel.getRangeAt && sel.rangeCount) return sel.getRangeAt(0); 48761 } 48762 48763 return this.document.createRange(); 48764 } 48765 else // rangy 48766 { 48767 if (!this.opts.iframe) return rangy.createRange(); 48768 else return rangy.createRange(this.iframeDoc()); 48769 } 48770 }, 48771 selectionElement: function(node) 48772 { 48773 this.setCaret(node); 48774 }, 48775 selectionStart: function(node) 48776 { 48777 this.selectionSet(node[0] || node, 0, null, 0); 48778 }, 48779 selectionEnd: function(node) 48780 { 48781 this.selectionSet(node[0] || node, 1, null, 1); 48782 }, 48783 selectionSet: function(orgn, orgo, focn, foco) 48784 { 48785 if (focn == null) focn = orgn; 48786 if (foco == null) foco = orgo; 48787
48788 var sel = this.getSelection(); 48789 if (!sel) return; 48790 48791 var range = this.getRange(); 48792 range.setStart(orgn, orgo); 48793 range.setEnd(focn, foco ); 48794 48795 try { 48796 sel.removeAllRanges(); 48797 } catch (e) {} 48798 48799 sel.addRange(range); 48800 }, 48801 selectionWrap: function(tag) 48802 { 48803 tag = tag.toLowerCase(); 48804 48805 var block = this.getBlock(); 48806 if (block) 48807 { 48808 var wrapper = this.formatChangeTag(block, tag); 48809 this.sync(); 48810 return wrapper; 48811 } 48812 48813 var sel = this.getSelection(); 48814 var range = sel.getRangeAt(0); 48815 var wrapper = document.createElement(tag); 48816 wrapper.appendChild(range.extractContents()); 48817 range.insertNode(wrapper); 48818 48819 this.selectionElement(wrapper); 48820 48821 return wrapper; 48822 }, 48823 selectionAll: function() 48824 { 48825 var range = this.getRange(); 48826 range.selectNodeContents(this.$editor[0]); 48827 48828 var sel = this.getSelection(); 48829 sel.removeAllRanges(); 48830 sel.addRange(range); 48831 }, 48832 selectionRemove: function() 48833 { 48834 this.getSelection().removeAllRanges(); 48835 }, 48836 getCaretOffset: function (element) 48837 { 48838 var caretOffset = 0; 48839 48840 var range = this.getRange(); 48841 var preCaretRange = range.cloneRange(); 48842 preCaretRange.selectNodeContents(element); 48843 preCaretRange.setEnd(range.endContainer, range.endOffset); 48844 caretOffset = $.trim(preCaretRange.toString()).length; 48845 48846 return caretOffset; 48847 }, 48848 getCaretOffsetRange: function() 48849 { 48850 return new Range(this.getSelection().getRangeAt(0)); 48851 }, 48852 setCaret: function (el, start, end) 48853 { 48854 if (typeof end === 'undefined') end = start; 48855 el = el[0] || el; 48856 48857 var range = this.getRange(); 48858 range.selectNodeContents(el); 48859 48860 var textNodes = this.getTextNodesIn(el); 48861 var foundStart = false;
48862 var charCount = 0, endCharCount; 48863 48864 if (textNodes.length == 1 && start) 48865 { 48866 range.setStart(textNodes[0], start); 48867 range.setEnd(textNodes[0], end); 48868 } 48869 else 48870 { 48871 for (var i = 0, textNode; textNode = textNodes[i++];) 48872 { 48873 endCharCount = charCount + textNode.length; 48874 if (!foundStart && start >= charCount && (start < endCharCount || (start == endCharCount && i < textNodes.length))) 48875 { 48876 range.setStart(textNode, start - charCount); 48877 foundStart = true; 48878 } 48879 48880 if (foundStart && end <= endCharCount) 48881 { 48882 range.setEnd( textNode, end - charCount ); 48883 break; 48884 } 48885 48886 charCount = endCharCount; 48887 } 48888 } 48889 48890 var sel = this.getSelection(); 48891 sel.removeAllRanges(); 48892 sel.addRange( range ); 48893 }, 48894 getTextNodesIn: function (node) 48895 { 48896 var textNodes = []; 48897 48898 if (node.nodeType == 3) textNodes.push(node); 48899 else 48900 { 48901 var children = node.childNodes; 48902 for (var i = 0, len = children.length; i < len; ++i) 48903 { 48904 textNodes.push.apply(textNodes, this.getTextNodesIn(children[i])); 48905 } 48906 } 48907 48908 return textNodes; 48909 }, 48910 48911 // GET ELEMENTS 48912 getCurrent: function() 48913 { 48914 var el = false; 48915 var sel = this.getSelection(); 48916 48917 if (sel.rangeCount > 0) el = sel.getRangeAt(0).startContainer; 48918 48919 return this.isParentRedactor(el); 48920 }, 48921 getParent: function(elem) 48922 { 48923 elem = elem || this.getCurrent(); 48924 if (elem) return this.isParentRedactor( $( elem ).parent()[0] ); 48925 else return false; 48926 }, 48927 getBlock: function(node) 48928 { 48929 if (typeof node === 'undefined') node = this.getCurrent(); 48930 48931 while (node) 48932 { 48933 if (this.nodeTestBlocks(node)) 48934 { 48935 if ($(node).hasClass('redactor_editor')) return false; 48936 return node; 48937 } 48938 48939 node = node.parentNode; 48940 } 48941 48942 return false; 48943 }, 48944 getBlocks: function(nodes) 48945 { 48946 var newnodes = []; 48947 if (typeof nodes == 'undefined') 48948 { 48949 var range = this.getRange(); 48950 if (range && range.collapsed === true) return [this.getBlock()]; 48951 var nodes = this.getNodes(range); 48952 } 48953 48954 $.each(nodes, $.proxy(function(i,node) 48955 { 48956 if (this.opts.iframe === false && $(node).parents('div.redactor_editor').size() == 0) return false; 48957 if (this.nodeTestBlocks(node)) newnodes.push(node); 48958 48959 }, this)); 48960 48961 if (newnodes.length === 0) newnodes = [this.getBlock()]; 48962 48963 return newnodes; 48964 }, 48965 nodeTestBlocks: function(node) 48966 { 48967 return node.nodeType == 1 && this.rTestBlock.test(node.nodeName); 48968 }, 48969 tagTestBlock: function(tag) 48970 { 48971 return this.rTestBlock.test(tag); 48972 }, 48973 getSelectedNodes: function(range) 48974 { 48975 if (typeof range == 'undefined' || range == false) var range = this.getRange() 48976 if (range && range.collapsed === true) 48977 { 48978 return [this.getCurrent()]; 48979 } 48980 48981 var sel = this.getSelection(); 48982 try { 48983 var frag = sel.getRangeAt(0).cloneContents(); 48984 } 48985 catch(e) 48986 { 48987 return(false); 48988 } 48989 48990 var tempspan = this.document.createElement("span"); 48991 tempspan.appendChild(frag); 48992 48993 window.selnodes = tempspan.childNodes; 48994 48995 var len = selnodes.length; 48996 var output = []; 48997 for(var i = 0, u = len; i<u; i++) 48998 { 48999 output.push(selnodes[i]); 49000 } 49001 49002 if (output.length == 0) output.push(this.getCurrent()); 49003 49004 return output; 49005 }, 49006 getNodes: function(range, tag) 49007 { 49008 if (this.opts.linebreaks) 49009 { 49010 return this.getSelectedNodes(range); 49011 } 49012 49013 49014 if (typeof range == 'undefined' || range == false) var range = this.getRange(); 49015 if (range && range.collapsed === true) 49016 { 49017 if (typeof tag === 'undefined' && this.tagTestBlock(tag)) 49018 { 49019 var block = this.getBlock(); 49020 if (block.tagName == tag) return [block]; 49021 else return []; 49022 } 49023 else 49024 { 49025 return [this.getCurrent()]; 49026 } 49027 } 49028 49029 var nodes = [], finalnodes = []; 49030 49031 var sel = this.document.getSelection(); 49032 if (!sel.isCollapsed) nodes = this.getRangeSelectedNodes(sel.getRangeAt(0)); 49033 49034 $.each(nodes, $.proxy(function(i,node) 49035 { 49036 if (this.opts.iframe === false && $(node).parents('div.redactor_editor').size() == 0) return false; 49037 49038 if (typeof tag === 'undefined') 49039 { 49040 if ($.trim(node.textContent) != '') 49041 { 49042 finalnodes.push(node); 49043 } 49044 } 49045 else if (node.tagName == tag) 49046 { 49047 finalnodes.push(node); 49048 } 49049 49050 }, this)); 49051 49052 if (finalnodes.length == 0) 49053 { 49054 if (typeof tag === 'undefined' && this.tagTestBlock(tag)) 49055 { 49056 var block = this.getBlock(); 49057 if (block.tagName == tag) return finalnodes.push(block); 49058 else return []; 49059 } 49060 else 49061 { 49062 finalnodes.push(this.getCurrent()); 49063 } 49064 } 49065 49066 return finalnodes; 49067 }, 49068 getElement: function(node) 49069 { 49070 if (!node) node = this.getCurrent(); 49071 while (node) 49072 { 49073 if (node.nodeType == 1) 49074 { 49075 if ($(node).hasClass('redactor_editor')) return false;
49076 return node; 49077 } 49078 49079 node = node.parentNode; 49080 } 49081 49082 return false; 49083 }, 49084 getRangeSelectedNodes: function(range) 49085 { 49086 range = range || this.getRange(); 49087 var node = range.startContainer; 49088 var endNode = range.endContainer; 49089 49090 if (node == endNode) return [node]; 49091 49092 var rangeNodes = []; 49093 while (node && node != endNode) 49094 { 49095 rangeNodes.push(node = this.nextNode(node)); 49096 } 49097 49098 node = range.startContainer; 49099 while (node && node != range.commonAncestorContainer) 49100 { 49101 rangeNodes.unshift( node ); 49102 node = node.parentNode; 49103 } 49104 49105 return rangeNodes; 49106 }, 49107 nextNode: function(node) 49108 { 49109 if (node.hasChildNodes()) return node.firstChild; 49110 else 49111 { 49112 while (node && !node.nextSibling) 49113 { 49114 node = node.parentNode; 49115 } 49116 49117 if (!node) return null; 49118 return node.nextSibling; 49119 } 49120 }, 49121 49122 49123 // GET SELECTION HTML OR TEXT 49124 getSelectionText: function() 49125 { 49126 return this.getSelection().toString(); 49127 }, 49128 getSelectionHtml: function() 49129 { 49130 var html = ''; 49131 49132 var sel = this.getSelection(); 49133 if (sel.rangeCount) 49134 { 49135 var container = this.document.createElement( "div" ); 49136 var len = sel.rangeCount; 49137 for (var i = 0; i < len; ++i) 49138 { 49139 container.appendChild(sel.getRangeAt(i).cloneContents()); 49140 } 49141 49142 html = container.innerHTML; 49143 } 49144 49145 return this.syncClean(html); 49146 }, 49147 49148 // SAVE & RESTORE 49149 selectionSave: function() 49150 { 49151 if (!this.isFocused()) this.$editor.focus(); 49152 49153 if (!this.opts.rangy) 49154 { 49155 this.selectionCreateMarker(this.getRange()); 49156 } 49157 // rangy 49158 else 49159 { 49160 this.savedSel = rangy.saveSelection(); 49161 } 49162 }, 49163 selectionCreateMarker: function(range, remove) 49164 { 49165 if (!range) return; 49166 49167 var node1 = $('<span id="selection-marker-1" class="redactor-selection-marker">' + this.opts.invisibleSpace + '</span>', this.document)[0]; 49168 var node2 = $('<span id="selection-marker-2" class="redactor-selection-marker">' + this.opts.invisibleSpace + '</span>', this.document)[0]; 49169 49170 if (range.collapsed === true) 49171 { 49172 this.selectionSetMarker(range, node1, true); 49173 } 49174 else 49175 { 49176 this.selectionSetMarker(range, node1, true); 49177 this.selectionSetMarker(range, node2, false); 49178 } 49179 49180 this.savedSel = this.$editor.html(); 49181 49182 this.selectionRestore(false, false); 49183 }, 49184 selectionSetMarker: function(range, node, type) 49185 { 49186 var boundaryRange = range.cloneRange(); 49187 49188 boundaryRange.collapse(type); 49189 49190 boundaryRange.insertNode(node); 49191 boundaryRange.detach(); 49192 }, 49193 selectionRestore: function(replace, remove) 49194 { 49195 if (!this.opts.rangy) 49196 { 49197 if (replace === true && this.savedSel) 49198 { 49199 this.$editor.html(this.savedSel); 49200 } 49201 49202 var node1 = this.$editor.find('span#selection-marker-1'); 49203 var node2 = this.$editor.find('span#selection-marker-2'); 49204 49205 if (this.browser('mozilla')) 49206 { 49207 this.$editor.focus(); 49208 } 49209 else if (!this.isFocused()) 49210 { 49211 this.$editor.focus(); 49212 } 49213 49214 if (node1.length != 0 && node2.length != 0) 49215 { 49216 this.selectionSet(node1[0], 0, node2[0], 0); 49217 } 49218 else if (node1.length != 0) 49219 { 49220 this.selectionSet(node1[0], 0, null, 0); 49221 } 49222 49223 if (remove !== false) 49224 { 49225 this.selectionRemoveMarkers(); 49226 this.savedSel = false; 49227 } 49228 } 49229 // rangy 49230 else 49231 { 49232 rangy.restoreSelection(this.savedSel); 49233 } 49234 }, 49235 selectionRemoveMarkers: function(type) 49236 { 49237 if (!this.opts.rangy) 49238 { 49239 $.each(this.$editor.find('span.redactor-selection-marker'), function() 49240 {
49241 var html = $.trim($(this).html().replace(/[^\u0000-\u1C7F]/g, '')); 49242 if (html == '') 49243 { 49244 $(this).remove(); 49245 } 49246 else 49247 { 49248 $(this).removeAttr('class').removeAttr('id'); 49249 } 49250 }); 49251 } 49252 // rangy 49253 else 49254 { 49255 rangy.removeMarkers(this.savedSel); 49256 } 49257 }, 49258 49259 // TABLE 49260 tableShow: function() 49261 { 49262 this.selectionSave(); 49263 49264 this.modalInit(this.opts.curLang.table, this.opts.modal_table, 300, $.proxy(function() 49265 { 49266 $('#redactor_insert_table_btn').click($.proxy(this.tableInsert, this)); 49267 49268 setTimeout(function() 49269 { 49270 $('#redactor_table_rows').focus(); 49271 49272 }, 200); 49273 49274 }, this)); 49275 }, 49276 tableInsert: function() 49277 { 49278 var rows = $('#redactor_table_rows').val(), 49279 columns = $('#redactor_table_columns').val(), 49280 $table_box = $('<div></div>'), 49281 tableId = Math.floor(Math.random() * 99999), 49282 $table = $('<table id="table' + tableId + '"><tbody></tbody></table>'), 49283 i, $row, z, $column; 49284 49285 for (i = 0; i < rows; i++) 49286 { 49287 $row = $('<tr></tr>'); 49288 49289 for (z = 0; z < columns; z++) 49290 { 49291 $column = $('<td>' + this.opts.invisibleSpace + '</td>'); 49292 49293 // set the focus to the first td 49294 if (i === 0 && z === 0) $column.append('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); 49295 49296 $($row).append($column); 49297 } 49298 49299 $table.append($row); 49300 } 49301 49302 $table_box.append($table); 49303 var html = $table_box.html(); 49304 49305 this.modalClose(); 49306 this.selectionRestore(); 49307 49308 var current = this.getBlock() || this.getCurrent(); 49309 49310 if (current && current.tagName != 'BODY') $(current).after(html) 49311 else this.insertHtmlAdvanced(html, false); 49312 49313 this.selectionRestore(); 49314 49315 var table = this.$editor.find('#table' + tableId); 49316 this.buttonActiveObserver(); 49317 49318 table.find('span#selection-marker-1').remove(); 49319 table.removeAttr('id'); 49320 49321 this.sync(); 49322 }, 49323 tableDeleteTable: function() 49324 { 49325 var $table = $(this.getParent()).closest('table'); 49326 if ($table.size() == 0) return false; 49327 49328 this.bufferSet(); 49329 49330 $table.remove(); 49331 this.sync(); 49332 }, 49333 tableDeleteRow: function() 49334 { 49335 var $table = $(this.getParent()).closest('table'); 49336 if ($table.size() == 0) return false; 49337 49338 this.bufferSet(); 49339 49340 var $current_tr = $(this.getParent()).closest('tr'); 49341 var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next(); 49342 if ($focus_tr.length) 49343 { 49344 var $focus_td = $focus_tr.children('td' ).first(); 49345 if ($focus_td.length) 49346 { 49347 $focus_td.prepend('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); 49348 } 49349 } 49350 49351 $current_tr.remove(); 49352 this.selectionRestore(); 49353 this.sync(); 49354 }, 49355 tableDeleteColumn: function() 49356 { 49357 var $table = $(this.getParent()).closest('table'); 49358 if ($table.size() == 0) return false; 49359 49360 this.bufferSet(); 49361 49362 var $current_td = $(this.getParent()).closest('td'); 49363 var index = $current_td.get(0).cellIndex; 49364 49365 // Set the focus correctly 49366 $table.find('tr').each($.proxy(function(i, elem) 49367 { 49368 var focusIndex = index - 1 < 0 ? index + 1 : index - 1; 49369 if (i === 0) 49370 { 49371 $(elem).find('td').eq(focusIndex).prepend('<span id="selection-marker-1">' + this.opts.invisibleSpace + '</span>'); 49372 } 49373 49374 $(elem).find('td').eq(index).remove(); 49375 49376 }, this)); 49377 49378 this.selectionRestore(); 49379 this.sync(); 49380 }, 49381 tableAddHead: function() 49382 { 49383 var $table = $(this.getParent()).closest('table'); 49384 if ($table.size() == 0) return false; 49385 49386 this.bufferSet(); 49387 49388 if ($table.find('thead').size() !== 0) this.tableDeleteHead(); 49389 else 49390 { 49391 var tr = $table.find('tr').first().clone(); 49392 tr.find('td').html(this.opts.invisibleSpace); 49393 $thead = $('<thead></thead>'); 49394 $thead.append(tr); 49395 $table.prepend($thead); 49396 49397 this.sync(); 49398 } 49399 }, 49400 tableDeleteHead: function() 49401 { 49402 var $table = $(this.getParent()).closest('table'); 49403 var $thead = $table.find('thead'); 49404 49405 if ($thead.size() == 0) return false; 49406 49407 this.bufferSet(); 49408 49409 $thead.remove(); 49410 this.sync(); 49411 }, 49412 tableAddRowAbove: function() 49413 { 49414 this.tableAddRow('before'); 49415 }, 49416 tableAddRowBelow: function() 49417 { 49418 this.tableAddRow('after'); 49419 }, 49420 tableAddColumnLeft: function() 49421 { 49422 this.tableAddColumn('before'); 49423 }, 49424 tableAddColumnRight: function() 49425 { 49426 this.tableAddColumn('after'); 49427 }, 49428 tableAddRow: function(type) 49429 { 49430 var $table = $(this.getParent()).closest('table'); 49431 if ($table.size() == 0) return false;
49432 49433 this.bufferSet(); 49434 49435 var $current_tr = $(this.getParent()).closest('tr'); 49436 var new_tr = $current_tr.clone(); 49437 new_tr.find('td').html(this.opts.invisibleSpace); 49438 49439 if (type === 'after') $current_tr.after(new_tr); 49440 else $current_tr.before(new_tr); 49441 49442 this.sync(); 49443 }, 49444 tableAddColumn: function (type) 49445 { 49446 var $table = $(this.getParent()).closest('table'); 49447 if ($table.size() == 0) return false; 49448 49449 this.bufferSet(); 49450 49451 var index = 0; 49452 49453 var $current_tr = $(this.getParent()).closest('tr'); 49454 var $current_td = $(this.getParent()).closest('td'); 49455 49456 $current_tr.find('td').each($.proxy(function(i, elem) 49457 { 49458 if ($(elem)[0] === $current_td[0]) index = i; 49459 49460 }, this)); 49461 49462 $table.find('tr').each($.proxy(function(i, elem) 49463 { 49464 var $current = $(elem).find('td').eq(index); 49465 49466 var td = $current.clone(); 49467 td.html(this.opts.invisibleSpace); 49468 49469 type === 'after' ? $current.after(td) : $current.before(td); 49470 49471 }, this)); 49472 49473 this.sync(); 49474 }, 49475 49476 // VIDEO 49477 videoShow: function() 49478 { 49479 this.selectionSave(); 49480 49481 this.modalInit(this.opts.curLang.video, this.opts.modal_video, 600, $.proxy(function() 49482 { 49483 $('#redactor_insert_video_btn').click($.proxy(this.videoInsert, this)); 49484 49485 setTimeout(function() 49486 { 49487 $('#redactor_insert_video_area').focus(); 49488 49489 }, 200); 49490 49491 }, this)); 49492 }, 49493 videoInsert: function () 49494 { 49495 var data = $('#redactor_insert_video_area').val(); 49496 data = this.cleanStripTags(data); 49497 49498 this.selectionRestore(); 49499 49500 var current = this.getBlock() || this.getCurrent(); 49501 49502 if (current) $(current).after(data) 49503 else this.insertHtmlAdvanced(data, false); 49504 49505 this.sync(); 49506 this.modalClose(); 49507 }, 49508 49509 // LINK 49510 linkShow: function() 49511 { 49512 this.selectionSave(); 49513 49514 var callback = $.proxy(function() 49515 { 49516 this.insert_link_node = false; 49517 49518 var sel = this.getSelection(); 49519 var url = '', text = '', target = ''; 49520 49521 var elem = this.getParent(); 49522 var par = $(elem).parent().get(0); 49523 if (par && par.tagName === 'A') 49524 { 49525 elem = par; 49526 } 49527 49528 if (elem && elem.tagName === 'A') 49529 { 49530 url = elem.href; 49531 text = $(elem).text(); 49532 target = elem.target; 49533 49534 this.insert_link_node = elem; 49535 } 49536 else text = sel.toString(); 49537 49538 $('.redactor_link_text').val(text); 49539 49540 var thref = self.location.href.replace(/\/$/i, ''); 49541 var turl = url.replace(thref, ''); 49542 49543 // remove host from href 49544 if (this.opts.linkProtocol === false) 49545 { 49546 var re = new RegExp('^(http|ftp|https)://' + self.location.host, 'i'); 49547 turl = turl.replace(re, ''); 49548 } 49549 49550 var tabs = $('#redactor_tabs').find('a'); 49551 49552 if (this.opts.linkEmail === false) tabs.eq(1).remove(); 49553 if (this.opts.linkAnchor === false) tabs.eq(2).remove(); 49554 if (this.opts.linkEmail === false && this.opts.linkAnchor === false) 49555 { 49556 $('#redactor_tabs').remove(); 49557 $('#redactor_link_url').val(turl); 49558 } 49559 else 49560 { 49561 if (url.search('mailto:') === 0) 49562 { 49563 this.modalSetTab.call(this, 2); 49564 49565 $('#redactor_tab_selected').val(2); 49566 $('#redactor_link_mailto').val(url.replace('mailto:', '')); 49567 } 49568 else if (turl.search(/^#/gi) === 0) 49569 { 49570 this.modalSetTab.call(this, 3); 49571 49572 $('#redactor_tab_selected').val(3); 49573 $('#redactor_link_anchor').val(turl.replace(/^#/gi, '' )); 49574 } 49575 else 49576 { 49577 $('#redactor_link_url').val(turl); 49578 } 49579 } 49580 49581 if (target === '_blank') $('#redactor_link_blank').prop('checked', true); 49582 49583 $('#redactor_insert_link_btn').click($.proxy(this.linkProcess, this)); 49584 49585 setTimeout(function() 49586 { 49587 $('#redactor_link_url').focus(); 49588 49589 }, 200); 49590 49591 }, this); 49592 49593 this.modalInit(this.opts.curLang.link, this.opts.modal_link, 460, callback); 49594 49595 }, 49596 linkProcess: function() 49597 { 49598 var tab_selected = $('#redactor_tab_selected').val(); 49599 var link = '', text = '', target = '', targetBlank = ''; 49600 49601 // url 49602 if (tab_selected === '1') 49603 { 49604 link = $('#redactor_link_url').val(); 49605 text = $('#redactor_link_url_text').val(); 49606 49607 if ($('#redactor_link_blank').prop('checked')) 49608 { 49609 target = ' target="_blank"'; 49610 targetBlank = '_blank'; 49611 } 49612 49613 // test url (add protocol) 49614 var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}'; 49615 var re = new RegExp('^(http|ftp|https)://' + pattern, 'i'); 49616 var re2 = new RegExp('^' + pattern, 'i'); 49617 49618 if (link.search(re) == -1 && link.search(re2) == 0 && this.opts.linkProtocol) 49619 { 49620 link = this.opts.linkProtocol + link; 49621 } 49622 } 49623 // mailto 49624 else if (tab_selected === '2') 49625 { 49626 link = 'mailto:' + $('#redactor_link_mailto').val(); 49627 text = $('#redactor_link_mailto_text').val(); 49628 } 49629 // anchor 49630 else if (tab_selected === '3') 49631 { 49632 link = '#' + $('#redactor_link_anchor').val(); 49633 text = $('#redactor_link_anchor_text').val(); 49634 } 49635 49636 text = text.replace(/<|>/g, ''); 49637 this.linkInsert('<a href="' + link + '"' + target + '>
49637' + text + '</a>', $.trim(text), link, targetBlank); 49638 49639 }, 49640 linkInsert: function (a, text, link, target) 49641 { 49642 this.selectionRestore(); 49643 49644 if (text !== '') 49645 { 49646 if (this.insert_link_node) 49647 { 49648 this.bufferSet(); 49649 49650 $(this.insert_link_node).text(text).attr('href', link); 49651 49652 if (target !== '') $(this.insert_link_node).attr('target', target); 49653 else $(this.insert_link_node).removeAttr('target'); 49654 49655 this.sync(); 49656 } 49657 else 49658 { 49659 this.exec('inserthtml', a); 49660 } 49661 } 49662 49663 // link tooltip 49664 setTimeout($.proxy(function() 49665 { 49666 if (this.opts.observeLinks) this.observeLinks(); 49667 }, this), 5); 49668 49669 this.modalClose(); 49670 }, 49671 49672 // FILE 49673 fileShow: function () 49674 { 49675 49676 this.selectionSave(); 49677 49678 var callback = $.proxy(function() 49679 { 49680 var sel = this.getSelection(); 49681 49682 var text = ''; 49683 if (this.oldIE()) text = sel.text; 49684 else text = sel.toString(); 49685 49686 $('#redactor_filename').val(text); 49687 49688 // dragupload 49689 if (!this.isMobile()) 49690 { 49691 this.draguploadInit('#redactor_file', { 49692 url: this.opts.fileUpload, 49693 uploadFields: this.opts.uploadFields, 49694 success: $.proxy(this.fileCallback, this), 49695 error: $.proxy( function(obj, json) 49696 { 49697 this.callback('fileUploadError', json); 49698 49699 }, this), 49700 uploadParam: this.opts.fileUploadParam 49701 }); 49702 } 49703 49704 this.uploadInit('redactor_file', { 49705 auto: true, 49706 url: this.opts.fileUpload, 49707 success: $.proxy(this.fileCallback, this), 49708 error: $.proxy(function(obj, json) 49709 { 49710 this.callback('fileUploadError', json); 49711 49712 }, this) 49713 }); 49714 49715 }, this); 49716 49717 this.modalInit(this.opts.curLang.file, this.opts.modal_file, 500, callback); 49718 }, 49719 fileCallback: function(json) 49720 { 49721 49722 this.selectionRestore(); 49723 49724 if (json !== false) 49725 { 49726 49727 var text = $('#redactor_filename').val(); 49728 if (text === '') text = json.filename; 49729 49730 var link = '<a href="' + json.filelink + '" id="filelink-marker">
49730' + text + '</a>'; 49731 49732 // chrome fix 49733 if (this.browser('webkit') && !!this.window.chrome) 49734 { 49735 link = link + ' '; 49736 } 49737 49738 this.execCommand('inserthtml', link, false); 49739 49740 var linkmarker = $(this.$editor.find('a#filelink-marker')); 49741 if (linkmarker.size() != 0) linkmarker.removeAttr('id'); 49742 else linkmarker = false; 49743 49744 this.sync(); 49745 49746 // file upload callback 49747 this.callback('fileUpload', linkmarker, json); 49748 } 49749 49750 this.modalClose(); 49751 }, 49752 49753 // IMAGE 49754 imageShow: function() 49755 { 49756 49757 this.selectionSave(); 49758 49759 var callback = $.proxy(function() 49760 { 49761 // json 49762 if (this.opts.imageGetJson) 49763 { 49764 $.getJSON(this.opts.imageGetJson, $.proxy(function(data) 49765 { 49766 var folders = {}, count = 0; 49767 49768 // folders 49769 $.each(data, $.proxy(function(key, val) 49770 { 49771 if (typeof val.folder !== 'undefined') 49772 { 49773 count++; 49774 folders[val.folder] = count; 49775 } 49776 49777 }, this)); 49778 49779 var folderclass = false; 49780 $.each(data, $.proxy(function(key, val) 49781 { 49782 // title 49783 var thumbtitle = ''; 49784 if (typeof val.title !== 'undefined') thumbtitle = val.title; 49785 49786 var folderkey = 0; 49787 if (!$.isEmptyObject(folders) && typeof val.folder !== 'undefined') 49788 { 49789 folderkey = folders[val.folder]; 49790 if (folderclass === false) folderclass = '.redactorfolder' + folderkey; 49791 } 49792 49793 var img = $('<img src="' + val.thumb + '" class="redactorfolder redactorfolder' + folderkey + '" rel="' + val.image + '" title="' + thumbtitle + '" />'); 49794 $('#redactor_image_box').append(img); 49795 $(img).click($.proxy(this.imageThumbClick, this)); 49796 49797 }, this)); 49798 49799 // folders 49800 if (!$.isEmptyObject(folders)) 49801 { 49802 $('.redactorfolder').hide(); 49803 $(folderclass).show(); 49804 49805 var onchangeFunc = function(e) 49806 { 49807 $('.redactorfolder').hide(); 49808 $('.redactorfolder' + $(e.target).val()).show(); 49809 }; 49810 49811 var select = $('<select id="redactor_image_box_select">'); 49812 $.each( folders, function(k, v) 49813 { 49814 select.append( $('<option value="' + v + '">' + k + '</option>')); 49815 }); 49816 49817 $('#redactor_image_box').before(select); 49818 select.change(onchangeFunc); 49819 } 49820 }, this)); 49821 49822 } 49823 else 49824 { 49825 $('#redactor_tabs').find('a').eq(1).remove(); 49826 } 49827 49828 if (this.opts.imageUpload || this.opts.s3) 49829 { 49830 // dragupload 49831 if (!this.isMobile() && this.opts.s3 === false) 49832 { 49833 if ($('#redactor_file' ).length) 49834 { 49835 this.draguploadInit('#redactor_file', { 49836 url: this.opts.imageUpload, 49837 uploadFields: this.opts.uploadFields, 49838 success: $.proxy(this.imageCallback, this), 49839 error: $.proxy(function(obj, json) 49840 { 49841 this.callback('imageUploadError', json); 49842 49843 }, this), 49844 uploadParam: this.opts.imageUploadParam 49845 }); 49846 } 49847 } 49848 49849 if (this.opts.s3 === false) 49850 { 49851 // ajax upload 49852 this.uploadInit('redactor_file', { 49853 auto: true, 49854 url: this.opts.imageUpload, 49855 success: $.proxy(this.imageCallback, this), 49856 error: $.proxy(function(obj, json) 49857 { 49858 this.callback('imageUploadError', json); 49859 49860 }, this) 49861 }); 49862 } 49863 // s3 upload 49864 else 49865 { 49866 $('#redactor_file').on('change.redactor', $.proxy(this.s3handleFileSelect, this)); 49867 } 49868 49869 } 49870 else 49871 { 49872 $('.redactor_tab').hide(); 49873 if (!this.opts.imageGetJson) 49874 { 49875 $('#redactor_tabs').remove(); 49876 $('#redactor_tab3').show(); 49877 } 49878 else 49879 { 49880 var tabs = $('#redactor_tabs').find('a'); 49881 tabs.eq(0).remove(); 49882 tabs.eq(1).addClass('redactor_tabs_act'); 49883 $('#redactor_tab2').show(); 49884 } 49885 } 49886 49887 $('#redactor_upload_btn').click($.proxy(this.imageCallbackLink, this)); 49888 49889 if (!this.opts.imageUpload && !this.opts.imageGetJson) 49890 { 49891 setTimeout(function() 49892 { 49893 $('#redactor_file_link').focus(); 49894 49895 }, 200); 49896 } 49897 49898 }, this); 49899 49900 this.modalInit(this.opts.curLang.image, this.opts.modal_image, 610, callback); 49901 49902 }, 49903 imageEdit: function(image) 49904 { 49905 var $el = image; 49906 var parent = $el.parent().parent(); 49907 49908 var callback = $.proxy(function() 49909 { 49910 $('#redactor_file_alt').val($el.attr('alt')); 49911 $('#redactor_image_edit_src').attr('href', $el.attr('src')); 49912 $('#redactor_form_image_align').val($el.css('float')); 49913 49914 if ($(parent).get(0).tagName === 'A') 49915 { 49916 $('#redactor_file_link').val($(parent).attr('href')); 49917 49918 if ($(parent).attr('target') == '_blank') 49919 { 49920 $('#redactor_link_blank').prop('checked', true); 49921 } 49922 } 49923 49924 $('#redactor_image_delete_btn').click($.proxy(function() 49925 { 49926 this.imageRemove($el); 49927 49928 }, this)); 49929 49930 $('#redactorSaveBtn').click($.proxy(function() 49931 { 49932 this.imageSave($el); 49933 49934 }, this)); 49935 49936 }, this); 49937 49938 this.modalInit(this.opts.curLang.edit, this.opts.modal_image_edit, 380, callback); 49939 49940 }, 49941 imageRemove: function(el) 49942 { 49943 var parent = $(el).parent(); 49944 $(el).remove(); 49945 49946 if (parent.length && parent[0].tagName === 'P') 49947 { 49948 this.$editor.focus(); 49949 this.selectionStart(parent); 49950 } 49951 49952 // delete callback 49953 this.callback('imageDelete', el); 49954 49955 this.modalClose(); 49956 this.sync(); 49957 }, 49958 imageSave: function(el) 49959 { 49960 var $el = $(el); 49961 var parent = $el.parent(); 49962 49963 $el.attr('alt', $('#redactor_file_alt').val()); 49964 49965 var floating = $('#redactor_form_image_align').val(); 49966 49967 if (floating === 'left') 49968 { 49969 $el.css({ 'float': 'left', 'margin': '0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ' 0' }); 49970 } 49971 else if (floating === 'right') 49972 { 49973 $el.css({ 'float': 'right', 'margin': '0 0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + '' }); 49974 } 49975 else 49976 {
49977 var imageBox = $el.closest('#redactor-image-box'); 49978 if (imageBox.size() != 0) imageBox.css({ 'float': '', 'margin': '' }); 49979 $el.css({ 'float': '', 'margin': '' }); 49980 } 49981 49982 // as link 49983 var link = $.trim($('#redactor_file_link').val()); 49984 if (link !== '') 49985 { 49986 var target = false; 49987 if ($('#redactor_link_blank').prop('checked')) 49988 { 49989 target = true; 49990 } 49991 49992 if (parent.get(0).tagName !== 'A') 49993 { 49994 var a = $('<a href="' + link + '">' + this.outerHtml(el) + '</a>'); 49995 49996 if (target) 49997 { 49998 a.attr('target', '_blank'); 49999 } 50000 50001 $el.replaceWith(a); 50002 } 50003 else 50004 { 50005 parent.attr('href', link); 50006 if (target) 50007 { 50008 parent.attr('target', '_blank'); 50009 } 50010 else 50011 { 50012 parent.removeAttr('target'); 50013 } 50014 } 50015 } 50016 else 50017 { 50018 if (parent.get(0).tagName === 'A') 50019 { 50020 parent.replaceWith(this.outerHtml(el)); 50021 } 50022 } 50023 50024 this.modalClose(); 50025 this.observeImages(); 50026 this.sync(); 50027 50028 }, 50029 imageResizeHide: function(e) 50030 { 50031 if (e !== false && $(e.target).parent().size() != 0 && $(e.target).parent()[0].id === 'redactor-image-box') 50032 { 50033 return false; 50034 } 50035 50036 var imageBox = this.$editor.find('#redactor-image-box'); 50037 if (imageBox.size() == 0) 50038 { 50039 return false; 50040 } 50041 50042 this.$editor.find('#redactor-image-editter, #redactor-image-resizer').remove(); 50043 50044 var margin = imageBox[0].style.margin; 50045 if (margin != '0px') 50046 { 50047 imageBox.find('img').css('margin', margin); 50048 imageBox.css('margin', ''); 50049 } 50050 50051 imageBox.find('img').css('opacity', ''); 50052 imageBox.replaceWith(function() 50053 { 50054 return $(this).contents(); 50055 }); 50056 50057 $(document).off('click.redactor-image-resize-hide'); 50058 this.$editor.off('click.redactor-image-resize-hide'); 50059 this.$editor.off('keydown.redactor-image-delete'); 50060 50061 this.sync() 50062 50063 }, 50064 imageResize: function(image) 50065 { 50066 var $image = $(image); 50067 50068 $image.on('mousedown', $.proxy(function() 50069 { 50070 this.imageResizeHide(false); 50071 }, this)); 50072 50073 $image.on('dragstart', $.proxy(function() 50074 { 50075 this.$editor.on('drop.redactor-image-inside-drop', $.proxy(function() 50076 { 50077 setTimeout($.proxy(function() 50078 { 50079 this.observeImages(); 50080 this.$editor.off('drop.redactor-image-inside-drop'); 50081 this.sync(); 50082 50083 }, this), 1); 50084 50085 },this)); 50086 }, this)); 50087 50088 $image.on('click', $.proxy(function(e) 50089 { 50090 if (this.$editor.find('#redactor-image-box').size() != 0) 50091 { 50092 return false; 50093 } 50094 50095 var clicked = false, 50096 start_x, 50097 start_y, 50098 ratio = $image.width() / $image.height(), 50099 min_w = 20, 50100 min_h = 10; 50101 50102 var imageResizer = this.imageResizeControls($image); 50103 50104 // resize 50105 var isResizing = false; 50106 imageResizer.on('mousedown', function(e) 50107 { 50108 isResizing = true; 50109 e.preventDefault(); 50110 50111 ratio = $image.width() / $image.height(); 50112 50113 start_x = Math.round(e.pageX - $image.eq(0).offset().left); 50114 start_y = Math.round(e.pageY - $image.eq(0).offset().top); 50115 50116 }); 50117 50118 $(this.document.body).on('mousemove', $.proxy(function(e) 50119 { 50120 if (isResizing) 50121 { 50122 var mouse_x = Math.round(e.pageX - $image.eq(0).offset().left) - start_x; 50123 var mouse_y = Math.round(e.pageY - $image.eq(0).offset().top) - start_y; 50124 50125 var div_h = $image.height(); 50126 50127 var new_h = parseInt(div_h, 10) + mouse_y; 50128 var new_w = Math.round(new_h * ratio); 50129 50130 if (new_w > min_w) 50131 { 50132 $image.width(new_w); 50133 50134 if (new_w < 100) 50135 { 50136 this.imageEditter.css({ 50137 marginTop: '-7px', 50138 marginLeft: '-13px', 50139 fontSize: '9px', 50140 padding: '3px 5px' 50141 }); 50142 } 50143 else 50144 { 50145 this.imageEditter.css({ 50146 marginTop: '-11px', 50147 marginLeft: '-18px', 50148 fontSize: '11px', 50149 padding: '7px 10px' 50150 }); 50151 } 50152 } 50153 50154 start_x = Math.round(e.pageX - $image.eq(0).offset().left); 50155 start_y = Math.round(e.pageY - $image.eq(0).offset().top); 50156 50157 this.sync() 50158 } 50159 }, this)).on('mouseup', function() 50160 { 50161 isResizing = false; 50162 }); 50163 50164 50165 this.$editor.on('keydown.redactor-image-delete', $.proxy(function(e) 50166 { 50167 var key = e.which; 50168 50169 if (this.keyCode.BACKSPACE == key || this.keyCode.DELETE == key) 50170 { 50171 this.imageResizeHide(false); 50172 this.imageRemove($image); 50173 } 50174 50175 }, this)); 50176 50177 $(document).on('click.redactor-image-resize-hide', $.proxy(this.imageResizeHide, this)); 50178 this.$editor.on('click.redactor-image-resize-hide', $.proxy(this.imageResizeHide, this)); 50179 50180 50181 }, this)); 50182 }, 50183 imageResizeControls: function($image) 50184 { 50185 var imageBox = $('<span id="redactor-image-box" data-redactor="verified">'); 50186 imageBox.css({ 50187 position: 'relative', 50188 display: 'inline-block', 50189 lineHeight: 0, 50190 outline: '1px dashed rgba(0, 0, 0, .6)', 50191 'float': $image.css('float') 50192 }); 50193 imageBox.attr('contenteditable', false); 50194 50195 var margin = $image[0].style.margin; 50196 if (margin != '0px') 50197 { 50198 imageBox.css('margin', margin); 50199 $image.css('margin', ''); 50200 } 50201 50202 $image.css('opacity', .5).after(imageBox); 50203 50204 // editter 50205 this.imageEditter = $('<span id="redactor-image-editter" data-redactor="verified">' + this.opts.curLang.edit + '</span>'); 50206 this.imageEditter.css({ 50207 position: 'absolute', 50208 zIndex: 2, 50209 top: '50%', 50210 left: '50%', 50211 marginTop: '-11px', 50212 marginLeft: '-18px', 50213 lineHeight: 1, 50214 backgroundColor: '#000', 50215 color: '#fff', 50216 fontSize: '11px', 50217 padding: '7px 10px', 50218 cursor: 'pointer' 50219 }); 50220 this.imageEditter.attr('contenteditable', false); 50221 this.imageEditter.on('click', $.proxy(function() 50222 { 50223 this.imageEdit($image); 50224 }, this)); 50225 imageBox.append(this.imageEditter); 50226 50227 // resizer 50228 var imageResizer = $('<span id="redactor-image-resizer" data-redactor="verified"></span>'); 50229 imageResizer.css({ 50230 position: 'absolute', 50231 zIndex: 2, 50232 lineHeight: 1, 50233 cursor: 'nw-resize', 50234 bottom: '-4px',
50235 right: '-5px', 50236 border: '1px solid #fff', 50237 backgroundColor: '#000', 50238 width: '8px', 50239 height: '8px' 50240 }); 50241 imageResizer.attr('contenteditable', false); 50242 imageBox.append(imageResizer); 50243 50244 imageBox.append($image); 50245 50246 return imageResizer; 50247 }, 50248 imageThumbClick: function(e) 50249 { 50250 var img = '<img id="image-marker" src="' + $(e.target).attr('rel') + '" alt="' + $(e.target).attr('title') + '" />'; 50251 50252 if (this.opts.paragraphy) img = '<p>' + img + '</p>'; 50253 50254 this.imageInsert(img, true); 50255 }, 50256 imageCallbackLink: function() 50257 { 50258 var val = $('#redactor_file_link').val(); 50259 50260 if (val !== '') 50261 { 50262 var data = '<img id="image-marker" src="' + val + '" />'; 50263 if (this.opts.linebreaks === false) data = '<p>' + data + '</p>'; 50264 50265 this.imageInsert(data, true); 50266 50267 } 50268 else this.modalClose(); 50269 }, 50270 imageCallback: function(data) 50271 { 50272 this.imageInsert(data); 50273 }, 50274 imageInsert: function(json, link) 50275 { 50276 this.selectionRestore(); 50277 50278 if (json !== false) 50279 { 50280 var html = ''; 50281 if (link !== true) 50282 { 50283 html = '<img id="image-marker" src="' + json.filelink + '" />'; 50284 if (this.opts.paragraphy) html = '<p>' + html + '</p>'; 50285 } 50286 else 50287 { 50288 html = json; 50289 } 50290 50291 this.execCommand('inserthtml', html, false); 50292 50293 var image = $(this.$editor.find('img#image-marker')); 50294 50295 if (image.length) image.removeAttr('id'); 50296 else image = false; 50297 50298 this.sync(); 50299 50300 // upload image callback 50301 link !== true && this.callback('imageUpload', image, json); 50302 } 50303 50304 this.modalClose(); 50305 this.observeImages(); 50306 }, 50307 50308 // MODAL 50309 modalTemplatesInit: function() 50310 { 50311 $.extend( this.opts, 50312 { 50313 modal_file: String() 50314 + '<section>' 50315 + '<div id="redactor-progress" class="redactor-progress redactor-progress-striped" style="display: none;">' 50316 + '<div id="redactor-progress-bar" class="redactor-progress-bar" style="width: 100%;"></div>' 50317 + '</div>' 50318 + '<form id="redactorUploadFileForm" method="post" action="" enctype="multipart/form-data">' 50319 + '<label>' + this.opts.curLang.filename + '</label>' 50320 + '<input type="text" id="redactor_filename" class="redactor_input" />' 50321 + '<div style="margin-top: 7px;">' 50322 + '<input type="file" id="redactor_file" name="' + this.opts.fileUploadParam + '" />' 50323 + '</div>' 50324 + '</form>' 50325 + '</section>', 50326 50327 modal_image_edit: String() 50328 + '<section>' 50329 + '<label>' + this.opts.curLang.title + '</label>' 50330 + '<input id="redactor_file_alt" class="redactor_input" />' 50331 + '<label>' + this.opts.curLang.link + '</label>' 50332 + '<input id="redactor_file_link" class="redactor_input" />' 50333 + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>' 50334 + '<label>' + this.opts.curLang.image_position + '</label>' 50335 + '<select id="redactor_form_image_align">' 50336 + '<option value="none">' + this.opts.curLang.none + '</option>' 50337 + '<option value="left">' + this.opts.curLang.left + '</option>' 50338 + '<option value="right">' + this.opts.curLang.right + '</option>' 50339 + '</select>' 50340 + '</section>' 50341 + '<footer>' 50342 + '<button id="redactor_image_delete_btn" class="redactor_modal_btn redactor_modal_delete_btn">' + this.opts.curLang._delete + '</button> ' 50343 + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' 50344 + '<input type="button" name="save" class="redactor_modal_btn redactor_modal_action_btn" id="redactorSaveBtn" value="' + this.opts.curLang.save + '" />' 50345 + '</footer>', 50346 50347 modal_image: String() 50348 + '<section>' 50349 + '<div id="redactor_tabs">' 50350 + '<a href="#" class="redactor_tabs_act">' + this.opts.curLang.upload + '</a>' 50351 + '<a href="#">' + this.opts.curLang.choose + '</a>' 50352 + '<a href="#">' + this.opts.curLang.link + '</a>' 50353 + '</div>' 50354 + '<div id="redactor-progress" class="redactor-progress redactor-progress-striped" style="display: none;">' 50355 + '<div id="redactor-progress-bar" class="redactor-progress-bar" style="width: 100%;"></div>' 50356 + '</div>' 50357 + '<form id="redactorInsertImageForm" method="post" action="" enctype="multipart/form-data">' 50358 + '<div id="redactor_tab1" class="redactor_tab">' 50359 + '<input type="file" id="redactor_file" name="' + this.opts.imageUploadParam + '" />' 50360 + '</div>' 50361 + '<div id="redactor_tab2" class="redactor_tab" style="display: none;">' 50362 + '<div id="redactor_image_box"></div>' 50363 + '</div>' 50364 + '</form>' 50365 + '<div id="redactor_tab3" class="redactor_tab" style="display: none;">' 50366 + '<label>' + this.opts.curLang.image_web_link + '</label>' 50367 + '<input type="text" name="redactor_file_link" id="redactor_file_link" class="redactor_input" />' 50368 + '</div>' 50369 + '</section>' 50370 + '<footer>' 50371 + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' 50372 + '<input type="button" name="upload" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_upload_btn" value="' + this.opts.curLang.insert + '" />' 50373 + '</footer>', 50374 50375 modal_link: String() 50376 + '<section>' 50377 + '<form id="redactorInsertLinkForm" method="post" action="">' 50378 + '<div id="redactor_tabs">' 50379 + '<a href="#" class="redactor_tabs_act">URL</a>' 50380 + '<a href="#">Email</a>' 50381 + '<a href="#">
50381' + this.opts.curLang.anchor + '</a>' 50382 + '</div>' 50383 + '<input type="hidden" id="redactor_tab_selected" value="1" />' 50384 + '<div class="redactor_tab" id="redactor_tab1">' 50385 + '<label>URL</label>' 50386 + '<input type="text" id="redactor_link_url" class="redactor_input" />' 50387 + '<label>' + this.opts.curLang.text + '</label>' 50388 + '<input type="text" class="redactor_input redactor_link_text" id="redactor_link_url_text" />' 50389 + '<label><input type="checkbox" id="redactor_link_blank"> ' + this.opts.curLang.link_new_tab + '</label>' 50390 + '</div>' 50391 + '<div class="redactor_tab" id="redactor_tab2" style="display: none;">' 50392 + '<label>Email</label>' 50393 + '<input type="text" id="redactor_link_mailto" class="redactor_input" />' 50394 + '<label>' + this.opts.curLang.text + '</label>' 50395 + '<input type="text" class="redactor_input redactor_link_text" id="redactor_link_mailto_text" />' 50396 + '</div>' 50397 + '<div class="redactor_tab" id="redactor_tab3" style="display: none;">' 50398 + '<label>' + this.opts.curLang.anchor + '</label>' 50399 + '<input type="text" class="redactor_input" id="redactor_link_anchor" />' 50400 + '<label>' + this.opts.curLang.text + '</label>' 50401 + '<input type="text" class="redactor_input redactor_link_text" id="redactor_link_anchor_text" />' 50402 + '</div>' 50403 + '</form>' 50404 + '</section>' 50405 + '<footer>' 50406 + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' 50407 + '<input type="button" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_insert_link_btn" value="' + this.opts.curLang.insert + '" />' 50408 + '</footer>', 50409 50410 modal_table: String() 50411 + '<section>' 50412 + '<label>' + this.opts.curLang.rows + '</label>' 50413 + '<input type="text" size="5" value="2" id="redactor_table_rows" />' 50414 + '<label>' + this.opts.curLang.columns + '</label>' 50415 + '<input type="text" size="5" value="3" id="redactor_table_columns" />' 50416 + '</section>' 50417 + '<footer>' 50418 + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' 50419 + '<input type="button" name="upload" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_insert_table_btn" value="' + this.opts.curLang.insert + '" />' 50420 + '</footer>', 50421 50422 modal_video: String() 50423 + '<section>' 50424 + '<form id="redactorInsertVideoForm">' 50425 + '<label>' + this.opts.curLang.video_html_code + '</label>' 50426 + '<textarea id="redactor_insert_video_area" style="width: 99%; height: 160px;"></textarea>' 50427 + '</form>' 50428 + '</section>' 50429 + '<footer>' 50430 + '<button class="redactor_modal_btn redactor_btn_modal_close">' + this.opts.curLang.cancel + '</button>' 50431 + '<input type="button" class="redactor_modal_btn redactor_modal_action_btn" id="redactor_insert_video_btn" value="' + this.opts.curLang.insert + '" />' 50432 + '</footer>' 50433 50434 }); 50435 }, 50436 modalInit: function(title, content, width, callback) 50437 { 50438 var $redactorModalOverlay = $('#redactor_modal_overlay'); 50439 50440 // modal overlay 50441 if (!$redactorModalOverlay.length) 50442 { 50443 this.$overlay = $redactorModalOverlay = $('<div id="redactor_modal_overlay" style="display: none;"></div>'); 50444 $('body').prepend(this.$overlay); 50445 } 50446 50447 if (this.opts.modalOverlay) 50448 { 50449 $redactorModalOverlay.show().on('click', $.proxy(this.modalClose, this)); 50450 } 50451 50452 var $redactorModal = $('#redactor_modal'); 50453 50454 if (!$redactorModal.length) 50455 { 50456 this.$modal = $redactorModal = $('<div id="redactor_modal" style="display: none;"><div id="redactor_modal_close">×</div><header id="redactor_modal_header"></header><div id="redactor_modal_inner"></div></div>'); 50457 $('body').append(this.$modal); 50458 } 50459 50460 $('#redactor_modal_close').on('click', $.proxy(this.modalClose, this)); 50461 50462 this.hdlModalClose = $.proxy(function(e) 50463 { 50464 if (e.keyCode === this.keyCode.ESC) 50465 { 50466 this.modalClose(); 50467 return false; 50468 } 50469 50470 }, this); 50471 50472 $(document).keyup(this.hdlModalClose); 50473 this.$editor.keyup(this.hdlModalClose); 50474 50475 // set content 50476 this.modalcontent = false;
50477 if (content.indexOf('#') == 0) 50478 { 50479 this.modalcontent = $(content); 50480 $('#redactor_modal_inner').empty().append(this.modalcontent.html()); 50481 this.modalcontent.html(''); 50482 50483 } 50484 else 50485 { 50486 $('#redactor_modal_inner').empty().append(content); 50487 } 50488 50489 $redactorModal.find('#redactor_modal_header').html(title); 50490 50491 // draggable 50492 if (typeof $.fn.draggable !== 'undefined') 50493 { 50494 $redactorModal.draggable({ handle: '#redactor_modal_header' }); 50495 $redactorModal.find('#redactor_modal_header').css('cursor', 'move'); 50496 } 50497 50498 var $redactor_tabs = $('#redactor_tabs'); 50499 50500 // tabs 50501 if ($redactor_tabs.length ) 50502 { 50503 var that = this; 50504 $redactor_tabs.find('a').each(function(i, s) 50505 { 50506 i++; 50507 $(s).on('click', function(e) 50508 { 50509 e.preventDefault(); 50510 50511 $redactor_tabs.find('a').removeClass('redactor_tabs_act'); 50512 $(this).addClass('redactor_tabs_act'); 50513 $('.redactor_tab').hide(); 50514 $('#redactor_tab' + i ).show(); 50515 $('#redactor_tab_selected').val(i); 50516 50517 if (that.isMobile() === false) 50518 { 50519 var height = $redactorModal.outerHeight(); 50520 $redactorModal.css('margin-top', '-' + (height + 10) / 2 + 'px'); 50521 } 50522 }); 50523 }); 50524 } 50525 50526 $redactorModal.find('.redactor_btn_modal_close').on('click', $.proxy(this.modalClose, this)); 50527 50528 // save scroll 50529 if (this.opts.autoresize === true) this.saveModalScroll = this.document.body.scrollTop; 50530 50531 if (this.isMobile() === false) 50532 { 50533 $redactorModal.css({ 50534 position: 'fixed', 50535 top: '-2000px', 50536 left: '50%', 50537 width: width + 'px', 50538 marginLeft: '-' + (width + 60) / 2 + 'px' 50539 }).show(); 50540 50541 this.modalSaveBodyOveflow = $(document.body).css('overflow'); 50542 $(document.body).css('overflow', 'hidden'); 50543 50544 } 50545 else 50546 { 50547 $redactorModal.css({ 50548 position: 'fixed', 50549 width: '100%', 50550 height: '100%', 50551 top: '0', 50552 left: '0', 50553 margin: '0', 50554 minHeight: '300px' 50555 }).show(); 50556 } 50557 50558 // callback 50559 if (typeof callback === 'function') callback(); 50560 50561 if (this.isMobile() === false) 50562 { 50563 setTimeout(function() 50564 { 50565 var height = $redactorModal.outerHeight(); 50566 $redactorModal.css({ 50567 top: '50%', 50568 height: 'auto', 50569 minHeight: 'auto', 50570 marginTop: '-' + (height + 10) / 2 + 'px' 50571 }); 50572 }, 10); 50573 } 50574 50575 }, 50576 modalClose: function() 50577 { 50578 $('#redactor_modal_close').off('click', this.modalClose ); 50579 $('#redactor_modal').fadeOut('fast', $.proxy(function() 50580 { 50581 var redactorModalInner = $('#redactor_modal_inner'); 50582 50583 if (this.modalcontent !== false) 50584 { 50585 this.modalcontent.html(redactorModalInner.html()); 50586 this.modalcontent = false; 50587 } 50588 50589 redactorModalInner.html(''); 50590 50591 if (this.opts.modalOverlay) 50592 { 50593 $('#redactor_modal_overlay').hide().off('click', this.modalClose); 50594 } 50595 50596 $(document).unbind('keyup', this.hdlModalClose); 50597 this.$editor.unbind('keyup', this.hdlModalClose); 50598 50599 this.selectionRestore(); 50600 50601 // restore scroll 50602 if (this.opts.autoresize && this.saveModalScroll) $(this.document.body).scrollTop(this.saveModalScroll); 50603 50604 }, this)); 50605 50606 50607 if (this.isMobile() === false) 50608 { 50609 $(document.body).css('overflow', this.modalSaveBodyOveflow ? this.modalSaveBodyOveflow : 'visible'); 50610 } 50611 50612 return false; 50613 }, 50614 modalSetTab: function(num) 50615 { 50616 $('.redactor_tab').hide(); 50617 $('#redactor_tabs').find('a').removeClass('redactor_tabs_act').eq(num - 1).addClass('redactor_tabs_act'); 50618 $('#redactor_tab' + num).show(); 50619 }, 50620 50621 // S3 50622 s3handleFileSelect: function(e) 50623 { 50624 var files = e.target.files; 50625 50626 for (var i = 0, f; f = files[i]; i++) 50627 { 50628 this.s3uploadFile(f); 50629 } 50630 }, 50631 s3uploadFile: function(file) 50632 { 50633 this.s3executeOnSignedUrl(file, $.proxy(function(signedURL) 50634 { 50635 this.s3uploadToS3(file, signedURL); 50636 }, this)); 50637 }, 50638 s3executeOnSignedUrl: function(file, callback) 50639 { 50640 var xhr = new XMLHttpRequest(); 50641 xhr.open('GET', this.opts.s3 + '?name=' + file.name + '&type=' + file.type, true); 50642 50643 // Hack to pass bytes through unprocessed. 50644 xhr.overrideMimeType('text/plain; charset=x-user-defined'); 50645 50646 xhr.onreadystatechange = function(e) 50647 { 50648 if (this.readyState == 4 && this.status == 200) 50649 { 50650 $('#redactor-progress').fadeIn(); 50651 try { 50652 callback(decodeURIComponent(this.responseText)); 50653 } catch (e) { 50654 if (typeof window !== 'undefined' && window.Sentry && window.Sentry.captureException) { 50655 window.Sentry.captureException(new Error('Redactor response decoding failed'), { 50656 tags: { 50657 error_type: 'decode_failure', 50658 library: 'redactor', 50659 version: '9.1.6' 50660 }, 50661 extra: { 50662 response_text: this.responseText, 50663 error_message: e.message, 50664 stack_trace: e.stack, 50665 timestamp: new Date().toISOString(), 50666 page_url: typeof window !== 'undefined' ? window.location.href : 'unknown' 50667 }, 50668 level: 'warning' 50669 }); 50670 } 50671 callback(this.responseText); 50672 } 50673 } 50674 else if(this.readyState == 4 && this.status != 200) 50675 { 50676 //setProgress(0, 'Could not contact signing script. Status = ' + this.status); 50677 } 50678 }; 50679 50680 xhr.send(); 50681 }, 50682 s3createCORSRequest: function(method, url) 50683 { 50684 var xhr = new XMLHttpRequest(); 50685 if ("withCredentials" in xhr) 50686 { 50687 xhr.open(method, url, true); 50688 } 50689 else if (typeof XDomainRequest != "undefined") 50690 { 50691 xhr = new XDomainRequest(); 50692 xhr.open(method, url); 50693 } 50694 else 50695 {
50696 xhr = null; 50697 } 50698 50699 return xhr; 50700 }, 50701 s3uploadToS3: function(file, url) 50702 { 50703 var xhr = this.s3createCORSRequest('PUT', url); 50704 if (!xhr) 50705 { 50706 //setProgress(0, 'CORS not supported'); 50707 } 50708 else 50709 { 50710 xhr.onload = $.proxy(function() 50711 { 50712 if (xhr.status == 200) 50713 { 50714 //setProgress(100, 'Upload completed.'); 50715 50716 $('#redactor-progress').hide(); 50717 50718 var s3image = url.split('?'); 50719 50720 if (!s3image[0]) 50721 { 50722 // url parsing is fail 50723 return false; 50724 } 50725 50726 this.selectionRestore(); 50727 50728 var html = ''; 50729 html = '<img id="image-marker" src="' + s3image[0] + '" />'; 50730 if (this.opts.paragraphy) html = '<p>' + html + '</p>'; 50731 50732 this.execCommand('inserthtml', html, false); 50733 50734 var image = $(this.$editor.find('img#image-marker')); 50735 50736 if (image.length) image.removeAttr('id'); 50737 else image = false; 50738 50739 this.sync(); 50740 50741 // upload image callback 50742 this.callback('imageUpload', image, false); 50743 50744 this.modalClose(); 50745 this.observeImages(); 50746 50747 } 50748 else 50749 { 50750 //setProgress(0, 'Upload error: ' + xhr.status); 50751 } 50752 }, this); 50753 50754 xhr.onerror = function() 50755 { 50756 //setProgress(0, 'XHR error.'); 50757 }; 50758 50759 xhr.upload.onprogress = function(e) 50760 { 50761 /* 50762 if (e.lengthComputable) 50763 { 50764 var percentLoaded = Math.round((e.loaded / e.total) * 100); 50765 setProgress(percentLoaded, percentLoaded == 100 ? 'Finalizing.' : 'Uploading.'); 50766 } 50767 */ 50768 }; 50769 50770 xhr.setRequestHeader('Content-Type', file.type); 50771 xhr.setRequestHeader('x-amz-acl', 'public-read'); 50772 50773 xhr.send(file); 50774 } 50775 }, 50776 50777 // UPLOAD 50778 uploadInit: function(el, options) 50779 { 50780 this.uploadOptions = { 50781 url: false, 50782 success: false, 50783 error: false, 50784 start: false, 50785 trigger: false, 50786 auto: false, 50787 input: false 50788 }; 50789 50790 $.extend(this.uploadOptions, options); 50791 50792 var $el = $('#' + el); 50793 50794 // Test input or form 50795 if ($el.length && $el[0].tagName === 'INPUT') 50796 { 50797 this.uploadOptions.input = $el; 50798 this.el = $($el[0].form); 50799 } 50800 else this.el = $el; 50801 50802 this.element_action = this.el.attr('action'); 50803 50804 // Auto or trigger 50805 if (this.uploadOptions.auto) 50806 { 50807 $(this.uploadOptions.input).change($.proxy(function(e) 50808 { 50809 this.el.submit(function(e) 50810 { 50811 return false; 50812 }); 50813 50814 this.uploadSubmit(e); 50815 50816 }, this)); 50817 50818 } 50819 else if (this.uploadOptions.trigger) 50820 { 50821 $('#' + this.uploadOptions.trigger).click($.proxy(this.uploadSubmit, this)); 50822 } 50823 }, 50824 uploadSubmit: function(e) 50825 { 50826 $('#redactor-progress').fadeIn(); 50827 this.uploadForm(this.element, this.uploadFrame()); 50828 }, 50829 uploadFrame: function() 50830 { 50831 this.id = 'f' + Math.floor(Math.random() * 99999); 50832 50833 var d = this.document.createElement('div'); 50834 var iframe = '<iframe style="display:none" id="' + this.id + '" name="' + this.id + '"></iframe>'; 50835 50836 d.innerHTML = iframe; 50837 $(d).appendTo("body"); 50838 50839 // Start 50840 if (this.uploadOptions.start) this.uploadOptions.start(); 50841 50842 $( '#' + this.id ).load($.proxy(this.uploadLoaded, this)); 50843 50844 return this.id; 50845 }, 50846 uploadForm: function(f, name) 50847 { 50848 if (this.uploadOptions.input) 50849 { 50850 var formId = 'redactorUploadForm' + this.id, 50851 fileId = 'redactorUploadFile' + this.id; 50852 50853 this.form = $('<form action="' + this.uploadOptions.url + '" method="POST" target="' + name + '" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data" />'); 50854 50855 // append hidden fields 50856 if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object') 50857 { 50858 $.each(this.opts.uploadFields, $.proxy(function(k, v) 50859 { 50860 if (v != null && v.toString().indexOf('#') === 0) v = $(v).val(); 50861 50862 var hidden = $('<input/>', { 50863 'type': "hidden", 50864 'name': k, 50865 'value': v 50866 }); 50867 50868 $(this.form).append(hidden); 50869 50870 }, this)); 50871 } 50872 50873 var oldElement = this.uploadOptions.input; 50874 var newElement = $(oldElement).clone(); 50875 50876 $(oldElement).attr('id', fileId).before(newElement).appendTo(this.form); 50877 50878 $(this.form).css('position', 'absolute') 50879 .css('top', '-2000px') 50880 .css('left', '-2000px') 50881 .appendTo('body'); 50882 50883 this.form.submit(); 50884 50885 } 50886 else 50887 {
50888 f.attr('target', name) 50889 .attr('method', 'POST') 50890 .attr('enctype', 'multipart/form-data') 50891 .attr('action', this.uploadOptions.url); 50892 50893 this.element.submit(); 50894 } 50895 }, 50896 uploadLoaded: function() 50897 { 50898 var i = $( '#' + this.id)[0], d; 50899 50900 if (i.contentDocument) d = i.contentDocument; 50901 else if (i.contentWindow) d = i.contentWindow.document; 50902 else d = window.frames[this.id].document; 50903 50904 // Success 50905 if (this.uploadOptions.success) 50906 { 50907 $('#redactor-progress').hide(); 50908 50909 if (typeof d !== 'undefined') 50910 { 50911 // Remove bizarre <pre> tag wrappers around our json data: 50912 var rawString = d.body.innerHTML; 50913 var jsonString = rawString.match(/\{(.|\n)*\}/)[0]; 50914 50915 jsonString = jsonString.replace(/^\[/, ''); 50916 jsonString = jsonString.replace(/\]$/, ''); 50917 50918 var json = $.parseJSON(jsonString); 50919 50920 if (typeof json.error == 'undefined') this.uploadOptions.success(json); 50921 else 50922 { 50923 this.uploadOptions.error(this, json); 50924 this.modalClose(); 50925 } 50926 } 50927 else 50928 { 50929 this.modalClose(); 50930 alert('Upload failed!'); 50931 } 50932 } 50933 50934 this.el.attr('action', this.element_action); 50935 this.el.attr('target', ''); 50936 }, 50937 50938 // DRAGUPLOAD 50939 draguploadInit: function (el, options) 50940 { 50941 this.draguploadOptions = $.extend({ 50942 url: false, 50943 success: false, 50944 error: false, 50945 preview: false, 50946 uploadFields: false, 50947 text: this.opts.curLang.drop_file_here, 50948 atext: this.opts.curLang.or_choose, 50949 uploadParam: false 50950 }, options); 50951 50952 if (window.FormData === undefined) return false; 50953 50954 this.droparea = $('<div class="redactor_droparea"></div>'); 50955 this.dropareabox = $('<div class="redactor_dropareabox">' + this.draguploadOptions.text + '</div>'); 50956 this.dropalternative = $('<div class="redactor_dropalternative">' + this.draguploadOptions.atext + '</div>'); 50957 50958 this.droparea.append(this.dropareabox); 50959 50960 $(el).before(this.droparea); 50961 $(el).before(this.dropalternative); 50962 50963 // drag over 50964 this.dropareabox.on('dragover', $.proxy(function() 50965 { 50966 return this.draguploadOndrag(); 50967 50968 }, this)); 50969 50970 // drag leave 50971 this.dropareabox.on('dragleave', $.proxy(function() 50972 { 50973 return this.draguploadOndragleave(); 50974 50975 }, this)); 50976 50977 // drop 50978 this.dropareabox.get(0).ondrop = $.proxy(function(e) 50979 { 50980 e.preventDefault(); 50981 50982 this.dropareabox.removeClass('hover').addClass('drop'); 50983 50984 this.dragUploadAjax(this.draguploadOptions.url, e.dataTransfer.files[0], false, false, false, this.draguploadOptions.uploadParam); 50985 50986 }, this ); 50987 }, 50988 dragUploadAjax: function(url, file, directupload, progress, e, uploadParam) 50989 { 50990 50991 50992 if (!directupload) 50993 { 50994 var xhr = $.ajaxSettings.xhr(); 50995 if (xhr.upload) 50996 { 50997 xhr.upload.addEventListener('progress', $.proxy(this.uploadProgress, this), false); 50998 } 50999 51000 $.ajaxSetup({ 51001 xhr: function () { return xhr; } 51002 }); 51003 } 51004 51005 var fd = new FormData(); 51006 51007 // append file data 51008 if (uploadParam !== false) 51009 { 51010 fd.append(uploadParam, file); 51011 } 51012 else 51013 { 51014 fd.append('file', file); 51015 } 51016 51017 // append hidden fields 51018 if (this.opts.uploadFields !== false && typeof this.opts.uploadFields === 'object') 51019 { 51020 $.each(this.opts.uploadFields, $.proxy(function(k, v) 51021 { 51022 if (v != null && v.toString().indexOf('#') === 0) v = $(v).val(); 51023 fd.append(k, v); 51024 51025 }, this)); 51026 } 51027 51028 $.ajax({ 51029 url: url, 51030 dataType: 'html', 51031 data: fd, 51032 cache: false, 51033 contentType: false, 51034 processData: false, 51035 type: 'POST', 51036 success: $.proxy(function(data) 51037 { 51038 data = data.replace(/^\[/, ''); 51039 data = data.replace(/\]$/, ''); 51040 51041 var json = (typeof data === 'string' ? $.parseJSON(data) : data); 51042 51043 if (directupload) 51044 { 51045 progress.fadeOut('slow', function() 51046 { 51047 $(this).remove(); 51048 }); 51049 51050 var $img = $('<img>'); 51051 $img.attr('src', json.filelink).attr('id', 'drag-image-marker'); 51052 51053 this.insertNodeToCaretPositionFromPoint(e, $img[0]); 51054 51055 var image = $(this.$editor.find('img#drag-image-marker')); 51056 if (image.length) image.removeAttr('id'); 51057 else image = false; 51058 51059 this.sync(); 51060 this.observeImages(); 51061 51062 // upload callback 51063 if (image) this.callback('imageUpload', image, json); 51064 51065 // error callback 51066 if (typeof json.error !== 'undefined') this.callback('imageUploadError', json); 51067 } 51068 else 51069 { 51070 if (typeof json.error == 'undefined') 51071 { 51072 this.draguploadOptions.success(json); 51073 } 51074 else 51075 { 51076 this.draguploadOptions.error(this, json); 51077 this.draguploadOptions.success(false); 51078 } 51079 } 51080 51081 }, this) 51082 }); 51083 }, 51084 draguploadOndrag: function() 51085 { 51086 this.dropareabox.addClass('hover'); 51087 return false;
51088 }, 51089 draguploadOndragleave: function() 51090 { 51091 this.dropareabox.removeClass('hover'); 51092 return false; 51093 }, 51094 uploadProgress: function(e, text) 51095 { 51096 var percent = e.loaded ? parseInt(e.loaded / e.total * 100, 10) : e; 51097 this.dropareabox.text('Loading ' + percent + '% ' + (text || '')); 51098 }, 51099 51100 // UTILS 51101 isMobile: function() 51102 { 51103 return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent); 51104 }, 51105 normalize: function(str) 51106 { 51107 if (typeof(str) === 'undefined') return 0; 51108 return parseInt(str.replace('px',''), 10); 51109 }, 51110 outerHtml: function(el) 51111 { 51112 return $('<div>').append($(el).eq(0).clone()).html(); 51113 }, 51114 isString: function(obj) 51115 { 51116 return Object.prototype.toString.call(obj) == '[object String]'; 51117 }, 51118 isEmpty: function(html) 51119 { 51120 html = html.replace(/​|<br>|<br\/>| /gi, ''); 51121 html = html.replace(/\s/g, ''); 51122 html = html.replace(/^<p>[^\W\w\D\d]*?<\/p>$/i, ''); 51123 51124 51125 return html == ''; 51126 }, 51127 browser: function(browser) 51128 { 51129 var ua = navigator.userAgent.toLowerCase(); 51130 var match = /(chrome)[ \/]([\w.]+)/.exec(ua) 51131 || /(webkit)[ \/]([\w.]+)/.exec(ua) 51132 || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) 51133 || /(msie) ([\w.]+)/.exec(ua) 51134 || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) 51135 || []; 51136 51137 if (browser == 'version') return match[2]; 51138 if (browser == 'webkit') return (match[1] == 'chrome' || match[1] == 'webkit'); 51139 51140 return match[1] == browser; 51141 }, 51142 oldIE: function() 51143 { 51144 if (this.browser('msie') && parseInt(this.browser('version'), 10) < 9) return true; 51145 return false; 51146 }, 51147 getFragmentHtml: function (fragment) 51148 { 51149 var cloned = fragment.cloneNode(true); 51150 var div = this.document.createElement('div'); 51151 51152 div.appendChild(cloned); 51153 return div.innerHTML; 51154 }, 51155 extractContent: function() 51156 { 51157 var node = this.$editor[0]; 51158 var frag = this.document.createDocumentFragment(); 51159 var child; 51160 51161 while ((child = node.firstChild)) 51162 { 51163 frag.appendChild(child); 51164 } 51165 51166 return frag; 51167 }, 51168 isParentRedactor: function(el) 51169 { 51170 if (!el) return false; 51171 if (this.opts.iframe) return el; 51172 51173 if ($(el).parents('div.redactor_editor').length == 0 || $(el).hasClass('redactor_editor')) return false; 51174 else return el; 51175 }, 51176 currentOrParentIs: function(tagName) 51177 { 51178 var parent = this.getParent(), current = this.getCurrent(); 51179 return parent && parent.tagName === tagName ? parent : current && current.tagName === tagName ? current : false; 51180 }, 51181 isEndOfElement: function() 51182 { 51183 var current = this.getBlock(); 51184 var offset = this.getCaretOffset(current); 51185 51186 var text = $.trim($(current).text()).replace(/\n\r\n/g, ''); 51187 51188 var len = text.length; 51189 51190 if (offset == len) return true; 51191 else return false; 51192 }, 51193 isFocused: function() 51194 { 51195 var el, sel = this.getSelection(); 51196 51197 if (sel && sel.rangeCount && sel.rangeCount > 0) el = sel.getRangeAt(0).startContainer; 51198 if (!el) return false; 51199 if (this.opts.iframe) 51200 { 51201 if (this.getCaretOffsetRange().equals()) return !this.$editor.is(el); 51202 else return true; 51203 } 51204 51205 return $(el).closest('div.redactor_editor').length != 0; 51206 }, 51207 removeEmptyAttr: function (el, attr) 51208 { 51209 if ($(el).attr(attr) == '') $(el).removeAttr(attr); 51210 }, 51211 removeFromArrayByValue: function(array, value) 51212 { 51213 var index = null; 51214 51215 while ((index = array.indexOf(value)) !== -1) 51216 { 51217 array.splice(index, 1); 51218 } 51219 51220 return array; 51221 } 51222 51223 }; 51224 51225 // constructor 51226 Redactor.prototype.init.prototype = Redactor.prototype; 51227 51228 // LINKIFY 51229 $.Redactor.fn.formatLinkify = function(protocol, convertLinks, convertImageLinks, convertVideoLinks, linkSize) 51230 { 51231 var url1 = /(^|<|\s)(www\..+?\..+?)(\s|>|$)/g, 51232 url2 = /(^|<|\s)(((https?|ftp):\/\/|mailto:).+?)(\s|>|$)/g, 51233 urlImage = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/gi, 51234 urlYoutube = /^.*(youtu.be\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/, 51235 urlVimeo = /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/; 51236 51237 var childNodes = (this.$editor ? this.$editor.get(0) : this).childNodes, i = childNodes.length; 51238 while (i--) 51239 { 51240 var n = childNodes[i]; 51241 if (n.nodeType === 3) 51242 { 51243 var html = n.nodeValue; 51244 51245 // youtube & vimeo 51246 if (convertVideoLinks && html) 51247 { 51248 var iframeStart = '<iframe width="500" height="281" src="', 51249 iframeEnd = '" frameborder="0" allowfullscreen></iframe>'; 51250 51251 if (html.match(urlYoutube)) 51252 { 51253 html = html.replace(urlYoutube, iframeStart + '//www.youtube.com/embed/$2' + iframeEnd); 51254 $(n).after(html).remove(); 51255 } 51256 else if (html.match(urlVimeo)) 51257 { 51258 html = html.replace(urlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); 51259 $(n).after(html).remove(); 51260 } 51261 } 51262 51263 // image 51264 if (convertImageLinks && html && html.match(urlImage)) 51265 { 51266 html = html.replace(urlImage, '<img src="$1">'); 51267 51268 $(n).after(html).remove(); 51269 } 51270 51271 // link 51272 if (convertLinks && html && (html.match(url1) || html.match(url2))) 51273 { 51274 var href = (html.match(url1) || html.match(url2)); 51275 href = href[0]; 51276 if (href.length > linkSize) href = href.substring(0, linkSize) + '...'; 51277 51278 html = html.replace(/&/g, '&') 51279 .replace(/</g, '<') 51280 .replace(/>/g, '>') 51281 .replace(url1, '$1<a href="' + protocol + '$2">' + href + '</a>$3') 51282 .replace(url2, '$1<a href="$2">' + href + '</a>$5'); 51283 51284 51285 $(n).after(html).remove(); 51286 } 51287 } 51288 else if (n.nodeType === 1 && !/^(a|button|textarea)$/i.test(n.tagName)) 51289 { 51290 $.Redactor.fn.formatLinkify.call(n, protocol, convertLinks, convertImageLinks, convertVideoLinks, linkSize); 51291 } 51292 } 51293 }; 51294 51295})(jQuery); 51296(function() { 51297 var base, 51298 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 51299 hasProp = {}.hasOwnProperty; 51300 51301 if ((base = App.Pages).Forum == null) { 51302 base.Forum = {}; 51303 } 51304 51305 App.Pages.Forum.TopicsNew = (function(superClass) { 51306 extend(TopicsNew, superClass); 51307 51308 function TopicsNew() { 51309 return TopicsNew.__super__.constructor.apply(this, arguments); 51310 } 51311 51312 TopicsNew.prototype.getForm = function() { 51313 return $('#new_forum_topic'); 51314 }; 51315 51316 TopicsNew.prototype.initialize = function() { 51317 this.$form = this.getForm(); 51318 $('#forum_topic_content').redactor({ 51319 buttons: ['bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', '|', 'image', 'link'], 51320 minHeight: 300, 51321 imageUpload: "/forum/topics/upload_image?authenticity_token=" + ($('meta[name="csrf-token"]').attr('content')), 51322 imageUploadErrorCallback: function(e, json) { 51323 return alert(json.error); 51324 } 51325 }); 51326 $('#forum_topic_tags').tagsInput({ 51327 delimiter: ' ', 51328 width: '100%', 51329 height: 'auto' 51330 }); 51331 return this.initValidation(); 51332 }; 51333 51334 TopicsNew.prototype.validationSettings = function() { 51335 return { 51336 ignore: [], 51337 rules: { 51338 'forum_topic[board_id]': { 51339 required: true 51340 }, 51341 'forum_topic[title]': { 51342 required: true, 51343 onlyLatinSymbols: true, 51344 noEmoji: true 51345 }, 51346 'forum_topic[content]': { 51347 required: true, 51348 noEmoji: true 51349 } 51350 }, 51351 errorPlacement: function(error, element) { 51352 switch (element.attr('name')) { 51353 case 'forum_topic[board_id]': 51354 return error.insertAfter('#forum_topic_board_id_chosen'); 51355 case 'forum_topic[content]': 51356 return error.insertAfter('.redactor_box'); 51357 default: 51358 return error.insertAfter(element); 51359 } 51360 } 51361 }; 51362 }; 51363 51364 TopicsNew.prototype.initValidation = function() { 51365 return this.$form.validate(this.validationSettings()); 51366 }; 51367 51368 return TopicsNew; 51369 51370 })(App.Core.Page); 51371 51372}).call(this); 51373(function() { 51374 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 51375 hasProp = {}.hasOwnProperty; 51376 51377 App.Pages.Forum.TopicsEdit = (function(superClass) { 51378 extend(TopicsEdit, superClass); 51379 51380 function TopicsEdit() { 51381 return TopicsEdit.__super__.constructor.apply(this, arguments); 51382 } 51383 51384 TopicsEdit.prototype.getForm = function() { 51385 return $('.edit_forum_topic'); 51386 }; 51387 51388 return TopicsEdit; 51389 51390 })(App.Pages.Forum.TopicsNew); 51391 51392}).call(this); 51393(function() { 51394 var base, 51395 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 51396 hasProp = {}.hasOwnProperty; 51397 51398 if ((base = App.Pages).Forum == null) { 51399 base.Forum = {}; 51400 } 51401 51402 App.Pages.Forum.TopicsShow = (function(superClass) { 51403 extend(TopicsShow, superClass); 51404 51405 function TopicsShow() { 51406 return TopicsShow.__super__.constructor.apply(this, arguments); 51407 } 51408 51409 TopicsShow.prototype.initialize = function() { 51410 this.$newForumPostForm = $('#new_forum_post'); 51411 this.initComments(); 51412 this.bindEvents(); 51413 return this.initValidation(); 51414 }; 51415 51416 TopicsShow.prototype.initComments = function() { 51417 return $('.comments').each(function() { 51418 var widget; 51419 widget = new App.Widgets.Comments({ 51420 el: $(this), 51421 placement: 'append' 51422 }); 51423 widget.initialize(); 51424 return $(this).find('.comment-form-container').addClass('is-hidden'); 51425 }); 51426 }; 51427 51428 TopicsShow.prototype.bindEvents = function() { 51429 $('.js-delete-answer').each((function(_this) { 51430 return function(index, el) { 51431 return $(el).on('click', _this.onDeleteClick); 51432 }; 51433 })(this)); 51434 $('.js-reply-to-answer').each((function(_this) { 51435 return function(index, el) { 51436 return $(el).on('click', _this.onReplyClick); 51437 }; 51438 })(this)); 51439 $('.js-reply-to-topic').on('click', this.onReplyToTopicClick); 51440 this.$newForumPostForm.submit(function() { 51441 if ($('#new_forum_post').valid()) { 51442 $('.js-disable-answer-button').attr('disabled', true); 51443 } 51444 return true; 51445 }); 51446 $('.vote-block a').on('ajax:before', this.onVoteBefore); 51447 return $('.vote-block a').on('ajax:success', this.onVoteSuccess); 51448 }; 51449 51450 TopicsShow.prototype.onDeleteClick = function(e) { 51451 var $el; 51452 $el = $(e.currentTarget).parents('.forum-answer'); 51453 return $.ajax({ 51454 url: "/forum/posts/" + $el[0].id, 51455 type: 'DELETE', 51456 success: function() { 51457 return $el.remove(); 51458 } 51459 }); 51460 }; 51461 51462 TopicsShow.prototype.onReplyClick = function(e) { 51463 var $el, $form; 51464 $el = $(e.currentTarget).parents('.forum-answer').find('.comments'); 51465 $form = $el.find('.comment-form-container'); 51466 $form.removeClass('is-hidden'); 51467 return $('body, html').stop(true, true).animate({ 51468 scrollTop: $form.offset().top + $form.height() - $(window).height() 51469 }, 300); 51470 }; 51471 51472 TopicsShow.prototype.onReplyToTopicClick = function(e) { 51473 return App.events.publish('app:element:focus', $('#forum-answer-form')); 51474 }; 51475 51476 TopicsShow.prototype.onVoteBefore = function(e) { 51477 var $block, $this; 51478 $this = $(e.currentTarget); 51479 if ($this.data('disabled')) { 51480 return false;
51481 } 51482 $block = $this.parents('.vote-block'); 51483 return $block.find('.vote-block__action a').data('disabled', true); 51484 }; 51485 51486 TopicsShow.prototype.onVoteSuccess = function(e) { 51487 var $block, $this, score, value; 51488 $this = $(e.currentTarget); 51489 $this.parent().addClass('is-active'); 51490 $block = $this.parents('.vote-block'); 51491 value = parseInt($this.data('value'), 10); 51492 score = parseInt($block.find('.vote-block__score').text(), 10); 51493 $block.addClass('is-voted'); 51494 $block.find('.vote-block__action a').data('disabled', true); 51495 return $block.find('.vote-block__score').text(score + value); 51496 }; 51497 51498 TopicsShow.prototype.validationSettings = function() { 51499 return { 51500 ignore: [], 51501 rules: { 51502 'forum_post[content]': { 51503 noEmoji: true 51504 } 51505 } 51506 }; 51507 }; 51508 51509 TopicsShow.prototype.initValidation = function() { 51510 return this.$newForumPostForm.validate(this.validationSettings()); 51511 }; 51512 51513 return TopicsShow; 51514 51515 })(App.Core.Page); 51516 51517}).call(this); 51518/*! 51519 * Masonry PACKAGED v3.1.5 51520 * Cascading grid layout library 51521 * http://masonry.desandro.com 51522 * MIT License 51523 * by David DeSandro 51524 */ 51525 51526/** 51527 * Bridget makes jQuery widgets 51528 * v1.0.1 51529 */ 51530 51531 51532( function( window ) { 51533 51534 51535 51536// -------------------------- utils -------------------------- // 51537 51538var slice = Array.prototype.slice; 51539 51540function noop() {} 51541 51542// -------------------------- definition -------------------------- // 51543 51544function defineBridget( $ ) { 51545 51546// bail if no jQuery 51547if ( !$ ) { 51548 return; 51549} 51550 51551// -------------------------- addOptionMethod -------------------------- // 51552 51553/** 51554 * adds option method -> $().plugin('option', {...}) 51555 * @param {Function} PluginClass - constructor class 51556 */ 51557function addOptionMethod( PluginClass ) { 51558 // don't overwrite original option method 51559 if ( PluginClass.prototype.option ) { 51560 return; 51561 } 51562 51563 // option setter 51564 PluginClass.prototype.option = function( opts ) { 51565 // bail out if not an object 51566 if ( !$.isPlainObject( opts ) ){ 51567 return; 51568 } 51569 this.options = $.extend( true, this.options, opts ); 51570 }; 51571} 51572 51573 51574// -------------------------- plugin bridge -------------------------- // 51575 51576// helper function for logging errors 51577// $.error breaks jQuery chaining 51578var logError = typeof console === 'undefined' ? noop : 51579 function( message ) { 51580 console.error( message ); 51581 }; 51582 51583/** 51584 * jQuery plugin bridge, access methods like $elem.plugin('method') 51585 * @param {String} namespace - plugin name 51586 * @param {Function} PluginClass - constructor class 51587 */ 51588function bridge( namespace, PluginClass ) { 51589 // add to jQuery fn namespace 51590 $.fn[ namespace ] = function( options ) { 51591 if ( typeof options === 'string' ) { 51592 // call plugin method when first argument is a string 51593 // get arguments for method 51594 var args = slice.call( arguments, 1 ); 51595 51596 for ( var i=0, len = this.length; i < len; i++ ) { 51597 var elem = this[i]; 51598 var instance = $.data( elem, namespace ); 51599 if ( !instance ) { 51600 logError( "cannot call methods on " + namespace + " prior to initialization; " + 51601 "attempted to call '" + options + "'" ); 51602 continue; 51603 } 51604 if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) { 51605 logError( "no such method '" + options + "' for " + namespace + " instance" ); 51606 continue; 51607 } 51608 51609 // trigger method with arguments 51610 var returnValue = instance[ options ].apply( instance, args ); 51611 51612 // break look and return first value if provided 51613 if ( returnValue !== undefined ) { 51614 return returnValue; 51615 } 51616 } 51617 // return this if no return value 51618 return this; 51619 } else { 51620 return this.each( function() { 51621 var instance = $.data( this, namespace ); 51622 if ( instance ) { 51623 // apply options & init 51624 instance.option( options ); 51625 instance._init(); 51626 } else { 51627 // initialize new instance 51628 instance = new PluginClass( this, options ); 51629 $.data( this, namespace, instance ); 51630 } 51631 }); 51632 } 51633 }; 51634 51635} 51636 51637// -------------------------- bridget -------------------------- // 51638 51639/** 51640 * converts a Prototypical class into a proper jQuery plugin 51641 * the class must have a ._init method 51642 * @param {String} namespace - plugin name, used in $().pluginName 51643 * @param {Function} PluginClass - constructor class 51644 */ 51645$.bridget = function( namespace, PluginClass ) { 51646 addOptionMethod( PluginClass ); 51647 bridge( namespace, PluginClass ); 51648}; 51649 51650return $.bridget; 51651 51652} 51653 51654// transport 51655if ( typeof define === 'function' && define.amd ) { 51656 // AMD 51657 define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget ); 51658} else { 51659 // get jquery from browser global 51660 defineBridget( window.jQuery ); 51661} 51662 51663})( window ); 51664 51665/*! 51666 * eventie v1.0.5 51667 * event binding helper 51668 * eventie.bind( elem, 'click', myFn ) 51669 * eventie.unbind( elem, 'click', myFn ) 51670 * MIT license 51671 */ 51672 51673/*jshint browser: true, undef: true, unused: true */ 51674/*global define: false, module: false */ 51675 51676( function( window ) { 51677 51678 51679 51680var docElem = document.documentElement; 51681 51682var bind = function() {}; 51683 51684function getIEEvent( obj ) { 51685 var event = window.event; 51686 // add event.target 51687 event.target = event.target || event.srcElement || obj; 51688 return event; 51689} 51690 51691if ( docElem.addEventListener ) { 51692 bind = function( obj, type, fn ) { 51693 obj.addEventListener( type, fn, false ); 51694 }; 51695} else if ( docElem.attachEvent ) { 51696 bind = function( obj, type, fn ) { 51697 obj[ type + fn ] = fn.handleEvent ? 51698 function() { 51699 var event = getIEEvent( obj ); 51700 fn.handleEvent.call( fn, event ); 51701 } : 51702 function() { 51703 var event = getIEEvent( obj ); 51704 fn.call( obj, event ); 51705 }; 51706 obj.attachEvent( "on" + type, obj[ type + fn ] ); 51707 }; 51708} 51709 51710var unbind = function() {}; 51711 51712if ( docElem.removeEventListener ) { 51713 unbind = function( obj, type, fn ) { 51714 obj.removeEventListener( type, fn, false ); 51715 }; 51716} else if ( docElem.detachEvent ) { 51717 unbind = function( obj, type, fn ) { 51718 obj.detachEvent( "on" + type, obj[ type + fn ] ); 51719 try { 51720 delete obj[ type + fn ]; 51721 } catch ( err ) { 51722 // can't delete window object properties 51723 obj[ type + fn ] = undefined; 51724 } 51725 }; 51726} 51727 51728var eventie = { 51729 bind: bind, 51730 unbind: unbind 51731}; 51732 51733// ----- module definition ----- // 51734 51735if ( typeof define === 'function' && define.amd ) { 51736 // AMD 51737 define( 'eventie/eventie',eventie ); 51738} else if ( typeof exports === 'object' ) { 51739 // CommonJS 51740 module.exports = eventie; 51741} else { 51742 // browser global 51743 window.eventie = eventie; 51744} 51745 51746})( this ); 51747 51748/*! 51749 * docReady 51750 * Cross browser DOMContentLoaded event emitter 51751 */ 51752 51753/*jshint browser: true, strict: true, undef: true, unused: true*/ 51754/*global define: false */ 51755 51756( function( window ) { 51757 51758 51759 51760var document = window.document; 51761// collection of functions to be triggered on ready 51762var queue = []; 51763 51764function docReady( fn ) { 51765 // throw out non-functions 51766 if ( typeof fn !== 'function' ) { 51767 return; 51768 } 51769 51770 if ( docReady.isReady ) { 51771 // ready now, hit it 51772 fn(); 51773 } else { 51774 // queue function when ready 51775 queue.push( fn ); 51776 } 51777} 51778 51779docReady.isReady = false;
51780 51781// triggered on various doc ready events 51782function init( event ) { 51783 // bail if IE8 document is not ready just yet 51784 var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete'; 51785 if ( docReady.isReady || isIE8NotReady ) { 51786 return; 51787 } 51788 docReady.isReady = true; 51789 51790 // process queue 51791 for ( var i=0, len = queue.length; i < len; i++ ) { 51792 var fn = queue[i]; 51793 fn(); 51794 } 51795} 51796 51797function defineDocReady( eventie ) { 51798 eventie.bind( document, 'DOMContentLoaded', init ); 51799 eventie.bind( document, 'readystatechange', init ); 51800 eventie.bind( window, 'load', init ); 51801 51802 return docReady; 51803} 51804 51805// transport 51806if ( typeof define === 'function' && define.amd ) { 51807 // AMD 51808 // if RequireJS, then doc is already ready 51809 docReady.isReady = typeof requirejs === 'function'; 51810 define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady ); 51811} else { 51812 // browser global 51813 window.docReady = defineDocReady( window.eventie ); 51814} 51815 51816})( this ); 51817 51818/*! 51819 * EventEmitter v4.2.7 - git.io/ee 51820 * Oliver Caldwell 51821 * MIT license 51822 * @preserve 51823 */ 51824 51825(function () { 51826 51827 51828 /** 51829 * Class for managing events. 51830 * Can be extended to provide event functionality in other classes. 51831 * 51832 * @class EventEmitter Manages event registering and emitting. 51833 */ 51834 function EventEmitter() {} 51835 51836 // Shortcuts to improve speed and size 51837 var proto = EventEmitter.prototype; 51838 var exports = this; 51839 var originalGlobalValue = exports.EventEmitter; 51840 51841 /** 51842 * Finds the index of the listener for the event in it's storage array. 51843 * 51844 * @param {Function[]} listeners Array of listeners to search through. 51845 * @param {Function} listener Method to look for. 51846 * @return {Number} Index of the specified listener, -1 if not found 51847 * @api private 51848 */ 51849 function indexOfListener(listeners, listener) { 51850 var i = listeners.length; 51851 while (i--) { 51852 if (listeners[i].listener === listener) { 51853 return i; 51854 } 51855 } 51856 51857 return -1; 51858 } 51859 51860 /** 51861 * Alias a method while keeping the context correct, to allow for overwriting of target method. 51862 * 51863 * @param {String} name The name of the target method. 51864 * @return {Function} The aliased method 51865 * @api private 51866 */ 51867 function alias(name) { 51868 return function aliasClosure() { 51869 return this[name].apply(this, arguments); 51870 }; 51871 } 51872 51873 /** 51874 * Returns the listener array for the specified event. 51875 * Will initialise the event object and listener arrays if required. 51876 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object c
51876ontaining bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 51877 * Each property in the object response is an array of listener functions. 51878 * 51879 * @param {String|RegExp} evt Name of the event to return the listeners from. 51880 * @return {Function[]|Object} All listener functions for the event. 51881 */ 51882 proto.getListeners = function getListeners(evt) { 51883 var events = this._getEvents(); 51884 var response; 51885 var key; 51886 51887 // Return a concatenated array of all matching events if 51888 // the selector is a regular expression. 51889 if (evt instanceof RegExp) { 51890 response = {}; 51891 for (key in events) { 51892 if (events.hasOwnProperty(key) && evt.test(key)) { 51893 response[key] = events[key]; 51894 } 51895 } 51896 } 51897 else { 51898 response = events[evt] || (events[evt] = []); 51899 } 51900 51901 return response; 51902 }; 51903 51904 /** 51905 * Takes a list of listener objects and flattens it into a list of listener functions. 51906 * 51907 * @param {Object[]} listeners Raw listener objects. 51908 * @return {Function[]} Just the listener functions. 51909 */ 51910 proto.flattenListeners = function flattenListeners(listeners) { 51911 var flatListeners = []; 51912 var i; 51913 51914 for (i = 0; i < listeners.length; i += 1) { 51915 flatListeners.push(listeners[i].listener); 51916 } 51917 51918 return flatListeners; 51919 }; 51920 51921 /** 51922 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. 51923 * 51924 * @param {String|RegExp} evt Name of the event to return the listeners from. 51925 * @return {Object} All listener functions for an event in an object. 51926 */ 51927 proto.getListenersAsObject = function getListenersAsObject(evt) { 51928 var listeners = this.getListeners(evt); 51929 var response; 51930 51931 if (listeners instanceof Array) { 51932 response = {}; 51933 response[evt] = listeners; 51934 } 51935 51936 return response || listeners; 51937 }; 51938 51939 /** 51940 * Adds a listener function to the specified event. 51941 * The listener will not be added if it is a duplicate. 51942 * If the listener returns true then it will be removed after it is called. 51943 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 51944 * 51945 * @param {String|RegExp} evt Name of the event to attach the listener to. 51946 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 51947 * @return {Object} Current instance of EventEmitter for chaining. 51948 */ 51949 proto.addListener = function addListener(evt, listener) { 51950 var listeners = this.getListenersAsObject(evt); 51951 var listenerIsWrapped = typeof listener === 'object'; 51952 var key; 51953 51954 for (key in listeners) { 51955 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 51956 listeners[key].push(listenerIsWrapped ? listener : { 51957 listener: listener, 51958 once: false 51959 }); 51960 } 51961 } 51962 51963 return this; 51964 }; 51965 51966 /** 51967 * Alias of addListener 51968 */ 51969 proto.on = alias('addListener'); 51970 51971 /** 51972 * Semi-alias of addListener. It will add a listener that will be 51973 * automatically removed after it's first execution. 51974 * 51975 * @param {String|RegExp} evt Name of the event to attach the listener to. 51976 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 51977 * @return {Object} Current instance of EventEmitter for chaining. 51978 */ 51979 proto.addOnceListener = function addOnceListener(evt, listener) { 51980 return this.addListener(evt, { 51981 listener: listener, 51982 once: true 51983 }); 51984 }; 51985 51986 /** 51987 * Alias of addOnceListener. 51988 */ 51989 proto.once = alias('addOnceListener'); 51990 51991 /** 51992 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. 51993 * You need to tell it what event names should be matched by a regex. 51994 * 51995 * @param {String} evt Name of the event to create. 51996 * @return {Object} Current instance of EventEmitter for chaining. 51997 */ 51998 proto.defineEvent = function defineEvent(evt) { 51999 this.getListeners(evt); 52000 return this; 52001 }; 52002 52003 /** 52004 * Uses defineEvent to define multiple events. 52005 * 52006 * @param {String[]} evts An array of event names to define. 52007 * @return {Object} Current instance of EventEmitter for chaining. 52008 */ 52009 proto.defineEvents = function defineEvents(evts) { 52010 for (var i = 0; i < evts.length; i += 1) { 52011 this.defineEvent(evts[i]); 52012 } 52013 return this; 52014 }; 52015 52016 /** 52017 * Removes a listener function from the specified event. 52018 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 52019 * 52020 * @param {String|RegExp} evt Name of the event to remove the listener from. 52021 * @param {Function} listener Method to remove from the event. 52022 * @return {Object} Current instance of EventEmitter for chaining. 52023 */ 52024 proto.removeListener = function removeListener(evt, listener) { 52025 var listeners = this.getListenersAsObject(evt); 52026 var index; 52027 var key; 52028 52029 for (key in listeners) { 52030 if (listeners.hasOwnProperty(key)) { 52031 index = indexOfListener(listeners[key], listener); 52032 52033 if (index !== -1) { 52034 listeners[key].splice(index, 1); 52035 } 52036 } 52037 } 52038 52039 return this; 52040 }; 52041 52042 /** 52043 * Alias of removeListener 52044 */ 52045 proto.off = alias('removeListener'); 52046 52047 /** 52048 * Adds listeners in bulk using the manipulateListeners method. 52049 * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. 52050 * You can also pass it a regular expression to add the array of listeners to all events that match it. 52051 * Yeah, this function does quite a bit. That's probably a bad thing. 52052 * 52053 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. 52054 * @param {Function[]} [listeners] An optional array of listener functions to add. 52055 * @return {Object} Current instance of EventEmitter for chaining. 52056 */ 52057 proto.addListeners = function addListeners(evt, listeners) { 52058 // Pass through to manipulateListeners 52059 return this.manipulateListeners(false, evt, listeners); 52060 }; 52061 52062 /** 52063 * Removes listeners in bulk using the manipulateListeners method. 52064 * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 52065 * You can also pass it an event name and an array of listeners to be removed. 52066 * You can also pass it a regular expression to remove the listeners from all events that match it. 52067 * 52068 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. 52069 * @param {Function[]} [listeners] An optional array of listener functions to remove. 52070 * @return {Object} Current instance of EventEmitter for chaining. 52071 */ 52072 proto.removeListeners = function removeListeners(evt, listeners) { 52073 // Pass through to manipulateListeners 52074 return this.manipulateListeners(true, evt, listeners); 52075 }; 52076 52077 /** 52078 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. 52079 * The first argument will determine if the listeners are removed (true) or added (false). 52080 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 52081 * You can also pass it an event name and an array of listeners to be added/removed. 52082 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 52083 * 52084 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 52085 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. 52086 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 52087 * @return {Object} Current instance of EventEmitter for chaining. 52088 */ 52089 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 52090 var i; 52091 var value; 52092 var single = remove ? this.removeListener : this.addListener; 52093 var multiple = remove ? this.removeListeners : this.addListeners; 52094 52095 // If evt is an object then pass each of it's properties to this method 52096 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 52097 for (i in evt) { 52098 if (evt.hasOwnProperty(i) && (value = evt[i])) { 52099 // Pass the single listener straight through to the singular method 52100 if (typeof value === 'function') { 52101 single.call(this, i, value); 52102 } 52103 else { 52104 // Otherwise pass back to the multiple function 52105 multiple.call(this, i, value); 52106 } 52107 } 52108 } 52109 } 52110 else { 52111 // So evt must be a string 52112 // And listeners must be an array of listeners 52113 // Loop over it and pass each one to the multiple method 52114 i = listeners.length; 52115 while (i--) { 52116 single.call(this, evt, listeners[i]); 52117 } 52118 } 52119 52120 return this; 52121 }; 52122 52123 /** 52124 * Removes all listeners from a specified event. 52125 * If you do not specify an event then all listeners will be removed. 52126 * That means every event will be emptied. 52127 * You can also pass a regex to remove all events that match it. 52128 * 52129 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 52130 * @return {Object} Current instance of EventEmitter for chaining. 52131 */ 52132 proto.removeEvent = function removeEvent(evt) { 52133 var type = typeof evt; 52134 var events = this._getEvents(); 52135 var key; 52136 52137 // Remove different things depending on the state of evt 52138 if (type === 'string') { 52139 // Remove all listeners for the specified event 52140 delete events[evt]; 52141 } 52142 else if (evt instanceof RegExp) { 52143 // Remove all events matching the regex. 52144 for (key in events) { 52145 if (events.hasOwnProperty(key) && evt.test(key)) { 52146 delete events[key]; 52147 } 52148 } 52149 } 52150 else { 52151 // Remove all listeners in all events 52152 delete this._events; 52153 } 52154 52155 return this; 52156 }; 52157 52158 /** 52159 * Alias of removeEvent. 52160 * 52161 * Added to mirror the node API. 52162 */ 52163 proto.removeAllListeners = alias('removeEvent'); 52164 52165 /** 52166 * Emits an event of your choice. 52167 * When emitted, every listener attached to that event will be executed. 52168 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 52169 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
52170 * So they will not arrive within the array on the other side, they will be separate. 52171 * You can also pass a regular expression to emit to all events that match it. 52172 * 52173 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 52174 * @param {Array} [args] Optional array of arguments to be passed to each listener. 52175 * @return {Object} Current instance of EventEmitter for chaining. 52176 */ 52177 proto.emitEvent = function emitEvent(evt, args) { 52178 var listeners = this.getListenersAsObject(evt); 52179 var listener; 52180 var i; 52181 var key; 52182 var response; 52183 52184 for (key in listeners) { 52185 if (listeners.hasOwnProperty(key)) { 52186 i = listeners[key].length; 52187 52188 while (i--) { 52189 // If the listener returns true then it shall be removed from the event 52190 // The function is executed either with a basic call or an apply if there is an args array 52191 listener = listeners[key][i]; 52192 52193 if (listener.once === true) { 52194 this.removeListener(evt, listener.listener); 52195 } 52196 52197 response = listener.listener.apply(this, args || []); 52198 52199 if (response === this._getOnceReturnValue()) { 52200 this.removeListener(evt, listener.listener); 52201 } 52202 } 52203 } 52204 } 52205 52206 return this; 52207 }; 52208 52209 /** 52210 * Alias of emitEvent 52211 */ 52212 proto.trigger = alias('emitEvent'); 52213 52214 /** 52215 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. 52216 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 52217 * 52218 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 52219 * @param {...*} Optional additional arguments to be passed to each listener. 52220 * @return {Object} Current instance of EventEmitter for chaining. 52221 */ 52222 proto.emit = function emit(evt) { 52223 var args = Array.prototype.slice.call(arguments, 1); 52224 return this.emitEvent(evt, args); 52225 }; 52226 52227 /** 52228 * Sets the current value to check against when executing listeners. If a 52229 * listeners return value matches the one set here then it will be removed 52230 * after execution. This value defaults to true. 52231 * 52232 * @param {*} value The new value to check for when executing listeners. 52233 * @return {Object} Current instance of EventEmitter for chaining. 52234 */ 52235 proto.setOnceReturnValue = function setOnceReturnValue(value) { 52236 this._onceReturnValue = value; 52237 return this; 52238 }; 52239 52240 /** 52241 * Fetches the current value to check against when executing listeners. If 52242 * the listeners return value matches this one then it should be removed 52243 * automatically. It will return true by default. 52244 * 52245 * @return {*|Boolean} The current value to check for or the default, true. 52246 * @api private 52247 */ 52248 proto._getOnceReturnValue = function _getOnceReturnValue() { 52249 if (this.hasOwnProperty('_onceReturnValue')) { 52250 return this._onceReturnValue; 52251 } 52252 else { 52253 return true; 52254 } 52255 }; 52256 52257 /** 52258 * Fetches the events object and creates one if required. 52259 * 52260 * @return {Object} The events storage object. 52261 * @api private 52262 */ 52263 proto._getEvents = function _getEvents() { 52264 return this._events || (this._events = {}); 52265 }; 52266 52267 /** 52268 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 52269 * 52270 * @return {Function} Non conflicting EventEmitter class. 52271 */ 52272 EventEmitter.noConflict = function noConflict() { 52273 exports.EventEmitter = originalGlobalValue; 52274 return EventEmitter; 52275 }; 52276 52277 // Expose the class either via AMD, CommonJS or the global object 52278 if (typeof define === 'function' && define.amd) { 52279 define('eventEmitter/EventEmitter',[],function () { 52280 return EventEmitter; 52281 }); 52282 } 52283 else if (typeof module === 'object' && module.exports){ 52284 module.exports = EventEmitter; 52285 } 52286 else { 52287 this.EventEmitter = EventEmitter; 52288 } 52289}.call(this)); 52290 52291/*! 52292 * getStyleProperty v1.0.3 52293 * original by kangax 52294 * http://perfectionkills.com/feature-testing-css-properties/ 52295 */ 52296 52297/*jshint browser: true, strict: true, undef: true */ 52298/*global define: false, exports: false, module: false */ 52299 52300( function( window ) { 52301 52302 52303 52304var prefixes = 'Webkit Moz ms Ms O'.split(' '); 52305var docElemStyle = document.documentElement.style; 52306 52307function getStyleProperty( propName ) { 52308 if ( !propName ) { 52309 return; 52310 } 52311 52312 // test standard property first 52313 if ( typeof docElemStyle[ propName ] === 'string' ) { 52314 return propName; 52315 } 52316 52317 // capitalize 52318 propName = propName.charAt(0).toUpperCase() + propName.slice(1); 52319 52320 // test vendor specific properties 52321 var prefixed; 52322 for ( var i=0, len = prefixes.length; i < len; i++ ) { 52323 prefixed = prefixes[i] + propName; 52324 if ( typeof docElemStyle[ prefixed ] === 'string' ) { 52325 return prefixed; 52326 } 52327 } 52328} 52329 52330// transport 52331if ( typeof define === 'function' && define.amd ) { 52332 // AMD 52333 define( 'get-style-property/get-style-property',[],function() { 52334 return getStyleProperty; 52335 }); 52336} else if ( typeof exports === 'object' ) { 52337 // CommonJS for Component 52338 module.exports = getStyleProperty; 52339} else { 52340 // browser global 52341 window.getStyleProperty = getStyleProperty; 52342} 52343 52344})( window ); 52345 52346/** 52347 * getSize v1.1.7 52348 * measure size of elements 52349 */ 52350
52351/*jshint browser: true, strict: true, undef: true, unused: true */ 52352/*global define: false, exports: false, require: false, module: false */ 52353 52354( function( window, undefined ) { 52355 52356 52357 52358// -------------------------- helpers -------------------------- // 52359 52360var getComputedStyle = window.getComputedStyle; 52361var getStyle = getComputedStyle ? 52362 function( elem ) { 52363 return getComputedStyle( elem, null ); 52364 } : 52365 function( elem ) { 52366 return elem.currentStyle; 52367 }; 52368 52369// get a number from a string, not a percentage 52370function getStyleSize( value ) { 52371 var num = parseFloat( value ); 52372 // not a percent like '100%', and a number 52373 var isValid = value.indexOf('%') === -1 && !isNaN( num ); 52374 return isValid && num; 52375} 52376 52377// -------------------------- measurements -------------------------- // 52378 52379var measurements = [ 52380 'paddingLeft', 52381 'paddingRight', 52382 'paddingTop', 52383 'paddingBottom', 52384 'marginLeft', 52385 'marginRight', 52386 'marginTop', 52387 'marginBottom', 52388 'borderLeftWidth', 52389 'borderRightWidth', 52390 'borderTopWidth', 52391 'borderBottomWidth' 52392]; 52393 52394function getZeroSize() { 52395 var size = { 52396 width: 0, 52397 height: 0, 52398 innerWidth: 0, 52399 innerHeight: 0, 52400 outerWidth: 0, 52401 outerHeight: 0 52402 }; 52403 for ( var i=0, len = measurements.length; i < len; i++ ) { 52404 var measurement = measurements[i]; 52405 size[ measurement ] = 0; 52406 } 52407 return size; 52408} 52409 52410 52411 52412function defineGetSize( getStyleProperty ) { 52413 52414// -------------------------- box sizing -------------------------- // 52415 52416var boxSizingProp = getStyleProperty('boxSizing'); 52417var isBoxSizeOuter; 52418 52419/** 52420 * WebKit measures the outer-width on style.width on border-box elems 52421 * IE & Firefox measures the inner-width 52422 */ 52423( function() { 52424 if ( !boxSizingProp ) { 52425 return; 52426 } 52427 52428 var div = document.createElement('div'); 52429 div.style.width = '200px'; 52430 div.style.padding = '1px 2px 3px 4px'; 52431 div.style.borderStyle = 'solid'; 52432 div.style.borderWidth = '1px 2px 3px 4px'; 52433 div.style[ boxSizingProp ] = 'border-box'; 52434 52435 var body = document.body || document.documentElement; 52436 body.appendChild( div ); 52437 var style = getStyle( div ); 52438 52439 isBoxSizeOuter = getStyleSize( style.width ) === 200; 52440 body.removeChild( div ); 52441})(); 52442 52443 52444// -------------------------- getSize -------------------------- // 52445 52446function getSize( elem ) { 52447 // use querySeletor if elem is string 52448 if ( typeof elem === 'string' ) { 52449 elem = document.querySelector( elem ); 52450 } 52451 52452 // do not proceed on non-objects 52453 if ( !elem || typeof elem !== 'object' || !elem.nodeType ) { 52454 return; 52455 } 52456 52457 var style = getStyle( elem ); 52458 52459 // if hidden, everything is 0 52460 if ( style.display === 'none' ) { 52461 return getZeroSize(); 52462 } 52463 52464 var size = {}; 52465 size.width = elem.offsetWidth; 52466 size.height = elem.offsetHeight; 52467 52468 var isBorderBox = size.isBorderBox = !!( boxSizingProp && 52469 style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' ); 52470 52471 // get all measurements 52472 for ( var i=0, len = measurements.length; i < len; i++ ) { 52473 var measurement = measurements[i]; 52474 var value = style[ measurement ]; 52475 value = mungeNonPixel( elem, value ); 52476 var num = parseFloat( value ); 52477 // any 'auto', 'medium' value will be 0 52478 size[ measurement ] = !isNaN( num ) ? num : 0; 52479 } 52480 52481 var paddingWidth = size.paddingLeft + size.paddingRight; 52482 var paddingHeight = size.paddingTop + size.paddingBottom; 52483 var marginWidth = size.marginLeft + size.marginRight; 52484 var marginHeight = size.marginTop + size.marginBottom; 52485 var borderWidth = size.borderLeftWidth + size.borderRightWidth; 52486 var borderHeight = size.borderTopWidth + size.borderBottomWidth; 52487 52488 var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 52489 52490 // overwrite width and height if we can get it from style 52491 var styleWidth = getStyleSize( style.width ); 52492 if ( styleWidth !== false ) { 52493 size.width = styleWidth + 52494 // add padding and border unless it's already including it 52495 ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 52496 } 52497 52498 var styleHeight = getStyleSize( style.height ); 52499 if ( styleHeight !== false ) { 52500 size.height = styleHeight + 52501 // add padding and border unless it's already including it 52502 ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 52503 } 52504 52505 size.innerWidth = size.width - ( paddingWidth + borderWidth );
52506 size.innerHeight = size.height - ( paddingHeight + borderHeight ); 52507 52508 size.outerWidth = size.width + marginWidth; 52509 size.outerHeight = size.height + marginHeight; 52510 52511 return size; 52512} 52513 52514// IE8 returns percent values, not pixels 52515// taken from jQuery's curCSS 52516function mungeNonPixel( elem, value ) { 52517 // IE8 and has percent value 52518 if ( getComputedStyle || value.indexOf('%') === -1 ) { 52519 return value; 52520 } 52521 var style = elem.style; 52522 // Remember the original values 52523 var left = style.left; 52524 var rs = elem.runtimeStyle; 52525 var rsLeft = rs && rs.left; 52526 52527 // Put in the new values to get a computed value out 52528 if ( rsLeft ) { 52529 rs.left = elem.currentStyle.left; 52530 } 52531 style.left = value; 52532 value = style.pixelLeft; 52533 52534 // Revert the changed values 52535 style.left = left; 52536 if ( rsLeft ) { 52537 rs.left = rsLeft; 52538 } 52539 52540 return value; 52541} 52542 52543return getSize; 52544 52545} 52546 52547// transport 52548if ( typeof define === 'function' && define.amd ) { 52549 // AMD for RequireJS 52550 define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize ); 52551} else if ( typeof exports === 'object' ) { 52552 // CommonJS for Component 52553 module.exports = defineGetSize( require('get-style-property') ); 52554} else { 52555 // browser global 52556 window.getSize = defineGetSize( window.getStyleProperty ); 52557} 52558 52559})( window ); 52560 52561/** 52562 * matchesSelector helper v1.0.1 52563 * 52564 * @name matchesSelector 52565 * @param {Element} elem 52566 * @param {String} selector 52567 */ 52568 52569/*jshint browser: true, strict: true, undef: true, unused: true */ 52570/*global define: false */ 52571 52572( function( global, ElemProto ) { 52573 52574 52575 52576 var matchesMethod = ( function() { 52577 // check un-prefixed 52578 if ( ElemProto.matchesSelector ) { 52579 return 'matchesSelector'; 52580 } 52581 // check vendor prefixes 52582 var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 52583 52584 for ( var i=0, len = prefixes.length; i < len; i++ ) { 52585 var prefix = prefixes[i]; 52586 var method = prefix + 'MatchesSelector'; 52587 if ( ElemProto[ method ] ) { 52588 return method; 52589 } 52590 } 52591 })(); 52592 52593 // ----- match ----- // 52594 52595 function match( elem, selector ) { 52596 return elem[ matchesMethod ]( selector ); 52597 } 52598 52599 // ----- appendToFragment ----- // 52600 52601 function checkParent( elem ) { 52602 // not needed if already has parent 52603 if ( elem.parentNode ) { 52604 return; 52605 } 52606 var fragment = document.createDocumentFragment(); 52607 fragment.appendChild( elem ); 52608 } 52609 52610 // ----- query ----- // 52611 52612 // fall back to using QSA 52613 // thx @jonathantneal https://gist.github.com/3062955 52614 function query( elem, selector ) { 52615 // append to fragment if no parent 52616 checkParent( elem ); 52617 52618 // match elem with all selected elems of parent 52619 var elems = elem.parentNode.querySelectorAll( selector ); 52620 for ( var i=0, len = elems.length; i < len; i++ ) { 52621 // return true if match 52622 if ( elems[i] === elem ) { 52623 return true; 52624 } 52625 } 52626 // otherwise return false 52627 return false; 52628 } 52629 52630 // ----- matchChild ----- // 52631 52632 function matchChild( elem, selector ) { 52633 checkParent( elem ); 52634 return match( elem, selector ); 52635 } 52636 52637 // ----- matchesSelector ----- // 52638 52639 var matchesSelector; 52640 52641 if ( matchesMethod ) { 52642 // IE9 supports matchesSelector, but doesn't work on orphaned elems 52643 // check for that 52644 var div = document.createElement('div'); 52645 var supportsOrphans = match( div, 'div' ); 52646 matchesSelector = supportsOrphans ? match : matchChild; 52647 } else { 52648 matchesSelector = query; 52649 } 52650 52651 // transport 52652 if ( typeof define === 'function' && define.amd ) { 52653 // AMD 52654 define( 'matches-selector/matches-selector',[],function() { 52655 return matchesSelector; 52656 }); 52657 } else { 52658 // browser global 52659 window.matchesSelector = matchesSelector; 52660 } 52661 52662})( this, Element.prototype ); 52663 52664/** 52665 * Outlayer Item 52666 */ 52667 52668( function( window ) { 52669 52670 52671 52672// ----- get style ----- // 52673 52674var getComputedStyle = window.getComputedStyle; 52675var getStyle = getComputedStyle ? 52676 function( elem ) { 52677 return getComputedStyle( elem, null ); 52678 } : 52679 function( elem ) { 52680 return elem.currentStyle; 52681 }; 52682 52683 52684// extend objects 52685function extend( a, b ) { 52686 for ( var prop in b ) { 52687 a[ prop ] = b[ prop ]; 52688 } 52689 return a; 52690} 52691 52692function isEmptyObj( obj ) { 52693 for ( var prop in obj ) { 52694 return false;
52695 } 52696 prop = null; 52697 return true; 52698} 52699 52700// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 52701function toDash( str ) { 52702 return str.replace( /([A-Z])/g, function( $1 ){ 52703 return '-' + $1.toLowerCase(); 52704 }); 52705} 52706 52707// -------------------------- Outlayer definition -------------------------- // 52708 52709function outlayerItemDefinition( EventEmitter, getSize, getStyleProperty ) { 52710 52711// -------------------------- CSS3 support -------------------------- // 52712 52713var transitionProperty = getStyleProperty('transition'); 52714var transformProperty = getStyleProperty('transform'); 52715var supportsCSS3 = transitionProperty && transformProperty; 52716var is3d = !!getStyleProperty('perspective'); 52717 52718var transitionEndEvent = { 52719 WebkitTransition: 'webkitTransitionEnd', 52720 MozTransition: 'transitionend', 52721 OTransition: 'otransitionend', 52722 transition: 'transitionend' 52723}[ transitionProperty ]; 52724 52725// properties that could have vendor prefix 52726var prefixableProperties = [ 52727 'transform', 52728 'transition', 52729 'transitionDuration', 52730 'transitionProperty' 52731]; 52732 52733// cache all vendor properties 52734var vendorProperties = ( function() { 52735 var cache = {}; 52736 for ( var i=0, len = prefixableProperties.length; i < len; i++ ) { 52737 var prop = prefixableProperties[i]; 52738 var supportedProp = getStyleProperty( prop ); 52739 if ( supportedProp && supportedProp !== prop ) { 52740 cache[ prop ] = supportedProp; 52741 } 52742 } 52743 return cache; 52744})(); 52745 52746// -------------------------- Item -------------------------- // 52747 52748function Item( element, layout ) { 52749 if ( !element ) { 52750 return; 52751 } 52752 52753 this.element = element; 52754 // parent layout class, i.e. Masonry, Isotope, or Packery 52755 this.layout = layout; 52756 this.position = { 52757 x: 0, 52758 y: 0 52759 }; 52760 52761 this._create(); 52762} 52763 52764// inherit EventEmitter 52765extend( Item.prototype, EventEmitter.prototype ); 52766 52767Item.prototype._create = function() { 52768 // transition objects 52769 this._transn = { 52770 ingProperties: {}, 52771 clean: {}, 52772 onEnd: {} 52773 }; 52774 52775 this.css({ 52776 position: 'absolute' 52777 }); 52778}; 52779 52780// trigger specified handler for event type 52781Item.prototype.handleEvent = function( event ) { 52782 var method = 'on' + event.type; 52783 if ( this[ method ] ) { 52784 this[ method ]( event ); 52785 } 52786}; 52787 52788Item.prototype.getSize = function() { 52789 this.size = getSize( this.element ); 52790}; 52791 52792/** 52793 * apply CSS styles to element 52794 * @param {Object} style 52795 */ 52796Item.prototype.css = function( style ) { 52797 var elemStyle = this.element.style; 52798 52799 for ( var prop in style ) { 52800 // use vendor property if available 52801 var supportedProp = vendorProperties[ prop ] || prop; 52802 elemStyle[ supportedProp ] = style[ prop ]; 52803 } 52804}; 52805 52806 // measure position, and sets it 52807Item.prototype.getPosition = function() { 52808 var style = getStyle( this.element ); 52809 var layoutOptions = this.layout.options; 52810 var isOriginLeft = layoutOptions.isOriginLeft; 52811 var isOriginTop = layoutOptions.isOriginTop; 52812 var x = parseInt( style[ isOriginLeft ? 'left' : 'right' ], 10 ); 52813 var y = parseInt( style[ isOriginTop ? 'top' : 'bottom' ], 10 ); 52814 52815 // clean up 'auto' or other non-integer values 52816 x = isNaN( x ) ? 0 : x; 52817 y = isNaN( y ) ? 0 : y; 52818 // remove padding from measurement 52819 var layoutSize = this.layout.size; 52820 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 52821 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 52822 52823 this.position.x = x; 52824 this.position.y = y; 52825}; 52826 52827// set settled position, apply padding 52828Item.prototype.layoutPosition = function() { 52829 var layoutSize = this.layout.size; 52830 var layoutOptions = this.layout.options; 52831 var style = {}; 52832 52833 if ( layoutOptions.isOriginLeft ) { 52834 style.left = ( this.position.x + layoutSize.paddingLeft ) + 'px'; 52835 // reset other property 52836 style.right = ''; 52837 } else { 52838 style.right = ( this.position.x + layoutSize.paddingRight ) + 'px'; 52839 style.left = ''; 52840 } 52841 52842 if ( layoutOptions.isOriginTop ) { 52843 style.top = ( this.position.y + layoutSize.paddingTop ) + 'px'; 52844 style.bottom = ''; 52845 } else { 52846 style.bottom = ( this.position.y + layoutSize.paddingBottom ) + 'px'; 52847 style.top = ''; 52848 } 52849 52850 this.css( style ); 52851 this.emitEvent( 'layout', [ this ] ); 52852}; 52853 52854 52855// transform translate function 52856var translate = is3d ? 52857 function( x, y ) { 52858 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 52859 } : 52860 function( x, y ) { 52861 return 'translate(' + x + 'px, ' + y + 'px)'; 52862 }; 52863 52864
52865Item.prototype._transitionTo = function( x, y ) { 52866 this.getPosition(); 52867 // get current x & y from top/left 52868 var curX = this.position.x; 52869 var curY = this.position.y; 52870 52871 var compareX = parseInt( x, 10 ); 52872 var compareY = parseInt( y, 10 ); 52873 var didNotMove = compareX === this.position.x && compareY === this.position.y; 52874 52875 // save end position 52876 this.setPosition( x, y ); 52877 52878 // if did not move and not transitioning, just go to layout 52879 if ( didNotMove && !this.isTransitioning ) { 52880 this.layoutPosition(); 52881 return; 52882 } 52883 52884 var transX = x - curX; 52885 var transY = y - curY; 52886 var transitionStyle = {}; 52887 // flip cooridinates if origin on right or bottom 52888 var layoutOptions = this.layout.options; 52889 transX = layoutOptions.isOriginLeft ? transX : -transX; 52890 transY = layoutOptions.isOriginTop ? transY : -transY; 52891 transitionStyle.transform = translate( transX, transY ); 52892 52893 this.transition({ 52894 to: transitionStyle, 52895 onTransitionEnd: { 52896 transform: this.layoutPosition 52897 }, 52898 isCleaning: true 52899 }); 52900}; 52901 52902// non transition + transform support 52903Item.prototype.goTo = function( x, y ) { 52904 this.setPosition( x, y ); 52905 this.layoutPosition(); 52906}; 52907 52908// use transition and transforms if supported 52909Item.prototype.moveTo = supportsCSS3 ? 52910 Item.prototype._transitionTo : Item.prototype.goTo; 52911 52912Item.prototype.setPosition = function( x, y ) { 52913 this.position.x = parseInt( x, 10 ); 52914 this.position.y = parseInt( y, 10 ); 52915}; 52916 52917// ----- transition ----- // 52918 52919/** 52920 * @param {Object} style - CSS 52921 * @param {Function} onTransitionEnd 52922 */ 52923 52924// non transition, just trigger callback 52925Item.prototype._nonTransition = function( args ) { 52926 this.css( args.to ); 52927 if ( args.isCleaning ) { 52928 this._removeStyles( args.to ); 52929 } 52930 for ( var prop in args.onTransitionEnd ) { 52931 args.onTransitionEnd[ prop ].call( this ); 52932 } 52933}; 52934 52935/** 52936 * proper transition 52937 * @param {Object} args - arguments 52938 * @param {Object} to - style to transition to 52939 * @param {Object} from - style to start transition from 52940 * @param {Boolean} isCleaning - removes transition styles after transition 52941 * @param {Function} onTransitionEnd - callback 52942 */ 52943Item.prototype._transition = function( args ) { 52944 // redirect to nonTransition if no transition duration 52945 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 52946 this._nonTransition( args ); 52947 return; 52948 } 52949 52950 var _transition = this._transn; 52951 // keep track of onTransitionEnd callback by css property 52952 for ( var prop in args.onTransitionEnd ) { 52953 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 52954 } 52955 // keep track of properties that are transitioning 52956 for ( prop in args.to ) { 52957 _transition.ingProperties[ prop ] = true; 52958 // keep track of properties to clean up when transition is done 52959 if ( args.isCleaning ) { 52960 _transition.clean[ prop ] = true; 52961 } 52962 } 52963 52964 // set from styles 52965 if ( args.from ) { 52966 this.css( args.from ); 52967 // force redraw. http://blog.alexmaccaw.com/css-transitions 52968 var h = this.element.offsetHeight; 52969 // hack for JSHint to hush about unused var 52970 h = null; 52971 } 52972 // enable transition 52973 this.enableTransition( args.to ); 52974 // set styles that are transitioning 52975 this.css( args.to ); 52976 52977 this.isTransitioning = true; 52978 52979}; 52980 52981var itemTransitionProperties = transformProperty && ( toDash( transformProperty ) + 52982 ',opacity' ); 52983 52984Item.prototype.enableTransition = function(/* style */) { 52985 // only enable if not already transitioning 52986 // bug in IE10 were re-setting transition style will prevent 52987 // transitionend event from triggering 52988 if ( this.isTransitioning ) { 52989 return; 52990 } 52991 52992 // make transition: foo, bar, baz from style object 52993 // TODO uncomment this bit when IE10 bug is resolved 52994 // var transitionValue = []; 52995 // for ( var prop in style ) { 52996 // // dash-ify camelCased properties like WebkitTransition 52997 // transitionValue.push( toDash( prop ) ); 52998 // } 52999 // enable transition styles 53000 // HACK always enable transform,opacity for IE10 53001 this.css({ 53002 transitionProperty: itemTransitionProperties, 53003 transitionDuration: this.layout.options.transitionDuration 53004 }); 53005 // listen for transition end event 53006 this.element.addEventListener( transitionEndEvent, this, false ); 53007}; 53008 53009Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ]; 53010 53011// ----- events ----- // 53012 53013Item.prototype.onwebkitTransitionEnd = function( event ) { 53014 this.ontransitionend( event ); 53015}; 53016 53017Item.prototype.onotransitionend = function( event ) { 53018 this.ontransitionend( event ); 53019}; 53020 53021// properties that I munge to make my life easier 53022var dashedVendorProperties = { 53023 '-webkit-transform': 'transform', 53024 '-moz-transform': 'transform', 53025 '-o-transform': 'transform' 53026}; 53027 53028Item.prototype.ontransitionend = function( event ) { 53029 // disregard bubbled events from children 53030 if ( event.target !== this.element ) { 53031 return; 53032 } 53033 var _transition = this._transn; 53034 // get property name of transitioned property, convert to prefix-free 53035 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 53036 53037 // remove property that has completed transitioning 53038 delete _transition.ingProperties[ propertyName ]; 53039 // check if any properties are still transitioning 53040 if ( isEmptyObj( _transition.ingProperties ) ) { 53041 // all properties have completed transitioning 53042 this.disableTransition(); 53043 } 53044 // clean style 53045 if ( propertyName in _transition.clean ) { 53046 // clean up style 53047 this.element.style[ event.propertyName ] = ''; 53048 delete _transition.clean[ propertyName ]; 53049 } 53050 // trigger onTransitionEnd callback 53051 if ( propertyName in _transition.onEnd ) { 53052 var onTransitionEnd = _transition.onEnd[ propertyName ]; 53053 onTransitionEnd.call( this ); 53054 delete _transition.onEnd[ propertyName ]; 53055 } 53056 53057 this.emitEvent( 'transitionEnd', [ this ] ); 53058}; 53059 53060Item.prototype.disableTransition = function() { 53061 this.removeTransitionStyles(); 53062 this.element.removeEventListener( transitionEndEvent, this, false ); 53063 this.isTransitioning = false;
53064}; 53065 53066/** 53067 * removes style property from element 53068 * @param {Object} style 53069**/ 53070Item.prototype._removeStyles = function( style ) { 53071 // clean up transition styles 53072 var cleanStyle = {}; 53073 for ( var prop in style ) { 53074 cleanStyle[ prop ] = ''; 53075 } 53076 this.css( cleanStyle ); 53077}; 53078 53079var cleanTransitionStyle = { 53080 transitionProperty: '', 53081 transitionDuration: '' 53082}; 53083 53084Item.prototype.removeTransitionStyles = function() { 53085 // remove transition 53086 this.css( cleanTransitionStyle ); 53087}; 53088 53089// ----- show/hide/remove ----- // 53090 53091// remove element from DOM 53092Item.prototype.removeElem = function() { 53093 this.element.parentNode.removeChild( this.element ); 53094 this.emitEvent( 'remove', [ this ] ); 53095}; 53096 53097Item.prototype.remove = function() { 53098 // just remove element if no transition support or no transition 53099 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 53100 this.removeElem(); 53101 return; 53102 } 53103 53104 // start transition 53105 var _this = this; 53106 this.on( 'transitionEnd', function() { 53107 _this.removeElem(); 53108 return true; // bind once 53109 }); 53110 this.hide(); 53111}; 53112 53113Item.prototype.reveal = function() { 53114 delete this.isHidden; 53115 // remove display: none 53116 this.css({ display: '' }); 53117 53118 var options = this.layout.options; 53119 this.transition({ 53120 from: options.hiddenStyle, 53121 to: options.visibleStyle, 53122 isCleaning: true 53123 }); 53124}; 53125 53126Item.prototype.hide = function() { 53127 // set flag 53128 this.isHidden = true; 53129 // remove display: none 53130 this.css({ display: '' }); 53131 53132 var options = this.layout.options; 53133 this.transition({ 53134 from: options.visibleStyle, 53135 to: options.hiddenStyle, 53136 // keep hidden stuff hidden 53137 isCleaning: true, 53138 onTransitionEnd: { 53139 opacity: function() { 53140 // check if still hidden 53141 // during transition, item may have been un-hidden 53142 if ( this.isHidden ) { 53143 this.css({ display: 'none' }); 53144 } 53145 } 53146 } 53147 }); 53148}; 53149 53150Item.prototype.destroy = function() { 53151 this.css({ 53152 position: '', 53153 left: '', 53154 right: '', 53155 top: '', 53156 bottom: '', 53157 transition: '', 53158 transform: '' 53159 }); 53160}; 53161 53162return Item; 53163 53164} 53165 53166// -------------------------- transport -------------------------- // 53167 53168if ( typeof define === 'function' && define.amd ) { 53169 // AMD 53170 define( 'outlayer/item',[ 53171 'eventEmitter/EventEmitter', 53172 'get-size/get-size', 53173 'get-style-property/get-style-property' 53174 ], 53175 outlayerItemDefinition ); 53176} else { 53177 // browser global 53178 window.Outlayer = {}; 53179 window.Outlayer.Item = outlayerItemDefinition( 53180 window.EventEmitter, 53181 window.getSize, 53182 window.getStyleProperty 53183 ); 53184} 53185 53186})( window ); 53187 53188/*! 53189 * Outlayer v1.2.0 53190 * the brains and guts of a layout library 53191 * MIT license 53192 */ 53193 53194( function( window ) { 53195 53196 53197 53198// ----- vars ----- // 53199 53200var document = window.document; 53201var console = window.console; 53202var jQuery = window.jQuery; 53203 53204var noop = function() {}; 53205 53206// -------------------------- helpers -------------------------- // 53207 53208// extend objects 53209function extend( a, b ) { 53210 for ( var prop in b ) { 53211 a[ prop ] = b[ prop ]; 53212 } 53213 return a; 53214} 53215 53216 53217var objToString = Object.prototype.toString; 53218function isArray( obj ) { 53219 return objToString.call( obj ) === '[object Array]'; 53220} 53221 53222// turn element or nodeList into an array 53223function makeArray( obj ) { 53224 var ary = []; 53225 if ( isArray( obj ) ) { 53226 // use object if already an array 53227 ary = obj; 53228 } else if ( obj && typeof obj.length === 'number' ) { 53229 // convert nodeList to array 53230 for ( var i=0, len = obj.length; i < len; i++ ) { 53231 ary.push( obj[i] ); 53232 } 53233 } else { 53234 // array of single index 53235 ary.push( obj ); 53236 } 53237 return ary; 53238} 53239 53240// http://stackoverflow.com/a/384380/182183 53241var isElement = ( typeof HTMLElement === 'object' ) ? 53242 function isElementDOM2( obj ) { 53243 return obj instanceof HTMLElement; 53244 } : 53245 function isElementQuirky( obj ) { 53246 return obj && typeof obj === 'object' && 53247 obj.nodeType === 1 && typeof obj.nodeName === 'string'; 53248 }; 53249 53250// index of helper cause IE8 53251var indexOf = Array.prototype.indexOf ? function( ary, obj ) { 53252 return ary.indexOf( obj ); 53253 } : function( ary, obj ) { 53254 for ( var i=0, len = ary.length; i < len; i++ ) { 53255 if ( ary[i] === obj ) { 53256 return i; 53257 } 53258 } 53259 return -1; 53260 }; 53261 53262function removeFrom( obj, ary ) { 53263 var index = indexOf( ary, obj ); 53264 if ( index !== -1 ) { 53265 ary.splice( index, 1 ); 53266 } 53267} 53268 53269// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 53270function toDashed( str ) { 53271 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 53272 return $1 + '-' + $2; 53273 }).toLowerCase(); 53274} 53275 53276 53277function outlayerDefinition( eventie, docReady, EventEmitter, getSize, matchesSelector, Item ) { 53278 53279// -------------------------- Outlayer -------------------------- // 53280 53281// globally unique identifiers 53282var GUID = 0; 53283// internal store of all Outlayer intances 53284var instances = {}; 53285 53286 53287/** 53288 * @param {Element, String} element 53289 * @param {Object} options 53290 * @constructor 53291 */ 53292function Outlayer( element, options ) { 53293 // use element as selector string 53294 if ( typeof element === 'string' ) { 53295 element = document.querySelector( element ); 53296 } 53297 53298 // bail out if not proper element 53299 if ( !element || !isElement( element ) ) { 53300 if ( console ) { 53301 console.error( 'Bad ' + this.constructor.namespace + ' element: ' + element ); 53302 } 53303 return; 53304 } 53305 53306 this.element = element; 53307 53308 // options 53309 this.options = extend( {}, this.constructor.defaults ); 53310 this.option( options ); 53311 53312 // add id for Outlayer.getFromElement 53313 var id = ++GUID; 53314 this.element.outlayerGUID = id; // expando 53315 instances[ id ] = this; // associate via id 53316 53317 // kick it off 53318 this._create(); 53319 53320 if ( this.options.isInitLayout ) { 53321 this.layout(); 53322 } 53323} 53324 53325// settings are for internal use only 53326Outlayer.namespace = 'outlayer'; 53327Outlayer.Item = Item; 53328 53329// default options 53330Outlayer.defaults = { 53331 containerStyle: { 53332 position: 'relative' 53333 }, 53334 isInitLayout: true, 53335 isOriginLeft: true, 53336 isOriginTop: true, 53337 isResizeBound: true, 53338 isResizingContainer: true, 53339 // item options 53340 transitionDuration: '0.4s', 53341 hiddenStyle: { 53342 opacity: 0, 53343 transform: 'scale(0.001)' 53344 }, 53345 visibleStyle: { 53346 opacity: 1, 53347 transform: 'scale(1)' 53348 } 53349}; 53350 53351// inherit EventEmitter 53352extend( Outlayer.prototype, EventEmitter.prototype ); 53353 53354/** 53355 * set options 53356 * @param {Object} opts 53357 */ 53358Outlayer.prototype.option = function( opts ) { 53359 extend( this.options, opts ); 53360}; 53361 53362Outlayer.prototype._create = function() { 53363 // get items from children 53364 this.reloadItems(); 53365 // elements that affect layout, but are not laid out 53366 this.stamps = []; 53367 this.stamp( this.options.stamp ); 53368 // set container style 53369 extend( this.element.style, this.options.containerStyle ); 53370 53371 // bind resize method 53372 if ( this.options.isResizeBound ) { 53373 this.bindResize(); 53374 } 53375}; 53376 53377// goes through all children again and gets bricks in proper order 53378Outlayer.prototype.reloadItems = function() { 53379 // collection of item elements 53380 this.items = this._itemize( this.element.children ); 53381}; 53382 53383 53384/** 53385 * turn elements into Outlayer.Items to be used in layout 53386 * @param {Array or NodeList or HTMLElement} elems 53387 * @returns {Array} items - collection of new Outlayer Items 53388 */ 53389Outlayer.prototype._itemize = function( elems ) { 53390 53391 var itemElems = this._filterFindItemElements( elems ); 53392 var Item = this.constructor.Item; 53393 53394 // create new Outlayer Items for collection 53395 var items = []; 53396 for ( var i=0, len = itemElems.length; i < len; i++ ) { 53397 var elem = itemElems[i]; 53398 var item = new Item( elem, this ); 53399 items.push( item ); 53400 } 53401 53402 return items; 53403}; 53404 53405/** 53406 * get item elements to be used in layout 53407 * @param {Array or NodeList or HTMLElement} elems 53408 * @returns {Array} items - item elements 53409 */ 53410Outlayer.prototype._filterFindItemElements = function( elems ) { 53411 // make array of elems 53412 elems = makeArray( elems ); 53413 var itemSelector = this.options.itemSelector; 53414 var itemElems = []; 53415 53416 for ( var i=0, len = elems.length; i < len; i++ ) { 53417 var elem = elems[i]; 53418 // check that elem is an actual element 53419 if ( !isElement( elem ) ) { 53420 continue; 53421 } 53422 // filter & find items if we have an item selector 53423 if ( itemSelector ) { 53424 // filter siblings 53425 if ( matchesSelector( elem, itemSelector ) ) { 53426 itemElems.push( elem ); 53427 } 53428 // find children 53429 var childElems = elem.querySelectorAll( itemSelector ); 53430 // concat childElems to filterFound array 53431 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 53432 itemElems.push( childElems[j] ); 53433 } 53434 } else { 53435 itemElems.push( elem ); 53436 } 53437 } 53438 53439 return itemElems; 53440}; 53441 53442/** 53443 * getter method for getting item elements 53444 * @returns {Array} elems - collection of item elements 53445 */ 53446Outlayer.prototype.getItemElements = function() { 53447 var elems = []; 53448 for ( var i=0, len = this.items.length; i < len; i++ ) { 53449 elems.push( this.items[i].element ); 53450 } 53451 return elems; 53452}; 53453 53454// ----- init & layout ----- // 53455 53456/** 53457 * lays out all items 53458 */ 53459Outlayer.prototype.layout = function() { 53460 this._resetLayout(); 53461 this._manageStamps(); 53462 53463 // don't animate first layout 53464 var isInstant = this.options.isLayoutInstant !== undefined ? 53465 this.options.isLayoutInstant : !this._isLayoutInited; 53466 this.layoutItems( this.items, isInstant ); 53467 53468 // flag for initalized 53469 this._isLayoutInited = true; 53470}; 53471 53472// _init is alias for layout 53473Outlayer.prototype._init = Outlayer.prototype.layout; 53474 53475/** 53476 * logic before any new layout 53477 */ 53478Outlayer.prototype._resetLayout = function() {
53479 this.getSize(); 53480}; 53481 53482 53483Outlayer.prototype.getSize = function() { 53484 this.size = getSize( this.element ); 53485}; 53486 53487/** 53488 * get measurement from option, for columnWidth, rowHeight, gutter 53489 * if option is String -> get element from selector string, & get size of element 53490 * if option is Element -> get size of element 53491 * else use option as a number 53492 * 53493 * @param {String} measurement 53494 * @param {String} size - width or height 53495 * @private 53496 */ 53497Outlayer.prototype._getMeasurement = function( measurement, size ) { 53498 var option = this.options[ measurement ]; 53499 var elem; 53500 if ( !option ) { 53501 // default to 0 53502 this[ measurement ] = 0; 53503 } else { 53504 // use option as an element 53505 if ( typeof option === 'string' ) { 53506 elem = this.element.querySelector( option ); 53507 } else if ( isElement( option ) ) { 53508 elem = option; 53509 } 53510 // use size of element, if element 53511 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 53512 } 53513}; 53514 53515/** 53516 * layout a collection of item elements 53517 * @api public 53518 */ 53519Outlayer.prototype.layoutItems = function( items, isInstant ) { 53520 items = this._getItemsForLayout( items ); 53521 53522 this._layoutItems( items, isInstant ); 53523 53524 this._postLayout(); 53525}; 53526 53527/** 53528 * get the items to be laid out 53529 * you may want to skip over some items 53530 * @param {Array} items 53531 * @returns {Array} items 53532 */ 53533Outlayer.prototype._getItemsForLayout = function( items ) { 53534 var layoutItems = []; 53535 for ( var i=0, len = items.length; i < len; i++ ) { 53536 var item = items[i]; 53537 if ( !item.isIgnored ) { 53538 layoutItems.push( item ); 53539 } 53540 } 53541 return layoutItems; 53542}; 53543 53544/** 53545 * layout items 53546 * @param {Array} items 53547 * @param {Boolean} isInstant 53548 */ 53549Outlayer.prototype._layoutItems = function( items, isInstant ) { 53550 var _this = this; 53551 function onItemsLayout() { 53552 _this.emitEvent( 'layoutComplete', [ _this, items ] ); 53553 } 53554 53555 if ( !items || !items.length ) { 53556 // no items, emit event with empty array 53557 onItemsLayout(); 53558 return; 53559 } 53560 53561 // emit layoutComplete when done 53562 this._itemsOn( items, 'layout', onItemsLayout ); 53563 53564 var queue = []; 53565 53566 for ( var i=0, len = items.length; i < len; i++ ) { 53567 var item = items[i]; 53568 // get x/y object from method 53569 var position = this._getItemLayoutPosition( item ); 53570 // enqueue 53571 position.item = item; 53572 position.isInstant = isInstant || item.isLayoutInstant; 53573 queue.push( position ); 53574 } 53575 53576 this._processLayoutQueue( queue ); 53577}; 53578 53579/** 53580 * get item layout position 53581 * @param {Outlayer.Item} item 53582 * @returns {Object} x and y position 53583 */ 53584Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) { 53585 return { 53586 x: 0, 53587 y: 0 53588 }; 53589}; 53590 53591/** 53592 * iterate over array and position each item 53593 * Reason being - separating this logic prevents 'layout invalidation' 53594 * thx @paul_irish 53595 * @param {Array} queue 53596 */ 53597Outlayer.prototype._processLayoutQueue = function( queue ) { 53598 for ( var i=0, len = queue.length; i < len; i++ ) { 53599 var obj = queue[i]; 53600 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant ); 53601 } 53602}; 53603 53604/** 53605 * Sets position of item in DOM 53606 * @param {Outlayer.Item} item 53607 * @param {Number} x - horizontal position 53608 * @param {Number} y - vertical position 53609 * @param {Boolean} isInstant - disables transitions 53610 */ 53611Outlayer.prototype._positionItem = function( item, x, y, isInstant ) { 53612 if ( isInstant ) { 53613 // if not transition, just set CSS 53614 item.goTo( x, y ); 53615 } else { 53616 item.moveTo( x, y ); 53617 } 53618}; 53619 53620/** 53621 * Any logic you want to do after each layout, 53622 * i.e. size the container 53623 */ 53624Outlayer.prototype._postLayout = function() { 53625 this.resizeContainer(); 53626}; 53627 53628Outlayer.prototype.resizeContainer = function() { 53629 if ( !this.options.isResizingContainer ) { 53630 return; 53631 } 53632 var size = this._getContainerSize(); 53633 if ( size ) { 53634 this._setContainerMeasure( size.width, true ); 53635 this._setContainerMeasure( size.height, false ); 53636 } 53637}; 53638 53639/** 53640 * Sets width or height of container if returned 53641 * @returns {Object} size 53642 * @param {Number} width 53643 * @param {Number} height 53644 */ 53645Outlayer.prototype._getContainerSize = noop; 53646 53647/** 53648 * @param {Number} measure - size of width or height 53649 * @param {Boolean} isWidth 53650 */ 53651Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) { 53652 if ( measure === undefined ) { 53653 return; 53654 } 53655 53656 var elemSize = this.size; 53657 // add padding and border width if border box 53658 if ( elemSize.isBorderBox ) { 53659 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 53660 elemSize.borderLeftWidth + elemSize.borderRightWidth : 53661 elemSize.paddingBottom + elemSize.paddingTop + 53662 elemSize.borderTopWidth + elemSize.borderBottomWidth; 53663 } 53664 53665 measure = Math.max( measure, 0 ); 53666 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 53667}; 53668 53669/** 53670 * trigger a callback for a collection of items events 53671 * @param {Array} items - Outlayer.Items 53672 * @param {String} eventName 53673 * @param {Function} callback 53674 */ 53675Outlayer.prototype._itemsOn = function( items, eventName, callback ) { 53676 var doneCount = 0; 53677 var count = items.length; 53678 // event callback 53679 var _this = this; 53680 function tick() { 53681 doneCount++; 53682 if ( doneCount === count ) { 53683 callback.call( _this ); 53684 } 53685 return true; // bind once 53686 } 53687 // bind callback 53688 for ( var i=0, len = items.length; i < len; i++ ) { 53689 var item = items[i]; 53690 item.on( eventName, tick ); 53691 } 53692}; 53693 53694// -------------------------- ignore & stamps -------------------------- // 53695 53696 53697/** 53698 * keep item in collection, but do not lay it out 53699 * ignored items do not get skipped in layout 53700 * @param {Element} elem 53701 */ 53702Outlayer.prototype.ignore = function( elem ) { 53703 var item = this.getItem( elem ); 53704 if ( item ) { 53705 item.isIgnored = true; 53706 } 53707}; 53708 53709/** 53710 * return item to layout collection 53711 * @param {Element} elem 53712 */ 53713Outlayer.prototype.unignore = function( elem ) { 53714 var item = this.getItem( elem ); 53715 if ( item ) { 53716 delete item.isIgnored; 53717 } 53718}; 53719 53720/** 53721 * adds elements to stamps 53722 * @param {NodeList, Array, Element, or String} elems 53723 */ 53724Outlayer.prototype.stamp = function( elems ) { 53725 elems = this._find( elems ); 53726 if ( !elems ) { 53727 return; 53728 } 53729
53730 this.stamps = this.stamps.concat( elems ); 53731 // ignore 53732 for ( var i=0, len = elems.length; i < len; i++ ) { 53733 var elem = elems[i]; 53734 this.ignore( elem ); 53735 } 53736}; 53737 53738/** 53739 * removes elements to stamps 53740 * @param {NodeList, Array, or Element} elems 53741 */ 53742Outlayer.prototype.unstamp = function( elems ) { 53743 elems = this._find( elems ); 53744 if ( !elems ){ 53745 return; 53746 } 53747 53748 for ( var i=0, len = elems.length; i < len; i++ ) { 53749 var elem = elems[i]; 53750 // filter out removed stamp elements 53751 removeFrom( elem, this.stamps ); 53752 this.unignore( elem ); 53753 } 53754 53755}; 53756 53757/** 53758 * finds child elements 53759 * @param {NodeList, Array, Element, or String} elems 53760 * @returns {Array} elems 53761 */ 53762Outlayer.prototype._find = function( elems ) { 53763 if ( !elems ) { 53764 return; 53765 } 53766 // if string, use argument as selector string 53767 if ( typeof elems === 'string' ) { 53768 elems = this.element.querySelectorAll( elems ); 53769 } 53770 elems = makeArray( elems ); 53771 return elems; 53772}; 53773 53774Outlayer.prototype._manageStamps = function() { 53775 if ( !this.stamps || !this.stamps.length ) { 53776 return; 53777 } 53778 53779 this._getBoundingRect(); 53780 53781 for ( var i=0, len = this.stamps.length; i < len; i++ ) { 53782 var stamp = this.stamps[i]; 53783 this._manageStamp( stamp ); 53784 } 53785}; 53786 53787// update boundingLeft / Top 53788Outlayer.prototype._getBoundingRect = function() { 53789 // get bounding rect for container element 53790 var boundingRect = this.element.getBoundingClientRect(); 53791 var size = this.size; 53792 this._boundingRect = { 53793 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 53794 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 53795 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 53796 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 53797 }; 53798}; 53799 53800/** 53801 * @param {Element} stamp 53802**/ 53803Outlayer.prototype._manageStamp = noop; 53804 53805/** 53806 * get x/y position of element relative to container element 53807 * @param {Element} elem 53808 * @returns {Object} offset - has left, top, right, bottom 53809 */ 53810Outlayer.prototype._getElementOffset = function( elem ) { 53811 var boundingRect = elem.getBoundingClientRect(); 53812 var thisRect = this._boundingRect; 53813 var size = getSize( elem ); 53814 var offset = { 53815 left: boundingRect.left - thisRect.left - size.marginLeft, 53816 top: boundingRect.top - thisRect.top - size.marginTop, 53817 right: thisRect.right - boundingRect.right - size.marginRight, 53818 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 53819 }; 53820 return offset; 53821}; 53822 53823// -------------------------- resize -------------------------- // 53824 53825// enable event handlers for listeners 53826// i.e. resize -> onresize 53827Outlayer.prototype.handleEvent = function( event ) { 53828 var method = 'on' + event.type; 53829 if ( this[ method ] ) { 53830 this[ method ]( event ); 53831 } 53832}; 53833 53834/** 53835 * Bind layout to window resizing 53836 */ 53837Outlayer.prototype.bindResize = function() { 53838 // bind just one listener 53839 if ( this.isResizeBound ) { 53840 return; 53841 } 53842 eventie.bind( window, 'resize', this ); 53843 this.isResizeBound = true; 53844}; 53845 53846/** 53847 * Unbind layout to window resizing 53848 */ 53849Outlayer.prototype.unbindResize = function() { 53850 if ( this.isResizeBound ) { 53851 eventie.unbind( window, 'resize', this ); 53852 } 53853 this.isResizeBound = false; 53854}; 53855 53856// original debounce by John Hann 53857// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 53858 53859// this fires every resize 53860Outlayer.prototype.onresize = function() { 53861 if ( this.resizeTimeout ) { 53862 clearTimeout( this.resizeTimeout ); 53863 } 53864 53865 var _this = this; 53866 function delayed() { 53867 _this.resize(); 53868 delete _this.resizeTimeout; 53869 } 53870 53871 this.resizeTimeout = setTimeout( delayed, 100 ); 53872}; 53873 53874// debounced, layout on resize 53875Outlayer.prototype.resize = function() { 53876 // don't trigger if size did not change 53877 // or if resize was unbound. See #9 53878 53879 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 53880 return; 53881 } 53882 53883 this.layout(); 53884}; 53885 53886/** 53887 * check if layout is needed post layout 53888 * @returns Boolean 53889 */ 53890Outlayer.prototype.needsResizeLayout = function() { 53891 var size = getSize( this.element ); 53892 // check that this.size and size are there 53893 // IE8 triggers resize on body size change, so they might not be 53894 var hasSizes = this.size && size; 53895 return hasSizes && size.innerWidth !== this.size.innerWidth; 53896}; 53897 53898// -------------------------- methods -------------------------- // 53899 53900/** 53901 * add items to Outlayer instance 53902 * @param {Array or NodeList or Element} elems 53903 * @returns {Array} items - Outlayer.Items 53904**/ 53905Outlayer.prototype.addItems = function( elems ) { 53906 var items = this._itemize( elems ); 53907 // add items to collection 53908 if ( items.length ) { 53909 this.items = this.items.concat( items ); 53910 } 53911 return items; 53912}; 53913 53914/** 53915 * Layout newly-appended item elements 53916 * @param {Array or NodeList or Element} elems 53917 */ 53918Outlayer.prototype.appended = function( elems ) { 53919 var items = this.addItems( elems ); 53920 if ( !items.length ) { 53921 return; 53922 } 53923 // layout and reveal just the new items 53924 this.layoutItems( items, true ); 53925 this.reveal( items ); 53926}; 53927 53928/** 53929 * Layout prepended elements 53930 * @param {Array or NodeList or Element} elems 53931 */ 53932Outlayer.prototype.prepended = function( elems ) { 53933 var items = this._itemize( elems ); 53934 if ( !items.length ) { 53935 return; 53936 } 53937 // add items to beginning of collection 53938 var previousItems = this.items.slice(0); 53939 this.items = items.concat( previousItems ); 53940 // start new layout 53941 this._resetLayout(); 53942 this._manageStamps(); 53943 // layout new stuff without transition 53944 this.layoutItems( items, true ); 53945 this.reveal( items ); 53946 // layout previous items 53947 this.layoutItems( previousItems ); 53948}; 53949 53950/** 53951 * reveal a collection of items 53952 * @param {Array of Outlayer.Items} items 53953 */ 53954Outlayer.prototype.reveal = function( items ) { 53955 var len = items && items.length; 53956 if ( !len ) { 53957 return; 53958 } 53959 for ( var i=0; i < len; i++ ) { 53960 var item = items[i]; 53961 item.reveal(); 53962 } 53963}; 53964 53965/** 53966 * hide a collection of items 53967 * @param {Array of Outlayer.Items} items 53968 */ 53969Outlayer.prototype.hide = function( items ) { 53970 var len = items && items.length; 53971 if ( !len ) { 53972 return; 53973 } 53974 for ( var i=0; i < len; i++ ) { 53975 var item = items[i]; 53976 item.hide(); 53977 } 53978}; 53979 53980/** 53981 * get Outlayer.Item, given an Element 53982 * @param {Element} elem 53983 * @param {Function} callback 53984 * @returns {Outlayer.Item} item 53985 */ 53986Outlayer.prototype.getItem = function( elem ) { 53987 // loop through items to get the one that matches 53988 for ( var i=0, len = this.items.length; i < len; i++ ) { 53989 var item = this.items[i]; 53990 if ( item.element === elem ) { 53991 // return item 53992 return item; 53993 } 53994 } 53995}; 53996 53997/** 53998 * get collection of Outlayer.Items, given Elements 53999 * @param {Array} elems 54000 * @returns {Array} items - Outlayer.Items 54001 */ 54002Outlayer.prototype.getItems = function( elems ) { 54003 if ( !elems || !elems.length ) { 54004 return; 54005 } 54006 var items = []; 54007 for ( var i=0, len = elems.length; i < len; i++ ) { 54008 var elem = elems[i]; 54009 var item = this.getItem( elem ); 54010 if ( item ) { 54011 items.push( item ); 54012 } 54013 } 54014 54015 return items; 54016}; 54017 54018/**
54019 * remove element(s) from instance and DOM 54020 * @param {Array or NodeList or Element} elems 54021 */ 54022Outlayer.prototype.remove = function( elems ) { 54023 elems = makeArray( elems ); 54024 54025 var removeItems = this.getItems( elems ); 54026 // bail if no items to remove 54027 if ( !removeItems || !removeItems.length ) { 54028 return; 54029 } 54030 54031 this._itemsOn( removeItems, 'remove', function() { 54032 this.emitEvent( 'removeComplete', [ this, removeItems ] ); 54033 }); 54034 54035 for ( var i=0, len = removeItems.length; i < len; i++ ) { 54036 var item = removeItems[i]; 54037 item.remove(); 54038 // remove item from collection 54039 removeFrom( item, this.items ); 54040 } 54041}; 54042 54043// ----- destroy ----- // 54044 54045// remove and disable Outlayer instance 54046Outlayer.prototype.destroy = function() { 54047 // clean up dynamic styles 54048 var style = this.element.style; 54049 style.height = ''; 54050 style.position = ''; 54051 style.width = ''; 54052 // destroy items 54053 for ( var i=0, len = this.items.length; i < len; i++ ) { 54054 var item = this.items[i]; 54055 item.destroy(); 54056 } 54057 54058 this.unbindResize(); 54059 54060 delete this.element.outlayerGUID; 54061 // remove data for jQuery 54062 if ( jQuery ) { 54063 jQuery.removeData( this.element, this.constructor.namespace ); 54064 } 54065 54066}; 54067 54068// -------------------------- data -------------------------- // 54069 54070/** 54071 * get Outlayer instance from element 54072 * @param {Element} elem 54073 * @returns {Outlayer} 54074 */ 54075Outlayer.data = function( elem ) { 54076 var id = elem && elem.outlayerGUID; 54077 return id && instances[ id ]; 54078}; 54079 54080 54081// -------------------------- create Outlayer class -------------------------- // 54082 54083/** 54084 * create a layout class 54085 * @param {String} namespace 54086 */ 54087Outlayer.create = function( namespace, options ) { 54088 // sub-class Outlayer 54089 function Layout() { 54090 Outlayer.apply( this, arguments ); 54091 } 54092 // inherit Outlayer prototype, use Object.create if there 54093 if ( Object.create ) { 54094 Layout.prototype = Object.create( Outlayer.prototype ); 54095 } else { 54096 extend( Layout.prototype, Outlayer.prototype ); 54097 } 54098 // set contructor, used for namespace and Item 54099 Layout.prototype.constructor = Layout; 54100 54101 Layout.defaults = extend( {}, Outlayer.defaults ); 54102 // apply new options 54103 extend( Layout.defaults, options ); 54104 // keep prototype.settings for backwards compatibility (Packery v1.2.0) 54105 Layout.prototype.settings = {}; 54106 54107 Layout.namespace = namespace; 54108 54109 Layout.data = Outlayer.data; 54110 54111 // sub-class Item 54112 Layout.Item = function LayoutItem() { 54113 Item.apply( this, arguments ); 54114 }; 54115 54116 Layout.Item.prototype = new Item(); 54117 54118 // -------------------------- declarative -------------------------- // 54119 54120 /** 54121 * allow user to initialize Outlayer via .js-namespace class 54122 * options are parsed from data-namespace-option attribute 54123 */ 54124 docReady( function() { 54125 var dashedNamespace = toDashed( namespace ); 54126 var elems = document.querySelectorAll( '.js-' + dashedNamespace ); 54127 var dataAttr = 'data-' + dashedNamespace + '-options'; 54128 54129 for ( var i=0, len = elems.length; i < len; i++ ) { 54130 var elem = elems[i]; 54131 var attr = elem.getAttribute( dataAttr ); 54132 var options; 54133 try { 54134 options = attr && JSON.parse( attr ); 54135 } catch ( error ) { 54136 // log error, do not initialize 54137 if ( console ) { 54138 console.error( 'Error parsing ' + dataAttr + ' on ' + 54139 elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' + 54140 error ); 54141 } 54142 continue; 54143 } 54144 // initialize 54145 var instance = new Layout( elem, options ); 54146 // make available via $().data('layoutname') 54147 if ( jQuery ) { 54148 jQuery.data( elem, namespace, instance ); 54149 } 54150 } 54151 }); 54152 54153 // -------------------------- jQuery bridge -------------------------- // 54154 54155 // make into jQuery plugin 54156 if ( jQuery && jQuery.bridget ) { 54157 jQuery.bridget( namespace, Layout ); 54158 } 54159 54160 return Layout; 54161}; 54162 54163// ----- fin ----- // 54164 54165// back in global 54166Outlayer.Item = Item; 54167 54168return Outlayer; 54169 54170} 54171 54172// -------------------------- transport -------------------------- // 54173 54174if ( typeof define === 'function' && define.amd ) { 54175 // AMD 54176 define( 'outlayer/outlayer',[ 54177 'eventie/eventie', 54178 'doc-ready/doc-ready', 54179 'eventEmitter/EventEmitter', 54180 'get-size/get-size', 54181 'matches-selector/matches-selector', 54182 './item' 54183 ], 54184 outlayerDefinition ); 54185} else { 54186 // browser global 54187 window.Outlayer = outlayerDefinition( 54188 window.eventie, 54189 window.docReady, 54190 window.EventEmitter, 54191 window.getSize, 54192 window.matchesSelector, 54193 window.Outlayer.Item 54194 ); 54195} 54196 54197})( window ); 54198 54199/*! 54200 * Masonry v3.1.5 54201 * Cascading grid layout library 54202 * http://masonry.desandro.com 54203 * MIT License 54204 * by David DeSandro 54205 */ 54206 54207( function( window ) { 54208 54209 54210 54211// -------------------------- helpers -------------------------- // 54212 54213var indexOf = Array.prototype.indexOf ? 54214 function( items, value ) { 54215 return items.indexOf( value ); 54216 } : 54217 function ( items, value ) { 54218 for ( var i=0, len = items.length; i < len; i++ ) { 54219 var item = items[i]; 54220 if ( item === value ) { 54221 return i; 54222 } 54223 } 54224 return -1; 54225 }; 54226 54227// -------------------------- masonryDefinition -------------------------- // 54228 54229// used for AMD definition and requires 54230function masonryDefinition( Outlayer, getSize ) { 54231 // create an Outlayer layout class 54232 var Masonry = Outlayer.create('masonry'); 54233 54234 Masonry.prototype._resetLayout = function() {
54235 this.getSize(); 54236 this._getMeasurement( 'columnWidth', 'outerWidth' ); 54237 this._getMeasurement( 'gutter', 'outerWidth' ); 54238 this.measureColumns(); 54239 54240 // reset column Y 54241 var i = this.cols; 54242 this.colYs = []; 54243 while (i--) { 54244 this.colYs.push( 0 ); 54245 } 54246 54247 this.maxY = 0; 54248 }; 54249 54250 Masonry.prototype.measureColumns = function() { 54251 this.getContainerWidth(); 54252 // if columnWidth is 0, default to outerWidth of first item 54253 if ( !this.columnWidth ) { 54254 var firstItem = this.items[0]; 54255 var firstItemElem = firstItem && firstItem.element; 54256 // columnWidth fall back to item of first element 54257 this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || 54258 // if first elem has no width, default to size of container 54259 this.containerWidth; 54260 } 54261 54262 this.columnWidth += this.gutter; 54263 54264 this.cols = Math.floor( ( this.containerWidth + this.gutter ) / this.columnWidth ); 54265 this.cols = Math.max( this.cols, 1 ); 54266 }; 54267 54268 Masonry.prototype.getContainerWidth = function() { 54269 // container is parent if fit width 54270 var container = this.options.isFitWidth ? this.element.parentNode : this.element; 54271 // check that this.size and size are there 54272 // IE8 triggers resize on body size change, so they might not be 54273 var size = getSize( container ); 54274 this.containerWidth = size && size.innerWidth; 54275 }; 54276 54277 Masonry.prototype._getItemLayoutPosition = function( item ) { 54278 item.getSize(); 54279 // how many columns does this brick span 54280 var remainder = item.size.outerWidth % this.columnWidth; 54281 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 54282 // round if off by 1 pixel, otherwise use ceil 54283 var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); 54284 colSpan = Math.min( colSpan, this.cols ); 54285 54286 var colGroup = this._getColGroup( colSpan ); 54287 // get the minimum Y value from the columns 54288 var minimumY = Math.min.apply( Math, colGroup ); 54289 var shortColIndex = indexOf( colGroup, minimumY ); 54290 54291 // position the brick 54292 var position = { 54293 x: this.columnWidth * shortColIndex, 54294 y: minimumY 54295 }; 54296 54297 // apply setHeight to necessary columns 54298 var setHeight = minimumY + item.size.outerHeight; 54299 var setSpan = this.cols + 1 - colGroup.length; 54300 for ( var i = 0; i < setSpan; i++ ) { 54301 this.colYs[ shortColIndex + i ] = setHeight; 54302 } 54303 54304 return position; 54305 }; 54306 54307 /** 54308 * @param {Number} colSpan - number of columns the element spans 54309 * @returns {Array} colGroup 54310 */ 54311 Masonry.prototype._getColGroup = function( colSpan ) { 54312 if ( colSpan < 2 ) { 54313 // if brick spans only one column, use all the column Ys 54314 return this.colYs; 54315 } 54316 54317 var colGroup = []; 54318 // how many different places could this brick fit horizontally 54319 var groupCount = this.cols + 1 - colSpan; 54320 // for each group potential horizontal position 54321 for ( var i = 0; i < groupCount; i++ ) { 54322 // make an array of colY values for that one group 54323 var groupColYs = this.colYs.slice( i, i + colSpan ); 54324 // and get the max value of the array 54325 colGroup[i] = Math.max.apply( Math, groupColYs ); 54326 } 54327 return colGroup; 54328 }; 54329 54330 Masonry.prototype._manageStamp = function( stamp ) { 54331 var stampSize = getSize( stamp ); 54332 var offset = this._getElementOffset( stamp ); 54333 // get the columns that this stamp affects 54334 var firstX = this.options.isOriginLeft ? offset.left : offset.right; 54335 var lastX = firstX + stampSize.outerWidth; 54336 var firstCol = Math.floor( firstX / this.columnWidth ); 54337 firstCol = Math.max( 0, firstCol ); 54338 var lastCol = Math.floor( lastX / this.columnWidth ); 54339 // lastCol should not go over if multiple of columnWidth #425 54340 lastCol -= lastX % this.columnWidth ? 0 : 1; 54341 lastCol = Math.min( this.cols - 1, lastCol ); 54342 // set colYs to bottom of the stamp 54343 var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) + 54344 stampSize.outerHeight; 54345 for ( var i = firstCol; i <= lastCol; i++ ) { 54346 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); 54347 } 54348 }; 54349 54350 Masonry.prototype._getContainerSize = function() { 54351 this.maxY = Math.max.apply( Math, this.colYs ); 54352 var size = { 54353 height: this.maxY 54354 }; 54355 54356 if ( this.options.isFitWidth ) { 54357 size.width = this._getContainerFitWidth(); 54358 } 54359 54360 return size; 54361 }; 54362 54363 Masonry.prototype._getContainerFitWidth = function() { 54364 var unusedCols = 0; 54365 // count unused columns 54366 var i = this.cols; 54367 while ( --i ) { 54368 if ( this.colYs[i] !== 0 ) { 54369 break; 54370 } 54371 unusedCols++; 54372 } 54373 // fit container to columns that have been used 54374 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; 54375 }; 54376 54377 Masonry.prototype.needsResizeLayout = function() { 54378 var previousWidth = this.containerWidth; 54379 this.getContainerWidth(); 54380 return previousWidth !== this.containerWidth; 54381 }; 54382 54383 return Masonry; 54384} 54385 54386// -------------------------- transport -------------------------- // 54387 54388if ( typeof define === 'function' && define.amd ) { 54389 // AMD 54390 define( [ 54391 'outlayer/outlayer', 54392 'get-size/get-size' 54393 ], 54394 masonryDefinition ); 54395} else { 54396 // browser global 54397 window.Masonry = masonryDefinition( 54398 window.Outlayer, 54399 window.getSize 54400 ); 54401} 54402 54403})( window ); 54404(function() { 54405 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 54406 54407 if (window.App == null) { 54408 window.App = {}; 54409 } 54410 54411 if (App.Modules == null) { 54412 App.Modules = {}; 54413 } 54414 54415 App.Modules.InfiniteScroller = (function() { 54416 InfiniteScroller.prototype.canFetch = true; 54417 54418 InfiniteScroller.prototype.currentPage = null; 54419 54420 InfiniteScroller.prototype.firstPage = null; 54421 54422 InfiniteScroller.prototype.totalPages = null; 54423 54424 InfiniteScroller.prototype.loopPages = null; 54425 54426 InfiniteScroller.prototype.loadContainer = null; 54427 54428 InfiniteScroller.prototype.loader = null; 54429 54430 InfiniteScroller.prototype.pagesOverflow = false;
54431 54432 function InfiniteScroller(triggerElementSelector) { 54433 this.newPage = bind(this.newPage, this); 54434 this.onScroll = bind(this.onScroll, this); 54435 this.triggerElement = $(triggerElementSelector); 54436 this.currentPage = this.triggerElement.data('current-page'); 54437 this.totalPages = this.triggerElement.data('total-pages'); 54438 this.loopPages = this.triggerElement.data('loop-pages'); 54439 this.firstPage = this.currentPage; 54440 this.loadPath = this.triggerElement.data('load-path'); 54441 this.loadContainer = $(this.triggerElement.data('load-container')); 54442 this.loader = $(this.triggerElement.data('loader')); 54443 this.afterFetchCallbacks = []; 54444 $(document).on('scroll', this.onScroll); 54445 } 54446 54447 InfiniteScroller.prototype.onScroll = function() { 54448 if (this.triggerElement.isOnScreen()) { 54449 return this.fetchNewPage(); 54450 } 54451 }; 54452 54453 InfiniteScroller.prototype.hasNextPage = function() { 54454 if (this.loopPages) { 54455 return !this.pagesOverflow && this.nextPage() > this.currentPage || (this.nextPage() < this.firstPage); 54456 } else { 54457 return (this.totalPages == null) || this.nextPage() <= this.totalPages; 54458 } 54459 }; 54460 54461 InfiniteScroller.prototype.nextPage = function() { 54462 if (this.loopPages && (this.totalPages != null) && this.currentPage + 1 > this.totalPages) { 54463 return 1; 54464 } else { 54465 return this.currentPage + 1; 54466 } 54467 }; 54468 54469 InfiniteScroller.prototype.fetchNewPage = function() { 54470 if (!(this.canFetch && this.hasNextPage())) { 54471 return; 54472 } 54473 this.loader.fadeIn(); 54474 this.canFetch = false; 54475 this.loader.fadeIn(); 54476 this.currentPage = this.nextPage(); 54477 if (this.currentPage === 1) { 54478 this.pagesOverflow = true; 54479 } 54480 return $.ajax({ 54481 url: this.loadPath, 54482 data: { 54483 page: this.currentPage, 54484 skip_layout: true 54485 }, 54486 complete: (function(_this) { 54487 return function(data) { 54488 _this.loader.fadeOut(); 54489 _.each(_this.afterFetchCallbacks, function(callback) { 54490 return typeof callback === "function" ? callback(data.responseText) : void 0; 54491 }); 54492 return _this.canFetch = true; 54493 }; 54494 })(this) 54495 }); 54496 }; 54497 54498 InfiniteScroller.prototype.newPage = function(html) { 54499 _.each(this.afterFetchCallbacks, function(callback) { 54500 return typeof callback === "function" ? callback(html) : void 0; 54501 }); 54502 return this.canFetch = true; 54503 }; 54504 54505 InfiniteScroller.prototype.afterNewPageFetch = function(callback) { 54506 return this.afterFetchCallbacks.push(callback); 54507 }; 54508 54509 return InfiniteScroller; 54510 54511 })(); 54512 54513}).call(this); 54514(function() { 54515 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54516 hasProp = {}.hasOwnProperty; 54517 54518 App.Pages.GalleriesIndex = (function(superClass) { 54519 extend(GalleriesIndex, superClass); 54520 54521 function GalleriesIndex() { 54522 return GalleriesIndex.__super__.constructor.apply(this, arguments); 54523 } 54524 54525 GalleriesIndex.prototype.widgets = ['likes']; 54526 54527 GalleriesIndex.prototype.initialize = function() { 54528 this.infiniteScroll = new App.Modules.InfiniteScroller('.js-infinite-scroll-trigger'); 54529 this.initPlugins(); 54530 return this.bindEvents(); 54531 }; 54532 54533 GalleriesIndex.prototype.bindEvents = function() { 54534 $('.js-category-link, .js-tabs li, .js-link-to-content').on('click', this.showUpdatingSpinner); 54535 return this.infiniteScroll.afterNewPageFetch((function(_this) { 54536 return function(html) { 54537 return _this.initializeNewItems(html); 54538 }; 54539 })(this)); 54540 }; 54541 54542 GalleriesIndex.prototype.initPlugins = function() { 54543 this.$container = $('.js-gallery-items'); 54544 return imagesLoaded(this.$container, (function(_this) { 54545 return function() { 54546 var items; 54547 _this.$container.masonry({ 54548 selector: '.js-gallery-item' 54549 }); 54550 items = _this.$container.masonry('getItemElements'); 54551 _this.masonryItems = _.map(items, function(item) { 54552 return _this.$container.masonry('getItem', item); 54553 }); 54554 return _this.$container.masonry('layout'); 54555 }; 54556 })(this)); 54557 }; 54558 54559 GalleriesIndex.prototype.initializeNewItems = function(html) { 54560 var $newItems; 54561 $newItems = $(html); 54562 return imagesLoaded($newItems, (function(_this) { 54563 return function() { 54564 _this.$container.append($newItems).masonry('appended', $newItems, true); 54565 return App.events.publish('app:likes:bind', $newItems); 54566 }; 54567 })(this)); 54568 }; 54569 54570 GalleriesIndex.prototype.showUpdatingSpinner = function() { 54571 return $('.js-main-content').addClass('is-updating-with-spinner spinner--top is-fixed'); 54572 }; 54573 54574 return GalleriesIndex; 54575 54576 })(App.Core.Page); 54577 54578}).call(this); 54579(function() { 54580 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54581 hasProp = {}.hasOwnProperty; 54582 54583 App.Pages.GalleriesShow = (function(superClass) { 54584 extend(GalleriesShow, superClass); 54585 54586 function GalleriesShow() { 54587 return GalleriesShow.__super__.constructor.apply(this, arguments); 54588 } 54589 54590 GalleriesShow.prototype.widgets = ['comments', 'likes']; 54591 54592 return GalleriesShow; 54593 54594 })(App.Core.Page); 54595 54596}).call(this); 54597(function() { 54598 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54599 hasProp = {}.hasOwnProperty; 54600 54601 App.Pages.Global = (function(superClass) { 54602 extend(Global, superClass); 54603 54604 function Global() { 54605 return Global.__super__.constructor.apply(this, arguments); 54606 } 54607 54608 Global.prototype.widgets = ['anchorsManager', 'authControl', 'pinger', 'notification', 'autoDisableLink', 'backendEvents', 'buyButton', 'cookiesPolicy', 'pushNotifications', 'paymentAgreement', 'tipForDesigner', 'topNavigation', 'searchItems', 'potentialBuyerManager', 'translationsNotice']; 54609 54610 return Global; 54611 54612 })(App.Core.Page); 54613 54614}).call(this); 54615(function() { 54616 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 54617 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54618 hasProp = {}.hasOwnProperty; 54619 54620 App.Pages.HomeIndex = (function(superClass) { 54621 extend(HomeIndex, superClass); 54622 54623 function HomeIndex() { 54624 this.carouselNext = bind(this.carouselNext, this); 54625 this.carouselPrevious = bind(this.carouselPrevious, this); 54626 return HomeIndex.__super__.constructor.apply(this, arguments); 54627 } 54628 54629 HomeIndex.prototype.widgets = ['linkFaker', 'categoriesContainerTracking']; 54630 54631 HomeIndex.prototype.initialize = function() { 54632 this.bindEvents(); 54633 this.initCarousel(); 54634 this.openSupportWidget();
54635 return new LazyLoad({ 54636 elements_selector: '.js-lazy-img' 54637 }); 54638 }; 54639 54640 HomeIndex.prototype.bindEvents = function() { 54641 $('.js-header-block').hover(this.onHeaderBlockHover, this.onHeaderBlockHoverOut); 54642 $('.js-carousel-previous').click(this.carouselPrevious); 54643 return $('.js-carousel-next').click(this.carouselNext); 54644 }; 54645 54646 HomeIndex.prototype.onHeaderBlockHover = function(e) { 54647 var $target; 54648 $target = $($(e.currentTarget).data('target')); 54649 return $target.addClass('is-hover'); 54650 }; 54651 54652 HomeIndex.prototype.onHeaderBlockHoverOut = function(e) { 54653 var $target; 54654 $target = $($(e.currentTarget).data('target')); 54655 return $target.removeClass('is-hover'); 54656 }; 54657 54658 HomeIndex.prototype.initCarousel = function() { 54659 var itemWidth; 54660 itemWidth = $('.category-item').width(); 54661 return this.properties = { 54662 carouselWidth: itemWidth * $('.category-item').length, 54663 containerWidth: $('.categories-carousel').width(), 54664 items: $('.category-item').length, 54665 itemWidth: itemWidth, 54666 offsetWidth: $('.carousel__nav-left').width(), 54667 left: 0, 54668 step: itemWidth * 3 54669 }; 54670 }; 54671 54672 HomeIndex.prototype.carouselPrevious = function(e) { 54673 e.preventDefault(); 54674 return this.moveCarousel('left'); 54675 }; 54676 54677 HomeIndex.prototype.carouselNext = function(e) { 54678 e.preventDefault(); 54679 return this.moveCarousel('right'); 54680 }; 54681 54682 HomeIndex.prototype.moveCarousel = function(direction) { 54683 var leftPosition, offset; 54684 offset = 0; 54685 if (-this.properties.left === 0) { 54686 offset = this.properties.offsetWidth; 54687 } 54688 if (direction === 'left') { 54689 if (-this.properties.left > this.properties.step) { 54690 leftPosition = this.properties.left + this.properties.step; 54691 } else { 54692 leftPosition = 0; 54693 } 54694 } else { 54695 if ((this.properties.carouselWidth + this.properties.left) > (this.properties.containerWidth + this.properties.step)) { 54696 leftPosition = this.properties.left - this.properties.step + offset; 54697 } else { 54698 leftPosition = this.properties.left - (this.properties.carouselWidth + this.properties.left - this.properties.containerWidth); 54699 } 54700 } 54701 this.properties.left = leftPosition; 54702 $('.categories-list').css({ 54703 left: leftPosition 54704 }); 54705 return this.evalCarouselParams(); 54706 }; 54707 54708 HomeIndex.prototype.evalCarouselParams = function() { 54709 if (this.properties.left < 0) { 54710 $('.carousel__nav-left').css({ 54711 display: 'inline' 54712 }); 54713 } else { 54714 $('.carousel__nav-left').css({ 54715 display: 'none' 54716 }); 54717 } 54718 if ((this.properties.carouselWidth + this.properties.left) === this.properties.containerWidth) { 54719 return $('.carousel__nav-right').css({ 54720 display: 'none' 54721 }); 54722 } else { 54723 return $('.carousel__nav-right').css({ 54724 display: 'inline' 54725 }); 54726 } 54727 }; 54728 54729 HomeIndex.prototype.openSupportWidget = function() { 54730 if (window.location.hash === '#support' && typeof zE !== "undefined") { 54731 return setTimeout(function() { 54732 return zE('webWidget', 'open'); 54733 }, 2000); 54734 } else { 54735 return setTimeout((function(_this) { 54736 return function() { 54737 return _this.openSupportWidget(); 54738 }; 54739 })(this), 1000); 54740 } 54741 }; 54742 54743 return HomeIndex; 54744 54745 })(App.Core.Page); 54746 54747}).call(this); 54748(function() { 54749 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54750 hasProp = {}.hasOwnProperty; 54751 54752 App.Pages.InstantCheckoutPayment = (function(superClass) { 54753 extend(InstantCheckoutPayment, superClass); 54754 54755 function InstantCheckoutPayment() { 54756 return InstantCheckoutPayment.__super__.constructor.apply(this, arguments); 54757 } 54758 54759 InstantCheckoutPayment.prototype.initialize = function() { 54760 this.initBuyerType(); 54761 this.bindApplyCompanyInformation(); 54762 this.bindTabClick(); 54763 this.openRequiredTab(); 54764 return this.initCountrySelection(); 54765 }; 54766 54767 return InstantCheckoutPayment; 54768 54769 })(App.Pages.CheckoutPayment); 54770 54771}).call(this); 54772(function() { 54773 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54774 hasProp = {}.hasOwnProperty; 54775 54776 App.Pages.InstantCheckoutPlaceOrder = (function(superClass) { 54777 extend(InstantCheckoutPlaceOrder, superClass); 54778 54779 function InstantCheckoutPlaceOrder() { 54780 return InstantCheckoutPlaceOrder.__super__.constructor.apply(this, arguments); 54781 } 54782 54783 return InstantCheckoutPlaceOrder; 54784 54785 })(App.Pages.InstantCheckoutPayment); 54786 54787}).call(this); 54788(function() { 54789 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 54790 hasProp = {}.hasOwnProperty; 54791 54792 App.Pages.ItemFilesIndex = (function(superClass) { 54793 extend(ItemFilesIndex, superClass); 54794 54795 function ItemFilesIndex() { 54796 return ItemFilesIndex.__super__.constructor.apply(this, arguments); 54797 } 54798 54799 ItemFilesIndex.prototype.widgets = ['freeDownloadLink']; 54800 54801 ItemFilesIndex.prototype.initialize = function() { 54802 var $countdown, counter, fadeInDelay, fadeOutDelay; 54803 counter = App.config.environment === 'test' ? 1 : 20; 54804 $countdown = $('.countdown'); 54805 fadeOutDelay = App.config.environment === 'test' ? 1000 : 20000; 54806 fadeInDelay = App.config.environment === 'test' ? 1600 : 20600; 54807 setInterval((function() { 54808 counter--; 54809 if (counter < 0) { 54810 clearInterval; 54811 } else { 54812 $countdown.text("Please wait " + counter + " seconds..."); 54813 } 54814 }), 1000); 54815 $('.preloader--free-models').delay(fadeOutDelay).fadeOut('slow'); 54816 $('.details-box').delay(fadeInDelay).removeClass('is-hidden').fadeIn('slow'); 54817 return this.initiateSimilarProductsLoader(); 54818 }; 54819 54820 ItemFilesIndex.prototype.initiateSimilarProductsLoader = function() { 54821 return $.getScript("/items/" + gon.product_id + "/similar-products"); 54822 }; 54823 54824 return ItemFilesIndex; 54825 54826 })(App.Core.Page); 54827 54828}).call(this); 54829/*! nouislider - 8.5.1 - 2016-04-24 16:00:29 */ 54830 54831 54832(function (factory) { 54833 54834 if ( typeof define === 'function' && define.amd ) { 54835 54836 // AMD. Register as an anonymous module. 54837 define([], factory); 54838 54839 } else if ( typeof exports === 'object' ) { 54840 54841 // Node/CommonJS 54842 module.exports = factory(); 54843 54844 } else { 54845 54846 // Browser globals 54847 window.noUiSlider = factory(); 54848 } 54849 54850}(function( ){ 54851 54852 'use strict'; 54853 54854 54855 // Removes duplicates from an array.
54856 function unique(array) { 54857 return array.filter(function(a){ 54858 return !this[a] ? this[a] = true : false; 54859 }, {}); 54860 } 54861 54862 // Round a value to the closest 'to'. 54863 function closest ( value, to ) { 54864 return Math.round(value / to) * to; 54865 } 54866 54867 // Current position of an element relative to the document. 54868 function offset ( elem ) { 54869 54870 var rect = elem.getBoundingClientRect(), 54871 doc = elem.ownerDocument, 54872 docElem = doc.documentElement, 54873 pageOffset = getPageOffset(); 54874 54875 // getBoundingClientRect contains left scroll in Chrome on Android. 54876 // I haven't found a feature detection that proves this. Worst case 54877 // scenario on mis-match: the 'tap' feature on horizontal sliders breaks. 54878 if ( /webkit.*Chrome.*Mobile/i.test(navigator.userAgent) ) { 54879 pageOffset.x = 0; 54880 } 54881 54882 return { 54883 top: rect.top + pageOffset.y - docElem.clientTop, 54884 left: rect.left + pageOffset.x - docElem.clientLeft 54885 }; 54886 } 54887 54888 // Checks whether a value is numerical. 54889 function isNumeric ( a ) { 54890 return typeof a === 'number' && !isNaN( a ) && isFinite( a ); 54891 } 54892 54893 // Sets a class and removes it after [duration] ms. 54894 function addClassFor ( element, className, duration ) { 54895 addClass(element, className); 54896 setTimeout(function(){ 54897 removeClass(element, className); 54898 }, duration); 54899 } 54900 54901 // Limits a value to 0 - 100 54902 function limit ( a ) { 54903 return Math.max(Math.min(a, 100), 0); 54904 } 54905 54906 // Wraps a variable as an array, if it isn't one yet. 54907 function asArray ( a ) { 54908 return Array.isArray(a) ? a : [a]; 54909 } 54910 54911 // Counts decimals 54912 function countDecimals ( numStr ) { 54913 var pieces = numStr.split("."); 54914 return pieces.length > 1 ? pieces[1].length : 0; 54915 } 54916 54917 // http://youmightnotneedjquery.com/#add_class 54918 function addClass ( el, className ) { 54919 if ( el.classList ) { 54920 el.classList.add(className); 54921 } else { 54922 el.className += ' ' + className; 54923 } 54924 } 54925 54926 // http://youmightnotneedjquery.com/#remove_class 54927 function removeClass ( el, className ) { 54928 if ( el.classList ) { 54929 el.classList.remove(className); 54930 } else { 54931 el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); 54932 } 54933 } 54934 54935 // https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/ 54936 function hasClass ( el, className ) { 54937 return el.classList ? el.classList.contains(className) : new RegExp('\\b' + className + '\\b').test(el.className); 54938 } 54939 54940 // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes 54941 function getPageOffset ( ) { 54942 54943 var supportPageOffset = window.pageXOffset !== undefined, 54944 isCSS1Compat = ((document.compatMode || "") === "CSS1Compat"), 54945 x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft, 54946 y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop; 54947 54948 return { 54949 x: x, 54950 y: y 54951 }; 54952 } 54953 54954 // we provide a function to compute constants instead 54955 // of accessing window.* as soon as the module needs it 54956 // so that we do not compute anything if not needed 54957 function getActions ( ) { 54958 54959 // Determine the events to bind. IE11 implements pointerEvents without 54960 // a prefix, which breaks compatibility with the IE10 implementation. 54961 return window.navigator.pointerEnabled ? { 54962 start: 'pointerdown', 54963 move: 'pointermove', 54964 end: 'pointerup' 54965 } : window.navigator.msPointerEnabled ? { 54966 start: 'MSPointerDown', 54967 move: 'MSPointerMove', 54968 end: 'MSPointerUp' 54969 } : { 54970 start: 'mousedown touchstart', 54971 move: 'mousemove touchmove', 54972 end: 'mouseup touchend' 54973 }; 54974 } 54975 54976 54977// Value calculation 54978 54979 // Determine the size of a sub-range in relation to a full range. 54980 function subRangeRatio ( pa, pb ) { 54981 return (100 / (pb - pa)); 54982 } 54983 54984 // (percentage) How many percent is this value of this range? 54985 function fromPercentage ( range, value ) { 54986 return (value * 100) / ( range[1] - range[0] ); 54987 } 54988 54989 // (percentage) Where is this value on this range? 54990 function toPercentage ( range, value ) { 54991 return fromPercentage( range, range[0] < 0 ? 54992 value + Math.abs(range[0]) : 54993 value - range[0] ); 54994 } 54995 54996 // (value) How much is this percentage on this range? 54997 function isPercentage ( range, value ) { 54998 return ((value * ( range[1] - range[0] )) / 100) + range[0]; 54999 } 55000 55001 55002// Range conversion 55003 55004 function getJ ( value, arr ) { 55005 55006 var j = 1; 55007 55008 while ( value >= arr[j] ){ 55009 j += 1; 55010 } 55011 55012 return j; 55013 } 55014 55015 // (percentage) Input a value, find where, on a scale of 0-100, it applies. 55016 function toStepping ( xVal, xPct, value ) { 55017 55018 if ( value >= xVal.slice(-1)[0] ){ 55019 return 100; 55020 } 55021 55022 var j = getJ( value, xVal ), va, vb, pa, pb; 55023 55024 va = xVal[j-1]; 55025 vb = xVal[j]; 55026 pa = xPct[j-1]; 55027 pb = xPct[j]; 55028 55029 return pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb)); 55030 } 55031 55032 // (value) Input a percentage, find where it is on the specified range. 55033 function fromStepping ( xVal, xPct, value ) { 55034 55035 // There is no range group that fits 100 55036 if ( value >= 100 ){ 55037 return xVal.slice(-1)[0]; 55038 } 55039 55040 var j = getJ( value, xPct ), va, vb, pa, pb; 55041 55042 va = xVal[j-1]; 55043 vb = xVal[j]; 55044 pa = xPct[j-1]; 55045 pb = xPct[j]; 55046 55047 return isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb)); 55048 } 55049 55050 // (percentage) Get the step that applies at a certain value. 55051 function getStep ( xPct, xSteps, snap, value ) { 55052 55053 if ( value === 100 ) { 55054 return value; 55055 } 55056 55057 var j = getJ( value, xPct ), a, b; 55058 55059 // If 'snap' is set, steps are used as fixed points on the slider. 55060 if ( snap ) { 55061 55062 a = xPct[j-1]; 55063 b = xPct[j]; 55064 55065 // Find the closest position, a or b. 55066 if ((value - a) > ((b-a)/2)){ 55067 return b; 55068 } 55069 55070 return a; 55071 } 55072 55073 if ( !xSteps[j-1] ){ 55074 return value; 55075 } 55076 55077 return xPct[j-1] + closest( 55078 value - xPct[j-1], 55079 xSteps[j-1] 55080 ); 55081 } 55082 55083 55084// Entry parsing 55085 55086 function handleEntryPoint ( index, value, that ) { 55087 55088 var percentage; 55089 55090 // Wrap numerical input in an array.
55091 if ( typeof value === "number" ) { 55092 value = [value]; 55093 } 55094 55095 // Reject any invalid input, by testing whether value is an array. 55096 if ( Object.prototype.toString.call( value ) !== '[object Array]' ){ 55097 throw new Error("noUiSlider: 'range' contains invalid value."); 55098 } 55099 55100 // Covert min/max syntax to 0 and 100. 55101 if ( index === 'min' ) { 55102 percentage = 0; 55103 } else if ( index === 'max' ) { 55104 percentage = 100; 55105 } else { 55106 percentage = parseFloat( index ); 55107 } 55108 55109 // Check for correct input. 55110 if ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) { 55111 throw new Error("noUiSlider: 'range' value isn't numeric."); 55112 } 55113 55114 // Store values. 55115 that.xPct.push( percentage ); 55116 that.xVal.push( value[0] ); 55117 55118 // NaN will evaluate to false too, but to keep 55119 // logging clear, set step explicitly. Make sure 55120 // not to override the 'step' setting with false. 55121 if ( !percentage ) { 55122 if ( !isNaN( value[1] ) ) { 55123 that.xSteps[0] = value[1]; 55124 } 55125 } else { 55126 that.xSteps.push( isNaN(value[1]) ? false : value[1] ); 55127 } 55128 } 55129 55130 function handleStepPoint ( i, n, that ) { 55131 55132 // Ignore 'false' stepping. 55133 if ( !n ) { 55134 return true; 55135 } 55136 55137 // Factor to range ratio 55138 that.xSteps[i] = fromPercentage([ 55139 that.xVal[i] 55140 ,that.xVal[i+1] 55141 ], n) / subRangeRatio ( 55142 that.xPct[i], 55143 that.xPct[i+1] ); 55144 } 55145 55146 55147// Interface 55148 55149 // The interface to Spectrum handles all direction-based 55150 // conversions, so the above values are unaware. 55151 55152 function Spectrum ( entry, snap, direction, singleStep ) { 55153 55154 this.xPct = []; 55155 this.xVal = []; 55156 this.xSteps = [ singleStep || false ]; 55157 this.xNumSteps = [ false ]; 55158 55159 this.snap = snap; 55160 this.direction = direction; 55161 55162 var index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ]; 55163 55164 // Map the object keys to an array. 55165 for ( index in entry ) { 55166 if ( entry.hasOwnProperty(index) ) { 55167 ordered.push([entry[index], index]); 55168 } 55169 } 55170 55171 // Sort all entries by value (numeric sort). 55172 if ( ordered.length && typeof ordered[0][0] === "object" ) { 55173 ordered.sort(function(a, b) { return a[0][0] - b[0][0]; }); 55174 } else { 55175 ordered.sort(function(a, b) { return a[0] - b[0]; }); 55176 } 55177 55178 55179 // Convert all entries to subranges. 55180 for ( index = 0; index < ordered.length; index++ ) { 55181 handleEntryPoint(ordered[index][1], ordered[index][0], this); 55182 } 55183 55184 // Store the actual step values. 55185 // xSteps is sorted in the same order as xPct and xVal. 55186 this.xNumSteps = this.xSteps.slice(0); 55187 55188 // Convert all numeric steps to the percentage of the subrange they represent. 55189 for ( index = 0; index < this.xNumSteps.length; index++ ) { 55190 handleStepPoint(index, this.xNumSteps[index], this); 55191 } 55192 } 55193 55194 Spectrum.prototype.getMargin = function ( value ) { 55195 return this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false; 55196 }; 55197 55198 Spectrum.prototype.toStepping = function ( value ) { 55199 55200 value = toStepping( this.xVal, this.xPct, value ); 55201 55202 // Invert the value if this is a right-to-left slider. 55203 if ( this.direction ) { 55204 value = 100 - value; 55205 } 55206 55207 return value; 55208 }; 55209 55210 Spectrum.prototype.fromStepping = function ( value ) { 55211 55212 // Invert the value if this is a right-to-left slider. 55213 if ( this.direction ) { 55214 value = 100 - value; 55215 } 55216 55217 return fromStepping( this.xVal, this.xPct, value ); 55218 }; 55219 55220 Spectrum.prototype.getStep = function ( value ) { 55221 55222 // Find the proper step for rtl sliders by search in inverse direction. 55223 // Fixes issue #262. 55224 if ( this.direction ) { 55225 value = 100 - value; 55226 } 55227 55228 value = getStep(this.xPct, this.xSteps, this.snap, value ); 55229 55230 if ( this.direction ) { 55231 value = 100 - value; 55232 } 55233 55234 return value; 55235 }; 55236 55237 Spectrum.prototype.getApplicableStep = function ( value ) { 55238 55239 // If the value is 100%, return the negative step twice. 55240 var j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1; 55241 return [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]]; 55242 }; 55243 55244 // Outside testing 55245 Spectrum.prototype.convert = function ( value ) {
55246 return this.getStep(this.toStepping(value)); 55247 }; 55248 55249/* Every input option is tested and parsed. This'll prevent 55250 endless validation in internal methods. These tests are 55251 structured with an item for every option available. An 55252 option can be marked as required by setting the 'r' flag. 55253 The testing function is provided with three arguments: 55254 - The provided value for the option; 55255 - A reference to the options object; 55256 - The name for the option; 55257 55258 The testing function returns false when an error is detected, 55259 or true when everything is OK. It can also modify the option 55260 object, to make sure all values can be correctly looped elsewhere. */ 55261 55262 var defaultFormatter = { 'to': function( value ){ 55263 return value !== undefined && value.toFixed(2); 55264 }, 'from': Number }; 55265 55266 function testStep ( parsed, entry ) { 55267 55268 if ( !isNumeric( entry ) ) { 55269 throw new Error("noUiSlider: 'step' is not numeric."); 55270 } 55271 55272 // The step option can still be used to set stepping 55273 // for linear sliders. Overwritten if set in 'range'. 55274 parsed.singleStep = entry; 55275 } 55276 55277 function testRange ( parsed, entry ) { 55278 55279 // Filter incorrect input. 55280 if ( typeof entry !== 'object' || Array.isArray(entry) ) { 55281 throw new Error("noUiSlider: 'range' is not an object."); 55282 } 55283 55284 // Catch missing start or end. 55285 if ( entry.min === undefined || entry.max === undefined ) { 55286 throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'."); 55287 } 55288 55289 // Catch equal start or end. 55290 if ( entry.min === entry.max ) { 55291 throw new Error("noUiSlider: 'range' 'min' and 'max' cannot be equal."); 55292 } 55293 55294 parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep); 55295 } 55296 55297 function testStart ( parsed, entry ) { 55298 55299 entry = asArray(entry); 55300 55301 // Validate input. Values aren't tested, as the public .val method 55302 // will always provide a valid location. 55303 if ( !Array.isArray( entry ) || !entry.length || entry.length > 2 ) { 55304 throw new Error("noUiSlider: 'start' option is incorrect."); 55305 } 55306 55307 // Store the number of handles. 55308 parsed.handles = entry.length; 55309 55310 // When the slider is initialized, the .val method will 55311 // be called with the start options. 55312 parsed.start = entry; 55313 } 55314 55315 function testSnap ( parsed, entry ) { 55316 55317 // Enforce 100% stepping within subranges. 55318 parsed.snap = entry; 55319 55320 if ( typeof entry !== 'boolean' ){ 55321 throw new Error("noUiSlider: 'snap' option must be a boolean."); 55322 } 55323 } 55324 55325 function testAnimate ( parsed, entry ) { 55326 55327 // Enforce 100% stepping within subranges. 55328 parsed.animate = entry; 55329 55330 if ( typeof entry !== 'boolean' ){ 55331 throw new Error("noUiSlider: 'animate' option must be a boolean."); 55332 } 55333 } 55334 55335 function testAnimationDuration ( parsed, entry ) { 55336 55337 parsed.animationDuration = entry; 55338 55339 if ( typeof entry !== 'number' ){ 55340 throw new Error("noUiSlider: 'animationDuration' option must be a number."); 55341 } 55342 } 55343 55344 function testConnect ( parsed, entry ) { 55345 55346 if ( entry === 'lower' && parsed.handles === 1 ) { 55347 parsed.connect = 1; 55348 } else if ( entry === 'upper' && parsed.handles === 1 ) { 55349 parsed.connect = 2; 55350 } else if ( entry === true && parsed.handles === 2 ) { 55351 parsed.connect = 3; 55352 } else if ( entry === false ) { 55353 parsed.connect = 0; 55354 } else { 55355 throw new Error("noUiSlider: 'connect' option doesn't match handle count."); 55356 } 55357 } 55358 55359 function testOrientation ( parsed, entry ) { 55360 55361 // Set orientation to an a numerical value for easy 55362 // array selection. 55363 switch ( entry ){ 55364 case 'horizontal': 55365 parsed.ort = 0; 55366 break; 55367 case 'vertical': 55368 parsed.ort = 1; 55369 break; 55370 default: 55371 throw new Error("noUiSlider: 'orientation' option is invalid."); 55372 } 55373 } 55374 55375 function testMargin ( parsed, entry ) { 55376 55377 if ( !isNumeric(entry) ){ 55378 throw new Error("noUiSlider: 'margin' option must be numeric."); 55379 } 55380 55381 // Issue #582 55382 if ( entry === 0 ) { 55383 return; 55384 } 55385 55386 parsed.margin = parsed.spectrum.getMargin(entry); 55387 55388 if ( !parsed.margin ) { 55389 throw new Error("noUiSlider: 'margin' option is only supported on linear sliders."); 55390 } 55391 } 55392 55393 function testLimit ( parsed, entry ) { 55394 55395 if ( !isNumeric(entry) ){ 55396 throw new Error("noUiSlider: 'limit' option must be numeric."); 55397 } 55398 55399 parsed.limit = parsed.spectrum.getMargin(entry); 55400 55401 if ( !parsed.limit ) { 55402 throw new Error("noUiSlider: 'limit' option is only supported on linear sliders."); 55403 } 55404 } 55405 55406 function testDirection ( parsed, entry ) { 55407 55408 // Set direction as a numerical value for easy parsing.
55409 // Invert connection for RTL sliders, so that the proper 55410 // handles get the connect/background classes. 55411 switch ( entry ) { 55412 case 'ltr': 55413 parsed.dir = 0; 55414 break; 55415 case 'rtl': 55416 parsed.dir = 1; 55417 parsed.connect = [0,2,1,3][parsed.connect]; 55418 break; 55419 default: 55420 throw new Error("noUiSlider: 'direction' option was not recognized."); 55421 } 55422 } 55423 55424 function testBehaviour ( parsed, entry ) { 55425 55426 // Make sure the input is a string. 55427 if ( typeof entry !== 'string' ) { 55428 throw new Error("noUiSlider: 'behaviour' must be a string containing options."); 55429 } 55430 55431 // Check if the string contains any keywords. 55432 // None are required. 55433 var tap = entry.indexOf('tap') >= 0, 55434 drag = entry.indexOf('drag') >= 0, 55435 fixed = entry.indexOf('fixed') >= 0, 55436 snap = entry.indexOf('snap') >= 0, 55437 hover = entry.indexOf('hover') >= 0; 55438 55439 // Fix #472 55440 if ( drag && !parsed.connect ) { 55441 throw new Error("noUiSlider: 'drag' behaviour must be used with 'connect': true."); 55442 } 55443 55444 parsed.events = { 55445 tap: tap || snap, 55446 drag: drag, 55447 fixed: fixed, 55448 snap: snap, 55449 hover: hover 55450 }; 55451 } 55452 55453 function testTooltips ( parsed, entry ) { 55454 55455 var i; 55456 55457 if ( entry === false ) { 55458 return; 55459 } else if ( entry === true ) { 55460 55461 parsed.tooltips = []; 55462 55463 for ( i = 0; i < parsed.handles; i++ ) { 55464 parsed.tooltips.push(true); 55465 } 55466 55467 } else { 55468 55469 parsed.tooltips = asArray(entry); 55470 55471 if ( parsed.tooltips.length !== parsed.handles ) { 55472 throw new Error("noUiSlider: must pass a formatter for all handles."); 55473 } 55474 55475 parsed.tooltips.forEach(function(formatter){ 55476 if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) { 55477 throw new Error("noUiSlider: 'tooltips' must be passed a formatter or 'false'."); 55478 } 55479 }); 55480 } 55481 } 55482 55483 function testFormat ( parsed, entry ) { 55484 55485 parsed.format = entry; 55486 55487 // Any object with a to and from method is supported. 55488 if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) { 55489 return true; 55490 } 55491 55492 throw new Error("noUiSlider: 'format' requires 'to' and 'from' methods."); 55493 } 55494 55495 function testCssPrefix ( parsed, entry ) { 55496 55497 if ( entry !== undefined && typeof entry !== 'string' && entry !== false ) { 55498 throw new Error("noUiSlider: 'cssPrefix' must be a string or `false`."); 55499 } 55500 55501 parsed.cssPrefix = entry; 55502 } 55503
55504 function testCssClasses ( parsed, entry ) { 55505 55506 if ( entry !== undefined && typeof entry !== 'object' ) { 55507 throw new Error("noUiSlider: 'cssClasses' must be an object."); 55508 } 55509 55510 if ( typeof parsed.cssPrefix === 'string' ) { 55511 parsed.cssClasses = {}; 55512 55513 for ( var key in entry ) { 55514 if ( !entry.hasOwnProperty(key) ) { continue; } 55515 55516 parsed.cssClasses[key] = parsed.cssPrefix + entry[key]; 55517 } 55518 } else { 55519 parsed.cssClasses = entry; 55520 } 55521 } 55522 55523 // Test all developer settings and parse to assumption-safe values. 55524 function testOptions ( options ) { 55525 55526 // To prove a fix for #537, freeze options here. 55527 // If the object is modified, an error will be thrown. 55528 // Object.freeze(options); 55529 55530 var parsed = { 55531 margin: 0, 55532 limit: 0, 55533 animate: true, 55534 animationDuration: 300, 55535 format: defaultFormatter 55536 }, tests; 55537 55538 // Tests are executed in the order they are presented here. 55539 tests = { 55540 'step': { r: false, t: testStep }, 55541 'start': { r: true, t: testStart }, 55542 'connect': { r: true, t: testConnect }, 55543 'direction': { r: true, t: testDirection }, 55544 'snap': { r: false, t: testSnap }, 55545 'animate': { r: false, t: testAnimate }, 55546 'animationDuration': { r: false, t: testAnimationDuration }, 55547 'range': { r: true, t: testRange }, 55548 'orientation': { r: false, t: testOrientation }, 55549 'margin': { r: false, t: testMargin }, 55550 'limit': { r: false, t: testLimit }, 55551 'behaviour': { r: true, t: testBehaviour }, 55552 'format': { r: false, t: testFormat }, 55553 'tooltips': { r: false, t: testTooltips }, 55554 'cssPrefix': { r: false, t: testCssPrefix },
55555 'cssClasses': { r: false, t: testCssClasses } 55556 }; 55557 55558 var defaults = { 55559 'connect': false, 55560 'direction': 'ltr', 55561 'behaviour': 'tap', 55562 'orientation': 'horizontal', 55563 'cssPrefix' : 'noUi-', 55564 'cssClasses': { 55565 target: 'target', 55566 base: 'base', 55567 origin: 'origin', 55568 handle: 'handle', 55569 handleLower: 'handle-lower', 55570 handleUpper: 'handle-upper', 55571 horizontal: 'horizontal', 55572 vertical: 'vertical', 55573 background: 'background', 55574 connect: 'connect', 55575 ltr: 'ltr', 55576 rtl: 'rtl', 55577 draggable: 'draggable', 55578 drag: 'state-drag', 55579 tap: 'state-tap', 55580 active: 'active', 55581 stacking: 'stacking', 55582 tooltip: 'tooltip', 55583 pips: 'pips', 55584 pipsHorizontal: 'pips-horizontal', 55585 pipsVertical: 'pips-vertical', 55586 marker: 'marker', 55587 markerHorizontal: 'marker-horizontal', 55588 markerVertical: 'marker-vertical', 55589 markerNormal: 'marker-normal', 55590 markerLarge: 'marker-large', 55591 markerSub: 'marker-sub', 55592 value: 'value', 55593 valueHorizontal: 'value-horizontal', 55594 valueVertical: 'value-vertical', 55595 valueNormal: 'value-normal', 55596 valueLarge: 'value-large', 55597 valueSub: 'value-sub' 55598 } 55599 }; 55600 55601 // Run all options through a testing mechanism to ensure correct 55602 // input. It should be noted that options might get modified to 55603 // be handled properly. E.g. wrapping integers in arrays. 55604 Object.keys(tests).forEach(function( name ){ 55605 55606 // If the option isn't set, but it is required, throw an error. 55607 if ( options[name] === undefined && defaults[name] === undefined ) { 55608 55609 if ( tests[name].r ) { 55610 throw new Error("noUiSlider: '" + name + "' is required."); 55611 } 55612 55613 return true; 55614 } 55615 55616 tests[name].t( parsed, options[name] === undefined ? defaults[name] : options[name] ); 55617 }); 55618 55619 // Forward pips options 55620 parsed.pips = options.pips; 55621 55622 // Pre-define the styles. 55623 parsed.style = parsed.ort ? 'top' : 'left'; 55624 55625 return parsed; 55626 } 55627 55628 55629function closure ( target, options, originalOptions ){ 55630 var 55631 actions = getActions( ), 55632 // All variables local to 'closure' are prefixed with 'scope_' 55633 scope_Target = target, 55634 scope_Locations = [-1, -1], 55635 scope_Base, 55636 scope_Handles, 55637 scope_Spectrum = options.spectrum, 55638 scope_Values = [], 55639 scope_Events = {}, 55640 scope_Self; 55641 55642 55643 // Delimit proposed values for handle positions. 55644 function getPositions ( a, b, delimit ) { 55645 55646 // Add movement to current position. 55647 var c = a + b[0], d = a + b[1]; 55648 55649 // Only alter the other position on drag, 55650 // not on standard sliding. 55651 if ( delimit ) { 55652 if ( c < 0 ) { 55653 d += Math.abs(c); 55654 } 55655 if ( d > 100 ) { 55656 c -= ( d - 100 ); 55657 } 55658 55659 // Limit values to 0 and 100. 55660 return [limit(c), limit(d)]; 55661 } 55662 55663 return [c,d]; 55664 } 55665 55666 // Provide a clean event with standardized offset values. 55667 function fixEvent ( e, pageOffset ) { 55668 55669 // Prevent scrolling and panning on touch events, while 55670 // attempting to slide. The tap event also depends on this. 55671 e.preventDefault(); 55672 55673 // Filter the event to register the type, which can be 55674 // touch, mouse or pointer. Offset changes need to be 55675 // made on an event specific basis. 55676 var touch = e.type.indexOf('touch') === 0, 55677 mouse = e.type.indexOf('mouse') === 0, 55678 pointer = e.type.indexOf('pointer') === 0, 55679 x,y, event = e; 55680 55681 // IE10 implemented pointer events with a prefix; 55682 if ( e.type.indexOf('MSPointer') === 0 ) { 55683 pointer = true; 55684 } 55685 55686 if ( touch ) { 55687 // noUiSlider supports one movement at a time, 55688 // so we can select the first 'changedTouch'. 55689 x = e.changedTouches[0].pageX; 55690 y = e.changedTouches[0].pageY; 55691 } 55692 55693 pageOffset = pageOffset || getPageOffset(); 55694 55695 if ( mouse || pointer ) { 55696 x = e.clientX + pageOffset.x; 55697 y = e.clientY + pageOffset.y; 55698 } 55699 55700 event.pageOffset = pageOffset; 55701 event.points = [x, y]; 55702 event.cursor = mouse || pointer; // Fix #435 55703 55704 return event; 55705 } 55706 55707 // Append a handle to the base. 55708 function addHandle ( direction, index ) { 55709 55710 var origin = document.createElement('div'), 55711 handle = document.createElement('div'),
55712 classModifier = [options.cssClasses.handleLower, options.cssClasses.handleUpper]; 55713 55714 if ( direction ) { 55715 classModifier.reverse(); 55716 } 55717 55718 addClass(handle, options.cssClasses.handle); 55719 addClass(handle, classModifier[index]); 55720 55721 addClass(origin, options.cssClasses.origin); 55722 origin.appendChild(handle); 55723 55724 return origin; 55725 } 55726 55727 // Add the proper connection classes. 55728 function addConnection ( connect, target, handles ) { 55729 55730 // Apply the required connection classes to the elements 55731 // that need them. Some classes are made up for several 55732 // segments listed in the class list, to allow easy 55733 // renaming and provide a minor compression benefit. 55734 switch ( connect ) { 55735 case 1: addClass(target, options.cssClasses.connect); 55736 addClass(handles[0], options.cssClasses.background); 55737 break; 55738 case 3: addClass(handles[1], options.cssClasses.background); 55739 /* falls through */ 55740 case 2: addClass(handles[0], options.cssClasses.connect); 55741 /* falls through */ 55742 case 0: addClass(target, options.cssClasses.background); 55743 break; 55744 } 55745 } 55746 55747 // Add handles to the slider base. 55748 function addHandles ( nrHandles, direction, base ) { 55749 55750 var index, handles = []; 55751 55752 // Append handles. 55753 for ( index = 0; index < nrHandles; index += 1 ) { 55754 55755 // Keep a list of all added handles. 55756 handles.push( base.appendChild(addHandle( direction, index )) ); 55757 } 55758 55759 return handles; 55760 } 55761 55762 // Initialize a single slider. 55763 function addSlider ( direction, orientation, target ) { 55764 55765 // Apply classes and data to the target. 55766 addClass(target, options.cssClasses.target); 55767 55768 if ( direction === 0 ) { 55769 addClass(target, options.cssClasses.ltr); 55770 } else { 55771 addClass(target, options.cssClasses.rtl); 55772 } 55773 55774 if ( orientation === 0 ) { 55775 addClass(target, options.cssClasses.horizontal); 55776 } else { 55777 addClass(target, options.cssClasses.vertical); 55778 } 55779 55780 var div = document.createElement('div'); 55781 addClass(div, options.cssClasses.base); 55782 target.appendChild(div); 55783 return div; 55784 } 55785 55786 55787 function addTooltip ( handle, index ) { 55788 55789 if ( !options.tooltips[index] ) { 55790 return false; 55791 } 55792 55793 var element = document.createElement('div'); 55794 element.className = options.cssClasses.tooltip; 55795 return handle.firstChild.appendChild(element); 55796 } 55797 55798 // The tooltips option is a shorthand for using the 'update' event. 55799 function tooltips ( ) { 55800 55801 if ( options.dir ) { 55802 options.tooltips.reverse(); 55803 } 55804 55805 // Tooltips are added with options.tooltips in original order. 55806 var tips = scope_Handles.map(addTooltip); 55807 55808 if ( options.dir ) { 55809 tips.reverse(); 55810 options.tooltips.reverse(); 55811 } 55812 55813 bindEvent('update', function(f, o, r) { 55814 if ( tips[o] ) { 55815 tips[o].innerHTML = options.tooltips[o] === true ? f[o] : options.tooltips[o].to(r[o]); 55816 } 55817 }); 55818 } 55819 55820 55821 function getGroup ( mode, values, stepped ) { 55822 55823 // Use the range. 55824 if ( mode === 'range' || mode === 'steps' ) { 55825 return scope_Spectrum.xVal; 55826 } 55827 55828 if ( mode === 'count' ) { 55829 55830 // Divide 0 - 100 in 'count' parts. 55831 var spread = ( 100 / (values-1) ), v, i = 0; 55832 values = []; 55833 55834 // List these parts and have them handled as 'positions'. 55835 while ((v=i++*spread) <= 100 ) { 55836 values.push(v); 55837 } 55838 55839 mode = 'positions'; 55840 } 55841 55842 if ( mode === 'positions' ) { 55843 55844 // Map all percentages to on-range values. 55845 return values.map(function( value ){ 55846 return scope_Spectrum.fromStepping( stepped ? scope_Spectrum.getStep( value ) : value ); 55847 }); 55848 } 55849 55850 if ( mode === 'values' ) { 55851 55852 // If the value must be stepped, it needs to be converted to a percentage first. 55853 if ( stepped ) { 55854 55855 return values.map(function( value ){ 55856 55857 // Convert to percentage, apply step, return to value. 55858 return scope_Spectrum.fromStepping( scope_Spectrum.getStep( scope_Spectrum.toStepping( value ) ) ); 55859 }); 55860 55861 } 55862 55863 // Otherwise, we can simply use the values. 55864 return values; 55865 } 55866 } 55867 55868 function generateSpread ( density, mode, group ) { 55869 55870 function safeIncrement(value, increment) { 55871 // Avoid floating point variance by dropping the smallest decimal places. 55872 return (value + increment).toFixed(7) / 1; 55873 } 55874 55875 var originalSpectrumDirection = scope_Spectrum.direction, 55876 indexes = {}, 55877 firstInRange = scope_Spectrum.xVal[0], 55878 lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length-1], 55879 ignoreFirst = false, 55880 ignoreLast = false, 55881 prevPct = 0; 55882 55883 // This function loops the spectrum in an ltr linear fashion, 55884 // while the toStepping method is direction aware. Trick it into 55885 // believing it is ltr. 55886 scope_Spectrum.direction = 0; 55887 55888 // Create a copy of the group, sort it and filter away all duplicates. 55889 group = unique(group.slice().sort(function(a, b){ return a - b; })); 55890 55891 // Make sure the range starts with the first element. 55892 if ( group[0] !== firstInRange ) { 55893 group.unshift(firstInRange); 55894 ignoreFirst = true; 55895 } 55896 55897 // Likewise for the last one. 55898 if ( group[group.length - 1] !== lastInRange ) { 55899 group.push(lastInRange); 55900 ignoreLast = true; 55901 } 55902 55903 group.forEach(function ( current, index ) { 55904 55905 // Get the current step and the lower + upper positions. 55906 var step, i, q, 55907 low = current, 55908 high = group[index+1], 55909 newPct, pctDifference, pctPos, type, 55910 steps, realSteps, stepsize; 55911 55912 // When using 'steps' mode, use the provided steps. 55913 // Otherwise, we'll step on to the next subrange. 55914 if ( mode === 'steps' ) { 55915 step = scope_Spectrum.xNumSteps[ index ]; 55916 } 55917 55918 // Default to a 'full' step. 55919 if ( !step ) { 55920 step = high-low; 55921 } 55922 55923 // Low can be 0, so test for false. If high is undefined, 55924 // we are at the last subrange. Index 0 is already handled. 55925 if ( low === false || high === undefined ) { 55926 return; 55927 } 55928 55929 // Find all steps in the subrange. 55930 for ( i = low; i <= high; i = safeIncrement(i, step) ) { 55931 55932 // Get the percentage value for the current step, 55933 // calculate the size for the subrange. 55934 newPct = scope_Spectrum.toStepping( i ); 55935 pctDifference = newPct - prevPct; 55936 55937 steps = pctDifference / density; 55938 realSteps = Math.round(steps); 55939 55940 // This ratio represents the ammount of percentage-space a point indicates. 55941 // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided. 55942 // Round the percentage offset to an even number, then divide by two 55943 // to spread the offset on both sides of the range. 55944 stepsize = pctDifference/realSteps; 55945 55946 // Divide all points evenly, adding the correct number to this subrange. 55947 // Run up to <= so that 100% gets a point, event if ignoreLast is set. 55948 for ( q = 1; q <= realSteps; q += 1 ) { 55949 55950 // The ratio between the rounded value and the actual size might be ~1% off. 55951 // Correct the percentage offset by the number of points 55952 // per subrange. density = 1 will result in 100 points on the 55953 // full range, 2 for 50, 4 for 25, etc. 55954 pctPos = prevPct + ( q * stepsize ); 55955 indexes[pctPos.toFixed(5)] = ['x', 0]; 55956 } 55957 55958 // Determine the point type. 55959 type = (group.indexOf(i) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 ); 55960 55961 // Enforce the 'ignoreFirst' option by overwriting the type for 0. 55962 if ( !index && ignoreFirst ) { 55963 type = 0; 55964 } 55965 55966 if ( !(i === high && ignoreLast)) { 55967 // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value. 55968 indexes[newPct.toFixed(5)] = [i, type]; 55969 } 55970 55971 // Update the percentage count. 55972 prevPct = newPct; 55973 } 55974 }); 55975 55976 // Reset the spectrum. 55977 scope_Spectrum.direction = originalSpectrumDirection; 55978 55979 return indexes; 55980 } 55981 55982 function addMarking ( spread, filterFunc, formatter ) { 55983 55984 var element = document.createElement('div'), 55985 out = '', 55986 valueSizeClasses = [
55987 options.cssClasses.valueNormal, 55988 options.cssClasses.valueLarge, 55989 options.cssClasses.valueSub 55990 ], 55991 markerSizeClasses = [ 55992 options.cssClasses.markerNormal, 55993 options.cssClasses.markerLarge, 55994 options.cssClasses.markerSub 55995 ], 55996 valueOrientationClasses = [ 55997 options.cssClasses.valueHorizontal, 55998 options.cssClasses.valueVertical 55999 ], 56000 markerOrientationClasses = [ 56001 options.cssClasses.markerHorizontal, 56002 options.cssClasses.markerVertical 56003 ]; 56004 56005 addClass(element, options.cssClasses.pips); 56006 addClass(element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical); 56007 56008 function getClasses( type, source ){ 56009 var a = source === options.cssClasses.value, 56010 orientationClasses = a ? valueOrientationClasses : markerOrientationClasses, 56011 sizeClasses = a ? valueSizeClasses : markerSizeClasses; 56012 56013 return source + ' ' + orientationClasses[options.ort] + ' ' + sizeClasses[type]; 56014 } 56015 56016 function getTags( offset, source, values ) { 56017 return 'class="' + getClasses(values[1], source) + '" style="' + options.style + ': ' + offset + '%"'; 56018 } 56019 56020 function addSpread ( offset, values ){ 56021 56022 if ( scope_Spectrum.direction ) { 56023 offset = 100 - offset; 56024 } 56025 56026 // Apply the filter function, if it is set. 56027 values[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1]; 56028 56029 // Add a marker for every point 56030 out += '<div ' + getTags(offset, options.cssClasses.marker, values) + '></div>'; 56031 56032 // Values are only appended for points marked '1' or '2'. 56033 if ( values[1] ) { 56034 out += '<div ' + getTags(offset, options.cssClasses.value, values) + '>' + formatter.to(values[0]) + '</div>'; 56035 } 56036 } 56037 56038 // Append all points. 56039 Object.keys(spread).forEach(function(a){ 56040 addSpread(a, spread[a]); 56041 }); 56042 56043 element.innerHTML = out; 56044 56045 return element; 56046 } 56047 56048 function pips ( grid ) { 56049 56050 var mode = grid.mode, 56051 density = grid.density || 1, 56052 filter = grid.filter || false, 56053 values = grid.values || false, 56054 stepped = grid.stepped || false, 56055 group = getGroup( mode, values, stepped ), 56056 spread = generateSpread( density, mode, group ), 56057 format = grid.format || { 56058 to: Math.round 56059 }; 56060 56061 return scope_Target.appendChild(addMarking( 56062 spread, 56063 filter, 56064 format 56065 )); 56066 } 56067 56068 56069 // Shorthand for base dimensions. 56070 function baseSize ( ) { 56071 var rect = scope_Base.getBoundingClientRect(), alt = 'offset' + ['Width', 'Height'][options.ort]; 56072 return options.ort === 0 ? (rect.width||scope_Base[alt]) : (rect.height||scope_Base[alt]); 56073 } 56074 56075 // External event handling 56076 function fireEvent ( event, handleNumber, tap ) { 56077 56078 var i; 56079 56080 // During initialization, do not fire events. 56081 for ( i = 0; i < options.handles; i++ ) { 56082 if ( scope_Locations[i] === -1 ) { 56083 return; 56084 } 56085 } 56086 56087 if ( handleNumber !== undefined && options.handles !== 1 ) { 56088 handleNumber = Math.abs(handleNumber - options.dir); 56089 } 56090 56091 Object.keys(scope_Events).forEach(function( targetEvent ) { 56092 56093 var eventType = targetEvent.split('.')[0]; 56094 56095 if ( event === eventType ) { 56096 scope_Events[targetEvent].forEach(function( callback ) { 56097 56098 callback.call( 56099 // Use the slider public API as the scope ('this') 56100 scope_Self, 56101 // Return values as array, so arg_1[arg_2] is always valid. 56102 asArray(valueGet()), 56103 // Handle index, 0 or 1 56104 handleNumber, 56105 // Unformatted slider values 56106 asArray(inSliderOrder(Array.prototype.slice.call(scope_Values))), 56107 // Event is fired by tap, true or false 56108 tap || false, 56109 // Left offset of the handle, in relation to the slider 56110 scope_Locations 56111 ); 56112 }); 56113 } 56114 }); 56115 } 56116 56117 // Returns the input array, respecting the slider direction configuration. 56118 function inSliderOrder ( values ) { 56119 56120 // If only one handle is used, return a single value. 56121 if ( values.length === 1 ){ 56122 return values[0]; 56123 } 56124 56125 if ( options.dir ) { 56126 return values.reverse(); 56127 } 56128 56129 return values; 56130 } 56131 56132 56133 // Handler for attaching events trough a proxy. 56134 function attach ( events, element, callback, data ) { 56135 56136 // This function can be used to 'filter' events to the slider. 56137 // element is a node, not a nodeList 56138 56139 var method = function ( e ){ 56140 56141 if ( scope_Target.hasAttribute('disabled') ) { 56142 return false;
56143 } 56144 56145 // Stop if an active 'tap' transition is taking place. 56146 if ( hasClass(scope_Target, options.cssClasses.tap) ) { 56147 return false; 56148 } 56149 56150 e = fixEvent(e, data.pageOffset); 56151 56152 // Ignore right or middle clicks on start #454 56153 if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) { 56154 return false; 56155 } 56156 56157 // Ignore right or middle clicks on start #454 56158 if ( data.hover && e.buttons ) { 56159 return false; 56160 } 56161 56162 e.calcPoint = e.points[ options.ort ]; 56163 56164 // Call the event handler with the event [ and additional data ]. 56165 callback ( e, data ); 56166 56167 }, methods = []; 56168 56169 // Bind a closure on the target for every event type. 56170 events.split(' ').forEach(function( eventName ){ 56171 element.addEventListener(eventName, method, false); 56172 methods.push([eventName, method]); 56173 }); 56174 56175 return methods; 56176 } 56177 56178 // Handle movement on document for handle and range drag. 56179 function move ( event, data ) { 56180 56181 // Fix #498 56182 // Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty). 56183 // https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero 56184 // IE9 has .buttons and .which zero on mousemove. 56185 // Firefox breaks the spec MDN defines. 56186 if ( navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) { 56187 return end(event, data); 56188 } 56189 56190 var handles = data.handles || scope_Handles, positions, state = false, 56191 proposal = ((event.calcPoint - data.start) * 100) / data.baseSize, 56192 handleNumber = handles[0] === scope_Handles[0] ? 0 : 1, i; 56193 56194 // Calculate relative positions for the handles. 56195 positions = getPositions( proposal, data.positions, handles.length > 1); 56196 56197 state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 ); 56198 56199 if ( handles.length > 1 ) { 56200 56201 state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state; 56202 56203 if ( state ) { 56204 // fire for both handles 56205 for ( i = 0; i < data.handles.length; i++ ) { 56206 fireEvent('slide', i); 56207 } 56208 } 56209 } else if ( state ) { 56210 // Fire for a single handle 56211 fireEvent('slide', handleNumber); 56212 } 56213 } 56214 56215 // Unbind move events on document, call callbacks. 56216 function end ( event, data ) { 56217 56218 // The handle is no longer active, so remove the class. 56219 var active = scope_Base.querySelector( '.' + options.cssClasses.active ), 56220 handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1; 56221 56222 if ( active !== null ) { 56223 removeClass(active, options.cssClasses.active); 56224 } 56225 56226 // Remove cursor styles and text-selection events bound to the body. 56227 if ( event.cursor ) { 56228 document.body.style.cursor = ''; 56229 document.body.removeEventListener('selectstart', document.body.noUiListener); 56230 } 56231 56232 var d = document.documentElement; 56233 56234 // Unbind the move and end events, which are added on 'start'. 56235 d.noUiListeners.forEach(function( c ) { 56236 d.removeEventListener(c[0], c[1]); 56237 }); 56238 56239 // Remove dragging class. 56240 removeClass(scope_Target, options.cssClasses.drag); 56241 56242 // Fire the change and set events. 56243 fireEvent('set', handleNumber); 56244 fireEvent('change', handleNumber); 56245 56246 // If this is a standard handle movement, fire the end event. 56247 if ( data.handleNumber !== undefined ) { 56248 fireEvent('end', data.handleNumber); 56249 } 56250 } 56251 56252 // Fire 'end' when a mouse or pen leaves the document. 56253 function documentLeave ( event, data ) { 56254 if ( event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null ){ 56255 end ( event, data ); 56256 } 56257 } 56258 56259 // Bind move events on document. 56260 function start ( event, data ) { 56261 56262 var d = document.documentElement; 56263 56264 // Mark the handle as 'active' so it can be styled. 56265 if ( data.handles.length === 1 ) { 56266 // Support 'disabled' handles 56267 if ( data.handles[0].hasAttribute('disabled') ) { 56268 return false; 56269 } 56270
56271 addClass(data.handles[0].children[0], options.cssClasses.active); 56272 } 56273 56274 // Fix #551, where a handle gets selected instead of dragged. 56275 event.preventDefault(); 56276 56277 // A drag should never propagate up to the 'tap' event. 56278 event.stopPropagation(); 56279 56280 // Attach the move and end events. 56281 var moveEvent = attach(actions.move, d, move, { 56282 start: event.calcPoint, 56283 baseSize: baseSize(), 56284 pageOffset: event.pageOffset, 56285 handles: data.handles, 56286 handleNumber: data.handleNumber, 56287 buttonsProperty: event.buttons, 56288 positions: [ 56289 scope_Locations[0], 56290 scope_Locations[scope_Handles.length - 1] 56291 ] 56292 }), endEvent = attach(actions.end, d, end, { 56293 handles: data.handles, 56294 handleNumber: data.handleNumber 56295 }); 56296 56297 var outEvent = attach("mouseout", d, documentLeave, { 56298 handles: data.handles, 56299 handleNumber: data.handleNumber 56300 }); 56301 56302 d.noUiListeners = moveEvent.concat(endEvent, outEvent); 56303 56304 // Text selection isn't an issue on touch devices, 56305 // so adding cursor styles can be skipped. 56306 if ( event.cursor ) { 56307 56308 // Prevent the 'I' cursor and extend the range-drag cursor. 56309 document.body.style.cursor = getComputedStyle(event.target).cursor; 56310 56311 // Mark the target with a dragging state. 56312 if ( scope_Handles.length > 1 ) { 56313 addClass(scope_Target, options.cssClasses.drag); 56314 } 56315 56316 var f = function(){ 56317 return false; 56318 }; 56319 56320 document.body.noUiListener = f; 56321 56322 // Prevent text selection when dragging the handles. 56323 document.body.addEventListener('selectstart', f, false); 56324 } 56325 56326 if ( data.handleNumber !== undefined ) { 56327 fireEvent('start', data.handleNumber); 56328 } 56329 } 56330 56331 // Move closest handle to tapped location. 56332 function tap ( event ) { 56333 56334 var location = event.calcPoint, total = 0, handleNumber, to; 56335 56336 // The tap event shouldn't propagate up and cause 'edge' to run. 56337 event.stopPropagation(); 56338 56339 // Add up the handle offsets. 56340 scope_Handles.forEach(function(a){ 56341 total += offset(a)[ options.style ]; 56342 }); 56343 56344 // Find the handle closest to the tapped position. 56345 handleNumber = ( location < total/2 || scope_Handles.length === 1 ) ? 0 : 1; 56346 56347 // Check if handler is not disablet if yes set number to the next handler 56348 if (scope_Handles[handleNumber].hasAttribute('disabled')) { 56349 handleNumber = handleNumber ? 0 : 1; 56350 } 56351 56352 location -= offset(scope_Base)[ options.style ]; 56353 56354 // Calculate the new position. 56355 to = ( location * 100 ) / baseSize(); 56356 56357 if ( !options.events.snap ) { 56358 // Flag the slider as it is now in a transitional state. 56359 // Transition takes a configurable amount of ms (default 300). Re-enable the slider after that. 56360 addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration ); 56361 } 56362 56363 // Support 'disabled' handles 56364 if ( scope_Handles[handleNumber].hasAttribute('disabled') ) { 56365 return false; 56366 } 56367 56368 // Find the closest handle and calculate the tapped point. 56369 // The set handle to the new position. 56370 setHandle( scope_Handles[handleNumber], to ); 56371 56372 fireEvent('slide', handleNumber, true); 56373 fireEvent('set', handleNumber, true); 56374 fireEvent('change', handleNumber, true); 56375 56376 if ( options.events.snap ) { 56377 start(event, { handles: [scope_Handles[handleNumber]] }); 56378 } 56379 } 56380 56381 // Fires a 'hover' event for a hovered mouse/pen position. 56382 function hover ( event ) { 56383 56384 var location = event.calcPoint - offset(scope_Base)[ options.style ], 56385 to = scope_Spectrum.getStep(( location * 100 ) / baseSize()), 56386 value = scope_Spectrum.fromStepping( to ); 56387 56388 Object.keys(scope_Events).forEach(function( targetEvent ) { 56389 if ( 'hover' === targetEvent.split('.')[0] ) { 56390 scope_Events[targetEvent].forEach(function( callback ) { 56391 callback.call( scope_Self, value ); 56392 }); 56393 } 56394 }); 56395 } 56396 56397 // Attach events to several slider parts. 56398 function events ( behaviour ) { 56399 56400 // Attach the standard drag event to the handles. 56401 if ( !behaviour.fixed ) { 56402
56403 scope_Handles.forEach(function( handle, index ){ 56404 56405 // These events are only bound to the visual handle 56406 // element, not the 'real' origin element. 56407 attach ( actions.start, handle.children[0], start, { 56408 handles: [ handle ], 56409 handleNumber: index 56410 }); 56411 }); 56412 } 56413 56414 // Attach the tap event to the slider base. 56415 if ( behaviour.tap ) { 56416 56417 attach ( actions.start, scope_Base, tap, { 56418 handles: scope_Handles 56419 }); 56420 } 56421 56422 // Fire hover events 56423 if ( behaviour.hover ) { 56424 attach ( actions.move, scope_Base, hover, { hover: true } ); 56425 } 56426 56427 // Make the range draggable. 56428 if ( behaviour.drag ){ 56429 56430 var drag = [scope_Base.querySelector( '.' + options.cssClasses.connect )]; 56431 addClass(drag[0], options.cssClasses.draggable); 56432 56433 // When the range is fixed, the entire range can 56434 // be dragged by the handles. The handle in the first 56435 // origin will propagate the start event upward, 56436 // but it needs to be bound manually on the other. 56437 if ( behaviour.fixed ) { 56438 drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]); 56439 } 56440 56441 drag.forEach(function( element ) { 56442 attach ( actions.start, element, start, { 56443 handles: scope_Handles 56444 }); 56445 }); 56446 } 56447 } 56448 56449 56450 // Test suggested values and apply margin, step. 56451 function setHandle ( handle, to, noLimitOption ) { 56452 56453 var trigger = handle !== scope_Handles[0] ? 1 : 0, 56454 lowerMargin = scope_Locations[0] + options.margin, 56455 upperMargin = scope_Locations[1] - options.margin, 56456 lowerLimit = scope_Locations[0] + options.limit, 56457 upperLimit = scope_Locations[1] - options.limit; 56458 56459 // For sliders with multiple handles, 56460 // limit movement to the other handle. 56461 // Apply the margin option by adding it to the handle positions. 56462 if ( scope_Handles.length > 1 ) { 56463 to = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin ); 56464 } 56465 56466 // The limit option has the opposite effect, limiting handles to a 56467 // maximum distance from another. Limit must be > 0, as otherwise 56468 // handles would be unmoveable. 'noLimitOption' is set to 'false' 56469 // for the .val() method, except for pass 4/4. 56470 if ( noLimitOption !== false && options.limit && scope_Handles.length > 1 ) { 56471 to = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit ); 56472 } 56473 56474 // Handle the step option. 56475 to = scope_Spectrum.getStep( to ); 56476 56477 // Limit percentage to the 0 - 100 range 56478 to = limit(to); 56479 56480 // Return false if handle can't move 56481 if ( to === scope_Locations[trigger] ) { 56482 return false; 56483 } 56484 56485 // Set the handle to the new position. 56486 // Use requestAnimationFrame for efficient painting. 56487 // No significant effect in Chrome, Edge sees dramatic 56488 // performace improvements. 56489 if ( window.requestAnimationFrame ) { 56490 window.requestAnimationFrame(function(){ 56491 handle.style[options.style] = to + '%'; 56492 }); 56493 } else { 56494 handle.style[options.style] = to + '%'; 56495 } 56496 56497 // Force proper handle stacking 56498 if ( !handle.previousSibling ) { 56499 removeClass(handle, options.cssClasses.stacking); 56500 if ( to > 50 ) { 56501 addClass(handle, options.cssClasses.stacking); 56502 } 56503 } 56504 56505 // Update locations. 56506 scope_Locations[trigger] = to; 56507 56508 // Convert the value to the slider stepping/range. 56509 scope_Values[trigger] = scope_Spectrum.fromStepping( to ); 56510 56511 fireEvent('update', trigger); 56512 56513 return true; 56514 } 56515 56516 // Loop values from value method and apply them. 56517 function setValues ( count, values ) { 56518 56519 var i, trigger, to; 56520 56521 // With the limit option, we'll need another limiting pass. 56522 if ( options.limit ) { 56523 count += 1; 56524 } 56525 56526 // If there are multiple handles to be set run the setting 56527 // mechanism twice for the first handle, to make sure it 56528 // can be bounced of the second one properly. 56529 for ( i = 0; i < count; i += 1 ) { 56530 56531 trigger = i%2; 56532 56533 // Get the current argument from the array. 56534 to = values[trigger]; 56535 56536 // Setting with null indicates an 'ignore'.
56537 // Inputting 'false' is invalid. 56538 if ( to !== null && to !== false ) { 56539 56540 // If a formatted number was passed, attemt to decode it. 56541 if ( typeof to === 'number' ) { 56542 to = String(to); 56543 } 56544 56545 to = options.format.from( to ); 56546 56547 // Request an update for all links if the value was invalid. 56548 // Do so too if setting the handle fails. 56549 if ( to === false || isNaN(to) || setHandle( scope_Handles[trigger], scope_Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) { 56550 fireEvent('update', trigger); 56551 } 56552 } 56553 } 56554 } 56555 56556 // Set the slider value. 56557 function valueSet ( input, fireSetEvent ) { 56558 56559 var count, values = asArray( input ), i; 56560 56561 // Event fires by default 56562 fireSetEvent = (fireSetEvent === undefined ? true : !!fireSetEvent); 56563 56564 // The RTL settings is implemented by reversing the front-end, 56565 // internal mechanisms are the same. 56566 if ( options.dir && options.handles > 1 ) { 56567 values.reverse(); 56568 } 56569 56570 // Animation is optional. 56571 // Make sure the initial values where set before using animated placement. 56572 if ( options.animate && scope_Locations[0] !== -1 ) { 56573 addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration ); 56574 } 56575 56576 // Determine how often to set the handles. 56577 count = scope_Handles.length > 1 ? 3 : 1; 56578 56579 if ( values.length === 1 ) { 56580 count = 1; 56581 } 56582 56583 setValues ( count, values ); 56584 56585 // Fire the 'set' event for both handles. 56586 for ( i = 0; i < scope_Handles.length; i++ ) { 56587 56588 // Fire the event only for handles that received a new value, as per #579 56589 if ( values[i] !== null && fireSetEvent ) { 56590 fireEvent('set', i); 56591 } 56592 } 56593 } 56594 56595 // Get the slider value. 56596 function valueGet ( ) { 56597 56598 var i, retour = []; 56599 56600 // Get the value from all handles. 56601 for ( i = 0; i < options.handles; i += 1 ){ 56602 retour[i] = options.format.to( scope_Values[i] ); 56603 } 56604 56605 return inSliderOrder( retour ); 56606 } 56607 56608 // Removes classes from the root and empties it. 56609 function destroy ( ) { 56610 56611 for ( var key in options.cssClasses ) { 56612 if ( !options.cssClasses.hasOwnProperty(key) ) { continue; } 56613 removeClass(scope_Target, options.cssClasses[key]); 56614 } 56615 56616 while (scope_Target.firstChild) { 56617 scope_Target.removeChild(scope_Target.firstChild); 56618 } 56619 56620 delete scope_Target.noUiSlider; 56621 } 56622 56623 // Get the current step size for the slider. 56624 function getCurrentStep ( ) { 56625 56626 // Check all locations, map them to their stepping point. 56627 // Get the step point, then find it in the input list. 56628 var retour = scope_Locations.map(function( location, index ){ 56629 56630 var step = scope_Spectrum.getApplicableStep( location ), 56631 56632 // As per #391, the comparison for the decrement step can have some rounding issues. 56633 // Round the value to the precision used in the step. 56634 stepDecimals = countDecimals(String(step[2])), 56635 56636 // Get the current numeric value 56637 value = scope_Values[index], 56638 56639 // To move the slider 'one step up', the current step value needs to be added. 56640 // Use null if we are at the maximum slider value. 56641 increment = location === 100 ? null : step[2], 56642 56643 // Going 'one step down' might put the slider in a different sub-range, so we 56644 // need to switch between the current or the previous step. 56645 prev = Number((value - step[2]).toFixed(stepDecimals)), 56646 56647 // If the value fits the step, return the current step value. Otherwise, use the 56648 // previous step. Return null if the slider is at its minimum value. 56649 decrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false); 56650 56651 return [decrement, increment]; 56652 }); 56653 56654 // Return values in the proper order. 56655 return inSliderOrder( retour ); 56656 } 56657 56658 // Attach an event to this slider, possibly including a namespace 56659 function bindEvent ( namespacedEvent, callback ) { 56660 scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || []; 56661 scope_Events[namespacedEvent].push(callback); 56662 56663 // If the event bound is 'update,' fire it immediately for all handles.
56664 if ( namespacedEvent.split('.')[0] === 'update' ) { 56665 scope_Handles.forEach(function(a, index){ 56666 fireEvent('update', index); 56667 }); 56668 } 56669 } 56670 56671 // Undo attachment of event 56672 function removeEvent ( namespacedEvent ) { 56673 56674 var event = namespacedEvent && namespacedEvent.split('.')[0], 56675 namespace = event && namespacedEvent.substring(event.length); 56676 56677 Object.keys(scope_Events).forEach(function( bind ){ 56678 56679 var tEvent = bind.split('.')[0], 56680 tNamespace = bind.substring(tEvent.length); 56681 56682 if ( (!event || event === tEvent) && (!namespace || namespace === tNamespace) ) { 56683 delete scope_Events[bind]; 56684 } 56685 }); 56686 } 56687 56688 // Updateable: margin, limit, step, range, animate, snap 56689 function updateOptions ( optionsToUpdate, fireSetEvent ) { 56690 56691 // Spectrum is created using the range, snap, direction and step options. 56692 // 'snap' and 'step' can be updated, 'direction' cannot, due to event binding. 56693 // If 'snap' and 'step' are not passed, they should remain unchanged. 56694 var v = valueGet(), newOptions = testOptions({ 56695 start: [0, 0], 56696 margin: optionsToUpdate.margin, 56697 limit: optionsToUpdate.limit, 56698 step: optionsToUpdate.step === undefined ? options.singleStep : optionsToUpdate.step, 56699 range: optionsToUpdate.range, 56700 animate: optionsToUpdate.animate, 56701 snap: optionsToUpdate.snap === undefined ? options.snap : optionsToUpdate.snap 56702 }); 56703 56704 ['margin', 'limit', 'range', 'animate'].forEach(function(name){ 56705 56706 // Only change options that we're actually passed to update. 56707 if ( optionsToUpdate[name] !== undefined ) { 56708 options[name] = optionsToUpdate[name]; 56709 } 56710 }); 56711 56712 // Save current spectrum direction as testOptions in testRange call 56713 // doesn't rely on current direction 56714 newOptions.spectrum.direction = scope_Spectrum.direction; 56715 scope_Spectrum = newOptions.spectrum; 56716 56717 // Invalidate the current positioning so valueSet forces an update. 56718 scope_Locations = [-1, -1]; 56719 valueSet(optionsToUpdate.start || v, fireSetEvent); 56720 } 56721 56722 56723 // Throw an error if the slider was already initialized. 56724 if ( scope_Target.noUiSlider ) { 56725 throw new Error('Slider was already initialized.'); 56726 } 56727 56728 // Create the base element, initialise HTML and set classes. 56729 // Add handles and links. 56730 scope_Base = addSlider( options.dir, options.ort, scope_Target ); 56731 scope_Handles = addHandles( options.handles, options.dir, scope_Base ); 56732 56733 // Set the connect classes. 56734 addConnection ( options.connect, scope_Target, scope_Handles ); 56735 56736 if ( options.pips ) { 56737 pips(options.pips); 56738 } 56739 56740 if ( options.tooltips ) { 56741 tooltips(); 56742 } 56743 56744 scope_Self = { 56745 destroy: destroy, 56746 steps: getCurrentStep, 56747 on: bindEvent, 56748 off: removeEvent, 56749 get: valueGet, 56750 set: valueSet, 56751 updateOptions: updateOptions, 56752 options: originalOptions, // Issue #600 56753 target: scope_Target, // Issue #597 56754 pips: pips // Issue #594 56755 }; 56756 56757 // Attach user events. 56758 events( options.events ); 56759 56760 return scope_Self; 56761 56762} 56763 56764 56765 // Run the standard initializer 56766 function initialize ( target, originalOptions ) { 56767 56768 if ( !target.nodeName ) { 56769 throw new Error('noUiSlider.create requires a single element.'); 56770 } 56771 56772 // Test the options and create the slider environment; 56773 var options = testOptions( originalOptions, target ), 56774 slider = closure( target, options, originalOptions ); 56775 56776 // Use the public value method to set the start values. 56777 slider.set(options.start); 56778 56779 target.noUiSlider = slider; 56780 return slider; 56781 } 56782 56783 // Use an object instead of a function for future expansibility; 56784 return { 56785 create: initialize 56786 }; 56787 56788})); 56789/*! 56790 * jQuery.scrollTo 56791 * Copyright (c) 2007 Ariel Flesler - aflesler â gmail ⢠com | https://github.com/flesler 56792 * Licensed under MIT 56793 * https://github.com/flesler/jquery.scrollTo 56794 * @projectDescription Lightweight, cross-browser and highly customizable animated scrolling with jQuery 56795 * @author Ariel Flesler 56796 * @version 2.1.2 56797 */ 56798 56799;(function(factory) { 56800 'use strict'; 56801 if (typeof define === 'function' && define.amd) { 56802 // AMD 56803 define(['jquery'], factory); 56804 } else if (typeof module !== 'undefined' && module.exports) { 56805 // CommonJS 56806 module.exports = factory(require('jquery')); 56807 } else { 56808 // Global 56809 factory(jQuery); 56810 } 56811})(function($) { 56812 'use strict'; 56813 56814 var $scrollTo = $.scrollTo = function(target, duration, settings) { 56815 return $(window).scrollTo(target, duration, settings); 56816 }; 56817 56818 $scrollTo.defaults = { 56819 axis:'xy', 56820 duration: 0, 56821 limit:true 56822 }; 56823 56824 function isWin(elem) { 56825 return !elem.nodeName || 56826 $.inArray(elem.nodeName.toLowerCase(), ['iframe','#document','html','body']) !== -1; 56827 } 56828 56829 $.fn.scrollTo = function(target, duration, settings) { 56830 if (typeof duration === 'object') { 56831 settings = duration; 56832 duration = 0; 56833 } 56834 if (typeof settings === 'function') { 56835 settings = { onAfter:settings }; 56836 } 56837 if (target === 'max') { 56838 target = 9e9; 56839 } 56840 56841 settings = $.extend({}, $scrollTo.defaults, settings); 56842 // Speed is still recognized for backwards compatibility 56843 duration = duration || settings.duration; 56844 // Make sure the settings are given right 56845 var queue = settings.queue && settings.axis.length > 1; 56846 if (queue) { 56847 // Let's keep the overall duration 56848 duration /= 2; 56849 } 56850 settings.offset = both(settings.offset); 56851 settings.over = both(settings.over); 56852 56853 return this.each(function() { 56854 // Null target yields nothing, just like jQuery does 56855 if (target === null) return; 56856 56857 var win = isWin(this), 56858 elem = win ? this.contentWindow || window : this, 56859 $elem = $(elem), 56860 targ = target, 56861 attr = {}, 56862 toff; 56863 56864 switch (typeof targ) { 56865 // A number will pass the regex 56866 case 'number': 56867 case 'string': 56868 if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) { 56869 targ = both(targ); 56870 // We are done 56871 break; 56872 } 56873 // Relative/Absolute selector 56874 targ = win ? $(targ) : $(targ, elem); 56875 /* falls through */
56876 case 'object': 56877 if (targ.length === 0) return; 56878 // DOMElement / jQuery 56879 if (targ.is || targ.style) { 56880 // Get the real position of the target 56881 toff = (targ = $(targ)).offset(); 56882 } 56883 } 56884 56885 var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset; 56886 56887 $.each(settings.axis.split(''), function(i, axis) { 56888 var Pos = axis === 'x' ? 'Left' : 'Top', 56889 pos = Pos.toLowerCase(), 56890 key = 'scroll' + Pos, 56891 prev = $elem[key](), 56892 max = $scrollTo.max(elem, axis); 56893 56894 if (toff) {// jQuery / DOMElement 56895 attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos]); 56896 56897 // If it's a dom element, reduce the margin 56898 if (settings.margin) { 56899 attr[key] -= parseInt(targ.css('margin'+Pos), 10) || 0; 56900 attr[key] -= parseInt(targ.css('border'+Pos+'Width'), 10) || 0; 56901 } 56902 56903 attr[key] += offset[pos] || 0; 56904 56905 if (settings.over[pos]) { 56906 // Scroll to a fraction of its width/height 56907 attr[key] += targ[axis === 'x'?'width':'height']() * settings.over[pos]; 56908 } 56909 } else { 56910 var val = targ[pos]; 56911 // Handle percentage values 56912 attr[key] = val.slice && val.slice(-1) === '%' ? 56913 parseFloat(val) / 100 * max 56914 : val; 56915 } 56916 56917 // Number or 'number' 56918 if (settings.limit && /^\d+$/.test(attr[key])) { 56919 // Check the limits 56920 attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max); 56921 } 56922 56923 // Don't waste time animating, if there's no need. 56924 if (!i && settings.axis.length > 1) { 56925 if (prev === attr[key]) { 56926 // No animation needed 56927 attr = {}; 56928 } else if (queue) { 56929 // Intermediate animation 56930 animate(settings.onAfterFirst); 56931 // Don't animate this axis again in the next iteration. 56932 attr = {}; 56933 } 56934 } 56935 }); 56936 56937 animate(settings.onAfter); 56938 56939 function animate(callback) { 56940 var opts = $.extend({}, settings, { 56941 // The queue setting conflicts with animate() 56942 // Force it to always be true 56943 queue: true, 56944 duration: duration, 56945 complete: callback && function() { 56946 callback.call(elem, targ, settings); 56947 } 56948 }); 56949 $elem.animate(attr, opts); 56950 } 56951 }); 56952 }; 56953 56954 // Max scrolling position, works on quirks mode 56955 // It only fails (not too badly) on IE, quirks mode. 56956 $scrollTo.max = function(elem, axis) { 56957 var Dim = axis === 'x' ? 'Width' : 'Height', 56958 scroll = 'scroll'+Dim; 56959 56960 if (!isWin(elem)) 56961 return elem[scroll] - $(elem)[Dim.toLowerCase()](); 56962 56963 var size = 'client' + Dim, 56964 doc = elem.ownerDocument || elem.document, 56965 html = doc.documentElement, 56966 body = doc.body; 56967 56968 return Math.max(html[scroll], body[scroll]) - Math.min(html[size], body[size]); 56969 }; 56970 56971 function both(val) { 56972 return $.isFunction(val) || $.isPlainObject(val) ? val : { top:val, left:val }; 56973 } 56974 56975 // Add special hooks so that window scroll properties can be animated 56976 $.Tween.propHooks.scrollLeft = 56977 $.Tween.propHooks.scrollTop = { 56978 get: function(t) { 56979 return $(t.elem)[t.prop](); 56980 }, 56981 set: function(t) { 56982 var curr = this.get(t); 56983 // If interrupt is true and user scrolled, stop animating 56984 if (t.options.interrupt && t._last && t._last !== curr) { 56985 return $(t.elem).stop(); 56986 } 56987 var next = Math.round(t.now); 56988 // Don't waste CPU 56989 // Browsers don't render floating point scroll 56990 if (curr !== next) { 56991 $(t.elem)[t.prop](next); 56992 t._last = this.get(t); 56993 } 56994 } 56995 }; 56996 56997 // AMD requirement 56998 return $scrollTo; 56999}); 57000(function() { 57001 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 57002 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57003 hasProp = {}.hasOwnProperty; 57004 57005 App.Pages.ItemsIndex = (function(superClass) { 57006 var isTargetPage; 57007 57008 extend(ItemsIndex, superClass); 57009
57010 function ItemsIndex() { 57011 this.onPriceRangeUpdate = bind(this.onPriceRangeUpdate, this); 57012 this.onPriceRangeChanged = bind(this.onPriceRangeChanged, this); 57013 this.initAndBindPriceRangeFilter = bind(this.initAndBindPriceRangeFilter, this); 57014 return ItemsIndex.__super__.constructor.apply(this, arguments); 57015 } 57016 57017 isTargetPage = window.location.pathname.includes('ext/usd'); 57018 57019 ItemsIndex.prototype.widgets = ['customItemRequest']; 57020 57021 ItemsIndex.prototype.maxPrice = 500; 57022 57023 ItemsIndex.prototype.minValues = [2, 10, 20, 50, 100, 200, 300, 450]; 57024 57025 ItemsIndex.prototype.maxValues = [10, 20, 50, 100, 200, 300, 500]; 57026 57027 ItemsIndex.prototype.initialize = function() { 57028 this.bindPaginationTriggers(); 57029 this.bindFilters(); 57030 this.bindSearchForm(); 57031 this.bindActiveFilters(); 57032 App.events.subscribe('items:init-price-range-filter', this.initAndBindPriceRangeFilter); 57033 App.events.subscribe('items:set-meta-tags', this.setMetaTags); 57034 App.events.subscribe('items:init-sticky-filters-block', this.initStickyFiltersBlock); 57035 App.events.subscribe('items:init-license-filter-tooltip', this.initAndBindLicenseFilterTooltip); 57036 new LazyLoad({ 57037 elements_selector: '.js-lazy-img' 57038 }); 57039 return this.initializeRouter(); 57040 }; 57041 57042 ItemsIndex.prototype.setMetaTags = function(metaData) { 57043 var head, metaDescription, metaKeywords; 57044 document.title = metaData.title; 57045 $('meta[name=description],meta[name=keywords]').remove(); 57046 head = document.getElementsByTagName('head')[0]; 57047 metaDescription = document.createElement('meta'); 57048 metaDescription.name = 'description'; 57049 metaDescription.content = metaData.description; 57050 head.appendChild(metaDescription); 57051 metaKeywords = document.createElement('meta'); 57052 metaKeywords.name = 'keywords'; 57053 metaKeywords.content = metaData.keywords; 57054 return head.appendChild(metaKeywords); 57055 }; 57056 57057 ItemsIndex.prototype.handleFreeFilterForTarget = function() { 57058 if (window.location.search) { 57059 return this.router.navigate("" + window.location.pathname + window.location.search + "&swap_models=0", { 57060 trigger: true 57061 }); 57062 } else { 57063 return this.router.navigate(window.location.pathname + "?swap_models=0", { 57064 trigger: true 57065 }); 57066 } 57067 }; 57068 57069 ItemsIndex.prototype.initializeRouter = function() { 57070 this.router = new App.Backbone.Routers.ItemsSearch({ 57071 dedicateFileTypeFragments: $('.js-filter-block-container').data() 57072 }); 57073 if (!Backbone.history.started) { 57074 Backbone.history.start({ 57075 pushState: true, 57076 root: '/' 57077 }); 57078 return Backbone.history.started = true; 57079 } 57080 }; 57081 57082 ItemsIndex.prototype.bindPaginationTriggers = function() { 57083 $(document).on('click', '.pagination a', (function(_this) { 57084 return function(event) { 57085 mute(event); 57086 return _this.router.navigate("" + event.currentTarget.pathname + event.currentTarget.search, { 57087 trigger: true 57088 }); 57089 }; 57090 })(this)); 57091 $(document).on('keypress', '.custom-page-input', (function(_this) { 57092 return function(event) { 57093 var targetPage; 57094 if (event.which === 13) { 57095 mute(event); 57096 targetPage = $(".custom-page-input")[0].value; 57097 if (!(targetPage === '')) { 57098 return _this.router.applyFilter('page', targetPage); 57099 } 57100 } 57101 }; 57102 })(this)); 57103 return $(document).on('click', '.js-per-page', (function(_this) { 57104 return function(event) { 57105 var $perPageLink; 57106 mute(event); 57107 $perPageLink = $(event.currentTarget); 57108 $perPageLink.parents('.product-filters-footer__page-size').find('.is-active').removeClass('is-active'); 57109 $perPageLink.parent().addClass('is-active'); 57110 Cookies.set(_this.paginationCookieKey(), $perPageLink.text()); 57111 Cookies.set(gon.cookies_map.per_page_changed, true); 57112 return _this.router.removeFilter('page'); 57113 }; 57114 })(this)); 57115 }; 57116 57117 ItemsIndex.prototype.bindFilters = function() { 57118 $(document).on('change', '#sort_by,#polygons,#file_types,#licenses', (function(_this) { 57119 return function(event) { 57120 var name; 57121 mute(event); 57122 name = event.currentTarget.name; 57123 if (name === 'file_types[]') { 57124 name = 'file_types'; 57125 } 57126 if (name === 'licenses[]') { 57127 name = 'licenses'; 57128 } 57129 _this.router.applyFilter(name, event.currentTarget.value); 57130 if (event.currentTarget.value === '') { 57131 return _this.router.removeFilter(event.currentTarget.name); 57132 } 57133 }; 57134 })(this)); 57135 $(document).on('change', '.js-filter-checkbox', (function(_this) { 57136 return function(event) { 57137 var $checkbox, isAdult, name; 57138 mute(event); 57139 $checkbox = $(event.currentTarget); 57140 name = event.currentTarget.name; 57141 if (isTargetPage && name === 'free') { 57142 if ($checkbox.is(':checked')) { 57143 _this.router.removeFilter('swap_models'); 57144 return _this.router.removeFilter('price'); 57145 } else { 57146 return _this.handleFreeFilterForTarget(); 57147 } 57148 } else { 57149 if ($checkbox.is(':checked')) { 57150 if (name === 'adult_content') { 57151 isAdult = Cookies.get('i_am_an_adult') === 'true'; 57152 if (isAdult) { 57153 return _this.router.applyFilter(name, '1'); 57154 } else { 57155 _this.router.removeFilter(name); 57156 _this.addAdultModal(); 57157 $(document).on('click', '.js-set-adult-cookie', function() { 57158 Cookies.set('i_am_an_adult', true, { 57159 expires: 365 57160 }); 57161 _this.router.applyFilter(name, '1'); 57162 return _this.removeAdultModal(); 57163 }); 57164 return $(document).on('click', '.js-close-modal', function() { 57165 return _this.removeAdultModal(); 57166 }); 57167 } 57168 } else { 57169 return _this.router.applyFilter(name, '1'); 57170 } 57171 } else { 57172 return _this.router.removeFilter(name); 57173 } 57174 } 57175 }; 57176 })(this)); 57177 $(document).on('click', '.js-reset-all', (function(_this) { 57178 return function(event) { 57179 var basePath, listingPathname, useLocaleInPath; 57180 useLocaleInPath = I18n.locale !== I18n.defaultLocale; 57181 if (App.config.currentProductType === 'cg') { 57182 basePath = I18n.t('item-search-filters.3d-models-url'); 57183 } else { 57184 basePath = I18n.t('item-search-filters.3d-print-models-url'); 57185 } 57186 listingPathname = useLocaleInPath ? "/" + I18n.locale + "/" + basePath
57186: "/" + basePath; 57187 return _this.router.navigate(listingPathname, { 57188 trigger: true 57189 }); 57190 }; 57191 })(this)); 57192 $(document).on('click', '.js-toggle-filters-group', function(event) { 57193 return $(event.currentTarget).parent().toggleClass('is-opened'); 57194 }); 57195 return $(document).on('change', '#max_price,#min_price', (function(_this) { 57196 return function(event) { 57197 var maxValue, minValue; 57198 mute(event); 57199 minValue = Number($('#min_price').val()); 57200 maxValue = Number($('#max_price').val()); 57201 return _this.onPriceRangeChanged([minValue, maxValue < minValue ? minValue : maxValue]); 57202 }; 57203 })(this)); 57204 }; 57205 57206 ItemsIndex.prototype.bindActiveFilters = function() { 57207 return $(document).on('click', '.js-active-filters-container .js-reset', (function(_this) { 57208 return function(event) { 57209 var filterIdentifier; 57210 mute(event); 57211 filterIdentifier = $(event.currentTarget).parents('.active-filters__item').data(); 57212 if (isTargetPage && filterIdentifier.filter === 'free') { 57213 return _this.handleFreeFilterForTarget(); 57214 } else { 57215 return _this.router.removeFilter(filterIdentifier.filter, "" + filterIdentifier.filterValue); 57216 } 57217 }; 57218 })(this)); 57219 }; 57220 57221 ItemsIndex.prototype.bindSearchForm = function() { 57222 return $('#search-form').submit((function(_this) { 57223 return function(event) { 57224 var newKeywords; 57225 event.preventDefault(); 57226 newKeywords = $('#search-form [name=keywords]').val(); 57227 return _this.router.applyFilter('keywords', newKeywords, { 57228 reload: true 57229 }); 57230 }; 57231 })(this)); 57232 }; 57233 57234 ItemsIndex.prototype.initStickyFiltersBlock = function() { 57235 return $(window).load(function() { 57236 var jsStickyOffset, ref; 57237 jsStickyOffset = (ref = $('#navigation-header').height()) != null ? ref : 0; 57238 return $('.filter-block').sticky({ 57239 topSpacing: jsStickyOffset, 57240 wrapperClassName: 'sticky-filters-wrapper' 57241 }); 57242 }); 57243 }; 57244 57245 ItemsIndex.prototype.initAndBindLicenseFilterTooltip = function($tooltip) { 57246 var content; 57247 content = "<b>\n " + (I18n.t('browser.license.tooltip_title')) + "\n</b>\n" + (I18n.t('browser.license.tooltip_text')) + "\n<br/>\n<div class=\"u-text-center\">\n <a href=\"https://www.cgtrader.com/faq/page/112\" target=\"_blank\">\n " + (I18n.t('browser.license.tooltip_more')) + "\n </a>\n</div>"; 57248 return $tooltip.tooltipster({ 57249 theme: 'tooltip--light tooltip--popover u-text-left', 57250 animation: 'grow', 57251 contentAsHTML: true, 57252 content: content, 57253 position: 'left', 57254 interactive: true, 57255 maxWidth: 700 57256 }); 57257 }; 57258 57259 ItemsIndex.prototype.initAndBindPriceRangeFilter = function($priceRange) { 57260 var ref, startRange; 57261 if (!$priceRange.exists()) { 57262 return; 57263 } 57264 $priceRange.tooltipster({ 57265 theme: 'tooltip--light', 57266 animation: 'grow', 57267 delay: 0, 57268 autoClose: true, 57269 trigger: 'custom', 57270 updateAnimation: false, 57271 timer: 500 57272 }); 57273 startRange = (ref = JSON.parse($('#price').val())) != null ? ref : { 57274 from: 2, 57275 to: this.maxPrice 57276 }; 57277 if (this.minValues.includes(Math.round(startRange.from))) { 57278 $('#min_price').val(startRange.from); 57279 } else { 57280 $('#min_price').append('<option value="' + startRange.from + '" selected="selected">' + startRange.from + '</option>'); 57281 } 57282 if (this.maxValues.includes(Math.round(startRange.to))) { 57283 $('#max_price').val(startRange.to); 57284 } else { 57285 $('#max_price').append('<option value="' + startRange.to + '" selected="selected">' + startRange.to + '</option>'); 57286 } 57287 if (!$priceRange[0].noUiSlider) { 57288 noUiSlider.create($priceRange[0], { 57289 start: [startRange.from, startRange.to], 57290 connect: true, 57291 step: 1, 57292 range: { 57293 'min': 2, 57294 'max': this.maxPrice 57295 } 57296 }); 57297 } 57298 $priceRange[0].noUiSlider.on('change', this.onPriceRangeChanged); 57299 $priceRange[0].noUiSlider.on('set', this.onPriceRangeChanged); 57300 return $priceRange[0].noUiSlider.on('update', (function(_this) { 57301 return function(values, handle) { 57302 return _this.onPriceRangeUpdate(values, handle, $priceRange); 57303 }; 57304 })(this)); 57305 }; 57306 57307 ItemsIndex.prototype.onPriceRangeChanged = function(values) { 57308 var from, to; 57309 from = parseInt(values[0]); 57310 to = parseInt(values[1]); 57311 if (from === 2 && to === this.maxPrice) { 57312 return this.router.removeFilter('price'); 57313 } else { 57314 return this.router.applyFilter('price', { 57315 from: from, 57316 to: to 57317 }); 57318 } 57319 }; 57320 57321 ItemsIndex.prototype.onPriceRangeUpdate = function(values, handle, $priceRange) { 57322 var value; 57323 value = values[handle]; 57324 if ($priceRange.priceRangeChangeCounter == null) { 57325 $priceRange.priceRangeChangeCounter = 0; 57326 } 57327 $priceRange.priceRangeChangeCounter += 1; 57328 if ($priceRange.priceRangeChangeCounter < 10) { 57329 return; 57330 } 57331 if (+value === this.maxPrice) { 57332 value = this.maxPrice + " or more"; 57333 } 57334 if ($priceRange.hasClass('tooltipstered')) { 57335 return $priceRange.tooltipster({}).tooltipster('content', "$" + value).tooltipster('show'); 57336 } 57337 }; 57338 57339 ItemsIndex.prototype.selectedPriceScope = function() { 57340 return $('input[name=price_scope]:checked').val(); 57341 }; 57342 57343 ItemsIndex.prototype.paginationCookieKey = function() { 57344 if (_.isEmpty($.deparam((window.location.search || "").replace(/^\?/, '')).keywords)) { 57345 return gon.cookies_map.items_listing_per_page; 57346 } else { 57347 return gon.cookies_map.items_search_per_page; 57348 } 57349 }; 57350 57351 ItemsIndex.prototype.addAdultModal = function() { 57352 var $agreementModal; 57353 $agreementModal = $(JST["modals/adult_content_agreement_modal"]()); 57354 return $('body').prepend($agreementModal); 57355 }; 57356 57357 ItemsIndex.prototype.removeAdultModal = function() { 57358 return $('body').find('.overlay-modal--background').remove(); 57359 }; 57360 57361 return ItemsIndex; 57362 57363 })(App.Core.Page); 57364 57365}).call(this); 57366(function() { 57367 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57368 hasProp = {}.hasOwnProperty; 57369 57370 App.Pages.ItemsMobileIndex = (function(superClass) { 57371 extend(ItemsMobileIndex, superClass); 57372 57373 function ItemsMobileIndex() { 57374 return ItemsMobileIndex.__super__.constructor.apply(this, arguments); 57375 } 57376 57377 return ItemsMobileIndex; 57378 57379 })(App.Pages.ItemsIndex); 57380 57381}).call(this); 57382(function() { 57383 var base, 57384 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57385 hasProp = {}.hasOwnProperty; 57386 57387 if ((base = App.Pages).Jobs == null) { 57388 base.Jobs = {}; 57389 } 57390 57391 App.Pages.Jobs.CheckoutsPayment = (function(superClass) { 57392 extend(CheckoutsPayment, superClass); 57393 57394 function CheckoutsPayment() { 57395 return CheckoutsPayment.__super__.constructor.apply(this, arguments); 57396 } 57397 57398 CheckoutsPayment.prototype.initialize = function() { 57399 this.initBuyerType(); 57400 this.bindApplyCompanyInformation(); 57401 this.initDiscountTrigger(); 57402 this.initDiscountTriggerV2(); 57403 this.bindTabClick(); 57404 this.handleCouponPurchase(); 57405 return this.initCountrySelection(); 57406 }; 57407 57408 return CheckoutsPayment; 57409 57410 })(App.Pages.CheckoutPayment); 57411 57412}).call(this); 57413(function() { 57414 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57415 hasProp = {}.hasOwnProperty; 57416 57417 App.Pages.Jobs.CheckoutsPlaceOrder = (function(superClass) { 57418 extend(CheckoutsPlaceOrder, superClass); 57419 57420 function CheckoutsPlaceOrder() { 57421 return CheckoutsPlaceOrder.__super__.constructor.apply(this, arguments); 57422 } 57423 57424 return CheckoutsPlaceOrder; 57425 57426 })(App.Pages.Jobs.CheckoutsPayment); 57427 57428}).call(this); 57429(function() { 57430 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57431 hasProp = {}.hasOwnProperty; 57432 57433 App.Pages.OrdersShow = (function(superClass) { 57434 extend(OrdersShow, superClass); 57435 57436 function OrdersShow() { 57437 return OrdersShow.__super__.constructor.apply(this, arguments); 57438 } 57439 57440 OrdersShow.prototype.widgets = ['downloads', 'loyaltyLevelProgressInfoTooltip']; 57441 57442 OrdersShow.prototype.initialize = function() { 57443 $('.js-subscribe-marketing').on('click', this.onSubscribeClick); 57444 return this.sendDataToGoogleAnalytics(); 57445 }; 57446 57447 OrdersShow.prototype.sendDataToGoogleAnalytics = function() { 57448 var event; 57449 if (!gon.user_tracking_ga4_purchase) { 57450 return; 57451 } 57452 event = { 57453 event: 'purchase', 57454 enhanced_conversion_data: { 57455 email: gon.user_email 57456 } 57457 }; 57458 return dataLayer.push(Object.assign(event, gon.user_tracking_ga4_purchase)); 57459 }; 57460 57461 OrdersShow.prototype.onSubscribeClick = function(e) { 57462 var email; 57463 email = $('input[name="email"]').val(); 57464 return $.ajax({ 57465 url: '/api/internal/users/update-gdpr-answer', 57466 type: 'PUT', 57467 data: { 57468 answer: 'opt_in' 57469 }, 57470 success: function(response) { 57471 $(e.target).attr('disabled', 'disabled'); 57472 return App.events.publish('app:notification:flash:success', 'Thank you! You have successfully subscribed to our emails.'); 57473 } 57474 }); 57475 }; 57476 57477 return OrdersShow; 57478 57479 })(App.Core.Page); 57480 57481}).call(this); 57482(function() { 57483 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57484 hasProp = {}.hasOwnProperty; 57485 57486 App.Pages.PagesShow = (function(superClass) { 57487 extend(PagesShow, superClass); 57488 57489 function PagesShow() { 57490 return PagesShow.__super__.constructor.apply(this, arguments); 57491 } 57492 57493 PagesShow.prototype.widgets = ['loyaltyLevelProgressInfoTooltip']; 57494 57495 PagesShow.prototype.initialize = function() { 57496 return this.showLoyaltyLevelProgressBar(); 57497 }; 57498 57499 PagesShow.prototype.showLoyaltyLevelProgressBar = function() { 57500 this.$loyaltyLevelProgressBar = $('.js-loyalty-level-progress'); 57501 return this.$loyaltyLevelProgressBar.appendTo('#loyalty-level-progress-bar-block'); 57502 }; 57503 57504 return PagesShow; 57505 57506 })(App.Core.Page); 57507 57508}).call(this); 57509(function() { 57510 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57511 hasProp = {}.hasOwnProperty; 57512 57513 App.Pages.PrinterPagesShow = (function(superClass) { 57514 extend(PrinterPagesShow, superClass); 57515 57516 function PrinterPagesShow() { 57517 return PrinterPagesShow.__super__.constructor.apply(this, arguments); 57518 } 57519 57520 PrinterPagesShow.prototype.initialize = function() { 57521 this.bindEvents(); 57522 return $('.js-sticky').sticky({ 57523 topSpacing: 0, 57524 wrapperClassName: 'sticky-wrapper' 57525 }); 57526 }; 57527 57528 PrinterPagesShow.prototype.bindEvents = function() { 57529 return $('.js-focus').on('click', this.onFocusClick); 57530 }; 57531 57532 PrinterPagesShow.prototype.onFocusClick = function(e) { 57533 var $target; 57534 $target = $($(e.currentTarget).attr('href')); 57535 $('html, body').animate({ 57536 scrollTop: $target.offset().top - $('.printer-navigation').height(), 57537 easing: 'easeInOutCirc' 57538 }, { 57539 easing: 'easeInOutCirc', 57540 duration: 600 57541 }); 57542 return e.preventDefault(); 57543 }; 57544 57545 return PrinterPagesShow; 57546 57547 })(App.Core.Page); 57548 57549}).call(this); 57550(function() { 57551 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57552 hasProp = {}.hasOwnProperty; 57553 57554 App.Pages.ProductsShow = (function(superClass) { 57555 extend(ProductsShow, superClass); 57556 57557 function ProductsShow() { 57558 return ProductsShow.__super__.constructor.apply(this, arguments); 57559 } 57560 57561 ProductsShow.prototype.widgets = ['comments', 'reportContent', 'likes', 'wishLists']; 57562 57563 ProductsShow.prototype.initialize = function($el) { 57564 if ($el == null) { 57565 $el = $('.product-container, .product-page'); 57566 } 57567 this.$el = $el; 57568 App.state.is3DPrint = $('.site-page--product-3d-print').length > 0; 57569 this.handlers = this.eventHandlers(); 57570 this.modifySimilarProductAttributes(); 57571 this.bindEvents(); 57572 this.initTabs(); 57573 this.initMoneyBackTooltip(); 57574 this.initLicenseTooltip(); 57575 this.handleLicenseLink(); 57576 this.handleApproveButtons(); 57577 this.initiateSimilarProductsLoader(); 57578 this.updatesLikesViewsCounters(); 57579 return this.calculatePageHeight(); 57580 }; 57581 57582 ProductsShow.prototype.bindEvents = function() { 57583 App.events.subscribe('app:preview:change', this.handlers.previewItemChange); 57584 this.$el.find('.js-report-link').click(function() {
57585 return $('#modal-report-content').makeMeModal(); 57586 }); 57587 this.$el.find('.js-collections-list-button').click((function(_this) { 57588 return function() { 57589 _this.$el.find('.js-collections-list-item').removeClass('is-hidden'); 57590 _this.$el.find('.js-collections-list-button').addClass('is-hidden'); 57591 return _this.$el.find('.js-box-bottom-space').removeClass('is-hidden'); 57592 }; 57593 })(this)); 57594 this.$el.find('.js-toggle-collection-row').click(function() { 57595 return $(this).toggleClass('is-droped'); 57596 }); 57597 if ($('#js-collection-contents-rows')[0]) { 57598 this.loadingOtherContentsRows = false; 57599 window.addEventListener('scroll', (function(_this) { 57600 return function(event) { 57601 return _this.scrolledHandler(event); 57602 }; 57603 })(this)); 57604 } 57605 return this.$el.find('.js-hire-me').click((function(_this) { 57606 return function(e) { 57607 return _this.onHireMeClicked(e); 57608 }; 57609 })(this)); 57610 }; 57611 57612 ProductsShow.prototype.scrolledHandler = function(e) { 57613 var $lastTr; 57614 $lastTr = $('#js-collection-contents-rows tr').last(); 57615 if ($lastTr[0] && $lastTr.offset().top <= window.pageYOffset + window.innerHeight && !this.loadingOtherContentsRows) { 57616 this.loadingOtherContentsRows = true; 57617 return $.getScript("/items/" + gon.product_id + "/next-collection-rows/" + ($lastTr.data('page')), ((function(_this) { 57618 return function() { 57619 return _this.loadingOtherContentsRows = false; 57620 }; 57621 })(this))); 57622 } 57623 }; 57624 57625 ProductsShow.prototype.initTabs = function() { 57626 return this.$el.find('#product-tabs').easytabs({ 57627 animate: false, 57628 updateHash: false, 57629 panelActiveClass: 'is-active', 57630 tabActiveClass: 'is-active' 57631 }); 57632 }; 57633 57634 ProductsShow.prototype.initMoneyBackTooltip = function() { 57635 if (this.$el.find('.product-money-back').length === 0) { 57636 return; 57637 } 57638 return this.$el.find('.product-money-back__title').tooltipster({ 57639 theme: 'tooltip--light', 57640 animation: 'grow', 57641 trigger: 'click' 57642 }); 57643 }; 57644 57645 ProductsShow.prototype.initLicenseTooltip = function() { 57646 var detected_keyword_text; 57647 if (this.$el.find('.js-license-tooltip').data('keyword') === void 0) { 57648 detected_keyword_text = ''; 57649 } else { 57650 detected_keyword_text = "(namely owner of the brand \"" + (this.$el.find('.js-license-tooltip').data('keyword')) + "\")"; 57651 } 57652 return this.$el.find('.js-license-tooltip').tooltipster({ 57653 theme: 'tooltip--light tooltip--popover u-text-center', 57654 animation: 'grow', 57655 interactive: true, 57656 contentAsHTML: true, 57657 content: I18n.t("licenses_new.tooltips." + (this.$el.find('.js-license-tooltip').data('license')) + "_html", { 57658 keyword_detected: detected_keyword_text 57659 }), 57660 functionReady: (function(_this) { 57661 return function() { 57662 return _this.handleLicenseLink(); 57663 }; 57664 })(this) 57665 }); 57666 }; 57667 57668 ProductsShow.prototype.modifySimilarProductAttributes = function() { 57669 return $.each(this.$el.find('.content-box__image'), function(index, item) { 57670 $(item).addClass('js-similar-product'); 57671 return item.setAttribute('data-position', index + 1); 57672 }); 57673 }; 57674 57675 ProductsShow.prototype.handleLicenseLink = function() { 57676 var $el; 57677 $el = this.$el.find('.js-license'); 57678 $el.on('ajax:before', function() { 57679 return $el.attr('href', $el.data('href')); 57680 }); 57681 return $el.on('ajax:complete', function() { 57682 return $el.removeAttr('href'); 57683 }); 57684 }; 57685 57686 ProductsShow.prototype.handleApproveButtons = function() { 57687 if (App.config.isAdmin) { 57688 this.$el.find('.js-auto-approve').removeClass('is-hidden'); 57689 this.$el.find('.js-approve').on('change', this.handlers.changeHandler); 57690 return this.$el.find('.js-disapprove').on('change', this.handlers.changeHandler); 57691 } 57692 }; 57693 57694 ProductsShow.prototype.initiateSimilarProductsLoader = function() { 57695 if (!$('.js-related-products-grid-bottom-placeholder').exists()) { 57696 return; 57697 } 57698 return $.getScript("/items/" + gon.product_id + "/similar-products"); 57699 }; 57700 57701 ProductsShow.prototype.updatesLikesViewsCounters = function() { 57702 this.$el.find('.js-likes-counter').text(gon.item_likes); 57703 this.$el.find('.js-views-counter').text(gon.item_views); 57704 return this.$el.find('.js-downloads-counter').text(gon.item_downloads); 57705 }; 57706 57707 ProductsShow.prototype.calculatePageHeight = function() { 57708 if (window.innerWidth > 992) { 57709 return $('.product-page').css('min-height', $('.product-page__sidebar').height()); 57710 } 57711 }; 57712 57713 ProductsShow.prototype.eventHandlers = function() { 57714 return { 57715 thumbHover: (function(_this) { 57716 return function(e) { 57717 if ($(_this).hasClass('is-active') || $(_this).hasClass('product-thumbs-action')) { 57718 return; 57719 } 57720 return _this.$el.find('.product-thumbs li').not(_this).not('.is-active, .product-thumbs-action').addClass('is-disabled'); 57721 }; 57722 })(this), 57723 thumbHoverOut: (function(_this) { 57724 return function(e) { 57725 return _this.$el.find('.product-thumbs li').removeClass('is-disabled'); 57726 }; 57727 })(this), 57728 thumbClick: (function(_this) { 57729 return function(e) { 57730 var $el, $target; 57731 _this.handlers.updateCurrentCount('thumb', $(e.currentTarget).data('position')); 57732 if (_.has(e, 'zoomIn')) { 57733 return true; 57734 } 57735 e.preventDefault(); 57736 e.stopPropagation(); 57737 $el = $(e.currentTarget); 57738 $target = _this.$previewImages.find("li:eq(" + ($el.index()) + ")"); 57739 if ($el.hasClass('product-thumbs-action')) { 57740 return false;
57741 } 57742 return App.events.publish('app:preview:change', $target, 'auto'); 57743 }; 57744 })(this), 57745 previewItemChange: (function(_this) { 57746 return function($target, direction) { 57747 var $active, $thumb; 57748 $active = _this.$previewImages.find('.is-active'); 57749 if (direction === 'auto') { 57750 direction = 'next'; 57751 _this.sly.activate($target.index()); 57752 } 57753 $active.removeClass('is-active'); 57754 $target.addClass('is-active'); 57755 $target.find('iframe.sculpteo-preview').loadDynamicIframe(); 57756 $thumb = _this.$el.find(".product-thumbs li:eq(" + ($target.index()) + ")"); 57757 if ($thumb.hasClass('is-embedded')) { 57758 _this.$el.find('.js-zoom-in').fadeOut(); 57759 } else { 57760 _this.$el.find('.js-zoom-in').fadeIn(); 57761 } 57762 return _this.$el.find('.js-wr-watermark').toggleClass('hidden', !$thumb.hasClass('js-wr-360')); 57763 }; 57764 })(this), 57765 previewNavClick: (function(_this) { 57766 return function(e) { 57767 var $active, $el, $target, direction; 57768 $el = $(e.currentTarget); 57769 $active = _this.$previewImages.find('.is-active'); 57770 if ($(e.currentTarget).hasClass('js-preview-next')) { 57771 $target = $active.next(); 57772 direction = 'next'; 57773 _this.handlers.updateCurrentCount('next'); 57774 if ($el.data('trigger') === 'manual') { 57775 _this.sly.next(); 57776 } 57777 } else { 57778 $target = $active.prev(); 57779 direction = 'prev'; 57780 _this.handlers.updateCurrentCount('previous'); 57781 if ($el.data('trigger') === 'manual') { 57782 _this.sly.prev(); 57783 } 57784 } 57785 if ($target.length === 0) { 57786 return; 57787 } 57788 return App.events.publish('app:preview:change', $target, direction); 57789 }; 57790 })(this), 57791 updateCurrentCount: (function(_this) { 57792 return function(target, index) { 57793 var currentItem, totalItems; 57794 totalItems = parseInt(_this.$el.find('.total-images').text()); 57795 currentItem = parseInt(_this.$el.find('.current-image').text()); 57796 if (target === 'next') { 57797 if (currentItem < totalItems) { 57798 currentItem += 1; 57799 } 57800 } else if (target === 'previous') { 57801 if (currentItem > 1) { 57802 currentItem -= 1; 57803 } 57804 } else { 57805 currentItem = index; 57806 } 57807 return _this.$el.find('.current-image').text(currentItem); 57808 }; 57809 })(this), 57810 zoomClick: (function(_this) { 57811 return function(e) { 57812 return _this.$el.find('.product-thumbs li.is-active').not('.product-thumbs-action').first().find('a').trigger({ 57813 type: 'click', 57814 zoomIn: true 57815 }); 57816 }; 57817 })(this), 57818 changeHandler: function(e) { 57819 if (this.checked) { 57820 $(e.target).parents('.js-auto-approve').children().removeClass('auto-approval'); 57821 return $.post("//admin." + window.location.host + "/admin/approve/set_approve_status", { 57822 type: this.name, 57823 status: this.value, 57824 item_id: this.getAttribute('data-item') 57825 }); 57826 } 57827 }, 57828 resizeScrollbar: (function(_this) { 57829 return function(e) { 57830 return _this.sly.reload(); 57831 }; 57832 })(this) 57833 }; 57834 }; 57835 57836 ProductsShow.prototype.onHireMeClicked = function(e) { 57837 if (!App.config.userSignedIn) { 57838 e.preventDefault(); 57839 return App.events.publish('app:login:open', { 57840 redirectURL: e.target.href 57841 }); 57842 } 57843 }; 57844 57845 return ProductsShow; 57846 57847 })(App.Core.Page); 57848 57849}).call(this); 57850(function() { 57851 $.validator.addMethod('greaterThan', function(value, element, param) { 57852 this.$numberValue = Number(value.replace(/[^0-9\.\-]+/g, "")); 57853 return this.$numberValue > param; 57854 }, $.format('Must be greater than {0}')); 57855 57856 $.validator.addMethod('notLowerThan50Percent', function(value, element, param) { 57857 var originalPrice; 57858 originalPrice = Number($('input#original-product-price').val()); 57859 return value >= originalPrice * 0.5; 57860 }, 'Price offers should not be below the minimum of 50% of the original price'); 57861 57862 $.validator.addMethod('onlyLatinSymbols', function(value) { 57863 return /^[A-z0-9 ?!,.\-:()\/&%$*#@<>=]*$/.test(value); 57864 }, 'Should not contain non-latin symbols'); 57865
57866 $.validator.addMethod('validateUsername', function(value) { 57867 return /^[-A-Za-z0-9]*$/.test(value); 57868 }, 'Please use only latin symbols, numbers or a hyphen symbol ( - )'); 57869 57870 $.validator.addMethod('validatePassword', function(value) { 57871 return /^((?=.*\d)(?=.*[A-Z]))/.test(value); 57872 }, 'Your password should have at least one Uppercase character and one digit'); 57873 57874 $.validator.addMethod('oneFieldAllowed', function(value, element, param) { 57875 var otherValue; 57876 otherValue = $(param).val(); 57877 return (value && !otherValue) || (!value && otherValue); 57878 }, 'Only one field must be filled'); 57879 57880 $.validator.addMethod('validDateFormat', function(value, element) { 57881 return this.optional(element) || /^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$/.test(value); 57882 }, 'Please enter a valid date in the format YYYY-MM-DD'); 57883 57884 $.validator.addMethod('validCardDateFormat', function(value, element) { 57885 return this.optional(element) || /^(0[123456789]|10|11|12)(\s?[\/]\s?)([1-2][0-9])/.test(value); 57886 }, 'Please enter a valid date in the format MM/YY'); 57887 57888 $.validator.addMethod('validateCompetitors', function(value) { 57889 var competitorNotMentioned, competitorsList, downcasedInputValue; 57890 competitorNotMentioned = true; 57891 competitorsList = ['turbosquid', 'sketchfab', 'skfb.ly', 'gumroad', 'grabcad.com', 'shapeways.com', '3docean.net', '3dexport.com', 'pinshape.com', 'daz3d.com', 'assetstore.unity3d.com', 'renderosity.com', 'free3d.com', 'cults3d.com', '3dsky.org', 'highend3d.com']; 57892 downcasedInputValue = value.toLowerCase(); 57893 competitorsList.forEach(function(competitor) { 57894 if (downcasedInputValue.indexOf(competitor) !== -1) { 57895 return competitorNotMentioned = false; 57896 } 57897 }); 57898 return competitorNotMentioned; 57899 }, 'Please note that advertising other marketplaces is not allowed on your product information.'); 57900 57901 $.validator.addMethod('noEmoji', function(value) { 57902 this.$re = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g; 57903 return !this.$re.test(value); 57904 }, 'Emojis are not allowed'); 57905 57906}).call(this); 57907(function() { 57908 var base, 57909 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 57910 hasProp = {}.hasOwnProperty; 57911 57912 if ((base = App.Pages).Profile == null) { 57913 base.Profile = {}; 57914 } 57915 57916 App.Pages.Profile.ConversationsShow = (function(superClass) { 57917 extend(ConversationsShow, superClass); 57918 57919 function ConversationsShow() { 57920 return ConversationsShow.__super__.constructor.apply(this, arguments); 57921 } 57922 57923 ConversationsShow.prototype.initialize = function() { 57924 this.$form = $('.edit_item_price_offer'); 57925 this.$message_form = $('.new_conversation_message'); 57926 $('.js-novalidation').on('click', function() { 57927 return $('.js-price').rules('remove'); 57928 }); 57929 this.$message_form.submit(function() { 57930 if ($('.new_conversation_message').valid()) { 57931 $('.js-disable-reply-button').attr('disabled', true); 57932 } 57933 return true; 57934 }); 57935 this.initTooltip(); 57936 return this.initValidation(); 57937 }; 57938 57939 ConversationsShow.prototype.initTooltip = function() { 57940 return $('.js-tooltip-with-list').tooltipster({ 57941 theme: 'tooltip--light tooltip--popover tooltip--is-list', 57942 animation: 'grow', 57943 interactive: true, 57944 content: $('#hire-me-button-tooltip') 57945 }); 57946 }; 57947 57948 ConversationsShow.prototype.validationSettings = function() { 57949 return { 57950 rules: { 57951 'item_price_offer[offer_price]': { 57952 required: true, 57953 number: true, 57954 greaterThan: 2, 57955 notLowerThan50Percent: true 57956 }, 57957 'conversation_message[message]': { 57958 required: true 57959 } 57960 }, 57961 messages: { 57962 'item_price_offer[offer_price]': { 57963 greaterThan: $.format('Price must be greater than ${0}') 57964 } 57965 } 57966 }; 57967 }; 57968 57969 ConversationsShow.prototype.initValidation = function() { 57970 this.$form.validate(this.validationSettings()); 57971 return this.$message_form.validate(this.validationSettings()); 57972 }; 57973 57974 return ConversationsShow; 57975 57976 })(App.Core.Page); 57977 57978}).call(this); 57979(function() { 57980 this.JST || (this.JST = {}); 57981 this.JST["refunds/refund"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 57982 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 57983 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 57984 return parent[propertyName]; 57985 } 57986 return undefined 57987 }; 57988 57989 return "<tr class=\"u-text-center\">\n <td>" 57990 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"orderId") || (depth0 != null ? lookupProperty(depth0,"orderId") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
57990),{"name":"orderId","hash":{},"data":data,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":19}}}) : helper))) 57991 + "</td>\n <td>" 57992 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"purchased") || (depth0 != null ? lookupProperty(depth0,"purchased") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"purchased","hash":{},"data":data,"loc":{"start":{"line":3,"column":8},"end":{"line":3,"column":21}}}) : helper))) 57993 + "</td>\n <td>" 57994 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"title") || (depth0 != null ? lookupProperty(depth0,"title") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"title","hash":{},"data":data,"loc":{"start":{"line":4,"column":8},"end":{"line":4,"column":17}}}) : helper))) 57995 + "</td>\n <td>" 57996 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"buyer") || (depth0 != null ? lookupProperty(depth0,"buyer") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"buyer","hash":{},"data":data,"loc":{"start":{"line":5,"column":8},"end":{"line":5,"column":17}}}) : helper))) 57997 + "</td>\n <td>$" 57998 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"amount") || (depth0 != null ? lookupProperty(depth0,"amount") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"amount","hash":{},"data":data,"loc":{"start":{"line":6,"column":9},"end":{"line":6,"column":19}}}) : helper))) 57999 + "</td>\n <td>$" 58000 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"royaltiesAmount") || (depth0 != null ? lookupProperty(depth0,"royaltiesAmount") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"royaltiesAmount","hash":{},"data":data,"loc":{"start":{"line":7,"column":9},"end":{"line":7,"column":28}}}) : helper))) 58001 + "</td>\n <td>" 58002 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"refundDate") || (depth0 != null ? lookupProperty(depth0,"refundDate") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"refundDate","hash":{},"data":data,"loc":{"start":{"line":8,"column":8},"end":{"line":8,"column":22}}}) : helper))) 58003 + "</td>\n <td>" 58004 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"refundReason") || (depth0 != null ? lookupProperty(depth0,"refundReason") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"refundReason","hash":{},"data":data,"loc":{"start":{"line":9,"column":8},"end":{"line":9,"column":24}}}) : helper))) 58005 + "</td>\n</tr>"; 58006},"useData":true}); 58007 return this.JST["refunds/refund"]; 58008}).call(this); 58009(function() { 58010 var base, 58011 bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 58012 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 58013 hasProp = {}.hasOwnProperty; 58014 58015 if ((base = App.Pages).Profile == null) { 58016 base.Profile = {}; 58017 } 58018 58019 App.Pages.Profile.SalesIndex = (function(superClass) { 58020 extend(SalesIndex, superClass); 58021 58022 function SalesIndex() { 58023 this.onCouponLinkClick = bind(this.onCouponLinkClick, this); 58024 return SalesIndex.__super__.constructor.apply(this, arguments); 58025 } 58026 58027 SalesIndex.prototype.initialize = function() { 58028 this.initTabs(); 58029 this.initTooltip(); 58030 this.initCoupons(); 58031 this.initValidation(); 58032 return this.bindEvents(); 58033 }; 58034 58035 SalesIndex.prototype.initTabs = function() { 58036 return $('.js-tabs').easytabs({ 58037 animate: false, 58038 panelActiveClass: 'is-active', 58039 tabActiveClass: 'is-active' 58040 }); 58041 }; 58042 58043 SalesIndex.prototype.initTooltip = function() { 58044 return $('.js-payout-fee-tooltip').tooltipster({ 58045 theme: 'tooltip--light tooltip--popover u-text-center', 58046 animation: 'grow', 58047 interactive: true, 58048 position: 'top', 58049 maxWidth: 650, 58050 contentAsHTML: true, 58051 functionInit: function(origin) { 58052 return origin.data('content'); 58053 } 58054 }); 58055 }; 58056 58057 SalesIndex.prototype.initCoupons = function() { 58058 this.$couponLink = $('.js-new-coupon'); 58059 this.$couponFormContainer = $('.js-coupon-container'); 58060 return this.$couponLink.on('click', this.onCouponLinkClick); 58061 }; 58062 58063 SalesIndex.prototype.bindEvents = function() { 58064 $('.js-refunds').on('click', this.onRefundsClick); 58065 return $('.js-sale-off-participation').on('change', this.onSaleOffParticipationChange); 58066 }; 58067 58068 SalesIndex.prototype.onCouponLinkClick = function(e) { 58069 e.preventDefault(); 58070 e.stopPropagation(); 58071 return this.$couponLink.fadeOut().promise().done((function(_this) { 58072 return function() { 58073 _this.$couponFormContainer.parents('.table-responsive').hide().removeClass('is-hidden').fadeIn(1000); 58074 return _this.$couponFormContainer.hide().removeClass('is-hidden').fadeIn(1000); 58075 }; 58076 })(this)); 58077 }; 58078 58079 SalesIndex.prototype.onRefundsClick = function(e) { 58080 return $.ajax('/profile/refunds', { 58081 data: { 58082 refund_ids: $(e.target).data('refund-ids') 58083 }, 58084 success: function(response) { 58085 var $tbody;
58086 $tbody = $('#modal-refunds tbody'); 58087 $tbody.find('tr').remove(); 58088 _.each(response.data, function(refund) { 58089 return $tbody.append(JST['refunds/refund'](refund.attributes)); 58090 }); 58091 return $('#modal-refunds').makeMeModal(); 58092 } 58093 }); 58094 }; 58095 58096 SalesIndex.prototype.validationSettings = function() { 58097 return { 58098 rules: { 58099 'coupon[discount]': { 58100 required: true, 58101 number: true, 58102 min: 1, 58103 max: 99 58104 }, 58105 'coupon[max_usage_count]': { 58106 required: true, 58107 min: 1, 58108 max: 1000000 58109 } 58110 }, 58111 messages: { 58112 'coupon[discount]': { 58113 required: 'Please enter a discount' 58114 } 58115 }, 58116 errorPlacement: function(error, element) { 58117 if (element.attr('name') === 'coupon[discount]') { 58118 return error.appendTo($('.js-discount-error-field')); 58119 } else { 58120 return error.insertAfter(element); 58121 } 58122 } 58123 }; 58124 }; 58125 58126 SalesIndex.prototype.initValidation = function() { 58127 return $('.new_coupon').validate(this.validationSettings()); 58128 }; 58129 58130 SalesIndex.prototype.onSaleOffParticipationChange = function(e) { 58131 var message; 58132 message = $('.js-sale-off-participation').is(":checked") ? 'You are now participating in sale off campaigns' : 'You are no longer participating in sale off campaigns'; 58133 return $.ajax({ 58134 url: '/profile/settings/toggle-sale-off-participation', 58135 type: 'PUT', 58136 data: { 58137 sale_off: e.target.checked 58138 }, 58139 success: function() { 58140 return App.events.publish('app:notification:flash:success', message); 58141 } 58142 }); 58143 }; 58144 58145 return SalesIndex; 58146 58147 })(App.Core.Page); 58148 58149}).call(this); 58150(function() { 58151 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 58152 hasProp = {}.hasOwnProperty; 58153 58154 App.Pages.Profile.CouponsCreate = (function(superClass) { 58155 extend(CouponsCreate, superClass); 58156 58157 function CouponsCreate() { 58158 return CouponsCreate.__super__.constructor.apply(this, arguments); 58159 } 58160 58161 CouponsCreate.prototype.initialize = function() { 58162 CouponsCreate.__super__.initialize.apply(this, arguments); 58163 return this.showForm(); 58164 }; 58165 58166 CouponsCreate.prototype.initTabs = function() { 58167 return $('.js-tabs').easytabs({ 58168 animate: false, 58169 panelActiveClass: 'is-active', 58170 tabActiveClass: 'is-active', 58171 defaultTab: 'li:last-child' 58172 }); 58173 }; 58174 58175 CouponsCreate.prototype.showForm = function() { 58176 return $('.js-coupon-container').removeClass('is-hidden').parents('.table').removeClass('is-hidden'); 58177 }; 58178 58179 return CouponsCreate; 58180 58181 })(App.Pages.Profile.SalesIndex); 58182 58183}).call(this); 58184/* 58185 * HTML5 Sortable jQuery Plugin 58186 * http://farhadi.ir/projects/html5sortable 58187 * 58188 * Copyright 2012, Ali Farhadi 58189 * Released under the MIT license. 58190 */ 58191 58192(function($) { 58193var dragging, placeholders = $(); 58194$.fn.sortable = function(options) { 58195 var method = String(options); 58196 options = $.extend({ 58197 connectWith: false 58198 }, options); 58199 return this.each(function() { 58200 if (/^enable|disable|destroy$/.test(method)) { 58201 var items = $(this).children($(this).data('items')).attr('draggable', method == 'enable'); 58202 if (method == 'destroy') { 58203 items.add(this).removeData('connectWith items') 58204 .off('dragstart.h5s dragend.h5s selectstart.h5s dragover.h5s dragenter.h5s drop.h5s'); 58205 } 58206 return; 58207 } 58208 var isHandle, index, items = $(this).children(options.items); 58209 var placeholder = $('<' + (/^ul|ol$/i.test(this.tagName) ? 'li' : 'div') + ' class="sortable__item is-placeholder">'); 58210 items.find(options.handle).mousedown(function() { 58211 isHandle = true; 58212 }).mouseup(function() { 58213 isHandle = false; 58214 }); 58215 $(this).data('items', options.items) 58216 placeholders = placeholders.add(placeholder); 58217 if (options.connectWith) { 58218 $(options.connectWith).add(this).data('connectWith', options.connectWith); 58219 } 58220 items.attr('draggable', 'true').on('dragstart.h5s', function(e) { 58221 if (options.handle && !isHandle) { 58222 return false;
58223 } 58224 isHandle = false; 58225 var dt = e.originalEvent.dataTransfer; 58226 dt.effectAllowed = 'move'; 58227 dt.setData('Text', 'dummy'); 58228 index = (dragging = $(this)).addClass('sortable-dragging').index(); 58229 }).on('dragend.h5s', function() { 58230 if (!dragging) { 58231 return; 58232 } 58233 dragging.removeClass('sortable-dragging').show(); 58234 placeholders.detach(); 58235 if (index != dragging.index()) { 58236 dragging.parent().trigger('sortupdate', {item: dragging}); 58237 } 58238 dragging = null; 58239 }).not('a[href], img').on('selectstart.h5s', function() { 58240 this.dragDrop && this.dragDrop(); 58241 return false; 58242 }).end().add([this, placeholder]).on('dragover.h5s dragenter.h5s drop.h5s', function(e) { 58243 if (!items.is(dragging) && options.connectWith !== $(dragging).parent().data('connectWith')) { 58244 return true; 58245 } 58246 if (e.type == 'drop') { 58247 e.stopPropagation(); 58248 placeholders.filter(':visible').after(dragging); 58249 dragging.trigger('dragend.h5s'); 58250 return false; 58251 } 58252 e.preventDefault(); 58253 e.originalEvent.dataTransfer.dropEffect = 'move'; 58254 if (items.is(this)) { 58255 if (options.forcePlaceholderSize) { 58256 placeholder.height(dragging.outerHeight()); 58257 } 58258 dragging.hide(); 58259 $(this)[placeholder.index() < $(this).index() ? 'after' : 'before'](placeholder); 58260 placeholders.not(placeholder).detach(); 58261 } else if (!placeholders.is(this) && !$(this).children(options.items).length) { 58262 placeholders.detach(); 58263 $(this).append(placeholder); 58264 } 58265 return false; 58266 }); 58267 }); 58268}; 58269})(jQuery); 58270/* 58271 58272 jQuery Tags Input Plugin 1.3.3 58273 58274 Copyright (c) 2011 XOXCO, Inc 58275 58276 Documentation for this plugin lives here: 58277 http://xoxco.com/clickable/jquery-tags-input 58278 58279 Licensed under the MIT license: 58280 http://www.opensource.org/licenses/mit-license.php 58281 58282 [email protected] 58283 58284 58285 MODIFIED: 58286 Date: 2015-06-22 58287 Task: #DT-1534 58288 58289 $.fn.tagExist method - same tags with uppercase characters and not are same tag (car/Car/CAR) 58290*/ 58291 58292 58293(function($) { 58294 58295 var delimiter = new Array(); 58296 var tags_callbacks = new Array(); 58297 $.fn.doAutosize = function(o){ 58298 var minWidth = $(this).data('minwidth'), 58299 maxWidth = $(this).data('maxwidth'), 58300 val = '', 58301 input = $(this), 58302 testSubject = $('#'+$(this).data('tester_id')); 58303 58304 if (val === (val = input.val())) {return;} 58305 58306 // Enter new content into testSubject 58307 var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>'); 58308 testSubject.html(escaped); 58309 // Calculate new width + whether to change 58310 var testerWidth = testSubject.width(), 58311 newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth, 58312 currentWidth = input.width(), 58313 isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth) 58314 || (newWidth > minWidth && newWidth < maxWidth); 58315 58316 // Animate width 58317 if (isValidWidthChange) { 58318 input.width(newWidth); 58319 } 58320 58321 58322 }; 58323 $.fn.resetAutosize = function(options){ 58324 // alert(JSON.stringify(options)); 58325 var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(), 58326 maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding), 58327 val = '', 58328 input = $(this), 58329 testSubject = $('<tester/>').css({ 58330 position: 'absolute', 58331 top: -9999, 58332 left: -9999, 58333 width: 'auto', 58334 fontSize: input.css('fontSize'), 58335 fontFamily: input.css('fontFamily'), 58336 fontWeight: input.css('fontWeight'), 58337 letterSpacing: input.css('letterSpacing'), 58338 whiteSpace: 'nowrap' 58339 }), 58340 testerId = $(this).attr('id')+'_autosize_tester'; 58341 if(! $('#'+testerId).length > 0){ 58342 testSubject.attr('id', testerId); 58343 testSubject.appendTo('body'); 58344 } 58345 58346 input.data('minwidth', minWidth); 58347 input.data('maxwidth', maxWidth); 58348 input.data('tester_id', testerId); 58349 input.css('width', minWidth); 58350 }; 58351 58352 $.fn.addTag = function(value,options) { 58353 options = jQuery.extend({focus:false,callback:true},options); 58354 this.each(function() { 58355 var id = $(this).attr('id'); 58356 58357 var tagslist = $(this).val().split(delimiter[id]); 58358 if (tagslist[0] == '') { 58359 tagslist = new Array(); 58360 } 58361 58362 value = jQuery.trim(value); 58363 58364 if (options.unique) { 58365 var skipTag = $(this).tagExist(value); 58366 if(skipTag == true) { 58367 //Marks fake input as not_valid to let styling it 58368 $('#'+id+'_tag').addClass('is-invalid'); 58369 } 58370 } else { 58371 var skipTag = false;
58372 } 58373 58374 if (value !='' && skipTag != true) { 58375 $('<span>').addClass('tag').append( 58376 $('<span>').text(value).append(' '), 58377 $('<a>', { 58378 href : '#', 58379 title : 'Removing tag', 58380 text : 'x' 58381 }).click(function () { 58382 return $('#' + id).removeTag(escape(value)); 58383 }) 58384 ).insertBefore('#' + id + '_addTag'); 58385 58386 tagslist.push(value); 58387 58388 $('#'+id+'_tag').val(''); 58389 if (options.focus) { 58390 $('#'+id+'_tag').focus(); 58391 } else { 58392 $('#'+id+'_tag').blur(); 58393 } 58394 58395 $.fn.tagsInput.updateTagsField(this,tagslist); 58396 58397 if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) { 58398 var f = tags_callbacks[id]['onAddTag']; 58399 f.call(this, value); 58400 } 58401 if(tags_callbacks[id] && tags_callbacks[id]['onChange']) 58402 { 58403 var i = tagslist.length; 58404 var f = tags_callbacks[id]['onChange']; 58405 f.call(this, $(this), tagslist[i-1]); 58406 } 58407 } 58408 58409 }); 58410 58411 return false; 58412 }; 58413 58414 $.fn.removeTag = function(value) { 58415 value = unescape(value); 58416 this.each(function() { 58417 var id = $(this).attr('id'); 58418 58419 var old = $(this).val().split(delimiter[id]); 58420 58421 $('#'+id+'_tagsinput .tag').remove(); 58422 str = ''; 58423 for (i=0; i< old.length; i++) { 58424 if (old[i]!=value) { 58425 str = str + delimiter[id] +old[i]; 58426 } 58427 } 58428 58429 $.fn.tagsInput.importTags(this,str); 58430 58431 if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) { 58432 var f = tags_callbacks[id]['onRemoveTag']; 58433 f.call(this, value); 58434 } 58435 }); 58436 58437 return false; 58438 }; 58439 58440 $.fn.tagExist = function(val) { 58441 var id = $(this).attr('id'); 58442 var tagslist = $(this).val().toLowerCase().split(delimiter[id]); 58443 return (jQuery.inArray(val.toLowerCase(), tagslist) >= 0); //true when tag exists, false when not 58444 }; 58445 58446 // clear all existing tags and import new ones from a string 58447 $.fn.importTags = function(str) { 58448 id = $(this).attr('id'); 58449 $('#'+id+'_tagsinput .tag').remove(); 58450 $.fn.tagsInput.importTags(this,str); 58451 } 58452 58453 $.fn.tagsInput = function(options) { 58454 var settings = jQuery.extend({ 58455 interactive:true, 58456 defaultText:'add a tag', 58457 minChars:0, 58458 width:'300px', 58459 height:'100px', 58460 autocomplete: {selectFirst: false }, 58461 'hide':true, 58462 'delimiter':',', 58463 'unique':true, 58464 removeWithBackspace:true, 58465 placeholderColor:'#666666', 58466 autosize: true, 58467 comfortZone: 20, 58468 inputPadding: 6*2 58469 },options); 58470 58471 this.each(function() { 58472 if (settings.hide) { 58473 $(this).hide(); 58474 } 58475 var id = $(this).attr('id'); 58476 if (!id || delimiter[$(this).attr('id')]) { 58477 id = $(this).attr('id', 'tags' + new Date().getTime()).attr('id'); 58478 } 58479 58480 var data = jQuery.extend({ 58481 pid:id, 58482 real_input: '#'+id, 58483 holder: '#'+id+'_tagsinput', 58484 input_wrapper: '#'+id+'_addTag', 58485 fake_input: '#'+id+'_tag' 58486 },settings); 58487 58488 delimiter[id] = data.delimiter; 58489 58490 if (settings.onAddTag || settings.onRemoveTag || settings.onChange) { 58491 tags_callbacks[id] = new Array(); 58492 tags_callbacks[id]['onAddTag'] = settings.onAddTag; 58493 tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag; 58494 tags_callbacks[id]['onChange'] = settings.onChange; 58495 } 58496 58497 var markup = '<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag">'; 58498 58499 if (settings.interactive) { 58500 markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />'; 58501 } 58502 58503 markup = markup + '</div><div class="tags_clear"></div></div>'; 58504 58505 $(markup).insertAfter(this); 58506 58507 $(data.holder).css('width',settings.width); 58508 $(data.holder).css('min-height',settings.height); 58509 $(data.holder).css('height','100%'); 58510 58511 if ($(data.real_input).val()!='') { 58512 $.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val()); 58513 } 58514 if (settings.interactive) { 58515 $(data.fake_input).val($(data.fake_input).attr('data-default')); 58516 //$(data.fake_input).css('color',settings.placeholderColor);
58517 $(data.fake_input).resetAutosize(settings); 58518 58519 $(data.holder).bind('click',data,function(event) { 58520 $(event.data.fake_input).focus(); 58521 }); 58522 58523 $(data.fake_input).bind('focus',data,function(event) { 58524 if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) { 58525 $(event.data.fake_input).val(''); 58526 } 58527 //$(event.data.fake_input).css('color','#000000'); 58528 }); 58529 58530 if (settings.autocomplete_url != undefined) { 58531 autocomplete_options = {source: settings.autocomplete_url}; 58532 for (attrname in settings.autocomplete) { 58533 autocomplete_options[attrname] = settings.autocomplete[attrname]; 58534 } 58535 58536 if (jQuery.Autocompleter !== undefined) { 58537 $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete); 58538 $(data.fake_input).bind('result',data,function(event,data,formatted) { 58539 if (data) { 58540 $('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)}); 58541 } 58542 }); 58543 } else if (jQuery.ui.autocomplete !== undefined) { 58544 $(data.fake_input).autocomplete(autocomplete_options); 58545 $(data.fake_input).bind('autocompleteselect',data,function(event,ui) { 58546 $(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)}); 58547 return false; 58548 }); 58549 } 58550 58551 58552 } else { 58553 // if a user tabs out of the field, create a new tag 58554 // this is only available if autocomplete is not used. 58555 $(data.fake_input).bind('blur',data,function(event) { 58556 var d = $(this).attr('data-default'); 58557 if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) { 58558 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 58559 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 58560 } else { 58561 $(event.data.fake_input).val($(event.data.fake_input).attr('data-default')); 58562 //$(event.data.fake_input).css('color',settings.placeholderColor); 58563 } 58564 return false; 58565 }); 58566 58567 } 58568 // if user types a comma, create a new tag 58569 $(data.fake_input).bind('keypress',data,function(event) { 58570 if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13 ) { 58571 event.preventDefault(); 58572 if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) ) 58573 $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)}); 58574 $(event.data.fake_input).resetAutosize(settings); 58575 return false; 58576 } else if (event.data.autosize) { 58577 $(event.data.fake_input).doAutosize(settings); 58578 58579 } 58580 }); 58581 //Delete last tag on backspace 58582 data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event) 58583 { 58584 if(event.keyCode == 8 && $(this).val() == '') 58585 { 58586 event.preventDefault(); 58587 var last_tag = $(this).closest('.tagsinput').find('.tag:last').text(); 58588 var id = $(this).attr('id').replace(/_tag$/, ''); 58589 last_tag = last_tag.replace(/[\s]+x$/, ''); 58590 $('#' + id).removeTag(escape(last_tag)); 58591 $(this).trigger('focus'); 58592 } 58593 }); 58594 $(data.fake_input).blur(); 58595 58596 //Removes the not_valid class when user changes the value of the fake input 58597 if(data.unique) { 58598 $(data.fake_input).keydown(function(event){ 58599 if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéÃóúÃÃÃÃÃñÃ,/]+/)) { 58600 $(this).removeClass('is-invalid'); 58601 } 58602 }); 58603 } 58604 } // if settings.interactive 58605 }); 58606 58607 return this; 58608 58609 }; 58610 58611 $.fn.tagsInput.updateTagsField = function(obj,tagslist) { 58612 var id = $(obj).attr('id'); 58613 $(obj).val(tagslist.join(delimiter[id])); 58614 }; 58615 58616 $.fn.tagsInput.importTags = function(obj,val) { 58617 $(obj).val(''); 58618 var id = $(obj).attr('id'); 58619 var tags = val.split(delimiter[id]); 58620 for (i=0; i<tags.length; i++) { 58621 $(obj).addTag(tags[i],{focus:false,callback:false}); 58622 } 58623 if(tags_callbacks[id] && tags_callbacks[id]['onChange']) 58624 { 58625 var f = tags_callbacks[id]['onChange']; 58626 f.call(obj, obj, tags[i]); 58627 } 58628 }; 58629 58630})(jQuery); 58631(function() { 58632 this.JST || (this.JST = {}); 58633 this.JST["file_upload/file"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 58634 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 58635 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 58636 return parent[propertyName]; 58637 } 58638 return undefined 58639 }; 58640 58641 return "<div class=\"js-file-wrap\">\n <p>\n <a class=\"attachment\" href=\"" 58642 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"file_url") || (depth0 != null ? lookupProperty(depth0,"file_url") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
58642),{"name":"file_url","hash":{},"data":data,"loc":{"start":{"line":3,"column":32},"end":{"line":3,"column":44}}}) : helper))) 58643 + "\" target=\"_blank\">\n <span>" 58644 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"file_name") || (depth0 != null ? lookupProperty(depth0,"file_name") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"file_name","hash":{},"data":data,"loc":{"start":{"line":4,"column":12},"end":{"line":4,"column":25}}}) : helper))) 58645 + "</span>\n </a>\n <a class=\"remove\" href=\"" 58646 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"delete_url") || (depth0 != null ? lookupProperty(depth0,"delete_url") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"delete_url","hash":{},"data":data,"loc":{"start":{"line":6,"column":28},"end":{"line":6,"column":42}}}) : helper))) 58647 + "\" data-method=\"delete\" data-remote=\"true\" rel=\"nofollow\">\n <i class=\"far height-24 pull-right fa-times\"></i>\n </a>\n <br>\n </p>\n</div>"; 58648},"useData":true}); 58649 return this.JST["file_upload/file"]; 58650}).call(this); 58651(function() { 58652 this.JST || (this.JST = {}); 58653 this.JST["file_upload/file_v2"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 58654 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 58655 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 58656 return parent[propertyName]; 58657 } 58658 return undefined 58659 }; 58660 58661 return "<div class=\"js-file-wrap upload--file\">\n <i class=\"fal fa-paperclip height-24 is-not-spaced\"></i>\n <div class=\"file-info\">\n <a class=\"attachment\" href=\"" 58662 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"file_url") || (depth0 != null ? lookupProperty(depth0,"file_url") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"file_url","hash":{},"data":data,"loc":{"start":{"line":4,"column":32},"end":{"line":4,"column":44}}}) : helper))) 58663 + "\" target=\"_blank\">
58663\n <span>" 58664 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"file_name") || (depth0 != null ? lookupProperty(depth0,"file_name") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"file_name","hash":{},"data":data,"loc":{"start":{"line":5,"column":12},"end":{"line":5,"column":25}}}) : helper))) 58665 + "</span>\n </a>\n </div>\n <div class=\"file-remove\">\n <a class=\"remove\" href=\"" 58666 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"delete_url") || (depth0 != null ? lookupProperty(depth0,"delete_url") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"delete_url","hash":{},"data":data,"loc":{"start":{"line":9,"column":28},"end":{"line":9,"column":42}}}) : helper))) 58667 + "\" data-method=\"delete\" data-remote=\"true\" rel=\"nofollow\">\n <i class=\"far fa-times height-24 is-not-spaced\"></i>\n </a>\n </div>\n</div>"; 58668},"useData":true}); 58669 return this.JST["file_upload/file_v2"]; 58670}).call(this); 58671(function() { 58672 this.JST || (this.JST = {}); 58673 this.JST["file_upload/image"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 58674 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 58675 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 58676 return parent[propertyName]; 58677 } 58678 return undefined 58679 }; 58680 58681 return "<div class=\"js-file-wrap upload--image\">\n <div class=\"upload__image-wrapper\">\n <img src=\"" 58682 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"file_url") || (depth0 != null ? lookupProperty(depth0,"file_url") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"file_url","hash":{},"data":data,"loc":{"start":{"line":3,"column":14},"end":{"line":3,"column":26}}}) : helper))) 58683 + "\" />\n <a class=\"remove\" href=\"" 58684 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"delete_url") || (depth0 != null ? lookupProperty(depth0,"delete_url") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"delete_url","hash":{},"data":data,"loc":{"start":{"line":4,"column":28},"end":{"line":4,"column":42}}}) : helper))) 58685 + "\" data-method=\"delete\" data-remote=\"true\" rel=\"nofollow\">\n <i class=\"far height-12 fa-times is-not-spaced\"></i>\n </a>\n </div>\n</div>"; 58686},"useData":true}); 58687 return this.JST["file_upload/image"]; 58688}).call(this); 58689(function() { 58690 this.JST || (this.JST = {}); 58691 this.JST["file_upload/progress"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 58692 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 58693 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 58694 return parent[propertyName]; 58695 } 58696 return undefined 58697 }; 58698 58699 return "<div class=\"file file-upload-progress\" data-id=\"" 58700 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"id") || (depth0 != null ? lookupProperty(depth0,"id") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"id","hash":{},"data":data,"loc":{"start":{"line":1,"column":48},"end":{"line":1,"column":54}}}) : helper))) 58701 + "\">\n <div class=\"progress-bar__info\">\n Uploading " 58702 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"file_name") || (depth0 != null ? lookupProperty(depth0,"file_name") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
58702),{"name":"file_name","hash":{},"data":data,"loc":{"start":{"line":3,"column":16},"end":{"line":3,"column":29}}}) : helper))) 58703 + " ...\n\n <span class=\"progress-bar__percentage\"></span>\n\n <a href=\"javascript:;\" class=\"js-cancel-upload\">cancel</a>\n </div>\n <div class=\"progress-bar\">\n <div class=\"progress-bar__progress\"></div>\n </div>\n</div>"; 58704},"useData":true}); 58705 return this.JST["file_upload/progress"]; 58706}).call(this); 58707(function() { 58708 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 58709 58710 App.Modules.FileUpload = (function() { 58711 FileUpload.prototype.maxFileSize = 100 * 1024 * 1024; 58712 58713 FileUpload.prototype.templates = { 58714 progress: JST['file_upload/progress'], 58715 file: JST['file_upload/file'], 58716 image: JST['file_upload/image'], 58717 file_v2: JST['file_upload/file_v2'] 58718 }; 58719 58720 FileUpload.prototype.options = { 58721 url: '', 58722 dataType: 'json', 58723 autoUpload: false, 58724 formData: { 58725 _method: 'POST' 58726 } 58727 }; 58728 58729 FileUpload.prototype.uploads = {}; 58730 58731 function FileUpload(optionsUrl, $selector) { 58732 if ($selector == null) { 58733 $selector = $('#fileupload'); 58734 } 58735 this.cancelUpload = bind(this.cancelUpload, this); 58736 this.fileProgress = bind(this.fileProgress, this); 58737 this.fileUploadFailed = bind(this.fileUploadFailed, this); 58738 this.fileUploaded = bind(this.fileUploaded, this); 58739 this.fileAdded = bind(this.fileAdded, this); 58740 if ($selector.attr('id') === 'fileupload') { 58741 this.$filesElement = $('.files'); 58742 } else if ($selector.attr('id') === 'job-file-upload') { 58743 this.$filesElement = $('.files'); 58744 this.$imagesElement = $('.images'); 58745 this.isJobFileUpload = true; 58746 } else { 58747 this.$filesElement = $('.files.' + $selector.attr('id')); 58748 } 58749 this.options.url = optionsUrl; 58750 $selector.fileupload(this.options).on('fileuploadadd', this.fileAdded).on('fileuploadprogress', this.fileProgress).on('fileuploaddone', this.fileUploaded).on('fileuploadfail', this.fileUploadFailed); 58751 $(document).on('click', '.file-upload-progress .js-cancel-upload', this.cancelUpload); 58752 $(document).on('click', '#files a.remove', this.removeFile); 58753 } 58754 58755 FileUpload.prototype.fileAdded = function(_, data) { 58756 return $.each(data.files, (function(_this) { 58757 return function(index, file) { 58758 var upload; 58759 if (file.size > _this.maxFileSize) { 58760 App.events.publish('app:notification:flash:error', I18n.t('activerecord.errors.messages.file_too_big')); 58761 return; 58762 } 58763 upload = { 58764 id: guid(), 58765 file_name: file.name 58766 }; 58767 if (file.type.includes('image') && _this.isJobFileUpload) { 58768 data.context = $(_this.templates.progress(upload)).appendTo(_this.$imagesElement); 58769 } else { 58770 data.context = $(_this.templates.progress(upload)).appendTo(_this.$filesElement); 58771 } 58772 _this.uploads[upload.id] = upload; 58773 return upload.jqXHR = data.submit(); 58774 }; 58775 })(this)); 58776 }; 58777 58778 FileUpload.prototype.fileUploaded = function(_, data) { 58779 return $.each(data.result, (function(_this) { 58780 return function(index, file) { 58781 var error, id_field, progressBar, upload; 58782 if (file.url) { 58783 upload = { 58784 file_name: file.name, 58785 file_url: file.url, 58786 delete_url: file.delete_url 58787 }; 58788 if (_this.isJobFileUpload) { 58789 if (file.type === 'image') { 58790 $(data.context).html(_this.templates.image(upload)); 58791 } else { 58792 $(data.context).html(_this.templates.file_v2(upload)); 58793 } 58794 } else { 58795 $(data.context).html(_this.templates.file(upload)); 58796 } 58797 id_field = $('<input type="hidden" value="' + file.id + '" name="attachment_ids[]" />'); 58798 data.context.append(id_field); 58799 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + upload.id + "]"); 58800 return progressBar.remove(); 58801 } else if (file.error) { 58802 error = $('<span class="text-danger"/>').text(file.error); 58803 $(data.context.children()[index]).append('<br>').append(error); 58804 upload = _this.uploadByFileName(file.name); 58805 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + upload.id + "]"); 58806 return progressBar.remove(); 58807 } 58808 }; 58809 })(this)); 58810 }; 58811 58812 FileUpload.prototype.fileUploadFailed = function(_, data) { 58813 var errMsg; 58814 errMsg = data.jqXHR.responseJSON.errors.join(', '); 58815 return $.each(data.files, (function(_this) { 58816 return function(index, file) { 58817 var progressBar; 58818 $(data.context).append($('<span class="text-danger text-warning"/>').text(errMsg || 'File upload failed.')); 58819 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + (_this.uploadByFileName(file.name).id) + "]"); 58820 return progressBar.remove(); 58821 }; 58822 })(this)); 58823 }; 58824 58825 FileUpload.prototype.fileProgress = function(_, data) { 58826 return $.each(data.files, (function(_this) { 58827 return function(index, file) { 58828 var progress, progressBar, progressText, upload; 58829 progress = parseInt(data.loaded / data.total * 100, 10); 58830 progressText = progress === 100 ? 'processing' : progress + " %"; 58831 upload = _this.uploadByFileName(file.name); 58832 if (progress > 95) { 58833 upload.jqXHR.forbidCanceling = true; 58834 } 58835 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + upload.id + "]"); 58836 progressBar.find('.progress-bar__progress').css('width', progress + "%"); 58837 return progressBar.find(".progress-bar__info .progress-bar__percentage").html(progressText); 58838 }; 58839 })(this)); 58840 }; 58841 58842 FileUpload.prototype.uploadByFileName = function(filename) { 58843 return _.detect(this.uploads, function(obj, index) { 58844 return (obj != null ? obj.file_name : void 0) === filename; 58845 }); 58846 }; 58847 58848 FileUpload.prototype.cancelUpload = function(event) { 58849 var progressBar, uploadId; 58850 mute(event); 58851 progressBar = $(event.target).parents('.file-upload-progress'); 58852 uploadId = progressBar.data('id'); 58853 if (!this.uploads[uploadId] || this.uploads[uploadId].jqXHR.forbidCanceling) { 58854 return; 58855 } 58856 this.uploads[uploadId].jqXHR.abort(); 58857 progressBar.remove(); 58858 return this.uploads[uploadId] = null; 58859 }; 58860 58861 FileUpload.prototype.removeFile = function(e) { 58862 return $(this).closest('.js-file-wrap').remove(); 58863 }; 58864 58865 return FileUpload; 58866 58867 })(); 58868 58869}).call(this); 58870(function() { 58871 this.JST || (this.JST = {}); 58872 this.JST["galleries/uploaded_image"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 58873 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 58874 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 58875 return parent[propertyName]; 58876 } 58877 return undefined 58878 }; 58879 58880 return "<li class=\"sortable__item\"><img src=\"" 58881 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"thumb_image") || (depth0 != null ? lookupProperty(depth0,"thumb_image") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
58881),{"name":"thumb_image","hash":{},"data":data,"loc":{"start":{"line":1,"column":37},"end":{"line":1,"column":52}}}) : helper))) 58882 + "\" /><span class=\"u-text-center u-block\"><input type=\"checkbox\" /></span><input name=\"gallery[images][]\" type=\"hidden\" value=\"" 58883 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"gallery_image_id") || (depth0 != null ? lookupProperty(depth0,"gallery_image_id") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"gallery_image_id","hash":{},"data":data,"loc":{"start":{"line":1,"column":177},"end":{"line":1,"column":197}}}) : helper))) 58884 + "\" /></li>"; 58885},"useData":true}); 58886 return this.JST["galleries/uploaded_image"]; 58887}).call(this); 58888(function() { 58889 var base, 58890 bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 58891 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 58892 hasProp = {}.hasOwnProperty; 58893 58894 if ((base = App.Pages).Profile == null) { 58895 base.Profile = {}; 58896 } 58897 58898 App.Pages.Profile.GalleriesNew = (function(superClass) { 58899 extend(GalleriesNew, superClass); 58900 58901 function GalleriesNew() { 58902 this.onGalleryError = bind(this.onGalleryError, this); 58903 this.onSubmitGalleryForm = bind(this.onSubmitGalleryForm, this); 58904 this.cancelUpload = bind(this.cancelUpload, this); 58905 this.initUploader = bind(this.initUploader, this); 58906 this.removeSelectedImages = bind(this.removeSelectedImages, this); 58907 this.checkImages = bind(this.checkImages, this); 58908 this.bindEvents = bind(this.bindEvents, this); 58909 return GalleriesNew.__super__.constructor.apply(this, arguments); 58910 } 58911 58912 GalleriesNew.prototype.uploads = {}; 58913 58914 GalleriesNew.prototype.initialize = function() { 58915 this.$el = $("#gallery-form-container"); 58916 this.$imagesContainer = $("#gallery-uploaded-images"); 58917 this.$removeImagesBtn = $("#gallery-remove-selected"); 58918 this.$uploadProgress = $("#gallery-upload-progress"); 58919 this.$form = $('#gallery-form'); 58920 this.$imagesCount = $('#images-count'); 58921 this.initValidation(); 58922 this.initUploader(); 58923 this.checkImages(); 58924 this.bindEvents(); 58925 this.initTags(); 58926 this.$imagesContainer.sortable(); 58927 return this.totalUploadFiles = 0; 58928 }; 58929 58930 GalleriesNew.prototype.bindEvents = function() { 58931 this.$removeImagesBtn.on('click', this.removeSelectedImages); 58932 this.$form.on('ajax:before', this.onSubmitGalleryForm); 58933 this.$form.on('ajax:success', this.onGalleryPublished); 58934 return this.$form.on('ajax:error', this.onGalleryError); 58935 }; 58936 58937 GalleriesNew.prototype.validationSetings = function() { 58938 return { 58939 ignore: [], 58940 rules: { 58941 'gallery[title]': { 58942 required: true, 58943 validateCompetitors: true 58944 }, 58945 'gallery[description]': { 58946 validateCompetitors: true 58947 }, 58948 'gallery[tags]': { 58949 validateCompetitors: true 58950 }, 58951 tags_count: { 58952 required: true, 58953 min: 3 58954 }, 58955 images_count: { 58956 required: true, 58957 min: 1 58958 } 58959 }, 58960 messages: { 58961 tags_count: { 58962 min: $.format("You should add at least {0} tags.") 58963 }, 58964 images_count: { 58965 min: $.format("Please upload at least {0} image.") 58966 } 58967 }, 58968 errorPlacement: function(error, element) { 58969 if (element.attr('name') === 'gallery[tags]') { 58970 return error.appendTo($('.js-tags-error-field')); 58971 } else { 58972 return error.insertAfter(element); 58973 } 58974 } 58975 }; 58976 }; 58977 58978 GalleriesNew.prototype.initValidation = function() { 58979 return this.$form.validate(this.validationSetings()); 58980 }; 58981 58982 GalleriesNew.prototype.checkImages = function() { 58983 this.$imagesCount.val(this.$imagesContainer.find('li').length); 58984 this.$imagesCount.valid(); 58985 if (this.$imagesContainer.find('li').length > 0) { 58986 return this.$el.find('#project-images').removeClass('is-hidden').show(); 58987 } else { 58988 return this.$el.find('#project-images').hide().addClass('is-hidden'); 58989 } 58990 }; 58991 58992 GalleriesNew.prototype.removeSelectedImages = function() { 58993 this.$imagesContainer.find('input[type="checkbox"]:checked').each(function() { 58994 return $(this).parent().parent().remove(); 58995 }); 58996 this.checkImages(); 58997 return false;
58998 }; 58999 59000 GalleriesNew.prototype.initUploader = function() { 59001 this.$filesElement = $('.files'); 59002 $(document).on('click', '.file-upload-progress .js-cancel-upload', this.cancelUpload); 59003 return $('#gallery-upload').fileupload({ 59004 dataType: 'json', 59005 url: '/api/internal/gallery_images/temp_upload', 59006 autoUpload: true, 59007 dropZone: $('#gallery-dropzone'), 59008 paramName: 'files[]', 59009 add: (function(_this) { 59010 return function(_, data) { 59011 return $.each(data.files, function(index, file) { 59012 var upload; 59013 upload = { 59014 id: guid(), 59015 file_name: file.name 59016 }; 59017 data.context = $(JST["file_upload/progress"](upload)).appendTo(_this.$filesElement); 59018 _this.uploads[upload.id] = upload; 59019 return upload.jqXHR = data.submit(); 59020 }); 59021 }; 59022 })(this), 59023 progress: (function(_this) { 59024 return function(_, data) { 59025 return $.each(data.files, function(index, file) { 59026 var progress, progressBar, progressText, upload; 59027 progress = parseInt(data.loaded / data.total * 100, 10); 59028 progressText = progress === 100 ? 'processing' : progress + " %"; 59029 upload = _this.uploadByFileName(file.name); 59030 if (progress > 95) { 59031 upload.jqXHR.forbidCanceling = true; 59032 } 59033 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + upload.id + "]"); 59034 progressBar.find('.progress-bar__progress').css('width', progress + "%"); 59035 return progressBar.find(".progress-bar__info .progress-bar__percentage").html(progressText); 59036 }); 59037 }; 59038 })(this), 59039 done: (function(_this) { 59040 return function(_, data) { 59041 if (_this.$el.hasClass('is-hidden')) { 59042 _this.$el.hide().removeClass('is-hidden').fadeIn(); 59043 } 59044 $.each(data.result, function(index, file) { 59045 var id_field, progressBar, upload; 59046 if (file.thumb_image) { 59047 upload = { 59048 gallery_image_id: file.gallery_image_id, 59049 thumb_image: file.thumb_image 59050 }; 59051 _this.$imagesContainer.append(JST["galleries/uploaded_image"](upload)); 59052 id_field = $('<input type="hidden" value="' + file.gallery_image_id + '" name="gallery_image_ids[]" />'); 59053 data.context.append(id_field); 59054 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + (data.context.data('id')) + "]"); 59055 return progressBar.remove(); 59056 } else if (file.error) { 59057 progressBar = _this.$filesElement.find(".file-upload-progress[data-id=" + (data.context.data('id')) + "]"); 59058 return progressBar.remove(); 59059 } 59060 }); 59061 _this.$imagesContainer.sortable(); 59062 return _this.checkImages(); 59063 }; 59064 })(this) 59065 }); 59066 }; 59067 59068 GalleriesNew.prototype.uploadByFileName = function(filename) { 59069 return _.detect(this.uploads, function(obj, index) { 59070 return (obj != null ? obj.file_name : void 0) === filename; 59071 }); 59072 }; 59073 59074 GalleriesNew.prototype.cancelUpload = function(event) { 59075 var progressBar, uploadId; 59076 mute(event); 59077 progressBar = $(event.target).parents('.file-upload-progress'); 59078 uploadId = progressBar.data('id'); 59079 if (!this.uploads[uploadId] || this.uploads[uploadId].jqXHR.forbidCanceling) { 59080 return; 59081 } 59082 this.uploads[uploadId].jqXHR.abort(); 59083 progressBar.remove(); 59084 return this.uploads[uploadId] = null; 59085 }; 59086 59087 GalleriesNew.prototype.initTags = function() { 59088 return $('#gallery_tags').tagsInput({ 59089 delimiter: ' ', 59090 width: '100%', 59091 height: 'auto', 59092 onChange: function() { 59093 $('#tags-count').val($('.tagsinput .tag').length); 59094 $('#tags-count').valid(); 59095 return $('#gallery_tags').valid(); 59096 } 59097 }); 59098 }; 59099 59100 GalleriesNew.prototype.onSubmitGalleryForm = function() { 59101 return this.$form.find('button[type="submit"]').attr('disabled', true); 59102 }; 59103 59104 GalleriesNew.prototype.onGalleryPublished = function(e, data, status, xhr) { 59105 var categoryInput, currentCategory, currentTags, tagsInput; 59106 categoryInput = $('#gallery_category')[0]; 59107 currentCategory = $(categoryInput).find(':selected').text(); 59108 tagsInput = $('#gallery_tags')[0]; 59109 currentTags = tagsInput.value.replaceAll(' ', '_'); 59110 window.customEventTracker({ 59111 name: 'upload_content', 59112 userId: App.config.userId || '', 59113 eventData: { 59114 content_type: 'gallery', 59115 content_category: currentCategory, 59116 content_tags: currentTags, 59117 file_format: '', 59118 content_subcategory: '', 59119 model_price: 0.00 59120 } 59121 }); 59122 return window.location = '/profile/gallery'; 59123 }; 59124 59125 GalleriesNew.prototype.onGalleryError = function(xhr, status, error) { 59126 var errors; 59127 errors = xhr.responseJSON.errors; 59128 App.events.publish('app:notification:flash:error', this.parseErrors(errors)); 59129 return $('#gallery-form').find('button[type="submit"]').attr('disabled', false); 59130 }; 59131 59132 GalleriesNew.prototype.parseErrors = function(errors) { 59133 var attribute, error, errorMessages, parts; 59134 errorMessages = []; 59135 for (error in errors) { 59136 parts = errors[error].source.pointer.split('/'); 59137 attribute = parts[parts.length - 1]; 59138 errorMessages.push(attribute.capitalizeFirst + " " + errors[error].detail); 59139 } 59140 return errorMessages.join('.'); 59141 }; 59142 59143 return GalleriesNew; 59144 59145 })(App.Core.Page); 59146 59147}).call(this); 59148(function() { 59149 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 59150 hasProp = {}.hasOwnProperty; 59151 59152 App.Pages.Profile.GalleriesEdit = (function(superClass) { 59153 extend(GalleriesEdit, superClass); 59154 59155 function GalleriesEdit() { 59156 return GalleriesEdit.__super__.constructor.apply(this, arguments); 59157 } 59158 59159 return GalleriesEdit; 59160 59161 })(App.Pages.Profile.GalleriesNew); 59162 59163}).call(this); 59164/* ========================================================= 59165 * bootstrap-datepicker.js 59166 * http://www.eyecon.ro/bootstrap-datepicker
59167 * ========================================================= 59168 * Copyright 2012 Stefan Petre 59169 * 59170 * Licensed under the Apache License, Version 2.0 (the "License"); 59171 * you may not use this file except in compliance with the License. 59172 * You may obtain a copy of the License at 59173 * 59174 * http://www.apache.org/licenses/LICENSE-2.0 59175 * 59176 * Unless required by applicable law or agreed to in writing, software 59177 * distributed under the License is distributed on an "AS IS" BASIS, 59178 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59179 * See the License for the specific language governing permissions and 59180 * limitations under the License. 59181 * ========================================================= */ 59182 59183 59184!function( $ ) { 59185 59186 // Picker object 59187 59188 var Datepicker = function(element, options){ 59189 this.element = $(element); 59190 this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); 59191 this.picker = $(DPGlobal.template) 59192 .appendTo('body') 59193 .on({ 59194 click: $.proxy(this.click, this)//, 59195 //mousedown: $.proxy(this.mousedown, this) 59196 }); 59197 this.isInput = this.element.is('input'); 59198 this.component = this.element.is('.date') ? this.element.find('.add-on') : false; 59199 59200 if (this.isInput) { 59201 this.element.on({ 59202 focus: $.proxy(this.show, this), 59203 //blur: $.proxy(this.hide, this), 59204 keyup: $.proxy(this.update, this) 59205 }); 59206 } else { 59207 if (this.component){ 59208 this.component.on('click', $.proxy(this.show, this)); 59209 } else { 59210 this.element.on('click', $.proxy(this.show, this)); 59211 } 59212 } 59213 59214 this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; 59215 if (typeof this.minViewMode === 'string') { 59216 switch (this.minViewMode) { 59217 case 'months': 59218 this.minViewMode = 1; 59219 break; 59220 case 'years': 59221 this.minViewMode = 2; 59222 break; 59223 default: 59224 this.minViewMode = 0; 59225 break; 59226 } 59227 } 59228 this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; 59229 if (typeof this.viewMode === 'string') { 59230 switch (this.viewMode) { 59231 case 'months': 59232 this.viewMode = 1; 59233 break; 59234 case 'years': 59235 this.viewMode = 2; 59236 break; 59237 default: 59238 this.viewMode = 0; 59239 break; 59240 } 59241 } 59242 this.startViewMode = this.viewMode; 59243 this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; 59244 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; 59245 this.onRender = options.onRender; 59246 this.fillDow(); 59247 this.fillMonths(); 59248 this.update(); 59249 this.showMode(); 59250 }; 59251 59252 Datepicker.prototype = { 59253 constructor: Datepicker, 59254 59255 show: function(e) { 59256 this.picker.show(); 59257 this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); 59258 this.place(); 59259 $(window).on('resize', $.proxy(this.place, this)); 59260 if (e ) { 59261 e.stopPropagation(); 59262 e.preventDefault(); 59263 } 59264 if (!this.isInput) { 59265 } 59266 var that = this; 59267 $(document).on('mousedown', function(ev){ 59268 if ($(ev.target).closest('.datepicker').length == 0) { 59269 that.hide(); 59270 } 59271 }); 59272 this.element.trigger({ 59273 type: 'show', 59274 date: this.date 59275 }); 59276 }, 59277 59278 hide: function(){ 59279 this.picker.hide(); 59280 $(window).off('resize', this.place); 59281 this.viewMode = this.startViewMode; 59282 this.showMode(); 59283 if (!this.isInput) { 59284 $(document).off('mousedown', this.hide); 59285 } 59286 //this.set(); 59287 this.element.trigger({ 59288 type: 'hide', 59289 date: this.date 59290 }); 59291 }, 59292 59293 set: function() { 59294 var formated = DPGlobal.formatDate(this.date, this.format); 59295 if (!this.isInput) { 59296 if (this.component){ 59297 this.element.find('input').prop('value', formated); 59298 } 59299 this.element.data('date', formated); 59300 } else { 59301 this.element.prop('value', formated); 59302 } 59303 }, 59304 59305 setValue: function(newDate) { 59306 if (typeof newDate === 'string') { 59307 this.date = DPGlobal.parseDate(newDate, this.format); 59308 } else { 59309 this.date = new Date(newDate); 59310 } 59311 this.set(); 59312 this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); 59313 this.fill(); 59314 }, 59315 59316 place: function(){ 59317 var offset = this.component ? this.component.offset() : this.element.offset(); 59318 this.picker.css({ 59319 top: offset.top + this.height, 59320 left: offset.left 59321 }); 59322 }, 59323 59324 update: function(newDate){ 59325 this.date = DPGlobal.parseDate( 59326 typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), 59327 this.format 59328 ); 59329 this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); 59330 this.fill(); 59331 }, 59332 59333 fillDow: function(){ 59334 var dowCnt = this.weekStart; 59335 var html = '<tr>'; 59336 while (dowCnt < this.weekStart + 7) { 59337 html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>'; 59338 } 59339 html += '</tr>'; 59340 this.picker.find('.datepicker-days thead').append(html); 59341 }, 59342 59343 fillMonths: function(){ 59344 var html = ''; 59345 var i = 0 59346 while (i < 12) { 59347 html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>'; 59348 } 59349 this.picker.find('.datepicker-months td').append(html); 59350 }, 59351 59352 fill: function() { 59353 var d = new Date(this.viewDate), 59354 year = d.getFullYear(),
59355 month = d.getMonth(), 59356 currentDate = this.date.valueOf(); 59357 this.picker.find('.datepicker-days th:eq(1)') 59358 .text(DPGlobal.dates.months[month]+' '+year); 59359 var prevMonth = new Date(year, month-1, 28,0,0,0,0), 59360 day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); 59361 prevMonth.setDate(day); 59362 prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); 59363 var nextMonth = new Date(prevMonth); 59364 nextMonth.setDate(nextMonth.getDate() + 42); 59365 nextMonth = nextMonth.valueOf(); 59366 var html = []; 59367 var clsName, 59368 prevY, 59369 prevM; 59370 while(prevMonth.valueOf() < nextMonth) { 59371 if (prevMonth.getDay() === this.weekStart) { 59372 html.push('<tr>'); 59373 } 59374 clsName = this.onRender(prevMonth); 59375 prevY = prevMonth.getFullYear(); 59376 prevM = prevMonth.getMonth(); 59377 if ((prevM < month && prevY === year) || prevY < year) { 59378 clsName += ' old'; 59379 } else if ((prevM > month && prevY === year) || prevY > year) { 59380 clsName += ' new'; 59381 } 59382 if (prevMonth.valueOf() === currentDate) { 59383 clsName += ' active'; 59384 } 59385 html.push('<td class="day '+clsName+'">'+prevMonth.getDate() + '</td>'); 59386 if (prevMonth.getDay() === this.weekEnd) { 59387 html.push('</tr>'); 59388 } 59389 prevMonth.setDate(prevMonth.getDate()+1); 59390 } 59391 this.picker.find('.datepicker-days tbody').empty().append(html.join('')); 59392 var currentYear = this.date.getFullYear(); 59393 59394 var months = this.picker.find('.datepicker-months') 59395 .find('th:eq(1)') 59396 .text(year) 59397 .end() 59398 .find('span').removeClass('active'); 59399 if (currentYear === year) { 59400 months.eq(this.date.getMonth()).addClass('active'); 59401 } 59402 59403 html = ''; 59404 year = parseInt(year/10, 10) * 10; 59405 var yearCont = this.picker.find('.datepicker-years') 59406 .find('th:eq(1)') 59407 .text(year + '-' + (year + 9)) 59408 .end() 59409 .find('td'); 59410 year -= 1; 59411 for (var i = -1; i < 11; i++) { 59412 html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>'; 59413 year += 1; 59414 } 59415 yearCont.html(html); 59416 }, 59417 59418 click: function(e) { 59419 e.stopPropagation(); 59420 e.preventDefault(); 59421 var target = $(e.target).closest('span, td, th'); 59422 if (target.length === 1) { 59423 switch(target[0].nodeName.toLowerCase()) { 59424 case 'th': 59425 switch(target[0].className) { 59426 case 'switch': 59427 this.showMode(1); 59428 break; 59429 case 'prev': 59430 case 'next': 59431 this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( 59432 this.viewDate, 59433 this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + 59434 DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) 59435 ); 59436 this.fill(); 59437 this.set(); 59438 break; 59439 } 59440 break; 59441 case 'span': 59442 if (target.is('.month')) { 59443 var month = target.parent().find('span').index(target); 59444 this.viewDate.setMonth(month); 59445 } else { 59446 var year = parseInt(target.text(), 10)||0; 59447 this.viewDate.setFullYear(year); 59448 } 59449 if (this.viewMode !== 0) { 59450 this.date = new Date(this.viewDate); 59451 this.element.trigger({ 59452 type: 'changeDate', 59453 date: this.date, 59454 viewMode: DPGlobal.modes[this.viewMode].clsName 59455 }); 59456 } 59457 this.showMode(-1); 59458 this.fill(); 59459 this.set(); 59460 break; 59461 case 'td': 59462 if (target.is('.day') && !target.is('.disabled')){ 59463 var day = parseInt(target.text(), 10)||1; 59464 var month = this.viewDate.getMonth(); 59465 if (target.is('.old')) { 59466 month -= 1; 59467 } else if (target.is('.new')) { 59468 month += 1; 59469 } 59470 var year = this.viewDate.getFullYear(); 59471 this.date = new Date(year, month, day,0,0,0,0); 59472 this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); 59473 this.fill(); 59474 this.set(); 59475 this.element.trigger({ 59476 type: 'changeDate', 59477 date: this.date, 59478 viewMode: DPGlobal.modes[this.viewMode].clsName 59479 }); 59480 } 59481 break; 59482 } 59483 } 59484 }, 59485 59486 mousedown: function(e){ 59487 e.stopPropagation(); 59488 e.preventDefault(); 59489 }, 59490 59491 showMode: function(dir) { 59492 if (dir) { 59493 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); 59494 } 59495 this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); 59496 } 59497 }; 59498 59499 $.fn.datepicker = function ( option, val ) { 59500 return this.each(function () { 59501 var $this = $(this), 59502 data = $this.data('datepicker'), 59503 options = typeof option === 'object' && option; 59504 if (!data) { 59505 $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); 59506 } 59507 if (typeof option === 'string') data[option](val); 59508 }); 59509 }; 59510 59511 $.fn.datepicker.defaults = { 59512 onRender: function(date) { 59513 return ''; 59514 } 59515 }; 59516 $.fn.datepicker.Constructor = Datepicker; 59517 59518 var DPGlobal = { 59519 modes: [ 59520 { 59521 clsName: 'days', 59522 navFnc: 'Month', 59523 navStep: 1 59524 }, 59525 { 59526 clsName: 'months', 59527 navFnc: 'FullYear', 59528 navStep: 1 59529 }, 59530 { 59531 clsName: 'years', 59532 navFnc: 'FullYear', 59533 navStep: 10 59534 }], 59535 dates:{ 59536 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], 59537 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], 59538 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], 59539 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
59539November", "December"], 59540 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 59541 }, 59542 isLeapYear: function (year) { 59543 return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) 59544 }, 59545 getDaysInMonth: function (year, month) { 59546 return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] 59547 }, 59548 parseFormat: function(format){ 59549 var separator = format.match(/[.\/\-\s].*?/), 59550 parts = format.split(/\W+/); 59551 if (!separator || !parts || parts.length === 0){ 59552 throw new Error("Invalid date format."); 59553 } 59554 return {separator: separator, parts: parts}; 59555 }, 59556 parseDate: function(date, format) { 59557 var parts = date.split(format.separator), 59558 date = new Date(), 59559 val; 59560 date.setHours(0); 59561 date.setMinutes(0); 59562 date.setSeconds(0); 59563 date.setMilliseconds(0); 59564 if (parts.length === format.parts.length) { 59565 var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); 59566 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 59567 val = parseInt(parts[i], 10)||1; 59568 switch(format.parts[i]) { 59569 case 'dd': 59570 case 'd': 59571 day = val; 59572 date.setDate(val); 59573 break; 59574 case 'mm': 59575 case 'm': 59576 month = val - 1; 59577 date.setMonth(val - 1); 59578 break; 59579 case 'yy': 59580 year = 2000 + val; 59581 date.setFullYear(2000 + val); 59582 break; 59583 case 'yyyy': 59584 year = val; 59585 date.setFullYear(val); 59586 break; 59587 } 59588 } 59589 date = new Date(year, month, day, 0 ,0 ,0); 59590 } 59591 return date; 59592 }, 59593 formatDate: function(date, format){ 59594 var val = { 59595 d: date.getDate(), 59596 m: date.getMonth() + 1, 59597 yy: date.getFullYear().toString().substring(2), 59598 yyyy: date.getFullYear() 59599 }; 59600 val.dd = (val.d < 10 ? '0' : '') + val.d; 59601 val.mm = (val.m < 10 ? '0' : '') + val.m; 59602 var date = []; 59603 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 59604 date.push(val[format.parts[i]]); 59605 } 59606 return date.join(format.separator); 59607 }, 59608 headTemplate: '<thead>'+ 59609 '<tr>'+ 59610 '<th class="prev">‹</th>'+ 59611 '<th colspan="5" class="switch"></th>'+ 59612 '<th class="next">›</th>'+ 59613 '</tr>'+ 59614 '</thead>', 59615 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>' 59616 }; 59617 DPGlobal.template = '<div class="datepicker dropdown-menu">'+ 59618 '<div class="datepicker-days">'+ 59619 '<table class=" table-condensed">'+ 59620 DPGlobal.headTemplate+ 59621 '<tbody></tbody>'+ 59622 '</table>'+ 59623 '</div>'+ 59624 '<div class="datepicker-months">'+ 59625 '<table class="table-condensed">'+ 59626 DPGlobal.headTemplate+ 59627 DPGlobal.contTemplate+ 59628 '</table>'+ 59629 '</div>'+ 59630 '<div class="datepicker-years">'+ 59631 '<table class="table-condensed">'+ 59632 DPGlobal.headTemplate+ 59633 DPGlobal.contTemplate+ 59634 '</table>'+ 59635 '</div>'+ 59636 '</div>'; 59637 59638}( window.jQuery ); 59639(function() { 59640 var base, 59641 bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 59642 59643 if ((base = App.Pages).Profile == null) { 59644 base.Profile = {}; 59645 } 59646 59647 App.Pages.Profile.HyperwalletAccountsNew = (function() { 59648 function HyperwalletAccountsNew() { 59649 this.onCountrySelect = bind(this.onCountrySelect, this); 59650 this.onTabClick = bind(this.onTabClick, this); 59651 } 59652 59653 HyperwalletAccountsNew.prototype.initialize = function() { 59654 this.initTabs(); 59655 this.activateFormData(this.currentType()); 59656 this.initCountrySelection(); 59657 this.initDatePicker(); 59658 return this.initAttachmentsUploader(this.currentType()); 59659 }; 59660 59661 HyperwalletAccountsNew.prototype.initTabs = function() { 59662 var defaultTab; 59663 defaultTab = $(".payment-tabs a[data-type=" + (this.currentType()) + "]").parents('li'); 59664 $('.payment-tabs').easytabs({ 59665 animate: true, 59666 panelActiveClass: 'is-active', 59667 tabActiveClass: 'is-active', 59668 updateHash: false, 59669 defaultTab: defaultTab 59670 }); 59671 return $('.payment-tabs .tabs--sealed a').on('click', this.onTabClick); 59672 }; 59673 59674 HyperwalletAccountsNew.prototype.onTabClick = function(e) { 59675 var $el; 59676 $el = $(e.currentTarget); 59677 this.activateFormData($el.data('type')); 59678 return this.onCountrySelect(); 59679 }; 59680 59681 HyperwalletAccountsNew.prototype.activateFormData = function(type) { 59682 var $form; 59683 $form = $('.hyperwallet-account-form'); 59684 $('.js-payment-type-field').val(type); 59685 $form.find('input, select').prop('required', false); 59686 $form.find("#payment_" + type).find('input, select').prop('required', true); 59687 return $form.find('.js-ignore-required').prop('required', false); 59688 }; 59689 59690 HyperwalletAccountsNew.prototype.currentType = function() { 59691 return $('.js-payment-type-field').val(); 59692 }; 59693 59694 HyperwalletAccountsNew.prototype.initCountrySelection = function() { 59695 this.onCountrySelect(); 59696 $('select[name="company_country"]').on('change', this.onCountrySelect); 59697 return $('select[name="country"]').on('change', this.onCountrySelect); 59698 }; 59699 59700 HyperwalletAccountsNew.prototype.initDatePicker = function() { 59701 var $datePicker; 59702 $datePicker = $(".datepicker-input").datepicker({ 59703 format: "yyyy-mm-dd" 59704 }); 59705 return $datePicker.datepicker("hide"); 59706 }; 59707 59708 HyperwalletAccountsNew.prototype.onCountrySelect = function() { 59709 var $countrySelectField, $hyperwalletFields, $payoneerFields; 59710 if (this.currentType() === 'business') { 59711 $countrySelectField = $('select[name="company_country"]'); 59712 } else { 59713 $countrySelectField = $('select[name="country"]'); 59714 } 59715 $hyperwalletFields = $('.hyperwallet-fields'); 59716 $payoneerFields = $('.payoneer-fields'); 59717 if (['iq', 'af', 'tr'].includes($countrySelectField.val()) || $('.js-force-payonner
59717-agreement-field').val() === 'true') { 59718 $hyperwalletFields.addClass('is-hidden'); 59719 $payoneerFields.removeClass('is-hidden'); 59720 $payoneerFields.find("input").prop('required', true); 59721 $payoneerFields.find(".js-attachments-upload").removeAttr('required'); 59722 return $hyperwalletFields.find("input").prop('required', false); 59723 } else { 59724 $hyperwalletFields.removeClass('is-hidden'); 59725 $payoneerFields.addClass('is-hidden'); 59726 $payoneerFields.find("input").prop('required', false); 59727 return $hyperwalletFields.find("input").prop('required', true); 59728 } 59729 }; 59730 59731 HyperwalletAccountsNew.prototype.initAttachmentsUploader = function(currentType) { 59732 var $paymentInput; 59733 $paymentInput = $(".payoneer-fields").find('#fileupload'); 59734 return new App.Modules.FileUpload('/profile/hyperwallet-account/upload_attachment', $paymentInput); 59735 }; 59736 59737 return HyperwalletAccountsNew; 59738 59739 })(); 59740 59741}).call(this); 59742(function() { 59743 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 59744 hasProp = {}.hasOwnProperty; 59745 59746 App.Pages.Profile.HyperwalletAccountsCreate = (function(superClass) { 59747 extend(HyperwalletAccountsCreate, superClass); 59748 59749 function HyperwalletAccountsCreate() { 59750 return HyperwalletAccountsCreate.__super__.constructor.apply(this, arguments); 59751 } 59752 59753 return HyperwalletAccountsCreate; 59754 59755 })(App.Pages.Profile.HyperwalletAccountsNew); 59756 59757}).call(this); 59758(function() { 59759 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 59760 hasProp = {}.hasOwnProperty; 59761 59762 App.Pages.Profile.HyperwalletAccountsEdit = (function(superClass) { 59763 extend(HyperwalletAccountsEdit, superClass); 59764 59765 function HyperwalletAccountsEdit() { 59766 return HyperwalletAccountsEdit.__super__.constructor.apply(this, arguments); 59767 } 59768 59769 return HyperwalletAccountsEdit; 59770 59771 })(App.Pages.Profile.HyperwalletAccountsNew); 59772 59773}).call(this); 59774(function() { 59775 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 59776 59777 App.Pages.Profile.HyperwalletAccountsIndex = (function() { 59778 function HyperwalletAccountsIndex() { 59779 this.closeActivationModal = bind(this.closeActivationModal, this); 59780 } 59781 59782 HyperwalletAccountsIndex.prototype.initialize = function() { 59783 var cookieName, cookieValue, haveCookie, that; 59784 cookieName = 'new_payment_agreement_created'; 59785 cookieValue = Cookies.get(cookieName); 59786 haveCookie = cookieValue && ['individual', 'business'].includes(cookieValue); 59787 if (haveCookie) { 59788 this.showActivationModal(); 59789 if (window.customEventTracker) { 59790 return this.trackPaymentAgreementCreation(cookieValue); 59791 } else { 59792 that = this; 59793 return App.events.subscribe('app:tracking:load', function(data) { 59794 return that.trackPaymentAgreementCreation(cookieValue); 59795 }); 59796 } 59797 } 59798 }; 59799 59800 HyperwalletAccountsIndex.prototype.showActivationModal = function() { 59801 var modalTemplate; 59802 modalTemplate = $('#hyperwallet-activation-modal').html(); 59803 if (!modalTemplate) { 59804 return; 59805 } 59806 $('body').prepend(modalTemplate); 59807 $(document).on('click.hyperwalletActivationModal', '.js-close-modal', this.closeActivationModal); 59808 return $(document).on('click.hyperwalletActivationModal', '.overlay-modal--background', (function(_this) { 59809 return function(event) { 59810 if ($(event.target).hasClass('overlay-modal--background')) { 59811 return _this.closeActivationModal(); 59812 } 59813 }; 59814 })(this)); 59815 }; 59816 59817 HyperwalletAccountsIndex.prototype.closeActivationModal = function() { 59818 $('body').find('.overlay-modal--background').remove(); 59819 return $(document).off('.hyperwalletActivationModal'); 59820 }; 59821 59822 HyperwalletAccountsIndex.prototype.trackPaymentAgreementCreation = function(value) { 59823 var userId; 59824 userId = App.config.userId || ''; 59825 window.customEventTracker({ 59826 name: 'create_payment_agreement', 59827 userId: userId, 59828 customAttributes: {
59829 user_type: value 59830 }, 59831 eventData: {} 59832 }); 59833 return Cookies.remove('new_payment_agreement_created'); 59834 }; 59835 59836 return HyperwalletAccountsIndex; 59837 59838 })(); 59839 59840}).call(this); 59841(function() { 59842 var base, 59843 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 59844 hasProp = {}.hasOwnProperty; 59845 59846 if ((base = App.Pages).Profile == null) { 59847 base.Profile = {}; 59848 } 59849 59850 App.Pages.Profile.ItemsIndex = (function(superClass) { 59851 extend(ItemsIndex, superClass); 59852 59853 function ItemsIndex() { 59854 return ItemsIndex.__super__.constructor.apply(this, arguments); 59855 } 59856 59857 ItemsIndex.prototype.widgets = ['downloads']; 59858 59859 ItemsIndex.prototype.initialize = function() { 59860 this.bindEvents(); 59861 return this.initValidation(); 59862 }; 59863 59864 ItemsIndex.prototype.bindEvents = function() { 59865 $('.js-select-menu').on('change', this.onCheckboxClick); 59866 $('.js-select-all-in-page').on('click', this.onSelectAll); 59867 $('.js-select-filtered').on('click', this.onSelectFiltered); 59868 return $('.js-select-units').on('change', this.onUnitsChange); 59869 }; 59870 59871 ItemsIndex.prototype.onCheckboxClick = function(e) { 59872 if (e.target.checked === true) { 59873 return $('.js-menu').show(); 59874 } else { 59875 $('.js-menu').hide(); 59876 return $('input:checkbox').each(function() { 59877 return $(this).prop('checked', false); 59878 }); 59879 } 59880 }; 59881 59882 ItemsIndex.prototype.onSelectAll = function(e) { 59883 e.preventDefault(); 59884 $('.js-selected').val('this_page'); 59885 $('input:checkbox').each(function() { 59886 return $(this).prop('checked', true); 59887 }); 59888 return $('.js-menu').hide(); 59889 }; 59890 59891 ItemsIndex.prototype.onSelectFiltered = function(e) { 59892 e.preventDefault(); 59893 $('.js-selected').val('filtered'); 59894 $('input:checkbox').each(function() { 59895 return $(this).prop('checked', true); 59896 }); 59897 return $('.js-menu').hide(); 59898 }; 59899 59900 ItemsIndex.prototype.onUnitsChange = function(e) { 59901 $('#price').rules('remove', 'max'); 59902 $('#price').rules('remove', 'min'); 59903 if (e.target.value === 'set') { 59904 $('.js-change-units').text('$'); 59905 return $('#price').rules('add', { 59906 min: 2 59907 }); 59908 } else { 59909 $('.js-change-units').text('%'); 59910 if (e.target.value === 'decrease') { 59911 return $('#price').rules('add', { 59912 max: 99 59913 }); 59914 } 59915 } 59916 }; 59917 59918 ItemsIndex.prototype.validationSettings = function() { 59919 return { 59920 rules: { 59921 price: { 59922 required: true, 59923 min: 2 59924 } 59925 } 59926 }; 59927 }; 59928 59929 ItemsIndex.prototype.initValidation = function() { 59930 return $('#price-change-form').validate(this.validationSettings()); 59931 }; 59932 59933 return ItemsIndex; 59934 59935 })(App.Core.Page); 59936 59937}).call(this); 59938(function() { 59939 var base, 59940 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 59941 hasProp = {}.hasOwnProperty; 59942 59943 if ((base = App.Pages).Profile == null) { 59944 base.Profile = {}; 59945 } 59946 59947 App.Pages.Profile.ItemsShow = (function(superClass) { 59948 extend(ItemsShow, superClass); 59949 59950 function ItemsShow() { 59951 return ItemsShow.__super__.constructor.apply(this, arguments); 59952 } 59953 59954 ItemsShow.prototype.widgets = ['comments', 'reportContent', 'likes', 'wishLists']; 59955 59956 ItemsShow.prototype.initialize = function() { 59957 $(document).on('click', '.js-publish-in-preview', (function(_this) { 59958 return function(event) { 59959 mute(event); 59960 return _this.tryPublishing(event); 59961 }; 59962 })(this)); 59963 return ItemsShow.__super__.initialize.call(this); 59964 }; 59965 59966 ItemsShow.prototype.tryPublishing = function(event) { 59967 return $.ajax({ 59968 type: 'POST', 59969 url: "/profile/items/" + ($(event.target).data('id')) + "/publish", 59970 data: { 59971 item: { 59972 created_at: Date.now() 59973 } 59974 }, 59975 success: function(response, status) { 59976 if (response.error_message) { 59977 return App.events.publish('app:notification:flash:error', response.error_message); 59978 } else { 59979 return window.location = response.location; 59980 } 59981 } 59982 }); 59983 }; 59984 59985 return ItemsShow; 59986 59987 })(App.Pages.ProductsShow); 59988 59989}).call(this); 59990(function() { 59991 var base, 59992 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 59993 hasProp = {}.hasOwnProperty; 59994 59995 if ((base = App.Pages).Profile == null) { 59996 base.Profile = {}; 59997 } 59998 59999 App.Pages.Profile.LikedModelsIndex = (function(superClass) { 60000 extend(LikedModelsIndex, superClass); 60001 60002 function LikedModelsIndex() { 60003 return LikedModelsIndex.__super__.constructor.apply(this, arguments); 60004 } 60005 60006 LikedModelsIndex.prototype.widgets = ['downloads']; 60007 60008 return LikedModelsIndex; 60009 60010 })(App.Core.Page); 60011 60012}).call(this); 60013(function() { 60014 var base; 60015 60016 if ((base = App.Pages).Profile == null) { 60017 base.Profile = {}; 60018 } 60019 60020 App.Pages.Profile.PasswordRequestPassword = (function() { 60021 function PasswordRequestPassword() {} 60022 60023 PasswordRequestPassword.prototype.initialize = function() { 60024 this.$form = $('.js-complete-registration-form'); 60025 return this.initValidation(); 60026 }; 60027 60028 PasswordRequestPassword.prototype.validationSettings = function() { 60029 return { 60030 rules: { 60031 'email[]': { 60032 required: true, 60033 email: true 60034 }, 60035 password: { 60036 required: true, 60037 minlength: 8, 60038 validatePassword: true 60039 } 60040 } 60041 }; 60042 }; 60043 60044 PasswordRequestPassword.prototype.initValidation = function() { 60045 return this.$form.validate(this.validationSettings()); 60046 }; 60047 60048 return PasswordRequestPassword; 60049 60050 })(); 60051 60052}).call(this); 60053(function() { 60054 var base, 60055 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 60056 hasProp = {}.hasOwnProperty; 60057 60058 if ((base = App.Pages).Profile == null) { 60059 base.Profile = {}; 60060 } 60061 60062 App.Pages.Profile.PurchasesIndex = (function(superClass) { 60063 extend(PurchasesIndex, superClass); 60064 60065 function PurchasesIndex() { 60066 return PurchasesIndex.__super__.constructor.apply(this, arguments); 60067 } 60068 60069 PurchasesIndex.prototype.widgets = ['downloads', 'loyaltyLevelProgressInfoTooltip']; 60070 60071 return PurchasesIndex; 60072 60073 })(App.Core.Page); 60074 60075}).call(this); 60076(function() { 60077 var base; 60078 60079 if ((base = App.Pages).Profile == null) { 60080 base.Profile = {}; 60081 } 60082 60083 App.Pages.Profile.ReferralsIndex = (function() { 60084 function ReferralsIndex() {} 60085 60086 ReferralsIndex.prototype.initialize = function() { 60087 return this.initFacebookShareButton(); 60088 }; 60089 60090 ReferralsIndex.prototype.initFacebookShareButton = function() { 60091 var $el; 60092 $el = $('.js-facebook-share'); 60093 return $el.click(function(e) { 60094 e.preventDefault(); 60095 e.stopPropagation(); 60096 FB.init({ 60097 appId: App.config.facebookAppId 60098 }); 60099 return FB.ui({ 60100 method: 'share', 60101 href: $el.data('url') 60102 }); 60103 }); 60104 }; 60105 60106 return ReferralsIndex; 60107 60108 })(); 60109 60110}).call(this); 60111(function() { 60112 var base; 60113 60114 if ((base = App.Pages).Profile == null) { 60115 base.Profile = {}; 60116 } 60117 60118 App.Pages.Profile.SettingsShow = (function() { 60119 function SettingsShow() {} 60120 60121 SettingsShow.prototype.initialize = function() { 60122 this.$mainForm = $('#tab-settings-main').find('.edit_user'); 60123 this.$passwordForm = $('#tab-settings-password').find('.edit_user'); 60124 this.$usernameForm = $('#tab-settings-username').find('.edit_user'); 60125 this.$infoForm = $('#tab-settings-info').find('form'); 60126 this.$notificationsForm = $('#tab-settings-notifications').find('.edit_user'); 60127 this.initTabs(); 60128 this.initValidation(); 60129 this.initTracking(); 60130 this.initAvatarUploader(); 60131 return this.bindEvents(); 60132 }; 60133 60134 SettingsShow.prototype.bindEvents = function() { 60135 var countryField, ref, ref1, ref2; 60136 $('.js-email-field').on('input', (function(_this) { 60137 return function() { 60138 return _this.onEmailChange(_this.$mainForm); 60139 }; 60140 })(this)); 60141 $('.js-sale-off').on('change', this.onSaleOffChange); 60142 $('.js-engagement').on('change', this.onBuyerEngagementChange); 60143 $('.js-segment-radio').on('change', this.onUserSegmentChange); 60144 $('.js-accept-price-offers').on('change', this.onAcceptPriceOffersChange); 60145 countryField = $('#info_country')[0]; 60146 if (countryField == null) { 60147 return; 60148 } 60149 if (((ref = window.google) != null ? (ref1 = ref.maps) != null ? (ref2 = ref1.places) != null ? ref2.Autocomplete : void 0 : void 0 : void 0) == null) { 60150 return; 60151 } 60152 return new window.google.maps.places.Autocomplete(countryField, {}); 60153 }; 60154 60155 SettingsShow.prototype.initTabs = function() { 60156 return $('.js-tabs').easytabs({ 60157 animate: false, 60158 panelActiveClass: 'is-active', 60159 tabActiveClass: 'is-active' 60160 }); 60161 }; 60162 60163 SettingsShow.prototype.validationSettings = function() { 60164 return { 60165 rules: { 60166 'user[email]': { 60167 required: true, 60168 email: true 60169 }, 60170 'user[birthday]': { 60171 validDateFormat: true 60172 }, 60173 'user[current_password]': { 60174 required: true 60175 }, 60176 'user[password]': { 60177 required: true, 60178 minlength: 8, 60179 validatePassword: true 60180 }, 60181 'user[password_confirmation]': { 60182 required: true, 60183 equalTo: '#user_password' 60184 }, 60185 'user[new_username]': { 60186 required: true, 60187 validateUsername: true 60188 }, 60189 'user[new_username_confirmation]': { 60190 required: true, 60191 validateUsername: true, 60192 equalTo: '#user_new_username' 60193 } 60194 }, 60195 errorPlacement: function(error, element) { 60196 if (element.attr('name') === 'user[birthday]') { 60197 return error.appendTo($('.js-birthday-field-error')); 60198 } else { 60199 return error.insertAfter(element); 60200 } 60201 } 60202 }; 60203 }; 60204 60205 SettingsShow.prototype.getNotificationSettings = function() { 60206 var selctedSettingsRows, selectedSettings; 60207 selectedSettings = []; 60208 selctedSettingsRows = $('.checkbox:checked').closest('tr'); 60209 selctedSettingsRows.each(function(index, row) { 60210 return selectedSettings.push($(row).find('td[data-tracking-label]').attr('data-tracking-label')); 60211 }); 60212 return selectedSettings.join('_'); 60213 }; 60214 60215 SettingsShow.prototype.prepareTrackingAttributes = function() { 60216 var activeTab, settingsType; 60217 activeTab = $('.js-tabs .tabs').find('a.is-active'); 60218 settingsType = activeTab.attr('data-tracking-label'); 60219 return settingsType; 60220 }; 60221 60222 SettingsShow.prototype.trackFormSubmit = function(notificationSettings) { 60223 var settingsType; 60224 if (notificationSettings == null) { 60225 notificationSettings = ''; 60226 } 60227 settingsType = window.prepareSettingsTrackingAttributes(); 60228 return window.customEventTracker({ 60229 name: 'update_account_settings', 60230 eventData: { 60231 'settings_type': settingsType, 60232 'notification_settings_checked': notificationSettings 60233 } 60234 }); 60235 }; 60236 60237 SettingsShow.prototype.handleFormSubmit = function(e, form) { 60238 var isNotificationsForm, notificationSettings; 60239 if (form.valid()) { 60240 e.preventDefault(); 60241 e.stopPropagation();
60242 isNotificationsForm = form === this.$notificationsForm; 60243 notificationSettings = ''; 60244 if (isNotificationsForm) { 60245 notificationSettings = this.getNotificationSettings(); 60246 } 60247 this.trackFormSubmit(notificationSettings); 60248 return $(e.currentTarget).unbind().submit(); 60249 } 60250 }; 60251 60252 SettingsShow.prototype.initTracking = function() { 60253 var forms, that; 60254 that = this; 60255 forms = [this.$mainForm, this.$usernameForm, this.$passwordForm, this.$infoForm, this.$notificationsForm]; 60256 window.trackSettingsFormSubmit = this.trackFormSubmit; 60257 window.prepareSettingsTrackingAttributes = this.prepareTrackingAttributes; 60258 return forms.forEach(function(form) { 60259 return form.on('submit', function(e) { 60260 return that.handleFormSubmit(e, form); 60261 }); 60262 }); 60263 }; 60264 60265 SettingsShow.prototype.initValidation = function() { 60266 this.$mainForm.validate(this.validationSettings()); 60267 this.$passwordForm.validate(this.validationSettings()); 60268 return this.$usernameForm.validate(this.validationSettings()); 60269 }; 60270 60271 SettingsShow.prototype.initAvatarUploader = function() { 60272 return $('.js-avatar-upload').fileupload({ 60273 dataType: "json", 60274 url: "/api/internal/users/upload_avatar", 60275 autoUpload: true, 60276 add: function(e, data) { 60277 $("#upload-action").fadeOut().promise().done(function() { 60278 $("#upload-action").addClass("is-hidden"); 60279 return $("#upload-progress").fadeIn().promise().done(function() { 60280 return $("#upload-progress").removeClass("is-hidden"); 60281 }); 60282 }); 60283 return data.submit(); 60284 }, 60285 done: function(e, data) { 60286 $(".avatar img").fadeOut().promise().done(function() { 60287 return $(".avatar img").attr("src", data.jqXHR.responseJSON.url).fadeIn(); 60288 }); 60289 return $("#upload-progress").fadeOut().promise().done(function() { 60290 $("#upload-progress").addClass("is-hidden"); 60291 return $("#upload-action").fadeIn().promise().done(function() { 60292 return $("#upload-action").removeClass("is-hidden"); 60293 }); 60294 }); 60295 } 60296 }); 60297 }; 60298 60299 SettingsShow.prototype.onEmailChange = function(form) { 60300 form.find('.js-submit-button').addClass("is-hidden"); 60301 return form.find('.js-tfa-trigger').removeClass("is-hidden"); 60302 }; 60303 60304 SettingsShow.prototype.onSaleOffChange = function(e) { 60305 if (!e.target.checked) { 60306 return $('.js-unchecked-sale-off').val(false); 60307 } 60308 }; 60309 60310 SettingsShow.prototype.onBuyerEngagementChange = function(e) { 60311 if (!e.target.checked) { 60312 return $('.js-unchecked-buyer-engagement').val(false); 60313 } 60314 }; 60315 60316 SettingsShow.prototype.onUserSegmentChange = function(e) { 60317 return $.ajax({ 60318 url: '/api/internal/users/update-segment', 60319 type: 'PUT', 60320 data: { 60321 segment: $(e.currentTarget).val() 60322 } 60323 }); 60324 }; 60325 60326 SettingsShow.prototype.onAcceptPriceOffersChange = function(e) { 60327 if (!e.target.checked) { 60328 $('.js-accept-price-offers-to').val(''); 60329 return $('.js-accept-price-offers-to').prop('disabled', true); 60330 } else { 60331 return $('.js-accept-price-offers-to').prop('disabled', false); 60332 } 60333 }; 60334 60335 return SettingsShow; 60336 60337 })(); 60338 60339}).call(this); 60340(function() { 60341 var base, 60342 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 60343 hasProp = {}.hasOwnProperty; 60344 60345 if ((base = App.Pages).Profile == null) { 60346 base.Profile = {}; 60347 } 60348 60349 App.Pages.Profile.WishListsShow = (function(superClass) { 60350 extend(WishListsShow, superClass); 60351 60352 function WishListsShow() { 60353 return WishListsShow.__super__.constructor.apply(this, arguments); 60354 } 60355 60356 WishListsShow.prototype.initialize = function() { 60357 return this.bindEvents(); 60358 }; 60359 60360 WishListsShow.prototype.bindEvents = function() { 60361 var that; 60362 that = this; 60363 $('.js-remove-selected').click(this.removeSelected); 60364 $('.js-purchase-selected').click(this.purchaseSelected);
60365 $('.js-purchase-all').click(this.purchaseAll); 60366 $('.js-model-type-select').chosen().change(function(event, data) { 60367 return that.onSelect(event, data, 'model type'); 60368 }); 60369 $('.js-model-category-select').chosen().change(function(event, data) { 60370 return that.onSelect(event, data, 'model category'); 60371 }); 60372 return $('#wish-list-search-form form').submit(function(event) { 60373 event.preventDefault(); 60374 that.onSearchSubmit(); 60375 return this.submit(); 60376 }); 60377 }; 60378 60379 WishListsShow.prototype.onSearchSubmit = function() { 60380 var inputValue, textInput; 60381 textInput = $('#keywords'); 60382 inputValue = textInput.val(); 60383 if (window.searchTracker && inputValue) { 60384 return window.searchTracker({ 60385 searchTerm: inputValue, 60386 type: 'wish list' 60387 }); 60388 } 60389 }; 60390 60391 WishListsShow.prototype.removeSelected = function() { 60392 var selectedItemIds; 60393 selectedItemIds = []; 60394 $('.content-box.is-checked .js-check-box').each(function(index, el) { 60395 return selectedItemIds.push($(el).data('id')); 60396 }); 60397 return $.ajax({ 60398 url: "/api/internal/wish-lists/" + gon.wish_list_id + "/items/0", 60399 type: 'DELETE', 60400 data: { 60401 item_ids: selectedItemIds 60402 }, 60403 success: function() { 60404 return window.location.reload(); 60405 } 60406 }); 60407 }; 60408 60409 WishListsShow.prototype.purchaseSelected = function() { 60410 return $('.content-box.is-checked .js-order').click(); 60411 }; 60412 60413 WishListsShow.prototype.purchaseAll = function() { 60414 return $('.content-box .js-order').click(); 60415 }; 60416 60417 WishListsShow.prototype.onSelect = function(event, data, name) { 60418 var matchingOption, optionsElements, optionsValues, query, searchQuery, type, value; 60419 searchQuery = $('#keywords'); 60420 value = data.selected; 60421 if (name === 'model category') { 60422 optionsElements = event.target.options || []; 60423 optionsValues = Array.from(optionsElements).map((function(_this) { 60424 return function(opt) { 60425 return { 60426 value: opt.value, 60427 label: opt.text 60428 }; 60429 }; 60430 })(this)); 60431 matchingOption = optionsValues.find((function(_this) { 60432 return function(opt) { 60433 return opt.value === data.selected; 60434 }; 60435 })(this)); 60436 if (matchingOption) { 60437 value = matchingOption.label; 60438 } 60439 } 60440 if (window.filterTracker && data.selected) { 60441 query = searchQuery.val(); 60442 type = 'wish list'; 60443 window.removeCurrentSearchFilter({ 60444 name: name 60445 }); 60446 window.filterTracker({ 60447 name: name, 60448 value: value, 60449 searchTerm: query, 60450 type: type 60451 }); 60452 return window.searchTracker({ 60453 searchTerm: query, 60454 type: type 60455 }); 60456 } 60457 }; 60458 60459 return WishListsShow; 60460 60461 })(App.Core.Page); 60462 60463}).call(this); 60464if (!RedactorPlugins) var RedactorPlugins = {}; 60465 60466RedactorPlugins.fullscreen = { 60467 init: function() 60468 { 60469 this.fullscreen = false; 60470 60471 this.buttonAdd('fullscreen', 'Fullscreen', $.proxy(this.toggleFullscreen, this)); 60472 this.buttonSetRight('fullscreen'); 60473 60474 if (this.opts.fullscreen) this.toggleFullscreen(); 60475 }, 60476 toggleFullscreen: function() 60477 { 60478 var html; 60479 60480 if (!this.fullscreen) 60481 { 60482 this.buttonChangeIcon('fullscreen', 'normalscreen'); 60483 this.buttonActive('fullscreen'); 60484 this.fullscreen = true; 60485 60486 if (this.opts.toolbarExternal) 60487 { 60488 this.toolcss = {}; 60489 this.boxcss = {}; 60490 this.toolcss.width = this.$toolbar.css('width'); 60491 this.toolcss.top = this.$toolbar.css('top'); 60492 this.toolcss.position = this.$toolbar.css('position'); 60493 this.boxcss.top = this.$box.css('top'); 60494 } 60495 60496 this.fsheight = this.$editor.height(); 60497 60498 if (this.opts.iframe) html = this.get(); 60499 60500 this.tmpspan = $('<span></span>'); 60501 this.$box.addClass('redactor_box_fullscreen').after(this.tmpspan); 60502 60503 $('body, html').css('overflow', 'hidden'); 60504 $('body').prepend(this.$box); 60505 60506 if (this.opts.iframe) this.fullscreenIframe(html); 60507 60508 this.fullScreenResize(); 60509 $(window).resize($.proxy(this.fullScreenResize, this)); 60510 $(document).scrollTop(0, 0); 60511 60512 this.focus(); 60513 this.observeStart(); 60514 60515 } 60516 else 60517 { 60518 this.buttonRemoveIcon('fullscreen', 'normalscreen'); 60519 this.buttonInactive('fullscreen'); 60520 this.fullscreen = false;
60521 60522 $(window).off('resize', $.proxy(this.fullScreenResize, this)); 60523 $('body, html').css('overflow', ''); 60524 60525 this.$box.removeClass('redactor_box_fullscreen').css({ width: 'auto', height: 'auto' }); 60526 60527 if (this.opts.iframe) html = this.$editor.html(); 60528 this.tmpspan.after(this.$box).remove(); 60529 60530 if (this.opts.iframe) this.fullscreenIframe(html); 60531 else this.sync(); 60532 60533 var height = this.fsheight; 60534 if (this.opts.autoresize) height = 'auto'; 60535 60536 if (this.opts.toolbarExternal) 60537 { 60538 this.$box.css('top', this.boxcss.top); 60539 this.$toolbar.css({ 60540 'width': this.toolcss.width, 60541 'top': this.toolcss.top, 60542 'position': this.toolcss.position 60543 }); 60544 } 60545 60546 if (!this.opts.iframe) this.$editor.css('height', height); 60547 else this.$frame.css('height', height); 60548 60549 this.$editor.css('height', height); 60550 this.focus(); 60551 this.observeStart(); 60552 } 60553 }, 60554 fullscreenIframe: function(html) 60555 { 60556 this.$editor = this.$frame.contents().find('body').attr({ 60557 'contenteditable': true, 60558 'dir': this.opts.direction 60559 }); 60560 60561 // set document & window 60562 if (this.$editor[0]) 60563 { 60564 this.document = this.$editor[0].ownerDocument; 60565 this.window = this.document.defaultView || window; 60566 } 60567 60568 // iframe css 60569 this.iframeAddCss(); 60570 60571 if (this.opts.fullpage) this.setFullpageOnInit(html); 60572 else this.set(html); 60573 60574 if (this.opts.wym) this.$editor.addClass('redactor_editor_wym'); 60575 }, 60576 fullScreenResize: function() 60577 { 60578 if (!this.fullscreen) return false; 60579 60580 var toolbarHeight = this.$toolbar.height(); 60581 60582 var pad = this.$editor.css('padding-top').replace('px', ''); 60583 var height = $(window).height() - toolbarHeight; 60584 this.$box.width($(window).width() - 2).height(height + toolbarHeight); 60585 60586 if (this.opts.toolbarExternal) 60587 { 60588 this.$toolbar.css({ 60589 'top': '0px', 60590 'position': 'absolute', 60591 'width': '100%' 60592 }); 60593 60594 this.$box.css('top', toolbarHeight + 'px'); 60595 } 60596 60597 if (!this.opts.iframe) this.$editor.height(height - (pad * 2)); 60598 else 60599 { 60600 setTimeout($.proxy(function() 60601 { 60602 this.$frame.height(height); 60603 60604 }, this), 1); 60605 } 60606 60607 this.$editor.height(height); 60608 } 60609}; 60610if (!RedactorPlugins) var RedactorPlugins = {}; 60611 60612RedactorPlugins.fontsize = { 60613 init: function() 60614 { 60615 var fonts = [10, 11, 12, 14, 16, 18, 20, 24, 28, 30]; 60616 var that = this; 60617 var dropdown = {}; 60618 60619 $.each(fonts, function(i, s) 60620 { 60621 dropdown['s' + i] = { title: s + 'px', callback: function() { that.setFontsize(s); } }; 60622 }); 60623 60624 dropdown['remove'] = { title: 'Remove font size', callback: function() { that.resetFontsize(); } }; 60625 60626 this.buttonAdd( 'fontsize', 'Change font size', false, dropdown); 60627 }, 60628 setFontsize: function(size) 60629 { 60630 this.inlineSetStyle('font-size', size + 'px'); 60631 }, 60632 resetFontsize: function() 60633 { 60634 this.inlineRemoveStyle('font-size'); 60635 } 60636}; 60637if (!RedactorPlugins) var RedactorPlugins = {}; 60638 60639RedactorPlugins.fontcolor = { 60640 init: function() 60641 { 60642 var colors = ['#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00', '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca', '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694', '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314', '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100', '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b', '#974806', '#7f6000']; 60643 var buttons = ['fontcolor', 'backcolor']; 60644 60645 this.buttonAddSeparator(); 60646 60647 for (var i = 0; i < 2; i++) 60648 { 60649 var name = buttons[i]; 60650 60651 var $dropdown = $('<div class="redactor_dropdown redactor_dropdown_box_' + name + '" style="display: none; width: 210px;">'); 60652 60653 this.pickerBuild($dropdown, name, colors); 60654 $(this.$toolbar).append($dropdown); 60655 60656 this.buttonAdd(name, this.opts.curLang[name], $.proxy(function(btnName, $button, btnObject, e) 60657 { 60658 this.dropdownShow(e, btnName); 60659 60660 }, this)); 60661 } 60662 }, 60663 pickerBuild: function($dropdown, name, colors) 60664 { 60665 var rule = 'color'; 60666 if (name === 'backcolor') rule = 'background-color'; 60667 60668 var _self = this; 60669 var onSwatch = function(e) 60670 { 60671 e.preventDefault(); 60672 60673 var $this = $(this); 60674 _self.pickerSet($this.data('rule'), $this.attr('rel')); 60675 60676 } 60677 60678 var len = colors.length; 60679 for (var z = 0; z < len; z++) 60680 { 60681 var color = colors[z]; 60682 60683 var $swatch = $('<a rel="' + color + '" data-rule="' + rule +'" href="#" style="float: left; font-size: 0; border: 2px solid #fff; padding: 0; margin: 0; width: 15px; height: 15px;"></a>'); 60684 $swatch.css('background-color', color); 60685 $dropdown.append($swatch); 60686 $swatch.on('click', onSwatch); 60687 } 60688 60689 var $elNone = $('<a href="#" style="display: block; clear: both; padding: 4px 0; font-size: 11px; line-height: 1;"></a>') 60690 .html(this.opts.curLang.none) 60691 .on('click', function(e) 60692 { 60693 e.preventDefault(); 60694 _self.pickerSet(rule, false); 60695 }); 60696 60697 $dropdown.append($elNone); 60698 }, 60699 pickerSet: function(rule, type) 60700 { 60701 this.bufferSet(); 60702 60703 this.$editor.focus(); 60704 this.inlineRemoveStyle(rule); 60705 if (type !== false) this.inlineSetStyle(rule, type); 60706 if (this.opts.air) this.$air.fadeOut(100); 60707 this.sync(); 60708 } 60709}; 60710if (!RedactorPlugins) var RedactorPlugins = {}; 60711 60712RedactorPlugins.fontfamily = { 60713 init: function () 60714 { 60715 var fonts = [ 'Arial', 'Helvetica', 'Georgia', 'Times New Roman', 'Monospace' ]; 60716 var that = this; 60717 var dropdown = {}; 60718 60719 $.each(fonts, function(i, s) 60720 { 60721 dropdown['s' + i] = { title: s, callback: function() { that.setFontfamily(s); }}; 60722 }); 60723 60724 dropdown['remove'] = { title: 'Remove font', callback: function() { that.resetFontfamily(); }}; 60725 60726 this.buttonAdd('fontfamily', 'Change font family', false, dropdown); 60727 }, 60728 setFontfamily: function (value) 60729 { 60730 this.inlineSetStyle('font-family', value); 60731 }, 60732 resetFontfamily: function() 60733 { 60734 this.inlineRemoveStyle('font-family'); 60735 } 60736}; 60737(function() { 60738 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 60739 hasProp = {}.hasOwnProperty; 60740 60741 App.Pages.ScholarshipNew = (function(superClass) { 60742 extend(ScholarshipNew, superClass); 60743 60744 function ScholarshipNew() { 60745 return ScholarshipNew.__super__.constructor.apply(this, arguments); 60746 } 60747 60748 ScholarshipNew.prototype.initialize = function() { 60749 this.initTabs(); 60750 this.$form = $('.scholarship-submission-form'); 60751 if (this.$form.length > 0) { 60752 $('.js-scroll-to-form').on('click', this.scrollToSubmissionForm); 60753 this.attachRedactor($('.js-essay-field')); 60754 return this.initValidation(); 60755 } 60756 }; 60757 60758 ScholarshipNew.prototype.initTabs = function() { 60759 return $('.js-scholarship-easytabs').easytabs({ 60760 animate: true, 60761 panelActiveClass: 'is-active', 60762 panelContext: $('.js-scholarship-sections'), 60763 tabActiveClass: 'is-active' 60764 }); 60765 }; 60766 60767 ScholarshipNew.prototype.scrollToSubmissionForm = function() { 60768 $('.js-scholarship-easytabs').easytabs('select', '#section-submission'); 60769 return setTimeout(function() { 60770 return $('body').scrollTo('#section-submission'); 60771 }, 500); 60772 }; 60773 60774 ScholarshipNew.prototype.attachRedactor = function($element) { 60775 return $element.redactor({ 60776 plugins: ['fullscreen', 'fontsize', 'fontcolor', 'fontfamily'], 60777 minHeight: 300, 60778 convertDivs: false, 60779 autoresize: false, 60780 buttons: ['html', '|', 'formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'table', '|', 'alignment'] 60781 }); 60782 }; 60783 60784 ScholarshipNew.prototype.validationSettings = function() { 60785 return { 60786 rules: { 60787 'scholarship_application[full_name]': { 60788 required: true 60789 }, 60790 'scholarship_application[birthday]': { 60791 required: true 60792 }, 60793 'scholarship_application[country]': { 60794 required: true 60795 }, 60796 'scholarship_application[city]': { 60797 required: true 60798 }, 60799 'scholarship_application[university]': { 60800 required: true 60801 }, 60802 'scholarship_application[email]': { 60803 required: true, 60804 email: true 60805 } 60806 } 60807 }; 60808 }; 60809 60810 ScholarshipNew.prototype.initValidation = function() { 60811 return this.$form.validate(this.validationSettings()); 60812 }; 60813 60814 return ScholarshipNew; 60815 60816 })(App.Core.Page); 60817 60818}).call(this); 60819(function() { 60820 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 60821 hasProp = {}.hasOwnProperty; 60822 60823 App.Pages.ScholarshipAnnual = (function(superClass) { 60824 extend(ScholarshipAnnual, superClass); 60825 60826 function ScholarshipAnnual() { 60827 return ScholarshipAnnual.__super__.constructor.apply(this, arguments); 60828 } 60829 60830 return ScholarshipAnnual; 60831 60832 })(App.Pages.ScholarshipNew); 60833 60834}).call(this); 60835(function() { 60836 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 60837 hasProp = {}.hasOwnProperty; 60838 60839 App.Pages.ScholarshipCreate = (function(superClass) { 60840 extend(ScholarshipCreate, superClass); 60841 60842 function ScholarshipCreate() { 60843 return ScholarshipCreate.__super__.constructor.apply(this, arguments); 60844 } 60845 60846 return ScholarshipCreate; 60847 60848 })(App.Pages.ScholarshipNew); 60849 60850}).call(this); 60851/* 60852Copyright 2012 Igor Vaynberg 60853 60854Version: @@ver@@ Timestamp: @@timestamp@@ 60855 60856This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU 60857General Public License version 2 (the "GPL License"). You may choose either license to govern your 60858use of this software only upon the condition that you accept all of the terms of either the Apache 60859License or the GPL License. 60860 60861You may obtain a copy of the Apache License and the GPL License at: 60862 60863 http://www.apache.org/licenses/LICENSE-2.0 60864 http://www.gnu.org/licenses/gpl-2.0.html 60865 60866Unless required by applicable law or agreed to in writing, softw
60866are distributed under the 60867Apache License or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 60868CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for 60869the specific language governing permissions and limitations under the Apache License and the GPL License. 60870*/ 60871 60872 (function ($) { 60873 if(typeof $.fn.each2 == "undefined"){ 60874 $.fn.extend({ 60875 /* 60876 * 4-10 times faster .each replacement 60877 * use it carefully, as it overrides jQuery context of element on each iteration 60878 */ 60879 each2 : function (c) { 60880 var j = $([0]), i = -1, l = this.length; 60881 while ( 60882 ++i < l 60883 && (j.context = j[0] = this[i]) 60884 && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object 60885 ); 60886 return this; 60887 } 60888 }); 60889 } 60890})(jQuery); 60891 60892(function ($, undefined) { 60893 "use strict"; 60894 /*global document, window, jQuery, console */ 60895 60896 if (window.Select2 !== undefined) { 60897 return; 60898 } 60899 60900 var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer, 60901 lastMousePosition, $document; 60902 60903 KEY = { 60904 TAB: 9, 60905 ENTER: 13, 60906 ESC: 27, 60907 SPACE: 32, 60908 LEFT: 37, 60909 UP: 38, 60910 RIGHT: 39, 60911 DOWN: 40, 60912 SHIFT: 16, 60913 CTRL: 17, 60914 ALT: 18, 60915 PAGE_UP: 33, 60916 PAGE_DOWN: 34, 60917 HOME: 36, 60918 END: 35, 60919 BACKSPACE: 8, 60920 DELETE: 46, 60921 isArrow: function (k) { 60922 k = k.which ? k.which : k; 60923 switch (k) { 60924 case KEY.LEFT: 60925 case KEY.RIGHT: 60926 case KEY.UP: 60927 case KEY.DOWN: 60928 return true; 60929 } 60930 return false; 60931 }, 60932 isControl: function (e) { 60933 var k = e.which; 60934 switch (k) { 60935 case KEY.SHIFT: 60936 case KEY.CTRL: 60937 case KEY.ALT: 60938 return true; 60939 } 60940 60941 if (e.metaKey) return true; 60942 60943 return false; 60944 }, 60945 isFunctionKey: function (k) { 60946 k = k.which ? k.which : k; 60947 return k >= 112 && k <= 123; 60948 } 60949 }; 60950 60951 $document = $(document); 60952 60953 nextUid=(function() { var counter=1; return function() { return counter++; }; }()); 60954 60955 function indexOf(value, array) { 60956 var i = 0, l = array.length, v; 60957 60958 if (typeof value === "undefined") { 60959 return -1; 60960 } 60961 60962 if (value.constructor === String) { 60963 for (; i < l; i = i + 1) if (value.localeCompare(array[i]) === 0) return i; 60964 } else { 60965 for (; i < l; i = i + 1) { 60966 v = array[i]; 60967 if (v.constructor === String) { 60968 if (v.localeCompare(value) === 0) return i; 60969 } else { 60970 if (v === value) return i; 60971 } 60972 } 60973 } 60974 return -1; 60975 } 60976 60977 /** 60978 * Compares equality of a and b taking into account that a and b may be strings, in which case localeCompare is used 60979 * @param a 60980 * @param b 60981 */ 60982 function equal(a, b) { 60983 if (a === b) return true; 60984 if (a === undefined || b === undefined) return false; 60985 if (a === null || b === null) return false; 60986 if (a.constructor === String) return a.localeCompare(b) === 0; 60987 if (b.constructor === String) return b.localeCompare(a) === 0; 60988 return false; 60989 } 60990 60991 /** 60992 * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty 60993 * strings 60994 * @param string 60995 * @param separator 60996 */ 60997 function splitVal(string, separator) { 60998 var val, i, l; 60999 if (string === null || string.length < 1) return []; 61000 val = string.split(separator); 61001 for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]); 61002 return val; 61003 } 61004 61005 function getSideBorderPadding(element) { 61006 return element.outerWidth(false) - element.width(); 61007 } 61008 61009 function installKeyUpChangeEvent(element) { 61010 var key="keyup-change-value"; 61011 element.bind("keydown", function () { 61012 if ($.data(element, key) === undefined) { 61013 $.data(element, key, element.val()); 61014 } 61015 }); 61016 element.bind("keyup", function () { 61017 var val= $.data(element, key); 61018 if (val !== undefined && element.val() !== val) { 61019 $.removeData(element, key); 61020 element.trigger("keyup-change"); 61021 } 61022 }); 61023 } 61024 61025 $document.bind("mousemove", function (e) { 61026 lastMousePosition = {x: e.pageX, y: e.pageY}; 61027 }); 61028 61029 /** 61030 * filters mouse events so an event is fired only if the mouse moved. 61031 * 61032 * filters out mouse events that occur when mouse is stationary but 61033 * the elements under the pointer are scrolled. 61034 */ 61035 function installFilteredMouseMove(element) { 61036 element.bind("mousemove", function (e) { 61037 var lastpos = lastMousePosition; 61038 if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { 61039 $(e.target).trigger("mousemove-filtered", e); 61040 } 61041 }); 61042 } 61043 61044 /** 61045 * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made 61046 * within the last quietMillis milliseconds. 61047 * 61048 * @param quietMillis number of milliseconds to wait before invoking fn 61049 * @param fn function to be debounced 61050 * @param ctx object to be used as this reference within fn 61051 * @return debounced version of fn 61052 */ 61053 function debounce(quietMillis, fn, ctx) { 61054 ctx = ctx || undefined; 61055 var timeout; 61056 return function () { 61057 var args = arguments; 61058 window.clearTimeout(timeout); 61059 timeout = window.setTimeout(function() { 61060 fn.apply(ctx, args); 61061 }, quietMillis); 61062 }; 61063 } 61064 61065 /** 61066 * A simple implementation of a thunk 61067 * @param formula function used to lazily initialize the thunk 61068 * @return {Function} 61069 */ 61070 function thunk(formula) { 61071 var evaluated = false, 61072 value; 61073 return function() { 61074 if (evaluated === false) { value = formula(); evaluated = true; } 61075 return value; 61076 }; 61077 }; 61078 61079 function installDebouncedScroll(threshold, element) { 61080 var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); 61081 element.bind("scroll", function (e) { 61082 if (indexOf(e.target, element.get()) >= 0) notify(e); 61083 }); 61084 } 61085 61086 function killEvent(event) { 61087 event.preventDefault(); 61088 event.stopPropagation(); 61089 } 61090 function killEventImmediately(event) { 61091 event.preventDefault(); 61092 event.stopImmediatePropagation(); 61093 } 61094 61095 function measureTextWidth(e) { 61096 if (!sizer){ 61097 var style = e[0].currentStyle || window.getComputedStyle(e[0], null); 61098 sizer = $("<div></div>").css({ 61099 position: "absolute", 61100 left: "-10000px", 61101 top: "-10000px", 61102 display: "none", 61103 fontSize: style.fontSize, 61104 fontFamily: style.fontFamily, 61105 fontStyle: style.fontStyle, 61106 fontWeight: style.fontWeight, 61107 letterSpacing: style.letterSpacing, 61108 textTransform: style.textTransform, 61109 whiteSpace: "nowrap" 61110 }); 61111 $("body").append(sizer); 61112 } 61113 sizer.text(e.val()); 61114 return sizer.width(); 61115 } 61116 61117 function markMatch(text, term, markup) { 61118 var match=text.toUpperCase().indexOf(term.toUpperCase()), 61119 tl=term.length; 61120 61121 if (match<0) { 61122 markup.push(text); 61123 return; 61124 } 61125 61126 markup.push(text.substring(0, match)); 61127 markup.push("<span class='select2-match'>"); 61128 markup.push(text.substring(match, match + tl)); 61129 markup.push("</span>"); 61130 markup.push(text.substring(match + tl, text.length)); 61131 } 61132 61133 /** 61134 * Produces an ajax-based query function 61135 *
61136 * @param options object containing configuration paramters 61137 * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax 61138 * @param options.url url for the data 61139 * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url. 61140 * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified 61141 * @param options.traditional a boolean flag that should be true if you wish to use the traditional style of param serialization for the ajax request 61142 * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often 61143 * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2. 61144 * The expected format is an object c
61144ontaining the following keys: 61145 * results array of objects that will be used as choices 61146 * more (optional) boolean indicating whether there are more results available 61147 * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true} 61148 */ 61149 function ajax(options) { 61150 var timeout, // current scheduled but not yet executed request 61151 requestSequence = 0, // sequence used to drop out-of-order responses 61152 handler = null, 61153 quietMillis = options.quietMillis || 100; 61154 61155 return function (query) { 61156 window.clearTimeout(timeout); 61157 timeout = window.setTimeout(function () { 61158 requestSequence += 1; // increment the sequence 61159 var requestNumber = requestSequence, // this request's sequence number 61160 data = options.data, // ajax data function 61161 transport = options.transport || $.ajax, 61162 traditional = options.traditional || false, 61163 type = options.type || 'GET'; // set type of request (GET or POST) 61164 61165 data = data.call(this, query.term, query.page, query.context); 61166 61167 if( null !== handler) { handler.abort(); } 61168 61169 handler = transport.call(null, { 61170 url: options.url, 61171 dataType: options.dataType, 61172 data: data, 61173 type: type, 61174 traditional: traditional, 61175 success: function (data) { 61176 if (requestNumber < requestSequence) { 61177 return; 61178 } 61179 // TODO 3.0 - replace query.page with query so users have access to term, page, etc. 61180 var results = options.results(data, query.page); 61181 query.callback(results); 61182 } 61183 }); 61184 }, quietMillis); 61185 }; 61186 } 61187 61188 /** 61189 * Produces a query function that works with a local array 61190 * 61191 * @param options object containing configuration parameters. The options parameter can either be an array or an 61192 * object. 61193 * 61194 * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys. 61195 * 61196 * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain 61197 * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text' 61198 * key can either be a String in which case it is expected that each element in the 'data' array has a key with the 61199 * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract 61200 * the text. 61201 */ 61202 function local(options) { 61203 var data = options, // data elements 61204 dataText, 61205 text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search 61206 61207 if (!$.isArray(data)) { 61208 text = data.text; 61209 // if text is not a function we assume it to be a key name 61210 if (!$.isFunction(text)) { 61211 dataText = data.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available 61212 text = function (item) { return item[dataText]; }; 61213 } 61214 data = data.results; 61215 } 61216 61217 return function (query) { 61218 var t = query.term, filtered = { results: [] }, process; 61219 if (t === "") { 61220 query.callback({results: data}); 61221 return; 61222 } 61223 61224 process = function(datum, collection) { 61225 var group, attr; 61226 datum = datum[0]; 61227 if (datum.children) { 61228 group = {}; 61229 for (attr in datum) { 61230 if (datum.hasOwnProperty(attr)) group[attr]=datum[attr]; 61231 } 61232 group.children=[]; 61233 $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); }); 61234 if (group.children.length || query.matcher(t, text(group))) { 61235 collection.push(group); 61236 } 61237 } else { 61238 if (query.matcher(t, text(datum))) { 61239 collection.push(datum); 61240 } 61241 } 61242 }; 61243 61244 $(data).each2(function(i, datum) { process(datum, filtered.results); }); 61245 query.callback(filtered); 61246 }; 61247 } 61248 61249 // TODO javadoc 61250 function tags(data) { 61251 // TODO even for a function we should probably return a wrapper that does the same object/string check as 61252 // the function for arrays. otherwise only functions that return objects are supported. 61253 if ($.isFunction(data)) { 61254 return data; 61255 } 61256 61257 // if not a function we assume it to be an array 61258 61259 return function (query) { 61260 var t = query.term, filtered = {results: []}; 61261 $(data).each(function () { 61262 var isObject = this.text !== undefined, 61263 text = isObject ? this.text : this; 61264 if (t === "" || query.matcher(t, text)) { 61265 filtered.results.push(isObject ? this : {id: this, text: this}); 61266 } 61267 }); 61268 query.callback(filtered); 61269 }; 61270 } 61271 61272 /** 61273 * Checks if the formatter function should be used. 61274 * 61275 * Throws an error if it is not a function. Returns true if it should be used, 61276 * false if no formatting should be performed. 61277 * 61278 * @param formatter 61279 */ 61280 function checkFormatter(formatter, formatterName) { 61281 if ($.isFunction(formatter)) return true; 61282 if (!formatter) return false;
61283 throw new Error("formatterName must be a function or a falsy value"); 61284 } 61285 61286 function evaluate(val) { 61287 return $.isFunction(val) ? val() : val; 61288 } 61289 61290 function countResults(results) { 61291 var count = 0; 61292 $.each(results, function(i, item) { 61293 if (item.children) { 61294 count += countResults(item.children); 61295 } else { 61296 count++; 61297 } 61298 }); 61299 return count; 61300 } 61301 61302 /** 61303 * Default tokenizer. This function uses breaks the input on substring match of any string from the 61304 * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those 61305 * two options have to be defined in order for the tokenizer to work. 61306 * 61307 * @param input text user has typed so far or pasted into the search field 61308 * @param selection currently selected choices 61309 * @param selectCallback function(choice) callback tho add the choice to selection 61310 * @param opts select2's opts 61311 * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value 61312 */ 61313 function defaultTokenizer(input, selection, selectCallback, opts) { 61314 var original = input, // store the original so we can compare and know if we need to tell the search to update its text 61315 dupe = false, // check for whether a token we extracted represents a duplicate selected choice 61316 token, // token 61317 index, // position at which the separator was found 61318 i, l, // looping variables 61319 separator; // the matched separator 61320 61321 if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined; 61322 61323 while (true) { 61324 index = -1; 61325 61326 for (i = 0, l = opts.tokenSeparators.length; i < l; i++) { 61327 separator = opts.tokenSeparators[i]; 61328 index = input.indexOf(separator); 61329 if (index >= 0) break; 61330 } 61331 61332 if (index < 0) break; // did not find any token separator in the input string, bail 61333 61334 token = input.substring(0, index); 61335 input = input.substring(index + separator.length); 61336 61337 if (token.length > 0) { 61338 token = opts.createSearchChoice(token, selection); 61339 if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) { 61340 dupe = false; 61341 for (i = 0, l = selection.length; i < l; i++) { 61342 if (equal(opts.id(token), opts.id(selection[i]))) { 61343 dupe = true; break; 61344 } 61345 } 61346 61347 if (!dupe) selectCallback(token); 61348 } 61349 } 61350 } 61351 61352 if (original.localeCompare(input) != 0) return input; 61353 } 61354 61355 /** 61356 * blurs any Select2 container that has focus when an element outside them was clicked or received focus 61357 * 61358 * also takes care of clicks on label tags that point to the source element 61359 */ 61360 $document.ready(function () { 61361 $document.bind("mousedown touchend", function (e) { 61362 var target = $(e.target).closest("div.select2-container").get(0), attr; 61363 var targetDropdown = null; 61364 if (target) { 61365 $document.find("div.select2-container-active").each(function () { 61366 if (this !== target) $(this).data("select2").blur(); 61367 }); 61368 targetDropdown = $(target).data('select2').dropdown.get(0); 61369 } 61370 61371 // close any other active dropdowns 61372 target = targetDropdown || $(e.target).closest("div.select2-drop").get(0); 61373 $document.find("div.select2-drop-active").each(function () { 61374 if (this !== target) $(this).data("select2").blur(); 61375 }); 61376 61377 target=$(e.target); 61378 attr = target.attr("for"); 61379 if ("LABEL" === e.target.tagName && attr && attr.length > 0) { 61380 attr = attr.replace(/([\[\].])/g,'\\$1'); /* escapes [, ], and . so properly selects the id */ 61381 target = $("#"+attr); 61382 target = target.data("select2");
61383 if (target !== undefined) { target.focus(); e.preventDefault();} 61384 } 61385 }); 61386 }); 61387 61388 /** 61389 * Creates a new class 61390 * 61391 * @param superClass 61392 * @param methods 61393 */ 61394 function clazz(SuperClass, methods) { 61395 var constructor = function () {}; 61396 constructor.prototype = new SuperClass; 61397 constructor.prototype.constructor = constructor; 61398 constructor.prototype.parent = SuperClass.prototype; 61399 constructor.prototype = $.extend(constructor.prototype, methods); 61400 return constructor; 61401 } 61402 61403 AbstractSelect2 = clazz(Object, { 61404 61405 // abstract 61406 bind: function (func) { 61407 var self = this; 61408 return function () { 61409 func.apply(self, arguments); 61410 }; 61411 }, 61412 61413 // abstract 61414 init: function (opts) { 61415 var results, search, resultsSelector = ".select2-results"; 61416 61417 // prepare options 61418 this.opts = opts = this.prepareOpts(opts); 61419 61420 this.id=opts.id; 61421 61422 // destroy if called on an existing component 61423 if (opts.element.data("select2") !== undefined && 61424 opts.element.data("select2") !== null) { 61425 this.destroy(); 61426 } 61427 61428 this.enabled=true; 61429 this.container = this.createContainer(); 61430 61431 this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid()); 61432 this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); 61433 this.container.attr("id", this.containerId); 61434 61435 // cache the body so future lookups are cheap 61436 this.body = thunk(function() { return opts.element.closest("body"); }); 61437 61438 if (opts.element.attr("class") !== undefined) { 61439 this.container.addClass(opts.element.attr("class").replace(/validate\[[\S ]+] ?/, '')); 61440 } 61441 61442 this.container.css(evaluate(opts.containerCss)); 61443 this.container.addClass(evaluate(opts.containerCssClass)); 61444 61445 // swap container for the element 61446 this.opts.element 61447 .data("select2", this) 61448 .hide() 61449 .before(this.container); 61450 this.container.data("select2", this); 61451 61452 this.dropdown = this.container.find(".select2-drop"); 61453 this.dropdown.addClass(evaluate(opts.dropdownCssClass)); 61454 this.dropdown.data("select2", this); 61455 61456 this.results = results = this.container.find(resultsSelector); 61457 this.search = search = this.container.find("input.select2-input"); 61458 61459 search.attr("tabIndex", this.opts.element.attr("tabIndex")); 61460 61461 this.resultsPage = 0; 61462 this.context = null; 61463 61464 // initialize the container 61465 this.initContainer(); 61466 this.initContainerWidth(); 61467 61468 installFilteredMouseMove(this.results); 61469 this.dropdown.delegate(resultsSelector, "mousemove-filtered", this.bind(this.highlightUnderEvent)); 61470 61471 installDebouncedScroll(80, this.results); 61472 this.dropdown.delegate(resultsSelector, "scroll-debounced", this.bind(this.loadMoreIfNeeded)); 61473 61474 // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel 61475 if ($.fn.mousewheel) { 61476 results.mousewheel(function (e, delta, deltaX, deltaY) { 61477 var top = results.scrollTop(), height; 61478 if (deltaY > 0 && top - deltaY <= 0) { 61479 results.scrollTop(0); 61480 killEvent(e); 61481 } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { 61482 results.scrollTop(results.get(0).scrollHeight - results.height()); 61483 killEvent(e); 61484 } 61485 }); 61486 } 61487 61488 installKeyUpChangeEvent(search); 61489 search.bind("keyup-change", this.bind(this.updateResults)); 61490 search.bind("focus", function () { search.addClass("select2-focused"); if (search.val() === " ") search.val(""); }); 61491 search.bind("blur", function () { search.removeClass("select2-focused");}); 61492 61493 this.dropdown.delegate(resultsSelector, "mouseup", this.bind(function (e) { 61494 if ($(e.target).closest(".select2-result-selectable:not(.select2-disabled)").length > 0) { 61495 this.highlightUnderEvent(e); 61496 this.selectHighlighted(e); 61497 } else { 61498 this.focusSearch(); 61499 } 61500 killEvent(e); 61501 })); 61502 61503 // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening 61504 // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's 61505 // dom it will trigger the popup close, which is not what we want 61506 this.dropdown.bind("click mouseup mousedown", function (e) { e.stopPropagation(); }); 61507 61508 if ($.isFunction(this.opts.initSelection)) { 61509 // initialize selection based on the current value of the source element 61510 this.initSelection(); 61511 61512 // if the user has provided a function that can set selection based on the value of the source element 61513 // we monitor the change event on the element and trigger it, allowing for two way synchronization 61514 this.monitorSource(); 61515 } 61516 61517 if (opts.element.is(":disabled") || opts.element.is("[readonly='readonly']")) this.disable(); 61518 }, 61519 61520 // abstract 61521 destroy: function () { 61522 var select2 = this.opts.element.data("select2"); 61523 if (select2 !== undefined) { 61524 select2.container.remove(); 61525 select2.dropdown.remove(); 61526 select2.opts.element 61527 .removeData("select2") 61528 .unbind(".select2") 61529 .show(); 61530 } 61531 }, 61532 61533 // abstract 61534 prepareOpts: function (opts) { 61535 var element, select, idKey, ajaxUrl; 61536 61537 element = opts.element; 61538 61539 if (element.get(0).tagName.toLowerCase() === "select") { 61540 this.select = select = opts.element; 61541 } 61542 61543 if (select) { 61544 // these options are not allowed when attached to a select because they are picked up off the element itself 61545 $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () { 61546 if (this in opts) { 61547 throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element."); 61548 } 61549 }); 61550 } 61551 61552 opts = $.extend({}, { 61553 populateResults: function(container, results, query
61553) { 61554 var populate, data, result, children, id=this.opts.id, self=this; 61555 61556 populate=function(results, container, depth) { 61557 61558 var i, l, result, selectable, compound, node, label, innerContainer, formatted; 61559 61560 results = opts.sortResults(results, container, query); 61561 61562 for (i = 0, l = results.length; i < l; i = i + 1) { 61563 61564 result=results[i]; 61565 selectable=id(result) !== undefined; 61566 compound=result.children && result.children.length > 0; 61567 61568 node=$("<li></li>"); 61569 node.addClass("select2-results-dept-"+depth); 61570 node.addClass("select2-result"); 61571 node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable"); 61572 if (compound) { node.addClass("select2-result-with-children"); } 61573 node.addClass(self.opts.formatResultCssClass(result)); 61574 61575 label=$("<div></div>"); 61576 label.addClass("select2-result-label"); 61577 61578 formatted=opts.formatResult(result, label, query); 61579 if (formatted!==undefined) { 61580 label.html(self.opts.escapeMarkup(formatted)); 61581 } 61582 61583 node.append(label); 61584 61585 if (compound) { 61586 61587 innerContainer=$("<ul></ul>"); 61588 innerContainer.addClass("select2-result-sub"); 61589 populate(result.children, innerContainer, depth+1); 61590 node.append(innerContainer); 61591 } 61592 61593 node.data("select2-data", result); 61594 container.append(node); 61595 } 61596 }; 61597 61598 populate(results, container, 0); 61599 } 61600 }, $.fn.select2.defaults, opts); 61601 61602 if (typeof(opts.id) !== "function") { 61603 idKey = opts.id; 61604 opts.id = function (e) { return e[idKey]; }; 61605 } 61606 61607 if (select) { 61608 opts.query = this.bind(function (query) { 61609 var data = { results: [], more: false }, 61610 term = query.term, 61611 children, firstChild, process; 61612 61613 process=function(element, collection) { 61614 var group; 61615 if (element.is("option")) { 61616 if (query.matcher(term, element.text(), element)) { 61617 collection.push({id:element.attr("value"), text:element.text(), element: element.get(), css: element.attr("class")}); 61618 } 61619 } else if (element.is("optgroup")) { 61620 group={text:element.attr("label"), children:[], element: element.get(), css: element.attr("class")}; 61621 element.children().each2(function(i, elm) { process(elm, group.children); }); 61622 if (group.children.length>0) { 61623 collection.push(group); 61624 } 61625 } 61626 }; 61627 61628 children=element.children(); 61629 61630 // ignore the placeholder option if there is one 61631 if (this.getPlaceholder() !== undefined && children.length > 0) { 61632 firstChild = children[0]; 61633 if ($(firstChild).text() === "") { 61634 children=children.not(firstChild); 61635 } 61636 } 61637 61638 children.each2(function(i, elm) { process(elm, data.results); }); 61639 61640 query.callback(data); 61641 }); 61642 // this is needed because inside val() we construct choices from options and there id is hardcoded 61643 opts.id=function(e) { return e.id; }; 61644 opts.formatResultCssClass = function(data) { return data.css; } 61645 } else {
61646 if (!("query" in opts)) { 61647 if ("ajax" in opts) { 61648 ajaxUrl = opts.element.data("ajax-url"); 61649 if (ajaxUrl && ajaxUrl.length > 0) { 61650 opts.ajax.url = ajaxUrl; 61651 } 61652 opts.query = ajax(opts.ajax); 61653 } else if ("data" in opts) { 61654 opts.query = local(opts.data); 61655 } else if ("tags" in opts) { 61656 opts.query = tags(opts.tags); 61657 if (opts.createSearchChoice === undefined) { 61658 opts.createSearchChoice = function (term) { return {id: term, text: term}; }; 61659 } 61660 opts.initSelection = function (element, callback) { 61661 var data = []; 61662 $(splitVal(element.val(), opts.separator)).each(function () { 61663 var id = this, text = this, tags=opts.tags; 61664 if ($.isFunction(tags)) tags=tags(); 61665 $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } }); 61666 data.push({id: id, text: text}); 61667 }); 61668 61669 callback(data); 61670 }; 61671 } 61672 } 61673 } 61674 if (typeof(opts.query) !== "function") { 61675 throw "query function not defined for Select2 " + opts.element.attr("id"); 61676 } 61677 61678 return opts; 61679 }, 61680 61681 /** 61682 * Monitor the original element for changes and update select2 accordingly 61683 */ 61684 // abstract 61685 monitorSource: function () { 61686 this.opts.element.bind("change.select2", this.bind(function (e) { 61687 if (this.opts.element.data("select2-change-triggered") !== true) { 61688 this.initSelection(); 61689 } 61690 })); 61691 }, 61692 61693 /** 61694 * Triggers the change event on the source element 61695 */ 61696 // abstract 61697 triggerChange: function (details) { 61698 61699 details = details || {}; 61700 details= $.extend({}, details, { type: "change", val: this.val() }); 61701 // prevents recursive triggering 61702 this.opts.element.data("select2-change-triggered", true); 61703 this.opts.element.trigger(details); 61704 this.opts.element.data("select2-change-triggered", false); 61705 61706 // some validation frameworks ignore the change event and listen instead to keyup, click for selects 61707 // so here we trigger the click event manually 61708 this.opts.element.click(); 61709 61710 // ValidationEngine ignorea the change event and listens instead to blur 61711 // so here we trigger the blur event manually if so desired 61712 if (this.opts.blurOnChange) 61713 this.opts.element.blur(); 61714 }, 61715 61716 61717 // abstract 61718 enable: function() { 61719 if (this.enabled) return; 61720 61721 this.enabled=true; 61722 this.container.removeClass("select2-container-disabled"); 61723 this.opts.element.removeAttr("disabled"); 61724 }, 61725 61726 // abstract 61727 disable: function() { 61728 if (!this.enabled) return; 61729 61730 this.close(); 61731 61732 this.enabled=false; 61733 this.container.addClass("select2-container-disabled"); 61734 this.opts.element.attr("disabled", "disabled"); 61735 }, 61736 61737 // abstract 61738 opened: function () { 61739 return this.container.hasClass("select2-dropdown-open"); 61740 }, 61741 61742 // abstract 61743 positionDropdown: function() { 61744 var offset = this.container.offset(), 61745 height = this.container.outerHeight(false), 61746 width = this.container.outerWidth(false), 61747 dropHeight = this.dropdown.outerHeight(false), 61748 viewPortRight = $(window).scrollLeft() + document.documentElement.clientWidth, 61749 viewportBottom = $(window).scrollTop() + document.documentElement.clientHeight, 61750 dropTop = offset.top + height, 61751 dropLeft = offset.left, 61752 enoughRoomBelow = dropTop + dropHeight <= viewportBottom, 61753 enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(), 61754 dropWidth = this.dropdown.outerWidth(false), 61755 enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight, 61756 aboveNow = this.dropdown.hasClass("select2-drop-above"), 61757 bodyOffset, 61758 above, 61759 css; 61760 61761 // console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow); 61762 // console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove); 61763 61764 // fix positioning when body has an offset and is not position: static 61765 61766 if (this.body().css('position') !== 'static') { 61767 bodyOffset = this.body().offset(); 61768 dropTop -= bodyOffset.top; 61769 dropLeft -= bodyOffset.left; 61770 } 61771 61772 // always prefer the current above/below alignment, unless there is not enough room 61773 61774 if (aboveNow) { 61775 above = true; 61776 if (!enoughRoomAbove && enoughRoomBelow) above = false;
61777 } else { 61778 above = false; 61779 if (!enoughRoomBelow && enoughRoomAbove) above = true; 61780 } 61781 61782 if (!enoughRoomOnRight) { 61783 dropLeft = offset.left + width - dropWidth; 61784 } 61785 61786 if (above) { 61787 dropTop = offset.top - dropHeight; 61788 this.container.addClass("select2-drop-above"); 61789 this.dropdown.addClass("select2-drop-above"); 61790 } 61791 else { 61792 this.container.removeClass("select2-drop-above"); 61793 this.dropdown.removeClass("select2-drop-above"); 61794 } 61795 61796 css = $.extend({ 61797 top: dropTop, 61798 left: dropLeft, 61799 width: width 61800 }, evaluate(this.opts.dropdownCss)); 61801 61802 this.dropdown.css(css); 61803 }, 61804 61805 // abstract 61806 shouldOpen: function() { 61807 var event; 61808 61809 if (this.opened()) return false; 61810 61811 event = $.Event("open"); 61812 this.opts.element.trigger(event); 61813 return !event.isDefaultPrevented(); 61814 }, 61815 61816 // abstract 61817 clearDropdownAlignmentPreference: function() { 61818 // clear the classes used to figure out the preference of where the dropdown should be opened 61819 this.container.removeClass("select2-drop-above"); 61820 this.dropdown.removeClass("select2-drop-above"); 61821 }, 61822 61823 /** 61824 * Opens the dropdown 61825 * 61826 * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example, 61827 * the dropdown is already open, or if the 'open' event listener on the element called preventDefault(). 61828 */ 61829 // abstract 61830 open: function () { 61831 61832 if (!this.shouldOpen()) return false; 61833 61834 window.setTimeout(this.bind(this.opening), 1); 61835 61836 return true; 61837 }, 61838 61839 /** 61840 * Performs the opening of the dropdown 61841 */ 61842 // abstract 61843 opening: function() { 61844 var cid = this.containerId, selector = this.containerSelector, 61845 scroll = "scroll." + cid, resize = "resize." + cid; 61846 61847 this.container.parents().each(function() { 61848 $(this).bind(scroll, function() { 61849 var s2 = $(selector); 61850 if (s2.length == 0) { 61851 $(this).unbind(scroll); 61852 } 61853 s2.select2("close"); 61854 }); 61855 }); 61856 61857 window.setTimeout(function() { 61858 // this is done inside a timeout because IE will sometimes fire a resize event while opening 61859 // the dropdown and that causes this handler to immediately close it. this way the dropdown 61860 // has a chance to fully open before we start listening to resize events 61861 $(window).bind(resize, function() { 61862 var s2 = $(selector); 61863 if (s2.length == 0) { 61864 $(window).unbind(resize); 61865 } 61866 s2.select2("close"); 61867 }) 61868 }, 10); 61869 61870 this.clearDropdownAlignmentPreference(); 61871 61872 if (this.search.val() === " ") { this.search.val(""); } 61873 61874 this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); 61875 61876 this.updateResults(true); 61877 61878 if(this.dropdown[0] !== this.body().children().last()[0]) { 61879 this.dropdown.detach().appendTo(this.body()); 61880 } 61881 61882 this.dropdown.show(); 61883 61884 this.positionDropdown(); 61885 this.dropdown.addClass("select2-drop-active"); 61886 61887 this.ensureHighlightVisible(); 61888 61889 this.focusSearch(); 61890 }, 61891 61892 // abstract 61893 close: function () { 61894 if (!this.opened()) return; 61895 61896 var self = this; 61897 61898 this.container.parents().each(function() { 61899 $(this).unbind("scroll." + self.containerId); 61900 }); 61901 $(window).unbind("resize." + this.containerId); 61902 61903 this.clearDropdownAlignmentPreference(); 61904 61905 this.dropdown.hide(); 61906 this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); 61907 this.results.empty(); 61908 this.clearSearch(); 61909 61910 this.opts.element.trigger($.Event("close")); 61911 }, 61912 61913 // abstract 61914 clearSearch: function () { 61915 61916 }, 61917 61918 // abstract 61919 ensureHighlightVisible: function () { 61920 var results = this.results, children, index, child, hb, rb, y, more; 61921 61922 index = this.highlight(); 61923 61924 if (index < 0) return; 61925 61926 if (index == 0) { 61927 61928 // if the first element is highlighted scroll all the way to the top, 61929 // that way any unselectable headers above it will also be scrolled 61930 // into view 61931 61932 results.scrollTop(0); 61933 return; 61934 } 61935 61936 children = results.find(".select2-result-selectable"); 61937 61938 child = $(children[index]); 61939 61940 hb = child.offset().top + child.outerHeight(true); 61941 61942 // if this is the last child lets also make sure select2-more-results is visible 61943 if (index === children.length - 1) { 61944 more = results.find("li.select2-more-results"); 61945 if (more.length > 0) { 61946 hb = more.offset().top + more.outerHeight(true); 61947 } 61948 } 61949 61950 rb = results.offset().top + results.outerHeight(true); 61951 if (hb > rb) { 61952 results.scrollTop(results.scrollTop() + (hb - rb)); 61953 } 61954 y = child.offset().top - results.offset().top; 61955 61956 // make sure the top of the element is visible 61957 if (y < 0 && child.css('display') != 'none' ) { 61958 results.scrollTop(results.scrollTop() + y); // y is negative 61959 } 61960 }, 61961 61962 // abstract 61963 moveHighlight: function (delta) { 61964 var choices = this.results.find(".select2-result-selectable"), 61965 index = this.highlight(); 61966 61967 while (index > -1 && index < choices.length) { 61968 index += delta; 61969 var choice = $(choices[index]); 61970 if (choice.hasClass("select2-result-selectable") && !c
61970hoice.hasClass("select2-disabled")) { 61971 this.highlight(index); 61972 break; 61973 } 61974 } 61975 }, 61976 61977 // abstract 61978 highlight: function (index) { 61979 var choices = this.results.find(".select2-result-selectable").not(".select2-disabled"); 61980 61981 if (arguments.length === 0) { 61982 return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); 61983 } 61984 61985 if (index >= choices.length) index = choices.length - 1; 61986 if (index < 0) index = 0; 61987 61988 choices.removeClass("select2-highlighted"); 61989 61990 $(choices[index]).addClass("select2-highlighted"); 61991 this.ensureHighlightVisible(); 61992 61993 }, 61994 61995 // abstract 61996 countSelectableResults: function() { 61997 return this.results.find(".select2-result-selectable").not(".select2-disabled").length; 61998 }, 61999 62000 // abstract 62001 highlightUnderEvent: function (event) { 62002 var el = $(event.target).closest(".select2-result-selectable"); 62003 if (el.length > 0 && !el.is(".select2-highlighted")) { 62004 var choices = this.results.find('.select2-result-selectable'); 62005 this.highlight(choices.index(el)); 62006 } else if (el.length == 0) { 62007 // if we are over an unselectable item remove al highlights 62008 this.results.find(".select2-highlighted").removeClass("select2-highlighted"); 62009 } 62010 }, 62011 62012 // abstract 62013 loadMoreIfNeeded: function () { 62014 var results = this.results, 62015 more = results.find("li.select2-more-results"), 62016 below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible 62017 offset = -1, // index of first element without data 62018 page = this.resultsPage + 1, 62019 self=this, 62020 term=this.search.val(), 62021 context=this.context; 62022 62023 if (more.length === 0) return; 62024 below = more.offset().top - results.offset().top - results.height(); 62025 62026 if (below <= 0) { 62027 more.addClass("select2-active"); 62028 this.opts.query({ 62029 term: term, 62030 page: page, 62031 context: context, 62032 matcher: this.opts.matcher, 62033 callback: this.bind(function (data) { 62034 62035 // ignore a response if the select2 has been closed before it was received 62036 if (!self.opened()) return; 62037 62038 62039 self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context}); 62040 62041 if (data.more===true) { 62042 more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1)); 62043 window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); 62044 } else { 62045 more.remove(); 62046 } 62047 self.positionDropdown(); 62048 self.resultsPage = page; 62049 })}); 62050 } 62051 }, 62052 62053 /** 62054 * Default tokenizer function which does nothing 62055 */ 62056 tokenize: function() { 62057 62058 }, 62059 62060 /** 62061 * @param initial whether or not this is the call to this method right after the dropdown has been opened 62062 */ 62063 // abstract 62064 updateResults: function (initial) { 62065 var search = this.search, results = this.results, opts = this.opts, data, self=this, input; 62066 62067 // if the search is currently hidden we do not alter the results 62068 if (initial !== true && (this.showSearchInput === false || !this.opened())) { 62069 return; 62070 } 62071 62072 search.addClass("select2-active"); 62073 62074 function postRender() { 62075 results.scrollTop(0); 62076 search.removeClass("select2-active"); 62077 self.positionDropdown(); 62078 } 62079 62080 function render(html) { 62081 results.html(self.opts.escapeMarkup(html)); 62082 postRender(); 62083 } 62084 62085 if (opts.maximumSelectionSize >=1) { 62086 data = this.data(); 62087 if ($.isArray(data) && data.length >= opts.maximumSelectionSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
62088 render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(opts.maximumSelectionSize) + "</li>"); 62089 return; 62090 } 62091 } 62092 62093 if (search.val().length < opts.minimumInputLength) { 62094 if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) { 62095 render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>"); 62096 } else { 62097 render(""); 62098 } 62099 return; 62100 } 62101 else if (opts.formatSearching()) { 62102 render("<li class='select2-searching'>" + opts.formatSearching() + "</li>"); 62103 } 62104 62105 if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) { 62106 if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) { 62107 render("<li class='select2-no-results'>" + opts.formatInputTooLong(search.val(), opts.maximumInputLength) + "</li>"); 62108 } else { 62109 render(""); 62110 } 62111 return; 62112 } 62113 62114 // give the tokenizer a chance to pre-process the input 62115 input = this.tokenize(); 62116 if (input != undefined && input != null) { 62117 search.val(input); 62118 } 62119 62120 this.resultsPage = 1; 62121 opts.query({ 62122 term: search.val(), 62123 page: this.resultsPage, 62124 context: null, 62125 matcher: opts.matcher, 62126 callback: this.bind(function (data) { 62127 var def; // default choice 62128 62129 // ignore a response if the select2 has been closed before it was received 62130 if (!this.opened()) return; 62131 62132 // save context, if any 62133 this.context = (data.context===undefined) ? null : data.context; 62134 62135 // create a default choice and prepend it to the list 62136 if (this.opts.createSearchChoice && search.val() !== "") { 62137 def = this.opts.createSearchChoice.call(null, search.val(), data.results); 62138 if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) { 62139 if ($(data.results).filter( 62140 function () { 62141 return equal(self.id(this), self.id(def)); 62142 }).length === 0) { 62143 data.results.unshift(def); 62144 } 62145 } 62146 } 62147 62148 if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) { 62149 render("<li class='select2-no-results'>" + opts.formatNoMatches(search.val()) + "</li>"); 62150 return; 62151 } 62152 62153 results.empty(); 62154 self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null}); 62155 62156 if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) { 62157 results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>"); 62158 window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); 62159 } 62160 62161 this.postprocessResults(data, initial); 62162 62163 postRender(); 62164 })}); 62165 }, 62166 62167 // abstract 62168 cancel: function () { 62169 this.close(); 62170 }, 62171 62172 // abstract 62173 blur: function () { 62174 this.close(); 62175 this.container.removeClass("select2-container-active"); 62176 this.dropdown.removeClass("select2-drop-active"); 62177 // synonymous to .is(':focus'), which is available in jquery >= 1.6 62178 if (this.search[0] === document.activeElement) { this.search.blur(); } 62179 this.clearSearch(); 62180 this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); 62181 this.opts.element.triggerHandler("blur"); 62182 }, 62183 62184 // abstract 62185 focusSearch: function () { 62186 // need to do it here as well as in timeout so it works in IE 62187 this.search.show(); 62188 this.search.focus(); 62189 62190 /* we do this in a timeout so that current event processing can complete before this code is executed.
62191 this makes sure the search field is focussed even if the current event would blur it */ 62192 window.setTimeout(this.bind(function () { 62193 // reset the value so IE places the cursor at the end of the input box 62194 this.search.show(); 62195 this.search.focus(); 62196 this.search.val(this.search.val()); 62197 }), 10); 62198 }, 62199 62200 // abstract 62201 selectHighlighted: function () { 62202 var index=this.highlight(), 62203 highlighted=this.results.find(".select2-highlighted").not(".select2-disabled"), 62204 data = highlighted.closest('.select2-result-selectable').data("select2-data"); 62205 if (data) { 62206 highlighted.addClass("select2-disabled"); 62207 this.highlight(index); 62208 this.onSelect(data); 62209 } 62210 }, 62211 62212 // abstract 62213 getPlaceholder: function () { 62214 return this.opts.element.attr("placeholder") || 62215 this.opts.element.attr("data-placeholder") || // jquery 1.4 compat 62216 this.opts.element.data("placeholder") || 62217 this.opts.placeholder; 62218 }, 62219 62220 /** 62221 * Get the desired width for the container element. This is 62222 * derived first from option `width` passed to select2, then 62223 * the inline 'style' on the original element, and finally 62224 * falls back to the jQuery calculated element width. 62225 */ 62226 // abstract 62227 initContainerWidth: function () { 62228 function resolveContainerWidth() { 62229 var style, attrs, matches, i, l; 62230 62231 if (this.opts.width === "off") { 62232 return null; 62233 } else if (this.opts.width === "element"){ 62234 return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'; 62235 } else if (this.opts.width === "copy" || this.opts.width === "resolve") { 62236 // check if there is inline style on the element that contains width 62237 style = this.opts.element.attr('style'); 62238 if (style !== undefined) { 62239 attrs = style.split(';'); 62240 for (i = 0, l = attrs.length; i < l; i = i + 1) { 62241 matches = attrs[i].replace(/\s/g, '') 62242 .match(/width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/); 62243 if (matches !== null && matches.length >= 1) 62244 return matches[1]; 62245 } 62246 } 62247 62248 if (this.opts.width === "resolve") { 62249 // next check if css('width') can resolve a width that is percent based, this is sometimes possible 62250 // when attached to input type=hidden or elements hidden via css 62251 style = this.opts.element.css('width'); 62252 if (style.indexOf("%") > 0) return style; 62253 62254 // finally, fallback on the calculated width of the element 62255 return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'); 62256 } 62257 62258 return null; 62259 } else if ($.isFunction(this.opts.width)) { 62260 return this.opts.width(); 62261 } else { 62262 return this.opts.width; 62263 } 62264 }; 62265 62266 var width = resolveContainerWidth.call(this); 62267 if (width !== null) { 62268 this.container.attr("style", "width: "+width); 62269 } 62270 } 62271 }); 62272 62273 SingleSelect2 = clazz(AbstractSelect2, { 62274 62275 // single 62276 62277 createContainer: function () { 62278 var container = $("<div></div>", { 62279 "class": "select2-container" 62280 }).html([ 62281 " <a href='javascript:void(0)' onclick='return false;' class='select2-choice'>", 62282 " <span></span><abbr class='select2-search-choice-close' style='display:none;'></abbr>", 62283 " <div><b></b></div>" , 62284 "</a>", 62285 " <div class='select2-drop select2-offscreen'>" , 62286 " <div class='select2-search'>" , 62287 " <input type='text' autocomplete='off' class='select2-input'/>" , 62288 " </div>" , 62289 " <ul class='select2-results'>" , 62290 " </ul>" , 62291 "</div>"].join("")); 62292 return container; 62293 }, 62294 62295 // single 62296 opening: function () { 62297 this.search.show(); 62298 this.parent.opening.apply(this, arguments); 62299 this.dropdown.removeClass("select2-offscreen"); 62300 }, 62301 62302 // single 62303 close: function () { 62304 if (!this.opened()) return; 62305 this.parent.close.apply(this, arguments); 62306 this.dropdown.removeAttr("style").addClass("select2-offscreen").insertAfter(this.selection).show(); 62307 }, 62308 62309 // single 62310 focus: function () { 62311 this.close(); 62312 this.selection.focus(); 62313 }, 62314 62315 // single 62316 isFocused: function () { 62317 return this.selection[0] === document.activeElement; 62318 }, 62319 62320 // single 62321 cancel: function () { 62322 this.parent.cancel.apply(this, arguments); 62323 this.selection.focus(); 62324 }, 62325 62326 // single 62327 initContainer: function () { 62328 62329 var selection, 62330 container = this.container, 62331 dropdown = this.dropdown, 62332 clickingInside = false;
62333 62334 this.selection = selection = container.find(".select2-choice"); 62335 62336 this.search.bind("keydown", this.bind(function (e) { 62337 if (!this.enabled) return; 62338 62339 if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { 62340 // prevent the page from scrolling 62341 killEvent(e); 62342 return; 62343 } 62344 62345 if (this.opened()) { 62346 switch (e.which) { 62347 case KEY.UP: 62348 case KEY.DOWN: 62349 this.moveHighlight((e.which === KEY.UP) ? -1 : 1); 62350 killEvent(e); 62351 return; 62352 case KEY.TAB: 62353 case KEY.ENTER: 62354 this.selectHighlighted(); 62355 killEvent(e); 62356 return; 62357 case KEY.ESC: 62358 this.cancel(e); 62359 killEvent(e); 62360 return; 62361 } 62362 } else { 62363 62364 if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { 62365 return; 62366 } 62367 62368 if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { 62369 return; 62370 } 62371 62372 this.open(); 62373 62374 if (e.which === KEY.ENTER) { 62375 // do not propagate the event otherwise we open, and propagate enter which closes 62376 return; 62377 } 62378 } 62379 })); 62380 62381 this.search.bind("focus", this.bind(function() { 62382 this.selection.attr("tabIndex", "-1"); 62383 })); 62384 this.search.bind("blur", this.bind(function() { 62385 if (!this.opened()) this.container.removeClass("select2-container-active"); 62386 window.setTimeout(this.bind(function() { 62387 // restore original tab index 62388 var ti=this.opts.element.attr("tabIndex") || 0; 62389 if (ti) { 62390 this.selection.attr("tabIndex", ti); 62391 } else { 62392 this.selection.removeAttr("tabIndex"); 62393 } 62394 }), 10); 62395 })); 62396 62397 selection.delegate("abbr", "mousedown", this.bind(function (e) { 62398 if (!this.enabled) return; 62399 this.clear(); 62400 killEventImmediately(e); 62401 this.close(); 62402 this.triggerChange(); 62403 this.selection.focus(); 62404 })); 62405 62406 selection.bind("mousedown", this.bind(function (e) { 62407 clickingInside = true; 62408 62409 if (this.opened()) { 62410 this.close(); 62411 this.selection.focus(); 62412 } else if (this.enabled) { 62413 this.open(); 62414 } 62415 62416 clickingInside = false;
62417 })); 62418 62419 dropdown.bind("mousedown", this.bind(function() { this.search.focus(); })); 62420 62421 selection.bind("focus", this.bind(function() { 62422 this.container.addClass("select2-container-active"); 62423 // hide the search so the tab key does not focus on it 62424 this.search.attr("tabIndex", "-1"); 62425 })); 62426 62427 selection.bind("blur", this.bind(function() { 62428 if (!this.opened()) { 62429 this.container.removeClass("select2-container-active"); 62430 } 62431 window.setTimeout(this.bind(function() { this.search.attr("tabIndex", this.opts.element.attr("tabIndex") || 0); }), 10); 62432 })); 62433 62434 selection.bind("keydown", this.bind(function(e) { 62435 if (!this.enabled) return; 62436 62437 if (e.which == KEY.DOWN || e.which == KEY.UP 62438 || (e.which == KEY.ENTER && this.opts.openOnEnter)) { 62439 this.open(); 62440 killEvent(e); 62441 return; 62442 } 62443 62444 if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { 62445 if (this.opts.allowClear) { 62446 this.clear(); 62447 } 62448 killEvent(e); 62449 return; 62450 } 62451 })); 62452 selection.bind("keypress", this.bind(function(e) { 62453 var key = String.fromCharCode(e.which); 62454 this.search.val(key); 62455 this.open(); 62456 })); 62457 62458 this.setPlaceholder(); 62459 62460 this.search.bind("focus", this.bind(function() { 62461 this.container.addClass("select2-container-active"); 62462 })); 62463 }, 62464 62465 // single 62466 clear: function() { 62467 this.opts.element.val(""); 62468 this.selection.find("span").empty(); 62469 this.selection.removeData("select2-data"); 62470 this.setPlaceholder(); 62471 }, 62472 62473 /** 62474 * Sets selection based on source element's value 62475 */ 62476 // single 62477 initSelection: function () { 62478 var selected; 62479 if (this.opts.element.val() === "" && this.opts.element.text() === "") { 62480 this.close(); 62481 this.setPlaceholder(); 62482 } else { 62483 var self = this; 62484 this.opts.initSelection.call(null, this.opts.element, function(selected){ 62485 if (selected !== undefined && selected !== null) { 62486 self.updateSelection(selected); 62487 self.close(); 62488 self.setPlaceholder(); 62489 } 62490 }); 62491 } 62492 }, 62493 62494 // single 62495 prepareOpts: function () { 62496 var opts = this.parent.prepareOpts.apply(this, arguments); 62497 62498 if (opts.element.get(0).tagName.toLowerCase() === "select") { 62499 // install the selection initializer 62500 opts.initSelection = function (element, callback) { 62501 var selected = element.find(":selected"); 62502 // a single select box always has a value, no need to null check 'selected' 62503 if ($.isFunction(callback)) 62504 callback({id: selected.attr("value"), text: selected.text(), element:selected}); 62505 }; 62506 } 62507 62508 return opts; 62509 }, 62510 62511 // single 62512 setPlaceholder: function () { 62513 var placeholder = this.getPlaceholder(); 62514 62515 if (this.opts.element.val() === "" && placeholder !== undefined) { 62516 62517 // check for a first blank option if attached to a select 62518 if (this.select && this.select.find("option:first").text() !== "") return; 62519 62520 this.selection.find("span").html(this.opts.escapeMarkup(placeholder)); 62521 62522 this.selection.addClass("select2-default"); 62523 62524 this.selection.find("abbr").hide(); 62525 } 62526 }, 62527 62528 // single 62529 postprocessResults: function (data, initial) { 62530 var selected = 0, self = this, showSearchInput = true; 62531 62532 // find the selected element in the result list 62533 62534 this.results.find(".select2-result-selectable").each2(function (i, elm) { 62535 if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) { 62536 selected = i; 62537 return false;
62538 } 62539 }); 62540 62541 // and highlight it 62542 62543 this.highlight(selected); 62544 62545 // hide the search box if this is the first we got the results and there are a few of them 62546 62547 if (initial === true) { 62548 showSearchInput = this.showSearchInput = countResults(data.results) >= this.opts.minimumResultsForSearch; 62549 this.dropdown.find(".select2-search")[showSearchInput ? "removeClass" : "addClass"]("select2-search-hidden"); 62550 62551 //add "select2-with-searchbox" to the container if search box is shown 62552 $(this.dropdown, this.container)[showSearchInput ? "addClass" : "removeClass"]("select2-with-searchbox"); 62553 } 62554 62555 }, 62556 62557 // single 62558 onSelect: function (data) { 62559 var old = this.opts.element.val(); 62560 62561 this.opts.element.val(this.id(data)); 62562 this.updateSelection(data); 62563 this.close(); 62564 this.selection.focus(); 62565 62566 if (!equal(old, this.id(data))) { this.triggerChange(); } 62567 }, 62568 62569 // single 62570 updateSelection: function (data) { 62571 62572 var container=this.selection.find("span"), formatted; 62573 62574 this.selection.data("select2-data", data); 62575 62576 container.empty(); 62577 formatted=this.opts.formatSelection(data, container); 62578 if (formatted !== undefined) { 62579 container.append(this.opts.escapeMarkup(formatted)); 62580 } 62581 62582 this.selection.removeClass("select2-default"); 62583 62584 if (this.opts.allowClear && this.getPlaceholder() !== undefined) { 62585 this.selection.find("abbr").show(); 62586 } 62587 }, 62588 62589 // single 62590 val: function () { 62591 var val, data = null, self = this; 62592 62593 if (arguments.length === 0) { 62594 return this.opts.element.val(); 62595 } 62596 62597 val = arguments[0]; 62598 62599 if (this.select) { 62600 this.select 62601 .val(val) 62602 .find(":selected").each2(function (i, elm) { 62603 data = {id: elm.attr("value"), text: elm.text()}; 62604 return false; 62605 }); 62606 this.updateSelection(data); 62607 this.setPlaceholder(); 62608 this.triggerChange(); 62609 } else { 62610 if (this.opts.initSelection === undefined) { 62611 throw new Error("cannot call val() if initSelection() is not defined"); 62612 } 62613 // val is an id. !val is true for [undefined,null,''] 62614 if (!val) { 62615 this.clear(); 62616 this.triggerChange(); 62617 return; 62618 } 62619 this.opts.element.val(val); 62620 this.opts.initSelection(this.opts.element, function(data){ 62621 self.opts.element.val(!data ? "" : self.id(data)); 62622 self.updateSelection(data); 62623 self.setPlaceholder(); 62624 self.triggerChange(); 62625 }); 62626 } 62627 }, 62628 62629 // single 62630 clearSearch: function () { 62631 this.search.val(""); 62632 }, 62633 62634 // single 62635 data: function(value) { 62636 var data; 62637 62638 if (arguments.length === 0) { 62639 data = this.selection.data("select2-data"); 62640 if (data == undefined) data = null; 62641 return data; 62642 } else { 62643 if (!value || value === "") { 62644 this.clear(); 62645 } else { 62646 this.opts.element.val(!value ? "" : this.id(value)); 62647 this.updateSelection(value); 62648 } 62649 } 62650 } 62651 }); 62652 62653 MultiSelect2 = clazz(AbstractSelect2, { 62654 62655 // multi 62656 createContainer: function () { 62657 var container = $("<div></div>", { 62658 "class": "select2-container select2-container-multi" 62659 }).html([ 62660 " <ul class='select2-choices'>", 62661 //"<li class='select2-search-choice'><span>California</span><a href="javascript:void(0)" class="select2-search-choice-close"></a></li>" , 62662 " <li class='select2-search-field'>" , 62663 " <input type='text' autocomplete='off' class='select2-input'>" , 62664 " </li>" , 62665 "</ul>" , 62666 "<div class='select2-drop select2-drop-multi' style='display:none;'>" , 62667 " <ul class='select2-results'>" , 62668 " </ul>" , 62669 "</div>"].join("")); 62670 return container; 62671 }, 62672 62673 // multi 62674 prepareOpts: function () { 62675 var opts = this.parent.prepareOpts.apply(this, arguments); 62676 62677 // TODO validate placeholder is a string if specified 62678 62679 if (opts.element.get(0).tagName.toLowerCase() === "select") { 62680 // install sthe selection initializer 62681 opts.initSelection = function (element,callback) { 62682 62683 var data = []; 62684 element.find(":selected").each2(function (i, elm) { 62685 data.push({id: elm.attr("value"), text: elm.text(), element: elm}); 62686 }); 62687 62688 if ($.isFunction(callback)) 62689 callback(data); 62690 }; 62691 } 62692 62693 return opts; 62694 }, 62695 62696 // multi 62697 initContainer: function () { 62698 62699 var selector = ".select2-choices", selection; 62700 62701 this.searchContainer = this.container.find(".select2-search-field"); 62702 this.selection = selection = this.container.find(selector); 62703 62704 this.search.bind("keydown", this.bind(function (e) { 62705 if (!this.enabled) return; 62706 62707 if (e.which === KEY.BACKSPACE && this.search.val() === "") { 62708 this.close(); 62709 62710 var choices, 62711 selected = selection.find(".select2-search-choice-focus"); 62712 if (selected.length > 0) { 62713 this.unselect(selected.first()); 62714 this.search.width(10); 62715 killEvent(e); 62716 return; 62717 } 62718 62719 choices = selection.find(".select2-search-choice:not(.select2-locked)"); 62720 if (choices.length > 0) { 62721 choices.last().addClass("select2-search-choice-focus"); 62722 } 62723 } else { 62724 selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); 62725 } 62726 62727 if (this.opened()) { 62728 switch (e.which) { 62729 case KEY.UP: 62730 case KEY.DOWN: 62731 this.moveHighlight((e.which === KEY.UP) ? -1 : 1); 62732 killEvent(e); 62733 return; 62734 case KEY.ENTER: 62735 case KEY.TAB: 62736 this.selectHighlighted(); 62737 killEvent(e); 62738 return; 62739 case KEY.ESC: 62740 this.cancel(e); 62741 killEvent(e); 62742 return; 62743 } 62744 } 62745 62746 if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) 62747 || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { 62748 return; 62749 } 62750 62751 if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { 62752 return; 62753 } 62754 62755 this.open(); 62756 62757 if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { 62758 // prevent the page from scrolling 62759 killEvent(e); 62760 } 62761 })); 62762 62763 this.search.bind("keyup", this.bind(this.resizeSearch)); 62764 62765 this.search.bind("blur", this.bind(function(e) { 62766 this.container.removeClass("select2-container-active"); 62767 this.search.removeClass("select2-focused"); 62768 this.clearSearch(); 62769 e.stopImmediatePropagation(); 62770 })); 62771 62772 this.container.delegate(selector, "mousedown", this.bind(function (e) { 62773 if (!this.enabled) return; 62774 if ($(e.target).closest(".select2-search-choice").length > 0) { 62775 // clicked inside a select2 search choice, do not open 62776 return; 62777 } 62778 this.clearPlaceholder(); 62779 this.open(); 62780 this.focusSearch(); 62781 e.preventDefault(); 62782 })); 62783 62784 this.container.delegate(selector, "focus", this.bind(function () { 62785 if (!this.enabled) return; 62786 this.container.addClass("select2-container-active"); 62787 this.dropdown.addClass("select2-drop-active"); 62788 this.clearPlaceholder(); 62789 })); 62790 62791 // set the placeholder if necessary 62792 this.clearSearch(); 62793 }, 62794 62795 // multi 62796 enable: function() { 62797 if (this.enabled) return; 62798 62799 this.parent.enable.apply(this, arguments); 62800 62801 this.search.removeAttr("disabled"); 62802 }, 62803 62804 // multi 62805 disable: function() { 62806 if (!this.enabled) return; 62807 62808 this.parent.disable.apply(this, arguments); 62809 62810 this.search.attr("disabled", true); 62811 }, 62812 62813 // multi 62814 initSelection: function () { 62815 var data; 62816 if (this.opts.element.val() === "" && this.opts.element.text() === "") { 62817 this.updateSelection([]); 62818 this.close(); 62819 // set the placeholder if necessary 62820 this.clearSearch(); 62821 } 62822 if (this.select || this.opts.element.val() !== "") { 62823 var self = this; 62824 this.opts.initSelection.call(null, this.opts.element, function(data){ 62825 if (data !== undefined && data !== null) { 62826 self.updateSelection(data); 62827 self.close(); 62828 // set the placeholder if necessary 62829 self.clearSearch(); 62830 } 62831 }); 62832 } 62833 }, 62834 62835 // multi 62836 clearSearch: function () { 62837 var placeholder = this.getPlaceholder(); 62838 62839 if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) { 62840 this.search.val(placeholder).addClass("select2-default"); 62841 // stretch the search box to full width of the container so as much of the placeholder is visible as possible 62842 this.resizeSearch(); 62843 } else { 62844 // we set this to " " instead of "" and later clear it on focus() because there is a firefox bug 62845 // that does not properly render the caret when the field starts out blank 62846 this.search.val(" ").width(10); 62847 } 62848 }, 62849 62850 // multi 62851 clearPlaceholder: function () { 62852 if (this.search.hasClass("select2-default")) { 62853 this.search.val("").removeClass("select2-default"); 62854 } else { 62855 // work around for the space character we set to avoid firefox caret bug 62856 if (this.search.val() === " ") this.search.val(""); 62857 } 62858 }, 62859 62860 // multi 62861 opening: function () { 62862 this.parent.opening.apply(this, arguments); 62863 62864 this.clearPlaceholder(); 62865 this.resizeSearch(); 62866 this.focusSearch(); 62867 }, 62868 62869 // multi 62870 close: function () { 62871 if (!this.opened()) return; 62872 this.parent.close.apply(this, arguments); 62873 }, 62874 62875 // multi 62876 focus: function () { 62877 this.close(); 62878 this.search.focus(); 62879 }, 62880 62881 // multi 62882 isFocused: function () { 62883 return this.search.hasClass("select2-focused"); 62884 }, 62885 62886 // multi 62887 updateSelection: function (data) { 62888 var ids = [], filtered = [], self = this; 62889 62890 // filter out duplicates 62891 $(data).each(function () { 62892 if (indexOf(self.id(this), ids) < 0) { 62893 ids.push(self.id(this)); 62894 filtered.push(this); 62895 } 62896 }); 62897 data = filtered; 62898 62899 this.selection.find(".select2-search-choice").remove(); 62900 $(data).each(function () { 62901 self.addSelectedChoice(this); 62902 }); 62903 self.postprocessResults(); 62904 }, 62905 62906 tokenize: function() { 62907 var input = this.search.val(); 62908 input = this.opts.tokenizer(input, this.data(), this.bind(this.onSelect), this.opts); 62909 if (input != null && input != undefined) { 62910 this.search.val(input); 62911 if (input.length > 0) { 62912 this.open(); 62913 } 62914 } 62915 62916 }, 62917 62918 // multi 62919 onSelect: function (data) { 62920 this.addSelectedChoice(data); 62921 if (this.select || !this.opts.closeOnSelect) this.postprocessResults(); 62922 62923 if (this.opts.closeOnSelect) { 62924 this.close(); 62925 this.search.width(10); 62926 } else { 62927 if (this.countSelectableResults()>0) { 62928 this.search.width(10); 62929 this.resizeSearch(); 62930 this.positionDropdown(); 62931 } else { 62932 // if nothing left to select close 62933 this.close(); 62934 } 62935 } 62936 62937 // since its not possible to select an element that has already been 62938 // added we do not need to check if this is a new element before firing change 62939 this.triggerChange({ added: data }); 62940 62941 this.focusSearch(); 62942 }, 62943 62944 // multi 62945 cancel: function () { 62946 this.close(); 62947 this.focusSearch(); 62948 }, 62949 62950 addSelectedChoice: function (data) { 62951 var enableChoice = !data.locked, 62952 enabledItem = $( 62953 "<li class='select2-search-choice'>" + 62954 " <div></div>" + 62955 " <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" + 62956 "</li>"), 62957 disabledItem = $( 62958 "<li class='select2-search-choice select2-locked'>" + 62959 "<div></div>" + 62960 "</li>"); 62961 var choice = enableChoice ? enabledItem : disabledItem, 62962 id = this.id(data), 62963 val = this.getVal(), 62964 formatted; 62965 62966 formatted=this.opts.formatSelection(data, choice.find("div")); 62967 if (formatted != undefined) { 62968 choice.find("div").replaceWith("<div>"+this.opts.escapeMarkup(formatted)+"</div>"); 62969 } 62970 62971 if(enableChoice){ 62972 choice.find(".select2-search-choice-close") 62973 .bind("mousedown", killEvent) 62974 .bind("click dblclick", this.bind(function (e) { 62975 if (!this.enabled) return; 62976 62977 $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){ 62978 this.unselect($(e.target)); 62979 this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); 62980 this.close(); 62981 this.focusSearch(); 62982 })).dequeue(); 62983 killEvent(e); 62984 })).bind("focus", this.bind(function () { 62985 if (!this.enabled) return; 62986 this.container.addClass("select2-container-active"); 62987 this.dropdown.addClass("select2-drop-active"); 62988 })); 62989 } 62990 62991 choice.data("select2-data", data); 62992 choice.insertBefore(this.searchContainer); 62993 62994 val.push(id); 62995 this.setVal(val); 62996 }, 62997 62998 // multi 62999 unselect: function (selected) { 63000 var val = this.getVal(), 63001 data, 63002 index; 63003 63004
63004 selected = selected.closest(".select2-search-choice"); 63005 63006 if (selected.length === 0) { 63007 throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; 63008 } 63009 63010 data = selected.data("select2-data"); 63011 63012 index = indexOf(this.id(data), val); 63013 63014 if (index >= 0) { 63015 val.splice(index, 1); 63016 this.setVal(val); 63017 if (this.select) this.postprocessResults(); 63018 } 63019 selected.remove(); 63020 this.triggerChange({ removed: data }); 63021 }, 63022 63023 // multi 63024 postprocessResults: function () { 63025 var val = this.getVal(), 63026 choices = this.results.find(".select2-result-selectable"), 63027 compound = this.results.find(".select2-result-with-children"), 63028 self = this; 63029 63030 choices.each2(function (i, choice) { 63031 var id = self.id(choice.data("select2-data")); 63032 if (indexOf(id, val) >= 0) { 63033 choice.addClass("select2-disabled").removeClass("select2-result-selectable"); 63034 } else { 63035 choice.removeClass("select2-disabled").addClass("select2-result-selectable"); 63036 } 63037 }); 63038 63039 compound.each2(function(i, e) { 63040 if (!e.is('.select2-result-selectable') && e.find(".select2-result-selectable").length==0) { // FIX FOR HIRECHAL DATA 63041 e.addClass("select2-disabled"); 63042 } else { 63043 e.removeClass("select2-disabled"); 63044 } 63045 }); 63046 63047 if (this.highlight() == -1){ 63048 choices.each2(function (i, choice) { 63049 if (!choice.hasClass("select2-disabled") && choice.hasClass("select2-result-selectable")) { 63050 self.highlight(0); 63051 return false; 63052 } 63053 }); 63054 } 63055 63056 }, 63057 63058 // multi 63059 resizeSearch: function () { 63060 63061 var minimumWidth, left, maxWidth, containerLeft, searchWidth, 63062 sideBorderPadding = getSideBorderPadding(this.search); 63063 63064 minimumWidth = measureTextWidth(this.search) + 10; 63065 63066 left = this.search.offset().left; 63067 63068 maxWidth = this.selection.width(); 63069 containerLeft = this.selection.offset().left; 63070 63071 searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; 63072 if (searchWidth < minimumWidth) { 63073 searchWidth = maxWidth - sideBorderPadding; 63074 } 63075 63076 if (searchWidth < 40) { 63077 searchWidth = maxWidth - sideBorderPadding; 63078 } 63079 63080 if (searchWidth <= 0) { 63081 searchWidth = minimumWidth 63082 } 63083 63084 this.search.width(searchWidth); 63085 }, 63086 63087 // multi 63088 getVal: function () { 63089 var val; 63090 if (this.select) { 63091 val = this.select.val(); 63092 return val === null ? [] : val; 63093 } else { 63094 val = this.opts.element.val(); 63095 return splitVal(val, this.opts.separator); 63096 } 63097 }, 63098 63099 // multi 63100 setVal: function (val) { 63101 var unique; 63102 if (this.select) { 63103 this.select.val(val); 63104 } else { 63105 unique = []; 63106 // filter out duplicates 63107 $(val).each(function () { 63108 if (indexOf(this, unique) < 0) unique.push(this); 63109 }); 63110 this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator)); 63111 } 63112 }, 63113 63114 // multi 63115 val: function () { 63116 var val, data = [], self=this; 63117 63118 if (arguments.length === 0) { 63119 return this.getVal(); 63120 } 63121 63122 val = arguments[0]; 63123 63124 if (!val) { 63125 this.opts.element.val(""); 63126 this.updateSelection([]); 63127 this.clearSearch(); 63128 this.triggerChange(); 63129 return; 63130 } 63131 63132 // val is a list of ids 63133 this.setVal(val); 63134 63135 if (this.select) { 63136 this.select.find(":selected").each(function () { 63137 data.push({id: $(this).attr("value"), text: $(this).text()}); 63138 }); 63139 this.updateSelection(data); 63140 this.triggerChange(); 63141 } else { 63142 if (this.opts.initSelection === undefined) { 63143 throw new Error("val() cannot be called if initSelection() is not defined") 63144 } 63145 63146 this.opts.initSelection(this.opts.element, function(data){ 63147 var ids=$(data).map(self.id); 63148 self.setVal(ids); 63149 self.updateSelection(data); 63150 self.clearSearch(); 63151 self.triggerChange(); 63152 }); 63153 } 63154 this.clearSearch(); 63155 }, 63156 63157 // multi 63158 onSortStart: function() { 63159 if (this.select) { 63160 throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead."); 63161 } 63162
63163 // collapse search field into 0 width so its container can be collapsed as well 63164 this.search.width(0); 63165 // hide the container 63166 this.searchContainer.hide(); 63167 }, 63168 63169 // multi 63170 onSortEnd:function() { 63171 63172 var val=[], self=this; 63173 63174 // show search and move it to the end of the list 63175 this.searchContainer.show(); 63176 // make sure the search container is the last item in the list 63177 this.searchContainer.appendTo(this.searchContainer.parent()); 63178 // since we collapsed the width in dragStarted, we resize it here 63179 this.resizeSearch(); 63180 63181 // update selection 63182 63183 this.selection.find(".select2-search-choice").each(function() { 63184 val.push(self.opts.id($(this).data("select2-data"))); 63185 }); 63186 this.setVal(val); 63187 this.triggerChange(); 63188 }, 63189 63190 // multi 63191 data: function(values) { 63192 var self=this, ids; 63193 if (arguments.length === 0) { 63194 return this.selection 63195 .find(".select2-search-choice") 63196 .map(function() { return $(this).data("select2-data"); }) 63197 .get(); 63198 } else { 63199 if (!values) { values = []; } 63200 ids = $.map(values, function(e) { return self.opts.id(e)}); 63201 this.setVal(ids); 63202 this.updateSelection(values); 63203 this.clearSearch(); 63204 } 63205 } 63206 }); 63207 63208 $.fn.select2 = function () { 63209 63210 var args = Array.prototype.slice.call(arguments, 0), 63211 opts, 63212 select2, 63213 value, multiple, allowedMethods = ["val", "destroy", "opened", "open", "close", "focu
63213s", "isFocused", "container", "onSortStart", "onSortEnd", "enable", "disable", "positionDropdown", "data"]; 63214 63215 this.each(function () { 63216 if (args.length === 0 || typeof(args[0]) === "object") { 63217 opts = args.length === 0 ? {} : $.extend({}, args[0]); 63218 opts.element = $(this); 63219 63220 if (opts.element.get(0).tagName.toLowerCase() === "select") { 63221 multiple = opts.element.attr("multiple"); 63222 } else { 63223 multiple = opts.multiple || false; 63224 if ("tags" in opts) {opts.multiple = multiple = true;} 63225 } 63226 63227 select2 = multiple ? new MultiSelect2() : new SingleSelect2(); 63228 select2.init(opts); 63229 } else if (typeof(args[0]) === "string") { 63230 63231 if (indexOf(args[0], allowedMethods) < 0) { 63232 throw "Unknown method: " + args[0]; 63233 } 63234 63235 value = undefined; 63236 select2 = $(this).data("select2"); 63237 if (select2 === undefined) return; 63238 if (args[0] === "container") { 63239 value=select2.container; 63240 } else { 63241 value = select2[args[0]].apply(select2, args.slice(1)); 63242 } 63243 if (value !== undefined) {return false;} 63244 } else { 63245 throw "Invalid arguments to select2 plugin: " + args; 63246 } 63247 }); 63248 return (value === undefined) ? this : value; 63249 }; 63250 63251 // plugin defaults, accessible to users 63252 $.fn.select2.defaults = { 63253 width: "copy", 63254 closeOnSelect: true, 63255 openOnEnter: true, 63256 containerCss: {}, 63257 dropdownCss: {}, 63258 containerCssClass: "", 63259 dropdownCssClass: "", 63260 formatResult: function(result, container, query) { 63261 var markup=[]; 63262 markMatch(result.text, query.term, markup); 63263 return markup.join(""); 63264 }, 63265 formatSelection: function (data, container) { 63266 return data ? data.text : undefined; 63267 }, 63268 sortResults: function (results, container, query) { 63269 return results; 63270 }, 63271 formatResultCssClass: function(data) {return undefined;}, 63272 formatNoMatches: function () { return "No matches found"; }, 63273 formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1? "" : "s"); }, 63274 formatInputTooLong: function (input, max) { var n = input.length - max; return "Please enter " + n + " less character" + (n == 1? "" : "s"); }, 63275 formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, 63276 formatLoadMore: function (pageNumber) { return "Loading more results..."; }, 63277 formatSearching: function () { return "Searching..."; }, 63278 minimumResultsForSearch: 0, 63279 minimumInputLength: 0, 63280 maximumInputLength: null, 63281 maximumSelectionSize: 0, 63282 id: function (e) { return e.id; }, 63283 matcher: function(term, text) { 63284 return text.toUpperCase().indexOf(term.toUpperCase()) >= 0; 63285 }, 63286 separator: ",", 63287 tokenSeparators: [], 63288 tokenizer: defaultTokenizer, 63289 escapeMarkup: function (markup) { 63290 if (markup && typeof(markup) === "string") { 63291 return markup.replace(/&/g, "&"); 63292 } 63293 return markup; 63294 }, 63295 blurOnChange: false 63296 }; 63297 63298 // exports 63299 window.Select2 = { 63300 query: { 63301 ajax: ajax, 63302 local: local, 63303 tags: tags 63304 }, util: { 63305 debounce: debounce, 63306 markMatch: markMatch 63307 }, "class": { 63308 "abstract": AbstractSelect2, 63309 "single": SingleSelect2, 63310 "multi": MultiSelect2 63311 } 63312 }; 63313 63314}(jQuery)); 63315(function() { 63316 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 63317 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63318 hasProp = {}.hasOwnProperty; 63319 63320 App.Pages.TutorialsEdit = (function(superClass) { 63321 extend(TutorialsEdit, superClass); 63322 63323 function TutorialsEdit() { 63324 this.attachRedactor = bind(this.attachRedactor, this); 63325 this.onStepRemove = bind(this.onStepRemove, this); 63326 this.onStepInsert = bind(this.onStepInsert, this); 63327 this.removePrimaryImage = bind(this.removePrimaryImage, this); 63328 this.initUploader = bind(this.initUploader, this); 63329 this.handleFormSubmit = bind(this.handleFormSubmit, this); 63330 this.onSoftwareChange = bind(this.onSoftwareChange, this); 63331 this.onCategoriesChange = bind(this.onCategoriesChange, this); 63332 return TutorialsEdit.__super__.constructor.apply(this, arguments); 63333 } 63334 63335 TutorialsEdit.prototype.initialize = function() { 63336 var $steps; 63337 this.$form = $('.edit_tutorial'); 63338 this.imagesPath = "/tutorials/" + gon.tutorial_id + "/images"; 63339 this.$dropZone = $('.js-primary-image-dropzone'); 63340 this.$uploadProgress = $('.js-primary-image-upload-progress'); 63341 this.$uploadText = $('.upload-dropzone__text'); 63342 this.$primaryImage = $('.tutorial__primary-image'); 63343 this.$primaryImageContainer = $('.js-primary-image-container'); 63344 this.reindexStepTitles = true; 63345 this.$categoriesCountField = $('#categories-count'); 63346 this.$softwareCountField = $('#software-count'); 63347 this.$imageUploadCounter = $('#image-upload-counter'); 63348 if (gon.tutorial_error_notification) { 63349 this.displayErrorNotification(); 63350 } 63351 this.initUploader(); 63352 this.attachRedactor($('.step-description')); 63353 $steps = $('.js-steps'); 63354 $steps.on('cocoon:after-insert', this.onStepInsert); 63355 $steps.on('cocoon:after-remove', this.onStepRemove); 63356 $('.step-position').on('change', (function(_this) { 63357 return function() { 63358 return _this.reindexStepTitles = false;
63359 }; 63360 })(this)); 63361 $('#tutorial_categories, #tutorial_software').select2({ 63362 containerCssClass: 'custom-select2', 63363 width: 'resolve' 63364 }); 63365 $('#tutorial_categories').on('change', this.onCategoriesChange); 63366 $('#tutorial_software').on('change', this.onSoftwareChange); 63367 $('#tutorial_tags').on('change', this.onTagsChange); 63368 this.$form.on('submit', this.handleFormSubmit); 63369 $("#tutorial_tags").select2({ 63370 containerCssClass: 'custom-select2', 63371 tags: [], 63372 tokenSeparators: [',', ' '] 63373 }); 63374 $('.js-primary-image-form__remove-link').on('ajax:success', this.removePrimaryImage); 63375 this.numberOfSelectedCategories = $('#s2id_tutorial_categories').find('.select2-search-choice').length; 63376 this.$categoriesCountField.val(this.numberOfSelectedCategories); 63377 this.numberOfSelectedSoftware = $('#s2id_tutorial_software').find('.select2-search-choice').length; 63378 this.$softwareCountField.val(this.numberOfSelectedSoftware); 63379 return this.initValidation(); 63380 }; 63381 63382 TutorialsEdit.prototype.onCategoriesChange = function() { 63383 this.$categoriesCountField.val($('#s2id_tutorial_categories').find('.select2-search-choice').length); 63384 return this.$categoriesCountField.valid(); 63385 }; 63386 63387 TutorialsEdit.prototype.onSoftwareChange = function() { 63388 this.$softwareCountField.val($('#s2id_tutorial_software').find('.select2-search-choice').length); 63389 return this.$softwareCountField.valid(); 63390 }; 63391 63392 TutorialsEdit.prototype.onTagsChange = function() { 63393 return $('#tutorial_tags').valid(); 63394 }; 63395 63396 TutorialsEdit.prototype.displayErrorNotification = function() { 63397 return App.events.publish('app:notification:error', gon.tutorial_error_notification); 63398 }; 63399 63400 TutorialsEdit.prototype.handleFormSubmit = function(e) { 63401 var categoriesSelect, currentCategories, currentTags, isValid, tagsInput; 63402 isValid = this.$form.valid(); 63403 if (isValid) { 63404 categoriesSelect = $('#tutorial_categories')[0]; 63405 currentCategories = $(categoriesSelect).find(':selected').toArray().map((function(_this) { 63406 return function(item) { 63407 return item.text; 63408 }; 63409 })(this)).join('_'); 63410 tagsInput = $('#tutorial_tags')[0]; 63411 currentTags = tagsInput.value.replaceAll(',', '_'); 63412 return window.customEventTracker({ 63413 name: 'upload_content', 63414 userId: App.config.userId || '', 63415 eventData: { 63416 content_type: 'tutorial', 63417 content_category: currentCategories, 63418 content_tags: currentTags, 63419 file_format: '', 63420 content_subcategory: '', 63421 model_price: 0.00 63422 } 63423 }); 63424 } 63425 }; 63426 63427 TutorialsEdit.prototype.initUploader = function() { 63428 return $('#tutorial_primary_image').fileupload({ 63429 dataType: 'json', 63430 url: "/tutorials/" + gon.tutorial_id + "/images", 63431 autoUpload: true, 63432 dropZone: this.$dropZone, 63433 formData: { 63434 _method: 'post', 63435 primary: true 63436 }, 63437 paramName: 'file', 63438 add: (function(_this) { 63439 return function(_, data) { 63440 _this.$dropZone.removeClass('no-image'); 63441 _this.$uploadText.hide(); 63442 _this.$primaryImageContainer.hide(); 63443 if (!_this.$uploadProgress.is(':visible')) { 63444 _this.$uploadProgress.removeClass('is-hidden').fadeIn(); 63445 } 63446 return data.submit(); 63447 }; 63448 })(this), 63449 done: (function(_this) { 63450 return function(_, data) { 63451 _this.$uploadProgress.hide(); 63452 data = $.parseJSON(data.jqXHR.responseText); 63453 _this.$primaryImage.attr('src', data.image); 63454 _this.$primaryImageContainer.removeClass('is-hidden').fadeIn(); 63455 $('.js-primary-image-form__remove-link').attr('href', "/tutorials/" + gon.tutorial_id + "/images/" + data.id); 63456 _this.$imageUploadCounter.val(1); 63457 return _this.$imageUploadCounter.valid(); 63458 }; 63459 })(this) 63460 }); 63461 }; 63462 63463 TutorialsEdit.prototype.removePrimaryImage = function() { 63464 this.$primaryImageContainer.hide(); 63465 this.$dropZone.addClass('no-image'); 63466 this.$uploadText.show().removeClass('is-hidden'); 63467 this.$imageUploadCounter.val(0); 63468 return this.$imageUploadCounter.valid(); 63469 }; 63470 63471 TutorialsEdit.prototype.onStepInsert = function(e, step) { 63472 var displayPos, nextPos, previousStep; 63473 previousStep = step.prev('.nested-fields:visible'); 63474 if (previousStep.length > 0) { 63475 nextPos = +previousStep.find('.step-position-input').val() + 1; 63476 displayPos = nextPos + 1; 63477 } else { 63478 nextPos = 0; 63479 displayPos = 1; 63480 } 63481 step.find('.step-position').val("Step " + displayPos); 63482 step.find('.step-position-input').val(nextPos); 63483 return this.attachRedactor(step.find('.step-description')); 63484 }; 63485 63486 TutorialsEdit.prototype.onStepRemove = function() { 63487 return $('.nested-fields:visible').each((function(_this) { 63488 return function(index, step) { 63489 if (_this.reindexStepTitles) { 63490 $(step).find('.step-position').val("Step " + (index + 1)); 63491 return $(step).find('.step-position-input').val(index); 63492 } 63493 }; 63494 })(this)); 63495 }; 63496 63497 TutorialsEdit.prototype.attachRedactor = function($element) { 63498 return $element.redactor({ 63499 plugins: ['fullscreen', 'fontsize', 'fontcolor', 'fontfamily'], 63500 minHeight: 300, 63501 convertDivs: false, 63502 autoresize: false, 63503 imageUpload: this.imagesPath, 63504 imageGetJson: this.imagesPath 63505 }); 63506 }; 63507 63508 TutorialsEdit.prototype.validationSettings = function() { 63509 return { 63510 ignore: [], 63511 rules: { 63512 'tutorial[title]': { 63513 required: true, 63514 validateCompetitors: true 63515 }, 63516 'tutorial[description]': { 63517 validateCompetitors: true 63518 }, 63519 'tutorial[tags]': { 63520 validateCompetitors: true 63521 }, 63522 categories_count: { 63523 required: true, 63524 min: 1 63525 }, 63526 software_count: { 63527 required: true, 63528 min: 1 63529 }, 63530 image_upload_counter: { 63531 required: true, 63532 range: [1, 1] 63533 }, 63534 publish: { 63535 required: true 63536 } 63537 }, 63538 messages: { 63539 categories_count: { 63540 min: 'Please select at least 1 category' 63541 }, 63542 software_count: { 63543 min: 'Please select at least 1 software' 63544 }, 63545 image_upload_counter: { 63546 range: 'Please upload preview image' 63547 } 63548 }, 63549 errorPlacement: function(error, element) { 63550 switch (element.attr('name')) { 63551 case 'categories_count': 63552 return error.insertAfter('#s2id_tutorial_categories'); 63553 case 'software_count': 63554 return error.insertAfter('#s2id_tutorial_software'); 63555 case 'publish': 63556 return error.appendTo($('.js-publish-checkbox-error')); 63557 default: 63558 return error.insertAfter(element); 63559 } 63560 } 63561 }; 63562 }; 63563 63564 TutorialsEdit.prototype.initValidation = function() { 63565 return this.$form.validate(this.validationSettings()); 63566 }; 63567 63568 return TutorialsEdit; 63569 63570 })(App.Core.Page); 63571 63572}).call(this); 63573(function() { 63574 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63575 hasProp = {}.hasOwnProperty; 63576 63577 App.Pages.TutorialsShow = (function(superClass) { 63578 extend(TutorialsShow, superClass); 63579 63580 function TutorialsShow() { 63581 return TutorialsShow.__super__.constructor.apply(this, arguments); 63582 } 63583 63584 TutorialsShow.prototype.widgets = ['comments', 'likes']; 63585 63586 TutorialsShow.prototype.initialize = function() { 63587 if (gon.preview) { 63588 return this.displayPreviewBar(); 63589 } 63590 }; 63591 63592 TutorialsShow.prototype.displayPreviewBar = function() { 63593 return $('.js-display-preview-bar').show(); 63594 }; 63595 63596 return TutorialsShow; 63597 63598 })(App.Core.Page); 63599 63600}).call(this); 63601(function() { 63602 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63603 hasProp = {}.hasOwnProperty; 63604 63605 App.Pages.TutorialsSubmitForReview = (function(superClass) { 63606 extend(TutorialsSubmitForReview, superClass); 63607 63608 function TutorialsSubmitForReview() { 63609 return TutorialsSubmitForReview.__super__.constructor.apply(this, arguments); 63610 } 63611 63612 return TutorialsSubmitForReview; 63613 63614 })(App.Pages.TutorialsEdit); 63615 63616}).call(this); 63617(function() { 63618 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63619 hasProp = {}.hasOwnProperty; 63620 63621 App.Pages.TutorialsUpdate = (function(superClass) { 63622 extend(TutorialsUpdate, superClass); 63623 63624 function TutorialsUpdate() { 63625 return TutorialsUpdate.__super__.constructor.apply(this, arguments); 63626 } 63627 63628 return TutorialsUpdate; 63629 63630 })(App.Pages.TutorialsEdit); 63631 63632}).call(this); 63633(function() { 63634 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63635 hasProp = {}.hasOwnProperty; 63636 63637 App.Pages.UsersIndex = (function(superClass) { 63638 extend(UsersIndex, superClass); 63639 63640 function UsersIndex() { 63641 return UsersIndex.__super__.constructor.apply(this, arguments); 63642 } 63643 63644 UsersIndex.prototype.initialize = function() { 63645 return this.bindEvents(); 63646 }; 63647 63648 UsersIndex.prototype.bindEvents = function() { 63649 return $('.js-user-search-button, .pagination li').on('click', this.showUpdatingSpinner); 63650 }; 63651 63652 UsersIndex.prototype.showUpdatingSpinner = function() { 63653 return $('.users-list').addClass('is-updating-with-spinner spinner--top is-fixed'); 63654 }; 63655 63656 return UsersIndex; 63657 63658 })(App.Core.Page); 63659 63660}).call(this); 63661(function() { 63662 var base, 63663 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63664 hasProp = {}.hasOwnProperty; 63665 63666 if ((base = App.Pages).Users == null) { 63667 base.Users = {}; 63668 } 63669 63670 App.Pages.Users.PasswordsEdit = (function(superClass) { 63671 extend(PasswordsEdit, superClass); 63672 63673 function PasswordsEdit() { 63674 return PasswordsEdit.__super__.constructor.apply(this, arguments); 63675 } 63676 63677 PasswordsEdit.prototype.initialize = function() { 63678 this.$resetPasswordForm = $('.new_user'); 63679 return this.initValidation(); 63680 }; 63681 63682 PasswordsEdit.prototype.validationSettings = function() { 63683 return { 63684 rules: { 63685 'user[password]': { 63686 required: true, 63687 minlength: 8, 63688 validatePassword: true 63689 }, 63690 'user[password_confirmation]': { 63691 required: true, 63692 minlength: 8, 63693 equalTo: '#user_password' 63694 } 63695 } 63696 }; 63697 }; 63698 63699 PasswordsEdit.prototype.initValidation = function() { 63700 return this.$resetPasswordForm.validate(this.validationSettings()); 63701 }; 63702 63703 return PasswordsEdit; 63704 63705 })(App.Core.Page); 63706 63707}).call(this); 63708(function() { 63709 var base, 63710 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63711 hasProp = {}.hasOwnProperty; 63712 63713 if ((base = App.Pages).Users == null) { 63714 base.Users = {}; 63715 } 63716 63717 App.Pages.Users.PasswordsNew = (function(superClass) { 63718 extend(PasswordsNew, superClass); 63719 63720 function PasswordsNew() { 63721 return PasswordsNew.__super__.constructor.apply(this, arguments); 63722 } 63723 63724 PasswordsNew.prototype.initialize = function() { 63725 this.$forgotYourPasswordForm = $('.new_user'); 63726 return this.initValidation(); 63727 }; 63728 63729 PasswordsNew.prototype.validationSettings = function() { 63730 return { 63731 rules: { 63732 'user[email]': { 63733 required: true, 63734 email: true 63735 } 63736 } 63737 }; 63738 }; 63739 63740 PasswordsNew.prototype.initValidation = function() { 63741 return this.$forgotYourPasswordForm.validate(this.validationSettings()); 63742 }; 63743 63744 return PasswordsNew; 63745 63746 })(App.Core.Page); 63747 63748}).call(this); 63749(function() { 63750 var base, 63751 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63752 hasProp = {}.hasOwnProperty; 63753 63754 if ((base = App.Pages).Users == null) { 63755 base.Users = {}; 63756 } 63757 63758 App.Pages.Users.SessionsNew = (function(superClass) { 63759 extend(SessionsNew, superClass); 63760 63761 function SessionsNew() { 63762 return SessionsNew.__super__.constructor.apply(this, arguments); 63763 } 63764 63765 SessionsNew.prototype.initialize = function() { 63766 this.$signInForm = $('#new_user'); 63767 return this.initValidation(); 63768 }; 63769 63770 SessionsNew.prototype.validationSettings = function() { 63771 return { 63772 rules: { 63773 'user[login]': { 63774 required: true 63775 }, 63776 'user[password]': { 63777 required: true 63778 } 63779 } 63780 }; 63781 }; 63782 63783 SessionsNew.prototype.initValidation = function() { 63784 return this.$signInForm.validate(this.validationSettings()); 63785 }; 63786 63787 return SessionsNew; 63788 63789 })(App.Core.Page); 63790 63791}).call(this); 63792(function() { 63793 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63794 hasProp = {}.hasOwnProperty; 63795 63796 App.Pages.Users.SessionsCreate = (function(superClass) { 63797 extend(SessionsCreate, superClass); 63798 63799 function SessionsCreate() { 63800 return SessionsCreate.__super__.constructor.apply(this, arguments); 63801 } 63802 63803 return SessionsCreate; 63804 63805 })(App.Pages.Users.SessionsNew); 63806 63807}).call(this); 63808(function() { 63809 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63810 hasProp = {}.hasOwnProperty; 63811 63812 App.Pages.Users.SessionsFailureHtml = (function(superClass) { 63813 extend(SessionsFailureHtml, superClass); 63814 63815 function SessionsFailureHtml() { 63816 return SessionsFailureHtml.__super__.constructor.apply(this, arguments); 63817 } 63818 63819 return SessionsFailureHtml; 63820 63821 })(App.Pages.Users.SessionsNew); 63822 63823}).call(this); 63824(function() { 63825 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 63826 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63827 hasProp = {}.hasOwnProperty; 63828 63829 App.Pages.UsersShow = (function(superClass) { 63830 extend(UsersShow, superClass); 63831 63832 function UsersShow() { 63833 this.lazyloadImages = bind(this.lazyloadImages, this); 63834 return UsersShow.__super__.constructor.apply(this, arguments); 63835 }
63836 63837 UsersShow.prototype.widgets = ['follow']; 63838 63839 UsersShow.prototype.initialize = function() { 63840 this.initTooltip(); 63841 if ($('.tab-content').exists()) { 63842 return this.initTabs(); 63843 } 63844 }; 63845 63846 UsersShow.prototype.initTooltip = function() { 63847 $('.js-tooltip-with-list').tooltipster({ 63848 theme: 'tooltip--light tooltip--popover tooltip--is-list', 63849 animation: 'grow', 63850 interactive: true, 63851 content: $('#hire-me-button-tooltip') 63852 }); 63853 return $('.js-tooltip-hire-me-template').tooltipster({ 63854 theme: 'tooltip--light tooltip--popover', 63855 animation: 'grow', 63856 interactive: true, 63857 content: 'Send Project invitation to your client.' 63858 }); 63859 }; 63860 63861 UsersShow.prototype.initTabs = function() { 63862 $('.user-content__tabs').easytabs({ 63863 animate: true, 63864 panelActiveClass: 'is-active', 63865 panelContext: $('.user-content__content'), 63866 tabActiveClass: 'is-active', 63867 updateHash: false, 63868 defaultTab: $('.user-content .tabs li').first() 63869 }).bind('easytabs:after', this.lazyloadImages); 63870 return this.lazyloadImages(); 63871 }; 63872 63873 UsersShow.prototype.lazyloadImages = function() { 63874 return new LazyLoad({ 63875 elements_selector: '.js-lazy-img' 63876 }); 63877 }; 63878 63879 return UsersShow; 63880 63881 })(App.Core.Page); 63882 63883}).call(this); 63884(function() { 63885 App.Pages.UsersThanks = (function() { 63886 function UsersThanks() {} 63887 63888 UsersThanks.prototype.initialize = function() { 63889 return $(window).load(function() { 63890 return App.events.publish('app:element:focus', $('.js-thanks')); 63891 }); 63892 }; 63893 63894 return UsersThanks; 63895 63896 })(); 63897 63898}).call(this); 63899(function() { 63900 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 63901 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 63902 hasProp = {}.hasOwnProperty; 63903 63904 App.Pages.WelcomeIndex = (function(superClass) { 63905 extend(WelcomeIndex, superClass); 63906 63907 function WelcomeIndex() { 63908 this.setSelectedContent = bind(this.setSelectedContent, this); 63909 this.bindEvents = bind(this.bindEvents, this); 63910 return WelcomeIndex.__super__.constructor.apply(this, arguments); 63911 } 63912 63913 WelcomeIndex.prototype.initialize = function() { 63914 this.activeBtnClassName = 'btn-primary'; 63915 this.inactiveBtnClassName = 'btn-default'; 63916 this.$btnGroup = $('.js-segments-buttons'); 63917 this.$allSegmentsInfo = $('.js-segments-info'); 63918 return this.bindEvents(); 63919 }; 63920 63921 WelcomeIndex.prototype.bindEvents = function() { 63922 return this.$btnGroup.find('button').on('click', this.setSelectedContent); 63923 }; 63924 63925 WelcomeIndex.prototype.setSelectedContent = function(e) { 63926 this.$el = $(e.currentTarget); 63927 this.selectedValue = this.$el.context.innerText.toLowerCase(); 63928 this.$activeSegmentContent = this.$allSegmentsInfo.find(".js-" + this.selectedValue + "-segment-content"); 63929 this.$btnGroup.find('button').removeClass(this.activeBtnClassName).addClass(this.inactiveBtnClassName); 63930 this.$el.removeClass(this.inactiveBtnClassName).addClass(this.activeBtnClassName); 63931 this.$allSegmentsInfo.find('.segment-info').addClass('is-hidden'); 63932 return this.$activeSegmentContent.removeClass('is-hidden'); 63933 }; 63934 63935 return WelcomeIndex; 63936 63937 })(App.Core.Page); 63938 63939}).call(this); 63940(function() { 63941 63942 63943}).call(this); 63944(function() { 63945 63946 63947}).call(this); 63948(function() { 63949 App.Backbone = { 63950 Models: {}, 63951 Collections: {}, 63952 Routers: {}, 63953 Views: { 63954 Publisher20: { 63955 Printable: {}, 63956 Cg: {} 63957 }, 63958 Comments: {}, 63959 Modals: {} 63960 }, 63961 Configs: {} 63962 }; 63963 63964}).call(this); 63965(function() { 63966 this.JST || (this.JST = {}); 63967 this.JST["chosen"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) { 63968 return "multiple=\"multiple\""; 63969},"3":function(container,depth0,helpers,partials,data) { 63970 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 63971 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 63972 return parent[propertyName]; 63973 } 63974 return undefined 63975 }; 63976 63977 return " <option value=\"" 63978 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"id") || (depth0 != null ? lookupProperty(depth0,"id") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
63978),{"name":"id","hash":{},"data":data,"loc":{"start":{"line":3,"column":23},"end":{"line":3,"column":29}}}) : helper))) 63979 + "\">" 63980 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"text") || (depth0 != null ? lookupProperty(depth0,"text") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"text","hash":{},"data":data,"loc":{"start":{"line":3,"column":31},"end":{"line":3,"column":39}}}) : helper))) 63981 + "</option>\n"; 63982},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 63983 var stack1, helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 63984 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 63985 return parent[propertyName]; 63986 } 63987 return undefined 63988 }; 63989 63990 return "<select name=\"" 63991 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"name") || (depth0 != null ? lookupProperty(depth0,"name") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"name","hash":{},"data":data,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":22}}}) : helper))) 63992 + "\" id=\"" 63993 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"id") || (depth0 != null ? lookupProperty(depth0,"id") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"id","hash":{},"data":data,"loc":{"start":{"line":1,"column":28},"end":{"line":1,"column":34}}}) : helper))) 63994 + "\" data-placeholder=\"" 63995 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"placeholder") || (depth0 != null ? lookupProperty(depth0,"placeholder") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"placeholder","hash":{},"data":data,"loc":{"start":{"line":1,"column":54},"end":{"line":1,"column":69}}}) : helper))) 63996 + "\" " 63997 + ((stack1 = lookupProperty(helpers,"if").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"multiple") : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":1,"column":71},"end":{"line":1,"column":114}}})) != null ? stack1 : "") 63998 + ">\n" 63999 + ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"selectOptions") : depth0),{"name":"each","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":2,"column":4},"end":{"line":4,"column":13}}})) != null ? stack1 : "") 64000 + "</select>"; 64001},"useData":true}); 64002 return this.JST["chosen"]; 64003}).call(this); 64004(function() { 64005 this.JST || (this.JST = {}); 64006 this.JST["comments/form"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64007 var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64008 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64009 return parent[propertyName]; 64010 } 64011 return undefined 64012 }; 64013 64014 return "<form action=\"\" class=\"comment-form\" method=\"post\"><input name=\"utf8\" type=\"hidden\" /><input name=\"authenticity_token\" type=\"hidden\" /><div class=\"comment-form__author\"><a href=\"" 64015 + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? lookupProperty(depth0,"author") : depth0)) != null ? lookupProperty(stack1,"url") : stack1), depth0)) 64016 + "\" title=\"" 64017 + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? lookupProperty(depth0,"author") : depth0)) != null ? lookupProperty(stack1,"username") : stack1), depth0)) 64018 + "\"><img alt=\"" 64019 + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? lookupProperty(depth0,"author") : depth0)) != null ? lookupProperty(stack1,"username") : stack1), depth0)) 64020 + "\" class=\"avatar\" src=\"" 64021 + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? lookupProperty(depth0,"author") : depth0)) != null ? lookupProperty(stack1,"avatar_url") : stack1), depth0)) 64022 + "\" /></a></div><div class=\"comment-form__content\"><textarea class=\"field field--compact-text\" name=\"content\" placeholder=\"Your comment\" required=\"\"></textarea><button class=\"js-auth-control cgt-button cgt-button--primary cgt-button--small js-comment-submit\" type=\"submit\"><span>Post comment</span></button></div></form>"; 64023},"useData":true}); 64024 return this.JST["comments/form"]; 64025}).call(this); 64026(function() { 64027 this.JST || (this.JST = {}); 64028 this.JST["cookies_policy/disabled_cookies_modal"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64029 var lookupProperty = container.lookupProperty || function(parent, propertyName) { 64030 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64031 return parent[propertyName]; 64032 } 64033 return undefined 64034 }; 64035 64036 return "<div class=\"overlay-modal--background overlay-modal--background_after-open\">\n <div class=\"overlay-modal--container_after-open overlay-modal-container--xs\" tabindex=\"-1\" role=\"dialog\" aria-label=\"Modal\">\n <div class=\"overlay-modal\">
64036\n <button class=\"btn btn-transparent overlay-modal--close-inner js-close-modal\"><i class=\"svg-inline--fa fal fa-times is-grey-dark\" data-fa-transform=\"\"></i></button>\n <div class=\"overlay-modal--content overlay-modal--cookies\">\n <div class=\"l-inner-large\">\n <h2 class=\"modal-title\">" 64037 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"disabled_cookies_modal.title",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":7,"column":34},"end":{"line":7,"column":73}}})) 64038 + "</h2>\n <p class=\"text-default\">\n " 64039 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"disabled_cookies_modal.text_1",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":9,"column":12},"end":{"line":9,"column":52}}})) 64040 + "\n </p>\n <p class=\"text-default\">\n " 64041 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"disabled_cookies_modal.text_2",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":12,"column":12},"end":{"line":12,"column":52}}})) 64042 + "\n </p>\n <div class=\"footer u-text-right u-mt10\">\n <button type=\"button\" class=\"btn btn-fat btn-primary js-close-modal\">\n " 64043 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"disabled_cookies_modal.button",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":16,"column":14},"end":{"line":16,"column":54}}})) 64044 + "\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>"; 64045},"useData":true}); 64046 return this.JST["cookies_policy/disabled_cookies_modal"]; 64047}).call(this); 64048(function() { 64049 this.JST || (this.JST = {}); 64050 this.JST["cookies_policy/notification_bar"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64051 var lookupProperty = container.lookupProperty || function(parent, propertyName) { 64052 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64053 return parent[propertyName]; 64054 } 64055 return undefined 64056 }; 64057 64058 return "<div class=\"notice\">\n <div class=\"notice-content\">\n <span class=\"close-notice js-cookies-policy-close\">\n <i class=\"fal fa-times is-not-spaced\"/>\n </span>\n " 64059 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"layout.cookies_policy.text",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":41}}})) 64060 + "\n <a class=\"link--darker\" target=\"_blank\" href=\"/pages/cookie-notice\">" 64061 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"layout.cookies_policy.learn_more",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":7,"column":72},"end":{"line":7,"column":115}}})) 64062 + "</a>\n <button class=\"btn btn-primary btn-sm js-cookies-policy-accept\">" 64063 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"layout.cookies_policy.accept",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":8,"column":68},"end":{"line":8,"column":107}}})) 64064 + "</button>\n </div>\n</div>"; 64065},"useData":true}); 64066 return this.JST["cookies_policy/notification_bar"]; 64067}).call(this); 64068(function() { 64069 this.JST || (this.JST = {}); 64070 this.JST["modals/adult_content_agreement_modal"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64071 return "<div class=\"overlay-modal--background overlay-modal--background_after-open\">\n <div class=\" overlay-modal--container_after-open overlay-modal-container--xs\" tabindex=\"-1\" role=\"dialog\" aria-label=\"Modal\">\n <div class=\"overlay-modal\">
64071\n <button class=\"btn btn-transparent overlay-modal--close-inner js-close-modal\"><i class=\"svg-inline--fa fal fa-times is-grey-dark\" data-fa-transform=\"\"></i></button>\n <div class=\"overlay-modal--content overlay-modal--adult\">\n <div class=\"l-inner-large\">\n <h2 class=\"modal-title\">Adult content warning</h2>\n <p class=\"modal-description\">You're about to see adult content. Please confirm your age.</p>\n <p class=\"modal-note\"><span>Note:</span> we take no responsibility for any content if you decide to proceed as a minor.</p>\n <div class=\"footer u-text-right u-mt10\">\n <button type=\"button\" class=\"btn btn-fat btn-outline-default u-ml10 js-set-adult-cookie\">I'm an adult, continue</button>\n <button type=\"button\" class=\"btn btn-fat btn-primary js-close-modal\">Cancel</button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>"; 64072},"useData":true}); 64073 return this.JST["modals/adult_content_agreement_modal"]; 64074}).call(this); 64075(function() { 64076 this.JST || (this.JST = {}); 64077 this.JST["modals/custom_item_request_modal"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) { 64078 var stack1, helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64079 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64080 return parent[propertyName]; 64081 } 64082 return undefined 64083 }; 64084 64085 return " <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\">Formats</label>\n <div class=\"col-12 col-md-8\">\n <input name=\"custom_model_request[formats]\" type=\"hidden\" value=\"" 64086 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"formats") || (depth0 != null ? lookupProperty(depth0,"formats") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"formats","hash":{},"data":data,"loc":{"start":{"line":37,"column":79},"end":{"line":37,"column":90}}}) : helper))) 64087 + "\">\n" 64088 + ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"formats") : depth0),{"name":"each","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":38,"column":14},"end":{"line":40,"column":23}}})) != null ? stack1 : "") 64089 + " </div>\n </div>\n"; 64090},"2":function(container,depth0,helpers,partials,data) { 64091 return " <div class=\"active-filters__item not-removable\">" 64092 + container.escapeExpression(container.lambda(depth0, depth0)) 64093 + "</div>\n"; 64094},"4":function(container,depth0,helpers,partials,data) { 64095 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64096 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64097 return parent[propertyName]; 64098 } 64099 return undefined 64100 }; 64101 64102 return " <div class=\"js-polygons-container\">\n <div class=\"form-group row js-polygons-row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\">Poly count</label>\n <div class=\"col-12 col-md-8\">\n <input name=\"custom_model_request[poly_count]\" type=\"hidden\" value=\"" 64103 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"polygons") || (depth0 != null ? lookupProperty(depth0,"polygons") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"polygons","hash":{},"data":data,"loc":{"start":{"line":50,"column":84},"end":{"line":50,"column":96}}}) : helper))) 64104 + "\">\n <div class=\"active-filters__item not-removable\">" 64105 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"polygons") || (depth0 != null ? lookupProperty(depth0,"polygons") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
64105),{"name":"polygons","hash":{},"data":data,"loc":{"start":{"line":51,"column":64},"end":{"line":51,"column":76}}}) : helper))) 64106 + "</div>\n </div>\n </div>\n </div>\n"; 64107},"6":function(container,depth0,helpers,partials,data) { 64108 var stack1, helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64109 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64110 return parent[propertyName]; 64111 } 64112 return undefined 64113 }; 64114 64115 return " <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\">License</label>\n <div class=\"col-12 col-md-8\">\n <input name=\"custom_model_request[license]\" type=\"hidden\" value=\"" 64116 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"licenses") || (depth0 != null ? lookupProperty(depth0,"licenses") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"licenses","hash":{},"data":data,"loc":{"start":{"line":61,"column":79},"end":{"line":61,"column":91}}}) : helper))) 64117 + "\">\n" 64118 + ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"licenses") : depth0),{"name":"each","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":62,"column":14},"end":{"line":64,"column":23}}})) != null ? stack1 : "") 64119 + " </div>\n </div>\n"; 64120},"8":function(container,depth0,helpers,partials,data) { 64121 return " <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\" for=\"email\">Email</label>\n <div class=\"col-12 col-md-8\">\n <input type=\"email\" id=\"email\" class=\"form-control form-control-sm\" name=\"custom_model_request[email]\">\n </div>\n </div>\n"; 64122},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64123 var stack1, helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64124 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64125 return parent[propertyName]; 64126 } 64127 return undefined 64128 }; 64129 64130 return "<div id=\"modal-request-custom-item\" class=\"modal modal--full modal--light modal--request-custom-item\">\n <button aria-hidden=\"true\" class=\"btn btn--transparent modal--close js-modal-close\" data-dismiss=\"modal\" type=\"button\">\n <i class=\"far fa-times fa-lg is-grey is-not-spaced\"></i>\n </button>\n\n <div class=\"modal-content\">\n <div class=\"modal-light__header\">\n Looking for <strong>" 64131 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"keywords") || (depth0 != null ? lookupProperty(depth0,"keywords") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"keywords","hash":{},"data":data,"loc":{"start":{"line":8,"column":26},"end":{"line":8,"column":38}}}) : helper))) 64132 + "</strong> 3D model? Let our team help you find it!\n </div>\n\n <div class=\"modal-light__body\">\n <div class=\"form-heading\">\n Fill in the form below, and we'll get back to you. Please provide as many details as possible.\n </div>\n\n <form id=\"request-custom-item\" action=\"/custom-model-requests\" method=\"post\" data-remote=true class=\"request-form js-request-form\">\n <input type=\"hidden\" name=\"authenticity_token\" value=\"" 64133 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"authenticityToken") || (depth0 != null ? lookupProperty(depth0,"authenticityToken") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
64133),{"name":"authenticityToken","hash":{},"data":data,"loc":{"start":{"line":17,"column":62},"end":{"line":17,"column":83}}}) : helper))) 64134 + "\">\n <input type=\"hidden\" name=\"custom_model_request[search_query]\" value=\"" 64135 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"keywords") || (depth0 != null ? lookupProperty(depth0,"keywords") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"keywords","hash":{},"data":data,"loc":{"start":{"line":18,"column":78},"end":{"line":18,"column":90}}}) : helper))) 64136 + "\">\n <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\">Price</label>\n <div class=\"col-12 col-md-8\">\n <input class=\"js-price-input\" name=\"custom_model_request[price]\" type=\"hidden\" value=\"" 64137 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"price") || (depth0 != null ? lookupProperty(depth0,"price") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"price","hash":{},"data":data,"loc":{"start":{"line":22,"column":98},"end":{"line":22,"column":107}}}) : helper))) 64138 + "\">\n <div id=\"price-range-request\" class=\"price-range price-range--longer\"></div>\n <div class=\"active-filters__item\">\n <span class=\"js-price-filter\">" 64139 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"price") || (depth0 != null ? lookupProperty(depth0,"price") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"price","hash":{},"data":data,"loc":{"start":{"line":25,"column":44},"end":{"line":25,"column":53}}}) : helper))) 64140 + "</span>\n <span class=\"active-filters__item-remove js-reset-price\">\n <i class=\"far fa-times is-not-spaced\"></i>\n </span>\n </div>\n </div>\n </div>\n\n" 64141 + ((stack1 = lookupProperty(helpers,"if").call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? lookupProperty(depth0,"formats") : depth0)) != null ? lookupProperty(stack1,"length") : stack1),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":33,"column":8},"end":{"line":43,"column":15}}})) != null ? stack1 : "") 64142 + "\n" 64143 + ((stack1 = lookupProperty(helpers,"if").call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? lookupProperty(depth0,"polygons") : depth0)) != null ? lookupProperty(stack1,"length") : stack1),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":45,"column":8},"end":{"line":55,"column":15}}})) != null ? stack1 : "") 64144 + "\n" 64145 + ((stack1 = lookupProperty(helpers,"if").call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? lookupProperty(depth0,"licenses") : depth0)) != null ? lookupProperty(stack1,"length") : stack1),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":57,"column":8},"end":{"line":67,"column":15}}})) != null ? stack1 : "") 64146 + "\n <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\">Additional specifications</label>\n <div class=\"col-12 col-md-8 js-checkboxes-container\">\n <div class=\"checkbox-block\">\n <input type=\"checkbox\" name=\"custom_model_request[selected_checkboxes[print_ready]]\" id=\"print_ready_request\" value=true class=\"checkbox is-spaced\">\n <label class=\"col-form-label col-form-label-sm\" for=\"print_ready_request\">3D Print</label>\n </div>\n\n <div class=\"checkbox-block\">\n <input type=\"checkbox\" name=\"custom_model_request[selected_checkboxes[low_poly]]\" id=\"low_poly_request\" value=true class=\"checkbox is-spaced\">\n <label class=\"col-form-label col-form-label-sm\" for=\"low_poly_request\">Low-poly</label>\n </div>\n\n <div class=\"checkbox-block\">\n <input type=\"checkbox\" name=\"custom_model_request[selected_checkboxes[animated]]\" id=\"animated_request\" value=true class=\"checkbox is-spaced\">\n <label class=\"col-form-label col-form-label-sm\" for=\"animated_request\">Animated</label>\n </div>\n\n <div class=\"checkbox-block\">\n <input type=\"checkbox\" name=\"custom_model_request[selected_checkboxes[pbr]]\" id=\"pbr_request\" value=true class=\"checkbox is-spaced\">\n <label class=\"col-form-label col-form-label-sm\" for=\"pbr_request\">PBR</label>\n </div>\n\n <div class=\"checkbox-block\">\n <input type=\"checkbox\" name=\"custom_model_request[selected_checkboxes[rigged]]\" id=\"rigged_request\" value=true class=\"checkbox is-spaced\">\n <label class=\"col-form-label col-form-label-sm\" for=\"rigged_request\">Rigged</label>\n </div>\n\n <div class=\"checkbox-block\">\n <input type=\"checkbox\" name=\"custom_model_request[selected_checkboxes[
64146collection]]\" id=\"collection_request\" value=true class=\"checkbox is-spaced\">\n <label class=\"col-form-label col-form-label-sm\" for=\"collection_request\">Collection</label>\n </div>\n </div>\n </div>\n\n <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\" for=\"details\">Details</label>\n <div class=\"col-12 col-md-8\">\n <textarea id=\"details\" class=\"form-control form-control-sm\" name=\"custom_model_request[details]\" rows=\"5\" />\n </div>\n </div>\n\n <div class=\"form-group row\">\n <label class=\"col-12 col-md-4 col-form-label col-form-label-sm\" for=\"deadline\">Latest date you need the model on</label>\n <div class=\"col-12 col-md-8\">\n <input id=\"deadline\" class=\"form-control form-control-sm js-deadline-field\" name=\"custom_model_request[deadline]\">\n </div>\n </div>\n\n" 64147 + ((stack1 = lookupProperty(helpers,"unless").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"signedIn") : depth0),{"name":"unless","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":118,"column":8},"end":{"line":125,"column":19}}})) != null ? stack1 : "") 64148 + "\n <div class=\"row\">\n <div class=\"col-12 col-md-3 offset-md-4\">\n <button class=\"btn btn-primary btn-block\" type=\"submit\">Submit</button>\n </div>\n </div>\n </form>\n </div>\n\n <div class=\"modal-light__success-screen js-success-screen is-hidden\">\n <p>Your request was submitted successfully! Our team will get in touch with you shortly.</p>\n </div>\n </div>\n</div>"; 64149},"useData":true}); 64150 return this.JST["modals/custom_item_request_modal"]; 64151}).call(this); 64152(function() { 64153 this.JST || (this.JST = {}); 64154 this.JST["payment_agreement/notification_bar"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64155 return "<div class=\"notice is-secondary-color\">\n In order to get your next payment, please update required information in CGTrader agreement\n <a href=\"/profile/payment_agreements\" class=\"btn btn-white btn-sm\">Here</a>\n</div>"; 64156},"useData":true}); 64157 return this.JST["payment_agreement/notification_bar"]; 64158}).call(this); 64159(function() { 64160 this.JST || (this.JST = {}); 64161 this.JST["search_suggestion"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64162 var stack1, helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64163 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64164 return parent[propertyName]; 64165 } 64166 return undefined 64167 }; 64168 64169 return "<span class=\"site-search-suggestions__col-suggestion\">\n <a href=\"/search?" 64170 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"params") || (depth0 != null ? lookupProperty(depth0,"params") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"params","hash":{},"data":data,"loc":{"start":{"line":2,"column":19},"end":{"line":2,"column":29}}}) : helper))) 64171 + "&suggested=1\" class=\"js-suggestion-keyword\" data-keyword=\"" 64172 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"suggestion") || (depth0 != null ? lookupProperty(depth0,"suggestion") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"suggestion","hash":{},"data":data,"loc":{"start":{"line":2,"column":87},"end":{"line":2,"column":101}}}) : helper))) 64173 + "\" id=\"suggestion_" 64174 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"suggestion_id") || (depth0 != null ? lookupProperty(depth0,"suggestion_id") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}
64174),{"name":"suggestion_id","hash":{},"data":data,"loc":{"start":{"line":2,"column":118},"end":{"line":2,"column":135}}}) : helper))) 64175 + "\">\n <img src=\"" 64176 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"thumbnailUrl") || (depth0 != null ? lookupProperty(depth0,"thumbnailUrl") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"thumbnailUrl","hash":{},"data":data,"loc":{"start":{"line":3,"column":14},"end":{"line":3,"column":30}}}) : helper))) 64177 + "\" alt=\"\">\n " 64178 + ((stack1 = ((helper = (helper = lookupProperty(helpers,"suggestionHtml") || (depth0 != null ? lookupProperty(depth0,"suggestionHtml") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"suggestionHtml","hash":{},"data":data,"loc":{"start":{"line":4,"column":6},"end":{"line":4,"column":26}}}) : helper))) != null ? stack1 : "") 64179 + "\n </a>\n</span>"; 64180},"useData":true}); 64181 return this.JST["search_suggestion"]; 64182}).call(this); 64183(function() { 64184 this.JST || (this.JST = {}); 64185 this.JST["support/notification_bar"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64186 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64187 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64188 return parent[propertyName]; 64189 } 64190 return undefined 64191 }; 64192 64193 return "<div class=\"site-admin-control-warning\">\n <div class=\"container-fixed\">\n <div class=\"u-float-left\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n Under <a href=\"/" 64194 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"username") || (depth0 != null ? lookupProperty(depth0,"username") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"username","hash":{},"data":data,"loc":{"start":{"line":5,"column":28},"end":{"line":5,"column":40}}}) : helper))) 64195 + "\">" 64196 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"username") || (depth0 != null ? lookupProperty(depth0,"username") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"username","hash":{},"data":data,"loc":{"start":{"line":5,"column":42},"end":{"line":5,"column":54}}}) : helper))) 64197 + "</a> support.\n </div>\n <div class=\"u-float-right\">\n <a href=\"/stop_impersonating\">\n <i class=\"fas fa-unlock-alt fa-lg\"></i> End support session\n </a>\n </div>\n </div>\n</div>"; 64198},"useData":true}); 64199 return this.JST["support/notification_bar"]; 64200}).call(this); 64201(function() { 64202 this.JST || (this.JST = {}); 64203 this.JST["tip_for_designer/notification_bar"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64204 var helper, lookupProperty = container.lookupProperty || function(parent, propertyName) { 64205 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64206 return parent[propertyName]; 64207 } 64208 return undefined 64209 }; 64210 64211 return "<div class=\"notice\">\n <div class=\"notice-content\">\n <span class=\"close-notice js-tip-close\">\n <i class=\"fal fa-times is-not-spaced\" />\n </span>\n " 64212 + container.escapeExpression(((helper = (helper = lookupProperty(helpers,"body") || (depth0 != null ? lookupProperty(depth0,"body") : depth0)) != null ? helper : container.hooks.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"body","hash":{},"data":data,"loc":{"start":{"line":6,"column":8},"end":{"line":6,"column":16}}}) : helper))) 64213 + "\n </div>\n</div>"; 64214},"useData":true}); 64215 return this.JST["tip_for_designer/notification_bar"]; 64216}).call(this); 64217(function() { 64218 this.JST || (this.JST = {}); 64219 this.JST["translations_notice/notification_bar"] = Handlebars.template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { 64220 var lookupProperty = container.lookupProperty || function(parent, propertyName) { 64221 if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { 64222 return parent[propertyName]; 64223 } 64224 return undefined 64225 }; 64226 64227 return "<div class=\"notice notice-float notice-light notice-translation\">\n <span class=\"close-notice\">\n <i class=\"fal fa-times is-not-spaced\"/>\n </span>\n <div class=\"notice-content\">\n " 64228 + container.escapeExpression((lookupProperty(helpers,"I18n")||(
64228depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"layout.translations_notice.text",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":6,"column":4},"end":{"line":6,"column":46}}})) 64229 + "\n <a href=\"\">" 64230 + container.escapeExpression((lookupProperty(helpers,"I18n")||(depth0 && lookupProperty(depth0,"I18n"))||container.hooks.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}),"layout.translations_notice.cta",{"name":"I18n","hash":{},"data":data,"loc":{"start":{"line":7,"column":15},"end":{"line":7,"column":56}}})) 64231 + " ðºð¸</a>\n </div>\n</div>"; 64232},"useData":true}); 64233 return this.JST["translations_notice/notification_bar"]; 64234}).call(this); 64235(function() { 64236 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64237 hasProp = {}.hasOwnProperty; 64238 64239 App.Backbone.Views.Carousel = (function(superClass) { 64240 extend(Carousel, superClass); 64241 64242 function Carousel() { 64243 return Carousel.__super__.constructor.apply(this, arguments); 64244 } 64245 64246 Carousel.prototype.events = { 64247 'click .js-carousel-trigger': 'handleCarouselClick' 64248 }; 64249 64250 Carousel.prototype.states = { 64251 active: 'is-active', 64252 hidden: 'is-hidden', 64253 loaded: 'is-loaded' 64254 }; 64255 64256 Carousel.prototype.initialize = function(options) { 64257 this.el = options.el; 64258 this.$trigger = options.$trigger; 64259 this.$tooltipster = options.$tooltipster; 64260 this.current = 0; 64261 _.bindAll(this, 'reset'); 64262 this.render(); 64263 this.cacheUI(); 64264 this.bindTooltipsterReposition(); 64265 this.activate(this.current); 64266 this.subscribe(); 64267 return this; 64268 }; 64269 64270 Carousel.prototype.subscribe = function() { 64271 if (!this.$trigger) { 64272 return; 64273 } 64274 return this.$trigger.on('click', _.bind(this.handleCarouselClick, this)); 64275 }; 64276 64277 Carousel.prototype.unsubscribe = function() { 64278 if (!this.$trigger) { 64279 return; 64280 } 64281 return this.$trigger.off('click', _.bind(this.handleCarouselClick, this)); 64282 }; 64283 64284 Carousel.prototype.render = function() { 64285 var $container, figcaption, images, itemTitle, items, loaderClasses; 64286 $container = this.$el.find('.js-carousel-items'); 64287 itemTitle = this.$el.find('.content-box__content').data('name'); 64288 figcaption = "<figcaption class='content-box__title'>" + itemTitle + "</figcaption>"; 64289 items = $container.data('images'); 64290 this.$el.find('.content-box__price').removeClass('title-is-hidden').addClass('discount-is-visible'); 64291 if (!(items && items.length)) { 64292 return this; 64293 } 64294 loaderClasses = 'is-loading is-loading-image js-carousel-slide'; 64295 images = _.map(items, function(item) { 64296 return $('<img>').attr({ 64297 src: '', 64298 alt: '', 64299 'data-src': item 64300 }).addClass(loaderClasses)[0].outerHTML; 64301 }); 64302 $container.html(images.join()); 64303 $container.append(figcaption); 64304 return this; 64305 }; 64306 64307 Carousel.prototype.cacheUI = function() { 64308 return this.$items = this.$el.find('.js-carousel-slide'); 64309 }; 64310 64311 Carousel.prototype.bindTooltipsterReposition = function() { 64312 return _.forEach(this.$items, (function(_this) { 64313 return function(item) { 64314 return $(item).load(function() { 64315 if (_this.$tooltipster.hasClass('tooltipstered')) { 64316 return _this.$tooltipster.tooltipster('reposition'); 64317 } 64318 }); 64319 }; 64320 })(this)); 64321 }; 64322 64323 Carousel.prototype.findNext = function(offset, direction) { 64324 var movement, next; 64325 movement = direction === 'prev' ? -1 : 1; 64326 next = offset + movement; 64327 if (next < 0) { 64328 next = this.$items.length - 1; 64329 } else if (next >= this.$items.length) { 64330 next = 0; 64331 } 64332 return next; 64333 }; 64334 64335 Carousel.prototype.move = function(direction) { 64336 var next; 64337 next = this.findNext(this.current, direction); 64338 return this.activate(next, direction); 64339 }; 64340 64341 Carousel.prototype.activate = function(item, direction) { 64342 var after_next, next, previous; 64343 this.$items.removeClass(this.states.active).addClass(this.states.hidden); 64344 this.$items.eq(item).removeClass(this.states.hidden).addClass(this.states.active); 64345 this.current = item; 64346 if (direction == null) { 64347 return; 64348 } 64349 next = this.findNext(this.current, direction); 64350 this.preload(next); 64351 after_next = this.findNext(next, direction); 64352 this.preload(after_next); 64353 previous = this.findNext(this.current, this.oppositeDirection(direction)); 64354 return this.preload(previous); 64355 }; 64356 64357 Carousel.prototype.preload = function(item) { 64358 var $item, img, imgLoad; 64359 $item = this.$items.eq(item); 64360 if ($item.hasClass(this.states.loaded)) { 64361 return; 64362 } 64363 img = new Image(); 64364 img.src = $item.data('src'); 64365 imgLoad = imagesLoaded(img); 64366 return imgLoad.on('done', (function(_this) { 64367 return function() { 64368 return $item.attr('src', img.src).removeClass('is-loading is-loading-image').addClass(_this.states.loaded); 64369 }; 64370 })(this)); 64371 }; 64372 64373 Carousel.prototype.remove = function() { 64374 this.stopListening(); 64375 this.unsubscribe(); 64376 return this.$el.remove(); 64377 }; 64378 64379 Carousel.prototype.reset = function(origin, callback) { 64380 this.preload(0); 64381 this.activate(0, 'next'); 64382 if (callback != null) { 64383 return callback(); 64384 } 64385 }; 64386 64387 Carousel.prototype.handleCarouselClick = function(event) { 64388 var direction; 64389 direction = $(event.currentTarget).data('direction'); 64390 return this.move(direction); 64391 }; 64392 64393 Carousel.prototype.oppositeDirection = function(direction) { 64394 if (direction === 'prev') { 64395 return 'next'; 64396 } else { 64397 return 'prev'; 64398 } 64399 }; 64400 64401 return Carousel; 64402 64403 })(Backbone.View); 64404 64405}).call(this); 64406(function() { 64407 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64408 hasProp = {}.hasOwnProperty; 64409 64410 App.Backbone.Views.ChosenView = (function(superClass) { 64411 extend(ChosenView, superClass); 64412 64413 ChosenView.prototype.template = JST["chosen"]; 64414 64415 function ChosenView(options) { 64416 this.viewOptions = { 64417 id: options.id, 64418 placeholder: options.placeholder, 64419 onChange: options.onChange, 64420 required: options.required, 64421 multiple: options.multiple, 64422 name: (options.name != null ? options.name : options.id), 64423 allow_single_deselect: ((options.multiple == null) && (options.allow_single_deselect != null) ? true : false) 64424 }; 64425 ChosenView.__super__.constructor.apply(this, arguments); 64426 } 64427 64428 ChosenView.prototype.render = function(options) { 64429 var ref, select; 64430 this.viewOptions.value = options.value; 64431 this.viewOptions.selectOptions = options.collection; 64432 $(this.el).find('select').chosen('destroy'); 64433 $(this.el).html(this.template(this.viewOptions)); 64434 select = $(this.el).find('select'); 64435 select.val(this.viewOptions.value); 64436 if (this.viewOptions.required) { 64437 select.attr('required', 'required'); 64438 } 64439 select.chosen({ 64440 width: (ref = this.viewOptions.width) != null ? ref : '100px', 64441 value: this.viewOptions.value, 64442 disable_search_threshold: 10, 64443 placeholder: this.viewOptions.placeholder, 64444 allow_single_deselect: this.viewOptions.allow_single_deselect 64445 }).change(this.viewOptions.onChange); 64446 return this; 64447 }; 64448 64449 return ChosenView; 64450 64451 })(Backbone.View); 64452 64453}).call(this); 64454(function() { 64455 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 64456 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64457 hasProp = {}.hasOwnProperty; 64458 64459 App.Backbone.Views.Comments.Form = (function(superClass) { 64460 extend(Form, superClass); 64461 64462 function Form() { 64463 this.onSubmit = bind(this.onSubmit, this); 64464 return Form.__super__.constructor.apply(this, arguments); 64465 } 64466 64467 Form.prototype.template = JST["comments/form"]; 64468 64469 Form.prototype.attributes = { 64470 "class": 'comment-form-container' 64471 }; 64472 64473 Form.prototype.events = { 64474 'submit': 'onThrottledSubmit' 64475 }; 64476 64477 Form.prototype.initialize = function() { 64478 return this.onThrottledSubmit = _.throttle(this.onSubmit, 1500); 64479 }; 64480 64481 Form.prototype.render = function() { 64482 var renderData; 64483 renderData = this.model.toJSON(); 64484 renderData.author = { 64485 username: App.config.username, 64486 avatar_url: App.config.userAvatarUrl || '/assets/avatar/small_avatar.png' 64487 }; 64488 $(this.el).html(this.template(renderData)); 64489 Backbone.Syphon.deserialize(this, this.model.toJSON()); 64490 return this; 64491 }; 64492 64493 Form.prototype.onSubmit = function(e) { 64494 var $button; 64495 e.preventDefault(); 64496 e.stopPropagation(); 64497 $button = $(this.el).find('.js-comment-submit'); 64498 if (!App.config.userSignedIn) { 64499 return; 64500 } 64501 if ($button.hasClass('is-disabled')) { 64502 return; 64503 } 64504 $button.attr('disabled', true).addClass('is-disabled');
64505 this.model.set(Backbone.Syphon.serialize(this)); 64506 return this.model.save({}, { 64507 success: (function(_this) { 64508 return function(model, response) { 64509 $button.removeAttr('disabled').removeClass('is-disabled'); 64510 App.events.publish('app:comment:posted'); 64511 _this.model.set({ 64512 content: '' 64513 }); 64514 Backbone.Syphon.deserialize(_this, _this.model.toJSON()); 64515 $(_this.el).fadeOut(); 64516 return location.reload(); 64517 }; 64518 })(this), 64519 error: function(model, response) { 64520 $button.removeAttr('disabled').removeClass('is-disabled'); 64521 return App.events.publish('app:notification:flash:error', response.responseJSON['errors'][0]['detail']); 64522 } 64523 }); 64524 }; 64525 64526 return Form; 64527 64528 })(Backbone.View); 64529 64530}).call(this); 64531(function() { 64532 var ref, 64533 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64534 hasProp = {}.hasOwnProperty; 64535 64536 if ((ref = App.Backbone) != null) { 64537 ref.Views || (ref.Views = {}); 64538 } 64539 64540 App.Backbone.Views.SearchSuggestionViewV2 = (function(superClass) { 64541 extend(SearchSuggestionViewV2, superClass); 64542 64543 function SearchSuggestionViewV2() { 64544 return SearchSuggestionViewV2.__super__.constructor.apply(this, arguments); 64545 } 64546 64547 SearchSuggestionViewV2.prototype.template = JST['search_suggestion']; 64548 64549 SearchSuggestionViewV2.prototype.tagName = 'li'; 64550 64551 SearchSuggestionViewV2.prototype.events = { 64552 'mouseenter .js-suggestion-keyword': 'onKeywordHover', 64553 'mouseleave .js-suggestion-keyword': 'onKeywordHoverOut', 64554 'click .js-suggestion-keyword': 'onSearchSuggestionClick' 64555 }; 64556 64557 SearchSuggestionViewV2.prototype.initialize = function(options) { 64558 this.options = options; 64559 }; 64560 64561 SearchSuggestionViewV2.prototype.serialize = function() { 64562 return { 64563 suggestion: this.options.data.suggestion, 64564 suggestionHtml: this.options.data.suggestionHtml, 64565 suggestion_id: this.options.data.suggestion.replace(/[^a-z0-9]/gi, '_'), 64566 total: this.options.data.total, 64567 thumbnailUrl: this.options.data.thumbnailUrl, 64568 params: $.param({ 64569 keywords: this.options.data.suggestion 64570 }) 64571 }; 64572 }; 64573 64574 SearchSuggestionViewV2.prototype.render = function() { 64575 this.$el.html(this.template(this.serialize())); 64576 return this; 64577 }; 64578 64579 SearchSuggestionViewV2.prototype.onSearchSuggestionClick = function(event) { 64580 var $link; 64581 event.preventDefault(); 64582 $link = $(event.currentTarget); 64583 if (App.Backbone.Routers.ItemsSearch.instance) { 64584 App.Backbone.Routers.ItemsSearch.instance.applyFilter('keywords', $link.data('keyword')); 64585 return App.events.publish('browser:filters:changed'); 64586 } else { 64587 return window.location = $link.attr('href'); 64588 } 64589 }; 64590 64591 return SearchSuggestionViewV2; 64592 64593 })(Backbone.View); 64594 64595}).call(this); 64596(function() { 64597 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64598 hasProp = {}.hasOwnProperty; 64599 64600 App.Backbone.Models.Comment = (function(superClass) { 64601 extend(Comment, superClass); 64602 64603 function Comment() { 64604 return Comment.__super__.constructor.apply(this, arguments); 64605 } 64606 64607 Comment.prototype.urlRoot = '/api/internal/comments'; 64608 64609 return Comment; 64610 64611 })(Backbone.Model); 64612 64613 App.Backbone.Collections.CommentsCollection = (function(superClass) { 64614 extend(CommentsCollection, superClass); 64615 64616 function CommentsCollection() { 64617 return CommentsCollection.__super__.constructor.apply(this, arguments); 64618 } 64619 64620 CommentsCollection.prototype.url = '/api/internal/comments'; 64621 64622 CommentsCollection.prototype.model = App.Backbone.Models.Comment; 64623 64624 return CommentsCollection; 64625 64626 })(Backbone.Collection); 64627 64628}).call(this); 64629(function() { 64630 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64631 hasProp = {}.hasOwnProperty; 64632 64633 App.Backbone.Models.Conversation = (function(superClass) { 64634 extend(Conversation, superClass); 64635 64636 function Conversation() { 64637 return Conversation.__super__.constructor.apply(this, arguments); 64638 } 64639 64640 Conversation.prototype.urlRoot = '/api/internal/conversations'; 64641 64642 return Conversation; 64643 64644 })(Backbone.Model); 64645 64646 App.Backbone.Models.ItemPriceOffer = (function(superClass) { 64647 extend(ItemPriceOffer, superClass); 64648 64649 function ItemPriceOffer() { 64650 return ItemPriceOffer.__super__.constructor.apply(this, arguments); 64651 } 64652 64653 ItemPriceOffer.prototype.urlRoot = '/api/internal/price_offers'; 64654 64655 return ItemPriceOffer; 64656 64657 })(Backbone.Model); 64658 64659}).call(this); 64660(function() { 64661 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64662 hasProp = {}.hasOwnProperty; 64663 64664 App.Backbone.Models.FileConversionRequest = (function(superClass) { 64665 extend(FileConversionRequest, superClass); 64666 64667 function FileConversionRequest() { 64668 return FileConversionRequest.__super__.constructor.apply(this, arguments); 64669 } 64670 64671 FileConversionRequest.prototype.url = '/file_conversions'; 64672 64673 return FileConversionRequest; 64674 64675 })(Backbone.Model); 64676 64677}).call(this); 64678(function() { 64679 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64680 hasProp = {}.hasOwnProperty; 64681 64682 App.Backbone.Models.FileExtension = (function(superClass) { 64683 extend(FileExtension, superClass); 64684 64685 function FileExtension() { 64686 return FileExtension.__super__.constructor.apply(this, arguments); 64687 } 64688 64689 return FileExtension; 64690 64691 })(Backbone.Model); 64692 64693 App.Backbone.Collections.FileExtensionsCollection = (function(superClass) { 64694 extend(FileExtensionsCollection, superClass); 64695 64696 function FileExtensionsCollection() { 64697 return FileExtensionsCollection.__super__.constructor.apply(this, arguments); 64698 } 64699 64700 FileExtensionsCollection.prototype.model = App.Backbone.Models.FileExtension; 64701 64702 FileExtensionsCollection.prototype.url = function() { 64703 return "/file_conversions/available_extensions"; 64704 }; 64705 64706 FileExtensionsCollection.prototype.toSelectData = function(options) { 64707 var result; 64708 result = this.map(function(model) { 64709 return { 64710 id: model.get('id'), 64711 text: model.get('file_extension') 64712 }; 64713 }); 64714 if (options.includeOther) { 64715 result.push({ 64716 id: 0, 64717 text: 'Other' 64718 }); 64719 } 64720 if (options.includeBlank) { 64721 result = [['', '']].concat(result); 64722 } 64723 return result; 64724 }; 64725 64726 return FileExtensionsCollection; 64727 64728 })(Backbone.Collection); 64729 64730}).call(this); 64731(function() { 64732 var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, 64733 extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64734 hasProp = {}.hasOwnProperty; 64735 64736 App.Backbone.Models.FileType = (function(superClass) { 64737 extend(FileType, superClass); 64738 64739 function FileType() { 64740 this.initialize = bind(this.initialize, this); 64741 return FileType.__super__.constructor.apply(this, arguments); 64742 } 64743 64744 FileType.prototype.initialize = function() { 64745 this.renderers = new App.Backbone.Collections.RenderersCollection(this.attributes.renderers); 64746 return delete this.attributes.renderers; 64747 }; 64748 64749 return FileType; 64750 64751 })(Backbone.Model); 64752 64753 App.Backbone.Collections.FileTypesCollection = (function(superClass) { 64754 extend(FileTypesCollection, superClass); 64755 64756 function FileTypesCollection() { 64757 return FileTypesCollection.__super__.constructor.apply(this, arguments); 64758 } 64759 64760 FileTypesCollection.prototype.model = App.Backbone.Models.FileType; 64761 64762 FileTypesCollection.prototype.toSelectData = function() { 64763 return this.map(function(model) { 64764 return { 64765 id: model.get('id'), 64766 text: model.get('title') 64767 }; 64768 }); 64769 }; 64770 64771 return FileTypesCollection; 64772 64773 })(Backbone.Collection); 64774 64775}).call(this); 64776(function() { 64777 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64778 hasProp = {}.hasOwnProperty; 64779 64780 App.Backbone.Models.Format = (function(superClass) { 64781 extend(Format, superClass); 64782 64783 function Format() { 64784 return Format.__super__.constructor.apply(this, arguments); 64785 } 64786 64787 return Format; 64788 64789 })(Backbone.Model); 64790 64791 App.Backbone.Collections.FormatsCollection = (function(superClass) { 64792 extend(FormatsCollection, superClass); 64793 64794 function FormatsCollection() { 64795 return FormatsCollection.__super__.constructor.apply(this, arguments); 64796 } 64797 64798 FormatsCollection.prototype.model = App.Backbone.Models.Format; 64799 64800 FormatsCollection.prototype.findById = function(formatId) { 64801 return this.detect(function(format) { 64802 return format.id === formatId; 64803 }); 64804 }; 64805 64806 FormatsCollection.prototype.findByFileExtensions = function(fileExtensions) { 64807 return this.detect(function(format) { 64808 return _.difference(fileExtensions, format.get('formats')).length === 0; 64809 }); 64810 }; 64811 64812 FormatsCollection.prototype.subtract = function(otherCollection) { 64813 var subtractArray; 64814 subtractArray = this.select(function(format) { 64815 return otherCollection.findById(format.id) == null; 64816 }); 64817 return new App.Backbone.Collections.FormatsCollection(subtractArray); 64818 }; 64819 64820 FormatsCollection.prototype.toSelectData = function() { 64821 return this.map(function(model) { 64822 return { 64823 id: model.get('id'), 64824 text: model.get('name') 64825 }; 64826 }); 64827 }; 64828 64829 return FormatsCollection; 64830 64831 })(Backbone.Collection); 64832 64833}).call(this); 64834(function() { 64835 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64836 hasProp = {}.hasOwnProperty; 64837 64838 App.Backbone.Models.PrinterType = (function(superClass) { 64839 extend(PrinterType, superClass); 64840 64841 function PrinterType() { 64842 return PrinterType.__super__.constructor.apply(this, arguments); 64843 } 64844 64845 return PrinterType; 64846 64847 })(Backbone.Model); 64848 64849 App.Backbone.Collections.PrinterTypesCollection = (function(superClass) { 64850 extend(PrinterTypesCollection, superClass); 64851 64852 function PrinterTypesCollection() { 64853 return PrinterTypesCollection.__super__.constructor.apply(this, arguments); 64854 } 64855 64856 PrinterTypesCollection.prototype.model = App.Backbone.Models.PrinterType; 64857 64858 PrinterTypesCollection.prototype.toSelectData = function() { 64859 return this.map(function(model) { 64860 return { 64861 id: model.get('id'), 64862 text: (model.get('manufacturer')) + " - " + (model.get('name')) 64863 }; 64864 }); 64865 }; 64866 64867 return PrinterTypesCollection; 64868 64869 })(Backbone.Collection); 64870 64871}).call(this); 64872(function() { 64873 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64874 hasProp = {}.hasOwnProperty; 64875 64876 App.Backbone.Models.Software = (function(superClass) { 64877 extend(Software, superClass); 64878 64879 function Software() { 64880 return Software.__super__.constructor.apply(this, arguments); 64881 } 64882 64883 return Software; 64884 64885 })(Backbone.Model); 64886 64887 App.Backbone.Collections.SoftwareCollection = (function(superClass) { 64888 extend(SoftwareCollection, superClass); 64889 64890 function SoftwareCollection() { 64891 return SoftwareCollection.__super__.constructor.apply(this, arguments); 64892 } 64893
64894 SoftwareCollection.prototype.model = App.Backbone.Models.Software; 64895 64896 SoftwareCollection.prototype.url = function() { 64897 return "/file_conversions/available_software"; 64898 }; 64899 64900 SoftwareCollection.prototype.toSelectData = function(options) { 64901 var result; 64902 result = this.map(function(model) { 64903 return { 64904 id: model.get('id'), 64905 text: model.get('title') 64906 }; 64907 }); 64908 if (options.includeOther) { 64909 result.push({ 64910 id: 0, 64911 text: 'Other' 64912 }); 64913 } 64914 if (options.includeBlank) { 64915 result = [['', '']].concat(result); 64916 } 64917 return result; 64918 }; 64919 64920 return SoftwareCollection; 64921 64922 })(Backbone.Collection); 64923 64924}).call(this); 64925(function() { 64926 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64927 hasProp = {}.hasOwnProperty; 64928 64929 App.Backbone.Models.User = (function(superClass) { 64930 extend(User, superClass); 64931 64932 function User() { 64933 return User.__super__.constructor.apply(this, arguments); 64934 } 64935 64936 return User; 64937 64938 })(Backbone.Model); 64939 64940}).call(this); 64941(function() { 64942 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64943 hasProp = {}.hasOwnProperty; 64944 64945 App.Backbone.Models.WishList = (function(superClass) { 64946 extend(WishList, superClass); 64947 64948 function WishList() { 64949 return WishList.__super__.constructor.apply(this, arguments); 64950 } 64951 64952 return WishList; 64953 64954 })(Backbone.Model); 64955 64956 App.Backbone.Collections.WishListsCollection = (function(superClass) { 64957 extend(WishListsCollection, superClass); 64958 64959 function WishListsCollection() { 64960 return WishListsCollection.__super__.constructor.apply(this, arguments); 64961 } 64962 64963 WishListsCollection.prototype.model = App.Backbone.Models.WishList; 64964 64965 WishListsCollection.prototype.url = '/api/internal/wish-lists'; 64966 64967 WishListsCollection.prototype.parse = function(response) { 64968 return response.data; 64969 }; 64970 64971 return WishListsCollection; 64972 64973 })(Backbone.Collection); 64974 64975}).call(this); 64976(function() { 64977 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 64978 hasProp = {}.hasOwnProperty; 64979 64980 App.Backbone.Models.WishListItem = (function(superClass) { 64981 extend(WishListItem, superClass); 64982 64983 function WishListItem() { 64984 return WishListItem.__super__.constructor.apply(this, arguments); 64985 } 64986 64987 WishListItem.prototype.url = function() { 64988 if (this.id != null) { 64989 return "/api/internal/wish-lists/" + this.attributes.data.attributes.wish_list_id + "/items/" + this.id; 64990 } else { 64991 return "/api/internal/wish-lists/" + this.attributes.data.attributes.wish_list_id + "/items"; 64992 } 64993 }; 64994 64995 return WishListItem; 64996 64997 })(Backbone.Model); 64998 64999}).call(this); 65000(function() { 65001 var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 65002 hasProp = {}.hasOwnProperty; 65003 65004 App.Backbone.Routers.ItemsSearch = (function(superClass) { 65005 extend(ItemsSearch, superClass); 65006 65007 function ItemsSearch() { 65008 return ItemsSearch.__super__.constructor.apply(this, arguments); 65009 } 65010 65011 ItemsSearch.prototype.urlBuilder = null; 65012 65013 ItemsSearch.prototype.skipLoading = true; 65014 65015 ItemsSearch.prototype.routes = { 65016 '': 'backToRoot', 65017 '*any': 'index' 65018 }; 65019 65020 ItemsSearch.prototype.initialize = function(options) { 65021 this.urlBuilder = new ItemsSearchUrlBuilder; 65022 this.dedicateFileTypeFragments = options.dedicateFileTypeFragments; 65023 return App.Backbone.Routers.ItemsSearch.instance = this; 65024 }; 65025 65026 ItemsSearch.prototype.backToRoot = function() { 65027 return window.location = '/'; 65028 }; 65029 65030 ItemsSearch.prototype.index = function() { 65031 if (this.skipLoading) { 65032 this.skipLoading = false;
65033 this.initUI(); 65034 return; 65035 } 65036 return this.fetchItems(function() { 65037 if ($(window).scrollTop() > 400) { 65038 return $('body').clearQueue().scrollTo('#focus-marker', { 65039 duration: 600, 65040 offset: -120, 65041 easing: 'easeInOutCirc' 65042 }); 65043 } 65044 }); 65045 }; 65046 65047 ItemsSearch.prototype.configureUrlBuilder = function() { 65048 this.urlBuilder.set(window.location); 65049 this.urlBuilder.setExtraSource({ 65050 file_types: JSON.parse($('#active_file_types').val()) 65051 }); 65052 this.urlBuilder.setDedicateFileTypeFragments(this.dedicateFileTypeFragments); 65053 return this.urlBuilder.setProductType(App.config.currentProductType); 65054 }; 65055 65056 ItemsSearch.prototype.applyFilter = function(key, value, options) { 65057 var newUrl; 65058 if (options == null) { 65059 options = {}; 65060 } 65061 this.configureUrlBuilder(); 65062 newUrl = this.urlBuilder.applyFilter(key, value); 65063 if (options.reload) { 65064 return window.location = newUrl; 65065 } else { 65066 return this.navigate(newUrl, { 65067 trigger: true 65068 }); 65069 } 65070 }; 65071 65072 ItemsSearch.prototype.removeFilter = function(key, subValue) { 65073 var newUrl, oldUrl; 65074 if (subValue == null) { 65075 subValue = null; 65076 } 65077 this.configureUrlBuilder(); 65078 newUrl = this.urlBuilder.removeFilter(key, subValue); 65079 oldUrl = "" + window.location.pathname + window.location.search; 65080 this.navigate(newUrl, { 65081 trigger: true 65082 }); 65083 if (newUrl === oldUrl) { 65084 return this.index(); 65085 } 65086 }; 65087 65088 ItemsSearch.prototype.navigateToCategory = function(newLocation) { 65089 this.configureUrlBuilder(); 65090 this.urlBuilder.set({ 65091 pathname: newLocation, 65092 search: window.location.search 65093 }); 65094 return this.navigate(this.urlBuilder.build(), { 65095 trigger: true 65096 }); 65097 }; 65098 65099 ItemsSearch.prototype.fetchItems = function(callback) { 65100 var ref; 65101 $('.content-box-wrapper').addClass('is-updating-with-spinner spinner--top is-fixed'); 65102 if ((ref = this.currentRequest) != null) { 65103 ref.abort(); 65104 } 65105 return this.currentRequest = $.getScript("" + window.location.pathname + window.location.search, (function(_this) { 65106 return function() { 65107 _this.updateUI(); 65108 return typeof callback === "function" ? callback() : void 0; 65109 }; 65110 })(this)); 65111 }; 65112 65113 ItemsSearch.prototype.initUI = function() { 65114 App.events.publish('app:ui:refresh', $('.js-filter-block-container')); 65115 App.events.publish('items:init-price-range-filter', $('#price_range')); 65116 App.events.publish('items:init-sticky-filters-block', $('.js-sticky')); 65117 return App.events.publish('items:init-license-filter-tooltip', $('.js-license-filter-tooltip')); 65118 }; 65119 65120 ItemsSearch.prototype.updateUI = function() { 65121 this.initUI(); 65122 return App.events.publish('app:product:bind', $('#products-list .content-box')); 65123 }; 65124 65125 return ItemsSearch; 65126 65127 })(Backbone.Router); 65128 65129}).call(this); 65130(function() { 65131 var base; 65132 65133 if ((base = $.fn).loadDynamicIframe == null) { 65134 base.loadDynamicIframe = function() { 65135 return this.each(function(index, el) { 65136 var src; 65137 src = $(el).data('src'); 65138 if (el.src !== src) { 65139 return el.src = src; 65140 } 65141 }); 65142 }; 65143 } 65144 65145}).call(this); 65146(function() { 65147 if (window.mute == null) { 65148 window.mute = function(event) { 65149 return (event != null ? event.preventDefault() : void 0) && (event != null ? event.stopPropagation() : void 0); 65150 }; 65151 } 65152 65153}).call(this); 65154(function() { 65155 var base; 65156 65157 if ((base = $.fn).renderFormErrors == null) { 65158 base.renderFormErrors = function(errors) { 65159 var attribute, el, error, id, input, missingAttributeErrors; 65160 if (!this.is('form')) { 65161 throw 'Can\'t render errors. Use appropriate DOM element.'; 65162 } 65163 id = this.attr('id'); 65164 missingAttributeErrors = []; 65165 this.find('label.error.error-manually-added').remove(); 65166 for (attribute in errors) { 65167 error = errors[attribute]; 65168 if (attribute === 'custom_errors') { 65169 continue; 65170 } 65171 input = this.find("#" + id + "-" + attribute); 65172 if (input[0]) { 65173 el = "<label class='error error-manually-added u-text-justify u-block' for='" + id + "-" + attribute + "'>" + error + "</label>"; 65174 input.parent().append(el); 65175 } else { 65176 if (errors.custom_errors && errors.custom_errors[attribute]) { 65177 missingAttributeErrors.push(errors.custom_errors[attribute]); 65178 } 65179 } 65180 } 65181 if (missingAttributeErrors[0]) { 65182 App.events.publish("app:notification:flash:error", missingAttributeErrors.join(' ')); 65183 } 65184 return true; 65185 }; 65186 } 65187 65188}).call(this); 65189(function() { 65190 if (window.guid == null) { 65191 window.guid = function() { 65192 var s4; 65193 s4 = function() { 65194 return Math.floor((1 + Math.random(new Date().getTime())) * 0x10000).toString(16).substring(1); 65195 }; 65196 return s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4(); 65197 }; 65198 } 65199 65200}).call(this); 65201(function() { 65202 var base; 65203 65204 if ((base = $.fn).hideOnOutsideClick == null) { 65205 base.hideOnOutsideClick = function(hideFunction) { 65206 return $(document).mouseup((function(_this) { 65207 return function(e) { 65208 if (!_this.is(e.target) && _this.has(e.target).length === 0) { 65209 return typeof hideFunction === "function" ? hideFunction(e) : void 0; 65210 } 65211 }; 65212 })(this)); 65213 }; 65214 } 65215 65216}).call(this); 65217(function() { 65218 $.fn.exists = function() { 65219 return this.length > 0; 65220 }; 65221 65222}).call(this); 65223(function() { 65224 var base; 65225 65226 if ((base = $.fn).renderSerializedErrors == null) { 65227 base.renderSerializedErrors = function(errors) { 65228 var attribute, el, error, errorMessages, id, input, parts; 65229 if (!this.is('form')) { 65230 throw 'Can\'t render errors. Use appropriate DOM element.'; 65231 } 65232 id = this.attr('id'); 65233 errorMessages = []; 65234 this.find('label.error.error-manually-added').remove(); 65235 for (error in errors) { 65236 parts = errors[error].source.pointer.split('/'); 65237 attribute = parts[parts.length - 1]; 65238 input = this.find("#" + id + "-" + attribute); 65239 if (input[0]) { 65240 el = "<label class=\"error error-manually-added u-text-justify u-block\" for=\"" + id + "-" + attribute + "\">\n " + errors[error].detail + "\n</label>"; 65241 input.parent().append(el); 65242 } else { 65243 errorMessages.push(errors[error].detail); 65244 } 65245 } 65246 if (errorMessages[0]) { 65247 App.events.publish("app:notification:flash:error", errorMessages.join(' ')); 65248 } 65249 return true; 65250 }; 65251 } 65252 65253}).call(this); 65254(function() { 65255 var base, base1; 65256 65257 $.fn.isOnScreen = function() { 65258 var bounds, viewport, win; 65259 win = $(window); 65260 viewport = { 65261 top: win.scrollTop(), 65262 left: win.scrollLeft() 65263 }; 65264 viewport.right = viewport.left + win.width(); 65265 viewport.bottom = viewport.top + win.height(); 65266 bounds = this.offset(); 65267 bounds.right = bounds.left + this.outerWidth(); 65268 bounds.bottom = bounds.top + this.outerHeight(); 65269 return !(viewport.right < bounds.left || viewport.left >
65269 bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom); 65270 }; 65271 65272 if ((base = $.fn).exists == null) { 65273 base.exists = function() { 65274 return this.length > 0; 65275 }; 65276 } 65277 65278 if ((base1 = $.fn).select2 == null) { 65279 base1.select2 = function() {}; 65280 } 65281 65282}).call(this); 65283(function() { 65284 var bootApp, hasBlockingLoader, input, loadApp; 65285 65286 loadApp = function() { 65287 App.events.publish('app:config:load', $('#application-settings').data()); 65288 App.events.publish('app:page:execute'); 65289 return App.events.publish('app:ui:init'); 65290 }; 65291 65292 input = document.querySelector('#browser-cache-test'); 65293 65294 bootApp = function() { 65295 if (input != null) { 65296 if (input.value) { 65297 window.location = window.location.toString().replace(location.hash, ''); 65298 } else { 65299 loadApp(); 65300 } 65301 return input.value = (new Date).getTime(); 65302 } else { 65303 return loadApp(); 65304 } 65305 }; 65306 65307 hasBlockingLoader = document.querySelector('.js-loader-container') != null; 65308 65309 if (hasBlockingLoader) { 65310 if (document.readyState === 'loading') { 65311 document.addEventListener('DOMContentLoaded', bootApp); 65312 } else { 65313 setTimeout(bootApp, 0); 65314 } 65315 } else { 65316 window.addEventListener('load', bootApp); 65317 } 65318 65319}).call(this); 65320 65321/* Blob.js 65322 * A Blob implementation. 65323 * 2018-01-12 65324 * 65325 * By Eli Grey, http://eligrey.com 65326 * By Devin Samarin, https://github.com/dsamarin 65327 * License: MIT 65328 * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md 65329 */ 65330 65331/*global self, unescape */ 65332/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 65333 plusplus: true */ 65334 65335/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ 65336 65337 65338(function(global) { 65339 (function (factory) { 65340 if (typeof define === "function" && define.amd) { 65341 // AMD. Register as an anonymous module. 65342 define(["exports"], factory); 65343 } else if (typeof exports === "object" && typeof exports.nodeName !== "string") { 65344 // CommonJS 65345 factory(exports); 65346 } else { 65347 // Browser globals 65348 factory(global); 65349 } 65350 })(function (exports) { 65351 "use strict"; 65352 65353 exports.URL = global.URL || global.webkitURL; 65354 65355 if (global.Blob && global.URL) { 65356 try { 65357 new Blob; 65358 return; 65359 } catch (e) { 65360 // Blob did not instantiate, time to polyfill 65361 } 65362 } 65363 65364 // Internally we use a BlobBuilder implementation to base Blob off of 65365 // in order to support older browsers that only have BlobBuilder 65366 var BlobBuilder = global.BlobBuilder || global.WebKitBlobBuilder || global.MozBlobBuilder || (function() { 65367 var get_class = function(object) { 65368 return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 65369 } 65370 , FakeBlobBuilder = function BlobBuilder() { 65371 this.data = []; 65372 } 65373 , FakeBlob = function Blob(data, type, encoding) { 65374 this.data = data; 65375 this.size = data.length; 65376 this.type = type; 65377 this.encoding = encoding; 65378 } 65379 , FBB_proto = FakeBlobBuilder.prototype 65380 , FB_proto = FakeBlob.prototype 65381 , FileReaderSync = global.FileReaderSync 65382 , FileException = function(type) { 65383 this.code = this[this.name = type]; 65384 } 65385 , file_ex_codes = ( 65386 "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " 65387 + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" 65388 ).split(" ") 65389 , file_ex_code = file_ex_codes.length 65390 , real_URL = global.URL || global.webkitURL || exports 65391 , real_create_object_URL = real_URL.createObjectURL 65392 , real_revoke_object_URL = real_URL.revokeObjectURL 65393 , URL = real_URL 65394 , btoa = global.btoa 65395 , atob = global.atob 65396 65397 , ArrayBuffer = global.ArrayBuffer 65398 , Uint8Array = global.Uint8Array 65399 65400 , origin = /^[\w-]+:\/*\[?[\w.:-]+\]?(?::[0-9]+)?/ 65401 ; 65402 FakeBlob.fake = FB_proto.fake = true; 65403 while (file_ex_code--) { 65404 FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; 65405 } 65406 // Polyfill URL 65407 if (!real_URL.createObjectURL) { 65408 URL = exports.URL = function(uri) { 65409 var uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") 65410 , uri_origin 65411 ; 65412 uri_info.href = uri; 65413 if (!("origin" in uri_info)) { 65414 if (uri_info.protocol.toLowerCase() === "data:") { 65415 uri_info.origin = null; 65416 } else { 65417 uri_origin = uri.match(origin); 65418 uri_info.origin = uri_origin && uri_origin[1]; 65419 } 65420 } 65421 return uri_info; 65422 }; 65423 } 65424 URL.createObjectURL = function(blob) { 65425 var 65426 type = blob.type 65427 , data_URI_header 65428 ; 65429 if (type === null) { 65430 type = "application/octet-stream"; 65431 } 65432 if (blob instanceof FakeBlob) { 65433 data_URI_header = "data:" + type; 65434 if (blob.encoding === "base64") { 65435 return data_URI_header + ";base64," + blob.data; 65436 } else if (blob.encoding === "URI") { 65437 try { 65438 return `${data_URI_header},${decodeURIComponent(blob.data)}` 65439 } catch (e) { 65440 if (typeof window !== 'undefined' && window.Sentry && window.Sentry.captureException) { 65441 window.Sentry.captureException(new Error('Blob data URI decoding failed'), { 65442 tags: { 65443 error_type: 'url_decode_failure', 65444 library: 'blob_polyfill', 65445 component: 'blob_create_object_url', 65446 }, 65447 extra: { 65448 data_data: blob.data, 65449 data_encoding: blob.encoding, 65450 data_type: blob.type, 65451 error_message: e.message, 65452 stack_trace: e.stack, 65453 timestamp: new Date().toISOString(), 65454 page_url: typeof window !== 'undefined' ? window.location.href : 'unknown', 65455 level: 'warning', 65456 } 65457 }) 65458 } 65459 // Fallback to original data if URI is malformed 65460 return `${data_URI_header},${blob.data}` 65461 } 65462 } if (btoa) { 65463 return data_URI_header + ";base64," + btoa(blob.data); 65464 } else { 65465 return data_URI_header + "," + encodeURIComponent(blob.data); 65466 } 65467 } else if (real_create_object_URL) { 65468 return real_create_object_URL.call(real_URL, blob); 65469 } 65470 }; 65471 URL.revokeObjectURL = function(object_URL) { 65472 if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { 65473 real_revoke_object_URL.call(real_URL, object_URL); 65474 } 65475 }; 65476 FBB_proto.append = function(data/*, endings*/) { 65477 var bb = this.data; 65478 // decode data to a binary string 65479 if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { 65480 var str = "" 65481 , buf = new Uint8Array(data) 65482 , i = 0 65483 , buf_len = buf.length 65484 ; 65485 for (; i < buf_len; i++) { 65486 str += String.fromCharCode(buf[i]); 65487 } 65488 bb.push(str); 65489 } else if (get_class(data) === "Blob" || get_class(data) === "File") { 65490 if (FileReaderSync) { 65491 var fr = new FileReaderSync; 65492 bb.push(fr.readAsBinaryString(data)); 65493 } else { 65494 // async FileReader won't work as BlobBuilder is sync 65495 throw new FileException("NOT_READABLE_ERR"); 65496 } 65497 } else if (data instanceof FakeBlob) { 65498 if (data.encoding === "base64" && atob) { 65499 bb.push(atob(data.data)); 65500 } else if (data.encoding === "URI") { 65501 try { 65502 bb.push(decodeURIComponent(data.data)) 65503 } catch (e) { 65504 window.Sentry.captureException(new Error('Blob data URI decoding failed'), { 65505 tags: { 65506 error_type: 'url_decode_failure', 65507 library: 'blob_polyfill', 65508 component: 'blob_append', 65509 }, 65510 extra: { 65511 data_data: data.data, 65512 data_encoding: data.encoding, 65513 data_type: data.type, 65514 error_message: e.message, 65515 stack_trace: e.stack, 65516 timestamp: new Date().toISOString(), 65517 page_url: typeof window !== 'undefined' ? window.location.href : 'unknown', 65518 level: 'warning', 65519 } 65520 }) 65521 // Fallback to original data if URI is malformed 65522 bb.push(data.data) 65523 } 65524 } else if (data.encoding === "raw") { 65525 bb.push(data.data); 65526 } 65527 } else { 65528 if (typeof data !== "string") { 65529 data += ""; // convert unsupported types to strings 65530 } 65531 // decode UTF-16 to binary string 65532 bb.push(unescape(encodeURIComponent(data))); 65533 } 65534 }; 65535 FBB_proto.getBlob = function(type) { 65536 if (!arguments.length) { 65537 type = null; 65538 } 65539 return new FakeBlob(this.data.join(""), type, "raw"); 65540 }; 65541 FBB_proto.toString = function() { 65542 return "[object BlobBuilder]"; 65543 }; 65544 FB_proto.slice = function(start, end, type) { 65545 var args = arguments.length; 65546 if (args < 3) { 65547 type = null; 65548 } 65549 return new FakeBlob(this.data.slice(start, args > 1 ? end : this.data.length) 65550 , type 65551 , this.encoding 65552 ); 65553 }; 65554 FB_proto.toString = function() { 65555 return "[object Blob]"; 65556 }; 65557 FB_proto.close = function() { 65558 this.size = 0; 65559 delete this.data; 65560 }; 65561 return FakeBlobBuilder; 65562 }()); 65563 65564 exports.Blob = function(blobParts, options) { 65565 var type = options ? (options.type || "") : ""; 65566 var builder = new BlobBuilder(); 65567 if (blobParts) { 65568 for (var i = 0, len = blobParts.length; i < len; i++) { 65569 if (Uint8Array && blobParts[i] instanceof Uint8Array) { 65570 builder.append(blobParts[i].buffer); 65571 } 65572 else { 65573 builder.append(blobParts[i]); 65574 } 65575 } 65576 } 65577 var blob = builder.getBlob(type); 65578 if (!blob.slice && blob.webkitSlice) { 65579 blob.slice = blob.webkitSlice; 65580 } 65581 return blob; 65582 }; 65583 65584 var getPrototypeOf = Object.getPrototypeOf || function(object) { 65585 return object.__proto__; 65586 }; 65587 exports.Blob.prototype = getPrototypeOf(new exports.Blob()); 65588 }); 65589})( 65590 typeof self !== "undefined" && self || 65591 typeof window !== "undefined" && window || 65592 typeof global !== "undefined" && global || 65593 this 65594); 65595;(function(){var k;function l(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}}var m="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,d){a!=Array.prototype&&a!=Object.prototype&&(a[b]=d.value)},n="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this;function p(){p=function(){};n.Symbol||(n.Symbol=r)}var r=function(){var a=0;return function(b){return"jscomp_symbol_"+(b||"")+a++}}(); 65596function u(){p();var a=n.Symbol.iterator;a||(a=n.Symbol.iterator=n.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&m(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return v(l(this))}});u=function(){}}function v(a){u();a={next:a};a[n.Symbol.iterator]=function(){return this};return a}function x(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):{next:l(a)}}var y;
65597if("function"==typeof Object.setPrototypeOf)y=Object.setPrototypeOf;else{var z;a:{var A={o:!0},B={};try{B.__proto__=A;z=B.o;break a}catch(a){}z=!1}y=z?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}var C=y;function D(){this.g=!1;this.c=null;this.m=void 0;this.b=1;this.l=this.s=0;this.f=null}function E(a){if(a.g)throw new TypeError("Generator is already running");a.g=!0}D.prototype.h=function(a){this.m=a}; 65598D.prototype.i=function(a){this.f={u:a,v:!0};this.b=this.s||this.l};D.prototype["return"]=function(a){this.f={"return":a};this.b=this.l};function F(a,b,d){a.b=d;return{value:b}}function G(a){this.w=a;this.j=[];for(var b in a)this.j.push(b);this.j.reverse()}function H(a){this.a=new D;this.A=a}H.prototype.h=function(a){E(this.a);if(this.a.c)return I(this,this.a.c.next,a,this.a.h);this.a.h(a);return J(this)}; 65599function K(a,b){E(a.a);var d=a.a.c;if(d)return I(a,"return"in d?d["return"]:function(a){return{value:a,done:!0}},b,a.a["return"]);a.a["return"](b);return J(a)}H.prototype.i=function(a){E(this.a);if(this.a.c)return I(this,this.a.c["throw"],a,this.a.h);this.a.i(a);return J(this)}; 65600function I(a,b,d,c){try{var e=b.call(a.a.c,d);if(!(e instanceof Object))throw new TypeError("Iterator result "+e+" is not an object");if(!e.done)return a.a.g=!1,e;var f=e.value}catch(g){return a.a.c=null,a.a.i(g),J(a)}a.a.c=null;c.call(a.a,f);return J(a)}function J(a){for(;a.a.b;)try{var b=a.A(a.a);if(b)return a.a.g=!1,{value:b.value,done:!1}}catch(d){a.a.m=void 0,a.a.i(d)}a.a.g=!1;if(a.a.f){b=a.a.f;a.a.f=null;if(b.v)throw b.u;return{value:b["return"],done:!0}}return{value:void 0,done:!0}} 65601function L(a){this.next=function(b){return a.h(b)};this["throw"]=function(b){return a.i(b)};this["return"]=function(b){return K(a,b)};u();this[Symbol.iterator]=function(){return this}}function M(a,b){var d=new L(new H(b));C&&C(d,a.prototype);return d} 65602if("undefined"===typeof FormData||!FormData.prototype.keys){var N=function(a,b){for(var d=0;d<a.length;d++)b(a[d])},O=function(a,b,d){if(2>arguments.length)throw new TypeError("2 arguments required, but only "+arguments.length+" present.");return b instanceof Blob?[a+"",b,void 0!==d?d+"":"string"===typeof b.name?b.name:"blob"]:[a+"",b+""]},P=function(a){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");return[a+""]},Q=function(a){var b=x(a);a=b.next().value;b=b.next().value; 65603a instanceof Blob&&(a=new File([a],b,{type:a.type,lastModified:a.lastModified}));return a},R="object"===typeof window?window:"object"===typeof self?self:this,S=R.FormData,T=R.XMLHttpRequest&&R.XMLHttpRequest.prototype.send,U=R.Request&&R.fetch;p();var V=R.Symbol&&Symbol.toStringTag,W=new WeakMap,X=Array.from||function(a){return[].slice.call(a)};V&&(Blob.prototype[V]||(Blob.prototype[V]="Blob"),"File"in R&&!File.prototype[V]&&(File.prototype[V]="File"));try{new File([],"")}catch(a){R.File=function(b, 65604d,c){b=new Blob(b,c);c=c&&void 0!==c.lastModified?new Date(c.lastModified):new Date;Object.defineProperties(b,{name:{value:d},lastModifiedDate:{value:c},lastModified:{value:+c},toString:{value:function(){return"[object File]"}}});V&&Object.defineProperty(b,V,{value:"File"});return b}}p();u();var Y=function(a){W.set(this,Object.create(null));if(!a)return this;var b=this;N(a.elements,function(a){a.name&&!a.disabled&&"submit"!==a.type&&"button"!==a.type&&("file"===a.type?N(a.files||[],function(c){b.append(a.name, 65605c)}):"select-multiple"===a.type||"select-one"===a.type?N(a.options,function(c){!c.disabled&&c.selected&&b.append(a.name,c.value)}):"checkbox"===a.type||"radio"===a.type?a.checked&&b.append(a.name,a.value):b.append(a.name,a.value))})};k=Y.prototype;k.append=function(a,b,d){var c=W.get(this);c[a]||(c[a]=[]);c[a].push([b,d])};k["delete"]=function(a){delete W.get(this)[a]};k.entries=function b(){var d=this,c,e,f,g,h,q;return M(b,function(b){switch(b.b){case 1:c=W.get(d),f=new G(c);case 2:var t;a:{for(t= 65606f;0<t.j.length;){var w=t.j.pop();if(w in t.w){t=w;break a}}t=null}if(null==(e=t)){b.b=0;break}g=x(c[e]);h=g.next();case 5:if(h.done){b.b=2;break}q=h.value;return F(b,[e,Q(q)],6);case 6:h=g.next(),b.b=5}})};
65606k.forEach=function(b,d){for(var c=x(this),e=c.next();!e.done;e=c.next()){var f=x(e.value);e=f.next().value;f=f.next().value;b.call(d,f,e,this)}};k.get=function(b){var d=W.get(this);return d[b]?Q(d[b][0]):null};k.getAll=function(b){return(W.get(this)[b]||[]).map(Q)};k.has=function(b){return b in 65607W.get(this)};k.keys=function d(){var c=this,e,f,g,h,q;return M(d,function(d){1==d.b&&(e=x(c),f=e.next());if(3!=d.b){if(f.done){d.b=0;return}g=f.value;h=x(g);q=h.next().value;return F(d,q,3)}f=e.next();d.b=2})};k.set=function(d,c,e){W.get(this)[d]=[[c,e]]};k.values=function c(){var e=this,f,g,h,q,w;return M(c,function(c){1==c.b&&(f=x(e),g=f.next());if(3!=c.b){if(g.done){c.b=0;return}h=g.value;q=x(h);q.next();w=q.next().value;return F(c,w,3)}g=f.next();c.b=2})};Y.prototype._asNative=function(){for(var c= 65608new S,e=x(this),f=e.next();!f.done;f=e.next()){var g=x(f.value);f=g.next().value;g=g.next().value;c.append(f,g)}return c};Y.prototype._blob=function(){for(var c="----formdata-polyfill-"+Math.random(),e=[],f=x(this),g=f.next();!g.done;g=f.next()){var h=x(g.value);g=h.next().value;h=h.next().value;e.push("--"+c+"\r\n");h instanceof Blob?e.push('Content-Disposition: form-data; name="'+g+'"; filename="'+h.name+'"\r\n',"Content-Type: "+(h.type||"application/octet-stream")+"\r\n\r\n",h,"\r\n"):e.push('Content-Disposition: form-data; name="'+ 65609g+'"\r\n\r\n'+h+"\r\n")}e.push("--"+c+"--");return new Blob(e,{type:"multipart/form-data; boundary="+c})};Y.prototype[Symbol.iterator]=function(){return this.entries()};Y.prototype.toString=function(){return"[object FormData]"};V&&(Y.prototype[V]="FormData");[["append",O],["delete",P],["get",P],["getAll",P],["has",P],["set",O]].forEach(function(c){var e=Y.prototype[c[0]];Y.prototype[c[0]]=function(){return e.apply(this,c[1].apply(this,X(arguments)))}});T&&(XMLHttpRequest.prototype.send=function(c){c instanceof 65610Y?(c=c._blob(),this.setRequestHeader("Content-Type",c.type),T.call(this,c)):T.call(this,c)});if(U){var Z=R.fetch;R.fetch=function(c,e){e&&e.body&&e.body instanceof Y&&(e.body=e.body._blob());return Z(c,e)}}R.FormData=Y}; 65611})(); 65612 65613 65614(function() { 65615 65616 65617}).call(this); 65618const isInCheckoutPage = window.location.pathname && window.location.pathname.includes('/checkout') 65619const availableCountriesForLocalPayments = ['BE', 'AT', 'DE', 'NL', 'IT', 'ES', 'PL'] 65620const merchantAccountId = 'cgtrader' 65621 65622var braintreeSdkUnavailable = false 65623 65624function showTrustlyButton() { 65625 // $(trustlyButton).removeClass('is-hidden') 65626} 65627 65628function prepareTrackViewItemList(attributes) { 65629 const { 65630 searchQuery, 65631 id, 65632 title, 65633 affiliation, 65634 index, 65635 authorUsername, 65636 category, 65637 subcategory, 65638 itemCategory3, 65639 itemCategory4, 65640 itemCategory5, 65641 productType, 65642 locationId, 65643 price, 65644 discount, 65645 } = attributes || {} 65646 65647 const trackable_attributes = { 65648 item_id: String(id), 65649 item_name: title, 65650 affiliation: affiliation, 65651 currency: 'USD', 65652 index: parseInt(index) || null, 65653 item_brand: authorUsername, 65654 item_category: category, 65655 item_category2: subcategory, 65656 item_category3: itemCategory3, 65657 item_category4: itemCategory4, 65658 item_category5: itemCategory5, 65659 item_list_id: searchQuery, 65660 item_list_name: searchQuery, 65661 item_variant: productType, 65662 location_id: locationId && locationId.join('_'), 65663 price: parseFloat(price), 65664 quantity: 1, 65665 } 65666 65667 if (discount > 0) { 65668 trackable_attributes.price = trackable_attributes.price + parseFloat(discount) 65669 trackable_attributes.discount = parseFloat(discount) 65670 } else { 65671 trackable_attributes.discount = 0 65672 } 65673 65674 return trackable_attributes 65675} 65676 65677function enableLocalPayments() { 65678 switch (countryCode) { 65679 case 'BE': 65680 $(bancontactButton).removeClass('is-hidden') 65681 $(klarnaButton).removeClass('is-hidden') 65682 break 65683 case 'AT': 65684 $(epsButton).removeClass('is-hidden') 65685 $(klarnaButton).removeClass('is-hidden') 65686 break 65687 case 'DE': 65688 $(giropayButton).removeClass('is-hidden') 65689 $(klarnaButton).removeClass('is-hidden') 65690 showTrustlyButton() 65691 break 65692 case 'NL': 65693 $(idealButton).removeClass('is-hidden') 65694 $(klarnaButton).removeClass('is-hidden') 65695 showTrustlyButton() 65696 break 65697 case 'IT': 65698 $(mybankButton).removeClass('is-hidden') 65699 $(klarnaButton).removeClass('is-hidden') 65700 $(satispayButton).removeClass('is-hidden') 65701 break 65702 case 'ES': 65703 $(klarnaButton).removeClass('is-hidden') 65704 showTrustlyButton() 65705 break 65706 case 'PL': 65707 $(p24Button).removeClass('is-hidden') 65708 break 65709 case 'AT': 65710 showTrustlyButton() 65711 break 65712 case 'EE': 65713 showTrustlyButton() 65714 break 65715 case 'FI': 65716 showTrustlyButton() 65717 break 65718 case 'LT': 65719 showTrustlyButton() 65720 break 65721 case 'LV': 65722 showTrustlyButton() 65723 break 65724 default: 65725 break 65726 } 65727} 65728 65729function trackPaymentEvent(paymentMethod) { 65730 if (window.dataLayer && gon && gon.cart_items) { 65731 const list = gon.cart_items.map((item) => prepareTrackViewItemList(item)) 65732 const couponValue = $('#coupon_code').val() || '' 65733 65734 if (window.dataLayer && list.length > 0) { 65735 window.dataLayer.push({ 65736 event: 'add_payment_info', 65737 user_id: App.config.userId || '', 65738 ecommerce: { 65739 currency: 'USD', 65740 value: gon.cart.value, 65741 coupon: couponValue, 65742 payment_type: paymentMethod, 65743 items: list, 65744 } 65745 }) 65746 } 65747 } 65748} 65749 65750// The four SDK tags in app/views/checkout/_gateway_setup.slim are parser-blocking and 65751// live in <head>, while this bundle is loaded at the end of <body>. The parser cannot 65752// reach our tag until those four have executed or permanently failed, so a missing 65753// `braintree` global here is a verdict, not a race. Do NOT add async/defer to those 65754// tags without replacing this check with a real readiness wait. 65755// 65756// Each of the four scripts attaches to window.braintree, so a partial failure yields a 65757// TypeError on the missing namespace rather than a ReferenceError. Check all four. 65758function braintreeSdkReady() { 65759 const sdk = window.braintree 65760 65761 return !!(sdk && sdk.dropin && sdk.client && sdk.localPayment && sdk.dataCollector) 65762} 65763window.braintreeSdkReady = braintreeSdkReady 65764 65765function reportBraintreeSdkUnavailable() { 65766 const sdk = window.braintree 65767 65768 console.error('Braintree SDK unavailable') 65769 65770 if (!window.Sentry) return 65771 65772 window.Sentry.captureMessage('Braintree SDK failed to load', { 65773 // A synthesized Error would carry a stack pointing at this reporter, whose frames 65774 // shift with every bundle digest and would refragment the issue on each deploy.
65775 level: 'error', 65776 fingerprint: ['braintree-sdk-unavailable'], 65777 tags: { section: 'checkout.braintree_sdk' }, 65778 extra: { 65779 path: window.location.pathname, 65780 hasBraintreeGlobal: !!sdk, 65781 braintreeKeys: sdk ? Object.keys(sdk) : [], 65782 readyState: document.readyState, 65783 msSinceNavigation: Math.round(window.performance.now()), 65784 }, 65785 }) 65786} 65787window.reportBraintreeSdkUnavailable = reportBraintreeSdkUnavailable 65788 65789// Nothing here can run at bundle-eval time. This file ships in the Sprockets bundle, 65790// which is `async` at the end of <body>, while light_bundle (which defines window.Sentry 65791// via initSentry) is `defer` in <head> - so an async bundle that lands first sees no 65792// Sentry at all. App.events is worse: it is a plain mediator with no replay, and its 65793// 'app:notification:flash:error' subscriber only exists once App.Pages.Global boots on 65794// 'app:page:execute'. Both are ready by DOM ready, since deferred scripts run before 65795// DOMContentLoaded, so defer the whole failure handling to that boundary. 65796function onCheckoutBoot(callback) { 65797 if (window.App && App.events) { 65798 App.events.subscribe('app:page:execute', callback) 65799 } else if (document.readyState === 'loading') { 65800 document.addEventListener('DOMContentLoaded', callback) 65801 } else { 65802 setTimeout(callback, 0) 65803 } 65804} 65805window.onCheckoutBoot = onCheckoutBoot 65806 65807// autohide false: the checkout is blocked, so the toast must not disappear. 65808function handleBraintreeSdkUnavailable() { 65809 onCheckoutBoot(function () { 65810 reportBraintreeSdkUnavailable() 65811 65812 if (!window.App || !App.events) return 65813 65814 App.events.publish( 65815 'app:notification:flash:error', 65816 'Payment form could not be loaded. An ad blocker, a privacy extension or your ' + 65817 'network may be blocking it. Please allow js.braintreegateway.com and reload.', 65818 false 65819 ) 65820 }) 65821} 65822window.handleBraintreeSdkUnavailable = handleBraintreeSdkUnavailable 65823 65824if (isInCheckoutPage) { 65825 // Velocity-triggered guest checkout captcha: when the lockout is active the 65826 // server renders #checkout-guest-captcha. Ensure the MTCaptcha scripts are 65827 // appended so the widget actually renders. 65828 if (document.getElementById('checkout-guest-captcha') && typeof window.appendMTCaptcha === 'function') { 65829 window.appendMTCaptcha() 65830 } 65831 65832 container = document.getElementById('braintree-sdk-container') 65833 payButton = document.getElementById('pay-button') 65834 alipayPaymentMethodOption = document.getElementById('alipay-payment-method-option') 65835 otherPaymentMethodsOption = document.getElementById('other-payment-methods-option') 65836 otherPaymentMethodsForm = document.getElementById('other-payment-methods-form') 65837 closeOtherPaymentMethodsFormButton = document.getElementById('close-other
65837-payment-methods-form-button') 65838 auxilaryInfo = $('#payment') 65839 65840 bancontactButton = document.getElementById('bancontact-button') 65841 epsButton = document.getElementById('eps-button') 65842 giropayButton = document.getElementById('giropay-button') 65843 idealButton = document.getElementById('ideal-button') 65844 klarnaButton = document.getElementById('sofort-button') 65845 mybankButton = document.getElementById('mybank-button') 65846 p24Button = document.getElementById('p24-button') 65847 trustlyButton = document.getElementById('trustly-button') 65848 satispayButton = document.getElementById('satispay-button') 65849 alipayButton = document.getElementById('alipay-button') 65850 65851 dataContainer = container && container.dataset 65852 countryCode = dataContainer && dataContainer.countryCode 65853 threeDSecureEnabled = !!dataContainer && dataContainer.threeDSecureEnabled === "true" 65854 dropinReady = false 65855 65856 setTimeout(() => { 65857 if ($('.js-loader-container .cgt-spinner').is(":visible")) { 65858 if (window.Sentry) { 65859 // The spinner is lifted by the checkout page class, not by this SDK, so the 65860 // extras record whether the Drop-in itself was the laggard. 65861 window.Sentry.captureMessage('Payment tab is still loading after 5 seconds', { 65862 extra: { 65863 id: auxilaryInfo.data('auxilary'), 65864 dropinReady: dropinReady, 65865 readyState: document.readyState, 65866 msSinceNavigation: Math.round(window.performance.now()), 65867 } 65868 }) 65869 65870 App.events.publish( 65871 'app:notification:flash:error', 65872 'Oops. Connection seems to be unstable today, please contact support.' 65873 ) 65874 } 65875 } else if (dataContainer && !dropinReady && !braintreeSdkUnavailable && window.Sentry) { 65876 // The page now boots at DOM ready, so a hung braintree.dropin.create no longer 65877 // keeps the spinner up: the tab is visible but the card form and pay button are 65878 // missing. Report it separately; no flash, since 5s Drop-in latency is often 65879 // transient on slow networks. 65880 window.Sentry.captureMessage('Braintree Drop-in not ready after 5 seconds', { 65881 extra: { 65882 id: auxilaryInfo.data('auxilary'), 65883 readyState: document.readyState, 65884 msSinceNavigation: Math.round(window.performance.now()), 65885 } 65886 }) 65887 } 65888 }, 5000) 65889 65890 if (dataContainer && braintreeSdkReady()) { 65891 try { 65892 braintree.dropin.create({ 65893 authorization: dataContainer.client_token, 65894 selector: '#braintree-sdk-container', 65895 threeDSecure: threeDSecureEnabled, 65896 dataCollector: true, 65897 card: { 65898 cardholderName: { 65899 required: true 65900 } 65901 }, 65902 paypal: { 65903 flow: 'checkout', 65904 commit: true, 65905 amount: dataContainer.amount, 65906 currency: dataContainer.currency, 65907 }, 65908 venmo: { 65909 allowNewBrowserTab: false, 65910 }, 65911 applePay: { 65912 displayName: 'CGTrader', 65913 paymentRequest: { 65914 total: { 65915 label: 'CGTrader', 65916 amount: dataContainer.amount, 65917 }, 65918 } 65919 }, 65920 googlePay: { 65921 merchantId: dataContainer.googleMerchantId, 65922 transactionInfo: { 65923 totalPriceStatus: 'FINAL', 65924 totalPrice: dataContainer.amount, 65925 currencyCode: dataContainer.currency, 65926 }, 65927 } 65928 }).then(function (dropinInstance) { 65929 dropinReady = true 65930 $(payButton).removeClass('is-hidden') 65931 65932 shouldSeeOtherPaymentMethodsOption = availableCountriesForLocalPayments.includes(countryCode) && dataContainer.currency === 'EUR' 65933 shouldSeeAlipayPaymentMethodOption = countryCode === 'CN' 65934 65935 if (shouldSeeOtherPaymentMethodsOption) { 65936 $(otherPaymentMethodsOption).removeClass('is-hidden') 65937 enableLocalPayments() 65938 } 65939 65940 if (shouldSeeAlipayPaymentMethodOption) { 65941 $(alipayPaymentMethodOption).removeClass('is-hidden') 65942 $(alipayButton).removeClass('is-hidden') 65943 } 65944 65945 function readGuestCheckoutCaptchaToken() { 65946 if (!document.getElementById('checkout-guest-captcha')) return null 65947 if (!window.mtcaptcha || typeof window.mtcaptcha.getVerifiedToken !== 'function') return '' 65948 65949 return window.mtcaptcha.getVerifiedToken('checkout-guest-captcha') || '' 65950 } 65951 65952 function appendGuestCheckoutCaptchaToken(urlWithPayload) { 65953 const token = readGuestCheckoutCaptchaToken() 65954 if (token === null) return urlWithPayload 65955
65956 return urlWithPayload + '&MTCaptchaToken=' + encodeURIComponent(token) 65957 } 65958 65959 function sendNonceToServer() { 65960 let payloadDataForSentry 65961 65962 // Velocity-triggered guest checkout captcha: require a solved widget 65963 // before issuing the payment request when the gate is active. 65964 if (document.getElementById('checkout-guest-captcha')) { 65965 const token = readGuestCheckoutCaptchaToken() 65966 if (!token) { 65967 if (typeof window.flash === 'function') { 65968 window.flash('Please complete the captcha to continue.') 65969 } else { 65970 window.alert('Please complete the captcha to continue.') 65971 } 65972 payButton.disabled = false 65973 return 65974 } 65975 } 65976 65977 dropinInstance.requestPaymentMethod({ 65978 threeDSecure: { 65979 collectDeviceData: true, 65980 amount: dataContainer.amount, 65981 email: dataContainer.email, 65982 additionalInformation: { 65983 ipAddress: dataContainer.ipAddress 65984 } 65985 } 65986 }).then(function (payload) { 65987 payButton.disabled = true 65988 controller_path = document.getElementById('controller_path').dataset.path 65989 payload_data = { 65990 nonce: payload.nonce, 65991 order_id: dataContainer.orderId, 65992 device_data: payload.deviceData, 65993 } 65994 65995 payloadDataForSentry = payload_data 65996 65997 const verifyUrl = controller_path + '&payload=' + encodeURIComponent(JSON.stringify(payload_data)) 65998 window.location = appendGuestCheckoutCaptchaToken(verifyUrl) 65999 }).catch(function (err) { 66000 // Handle errors in requesting payment method 66001 window.Sentry.captureException(new Error('Braintree Drop-in payment method request failed'), { 66002 tags: { 66003 error_type: 'payment_sdk_failure', 66004 component: 'braintree_dropin', 66005 stage: 'payment_method_request' 66006 }, 66007 extra: { 66008 error_message: err.message, 66009 stack_trace: err.stack, 66010 client_token_present: !!dataContainer.client_token, 66011 payload_data: payloadDataForSentry, 66012 timestamp: new Date().toISOString(), 66013 page_url: window.location.href 66014 }, 66015 level: 'error' 66016 }) 66017 payButton.disabled = false 66018 }) 66019 } 66020 66021 // allows us to still request the payment method manually, such as 66022 // when filling out a credit card form 66023 $(payButton).on('click', (e) => { 66024 e.preventDefault() 66025 payButton.disabled = true 66026 if (window.customEventTracker) { 66027 window.customEventTracker({ 66028 name: 'one_time_purchase_pay_click', 66029 eventData: { 66030 event_source: gon.is_buy_now ? 'buy_now' : 'cart', 66031 payment_method: 'credit_card', 66032 }, 66033 }) 66034 } 66035 sendNonceToServer() 66036 }) 66037 66038 if (dropinInstance.isPaymentMethodRequestable()) { 66039 // This will be true if you generated the client token 66040 // with a customer ID and there is a saved payment method 66041 // available to tokenize with that customer. 66042 payButton.disabled = false 66043 } 66044 66045 dropinInstance.on('changeActiveView', function ({ newViewId }) { 66046 if (shouldSeeOtherPaymentMethodsOption) { 66047 if (['methods', 'options'].includes(newViewId)) { 66048 $(otherPaymentMethodsOption).removeClass('is-hidden') 66049 $(otherPaymentMethodsForm).addClass('is-hidden') 66050 } else { 66051 $(otherPaymentMethodsOption).addClass('is-hidden') 66052 } 66053 } 66054 66055 if (shouldSeeAlipayPaymentMethodOption) { 66056 if (['methods', 'options'].includes(newViewId)) { 66057 $(alipayPaymentMethodOption).removeClass('is-hidden') 66058 $(otherPaymentMethodsForm).addClass('is-hidden') 66059 } else { 66060 $(alipayPaymentMethodOption).addClass('is-hidden') 66061 } 66062 } 66063 }); 66064 66065 dropinInstance.on('paymentMethodRequestable', function (event) { 66066 const { type, paymentMethodIsSelected } = event 66067 66068 // PayPalAccount 66069 // 66070 if (type === 'PayPalAccount') { 66071 trackPaymentEvent('PayPal') 66072 } 66073 66074 if (type === 'CreditCard') { 66075 trackPaymentEvent('Credit Card') 66076 } 66077 66078 if (paymentMethodIsSelected) { 66079 payButton.disabled = true; 66080 66081 if (type !== 'CreditCard') { 66082 sendNonceToServer(); 66083 } 66084 66085 return; 66086 } 66087 66088 payButton.disabled = false 66089 }); 66090 66091 dropinInstance.on('noPaymentMethodRequestable', function () { 66092 payButton.disabled = true 66093 }); 66094 66095 $(alipayPaymentMethodOption).on('click', (e) => { 66096 e.preventDefault() 66097 $(container).addClass('is-hidden') 66098 $(alipayPaymentMethodOption).addClass('is-hidden') 66099 $(otherPaymentMethodsForm).removeClass('is-hidden') 66100 }) 66101 66102 $(otherPaymentMethodsOption).on('click', (e) => { 66103 e.preventDefault() 66104 $(container).addClass('is-hidden') 66105 $(otherPaymentMethodsOption).addClass('is-hidden') 66106 $(otherPaymentMethodsForm).removeClass('is-hidden') 66107 }) 66108 66109 $(closeOtherPaymentMethodsFormButton).on('click', (e) => { 66110 e.preventDefault() 66111 $(container).removeClass('is-hidden') 66112 $(otherPaymentMethodsOption).removeClass('is-hidden') 66113 $(otherPaymentMethodsForm).addClass('is-hidden') 66114 }) 66115 66116 $('.gpay-button').on('click', (e) => { 66117 trackPaymentEvent('Google Pay') 66118 if (window.customEventTracker) { 66119 window.customEventTracker({ 66120 name: 'one_time_purchase_pay_click', 66121 eventData: { 66122 event_source: gon.is_buy_now ? 'buy_now' : 'cart', 66123 payment_method: 'google_pay', 66124 }, 66125 }) 66126 } 66127 }) 66128 }).catch(function (err) { 66129 // Handle any errors that might've occurred when creating Drop-in 66130 console.error(err) 66131 window.Sentry.captureException(err) 66132 }); 66133 } catch (e) { 66134 window.Sentry.captureException(e) 66135 } 66136 66137 try { 66138 // Create a client. 66139 braintree.client.create({ 66140 authorization: dataContainer.client_token, 66141 }).then(function (clientInstance) { 66142 // Create a local payment component. 66143 return braintree.localPayment.create({ 66144 client: clientInstance, 66145 merchantAccountId 66146 }); 66147 }).then(function (localPaymentInstance) { 66148 givenNameInput = document.getElementById('given-name-input') 66149 surnameInput = document.getElementById('surname-input') 66150 66151 function createLocalPaymentClickListener(type) { 66152 return function (event) { 66153 controller_path = document.getElementById('controller_path').dataset.path 66154 event.preventDefault(); 66155 66156 givenName = $(givenNameInput).val()
66157 surname = $(surnameInput).val() 66158 66159 if (!givenName || !surname) { 66160 if (!givenName) { 66161 $(givenNameInput).parent().addClass('cgt-input--error') 66162 } 66163 if (!surname) { 66164 $(surnameInput).parent().addClass('cgt-input--error') 66165 } 66166 return false 66167 } 66168 66169 if (window.customEventTracker) { 66170 window.customEventTracker({ 66171 name: 'one_time_purchase_pay_click', 66172 eventData: { 66173 event_source: gon.is_buy_now ? 'buy_now' : 'cart', 66174 payment_method: type, 66175 }, 66176 }) 66177 } 66178 66179 localPaymentInstance.startPayment({ 66180 paymentType: type, 66181 amount: dataContainer.amount, 66182 fallback: { // see Fallback section for details on these params 66183 buttonText: 'Return to CGTrader', 66184 url: window.location.href, 66185 }, 66186 currencyCode: dataContainer.currency, 66187 givenName, 66188 surname, 66189 email: dataContainer.email, 66190 onPaymentStart: function (data, start) { 66191 link_order_with_local_payment_path = document.getElementById('link_order_with_local_payment').dataset.path 66192 local_payment_id = data.paymentId 66193 order_id = dataContainer.orderId 66194 66195 payload = { order_id, local_payment_id } 66196 66197 fetch(link_order_with_local_payment_path, { 66198 method: 'POST', 66199 headers: { 66200 'Content-Type': 'application/json', 66201 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content') 66202 }, 66203 body: JSON.stringify(payload) 66204 }) 66205 start(); 66206 } 66207 }).then(function (payload) { 66208 // Send the nonce to your server to create a transaction 66209 controller_path = document.getElementById('controller_path').dataset.path 66210 payload_data = { nonce: payload.nonce, order_id: dataContainer.orderId } 66211 66212 const verifyUrl = controller_path + '&payload=' + encodeURIComponent(JSON.stringify(payload_data)) 66213 window.location = appendGuestCheckoutCaptchaToken(verifyUrl) 66214 }).catch(function (err) { 66215 if (err.code === 'LOCAL_PAYMENT_POPUP_CLOSED') { 66216 console.error('Customer closed Local Payment popup.'); 66217 } else { 66218 console.error('Error!', err); 66219 } 66220 }); 66221 }; 66222 } 66223 66224 $(givenNameInput).on('input', function () { 66225 $(givenNameInput).parent().removeClass('cgt-input--error') 66226 }) 66227 66228 $(surnameInput).on('input', function () { 66229 $(surnameInput).parent().removeClass('cgt-input--error') 66230 }) 66231 66232 $(bancontactButton).on('click', createLocalPaymentClickListener('bancontact')) 66233 $(epsButton).on('click', createLocalPaymentClickListener('eps')) 66234 $(giropayButton).on('click', createLocalPaymentClickListener('giropay')) 66235 $(idealButton).on('click', createLocalPaymentClickListener('ideal')) 66236 $(klarnaButton).on('click', createLocalPaymentClickListener('sofort')) 66237 $(mybankButton).on('click', createLocalPaymentClickListener('mybank')) 66238 $(p24Button).on('click', createLocalPaymentClickListener('p24')) 66239 $(trustlyButton).on('click', createLocalPaymentClickListener('trustly')) 66240 $(satispayButton).on('click', createLocalPaymentClickListener('satispay')) 66241 $(alipayButton).on('click', createLocalPaymentClickListener('alipay')) 66242 }).catch(function (err) { 66243 // Handle any errors that might've occurred when creating Local Payment 66244 console.error(err) 66245 window.Sentry.captureException(err) 66246 }); 66247 } catch (e) { 66248 window.Sentry.captureException(e) 66249 } 66250 } else if (dataContainer && document.querySelector('script[src*="js.braintreegateway.com"]')) { 66251 // Reached only when the SDK genuinely failed to load. A missing tag instead means 66252 // the gateway partial never rendered one (Rails.env.test?, or a non-web_sdk 66253 // gateway), which is not a failure - stay silent there. 66254 braintreeSdkUnavailable = true 66255 handleBraintreeSdkUnavailable() 66256 } 66257} 66258;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.