{"version":3,"sources":["../../../app/vendors/fss.js"],"names":["$","toggleClass","isMobile","any","apple","device","navigator","userAgent","indexOf","jQuery","uuid","replace","c","r","Math","random","toString","generateYears","today","Date","currentYear","getFullYear","output","first","i","year","parseInt","isLoading","getBrandByNumber","n","callback","context","ajax","url","apiURL","method","headers","Content-Type","ServiceKey","dataType","timeout","done","response","error","arguments","setTimeout","always","fn","serializeObject","o","a","this","serializeArray","each","undefined","name","push","value","urlParam","results","RegExp","exec","window","location","href","statesSelectsToPopulate","fillCitiesSelect","cselect","children","remove","y","length","city","append","id","addClass","removeClass","parents","bind","loadBrCities","get","resp","states","cities","z","select","hasClass","BR","state","label","toUpperCase","on","e","select2","data","val","currentTarget","applyTwoSelect","_el","el","_","isFunction","params","text","find","call","sel2","defaultOpts","theme","language","selectOnClose","dropdownCssClass","attr","onSelect2Callback","minimumResultsForSearch","Infinity","blur","isEmpty","findFunctionByString","applySelect2","sel","els","document","css","width","getBoundingClientRect","visibility","changeElementType","newType","attrs","attributes","idx","nodeName","nodeValue","replaceWith","SVGInject","noMobile","mySVGsToInject","querySelectorAll","SVGInjector","svg","setAttribute","strfn","fnArr","split","v","validationTooltipTpl","html","Mustache","parse","updatePosition","rendered","offset","posX","round","left","outerWidth","top","outerHeight","dropValidationBox","type","noDangerRemove","toLowerCase","snakeCase","slice","already","render","binded","TweenMax","set","opacity","off","throttle","self","focus","timeId","parent","to","ease","Sine","easeOut","closeFn","arr","clearTimeout","height","onComplete","input","activeElement","className","closeBtn","DEFAULTS","transitionEnd","processingPayment","customerKey","userProfile","_uuidRegExp","testUUid","str","test","getCustomerKey","store","setCustomerKey","key","setUserProfile","userWelcome","day","hr","getHours","console","warn","FS","trueId","userId","identify","substring","lastIndexOf","displayName","email","username","userId_str","userType_str","userType","customerKey_str","MUNDIPAGG","user","setCheckLastMerchant","payMethod","selPayMethod","Merchants","prototype","isMundiAdmin","prop","add","getResponseBasedError","mixpanel","track","_callback","responseJSON","errors","message","apply","status","TRANSLATOR","translate","_key","finded","forEachRight","dictionary","abbreviation","search","forEach","Diners","CasaShow","HugCard","Brazil","MasterCard","Residential","Billing","Shipping","Comercial","AuthAndCapture","AuthOnly","Invalid","NotAuthorized","Stone|1","Stone|0","Stone|1000","Stone|1001","Stone|1002","Stone|1003","Stone|1004","Stone|1005","Stone|1006","Stone|1007","Stone|1008","Stone|1009","Stone|1010","Stone|1011","Stone|1013","Stone|1014","Stone|1016","Stone|1017","Stone|1019","Stone|1020","Stone|1021","Stone|1022","Stone|1023","Stone|1024","Stone|1025","Stone|1042","Stone|1045","Stone|2000","Stone|2001","Stone|2002","Stone|2003","Stone|2004","Stone|2005","Stone|2006","Stone|2007","Stone|2008","Stone|2009","Stone|9102","Stone|9108","Stone|9109","Stone|9111","Stone|9112","Stone|9999","abbreviations","Rio de Janeiro","Mundipagg","merchant","customer","totalAmount","recurrencyOptions","headerTotalAmount","publicMerchantKey","isSandboxEnabled","setCustomer","setMerchant","people","Customer","customerName","Language","Email Confirmed","Is Enabled","isEnabled","$first_name","$email","getMerchant","getBoletoExpirationDiff","date","DaysToAddInBoletoExpirationDate","moment","diff","parseValue","parseNormalPattern","toVal","hasAttribute","matchRegex","getAttribute","match","advRegex","getHumanAmountInCents","isNaN","maskMoney","prefix","allowNegative","thousands","decimal","affixesStay","checkKeyMember","isCollection","isArray","setRequestData","isObject","merge","getRequestData","deleteDataKey","parseAmountInCents","toFixed","setSandboxMode","toggleSandbox","payBtn","ajaxSettings","hasOwnProperty","IsSandboxEnabled","next","LOGINCLIENT","_getCustomerData","makeCreditCardTransaction","preObj","items","$select","continuePreMerchant","LDUClass","lastPublicMerchantKey","$ajax","markOneMerchantExternalId","delay","retryFunction","setupMerchants","processResults","dataItems","map","obj","publicKey","merchantName","page","pagination","more","options","itemCount","cache","setupPaymentMethod","ccPayMethod","log","selHolder","statusCode","200","paymentMethodId","paymentMethod","txt","select2Merchant","placeholder","escapeMarkup","markup","templateResult","repo","loading","description","corporateName","templateSelection","initSelection","lastMerchantFor","Authorization","then","removeParticleJs","pjs","installMerchants","merchants","MERCHANTS","Client","isLogged","authClient","performingLogin","_setupAuth","_setupEventHandlers","myProfileRetry","checkTokenExpires","expires","Cookies","getTime","haveRefreshToken","tokenExpiration","getRefreshToken","_setRefreshToken","token","expiresWhen","floor","_AUTH_TOKEN_EXPIRE_TIMEOUT","setLoginError","serverError","custom","signinBtn","removeAttr","show","msg","_getUserProfile","userData","Intercom","userName","intercom","app_id","user_id","user_hash","CryptoJS","HmacSHA256","decodeURIComponent","signed_up_at","unix","intercomSettings","routeCustomerKey","headerMerchantName","splitNameFirst","splitNameLast","alpha","hTitle"],"mappings":"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","file":"main.js","sourcesContent":["//============================================================\n//\n// Copyright (C) 2013 Matthew Wagerfield\n//\n// Twitter: https://twitter.com/mwagerfield\n//\n// Permission is hereby granted, free of charge, to any\n// person obtaining a copy of this software and associated\n// documentation files (the \"Software\"), to deal in the\n// Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute,\n// sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do\n// so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice\n// shall be included in all copies or substantial portions\n// of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY\n// OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\n// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO\n// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE\n// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN\n// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\n// OR OTHER DEALINGS IN THE SOFTWARE.\n//\n//============================================================\n\n/**\n * Defines the Flat Surface Shader namespace for all the awesomeness to exist upon.\n * @author Matthew Wagerfield\n */\nFSS = {\n FRONT : 0,\n BACK : 1,\n DOUBLE : 2,\n SVGNS : 'http://www.w3.org/2000/svg'\n};\n\n/**\n * @class Array\n * @author Matthew Wagerfield\n */\nFSS.Array = typeof Float32Array === 'function' ? Float32Array : Array;\n\n/**\n * @class Utils\n * @author Matthew Wagerfield\n */\nFSS.Utils = {\n isNumber: function(value) {\n return !isNaN(parseFloat(value)) && isFinite(value);\n }\n};\n\n/**\n * Request Animation Frame Polyfill.\n * @author Paul Irish\n * @see https://gist.github.com/paulirish/1579671\n */\n(function() {\n if(document.getElementById('ffshadeoutput') === null){\n return false;\n }\n\n var lastTime = 0;\n var vendors = ['ms', 'moz', 'webkit', 'o'];\n\n for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {\n window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];\n window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];\n }\n\n if (!window.requestAnimationFrame) {\n window.requestAnimationFrame = function(callback, element) {\n var currentTime = new Date().getTime();\n var timeToCall = Math.max(0, 16 - (currentTime - lastTime));\n var id = window.setTimeout(function() {\n callback(currentTime + timeToCall);\n }, timeToCall);\n lastTime = currentTime + timeToCall;\n return id;\n };\n }\n\n if (!window.cancelAnimationFrame) {\n window.cancelAnimationFrame = function(id) {\n clearTimeout(id);\n };\n }\n\n}());\n\n/**\n * @object Math Augmentation\n * @author Matthew Wagerfield\n */\nMath.PIM2 = Math.PI*2;\nMath.PID2 = Math.PI/2;\nMath.randomInRange = function(min, max) {\n return min + (max - min) * Math.random();\n};\nMath.clamp = function(value, min, max) {\n value = Math.max(value, min);\n value = Math.min(value, max);\n return value;\n};\n\n/**\n * @object Vector3\n * @author Matthew Wagerfield\n */\nFSS.Vector3 = {\n create: function(x, y, z) {\n var vector = new FSS.Array(3);\n this.set(vector, x, y, z);\n return vector;\n },\n clone: function(a) {\n var vector = this.create();\n this.copy(vector, a);\n return vector;\n },\n set: function(target, x, y, z) {\n target[0] = x || 0;\n target[1] = y || 0;\n target[2] = z || 0;\n return this;\n },\n setX: function(target, x) {\n target[0] = x || 0;\n return this;\n },\n setY: function(target, y) {\n target[1] = y || 0;\n return this;\n },\n setZ: function(target, z) {\n target[2] = z || 0;\n return this;\n },\n copy: function(target, a) {\n target[0] = a[0];\n target[1] = a[1];\n target[2] = a[2];\n return this;\n },\n add: function(target, a) {\n target[0] += a[0];\n target[1] += a[1];\n target[2] += a[2];\n return this;\n },\n addVectors: function(target, a, b) {\n target[0] = a[0] + b[0];\n target[1] = a[1] + b[1];\n target[2] = a[2] + b[2];\n return this;\n },\n addScalar: function(target, s) {\n target[0] += s;\n target[1] += s;\n target[2] += s;\n return this;\n },\n subtract: function(target, a) {\n target[0] -= a[0];\n target[1] -= a[1];\n target[2] -= a[2];\n return this;\n },\n subtractVectors: function(target, a, b) {\n target[0] = a[0] - b[0];\n target[1] = a[1] - b[1];\n target[2] = a[2] - b[2];\n return this;\n },\n subtractScalar: function(target, s) {\n target[0] -= s;\n target[1] -= s;\n target[2] -= s;\n return this;\n },\n multiply: function(target, a) {\n target[0] *= a[0];\n target[1] *= a[1];\n target[2] *= a[2];\n return this;\n },\n multiplyVectors: function(target, a, b) {\n target[0] = a[0] * b[0];\n target[1] = a[1] * b[1];\n target[2] = a[2] * b[2];\n return this;\n },\n multiplyScalar: function(target, s) {\n target[0] *= s;\n target[1] *= s;\n target[2] *= s;\n return this;\n },\n divide: function(target, a) {\n target[0] /= a[0];\n target[1] /= a[1];\n target[2] /= a[2];\n return this;\n },\n divideVectors: function(target, a, b) {\n target[0] = a[0] / b[0];\n target[1] = a[1] / b[1];\n target[2] = a[2] / b[2];\n return this;\n },\n divideScalar: function(target, s) {\n if (s !== 0) {\n target[0] /= s;\n target[1] /= s;\n target[2] /= s;\n } else {\n target[0] = 0;\n target[1] = 0;\n target[2] = 0;\n }\n return this;\n },\n cross: function(target, a) {\n var x = target[0];\n var y = target[1];\n var z = target[2];\n target[0] = y*a[2] - z*a[1];\n target[1] = z*a[0] - x*a[2];\n target[2] = x*a[1] - y*a[0];\n return this;\n },\n crossVectors: function(target, a, b) {\n target[0] = a[1]*b[2] - a[2]*b[1];\n target[1] = a[2]*b[0] - a[0]*b[2];\n target[2] = a[0]*b[1] - a[1]*b[0];\n return this;\n },\n min: function(target, value) {\n if (target[0] < value) { target[0] = value; }\n if (target[1] < value) { target[1] = value; }\n if (target[2] < value) { target[2] = value; }\n return this;\n },\n max: function(target, value) {\n if (target[0] > value) { target[0] = value; }\n if (target[1] > value) { target[1] = value; }\n if (target[2] > value) { target[2] = value; }\n return this;\n },\n clamp: function(target, min, max) {\n this.min(target, min);\n this.max(target, max);\n return this;\n },\n limit: function(target, min, max) {\n var length = this.length(target);\n if (min !== null && length < min) {\n this.setLength(target, min);\n } else if (max !== null && length > max) {\n this.setLength(target, max);\n }\n return this;\n },\n dot: function(a, b) {\n return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];\n },\n normalise: function(target) {\n return this.divideScalar(target, this.length(target));\n },\n negate: function(target) {\n return this.multiplyScalar(target, -1);\n },\n distanceSquared: function(a, b) {\n var dx = a[0] - b[0];\n var dy = a[1] - b[1];\n var dz = a[2] - b[2];\n return dx*dx + dy*dy + dz*dz;\n },\n distance: function(a, b) {\n return Math.sqrt(this.distanceSquared(a, b));\n },\n lengthSquared: function(a) {\n return a[0]*a[0] + a[1]*a[1] + a[2]*a[2];\n },\n length: function(a) {\n return Math.sqrt(this.lengthSquared(a));\n },\n setLength: function(target, l) {\n var length = this.length(target);\n if (length !== 0 && l !== length) {\n this.multiplyScalar(target, l / length);\n }\n return this;\n }\n};\n\n/**\n * @object Vector4\n * @author Matthew Wagerfield\n */\nFSS.Vector4 = {\n create: function(x, y, z, w) {\n var vector = new FSS.Array(4);\n this.set(vector, x, y, z);\n return vector;\n },\n set: function(target, x, y, z, w) {\n target[0] = x || 0;\n target[1] = y || 0;\n target[2] = z || 0;\n target[3] = w || 0;\n return this;\n },\n setX: function(target, x) {\n target[0] = x || 0;\n return this;\n },\n setY: function(target, y) {\n target[1] = y || 0;\n return this;\n },\n setZ: function(target, z) {\n target[2] = z || 0;\n return this;\n },\n setW: function(target, w) {\n target[3] = w || 0;\n return this;\n },\n add: function(target, a) {\n target[0] += a[0];\n target[1] += a[1];\n target[2] += a[2];\n target[3] += a[3];\n return this;\n },\n multiplyVectors: function(target, a, b) {\n target[0] = a[0] * b[0];\n target[1] = a[1] * b[1];\n target[2] = a[2] * b[2];\n target[3] = a[3] * b[3];\n return this;\n },\n multiplyScalar: function(target, s) {\n target[0] *= s;\n target[1] *= s;\n target[2] *= s;\n target[3] *= s;\n return this;\n },\n min: function(target, value) {\n if (target[0] < value) { target[0] = value; }\n if (target[1] < value) { target[1] = value; }\n if (target[2] < value) { target[2] = value; }\n if (target[3] < value) { target[3] = value; }\n return this;\n },\n max: function(target, value) {\n if (target[0] > value) { target[0] = value; }\n if (target[1] > value) { target[1] = value; }\n if (target[2] > value) { target[2] = value; }\n if (target[3] > value) { target[3] = value; }\n return this;\n },\n clamp: function(target, min, max) {\n this.min(target, min);\n this.max(target, max);\n return this;\n }\n};\n\n/**\n * @class Color\n * @author Matthew Wagerfield\n */\nFSS.Color = function(hex, opacity) {\n this.rgba = FSS.Vector4.create();\n this.hex = hex || '#000000';\n this.opacity = FSS.Utils.isNumber(opacity) ? opacity : 1;\n this.set(this.hex, this.opacity);\n};\n\nFSS.Color.prototype = {\n set: function(hex, opacity) {\n hex = hex.replace('#', '');\n var size = hex.length / 3;\n this.rgba[0] = parseInt(hex.substring(size*0, size*1), 16) / 255;\n this.rgba[1] = parseInt(hex.substring(size*1, size*2), 16) / 255;\n this.rgba[2] = parseInt(hex.substring(size*2, size*3), 16) / 255;\n this.rgba[3] = FSS.Utils.isNumber(opacity) ? opacity : this.rgba[3];\n return this;\n },\n hexify: function(channel) {\n var hex = Math.ceil(channel*255).toString(16);\n if (hex.length === 1) { hex = '0' + hex; }\n return hex;\n },\n format: function() {\n var r = this.hexify(this.rgba[0]);\n var g = this.hexify(this.rgba[1]);\n var b = this.hexify(this.rgba[2]);\n this.hex = '#' + r + g + b;\n return this.hex;\n }\n};\n\n/**\n * @class Object\n * @author Matthew Wagerfield\n */\nFSS.Object = function() {\n this.position = FSS.Vector3.create();\n};\n\nFSS.Object.prototype = {\n setPosition: function(x, y, z) {\n FSS.Vector3.set(this.position, x, y, z);\n return this;\n }\n};\n\n/**\n * @class Light\n * @author Matthew Wagerfield\n */\nFSS.Light = function(ambient, diffuse) {\n FSS.Object.call(this);\n this.ambient = new FSS.Color(ambient || '#FFFFFF');\n this.diffuse = new FSS.Color(diffuse || '#FFFFFF');\n this.ray = FSS.Vector3.create();\n};\n\nFSS.Light.prototype = Object.create(FSS.Object.prototype);\n\n/**\n * @class Vertex\n * @author Matthew Wagerfield\n */\nFSS.Vertex = function(x, y, z) {\n this.position = FSS.Vector3.create(x, y, z);\n};\n\nFSS.Vertex.prototype = {\n setPosition: function(x, y, z) {\n FSS.Vector3.set(this.position, x, y, z);\n return this;\n }\n};\n\n/**\n * @class Triangle\n * @author Matthew Wagerfield\n */\nFSS.Triangle = function(a, b, c) {\n this.a = a || new FSS.Vertex();\n this.b = b || new FSS.Vertex();\n this.c = c || new FSS.Vertex();\n this.vertices = [this.a, this.b, this.c];\n this.u = FSS.Vector3.create();\n this.v = FSS.Vector3.create();\n this.centroid = FSS.Vector3.create();\n this.normal = FSS.Vector3.create();\n this.color = new FSS.Color();\n this.polygon = document.createElementNS(FSS.SVGNS, 'polygon');\n this.polygon.setAttributeNS(null, 'stroke-linejoin', 'round');\n this.polygon.setAttributeNS(null, 'stroke-miterlimit', '1');\n this.polygon.setAttributeNS(null, 'stroke-width', '1');\n this.computeCentroid();\n this.computeNormal();\n};\n\nFSS.Triangle.prototype = {\n computeCentroid: function() {\n this.centroid[0] = this.a.position[0] + this.b.position[0] + this.c.position[0];\n this.centroid[1] = this.a.position[1] + this.b.position[1] + this.c.position[1];\n this.centroid[2] = this.a.position[2] + this.b.position[2] + this.c.position[2];\n FSS.Vector3.divideScalar(this.centroid, 3);\n return this;\n },\n computeNormal: function() {\n FSS.Vector3.subtractVectors(this.u, this.b.position, this.a.position);\n FSS.Vector3.subtractVectors(this.v, this.c.position, this.a.position);\n FSS.Vector3.crossVectors(this.normal, this.u, this.v);\n FSS.Vector3.normalise(this.normal);\n return this;\n }\n};\n\n/**\n * @class Geometry\n * @author Matthew Wagerfield\n */\nFSS.Geometry = function() {\n this.vertices = [];\n this.triangles = [];\n this.dirty = false;\n};\n\nFSS.Geometry.prototype = {\n update: function() {\n if (this.dirty) {\n var t,triangle;\n for (t = this.triangles.length - 1; t >= 0; t--) {\n triangle = this.triangles[t];\n triangle.computeCentroid();\n triangle.computeNormal();\n }\n this.dirty = false;\n }\n return this;\n }\n};\n\n/**\n * @class Plane\n * @author Matthew Wagerfield\n */\nFSS.Plane = function(width, height, segments, slices) {\n FSS.Geometry.call(this);\n this.width = width || 100;\n this.height = height || 100;\n this.segments = segments || 4;\n this.slices = slices || 4;\n this.segmentWidth = this.width / this.segments;\n this.sliceHeight = this.height / this.slices;\n\n // Cache Variables\n var x, y, v0, v1, v2, v3,\n vertex, triangle, vertices = [],\n offsetX = this.width * -0.5,\n offsetY = this.height * 0.5;\n\n // Add Vertices\n for (x = 0; x <= this.segments; x++) {\n vertices.push([]);\n for (y = 0; y <= this.slices; y++) {\n vertex = new FSS.Vertex(offsetX + x*this.segmentWidth, offsetY - y*this.sliceHeight);\n vertices[x].push(vertex);\n this.vertices.push(vertex);\n }\n }\n\n // Add Triangles\n for (x = 0; x < this.segments; x++) {\n for (y = 0; y < this.slices; y++) {\n v0 = vertices[x+0][y+0];\n v1 = vertices[x+0][y+1];\n v2 = vertices[x+1][y+0];\n v3 = vertices[x+1][y+1];\n t0 = new FSS.Triangle(v0, v1, v2);\n t1 = new FSS.Triangle(v2, v1, v3);\n this.triangles.push(t0, t1);\n }\n }\n};\n\nFSS.Plane.prototype = Object.create(FSS.Geometry.prototype);\n\n/**\n * @class Material\n * @author Matthew Wagerfield\n */\nFSS.Material = function(ambient, diffuse) {\n this.ambient = new FSS.Color(ambient || '#444444');\n this.diffuse = new FSS.Color(diffuse || '#000');\n this.slave = new FSS.Color();\n};\n\n/**\n * @class Mesh\n * @author Matthew Wagerfield\n */\nFSS.Mesh = function(geometry, material) {\n FSS.Object.call(this);\n this.geometry = geometry || new FSS.Geometry();\n this.material = material || new FSS.Material();\n this.side = FSS.FRONT;\n this.visible = true;\n};\n\nFSS.Mesh.prototype = Object.create(FSS.Object.prototype);\n\nFSS.Mesh.prototype.update = function(lights, calculate) {\n var t,triangle, l,light, illuminance;\n\n // Update Geometry\n this.geometry.update();\n\n // Calculate the triangle colors\n if (calculate) {\n\n // Iterate through Triangles\n for (t = this.geometry.triangles.length - 1; t >= 0; t--) {\n triangle = this.geometry.triangles[t];\n\n // Reset Triangle Color\n FSS.Vector4.set(triangle.color.rgba);\n\n // Iterate through Lights\n for (l = lights.length - 1; l >= 0; l--) {\n light = lights[l];\n\n // Calculate Illuminance\n FSS.Vector3.subtractVectors(light.ray, light.position, triangle.centroid);\n FSS.Vector3.normalise(light.ray);\n illuminance = FSS.Vector3.dot(triangle.normal, light.ray);\n if (this.side === FSS.FRONT) {\n illuminance = Math.max(illuminance, 0);\n } else if (this.side === FSS.BACK) {\n illuminance = Math.abs(Math.min(illuminance, 0));\n } else if (this.side === FSS.DOUBLE) {\n illuminance = Math.max(Math.abs(illuminance), 0);\n }\n\n // Calculate Ambient Light\n FSS.Vector4.multiplyVectors(this.material.slave.rgba, this.material.ambient.rgba, light.ambient.rgba);\n FSS.Vector4.add(triangle.color.rgba, this.material.slave.rgba);\n\n // Calculate Diffuse Light\n FSS.Vector4.multiplyVectors(this.material.slave.rgba, this.material.diffuse.rgba, light.diffuse.rgba);\n FSS.Vector4.multiplyScalar(this.material.slave.rgba, illuminance);\n FSS.Vector4.add(triangle.color.rgba, this.material.slave.rgba);\n }\n\n // Clamp & Format Color\n FSS.Vector4.clamp(triangle.color.rgba, 0, 1);\n }\n }\n return this;\n};\n\n/**\n * @class Scene\n * @author Matthew Wagerfield\n */\nFSS.Scene = function() {\n this.meshes = [];\n this.lights = [];\n};\n\nFSS.Scene.prototype = {\n add: function(object) {\n if (object instanceof FSS.Mesh && !~this.meshes.indexOf(object)) {\n this.meshes.push(object);\n } else if (object instanceof FSS.Light && !~this.lights.indexOf(object)) {\n this.lights.push(object);\n }\n return this;\n },\n remove: function(object) {\n if (object instanceof FSS.Mesh && ~this.meshes.indexOf(object)) {\n this.meshes.splice(this.meshes.indexOf(object), 1);\n } else if (object instanceof FSS.Light && ~this.lights.indexOf(object)) {\n this.lights.splice(this.lights.indexOf(object), 1);\n }\n return this;\n }\n};\n\n/**\n * @class Renderer\n * @author Matthew Wagerfield\n */\nFSS.Renderer = function() {\n this.width = 0;\n this.height = 0;\n this.halfWidth = 0;\n this.halfHeight = 0;\n};\n\nFSS.Renderer.prototype = {\n setSize: function(width, height) {\n if (this.width === width && this.height === height) return;\n this.width = width;\n this.height = height;\n this.halfWidth = this.width * 0.5;\n this.halfHeight = this.height * 0.5;\n return this;\n },\n clear: function() {\n return this;\n },\n render: function(scene) {\n return this;\n }\n};\n\n/**\n * @class Canvas Renderer\n * @author Matthew Wagerfield\n */\nFSS.CanvasRenderer = function() {\n FSS.Renderer.call(this);\n this.element = document.createElement('canvas');\n this.element.style.display = 'block';\n this.element.setAttribute(\"id\", \"myCanvas\"); \n this.context = this.element.getContext('2d'); \n //this.element.style.filter = \"blur(10px)\";\n this.setSize(this.element.width, this.element.height);\n};\n\nFSS.CanvasRenderer.prototype = Object.create(FSS.Renderer.prototype);\n\nFSS.CanvasRenderer.prototype.setSize = function(width, height) {\n FSS.Renderer.prototype.setSize.call(this, width, height);\n this.element.width = width;\n this.element.height = height;\n this.context.setTransform(1, 0, 0, -1, this.halfWidth, this.halfHeight);\n return this;\n};\n\nFSS.CanvasRenderer.prototype.clear = function() {\n FSS.Renderer.prototype.clear.call(this);\n this.context.clearRect(-this.halfWidth, -this.halfHeight, this.width, this.height);\n return this;\n};\n\nFSS.CanvasRenderer.prototype.render = function(scene) {\n FSS.Renderer.prototype.render.call(this, scene);\n var m,mesh, t,triangle, color;\n\n // Clear Context\n this.clear();\n\n // Configure Context\n this.context.lineJoin = 'round';\n this.context.lineWidth = 1;\n\n // Update Meshes\n for (m = scene.meshes.length - 1; m >= 0; m--) {\n mesh = scene.meshes[m];\n if (mesh.visible) {\n mesh.update(scene.lights, true);\n\n // Render Triangles\n for (t = mesh.geometry.triangles.length - 1; t >= 0; t--) {\n triangle = mesh.geometry.triangles[t];\n color = triangle.color.format();\n this.context.beginPath();\n this.context.moveTo(triangle.a.position[0], triangle.a.position[1]);\n this.context.lineTo(triangle.b.position[0], triangle.b.position[1]);\n this.context.lineTo(triangle.c.position[0], triangle.c.position[1]);\n this.context.closePath();\n this.context.globalAlpha = 0.3;\n this.context.strokeStyle = color;\n this.context.fillStyle = color;\n this.context.stroke();\n this.context.fill();\n }\n }\n }\n return this;\n};\n\n/**\n * @class WebGL Renderer\n * @author Matthew Wagerfield\n */\nFSS.WebGLRenderer = function() {\n FSS.Renderer.call(this);\n this.element = document.createElement('canvas');\n this.element.style.display = 'block';\n\n // Set initial vertex and light count\n this.vertices = null;\n this.lights = null;\n\n // Create parameters object\n var parameters = {\n preserveDrawingBuffer: false,\n premultipliedAlpha: true,\n antialias: true,\n stencil: true,\n alpha: true\n };\n\n // Create and configure the gl context\n this.gl = this.getContext(this.element, parameters);\n\n // Set the internal support flag\n this.unsupported = !this.gl;\n\n // Setup renderer\n if (this.unsupported) {\n return 'WebGL is not supported by your browser.';\n } else {\n this.gl.clearColor(0.0, 0.0, 0.0, 0.0);\n this.gl.enable(this.gl.DEPTH_TEST);\n this.setSize(this.element.width, this.element.height);\n }\n};\n\nFSS.WebGLRenderer.prototype = Object.create(FSS.Renderer.prototype);\n\nFSS.WebGLRenderer.prototype.getContext = function(canvas, parameters) {\n var context = false;\n try {\n if (!(context = canvas.getContext('experimental-webgl', parameters))) {\n throw 'Error creating WebGL context.';\n }\n } catch (error) {\n console.error(error);\n }\n return context;\n};\n\nFSS.WebGLRenderer.prototype.setSize = function(width, height) {\n FSS.Renderer.prototype.setSize.call(this, width, height);\n if (this.unsupported) return;\n\n // Set the size of the canvas element\n this.element.width = width;\n this.element.height = height;\n\n // Set the size of the gl viewport\n this.gl.viewport(0, 0, width, height);\n return this;\n};\n\nFSS.WebGLRenderer.prototype.clear = function() {\n FSS.Renderer.prototype.clear.call(this);\n if (this.unsupported) return;\n this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);\n return this;\n};\n\nFSS.WebGLRenderer.prototype.render = function(scene) {\n FSS.Renderer.prototype.render.call(this, scene);\n if (this.unsupported) return;\n var m,mesh, t,tl,triangle, l,light,\n attribute, uniform, buffer, data, location,\n update = false, lights = scene.lights.length,\n index, v,vl,vetex,vertices = 0;\n\n // Clear context\n this.clear();\n\n // Build the shader program\n if (this.lights !== lights) {\n this.lights = lights;\n if (this.lights > 0) {\n this.buildProgram(lights);\n } else {\n return;\n }\n }\n\n // Update program\n if (!!this.program) {\n\n // Increment vertex counter\n for (m = scene.meshes.length - 1; m >= 0; m--) {\n mesh = scene.meshes[m];\n if (mesh.geometry.dirty) update = true;\n mesh.update(scene.lights, false);\n vertices += mesh.geometry.triangles.length*3;\n }\n\n // Compare vertex counter\n if (update || this.vertices !== vertices) {\n this.vertices = vertices;\n\n // Build buffers\n for (attribute in this.program.attributes) {\n buffer = this.program.attributes[attribute];\n buffer.data = new FSS.Array(vertices*buffer.size);\n\n // Reset vertex index\n index = 0;\n\n // Update attribute buffer data\n for (m = scene.meshes.length - 1; m >= 0; m--) {\n mesh = scene.meshes[m];\n\n for (t = 0, tl = mesh.geometry.triangles.length; t < tl; t++) {\n triangle = mesh.geometry.triangles[t];\n\n for (v = 0, vl = triangle.vertices.length; v < vl; v++) {\n vertex = triangle.vertices[v];\n switch (attribute) {\n case 'side':\n this.setBufferData(index, buffer, mesh.side);\n break;\n case 'position':\n this.setBufferData(index, buffer, vertex.position);\n break;\n case 'centroid':\n this.setBufferData(index, buffer, triangle.centroid);\n break;\n case 'normal':\n this.setBufferData(index, buffer, triangle.normal);\n break;\n case 'ambient':\n this.setBufferData(index, buffer, mesh.material.ambient.rgba);\n break;\n case 'diffuse':\n this.setBufferData(index, buffer, mesh.material.diffuse.rgba);\n break;\n }\n index++;\n }\n }\n }\n\n // Upload attribute buffer data\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer.buffer);\n this.gl.bufferData(this.gl.ARRAY_BUFFER, buffer.data, this.gl.DYNAMIC_DRAW);\n this.gl.enableVertexAttribArray(buffer.location);\n this.gl.vertexAttribPointer(buffer.location, buffer.size, this.gl.FLOAT, false, 0, 0);\n }\n }\n\n // Build uniform buffers\n this.setBufferData(0, this.program.uniforms.resolution, [this.width, this.height, this.width]);\n for (l = lights-1; l >= 0; l--) {\n light = scene.lights[l];\n this.setBufferData(l, this.program.uniforms.lightPosition, light.position);\n this.setBufferData(l, this.program.uniforms.lightAmbient, light.ambient.rgba);\n this.setBufferData(l, this.program.uniforms.lightDiffuse, light.diffuse.rgba);\n }\n\n // Update uniforms\n for (uniform in this.program.uniforms) {\n buffer = this.program.uniforms[uniform];\n location = buffer.location;\n data = buffer.data;\n switch (buffer.structure) {\n case '3f':\n this.gl.uniform3f(location, data[0], data[1], data[2]);\n break;\n case '3fv':\n this.gl.uniform3fv(location, data);\n break;\n case '4fv':\n this.gl.uniform4fv(location, data);\n break;\n }\n }\n }\n\n // Draw those lovely triangles\n this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vertices);\n return this;\n};\n\nFSS.WebGLRenderer.prototype.setBufferData = function(index, buffer, value) {\n if (FSS.Utils.isNumber(value)) {\n buffer.data[index*buffer.size] = value;\n } else {\n for (var i = value.length - 1; i >= 0; i--) {\n buffer.data[index*buffer.size+i] = value[i];\n }\n }\n};\n\n/**\n * Concepts taken from three.js WebGLRenderer\n * @see https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js\n */\nFSS.WebGLRenderer.prototype.buildProgram = function(lights) {\n if (this.unsupported) return;\n\n // Create shader source\n var vs = FSS.WebGLRenderer.VS(lights);\n var fs = FSS.WebGLRenderer.FS(lights);\n\n // Derive the shader fingerprint\n var code = vs + fs;\n\n // Check if the program has already been compiled\n if (!!this.program && this.program.code === code) return;\n\n // Create the program and shaders\n var program = this.gl.createProgram();\n var vertexShader = this.buildShader(this.gl.VERTEX_SHADER, vs);\n var fragmentShader = this.buildShader(this.gl.FRAGMENT_SHADER, fs);\n\n // Attach an link the shader\n this.gl.attachShader(program, vertexShader);\n this.gl.attachShader(program, fragmentShader);\n this.gl.linkProgram(program);\n\n // Add error handling\n if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {\n var error = this.gl.getError();\n var status = this.gl.getProgramParameter(program, this.gl.VALIDATE_STATUS);\n console.error('Could not initialise shader.\\nVALIDATE_STATUS: '+status+'\\nERROR: '+error);\n return null;\n }\n\n // Delete the shader\n this.gl.deleteShader(fragmentShader);\n this.gl.deleteShader(vertexShader);\n\n // Set the program code\n program.code = code;\n\n // Add the program attributes\n program.attributes = {\n side: this.buildBuffer(program, 'attribute', 'aSide', 1, 'f' ),\n position: this.buildBuffer(program, 'attribute', 'aPosition', 3, 'v3'),\n centroid: this.buildBuffer(program, 'attribute', 'aCentroid', 3, 'v3'),\n normal: this.buildBuffer(program, 'attribute', 'aNormal', 3, 'v3'),\n ambient: this.buildBuffer(program, 'attribute', 'aAmbient', 4, 'v4'),\n diffuse: this.buildBuffer(program, 'attribute', 'aDiffuse', 4, 'v4')\n };\n\n // Add the program uniforms\n program.uniforms = {\n resolution: this.buildBuffer(program, 'uniform', 'uResolution', 3, '3f', 1 ),\n lightPosition: this.buildBuffer(program, 'uniform', 'uLightPosition', 3, '3fv', lights),\n lightAmbient: this.buildBuffer(program, 'uniform', 'uLightAmbient', 4, '4fv', lights),\n lightDiffuse: this.buildBuffer(program, 'uniform', 'uLightDiffuse', 4, '4fv', lights)\n };\n\n // Set the renderer program\n this.program = program;\n\n // Enable program\n this.gl.useProgram(this.program);\n\n // Return the program\n return program;\n};\n\nFSS.WebGLRenderer.prototype.buildShader = function(type, source) {\n if (this.unsupported) return;\n\n // Create and compile shader\n var shader = this.gl.createShader(type);\n this.gl.shaderSource(shader, source);\n this.gl.compileShader(shader);\n\n // Add error handling\n if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n console.error(this.gl.getShaderInfoLog(shader));\n return null;\n }\n\n // Return the shader\n return shader;\n};\n\nFSS.WebGLRenderer.prototype.buildBuffer = function(program, type, identifier, size, structure, count) {\n var buffer = {buffer:this.gl.createBuffer(), size:size, structure:structure, data:null};\n\n // Set the location\n switch (type) {\n case 'attribute':\n buffer.location = this.gl.getAttribLocation(program, identifier);\n break;\n case 'uniform':\n buffer.location = this.gl.getUniformLocation(program, identifier);\n break;\n }\n\n // Create the buffer if count is provided\n if (!!count) {\n buffer.data = new FSS.Array(count*size);\n }\n\n // Return the buffer\n return buffer;\n};\n\nFSS.WebGLRenderer.VS = function(lights) {\n var shader = [\n\n // Precision\n 'precision mediump float;',\n\n // Lights\n '#define LIGHTS ' + lights,\n\n // Attributes\n 'attribute float aSide;',\n 'attribute vec3 aPosition;',\n 'attribute vec3 aCentroid;',\n 'attribute vec3 aNormal;',\n 'attribute vec4 aAmbient;',\n 'attribute vec4 aDiffuse;',\n\n // Uniforms\n 'uniform vec3 uResolution;',\n 'uniform vec3 uLightPosition[LIGHTS];',\n 'uniform vec4 uLightAmbient[LIGHTS];',\n 'uniform vec4 uLightDiffuse[LIGHTS];',\n\n // Varyings\n 'varying vec4 vColor;',\n\n // Main\n 'void main() {',\n\n // Create color\n 'vColor = vec4(0.0);',\n\n // Calculate the vertex position\n 'vec3 position = aPosition / uResolution * 2.0;',\n\n // Iterate through lights\n 'for (int i = 0; i < LIGHTS; i++) {',\n 'vec3 lightPosition = uLightPosition[i];',\n 'vec4 lightAmbient = uLightAmbient[i];',\n 'vec4 lightDiffuse = uLightDiffuse[i];',\n\n // Calculate illuminance\n 'vec3 ray = normalize(lightPosition - aCentroid);',\n 'float illuminance = dot(aNormal, ray);',\n 'if (aSide == 0.0) {',\n 'illuminance = max(illuminance, 0.0);',\n '} else if (aSide == 1.0) {',\n 'illuminance = abs(min(illuminance, 0.0));',\n '} else if (aSide == 2.0) {',\n 'illuminance = max(abs(illuminance), 0.0);',\n '}',\n\n // Calculate ambient light\n 'vColor += aAmbient * lightAmbient;',\n\n // Calculate diffuse light\n 'vColor += aDiffuse * lightDiffuse * illuminance;',\n '}',\n\n // Clamp color\n 'vColor = clamp(vColor, 0.0, 1.0);',\n\n // Set gl_Position\n 'gl_Position = vec4(position, 1.0);',\n\n '}'\n\n // Return the shader\n ].join('\\n');\n return shader;\n};\n\nFSS.WebGLRenderer.FS = function(lights) {\n var shader = [\n\n // Precision\n 'precision mediump float;',\n\n // Varyings\n 'varying vec4 vColor;',\n\n // Main\n 'void main() {',\n\n // Set gl_FragColor\n 'gl_FragColor = vColor;',\n\n '}'\n\n // Return the shader\n ].join('\\n');\n return shader;\n};\n\n/**\n * @class SVG Renderer\n * @author Matthew Wagerfield\n */\nFSS.SVGRenderer = function() {\n FSS.Renderer.call(this);\n this.element = document.createElementNS(FSS.SVGNS, 'svg');\n this.element.setAttribute('xmlns', FSS.SVGNS);\n this.element.setAttribute('version', '1.1');\n this.element.style.display = 'block';\n this.setSize(300, 150);\n};\n\nFSS.SVGRenderer.prototype = Object.create(FSS.Renderer.prototype);\n\nFSS.SVGRenderer.prototype.setSize = function(width, height) {\n FSS.Renderer.prototype.setSize.call(this, width, height);\n this.element.setAttribute('width', width);\n this.element.setAttribute('height', height);\n return this;\n};\n\nFSS.SVGRenderer.prototype.clear = function() {\n FSS.Renderer.prototype.clear.call(this);\n for (var i = this.element.childNodes.length - 1; i >= 0; i--) {\n this.element.removeChild(this.element.childNodes[i]);\n }\n return this;\n};\n\nFSS.SVGRenderer.prototype.render = function(scene) {\n FSS.Renderer.prototype.render.call(this, scene);\n var m,mesh, t,triangle, points, style;\n\n // Update Meshes\n for (m = scene.meshes.length - 1; m >= 0; m--) {\n mesh = scene.meshes[m];\n if (mesh.visible) {\n mesh.update(scene.lights, true);\n\n // Render Triangles\n for (t = mesh.geometry.triangles.length - 1; t >= 0; t--) {\n triangle = mesh.geometry.triangles[t];\n if (triangle.polygon.parentNode !== this.element) {\n this.element.appendChild(triangle.polygon);\n }\n points = this.formatPoint(triangle.a)+' ';\n points += this.formatPoint(triangle.b)+' ';\n points += this.formatPoint(triangle.c);\n style = this.formatStyle(triangle.color.format());\n triangle.polygon.setAttributeNS(null, 'points', points);\n triangle.polygon.setAttributeNS(null, 'style', style);\n }\n }\n }\n return this;\n};\n\nFSS.SVGRenderer.prototype.formatPoint = function(vertex) {\n return (this.halfWidth+vertex.position[0])+','+(this.halfHeight-vertex.position[1]);\n};\n\nFSS.SVGRenderer.prototype.formatStyle = function(color) {\n var style = 'fill:'+color+';';\n style += 'stroke:'+color+';';\n return style;\n};\n\n\n\n////////////////////////////////\n////////////////////////////////\n////////////////////////////////\n\n\n(function(){\n if(!document.getElementById('ffshadeoutput')){\n return false;\n }\n //------------------------------\n // Mesh Properties\n //------------------------------\n var MESH = {\n width: 1.8,\n height: 1.8,\n depth: 10,\n segments: 16,\n slices: 8,\n xRange: 0.8,\n yRange: 0.1,\n zRange: 1.0,\n ambient: '#555555',\n diffuse: '#696969',\n speed: 0.0001\n };\n\n //------------------------------\n // Light Properties\n //------------------------------\n var LIGHT = {\n count: 2,\n xyScalar: 1,\n zOffset: 100,\n ambient: '#1C2B36',\n diffuse: '#3BC0C3',\n speed: 0.0002,\n gravity: 500,\n dampening: 0.95,\n minLimit: 10,\n maxLimit: null,\n minDistance: 20,\n maxDistance: 400,\n autopilot: true,\n draw: false,\n bounds: FSS.Vector3.create(),\n step: FSS.Vector3.create(\n Math.randomInRange(0.2, 1.0),\n Math.randomInRange(0.2, 1.0),\n Math.randomInRange(0.2, 1.0)\n )\n };\n\n //------------------------------\n // Render Properties\n //------------------------------\n\n var RENDER = {\n renderer: 'canvas'\n };\n\n //------------------------------\n // Global Properties\n //------------------------------\n var now, start = Date.now();\n var center = FSS.Vector3.create();\n var attractor = FSS.Vector3.create();\n var container = document.getElementById('ffshade');\n var output = document.getElementById('ffshadeoutput');\n var renderer, scene, mesh, geometry, material;\n var canvasRenderer;\n var gui, autopilotController;\n //------------------------------\n // Methods\n //------------------------------\n function initialise() {\n createRenderer();\n createScene();\n createMesh();\n createLights();\n addEventListeners();\n resize(container.offsetWidth, container.offsetHeight);\n animate();\n }\n\n function createRenderer() {\n canvasRenderer = new FSS.CanvasRenderer();\n setRenderer(RENDER.renderer);\n }\n\n function setRenderer(index) {\n if (renderer) {\n output.removeChild(renderer.element);\n }\n\n renderer = canvasRenderer;\n\n renderer.setSize(container.offsetWidth, container.offsetHeight);\n output.appendChild(renderer.element);\n }\n\n function createScene() {\n scene = new FSS.Scene();\n }\n\n function createMesh() {\n scene.remove(mesh);\n renderer.clear();\n geometry = new FSS.Plane(MESH.width * renderer.width, MESH.height * renderer.height, MESH.segments, MESH.slices);\n material = new FSS.Material(MESH.ambient, MESH.diffuse);\n mesh = new FSS.Mesh(geometry, material);\n scene.add(mesh);\n\n // Augment vertices for animation\n var v, vertex;\n for (v = geometry.vertices.length - 1; v >= 0; v--) {\n vertex = geometry.vertices[v];\n vertex.anchor = FSS.Vector3.clone(vertex.position);\n vertex.step = FSS.Vector3.create(\n Math.randomInRange(0.2, 1.0),\n Math.randomInRange(0.2, 1.0),\n Math.randomInRange(0.2, 1.0)\n );\n vertex.time = Math.randomInRange(0, Math.PIM2);\n }\n }\n\n function createLights() {\n var l, light;\n for (l = scene.lights.length - 1; l >= 0; l--) {\n light = scene.lights[l];\n scene.remove(light);\n }\n renderer.clear();\n for (l = 0; l < LIGHT.count; l++) {\n light = new FSS.Light(LIGHT.ambient, LIGHT.diffuse);\n light.ambientHex = light.ambient.format();\n light.diffuseHex = light.diffuse.format();\n scene.add(light);\n\n // Augment light for animation\n light.mass = Math.randomInRange(0.5, 1);\n light.velocity = FSS.Vector3.create();\n light.acceleration = FSS.Vector3.create();\n light.force = FSS.Vector3.create();\n\n // Ring SVG Circle\n light.ring = document.createElementNS(FSS.SVGNS, 'circle');\n light.ring.setAttributeNS(null, 'stroke', light.ambientHex);\n light.ring.setAttributeNS(null, 'stroke-width', '0.5');\n light.ring.setAttributeNS(null, 'fill', 'none');\n light.ring.setAttributeNS(null, 'r', '10');\n\n // Core SVG Circle\n light.core = document.createElementNS(FSS.SVGNS, 'circle');\n light.core.setAttributeNS(null, 'fill', light.diffuseHex);\n light.core.setAttributeNS(null, 'r', '4');\n }\n }\n\n function resize(width, height) {\n renderer.setSize(width, height);\n FSS.Vector3.set(center, renderer.halfWidth, renderer.halfHeight);\n createMesh();\n }\n\n function animate() {\n now = Date.now() - start;\n update();\n render();\n requestAnimationFrame(animate);\n }\n\n function update() {\n var ox, oy, oz, l, light, v, vertex, offset = MESH.depth/2;\n\n // Update Bounds\n FSS.Vector3.copy(LIGHT.bounds, center);\n FSS.Vector3.multiplyScalar(LIGHT.bounds, LIGHT.xyScalar);\n\n // Update Attractor\n FSS.Vector3.setZ(attractor, LIGHT.zOffset);\n\n // Overwrite the Attractor position\n if (LIGHT.autopilot) {\n ox = Math.sin(LIGHT.step[0] * now * LIGHT.speed);\n oy = Math.cos(LIGHT.step[1] * now * LIGHT.speed);\n FSS.Vector3.set(attractor,\n LIGHT.bounds[0]*ox,\n LIGHT.bounds[1]*oy,\n LIGHT.zOffset);\n }\n\n // Animate Lights\n for (l = scene.lights.length - 1; l >= 0; l--) {\n light = scene.lights[l];\n\n // Reset the z position of the light\n FSS.Vector3.setZ(light.position, LIGHT.zOffset);\n\n // Calculate the force Luke!\n var D = Math.clamp(FSS.Vector3.distanceSquared(light.position, attractor), LIGHT.minDistance, LIGHT.maxDistance);\n var F = LIGHT.gravity * light.mass / D;\n FSS.Vector3.subtractVectors(light.force, attractor, light.position);\n FSS.Vector3.normalise(light.force);\n FSS.Vector3.multiplyScalar(light.force, F);\n\n // Update the light position\n FSS.Vector3.set(light.acceleration);\n FSS.Vector3.add(light.acceleration, light.force);\n FSS.Vector3.add(light.velocity, light.acceleration);\n FSS.Vector3.multiplyScalar(light.velocity, LIGHT.dampening);\n FSS.Vector3.limit(light.velocity, LIGHT.minLimit, LIGHT.maxLimit);\n FSS.Vector3.add(light.position, light.velocity);\n }\n\n // Animate Vertices\n for (v = geometry.vertices.length - 1; v >= 0; v--) {\n vertex = geometry.vertices[v];\n ox = Math.sin(vertex.time + vertex.step[0] * now * MESH.speed);\n oy = Math.cos(vertex.time + vertex.step[1] * now * MESH.speed);\n oz = Math.sin(vertex.time + vertex.step[2] * now * MESH.speed);\n FSS.Vector3.set(vertex.position,\n MESH.xRange*geometry.segmentWidth*ox,\n MESH.yRange*geometry.sliceHeight*oy,\n MESH.zRange*offset*oz - offset);\n FSS.Vector3.add(vertex.position, vertex.anchor);\n }\n\n // Set the Geometry to dirty\n geometry.dirty = true;\n }\n\n function render() {\n renderer.render(scene);\n\n // Draw Lights\n if (LIGHT.draw) {\n var l, lx, ly, light;\n for (l = scene.lights.length - 1; l >= 0; l--) {\n light = scene.lights[l];\n lx = light.position[0];\n ly = light.position[1];\n renderer.context.lineWidth = 0.5;\n renderer.context.beginPath();\n renderer.context.arc(lx, ly, 10, 0, Math.PIM2);\n renderer.context.strokeStyle = light.ambientHex;\n renderer.context.stroke();\n renderer.context.beginPath();\n renderer.context.arc(lx, ly, 4, 0, Math.PIM2);\n renderer.context.fillStyle = light.diffuseHex;\n renderer.context.fill();\n \n }\n }\n }\n\n function addEventListeners() {\n window.addEventListener('resize', onWindowResize);\n //container.addEventListener('mousemove', onMouseMove);\n }\n\n //------------------------------\n // Callbacks\n //------------------------------\n\n function onMouseMove(event) {\n FSS.Vector3.set(attractor, event.x, renderer.height - event.y);\n FSS.Vector3.subtract(attractor, center);\n }\n\n function onWindowResize(event) {\n resize(container.offsetWidth, container.offsetHeight);\n render();\n }\n\n\n // Let there be light!\n if(output !== null){\n //initialise();\n window.initFFS = initialise;\n }\n\n})(); "]}