From c3003f65101ea0a356e892bc683514a2e5a66504 Mon Sep 17 00:00:00 2001 From: spearce Date: Fri, 20 Dec 2013 16:39:14 -0500 Subject: [PATCH 01/15] Add info about template for Checkbox problem type Change text to "click Checkboxes on the Common Problem Types tab" and add image of checkbox button --- .../source/Images/ProbComponent_CheckboxIcon.gif | Bin 0 -> 1692 bytes docs/course_authors/source/common_problems.rst | 7 ++++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 docs/course_authors/source/Images/ProbComponent_CheckboxIcon.gif diff --git a/docs/course_authors/source/Images/ProbComponent_CheckboxIcon.gif b/docs/course_authors/source/Images/ProbComponent_CheckboxIcon.gif new file mode 100644 index 0000000000000000000000000000000000000000..f3ef4bdae69ad86e91fa663d1625153790cebb6c GIT binary patch literal 1692 zcmaJ>cUTi=96kcXRJ07S$`Fs>fSMf$B$_BBL}-m=7F0x!KZSnR@)LLk(E@|-K=iWl+{(Y-0SWi%gHP1>>X{pJ5tlEYwqg5rER@lsSOT? zYwz4Yl$*aP3Jnv-pz5u4x`7Rnn4G-ApfGV)->CLZ&qi3jF%l`MsNH?wSO^r|r0WgY z9M#e@qSX!7cMNKE1NEJQ4V^>Uj=`qx;pU!^=I-Ift|5&^Z>XWF10~6N8Vm+mk07fO5DZe25tY-Vf&f;Dl~M&JMG?@T2t}ZA7?-H8^q&^wiYZw{MVV-a zB1Yv@HKd@@DKtY%lR%N^|DkgE6k3G^!0+n)PhnM1f&!)nz$!FODTeiMCxexO!&kx( zhAM+lR5tk){i0C}RYju;kRQkbokOIE1dUg@OyET#jxVCZAVduN3b;hQ0!1p7aNPOc zOumN)ohD?m>2z-<+s)HmNEfFwawYG$jA^-sD99ChX928~ zZh<92B`OCeTINWnt;Jn9t=?O%WcpfY({ic$VyK3L{ntTHZt2rwm`=r3znBU>jOf#@ z)W_QB&0l~1@%r~yFMoUS{MTQ8e)e?y$>T>4AB>HT3=a(s^!N4NzjwE%yQ{N9*WPxg zwWYbKv7ugDS6fqEb^BIjMR{52%^TNCuKo05vF7RzS1w<=SX6kS;C%k~=gywV`|k9q zles63e|s$F=#j(OhrT&@;OqTg?aSJ`=gZw+WbWFzBV&7dTI#l~pQj`zB_^ojx5Qy8 zWvl{4J&7b)g}j1_uQO`1^gbRVr3%vz=FV9sg zdE6DtIcyJimYXY+L8nnEWYV$^U7VLLS-i-J=m;)!SYU5wYcqe|2Xn3GSXo+_zdw7H z+06F{Gw`M+#yBGYaC~I~7zW93GyLxW{F~C_3LlbfmcT(&6UI5(G!j_-Fu1Utv?af7 z=H(j|7nYVQ8t*=cU;5;+AblGgyS`)m*E1dwAgL4Y+ty%eC6`OmM~V& zPR{Nvg}fLhmOjN`SrJr`;fTXq6aDvQ;f<7GgcGYWsq`o7NPihCZ9UfW%22-Mp%5b}r89ba=t~=S_{rGfG*aq^pm+iXpRe Yv1yv|d!<{=%pL4ApAC4Y0l@OV0TdjkF#rGn literal 0 HcmV?d00001 diff --git a/docs/course_authors/source/common_problems.rst b/docs/course_authors/source/common_problems.rst index e213db737529..b5ee51779c0f 100644 --- a/docs/course_authors/source/common_problems.rst +++ b/docs/course_authors/source/common_problems.rst @@ -48,13 +48,14 @@ Create a Checkbox Problem ========================== #. Under **Add New Component**, click **Problem**. -#. In the **Select Problem Component Type** screen, click **Blank Common - Problem** on the **Common Problem Types** tab. +#. In the **Select Problem Component Type** screen, click **Checkboxes** on the **Common Problem Types** tab. #. In the Problem component that appears, click **Edit**. #. In the component editor, replace the default text with the text of your problem. Enter each answer option on its own line. #. Select all the answer options, and then click the checkbox button. - + + .. image:: Images/ProbComponent_CheckboxIcon.gif + When you do this, brackets appear next to each answer choice. #. Add an **x** between the brackets for the correct answer or answers. From 7fa8bffde475e5e1dbb1b5769fb1d8c5f5007cd9 Mon Sep 17 00:00:00 2001 From: spearce Date: Fri, 20 Dec 2013 16:43:54 -0500 Subject: [PATCH 02/15] Correct minor formatting error --- docs/course_authors/source/open_response_assessment.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/course_authors/source/open_response_assessment.rst b/docs/course_authors/source/open_response_assessment.rst index 034224adfe9e..e4b723c62e42 100644 --- a/docs/course_authors/source/open_response_assessment.rst +++ b/docs/course_authors/source/open_response_assessment.rst @@ -214,7 +214,7 @@ Step 4. Set the Assessment Type and Scoring .. note:: After you release your problem to students in your live course, make sure you don't make any changes to the code for the assessment type and scoring. Changing - this code can cause errors in live courses.* + this code can cause errors in live courses. To set the assessment type and scoring for your open response assessment, you'll enter code that specifies the type and order of assessments to use along with @@ -255,6 +255,9 @@ The problem that includes this code has the following characteristics. - To advance to the AI assessment, the response must have a peer assessment score of 4 or greater. +.. note:: If a response's score isn't high enough for the response to move to the next + assessment, + Set the Type and Scoring ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -377,7 +380,7 @@ Open response assessments include the following settings. | | | | | **Note** *Every problem must have a problem weight of at least | | | one point. Problems that have a problem weight of zero points | -| | don't appear on the instructor dashboard. | +| | don't appear on the instructor dashboard.* | +---------------------------------------------+--------------------------------------------------------------------+ | **Required Peer Grading** | This setting specifies the number of responses that each student | | | who submits a response has to grade before the student receives a | From 41d2c2171040b6a076db4168c581d225944b3f68 Mon Sep 17 00:00:00 2001 From: spearce Date: Mon, 23 Dec 2013 17:31:13 -0500 Subject: [PATCH 03/15] Add JSInput template information Update Advanced Problems page with Custom JavaScript Display and Grading (JS Input) problem info. Delete separate page for JS Input problems. Update Appendix F with new code for sample JS Input problem. --- .../source/advanced_problems.rst | 245 ++-- docs/course_authors/source/appendices/f.rst | 1132 ++++------------- .../source/javascript_input.rst | 113 -- 3 files changed, 381 insertions(+), 1109 deletions(-) delete mode 100644 docs/course_authors/source/javascript_input.rst diff --git a/docs/course_authors/source/advanced_problems.rst b/docs/course_authors/source/advanced_problems.rst index f327ce04444c..88814e597584 100644 --- a/docs/course_authors/source/advanced_problems.rst +++ b/docs/course_authors/source/advanced_problems.rst @@ -12,6 +12,9 @@ templates for these problems, but the problems open directly in the - :ref:`Circuit Schematic Builder` In circuit schematic problems, students create and modify circuits on an interactive grid and submit computer-generated analyses of the circuits for grading. +- :ref:`Custom JavaScript Display and Grading` With custom JavaScript display + and grading problems, you can incorporate problem types that you've created + in HTML into Studio via an IFrame. - :ref:`Write-Your-Own-Grader` Write-your-own-grader problems evaluate students' responses using an embedded Python script that you create. These problems can be any type. @@ -19,8 +22,6 @@ templates for these problems, but the problems open directly in the or objects to a specific location on an image. - :ref:`Image Mapped Input` Image mapped input problems require students to click a specific location on an image. -- :ref:`JavaScript Input` JavaScript input problems allow you to incorporate - problem types that you've created in HTML into Studio via an IFrame. - :ref:`Math Expression Input` Math expression input problems require students to enter a mathematical expression as text, such as e=m\*c^2. @@ -58,6 +59,130 @@ Create a Circuit Schematic Builder Problem #. In the component editor, replace the example code with your own code. #. Click **Save**. +.. _Custom JavaScript Display and Grading: + +Custom JavaScript Display and Grading +------------------------------------- + +Custom JavaScript display and grading problems allow you to create your own learning tool +using HTML and other standard Internet languages and then add the tool directly +into Studio. When you use this problem type, Studio embeds your tool in an +inline frame (IFrame) so that your students can interact with it in the LMS. You can grade +your students' work using JavaScript and some basic Python, and the grading +is integrated into the edX grading system. + +This problem type doesn't appear in the menu of advanced problems in Studio. To +create a JavaScript input problem type, you'll create a blank advanced problem, +and then enter your code into the component editor. + +.. image:: /Images/JavaScriptInputExample.gif + +Create a Custom JavaScript Display and Grading Problem +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. Create your JavaScript application, and then upload all files associated with + that application to the **Files & Uploads** page. +#. In the unit where you want to create the problem, click **Problem** + under **Add New Component**, and then click the **Advanced** tab. +#. Click **Custom JavaScript Display and Grading**. +#. In the component that appears, click **Edit**. +#. In the component editor, modify the example code according to your problem. + + - If some elements of your problem are located in different places, you need to + bypass the same-origin policy (SOP). To do this, change **sop="false"** + in line 8 to **sop="true"**. For more information, see + `same-origin policy `_. + +#. Click the **Settings** tab. +#. Set **Maximum Attempts** to a number larger than zero. +#. Click **Save**. + +To re-create the example problem above, follow these steps. + +#. Go to :ref:`Appendix F` and use the code samples to create the following files. + + - webGLDemo.html + - webGLDemo.js + - webGLDemo.css + - three.min.js + + **Note** *If you need to bypass the SOP, you'll also create a jschannel.js file.* + +#. On the **Files & Uploads** page, upload the files you just created. +#. Create a new custom JavaScript display and grading problem component. +#. On the **Settings** tab, set **Maximum Attempts** to a number larger than + zero. +#. In the problem component editor, paste the code below. +#. Click **Save.** + + + +JavaScript Input Problem Code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + + In the image below, click the cone. + + + + + + + + +.. note:: When you create a JavaScript Input problem, keep the following in mind. + + - The webGLDemo.js file defines the three JavaScript functions (**WebGLDemo.getGrade**, + **WebGLDemo.getState**, and **WebGLDemo.setState**). + + - The JavaScript input problem code uses **WebGLDemo.getGrade**, **WebGLDemo.getState**, + and **WebGLDemo.setState** to grade, save, or restore a problem. These functions must + be global in scope. + + - **WebGLDemo.getState** and **WebGLDemo.setState** are optional. You only have to define + these functions if you want to conserve the state of the problem. + + - **Width** and **height** represent the dimensions of the IFrame that holds the + application. + + - When the problem opens, the cone and the cube are both blue, or "unselected." When + you click either shape once, the shape becomes yellow, or "selected." To unselect + the shape, click it again. Continue clicking the shape to select and unselect it. + + - The response is graded as correct if the cone is selected (yellow) when the user + clicks **Check**. + + - Clicking **Check** or **Save** registers the problem's current state. + + + .. _Write-Your-Own-Grader: Write-Your-Own-Grader ("Custom Python-Evaluated Input") @@ -85,7 +210,7 @@ To create a write-your-own-grader problem: #. Click **Save**. For more information about write-your-own-grader problems, see `CustomResponse XML and Python -Script `_. +Script `_. .. _Drag and Drop: @@ -136,120 +261,8 @@ To create a image mapped input problem: #. In the component editor, replace the example code with your own code. #. Click **Save**. -.. _JavaScript Input: - -JavaScript Input ----------------- - -The JavaScript Input problem type allows you to create your own learning tool -using HTML and other standard Internet languages and then add the tool directly -into Studio. When you use this problem type, Studio embeds your tool in an -IFrame so that your students can interact with it in the LMS. You can grade -your students' work using JavaScript and some basic Python, and the grading -is integrated into the edX grading system. - -This problem type doesn't appear in the menu of advanced problems in Studio. To -create a JavaScript input problem type, you'll create a blank advanced problem, -and then enter your code into the component editor. - -.. image:: /Images/JavaScriptInputExample.gif - -Create a JavaScript Input Problem -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#. Create your JavaScript application, and then upload all files associated with - that application to the **Files & Uploads** page. -#. In the unit where you want to create the problem, click **Problem** - under **Add New Component**, and then click the **Advanced** tab. -#. Click **Blank Advanced Problem**. -#. In the component that appears, click **Edit**. -#. Click the **Settings** tab. -#. Set **Maximum Attempts** to a number larger than zero. -#. In the component editor, enter your code. -#. Click **Save**. - -To re-create the example problem above, follow these steps. - -#. Go to :ref:`Appendix F` and use the code samples to create the following files: - - - webGLDemo.html - - webGLDemo.js - - webGLDemo.css - - three.min.js - -#. On the **Files & Uploads** page, upload the four files you just created. -#. Create a new blank advanced problem component. -#. On the **Settings** tab, set **Maximum Attempts** to a number larger than - zero. -#. In the problem component editor, paste the code below. -#. Click **Save.** - -JavaScript Input Problem Code -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - - In the image below, click the cone. - - - - - - - - -.. notes:: When you create a JavaScript Input problem, keep the following in mind. - - - The webGLDemo.js file defines the three JavaScript functions (**WebGLDemo.getGrade**, - **WebGLDemo.getState**, and **WebGLDemo.setState**). - - - The JavaScript input problem code uses **WebGLDemo.getGrade**, **WebGLDemo.getState**, - and **WebGLDemo.setState** to grade, save, or restore a problem. These functions must - be global in scope. - - - **WebGLDemo.getState** and **WebGLDemo.setState** are optional. You only have to define - these functions if you want to conserve the state of the problem. - - - **Width** and **height** represent the dimensions of the IFrame that holds the - application. - - - When the problem opens, the cone and the cube are both blue, or "unselected." When - you click either shape once, the shape becomes yellow, or "selected." To unselect - the shape, click it again. Continue clicking the shape to select and unselect it. - - - The response is graded as correct if the cone is selected (yellow) when the user - clicks **Check**. - - - Clicking **Check** or **Save** registers the problem's current state. - .. _Math Expression Input: Math Expression Input @@ -341,5 +354,3 @@ To create a problem with an adaptive hint: #. In the component that appears, click **Edit**. #. In the component editor, replace the example code with your own code. #. Click **Save**. - - diff --git a/docs/course_authors/source/appendices/f.rst b/docs/course_authors/source/appendices/f.rst index 94a9258656b9..be499a047a16 100644 --- a/docs/course_authors/source/appendices/f.rst +++ b/docs/course_authors/source/appendices/f.rst @@ -1,48 +1,72 @@ .. _Appendix F: -Appendix F - Files for the Example JavaScript Input Problem -=========================================================== +Appendix F - Files for the Example Custom JavaScript Display and Grading Problem +================================================================================ -For the example JavaScript Input problem, you need the following four files: +For the example custom JavaScript display and grading problem, you need the `three.min.js `_ +library file. + +- On the `three.js home page `_ page, click **Download** in + the left pane. After the .zip file has finished downloading, open it, and then + open the **build** folder to access the three.min.js file. + +Additionally, you need the following files. You can find the code to create each +of these files below. - :ref:`webGLDemo.html` - :ref:`webGLDemo.css` - :ref:`webGLDemo.js` -- :ref:`three.min.js` -To create these files, copy the code for each file into a text editor, and +To create these files, copy the code for each file into a text editor, and then save each file. Make sure to use the correct file name extension when you save each file. +After you create these files, add them to the **Files & Uploads** page in Studio. + +.. note:: If you need to bypass the same-origin policy (SOP), you also need the + `jschannel.js `_ file. + + - On the `jschannel.js `_ + web page, copy the code for the file into a text editor, and then save the file as **jschannel.js**. + .. _webGLDemo.html: webGLDemo.html -------------- +If you don't need to bypass the SOP, use the following code. + :: - - + - - - + + - -
- + + + +If you need to bypass the SOP, use the following code. + +:: + + + + + + - - + + +
- - + .. _webGLDemo.css: webGLDemo.css @@ -51,886 +75,236 @@ webGLDemo.css :: #container { - background-color: black; - width: 400px; - height:400px; + background-color: black; + width: 400px; + height:400px; } - + .. _webGLDemo.js: webGLDemo.js ------------ -:: +:: var WebGLDemo = (function() { - - var width = 400, height = 400; - var container, renderer, scene, camera, projector, - ambientlight, directionalLight, - cylinder, cube, nonSelectedMaterial, selectedMaterial; - // Revolutions per second - var angularSpeed = 0.5, lastTime = 0; - var state = { - 'selectedObjects': { + + var width = 400, height = 400; + var container, renderer, scene, camera, projector, + ambientlight, directionalLight, + cylinder, cube, nonSelectedMaterial, selectedMaterial; + // Revolutions per second + var angularSpeed = 0.5, lastTime = 0; + var state = { + 'selectedObjects': { 'cylinder': false, 'cube': false - } - }; - - function init() { - container = document.getElementById('container'); - // Renderer - renderer = new THREE.WebGLRenderer({antialias:true}); - renderer.setSize(width, height); - renderer.setClearColor(0x000000, 1); - container.appendChild(renderer.domElement); - - // Scene - scene = new THREE.Scene(); - - // Camera - camera = new THREE.PerspectiveCamera(45, width/height, 1, 1000); - camera.position.z = 700; - - unselectedMaterial = new THREE.MeshPhongMaterial({ - specular: '#a9fcff', - color: '#00abb1', - emissive: '#006063', - shininess: 100 - }); - - selectedMaterial = new THREE.MeshPhongMaterial({ - specular: '#a9fcff', - color: '#abb100', - emissive: '#606300', - shininess: 100 - }); - - // Cylinder: bottomRadius, topRadius, height, segmentsRadius, segmentsHeight - cylinder = new THREE.Mesh(new THREE.CylinderGeometry(0, 100, 150, 50, 50, false), unselectedMaterial); - cylinder.position.x = -125; - cylinder.overdraw = true; - scene.add(cylinder); - - // Cube - cube = new THREE.Mesh(new THREE.CubeGeometry(120, 120, 120), unselectedMaterial); - cube.position.x = 125; - cube.overdraw = true; - scene.add(cube); - - // Ambient light - ambientLight = new THREE.AmbientLight(0x222222); - scene.add(ambientLight); - - // Directional light - directionalLight = new THREE.DirectionalLight(0xffffff); - directionalLight.position.set(1, 1, 1).normalize(); - scene.add(directionalLight); - - // Used to select element with mouse click - projector = new THREE.Projector(); - - renderer.domElement.addEventListener('click', onMouseClick, false); - - // Start animation - animate(); - } - - // This function is executed on each animation frame - function animate() { - // Request new frame - requestAnimationFrame(animate); - render(); - } - - function render() { - // Update - var time = (new Date()).getTime(); - var timeDiff = time - lastTime; - var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000; - cylinder.rotation.x += angleChange; - cylinder.rotation.z += angleChange; - cube.rotation.x += angleChange; - cube.rotation.y += angleChange; - lastTime = time; - - // Render - renderer.render(scene, camera); - } - - function onMouseClick(event) { - var vector = new THREE.Vector3((event.clientX / width) * 2 - 1, - -(event.clientY / height) * 2 + 1, 1); - projector.unprojectVector(vector, camera); - - var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize()), - intersects = raycaster.intersectObjects(scene.children); - - if (intersects.length > 0) { - if (intersects[0].object === cylinder) { - state.selectedObjects.cylinder = !state.selectedObjects.cylinder; + } + }, + channel; + + // Establish a channel only if this application is embedded in an iframe. + // This will let the parent window communicate with this application using + // RPC and bypass SOP restrictions. + if (window.parent !== window) { + channel = Channel.build({ + window: window.parent, + origin: "*", + scope: "JSInput" + }); + + channel.bind("getGrade", getGrade); + channel.bind("getState", getState); + channel.bind("setState", setState); } - else if (intersects[0].object === cube) { - state.selectedObjects.cube = !state.selectedObjects.cube; + + function init() { + container = document.getElementById('container'); + // Renderer + // First check if WebGL is supported. If not, rely on the canvas + // render and use a scene with less triangles as it is slow. + var testCanvas = document.createElement("canvas"); + var webglContext = null; + var contextNames = ["experimental-webgl", "webgl", "moz-webgl", + "webkit-3d"]; + var radiusSegments, heightSegments; + for (var i = 0; i < contextNames.length; i++) { + try { + webglContext = testCanvas.getContext(contextNames[i]); + if (webglContext) { + break; + } + } + catch (e) { + } + } + + if (webglContext) { + renderer = new THREE.WebGLRenderer({antialias:true}); + radiusSegments = 50; + heightSegments = 50; + } + else { + renderer = new THREE.CanvasRenderer(); + radiusSegments = 10; + heightSegments = 10; + } + + renderer.setSize(width, height); + renderer.setClearColor(0x000000, 1); + container.appendChild(renderer.domElement); + + // Scene + scene = new THREE.Scene(); + + // Camera + camera = new THREE.PerspectiveCamera(45, width/height, 1, 1000); + camera.position.z = 700; + + // Materials + unselectedMaterial = new THREE.MeshPhongMaterial({ + specular: '#a9fcff', + color: '#00abb1', + emissive: '#006063', + shininess: 100 + }); + + selectedMaterial = new THREE.MeshPhongMaterial({ + specular: '#a9fcff', + color: '#abb100', + emissive: '#606300', + shininess: 100 + }); + + if (!webglContext) { + unselectedMaterial.overdraw = 1.0; + selectedMaterial.overdraw = 1.0; + } + + // Cylinder: bottomRadius, topRadius, height, segmentsRadius, + // segmentsHeight + cylinder = new THREE.Mesh(new THREE.CylinderGeometry(0, 100, 150, + radiusSegments, + heightSegments, + false), + unselectedMaterial); + cylinder.position.x = -125; + cylinder.overdraw = true; + scene.add(cylinder); + + // Cube + cube = new THREE.Mesh(new THREE.CubeGeometry(120, 120, 120), + unselectedMaterial); + cube.position.x = 125; + cube.overdraw = true; + scene.add(cube); + + // Ambient light + ambientLight = new THREE.AmbientLight(0x222222); + scene.add(ambientLight); + + // Directional light + directionalLight = new THREE.DirectionalLight(0xffffff); + directionalLight.position.set(1, 1, 1).normalize(); + scene.add(directionalLight); + + // Used to select element with mouse click + projector = new THREE.Projector(); + + renderer.domElement.addEventListener('click', onMouseClick, false); + + // Start animation + animate(); } - - updateMaterials(); - } - } - - function updateMaterials() { - if (state.selectedObjects.cylinder) { - cylinder.material = selectedMaterial; + + // This function is executed on each animation frame + function animate() { + // Request new frame + requestAnimationFrame(animate); + render(); } - else { - cylinder.material = unselectedMaterial; + + function render() { + // Update + var time = (new Date()).getTime(), + timeDiff = time - lastTime, + angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000; + cylinder.rotation.x += angleChange; + cylinder.rotation.z += angleChange; + cube.rotation.x += angleChange; + cube.rotation.y += angleChange; + lastTime = time; + + // Render + renderer.render(scene, camera); } - - if (state.selectedObjects.cube) { - cube.material = selectedMaterial; + + function onMouseClick(event) { + var vector, raycaster, intersects; + + vector = new THREE.Vector3((event.clientX / width) * 2 - 1, + -(event.clientY / height) * 2 + 1, 1); + projector.unprojectVector(vector, camera); + raycaster = new THREE.Raycaster(camera.position, + vector.sub(camera.position).normalize()); + intersects = raycaster.intersectObjects(scene.children); + + if (intersects.length > 0) { + if (intersects[0].object === cylinder) { + state.selectedObjects.cylinder = !state.selectedObjects.cylinder; + } + else if (intersects[0].object === cube) { + state.selectedObjects.cube = !state.selectedObjects.cube; + } + updateMaterials(); + } } - else { - cube.material = unselectedMaterial; + + function updateMaterials() { + if (state.selectedObjects.cylinder) { + cylinder.material = selectedMaterial; + } + else { + cylinder.material = unselectedMaterial; + } + + if (state.selectedObjects.cube) { + cube.material = selectedMaterial; + } + else { + cube.material = unselectedMaterial; + } } - } - - init(); - - function getState() { - return JSON.stringify(state); - } - - function setState(stateStr) { - state = JSON.parse(stateStr); - updateMaterials(); - } - - function getGrade() { - // The following return value may or may not be used to grade server-side. - // If getState and setState are used, then the Python grader also gets - // access to the return value of getState and can choose it instead to grade. - return JSON.stringify(state['selectedObjects']); - } - - return { - getState: getState, - setState: setState, - getGrade: getGrade - }; - }()); - -.. _three.min.js: + init(); -three.min.js ------------- + function getGrade() { + // The following return value may or may not be used to grade + // server-side. + // If getState and setState are used, then the Python grader also gets + // access to the return value of getState and can choose it instead to + // grade. + return JSON.stringify(state['selectedObjects']); + } -:: + function getState() { + return JSON.stringify(state); + } + + // This function will be called with 1 argument when JSChannel is not used, + // 2 otherwise. In the latter case, the first argument is a transaction + // object that will not be used here + // (see http://mozilla.github.io/jschannel/docs/) + function setState() { + stateStr = arguments.length === 1 ? arguments[0] : arguments[1]; + state = JSON.parse(stateStr); + updateMaterials(); + } - // three.js - https://github.com/mrdoob/three.js - 'use strict';var THREE={REVISION:"62"};self.console=self.console||{info:function(){},log:function(){},debug:function(){},warn:function(){},error:function(){}};String.prototype.trim=String.prototype.trim||function(){return this.replace(/^\s+|\s+$/g,"")};THREE.extend=function(a,b){if(Object.keys)for(var c=Object.keys(b),d=0,e=c.length;d>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1c?b:c<2/3?a+6*(b-a)*(2/3-c):a},b=0.5>=c?c*(1+b):c+b-c*b,c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a))return a=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a),this.r= - Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]),this},copy:function(a){this.r=a.r;this.g= - a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;return this},convertLinearToGamma:function(){this.r=Math.sqrt(this.r);this.g=Math.sqrt(this.g);this.b=Math.sqrt(this.b);return this},getHex:function(){return 255*this.r<<16^255*this.g<< - 8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(){var a={h:0,s:0,l:0};return function(){var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),h,g=(f+e)/2;if(f===e)f=h=0;else{var i=e-f,f=0.5>=g?i/(e+f):i/(2-e-f);switch(e){case b:h=(c-d)/i+(cf&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(i-h)/c,this._x=0.25*c, - this._y=(a+e)/c,this._z=(d+g)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-g)/c,this._x=(a+e)/c,this._y=0.25*c,this._z=(h+i)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+g)/c,this._y=(h+i)/c,this._z=0.25*c);this._updateEuler();return this},inverse:function(){this.conjugate().normalize();return this},conjugate:function(){this._x*=-1;this._y*=-1;this._z*=-1;this._updateEuler();return this},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x* - this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);return this},multiply:function(a,b){return void 0!==b?(console.warn("DEPRECATED: Quaternion's .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z,f= - a._w,h=b._x,g=b._y,i=b._z,k=b._w;this._x=c*k+f*h+d*i-e*g;this._y=d*k+f*g+e*h-c*i;this._z=e*k+f*i+c*g-d*h;this._w=f*k-c*h-d*g-e*i;this._updateEuler();return this},multiplyVector3:function(a){console.warn("DEPRECATED: Quaternion's .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)},slerp:function(a,b){var c=this._x,d=this._y,e=this._z,f=this._w,h=f*a._w+c*a._x+d*a._y+e*a._z;0>h?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z= - -a._z,h=-h):this.copy(a);if(1<=h)return this._w=f,this._x=c,this._y=d,this._z=e,this;var g=Math.acos(h),i=Math.sqrt(1-h*h);if(0.001>Math.abs(i))return this._w=0.5*(f+this._w),this._x=0.5*(c+this._x),this._y=0.5*(d+this._y),this._z=0.5*(e+this._z),this;h=Math.sin((1-b)*g)/i;g=Math.sin(b*g)/i;this._w=f*h+this._w*g;this._x=c*h+this._x*g;this._y=d*h+this._y*g;this._z=e*h+this._z*g;this._updateEuler();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w}, - fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];this._w=a[3];this._updateEuler();return this},toArray:function(){return[this._x,this._y,this._z,this._w]},clone:function(){return new THREE.Quaternion(this._x,this._y,this._z,this._w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; - THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, - b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector2's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-= - a.y;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y); - return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/ - b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a){this.x=a[0];this.y=a[1];return this},toArray:function(){return[this.x,this.y]},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; - THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+ - a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."), - this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x* - b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements,e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]); - this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,h=a.z,a=a.w,g=a*b+f*d-h*c,i=a*c+h*b-e*d,k=a*d+e*c-f*b,b=-e*b-f*c-h*d;this.x=g*a+b*-e+i*-h-k*-f;this.y=i*a+b*-f+k*-e-g*-h;this.z=k*a+b*-h+g*-f-i*-e;return this},transformDirection:function(a){var b=this.x,c=this.y,d=this.z,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]* - b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.y< - a.y?this.y=a.y:this.y>b.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length())}, - setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},cross:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector3's .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b);var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c= - a.x,d=a.y,e=a.z,f=b.x,h=b.y,g=b.z;this.x=d*g-e*h;this.y=e*f-c*g;this.z=c*h-d*f;return this},angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y,a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(){console.error("REMOVED: Vector3's setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code.")}, - setEulerFromQuaternion:function(){console.error("REMOVED: Vector3's setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code.")},getPositionFromMatrix:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return this},getScaleFromMatrix:function(a){var b=this.set(a.elements[0],a.elements[1],a.elements[2]).length(),c=this.set(a.elements[4],a.elements[5],a.elements[6]).length(),a=this.set(a.elements[8],a.elements[9],a.elements[10]).length(); - this.x=b;this.y=c;this.z=a;return this},getColumnFromMatrix:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a){this.x=a[0];this.y=a[1];this.z=a[2];return this},toArray:function(){return[this.x,this.y,this.z]},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}}; - THREE.extend(THREE.Vector3.prototype,{applyEuler:function(){var a=new THREE.Quaternion;return function(b){!1===b instanceof THREE.Euler&&console.error("ERROR: Vector3's .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.");this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a=new THREE.Quaternion;return function(b,c){this.applyQuaternion(a.setFromAxisAngle(b,c));return this}}(),projectOnVector:function(){var a=new THREE.Vector3; - return function(b){a.copy(b).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a=new THREE.Vector3;return function(b){a.copy(this).projectOnVector(b).multiplyScalar(2);return this.subVectors(a,this)}}()});THREE.Vector4=function(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}; - THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x; - case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this}, - addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},sub:function(a,b){if(void 0!==b)return console.warn("DEPRECATED: Vector4's .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this}, - applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w,a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=0,this.w=1);return this},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b, - this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d,a=a.elements,e=a[0];d=a[4];var f=a[8],h=a[1],g=a[5],i=a[9];c=a[2];b=a[6];var k=a[10];if(0.01>Math.abs(d-h)&&0.01>Math.abs(f-c)&&0.01>Math.abs(i-b)){if(0.1>Math.abs(d+h)&&0.1>Math.abs(f+c)&&0.1>Math.abs(i+b)&&0.1>Math.abs(e+g+k-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;g=(g+1)/2;k=(k+1)/2;d=(d+h)/4;f=(f+c)/4;i=(i+b)/4;e>g&&e>k?0.01>e?(b=0,d=c=0.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):g>k?0.01>g? - (b=0.707106781,c=0,d=0.707106781):(c=Math.sqrt(g),b=d/c,d=i/c):0.01>k?(c=b=0.707106781,d=0):(d=Math.sqrt(k),b=f/d,c=i/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-i)*(b-i)+(f-c)*(f-c)+(h-d)*(h-d));0.001>Math.abs(a)&&(a=1);this.x=(b-i)/a;this.y=(f-c)/a;this.z=(h-d)/a;this.w=Math.acos((e+g+k-1)/2);return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);this.w>a.w&&(this.w=a.w);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);this.wb.w&&(this.w=b.w);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x* - this.x+this.y*this.y+this.z*this.z+this.w*this.w)},lengthManhattan:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&& - a.w===this.w},fromArray:function(a){this.x=a[0];this.y=a[1];this.z=a[2];this.w=a[3];return this},toArray:function(){return[this.x,this.y,this.z,this.w]},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ"; - THREE.Euler.prototype={constructor:THREE.Euler,_x:0,_y:0,_z:0,_order:THREE.Euler.DefaultOrder,_quaternion:void 0,_updateQuaternion:function(){void 0!==this._quaternion&&this._quaternion.setFromEuler(this,!1)},get x(){return this._x},set x(a){this._x=a;this._updateQuaternion()},get y(){return this._y},set y(a){this._y=a;this._updateQuaternion()},get z(){return this._z},set z(a){this._z=a;this._updateQuaternion()},get order(){return this._order},set order(a){this._order=a;this._updateQuaternion()}, - set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this._updateQuaternion();return this},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order;this._updateQuaternion();return this},setFromRotationMatrix:function(a,b){function c(a){return Math.min(Math.max(a,-1),1)}var d=a.elements,e=d[0],f=d[4],h=d[8],g=d[1],i=d[5],k=d[9],m=d[2],l=d[6],d=d[10],b=b||this._order;"XYZ"===b?(this._y=Math.asin(c(h)),0.99999>Math.abs(h)?(this._x=Math.atan2(-k,d),this._z= - Math.atan2(-f,e)):(this._x=Math.atan2(l,i),this._z=0)):"YXZ"===b?(this._x=Math.asin(-c(k)),0.99999>Math.abs(k)?(this._y=Math.atan2(h,d),this._z=Math.atan2(g,i)):(this._y=Math.atan2(-m,e),this._z=0)):"ZXY"===b?(this._x=Math.asin(c(l)),0.99999>Math.abs(l)?(this._y=Math.atan2(-m,d),this._z=Math.atan2(-f,i)):(this._y=0,this._z=Math.atan2(g,e))):"ZYX"===b?(this._y=Math.asin(-c(m)),0.99999>Math.abs(m)?(this._x=Math.atan2(l,d),this._z=Math.atan2(g,e)):(this._x=0,this._z=Math.atan2(-f,i))):"YZX"===b?(this._z= - Math.asin(c(g)),0.99999>Math.abs(g)?(this._x=Math.atan2(-k,i),this._y=Math.atan2(-m,e)):(this._x=0,this._y=Math.atan2(h,d))):"XZY"===b?(this._z=Math.asin(-c(f)),0.99999>Math.abs(f)?(this._x=Math.atan2(l,i),this._y=Math.atan2(h,e)):(this._x=Math.atan2(-k,d),this._y=0)):console.warn("WARNING: Euler.setFromRotationMatrix() given unsupported order: "+b);this._order=b;this._updateQuaternion();return this},setFromQuaternion:function(a,b,c){function d(a){return Math.min(Math.max(a,-1),1)}var e=a.x*a.x,f= - a.y*a.y,h=a.z*a.z,g=a.w*a.w,b=b||this._order;"XYZ"===b?(this._x=Math.atan2(2*(a.x*a.w-a.y*a.z),g-e-f+h),this._y=Math.asin(d(2*(a.x*a.z+a.y*a.w))),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),g+e-f-h)):"YXZ"===b?(this._x=Math.asin(d(2*(a.x*a.w-a.y*a.z))),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),g-e-f+h),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),g-e+f-h)):"ZXY"===b?(this._x=Math.asin(d(2*(a.x*a.w+a.y*a.z))),this._y=Math.atan2(2*(a.y*a.w-a.z*a.x),g-e-f+h),this._z=Math.atan2(2*(a.z*a.w-a.x*a.y),g-e+f-h)):"ZYX"=== - b?(this._x=Math.atan2(2*(a.x*a.w+a.z*a.y),g-e-f+h),this._y=Math.asin(d(2*(a.y*a.w-a.x*a.z))),this._z=Math.atan2(2*(a.x*a.y+a.z*a.w),g+e-f-h)):"YZX"===b?(this._x=Math.atan2(2*(a.x*a.w-a.z*a.y),g-e+f-h),this._y=Math.atan2(2*(a.y*a.w-a.x*a.z),g+e-f-h),this._z=Math.asin(d(2*(a.x*a.y+a.z*a.w)))):"XZY"===b?(this._x=Math.atan2(2*(a.x*a.w+a.y*a.z),g-e+f-h),this._y=Math.atan2(2*(a.x*a.z+a.y*a.w),g+e-f-h),this._z=Math.asin(d(2*(a.z*a.w-a.x*a.y)))):console.warn("WARNING: Euler.setFromQuaternion() given unsupported order: "+ - b);this._order=b;!1!==c&&this._updateQuaternion();return this},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this);this.setFromQuaternion(a,b)}}(),fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this._updateQuaternion();return this},toArray:function(){return[this._x,this._y,this._z,this._order]},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},clone:function(){return new THREE.Euler(this._x, - this._y,this._z,this._order)}};THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; - THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(0.5)},delta:function(a){return(a||new THREE.Vector3).subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a, - b){var c=b||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); - this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; - THREE.Box2.prototype={constructor:THREE.Box2,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){if(0this.max.x&&(this.max.x=b.x),b.ythis.max.y&&(this.max.y=b.y)}else this.makeEmpty();return this},setFromCenterAndSize:function(){var a=new THREE.Vector2;return function(b,c){var d=a.copy(c).multiplyScalar(0.5); - this.min.copy(b).sub(d);this.max.copy(b).add(d);return this}}(),copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},empty:function(){return this.max.xthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y?!0:!1},getParameter:function(a){return new THREE.Vector2((a.x-this.min.x)/(this.max.x-this.min.x), - (a.y-this.min.y)/(this.max.y-this.min.y))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector2).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector2;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max); - return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box2).copy(this)}};THREE.Box3=function(a,b){this.min=void 0!==a?a:new THREE.Vector3(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector3(-Infinity,-Infinity,-Infinity)}; - THREE.Box3.prototype={constructor:THREE.Box3,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},addPoint:function(a){a.xthis.max.x&&(this.max.x=a.x);a.ythis.max.y&&(this.max.y=a.y);a.zthis.max.z&&(this.max.z=a.z)},setFromPoints:function(a){if(0this.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z?!0:!1},getParameter:function(a){return new THREE.Vector3((a.x-this.min.x)/(this.max.x-this.min.x), - (a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},isIntersectionBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},clampPoint:function(a,b){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= - new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=0.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];return function(b){a[0].set(this.min.x,this.min.y, - this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.makeEmpty();this.setFromPoints(a);return this}}(),translate:function(a){this.min.add(a); - this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Matrix3=function(a,b,c,d,e,f,h,g,i){this.elements=new Float32Array(9);this.set(void 0!==a?a:1,b||0,c||0,d||0,void 0!==e?e:1,f||0,h||0,g||0,void 0!==i?i:1)}; - THREE.Matrix3.prototype={constructor:THREE.Matrix3,set:function(a,b,c,d,e,f,h,g,i){var k=this.elements;k[0]=a;k[3]=b;k[6]=c;k[1]=d;k[4]=e;k[7]=f;k[2]=h;k[5]=g;k[8]=i;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},copy:function(a){a=a.elements;this.set(a[0],a[3],a[6],a[1],a[4],a[7],a[2],a[5],a[8]);return this},multiplyVector3:function(a){console.warn("DEPRECATED: Matrix3's .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)}, - multiplyVector3Array:function(){var a=new THREE.Vector3;return function(b){for(var c=0,d=b.length;cd?c.copy(this.origin):c.copy(this.direction).multiplyScalar(d).add(this.origin)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceTo(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),distanceSqToSegment:function(a,b,c,d){var e=a.clone().add(b).multiplyScalar(0.5),f=b.clone().sub(a).normalize(),h=0.5*a.distanceTo(b), - g=this.origin.clone().sub(e),a=-this.direction.dot(f),b=g.dot(this.direction),i=-g.dot(f),k=g.lengthSq(),m=Math.abs(1-a*a),l,p;0<=m?(g=a*i-b,l=a*b-i,p=h*m,0<=g?l>=-p?l<=p?(h=1/m,g*=h,l*=h,a=g*(g+a*l+2*b)+l*(a*g+l+2*i)+k):(l=h,g=Math.max(0,-(a*l+b)),a=-g*g+l*(l+2*i)+k):(l=-h,g=Math.max(0,-(a*l+b)),a=-g*g+l*(l+2*i)+k):l<=-p?(g=Math.max(0,-(-a*h+b)),l=0a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)? - 0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)},isIntersectionBox:function(){var a=new THREE.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,h;d=1/this.direction.x;f=1/this.direction.y;h=1/this.direction.z;var g=this.origin;0<=d?(c=(a.min.x-g.x)*d,d*=a.max.x-g.x):(c=(a.max.x-g.x)*d,d*=a.min.x-g.x);0<=f?(e=(a.min.y-g.y)*f,f*= - a.max.y-g.y):(e=(a.max.y-g.y)*f,f*=a.min.y-g.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(fh||e>d)return null;if(e>c||c!==c)c=e;if(hd?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,f,h,g,i){b.subVectors(f,e);c.subVectors(h,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0< - f){if(g)return null;g=1}else if(0>f)g=-1,f=-f;else return null;a.subVectors(this.origin,e);e=g*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;h=g*this.direction.dot(b.cross(a));if(0>h||e+h>f)return null;e=-g*a.dot(d);return 0>e?null:this.at(e/f,i)}}(),applyMatrix4:function(a){this.direction.add(this.origin).applyMatrix4(a);this.origin.applyMatrix4(a);this.direction.sub(this.origin);this.direction.normalize();return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}, - clone:function(){return(new THREE.Ray).copy(this)}};THREE.Sphere=function(a,b){this.center=void 0!==a?a:new THREE.Vector3;this.radius=void 0!==b?b:0}; - THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new THREE.Box3;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).center(d);for(var e=0,f=0,h=b.length;f=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<= - this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius); - return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}};THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; - THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var h=this.planes;h[0].copy(a);h[1].copy(b);h[2].copy(c);h[3].copy(d);h[4].copy(e);h[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,a=c[0],d=c[1],e=c[2],f=c[3],h=c[4],g=c[5],i=c[6],k=c[7],m=c[8],l=c[9],p=c[10],s=c[11],t=c[12],n=c[13],r=c[14],c=c[15];b[0].setComponents(f-a,k-h,s-m,c-t).normalize();b[1].setComponents(f+ - a,k+h,s+m,c+t).normalize();b[2].setComponents(f+d,k+g,s+l,c+n).normalize();b[3].setComponents(f-d,k-g,s-l,c-n).normalize();b[4].setComponents(f-e,k-i,s-p,c-r).normalize();b[5].setComponents(f+e,k+i,s+p,c+r).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){for(var b=this.planes, - c=a.center,a=-a.radius,d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0h&&0>f)return!1}return!0}}(),containsPoint:function(a){for(var b= - this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; - THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d, - c);return this}}(),copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, - b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),a=this.distanceToPoint(a.end);return 0>b&&0a&&0f||1e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return ac?c:a},clampBottom:function(a,b){return a=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(0.5-Math.random())},sign:function(a){return 0>a?-1:0this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1: - f+2;k=this.points[c[0]];m=this.points[c[1]];l=this.points[c[2]];p=this.points[c[3]];g=h*h;i=h*g;d.x=b(k.x,m.x,l.x,p.x,h,g,i);d.y=b(k.y,m.y,l.y,p.y,h,g,i);d.z=b(k.z,m.z,l.z,p.z,h,g,i);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a=b.x+b.y}}(); - THREE.Triangle.prototype={constructor:THREE.Triangle,set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return 0.5*a.cross(b).length()}}(),midpoint:function(a){return(a|| - new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.Triangle.containsPoint(a,this.a,this.b,this.c)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}, - clone:function(){return(new THREE.Triangle).copy(this)}};THREE.Vertex=function(a){console.warn("THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.");return a};THREE.UV=function(a,b){console.warn("THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.");return new THREE.Vector2(a,b)};THREE.Clock=function(a){this.autoStart=void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}; - THREE.Clock.prototype={constructor:THREE.Clock,start:function(){this.oldTime=this.startTime=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now();this.running=!0},stop:function(){this.getElapsedTime();this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;this.autoStart&&!this.running&&this.start();if(this.running){var b=void 0!==self.performance&&void 0!==self.performance.now?self.performance.now():Date.now(), - a=0.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.EventDispatcher=function(){}; - THREE.EventDispatcher.prototype={constructor:THREE.EventDispatcher,apply:function(a){a.addEventListener=THREE.EventDispatcher.prototype.addEventListener;a.hasEventListener=THREE.EventDispatcher.prototype.hasEventListener;a.removeEventListener=THREE.EventDispatcher.prototype.removeEventListener;a.dispatchEvent=THREE.EventDispatcher.prototype.dispatchEvent},addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]);-1===c[a].indexOf(b)&& - c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)?!0:!1},removeEventListener:function(a,b){if(void 0!==this._listeners){var c=this._listeners,d=c[a].indexOf(b);-1!==d&&c[a].splice(d,1)}},dispatchEvent:function(){var a=[];return function(b){if(void 0!==this._listeners){var c=this._listeners[b.type];if(void 0!==c){b.target=this;for(var d=c.length,e=0;ef.scale.x)return s;s.push({distance:t,point:f.position,face:null,object:f})}else if(f instanceof - a.LOD)d.getPositionFromMatrix(f.matrixWorld),t=m.ray.origin.distanceTo(d),k(f.getObjectForDistance(t),m,s);else if(f instanceof a.Mesh){var n=f.geometry;null===n.boundingSphere&&n.computeBoundingSphere();b.copy(n.boundingSphere);b.applyMatrix4(f.matrixWorld);if(!1===m.ray.isIntersectionSphere(b))return s;e.getInverse(f.matrixWorld);c.copy(m.ray).applyMatrix4(e);if(null!==n.boundingBox&&!1===c.isIntersectionBox(n.boundingBox))return s;if(n instanceof a.BufferGeometry){var r=f.material;if(void 0=== - r||!1===n.dynamic)return s;var q,u,w=m.precision;if(void 0!==n.attributes.index)for(var z=n.offsets,B=n.attributes.index.array,D=n.attributes.position.array,x=n.offsets.length,F=n.attributes.index.array.length/3,F=0;Fm.far)||s.push({distance:t,point:q,face:null,faceIndex:null,object:f}));else{D=n.attributes.position.array;F=n.attributes.position.array.length;for(n=0;nm.far)||s.push({distance:t,point:q,face:null,faceIndex:null,object:f}))}}else if(n instanceof a.Geometry){B=f.material instanceof a.MeshFaceMaterial;D=!0===B?f.material.materials:null;w=m.precision;z=n.vertices;x=0;for(F=n.faces.length;xm.far)||s.push({distance:t,point:q,face:A,faceIndex:x,object:f})))}}else if(f instanceof a.Line){w=m.linePrecision;r=w*w;n=f.geometry;null===n.boundingSphere&&n.computeBoundingSphere();b.copy(n.boundingSphere);b.applyMatrix4(f.matrixWorld);if(!1===m.ray.isIntersectionSphere(b))return s;e.getInverse(f.matrixWorld);c.copy(m.ray).applyMatrix4(e);if(n instanceof a.Geometry){z=n.vertices;w=z.length;q=new a.Vector3;u=new a.Vector3;F=f.type===a.LineStrip?1: - 2;for(n=0;nr||(t=c.origin.distanceTo(u),tm.far||s.push({distance:t,point:q.clone().applyMatrix4(f.matrixWorld),face:null,faceIndex:null,object:f}))}}},m=function(a,b,c){for(var a=a.getDescendants(),d=0,e=a.length;de&&0>f||0>h&&0>g)return!1;0>e?c=Math.max(c,e/(e-f)):0>f&&(d=Math.min(d,e/(e-f)));0>h?c=Math.max(c,h/(h-g)):0>g&&(d=Math.min(d,h/(h-g)));if(dg.positionScreen.x||1g.positionScreen.y||1g.positionScreen.z||1< - g.positionScreen.z)}ea=0;for(F=ta.length;ea(ia.positionScreen.x-V.positionScreen.x)*(P.positionScreen.y-V.positionScreen.y)-(ia.positionScreen.y-V.positionScreen.y)*(P.positionScreen.x-V.positionScreen.x),Z===THREE.DoubleSide|| - da===(Z===THREE.FrontSide)){if(p===t){var Da=new THREE.RenderableFace3;s.push(Da);t++;p++;l=Da}else l=s[p++];l.id=U.id;l.v1.copy(V);l.v2.copy(P);l.v3.copy(ia);l.normalModel.copy(M.normal);!1===da&&(Z===THREE.BackSide||Z===THREE.DoubleSide)&&l.normalModel.negate();l.normalModel.applyMatrix3(R).normalize();l.normalModelView.copy(l.normalModel).applyMatrix3(J);l.centroidModel.copy(M.centroid).applyMatrix4(v);ia=M.vertexNormals;V=0;for(P=Math.min(ia.length,3);VA.z&&(z===D?(ta=new THREE.RenderableSprite,B.push(ta),D++,z++,w=ta):w=B[z++],w.id=U.id,w.x=A.x*fa,w.y=A.y*fa,w.z=A.z,w.object=U,w.rotation=U.rotation,w.scale.x=U.scale.x*Math.abs(w.x-(A.x+f.projectionMatrix.elements[0])/(A.w+f.projectionMatrix.elements[12])), - w.scale.y=U.scale.y*Math.abs(w.y-(A.y+f.projectionMatrix.elements[5])/(A.w+f.projectionMatrix.elements[13])),w.material=U.material,x.elements.push(w)));!0===m&&x.elements.sort(b);return x}};THREE.Face3=function(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.color=e instanceof THREE.Color?e:new THREE.Color;this.vertexColors=e instanceof Array?e:[];this.vertexTangents=[];this.materialIndex=void 0!==f?f:0;this.centroid=new THREE.Vector3}; - THREE.Face3.prototype={constructor:THREE.Face3,clone:function(){var a=new THREE.Face3(this.a,this.b,this.c);a.normal.copy(this.normal);a.color.copy(this.color);a.centroid.copy(this.centroid);a.materialIndex=this.materialIndex;var b,c;b=0;for(c=this.vertexNormals.length;bd?-1:1,e.vertexTangents[c]=new THREE.Vector4(z.x,z.y,z.z,d)}this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;cd;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}}for(f=a.length-1;0<=f;f--){e=a[f];this.faces.splice(e,1);c=0;for(h=this.faceVertexUvs.length;cb.max.x&&(b.max.x=c),db.max.y&&(b.max.y=d),eb.max.z&&(b.max.z=e)}if(void 0===a||0===a.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0)},computeBoundingSphere:function(){var a= - new THREE.Box3,b=new THREE.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);var c=this.attributes.position.array;if(c){for(var d=this.boundingSphere.center,e=0,f=c.length;eQ?-1:1;h[4*a]=J.x;h[4*a+1]=J.y;h[4*a+2]=J.z;h[4*a+3]=N}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var b=this.attributes.index.array,c=this.attributes.position.array,d=this.attributes.normal.array,e=this.attributes.uv.array,f=c.length/3;void 0===this.attributes.tangent&& - (this.attributes.tangent={itemSize:4,array:new Float32Array(4*f)});for(var h=this.attributes.tangent.array,g=[],i=[],k=0;ka.length?".":a.join("/"))+"/"},initMaterials:function(a,b){for(var c=[],d=0;da.opacity)i.transparent=a.transparent;void 0!==a.depthTest&&(i.depthTest=a.depthTest);void 0!==a.depthWrite&&(i.depthWrite=a.depthWrite);void 0!==a.visible&&(i.visible=a.visible);void 0!==a.flipSided&&(i.side=THREE.BackSide); - void 0!==a.doubleSided&&(i.side=THREE.DoubleSide);void 0!==a.wireframe&&(i.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"===a.vertexColors?i.vertexColors=THREE.FaceColors:a.vertexColors&&(i.vertexColors=THREE.VertexColors));a.colorDiffuse?i.color=f(a.colorDiffuse):a.DbgColor&&(i.color=a.DbgColor);a.colorSpecular&&(i.specular=f(a.colorSpecular));a.colorAmbient&&(i.ambient=f(a.colorAmbient));a.transparency&&(i.opacity=a.transparency);a.specularCoef&&(i.shininess=a.specularCoef);a.mapDiffuse&& - b&&e(i,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&e(i,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&e(i,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&e(i,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&e(i,"specularMap",a.mapSpecular,a.mapSpecularRepeat, - a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapBumpScale&&(i.bumpScale=a.mapBumpScale);a.mapNormal?(g=THREE.ShaderLib.normalmap,k=THREE.UniformsUtils.clone(g.uniforms),k.tNormal.value=i.normalMap,a.mapNormalFactor&&k.uNormalScale.value.set(a.mapNormalFactor,a.mapNormalFactor),i.map&&(k.tDiffuse.value=i.map,k.enableDiffuse.value=!0),i.specularMap&&(k.tSpecular.value=i.specularMap,k.enableSpecular.value=!0),i.lightMap&&(k.tAO.value=i.lightMap,k.enableAO.value=!0),k.uDiffuseColor.value.setHex(i.color), - k.uSpecularColor.value.setHex(i.specular),k.uAmbientColor.value.setHex(i.ambient),k.uShininess.value=i.shininess,void 0!==i.opacity&&(k.uOpacity.value=i.opacity),g=new THREE.ShaderMaterial({fragmentShader:g.fragmentShader,vertexShader:g.vertexShader,uniforms:k,lights:!0,fog:!0}),i.transparent&&(g.transparent=!0)):g=new THREE[g](i);void 0!==a.DbgName&&(g.name=a.DbgName);return g}};THREE.XHRLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; - THREE.XHRLoader.prototype={constructor:THREE.XHRLoader,load:function(a,b,c,d){var e=this,f=new XMLHttpRequest;void 0!==b&&f.addEventListener("load",function(c){b(c.target.responseText);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);f.open("GET",a,!0);f.send(null);e.manager.itemStart(a)},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.ImageLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager}; - THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b,c,d){var e=this,f=document.createElement("img");void 0!==b&&f.addEventListener("load",function(){e.manager.itemEnd(a);b(this)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);f.src=a;e.manager.itemStart(a);return f},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)}; - THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,h=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var g=JSON.parse(f.responseText),g=a.parse(g,d);c(g.geometry,g.materials)}else console.warn("THREE.JSONLoader: ["+b+"] seems to be unreachable or file there is empty");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load ["+b+"] ["+f.status+"]");else f.readyState===f.LOADING?e&&(0===h&& - (h=f.getResponseHeader("Content-Length")),e({total:h,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&void 0!==e&&(h=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)}; - THREE.JSONLoader.prototype.parse=function(a,b){var c=new THREE.Geometry,d=void 0!==a.scale?1/a.scale:1,e,f,h,g,i,k,m,l,p,s,t,n,r,q,u=a.faces;p=a.vertices;var w=a.normals,z=a.colors,B=0;if(void 0!==a.uvs){for(e=0;ef;f++)l=u[g++],q=r[2*l],l=r[2*l+1],q=new THREE.Vector2(q,l),2!==f&&c.faceVertexUvs[e][h].push(q),0!==f&&c.faceVertexUvs[e][h+1].push(q)}m&&(m=3*u[g++],s.normal.set(w[m++],w[m++],w[m]),n.normal.copy(s.normal));if(t)for(e=0;4>e;e++)m=3*u[g++],t=new THREE.Vector3(w[m++], - w[m++],w[m]),2!==e&&s.vertexNormals.push(t),0!==e&&n.vertexNormals.push(t);k&&(k=u[g++],k=z[k],s.color.setHex(k),n.color.setHex(k));if(p)for(e=0;4>e;e++)k=u[g++],k=z[k],2!==e&&s.vertexColors.push(new THREE.Color(k)),0!==e&&n.vertexColors.push(new THREE.Color(k));c.faces.push(s);c.faces.push(n)}else{s=new THREE.Face3;s.a=u[g++];s.b=u[g++];s.c=u[g++];h&&(h=u[g++],s.materialIndex=h);h=c.faces.length;if(e)for(e=0;ef;f++)l=u[g++],q=r[2*l],l=r[2*l+1], - q=new THREE.Vector2(q,l),c.faceVertexUvs[e][h].push(q)}m&&(m=3*u[g++],s.normal.set(w[m++],w[m++],w[m]));if(t)for(e=0;3>e;e++)m=3*u[g++],t=new THREE.Vector3(w[m++],w[m++],w[m]),s.vertexNormals.push(t);k&&(k=u[g++],s.color.setHex(z[k]));if(p)for(e=0;3>e;e++)k=u[g++],s.vertexColors.push(new THREE.Color(z[k]));c.faces.push(s)}if(a.skinWeights){g=0;for(i=a.skinWeights.length;gG.parameters.opacity&&(G.parameters.transparent=!0);G.parameters.normalMap?(E=THREE.ShaderLib.normalmap,y=THREE.UniformsUtils.clone(E.uniforms), - q=G.parameters.color,v=G.parameters.specular,r=G.parameters.ambient,I=G.parameters.shininess,y.tNormal.value=A.textures[G.parameters.normalMap],G.parameters.normalScale&&y.uNormalScale.value.set(G.parameters.normalScale[0],G.parameters.normalScale[1]),G.parameters.map&&(y.tDiffuse.value=G.parameters.map,y.enableDiffuse.value=!0),G.parameters.envMap&&(y.tCube.value=G.parameters.envMap,y.enableReflection.value=!0,y.uReflectivity.value=G.parameters.reflectivity),G.parameters.lightMap&&(y.tAO.value=G.parameters.lightMap, - y.enableAO.value=!0),G.parameters.specularMap&&(y.tSpecular.value=A.textures[G.parameters.specularMap],y.enableSpecular.value=!0),G.parameters.displacementMap&&(y.tDisplacement.value=A.textures[G.parameters.displacementMap],y.enableDisplacement.value=!0,y.uDisplacementBias.value=G.parameters.displacementBias,y.uDisplacementScale.value=G.parameters.displacementScale),y.uDiffuseColor.value.setHex(q),y.uSpecularColor.value.setHex(v),y.uAmbientColor.value.setHex(r),y.uShininess.value=I,G.parameters.opacity&& - (y.uOpacity.value=G.parameters.opacity),t=new THREE.ShaderMaterial({fragmentShader:E.fragmentShader,vertexShader:E.vertexShader,uniforms:y,lights:!0,fog:!0})):t=new THREE[G.type](G.parameters);t.name=R;A.materials[R]=t}for(R in C.materials)if(G=C.materials[R],G.parameters.materials){J=[];for(q=0;qg.end&&(g.end=e);b||(b=h)}}a.firstAnimation=b}; - THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=1E3*((c.end-c.start)/b),this.time=0):console.warn("animation["+a+"] undefined")}; - THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& - (this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; - THREE.MorphAnimMesh.prototype.clone=function(a){void 0===a&&(a=new THREE.MorphAnimMesh(this.geometry,this.material));a.duration=this.duration;a.mirroredLoop=this.mirroredLoop;a.time=this.time;a.lastKeyframe=this.lastKeyframe;a.currentKeyframe=this.currentKeyframe;a.direction=this.direction;a.directionBackwards=this.directionBackwards;THREE.Mesh.prototype.clone.call(this,a);return a};THREE.LOD=function(){THREE.Object3D.call(this);this.objects=[]};THREE.LOD.prototype=Object.create(THREE.Object3D.prototype);THREE.LOD.prototype.addLevel=function(a,b){void 0===b&&(b=0);for(var b=Math.abs(b),c=0;c=this.objects[d].distance)this.objects[d-1].object.visible=!1,this.objects[d].object.visible=!0;else break;for(;d=g||(g*=f.intensity,c.add(La.multiplyScalar(g)))}else f instanceof THREE.PointLight&&(h=ua.getPositionFromMatrix(f.matrixWorld),g=b.dot(ua.subVectors(h,a).normalize()),0>=g||(g*=0==f.distance?1:1-Math.min(a.distanceTo(h)/f.distance,1),0!=g&&(g*=f.intensity,c.add(La.multiplyScalar(g)))))}} - function c(a,b,c,d){m(b);l(c);p(d);s(a.getStyle());C.stroke();ra.expandByScalar(2*b)}function d(a){t(a.getStyle());C.fill()}function e(a,b,c,e,f,h,g,j,i,k,m,l,p){if(!(p instanceof THREE.DataTexture||void 0===p.image||0==p.image.width)){if(!0===p.needsUpdate){var n=p.wrapS==THREE.RepeatWrapping,r=p.wrapT==THREE.RepeatWrapping;Ga[p.id]=C.createPattern(p.image,!0===n&&!0===r?"repeat":!0===n&&!1===r?"repeat-x":!1===n&&!0===r?"repeat-y":"no-repeat");p.needsUpdate=!1}void 0===Ga[p.id]?t("rgba(0,0,0,1)"): - t(Ga[p.id]);var n=p.offset.x/p.repeat.x,r=p.offset.y/p.repeat.y,s=p.image.width*p.repeat.x,q=p.image.height*p.repeat.y,g=(g+n)*s,j=(1-j+r)*q,c=c-a,e=e-b,f=f-a,h=h-b,i=(i+n)*s-g,k=(1-k+r)*q-j,m=(m+n)*s-g,l=(1-l+r)*q-j,n=i*l-m*k;0===n?(void 0===fa[p.id]&&(b=document.createElement("canvas"),b.width=p.image.width,b.height=p.image.height,b=b.getContext("2d"),b.drawImage(p.image,0,0),fa[p.id]=b.getImageData(0,0,p.image.width,p.image.height).data),b=fa[p.id],g=4*(Math.floor(g)+Math.floor(j)*p.image.width), - V.setRGB(b[g]/255,b[g+1]/255,b[g+2]/255),d(V)):(n=1/n,p=(l*c-k*f)*n,k=(l*e-k*h)*n,c=(i*f-m*c)*n,e=(i*h-m*e)*n,a=a-p*g-c*j,g=b-k*g-e*j,C.save(),C.transform(p,k,c,e,a,g),C.fill(),C.restore())}}function f(a,b,c,d,e,f,h,g,j,i,k,m,l){var p,n;p=l.width-1;n=l.height-1;h*=p;g*=n;c-=a;d-=b;e-=a;f-=b;j=j*p-h;i=i*n-g;k=k*p-h;m=m*n-g;n=1/(j*m-k*i);p=(m*c-i*e)*n;i=(m*d-i*f)*n;c=(j*e-k*c)*n;d=(j*f-k*d)*n;a=a-p*h-c*g;b=b-i*h-d*g;C.save();C.transform(p,i,c,d,a,b);C.clip();C.drawImage(l,0,0);C.restore()}function h(a, - b,c,d){va[0]=255*a.r|0;va[1]=255*a.g|0;va[2]=255*a.b|0;va[4]=255*b.r|0;va[5]=255*b.g|0;va[6]=255*b.b|0;va[8]=255*c.r|0;va[9]=255*c.g|0;va[10]=255*c.b|0;va[12]=255*d.r|0;va[13]=255*d.g|0;va[14]=255*d.b|0;j.putImageData(Oa,0,0);Ea.drawImage(Pa,0,0);return wa}function g(a,b,c){var d=b.x-a.x,e=b.y-a.y,f=d*d+e*e;0!==f&&(c/=Math.sqrt(f),d*=c,e*=c,b.x+=d,b.y+=e,a.x-=d,a.y-=e)}function i(a){y!==a&&(y=C.globalAlpha=a)}function k(a){v!==a&&(a===THREE.NormalBlending?C.globalCompositeOperation="source-over": - a===THREE.AdditiveBlending?C.globalCompositeOperation="lighter":a===THREE.SubtractiveBlending&&(C.globalCompositeOperation="darker"),v=a)}function m(a){J!==a&&(J=C.lineWidth=a)}function l(a){ba!==a&&(ba=C.lineCap=a)}function p(a){oa!==a&&(oa=C.lineJoin=a)}function s(a){G!==a&&(G=C.strokeStyle=a)}function t(a){R!==a&&(R=C.fillStyle=a)}function n(a,b){if(pa!==a||N!==b)C.setLineDash([a,b]),pa=a,N=b}console.log("THREE.CanvasRenderer",THREE.REVISION);var r=THREE.Math.smoothstep,a=a||{},q=this,u,w,z,B= - new THREE.Projector,D=void 0!==a.canvas?a.canvas:document.createElement("canvas"),x=D.width,F=D.height,A=Math.floor(x/2),O=Math.floor(F/2),C=D.getContext("2d"),E=new THREE.Color(0),I=0,y=1,v=0,G=null,R=null,J=null,ba=null,oa=null,pa=null,N=0,M,Q,K,ca;new THREE.RenderableVertex;new THREE.RenderableVertex;var Fa,Ba,da,Aa,$,ea,V=new THREE.Color,P=new THREE.Color,Z=new THREE.Color,U=new THREE.Color,ka=new THREE.Color,ta=new THREE.Color,ia=new THREE.Color,La=new THREE.Color,Ga={},fa={},Da,Ua,Qa,xa,bb, - cb,Ma,fb,sb,pb,Ha=new THREE.Box2,la=new THREE.Box2,ra=new THREE.Box2,gb=new THREE.Color,sa=new THREE.Color,ga=new THREE.Color,ua=new THREE.Vector3,Pa,j,Oa,va,wa,Ea,Ra=16;Pa=document.createElement("canvas");Pa.width=Pa.height=2;j=Pa.getContext("2d");j.fillStyle="rgba(0,0,0,1)";j.fillRect(0,0,2,2);Oa=j.getImageData(0,0,2,2);va=Oa.data;wa=document.createElement("canvas");wa.width=wa.height=Ra;Ea=wa.getContext("2d");Ea.translate(-Ra/2,-Ra/2);Ea.scale(Ra,Ra);Ra--;void 0===C.setLineDash&&(C.setLineDash= - void 0!==C.mozDash?function(a){C.mozDash=null!==a[0]?a:null}:function(){});this.domElement=D;this.devicePixelRatio=void 0!==a.devicePixelRatio?a.devicePixelRatio:void 0!==self.devicePixelRatio?self.devicePixelRatio:1;this.sortElements=this.sortObjects=this.autoClear=!0;this.info={render:{vertices:0,faces:0}};this.supportsVertexTextures=function(){};this.setFaceCulling=function(){};this.setSize=function(a,b,c){x=a*this.devicePixelRatio;F=b*this.devicePixelRatio;A=Math.floor(x/2);O=Math.floor(F/2); - D.width=x;D.height=F;1!==this.devicePixelRatio&&!1!==c&&(D.style.width=a+"px",D.style.height=b+"px");Ha.set(new THREE.Vector2(-A,-O),new THREE.Vector2(A,O));la.set(new THREE.Vector2(-A,-O),new THREE.Vector2(A,O));y=1;v=0;oa=ba=J=R=G=null};this.setClearColor=function(a,b){E.set(a);I=void 0!==b?b:1;la.set(new THREE.Vector2(-A,-O),new THREE.Vector2(A,O))};this.setClearColorHex=function(a,b){console.warn("DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.");this.setClearColor(a, - b)};this.getMaxAnisotropy=function(){return 0};this.clear=function(){C.setTransform(1,0,0,-1,A,O);!1===la.empty()&&(la.intersect(Ha),la.expandByScalar(2),1>I&&C.clearRect(la.min.x|0,la.min.y|0,la.max.x-la.min.x|0,la.max.y-la.min.y|0),0>1,ba=I.height>>1,N=F.scale.x*A,E=F.scale.y*O,x=N*R,v=E*ba,ra.min.set(y.x-x,y.y-v),ra.max.set(y.x+x,y.y+v),!1===Ha.isIntersectionBox(ra)?ra.makeEmpty():(C.save(),C.translate(y.x,y.y),C.rotate(-F.rotation), - C.scale(N,-E),C.translate(-R,-ba),C.drawImage(I,0,0),C.restore())):(N=F.object.scale.x,E=F.object.scale.y,N*=F.scale.x*A,E*=F.scale.y*O,ra.min.set(y.x-N,y.y-E),ra.max.set(y.x+N,y.y+E),!1===Ha.isIntersectionBox(ra)?ra.makeEmpty():(t(J.color.getStyle()),C.save(),C.translate(y.x,y.y),C.rotate(-F.rotation),C.scale(N,E),C.fillRect(-1,-1,2,2),C.restore())):J instanceof THREE.SpriteCanvasMaterial&&(x=F.scale.x*A,v=F.scale.y*O,ra.min.set(y.x-x,y.y-v),ra.max.set(y.x+x,y.y+v),!1===Ha.isIntersectionBox(ra)? - ra.makeEmpty():(s(J.color.getStyle()),t(J.color.getStyle()),C.save(),C.translate(y.x,y.y),C.rotate(-F.rotation),C.scale(x,v),J.program(C),C.restore()))}else if(x instanceof THREE.RenderableLine){if(Q=x.v1,K=x.v2,Q.positionScreen.x*=A,Q.positionScreen.y*=O,K.positionScreen.x*=A,K.positionScreen.y*=O,ra.setFromPoints([Q.positionScreen,K.positionScreen]),!0===Ha.isIntersectionBox(ra))if(y=Q,F=K,J=x,x=v,i(x.opacity),k(x.blending),C.beginPath(),C.moveTo(y.positionScreen.x,y.positionScreen.y),C.lineTo(F.positionScreen.x, - F.positionScreen.y),x instanceof THREE.LineBasicMaterial){m(x.linewidth);l(x.linecap);p(x.linejoin);if(x.vertexColors!==THREE.VertexColors)s(x.color.getStyle());else if(v=J.vertexColors[0].getStyle(),J=J.vertexColors[1].getStyle(),v===J)s(v);else{try{var fa=C.createLinearGradient(y.positionScreen.x,y.positionScreen.y,F.positionScreen.x,F.positionScreen.y);fa.addColorStop(0,v);fa.addColorStop(1,J)}catch(oa){fa=v}s(fa)}C.stroke();ra.expandByScalar(2*x.linewidth)}else x instanceof THREE.LineDashedMaterial&& - (m(x.linewidth),l(x.linecap),p(x.linejoin),s(x.color.getStyle()),n(x.dashSize,x.gapSize),C.stroke(),ra.expandByScalar(2*x.linewidth),n(null,null))}else if(x instanceof THREE.RenderableFace3){Q=x.v1;K=x.v2;ca=x.v3;if(-1>Q.positionScreen.z||1K.positionScreen.z||1ca.positionScreen.z||1 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif", - lights_lambert_vertex:"vLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\nvLightBack = vec3( 0.0 );\n#endif\ntransformedNormal = normalize( transformedNormal );\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, dirVector );\nvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\ndirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\ndirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n#ifdef DOUBLE_SIDED\nvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n#endif\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\npointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\npointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n#ifdef DOUBLE_SIDED\nvLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\nfloat dotProduct = dot( transformedNormal, lVector );\nvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n#ifdef DOUBLE_SIDED\nvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n#endif\n#endif\n#ifdef WRAP_AROUND\nvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\nspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n#ifdef DOUBLE_SIDED\nspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n#endif\n#endif\nvLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n#ifdef DOUBLE_SIDED\nvLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( transformedNormal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\nvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n#ifdef DOUBLE_SIDED\nvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n#endif\n}\n#endif\nvLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;\n#ifdef DOUBLE_SIDED\nvLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;\n#endif", - lights_phong_pars_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif", - lights_phong_vertex:"#ifndef PHONG_PER_PIXEL\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nvPointLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz - mvPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nvSpotLight[ i ] = vec4( lVector, lDistance );\n}\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvWorldPosition = worldPosition.xyz;\n#endif", - lights_phong_pars_fragment:"uniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#else\nvarying vec4 vPointLight[ MAX_POINT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n#ifdef PHONG_PER_PIXEL\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#else\nvarying vec4 vSpotLight[ MAX_SPOT_LIGHTS ];\n#endif\n#endif\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )\nvarying vec3 vWorldPosition;\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;", - lights_phong_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#ifdef DOUBLE_SIDED\nnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n#endif\n#ifdef USE_NORMALMAP\nnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\nnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vPointLight[ i ].xyz );\nfloat lDistance = vPointLight[ i ].w;\n#endif\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n#endif\npointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\nvec3 pointHalfVector = normalize( lVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n#else\npointSpecular += specular * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n#ifdef PHONG_PER_PIXEL\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 lVector = lPosition.xyz + vViewPosition.xyz;\nfloat lDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nlDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\nlVector = normalize( lVector );\n#else\nvec3 lVector = normalize( vSpotLight[ i ].xyz );\nfloat lDistance = vSpotLight[ i ].w;\n#endif\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\nfloat dotProduct = dot( normal, lVector );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n#endif\nspotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\nvec3 spotHalfVector = normalize( lVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += specular * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, dirVector );\n#ifdef WRAP_AROUND\nfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\nfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n#endif\ndirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += diffuse * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( shininess + 2.0001 ) / 8.0;\nvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += specular * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;\n#endif", - color_pars_fragment:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_fragment:"#ifdef USE_COLOR\ngl_FragColor = gl_FragColor * vec4( vColor, 1.0 );\n#endif",color_pars_vertex:"#ifdef USE_COLOR\nvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n#ifdef GAMMA_INPUT\nvColor = color * color;\n#else\nvColor = color;\n#endif\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n#ifdef BONE_TEXTURE\nuniform sampler2D boneTexture;\nuniform int boneTextureWidth;\nuniform int boneTextureHeight;\nmat4 getBoneMatrix( const in float i ) {\nfloat j = i * 4.0;\nfloat x = mod( j, float( boneTextureWidth ) );\nfloat y = floor( j / float( boneTextureWidth ) );\nfloat dx = 1.0 / float( boneTextureWidth );\nfloat dy = 1.0 / float( boneTextureHeight );\ny = dy * ( y + 0.5 );\nvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\nvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\nvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\nvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\nmat4 bone = mat4( v1, v2, v3, v4 );\nreturn bone;\n}\n#else\nuniform mat4 boneGlobalMatrices[ MAX_BONES ];\nmat4 getBoneMatrix( const in float i ) {\nmat4 bone = boneGlobalMatrices[ int(i) ];\nreturn bone;\n}\n#endif\n#endif", - skinbase_vertex:"#ifdef USE_SKINNING\nmat4 boneMatX = getBoneMatrix( skinIndex.x );\nmat4 boneMatY = getBoneMatrix( skinIndex.y );\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n#ifdef USE_MORPHTARGETS\nvec4 skinVertex = vec4( morphed, 1.0 );\n#else\nvec4 skinVertex = vec4( position, 1.0 );\n#endif\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n#ifndef USE_MORPHNORMALS\nuniform float morphTargetInfluences[ 8 ];\n#else\nuniform float morphTargetInfluences[ 4 ];\n#endif\n#endif", - morphtarget_vertex:"#ifdef USE_MORPHTARGETS\nvec3 morphed = vec3( 0.0 );\nmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\nmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\nmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\nmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n#ifndef USE_MORPHNORMALS\nmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\nmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\nmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\nmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n#endif\nmorphed += position;\n#endif", - default_vertex:"vec4 mvPosition;\n#ifdef USE_SKINNING\nmvPosition = modelViewMatrix * skinned;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )\nmvPosition = modelViewMatrix * vec4( position, 1.0 );\n#endif\ngl_Position = projectionMatrix * mvPosition;",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\nvec3 morphedNormal = vec3( 0.0 );\nmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\nmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\nmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\nmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\nmorphedNormal += normal;\n#endif", - skinnormal_vertex:"#ifdef USE_SKINNING\nmat4 skinMatrix = skinWeight.x * boneMatX;\nskinMatrix \t+= skinWeight.y * boneMatY;\n#ifdef USE_MORPHNORMALS\nvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n#else\nvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n#endif\n#endif",defaultnormal_vertex:"vec3 objectNormal;\n#ifdef USE_SKINNING\nobjectNormal = skinnedNormal.xyz;\n#endif\n#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )\nobjectNormal = morphedNormal;\n#endif\n#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )\nobjectNormal = normal;\n#endif\n#ifdef FLIP_SIDED\nobjectNormal = -objectNormal;\n#endif\nvec3 transformedNormal = normalMatrix * objectNormal;", - shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\nuniform sampler2D shadowMap[ MAX_SHADOWS ];\nuniform vec2 shadowMapSize[ MAX_SHADOWS ];\nuniform float shadowDarkness[ MAX_SHADOWS ];\nuniform float shadowBias[ MAX_SHADOWS ];\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nfloat unpackDepth( const in vec4 rgba_depth ) {\nconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\nfloat depth = dot( rgba_depth, bit_shift );\nreturn depth;\n}\n#endif",shadowmap_fragment:"#ifdef USE_SHADOWMAP\n#ifdef SHADOWMAP_DEBUG\nvec3 frustumColors[3];\nfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\nfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\nfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n#endif\n#ifdef SHADOWMAP_CASCADE\nint inFrustumCount = 0;\n#endif\nfloat fDepth;\nvec3 shadowColor = vec3( 1.0 );\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\nbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\nbool inFrustum = all( inFrustumVec );\n#ifdef SHADOWMAP_CASCADE\ninFrustumCount += int( inFrustum );\nbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n#else\nbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n#endif\nbool frustumTest = all( frustumTestVec );\nif ( frustumTest ) {\nshadowCoord.z += shadowBias[ i ];\n#if defined( SHADOWMAP_TYPE_PCF )\nfloat shadow = 0.0;\nconst float shadowDelta = 1.0 / 9.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.25 * xPixelOffset;\nfloat dy0 = -1.25 * yPixelOffset;\nfloat dx1 = 1.25 * xPixelOffset;\nfloat dy1 = 1.25 * yPixelOffset;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\nfloat shadow = 0.0;\nfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\nfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\nfloat dx0 = -1.0 * xPixelOffset;\nfloat dy0 = -1.0 * yPixelOffset;\nfloat dx1 = 1.0 * xPixelOffset;\nfloat dy1 = 1.0 * yPixelOffset;\nmat3 shadowKernel;\nmat3 depthKernel;\ndepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\ndepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\ndepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\ndepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\ndepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\ndepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\ndepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\ndepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\ndepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\nvec3 shadowZ = vec3( shadowCoord.z );\nshadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\nshadowKernel[0] *= vec3(0.25);\nshadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\nshadowKernel[1] *= vec3(0.25);\nshadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\nshadowKernel[2] *= vec3(0.25);\nvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\nshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\nshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\nvec4 shadowValues;\nshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\nshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\nshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\nshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\nshadow = dot( shadowValues, vec4( 1.0 ) );\nshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n#else\nvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\nfloat fDepth = unpackDepth( rgbaDepth );\nif ( fDepth < shadowCoord.z )\nshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n#endif\n}\n#ifdef SHADOWMAP_DEBUG\n#ifdef SHADOWMAP_CASCADE\nif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n#else\nif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n#endif\n#endif\n}\n#ifdef GAMMA_OUTPUT\nshadowColor *= shadowColor;\n#endif\ngl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n#endif", - shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\nvarying vec4 vShadowCoord[ MAX_SHADOWS ];\nuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif",alphatest_fragment:"#ifdef ALPHATEST\nif ( gl_FragColor.a < ALPHATEST ) discard;\n#endif",linear_to_gamma_fragment:"#ifdef GAMMA_OUTPUT\ngl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n#endif"}; - THREE.UniformsUtils={merge:function(a){var b,c,d,e={};for(b=0;b dashSize ) {\ndiscard;\n}\ngl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f", - value:1}},vertexShader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform float mNear;\nuniform float mFar;\nuniform float opacity;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), opacity );\n}"},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.morphtarget_pars_vertex,"void main() {\nvNormal = normalize( normalMatrix * normal );", - THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"uniform float opacity;\nvarying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );\n}"},normalmap:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{enableAO:{type:"i",value:0},enableDiffuse:{type:"i",value:0},enableSpecular:{type:"i",value:0},enableReflection:{type:"i",value:0},enableDisplacement:{type:"i", - value:0},tDisplacement:{type:"t",value:null},tDiffuse:{type:"t",value:null},tCube:{type:"t",value:null},tNormal:{type:"t",value:null},tSpecular:{type:"t",value:null},tAO:{type:"t",value:null},uNormalScale:{type:"v2",value:new THREE.Vector2(1,1)},uDisplacementBias:{type:"f",value:0},uDisplacementScale:{type:"f",value:1},uDiffuseColor:{type:"c",value:new THREE.Color(16777215)},uSpecularColor:{type:"c",value:new THREE.Color(1118481)},uAmbientColor:{type:"c",value:new THREE.Color(16777215)},uShininess:{type:"f", - value:30},uOpacity:{type:"f",value:1},useRefract:{type:"i",value:0},uRefractionRatio:{type:"f",value:0.98},uReflectivity:{type:"f",value:0.5},uOffset:{type:"v2",value:new THREE.Vector2(0,0)},uRepeat:{type:"v2",value:new THREE.Vector2(1,1)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),fragmentShader:["uniform vec3 uAmbientColor;\nuniform vec3 uDiffuseColor;\nuniform vec3 uSpecularColor;\nuniform float uShininess;\nuniform float uOpacity;\nuniform bool enableDiffuse;\nuniform bool enableSpecular;\nuniform bool enableAO;\nuniform bool enableReflection;\nuniform sampler2D tDiffuse;\nuniform sampler2D tNormal;\nuniform sampler2D tSpecular;\nuniform sampler2D tAO;\nuniform samplerCube tCube;\nuniform vec2 uNormalScale;\nuniform bool useRefract;\nuniform float uRefractionRatio;\nuniform float uReflectivity;\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_HEMI_LIGHTS > 0\nuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\nuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\nuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n#endif\n#if MAX_SPOT_LIGHTS > 0\nuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\nuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\nuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\nuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\nuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n#endif\n#ifdef WRAP_AROUND\nuniform vec3 wrapRGB;\n#endif\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", - THREE.ShaderChunk.shadowmap_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,"void main() {\ngl_FragColor = vec4( vec3( 1.0 ), uOpacity );\nvec3 specularTex = vec3( 1.0 );\nvec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;\nnormalTex.xy *= uNormalScale;\nnormalTex = normalize( normalTex );\nif( enableDiffuse ) {\n#ifdef GAMMA_INPUT\nvec4 texelColor = texture2D( tDiffuse, vUv );\ntexelColor.xyz *= texelColor.xyz;\ngl_FragColor = gl_FragColor * texelColor;\n#else\ngl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );\n#endif\n}\nif( enableAO ) {\n#ifdef GAMMA_INPUT\nvec4 aoColor = texture2D( tAO, vUv );\naoColor.xyz *= aoColor.xyz;\ngl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;\n#endif\n}\nif( enableSpecular )\nspecularTex = texture2D( tSpecular, vUv ).xyz;\nmat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );\nvec3 finalNormal = tsb * normalTex;\n#ifdef FLIP_SIDED\nfinalNormal = -finalNormal;\n#endif\nvec3 normal = normalize( finalNormal );\nvec3 viewPosition = normalize( vViewPosition );\n#if MAX_POINT_LIGHTS > 0\nvec3 pointDiffuse = vec3( 0.0 );\nvec3 pointSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointVector = lPosition.xyz + vViewPosition.xyz;\nfloat pointDistance = 1.0;\nif ( pointLightDistance[ i ] > 0.0 )\npointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );\npointVector = normalize( pointVector );\n#ifdef WRAP_AROUND\nfloat pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );\nfloat pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );\nvec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n#else\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\n#endif\npointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;\nvec3 pointHalfVector = normalize( pointVector + viewPosition );\nfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\nfloat pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );\npointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;\n#else\npointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_SPOT_LIGHTS > 0\nvec3 spotDiffuse = vec3( 0.0 );\nvec3 spotSpecular = vec3( 0.0 );\nfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\nvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\nvec3 spotVector = lPosition.xyz + vViewPosition.xyz;\nfloat spotDistance = 1.0;\nif ( spotLightDistance[ i ] > 0.0 )\nspotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );\nspotVector = normalize( spotVector );\nfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\nif ( spotEffect > spotLightAngleCos[ i ] ) {\nspotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );\n#ifdef WRAP_AROUND\nfloat spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );\nfloat spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );\nvec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n#else\nfloat spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );\n#endif\nspotDiffuse += spotDistance * spotLightColor[ i ] * uDiffuseColor * spotDiffuseWeight * spotEffect;\nvec3 spotHalfVector = normalize( spotVector + viewPosition );\nfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\nfloat spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );\nspotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;\n#else\nspotSpecular += spotDistance * spotLightColor[ i ] * uSpecularColor * spotSpecularWeight * spotDiffuseWeight * spotEffect;\n#endif\n}\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec3 dirDiffuse = vec3( 0.0 );\nvec3 dirSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\n#ifdef WRAP_AROUND\nfloat directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );\nfloat directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );\nvec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );\n#else\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\n#endif\ndirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;\nvec3 dirHalfVector = normalize( dirVector + viewPosition );\nfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\nfloat dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );\ndirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n#else\ndirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;\n#endif\n}\n#endif\n#if MAX_HEMI_LIGHTS > 0\nvec3 hemiDiffuse = vec3( 0.0 );\nvec3 hemiSpecular = vec3( 0.0 );\nfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\nvec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );\nvec3 lVector = normalize( lDirection.xyz );\nfloat dotProduct = dot( normal, lVector );\nfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\nvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\nhemiDiffuse += uDiffuseColor * hemiColor;\nvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\nfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\nfloat hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, uShininess ), 0.0 );\nvec3 lVectorGround = -lVector;\nvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\nfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\nfloat hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, uShininess ), 0.0 );\n#ifdef PHYSICALLY_BASED_SHADING\nfloat dotProductGround = dot( normal, lVectorGround );\nfloat specularNormalization = ( uShininess + 2.0001 ) / 8.0;\nvec3 schlickSky = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );\nvec3 schlickGround = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );\nhemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n#else\nhemiSpecular += uSpecularColor * hemiColor * ( hemiSpecularWeightSky + hemiSpecularWeightGround ) * hemiDiffuseWeight;\n#endif\n}\n#endif\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n#if MAX_DIR_LIGHTS > 0\ntotalDiffuse += dirDiffuse;\ntotalSpecular += dirSpecular;\n#endif\n#if MAX_HEMI_LIGHTS > 0\ntotalDiffuse += hemiDiffuse;\ntotalSpecular += hemiSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalDiffuse += pointDiffuse;\ntotalSpecular += pointSpecular;\n#endif\n#if MAX_SPOT_LIGHTS > 0\ntotalDiffuse += spotDiffuse;\ntotalSpecular += spotSpecular;\n#endif\n#ifdef METAL\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor + totalSpecular );\n#else\ngl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor ) + totalSpecular;\n#endif\nif ( enableReflection ) {\nvec3 vReflect;\nvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\nif ( useRefract ) {\nvReflect = refract( cameraToVertex, normal, uRefractionRatio );\n} else {\nvReflect = reflect( cameraToVertex, normal );\n}\nvec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );\n#ifdef GAMMA_INPUT\ncubeColor.xyz *= cubeColor.xyz;\n#endif\ngl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );\n}", - THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n"),vertexShader:["attribute vec4 tangent;\nuniform vec2 uOffset;\nuniform vec2 uRepeat;\nuniform bool enableDisplacement;\n#ifdef VERTEX_TEXTURES\nuniform sampler2D tDisplacement;\nuniform float uDisplacementScale;\nuniform float uDisplacementBias;\n#endif\nvarying vec3 vTangent;\nvarying vec3 vBinormal;\nvarying vec3 vNormal;\nvarying vec2 vUv;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition;", - THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.skinnormal_vertex,"#ifdef USE_SKINNING\nvNormal = normalize( normalMatrix * skinnedNormal.xyz );\nvec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );\nvTangent = normalize( normalMatrix * skinnedTangent.xyz );\n#else\nvNormal = normalize( normalMatrix * normal );\nvTangent = normalize( normalMatrix * tangent.xyz );\n#endif\nvBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );\nvUv = uv * uRepeat + uOffset;\nvec3 displacedPosition;\n#ifdef VERTEX_TEXTURES\nif ( enableDisplacement ) {\nvec3 dv = texture2D( tDisplacement, uv ).xyz;\nfloat df = uDisplacementScale * dv.x + uDisplacementBias;\ndisplacedPosition = position + normalize( normal ) * df;\n} else {\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n}\n#else\n#ifdef USE_SKINNING\nvec4 skinVertex = vec4( position, 1.0 );\nvec4 skinned = boneMatX * skinVertex * skinWeight.x;\nskinned \t += boneMatY * skinVertex * skinWeight.y;\ndisplacedPosition = skinned.xyz;\n#else\ndisplacedPosition = position;\n#endif\n#endif\nvec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );\nvec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\nvWorldPosition = worldPosition.xyz;\nvViewPosition = -mvPosition.xyz;\n#ifdef USE_SHADOWMAP\nfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\nvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n}\n#endif\n}"].join("\n")}, - cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:"varying vec3 vWorldPosition;\nvoid main() {\nvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\nvWorldPosition = worldPosition.xyz;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",fragmentShader:"uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;\nvoid main() {\ngl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n}"}, - depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,"}"].join("\n"),fragmentShader:"vec4 pack_depth( const in float depth ) {\nconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\nconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\nvec4 res = fract( depth * bit_shift );\nres -= res.xxyz * bit_mask;\nreturn res;\n}\nvoid main() {\ngl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n}"}};THREE.WebGLRenderer=function(a){function b(a,b){var c=a.vertices.length,d=b.material;if(d.attributes){void 0===a.__webglCustomAttributesList&&(a.__webglCustomAttributesList=[]);for(var e in d.attributes){var f=d.attributes[e];if(!f.__webglInitialized||f.createUniqueBuffers){f.__webglInitialized=!0;var h=1;"v2"===f.type?h=2:"v3"===f.type?h=3:"v4"===f.type?h=4:"c"===f.type&&(h=3);f.size=h;f.array=new Float32Array(c*h);f.buffer=j.createBuffer();f.buffer.belongsToAttribute=e;f.needsUpdate=!0}a.__webglCustomAttributesList.push(f)}}} - function c(a,b){var c=b.geometry,h=a.faces3,g=3*h.length,i=1*h.length,k=3*h.length,h=d(b,a),m=f(h),l=e(h),p=h.vertexColors?h.vertexColors:!1;a.__vertexArray=new Float32Array(3*g);l&&(a.__normalArray=new Float32Array(3*g));c.hasTangents&&(a.__tangentArray=new Float32Array(4*g));p&&(a.__colorArray=new Float32Array(3*g));m&&(0l;l++)K.autoScaleCubemaps&&!f?(p=k,q=l,t=c.image[l],w=ac,t.width<=w&&t.height<=w||(z=Math.max(t.width,t.height),u=Math.floor(t.width*w/z),w=Math.floor(t.height*w/z),z=document.createElement("canvas"),z.width=u,z.height=w,z.getContext("2d").drawImage(t,0,0,t.width,t.height,0,0,u,w),t=z),p[q]=t):k[l]=c.image[l];l=k[0];p=0===(l.width&l.width-1)&&0===(l.height&l.height-1);q=v(c.format);t=v(c.type);E(j.TEXTURE_CUBE_MAP, - c,p);for(l=0;6>l;l++)if(f){w=k[l].mipmaps;z=0;for(y=w.length;z=Mb&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Mb);P+=1;return a}function D(a,b,c,d){a[b]=c.r*c.r*d;a[b+1]=c.g*c.g*d;a[b+2]=c.b*c.b*d}function x(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function F(a){a!==xa&&(j.lineWidth(a),xa=a)}function A(a,b,c){Da!==a&&(a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL),Da=a); - if(a&&(Ua!==b||Qa!==c))j.polygonOffset(b,c),Ua=b,Qa=c}function O(a){for(var a=a.split("\n"),b=0,c=a.length;bb;b++)j.deleteFramebuffer(a.__webglFramebuffer[b]),j.deleteRenderbuffer(a.__webglRenderbuffer[b]); - else j.deleteFramebuffer(a.__webglFramebuffer),j.deleteRenderbuffer(a.__webglRenderbuffer);K.info.memory.textures--},Fb=function(a){a=a.target;a.removeEventListener("dispose",Fb);Gb(a)},Hb=function(a){void 0!==a.__webglVertexBuffer&&j.deleteBuffer(a.__webglVertexBuffer);void 0!==a.__webglNormalBuffer&&j.deleteBuffer(a.__webglNormalBuffer);void 0!==a.__webglTangentBuffer&&j.deleteBuffer(a.__webglTangentBuffer);void 0!==a.__webglColorBuffer&&j.deleteBuffer(a.__webglColorBuffer);void 0!==a.__webglUVBuffer&& - j.deleteBuffer(a.__webglUVBuffer);void 0!==a.__webglUV2Buffer&&j.deleteBuffer(a.__webglUV2Buffer);void 0!==a.__webglSkinIndicesBuffer&&j.deleteBuffer(a.__webglSkinIndicesBuffer);void 0!==a.__webglSkinWeightsBuffer&&j.deleteBuffer(a.__webglSkinWeightsBuffer);void 0!==a.__webglFaceBuffer&&j.deleteBuffer(a.__webglFaceBuffer);void 0!==a.__webglLineBuffer&&j.deleteBuffer(a.__webglLineBuffer);void 0!==a.__webglLineDistanceBuffer&&j.deleteBuffer(a.__webglLineDistanceBuffer);if(void 0!==a.__webglCustomAttributesList)for(var b in a.__webglCustomAttributesList)j.deleteBuffer(a.__webglCustomAttributesList[b].buffer); - K.info.memory.geometries--},Gb=function(a){var b=a.program;if(void 0!==b){a.program=void 0;var c,d,e=!1,a=0;for(c=ca.length;ad.numSupportedMorphTargets?(l.sort(k),l.length=d.numSupportedMorphTargets):l.length>d.numSupportedMorphNormals?l.sort(k):0===l.length&&l.push([0,0]);for(m=0;mCa;Ca++)Ga=R[Ca],Ma[hb]=Ga.x,Ma[hb+1]=Ga.y,Ma[hb+2]=Ga.z,hb+=3;else for(Ca=0;3>Ca;Ca++)Ma[hb]=U.x,Ma[hb+1]=U.y,Ma[hb+2]=U.z,hb+=3;j.bindBuffer(j.ARRAY_BUFFER,v.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,Ma,D)}if(yb&&Cb&&N){E=0;for(I=aa.length;ECa;Ca++)Ea=$[Ca],bb[Oa]=Ea.x,bb[Oa+1]=Ea.y,Oa+=2;0Ca;Ca++)La=Fa[Ca],cb[Pa]=La.x,cb[Pa+1]=La.y,Pa+=2;0f;f++){a.__webglFramebuffer[f]=j.createFramebuffer();a.__webglRenderbuffer[f]=j.createRenderbuffer();j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var h=a,g=j.TEXTURE_CUBE_MAP_POSITIVE_X+f;j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer[f]);j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,g,h.__webglTexture,0);I(a.__webglRenderbuffer[f],a)}c&&j.generateMipmap(j.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=j.createFramebuffer(),a.__webglRenderbuffer= - a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:j.createRenderbuffer(),j.bindTexture(j.TEXTURE_2D,a.__webglTexture),E(j.TEXTURE_2D,a,c),j.texImage2D(j.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=j.TEXTURE_2D,j.bindFramebuffer(j.FRAMEBUFFER,a.__webglFramebuffer),j.framebufferTexture2D(j.FRAMEBUFFER,j.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&& - a.stencilBuffer&&j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a.__webglRenderbuffer):I(a.__webglRenderbuffer,a),c&&j.generateMipmap(j.TEXTURE_2D);b?j.bindTexture(j.TEXTURE_CUBE_MAP,null):j.bindTexture(j.TEXTURE_2D,null);j.bindRenderbuffer(j.RENDERBUFFER,null);j.bindFramebuffer(j.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=Ma,a=fb,d=bb,e=cb);b!==da&&(j.bindFramebuffer(j.FRAMEBUFFER,b), - j.viewport(d,e,c,a),da=b);sb=c;pb=a};this.shadowMapPlugin=new THREE.ShadowMapPlugin;this.addPrePlugin(this.shadowMapPlugin);this.addPostPlugin(new THREE.SpritePlugin);this.addPostPlugin(new THREE.LensFlarePlugin)};THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format: - THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=null}; - THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,clone:function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=this.stencilBuffer;a.generateMipmaps=this.generateMipmaps;a.shareDepthFrom=this.shareDepthFrom; - return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.RenderableVertex=function(){this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.visible=!0};THREE.RenderableVertex.prototype.copy=function(a){this.positionWorld.copy(a.positionWorld);this.positionScreen.copy(a.positionScreen)};THREE.RenderableFace3=function(){this.id=0;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.v3=new THREE.RenderableVertex;this.centroidModel=new THREE.Vector3;this.normalModel=new THREE.Vector3;this.normalModelView=new THREE.Vector3;this.vertexNormalsLength=0;this.vertexNormalsModel=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.vertexNormalsModelView=[new THREE.Vector3,new THREE.Vector3,new THREE.Vector3];this.material=this.color=null;this.uvs=[[]];this.z= - 0};THREE.RenderableObject=function(){this.id=0;this.object=null;this.z=0};THREE.RenderableSprite=function(){this.id=0;this.object=null;this.rotation=this.z=this.y=this.x=0;this.scale=new THREE.Vector2;this.material=null};THREE.RenderableLine=function(){this.id=0;this.v1=new THREE.RenderableVertex;this.v2=new THREE.RenderableVertex;this.vertexColors=[new THREE.Color,new THREE.Color];this.material=null;this.z=0};THREE.GeometryUtils={merge:function(a,b,c){var d,e,f=a.vertices.length,h=b instanceof THREE.Mesh?b.geometry:b,g=a.vertices,i=h.vertices,k=a.faces,m=h.faces,a=a.faceVertexUvs[0],h=h.faceVertexUvs[0];void 0===c&&(c=0);b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,e=(new THREE.Matrix3).getNormalMatrix(d));for(var b=0,l=i.length;ba?b(c,e-1):k[e]>8&255,i>>16&255,i>>24&255)),d}d.mipmapCount=1;g[2]&131072&&!1!==b&&(d.mipmapCount=Math.max(1,g[7]));d.isCubemap=g[28]&512?!0:!1;d.width=g[4];d.height=g[3];for(var g=g[1]+4,f=d.width,h=d.height,i=d.isCubemap?6:1,m=0;ml-1?0:l-1,s=l+1>e-1?e-1:l+1,t=0>m-1?0:m-1,n=m+1>d-1?d-1:m+1,r=[],q=[0,0,g[4*(l*d+m)]/255*b];r.push([-1,0,g[4*(l*d+t)]/255*b]);r.push([-1,-1,g[4*(p*d+t)]/255*b]);r.push([0,-1,g[4*(p*d+m)]/255*b]);r.push([1,-1,g[4*(p*d+n)]/255*b]);r.push([1,0,g[4*(l*d+n)]/255*b]);r.push([1,1,g[4*(s*d+n)]/255*b]);r.push([0,1,g[4*(s*d+m)]/255*b]);r.push([-1,1,g[4*(s*d+t)]/255*b]);p=[];t=r.length;for(s=0;se)return null;var f=[],h=[],g=[],i,k,m;if(0=l--){console.log("Warning, unable to triangulate polygon!");break}i=k;e<=i&&(i=0);k=i+1;e<=k&&(k=0);m=k+1;e<=m&&(m=0);var p;a:{var s=p=void 0,t=void 0,n=void 0,r=void 0,q=void 0,u=void 0,w=void 0,z= - void 0,s=a[h[i]].x,t=a[h[i]].y,n=a[h[k]].x,r=a[h[k]].y,q=a[h[m]].x,u=a[h[m]].y;if(1E-10>(n-s)*(u-t)-(r-t)*(q-s))p=!1;else{var B=void 0,D=void 0,x=void 0,F=void 0,A=void 0,O=void 0,C=void 0,E=void 0,I=void 0,y=void 0,I=E=C=z=w=void 0,B=q-n,D=u-r,x=s-q,F=t-u,A=n-s,O=r-t;for(p=0;pi)h=d+1;else if(0b&&(b=0);1=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; - THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;cb?b=g.x:g.xc?c=g.y:g.yd?d=g.z:g.zMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; - THREE.Path.prototype.toShapes=function(a){var b,c,d,e,f=[],h=new THREE.Path;b=0;for(c=this.actions.length;b - g&&(g+=c.length);g%=c.length;0>h&&(h+=k.length);h%=k.length;e=0<=g-1?g-1:c.length-1;f=0<=h-1?h-1:k.length-1;n=[k[h],c[g],c[e]];n=THREE.FontUtils.Triangulate.area(n);r=[k[h],k[f],c[g]];r=THREE.FontUtils.Triangulate.area(r);l+p>n+r&&(g=s,h=m,0>g&&(g+=c.length),g%=c.length,0>h&&(h+=k.length),h%=k.length,e=0<=g-1?g-1:c.length-1,f=0<=h-1?h-1:k.length-1);l=c.slice(0,g);p=c.slice(g);s=k.slice(h);m=k.slice(0,h);f=[k[h],k[f],c[g]];t.push([k[h],c[g],c[e]]);t.push(f);c=l.concat(s).concat(m).concat(p)}return{shape:c, - isolatedPts:t,allpoints:d}},triangulateShape:function(a,b){var c=THREE.Shape.Utils.removeHoles(a,b),d=c.allpoints,e=c.isolatedPts,c=THREE.FontUtils.Triangulate(c.shape,!1),f,h,g,i,k={};f=0;for(h=d.length;fd;d++)i=g[d].x+":"+g[d].y,i=k[i],void 0!==i&&(g[d]=i)}f=0;for(h=e.length;fd;d++)i=g[d].x+":"+g[d].y,i=k[i],void 0!==i&&(g[d]=i)}return c.concat(e)}, - isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+ - this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return new THREE.Vector2(b,a)}; - THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);a=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)}; - THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.getPoint=function(a){var b=new THREE.Vector2,c=[],d=this.points,e;e=(d.length-1)*a;a=Math.floor(e);e-=a;c[0]=0==a?a:a-1;c[1]=a;c[2]=a>d.length-2?d.length-1:a+1;c[3]=a>d.length-3?d.length-1:a+2;b.x=THREE.Curve.Utils.interpolate(d[c[0]].x,d[c[1]].x,d[c[2]].x,d[c[3]].x,e);b.y=THREE.Curve.Utils.interpolate(d[c[0]].y,d[c[1]].y,d[c[2]].y,d[c[3]].y,e);return b};THREE.EllipseCurve=function(a,b,c,d,e,f,h){this.aX=a;this.aY=b;this.xRadius=c;this.yRadius=d;this.aStartAngle=e;this.aEndAngle=f;this.aClockwise=h};THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype); - THREE.EllipseCurve.prototype.getPoint=function(a){var b;b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);b=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;a=this.aX+this.xRadius*Math.cos(b);b=this.aY+this.yRadius*Math.sin(b);return new THREE.Vector2(a,b)};THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype);THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b});THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1=b;this.v2=c},function(a){var b,c;b=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);c=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);a=THREE.Shape.Utils.b2(a,this.v0.z,this.v1.z,this.v2.z);return new THREE.Vector3(b,c,a)});THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b,c;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);c=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);a=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return new THREE.Vector3(b,c,a)});THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e,a=(d.length-1)*a;e=Math.floor(a);a-=e;c[0]=0==e?e:e-1;c[1]=e;c[2]=e>d.length-2?d.length-1:e+1;c[3]=e>d.length-3?d.length-1:e+2;e=d[c[0]];var f=d[c[1]],h=d[c[2]],c=d[c[3]];b.x=THREE.Curve.Utils.interpolate(e.x,f.x,h.x,c.x,a);b.y=THREE.Curve.Utils.interpolate(e.y,f.y,h.y,c.y,a);b.z=THREE.Curve.Utils.interpolate(e.z,f.z,h.z,c.z,a);return b});THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=new THREE.Vector3,c=[],d=this.points,e;e=(d.length-0)*a;a=Math.floor(e);e-=a;a+=0a.hierarchy[c].keys[d].time&& - (a.hierarchy[c].keys[d].time=0),void 0!==a.hierarchy[c].keys[d].rot&&!(a.hierarchy[c].keys[d].rot instanceof THREE.Quaternion)){var g=a.hierarchy[c].keys[d].rot;a.hierarchy[c].keys[d].rot=new THREE.Quaternion(g[0],g[1],g[2],g[3])}if(a.hierarchy[c].keys.length&&void 0!==a.hierarchy[c].keys[0].morphTargets){g={};for(d=0;ds;s++){c=b[s];h=i.prevKey[c];g=i.nextKey[c];if(g.time<=m){if(kd||1d?0:1;if("pos"===c)if(c=a.position,this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+ - (f[2]-e[2])*d;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)this.points[0]=this.getPrevKeyWith("pos",l,h.index-1).pos,this.points[1]=e,this.points[2]=f,this.points[3]=this.getNextKeyWith("pos",l,g.index+1).pos,d=0.33*d+0.33,e=this.interpolateCatmullRom(this.points,d),c.x=e[0],c.y=e[1],c.z=e[2],this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(d=this.interpolateCatmullRom(this.points,1.01*d), - this.target.set(d[0],d[1],d[2]),this.target.sub(c),this.target.y=0,this.target.normalize(),d=Math.atan2(this.target.x,this.target.z),a.rotation.set(0,d,0))}else"rot"===c?THREE.Quaternion.slerp(e,f,a.quaternion,d):"scl"===c&&(c=a.scale,c.x=e[0]+(f[0]-e[0])*d,c.y=e[1]+(f[1]-e[1])*d,c.z=e[2]+(f[2]-e[2])*d)}}}}; - THREE.Animation.prototype.interpolateCatmullRom=function(a,b){var c=[],d=[],e,f,h,g,i,k;e=(a.length-1)*b;f=Math.floor(e);e-=f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>a.length-2?f:f+1;c[3]=f>a.length-3?f:f+2;f=a[c[0]];g=a[c[1]];i=a[c[2]];k=a[c[3]];c=e*e;h=e*c;d[0]=this.interpolate(f[0],g[0],i[0],k[0],e,c,h);d[1]=this.interpolate(f[1],g[1],i[1],k[1],e,c,h);d[2]=this.interpolate(f[2],g[2],i[2],k[2],e,c,h);return d}; - THREE.Animation.prototype.interpolate=function(a,b,c,d,e,f,h){a=0.5*(c-a);d=0.5*(d-b);return(2*(b-c)+a+d)*h+(-3*(b-c)-2*a-d)*f+a*e+b};THREE.Animation.prototype.getNextKeyWith=function(a,b,c){for(var d=this.data.hierarchy[b].keys,c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c=h?b.interpolate(c,h):b.interpolate(c,c.time)}this.data.hierarchy[a].node.updateMatrix();d.matrixWorldNeedsUpdate=!0}}if(this.JITCompile&&void 0===f[0][e]){this.hierarchy[0].updateMatrixWorld(!0);for(a=0;ag?(b=Math.atan2(b.y-a.y,b.x-a.x),a=Math.atan2(c.y-a.y,c.x-a.x),b>a&&(a+=2*Math.PI),c=(b+a)/2,a=-Math.cos(c),c=-Math.sin(c),new THREE.Vector2(a,c)):d.multiplyScalar(g).add(h).sub(a).clone()}function e(c,d){var e,f;for(N=c.length;0<=--N;){e=N;f=N-1;0>f&&(f=c.length-1);for(var g=0,h=s+2*m, - g=0;gMath.abs(c-i)?[new THREE.Vector2(b,1-e),new THREE.Vector2(d,1-f),new THREE.Vector2(k,1-h),new THREE.Vector2(l,1-a)]:[new THREE.Vector2(c,1-e),new THREE.Vector2(i,1-f),new THREE.Vector2(m,1-h),new THREE.Vector2(p,1-a)]}};THREE.ExtrudeGeometry.__v1=new THREE.Vector2;THREE.ExtrudeGeometry.__v2=new THREE.Vector2;THREE.ExtrudeGeometry.__v3=new THREE.Vector2;THREE.ExtrudeGeometry.__v4=new THREE.Vector2; - THREE.ExtrudeGeometry.__v5=new THREE.Vector2;THREE.ExtrudeGeometry.__v6=new THREE.Vector2;THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);!1===a instanceof Array&&(a=[a]);this.shapebb=a[a.length-1].getBoundingBox();this.addShapeList(a,b);this.computeCentroids();this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;cc&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+0.5,a.y));return a.clone()}THREE.Geometry.call(this);for(var c=c||1,d=d||0,g=this,i=0,k=a.length;ip&&(0.2>a&&(d[0].x+=1),0.2>b&&(d[1].x+=1),0.2>m&&(d[2].x+=1));i=0;for(k=this.vertices.length;ic.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();THREE.ArrowHelper.prototype.setLength=function(a){this.scale.set(a,a,a)}; - THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.setHex(a);this.cone.material.color.setHex(a)};THREE.BoxHelper=function(a){var b=[new THREE.Vector3(1,1,1),new THREE.Vector3(-1,1,1),new THREE.Vector3(-1,-1,1),new THREE.Vector3(1,-1,1),new THREE.Vector3(1,1,-1),new THREE.Vector3(-1,1,-1),new THREE.Vector3(-1,-1,-1),new THREE.Vector3(1,-1,-1)];this.vertices=b;var c=new THREE.Geometry;c.vertices.push(b[0],b[1],b[1],b[2],b[2],b[3],b[3],b[0],b[4],b[5],b[5],b[6],b[6],b[7],b[7],b[4],b[0],b[4],b[1],b[5],b[2],b[6],b[3],b[7]);THREE.Line.call(this,c,new THREE.LineBasicMaterial({color:16776960}),THREE.LinePieces); - void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.Line.prototype); - THREE.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,b=b.boundingBox.max,d=this.vertices;d[0].set(b.x,b.y,b.z);d[1].set(c.x,b.y,b.z);d[2].set(c.x,c.y,b.z);d[3].set(b.x,c.y,b.z);d[4].set(b.x,b.y,c.z);d[5].set(c.x,b.y,c.z);d[6].set(c.x,c.y,c.z);d[7].set(b.x,c.y,c.z);this.geometry.computeBoundingSphere();this.geometry.verticesNeedUpdate=!0;this.matrixAutoUpdate=!1;this.matrixWorld=a.matrixWorld};THREE.BoundingBoxHelper=function(a,b){var c=b||8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.CubeGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)};THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200); - b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.Line.call(this,d,e,THREE.LinePieces);this.camera=a;this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()}; - THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype); - THREE.CameraHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Camera,c=new THREE.Projector;return function(){function d(d,h,g,i){a.set(h,g,i);c.unprojectVector(a,b);d=e.pointMap[d];if(void 0!==d){h=0;for(g=d.length;hd;d++)c.faces[d].color=this.colors[4>d?0:1];d=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(c,d);this.add(this.lightSphere); - this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()}; - THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.getPositionFromMatrix(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}();THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrixWorld=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()}; - THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)};THREE.SpotLightHelper=function(a){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrixWorld=a.matrixWorld;this.matrixAutoUpdate=!1;a=new THREE.CylinderGeometry(0,1,1,8,1,!0);a.applyMatrix((new THREE.Matrix4).makeTranslation(0,-0.5,0));a.applyMatrix((new THREE.Matrix4).makeRotationX(-Math.PI/2));var b=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});this.cone=new THREE.Mesh(a,b);this.add(this.cone);this.update()};THREE.SpotLightHelper.prototype=Object.create(THREE.Object3D.prototype); - THREE.SpotLightHelper.prototype.dispose=function(){this.cone.geometry.dispose();this.cone.material.dispose()};THREE.SpotLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){var c=this.light.distance?this.light.distance:1E4,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c);a.getPositionFromMatrix(this.light.matrixWorld);b.getPositionFromMatrix(this.light.target.matrixWorld);this.cone.lookAt(b.sub(a));this.cone.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)}}();THREE.VertexNormalsHelper=function(a,b,c,d){this.object=a;this.size=b||1;for(var b=c||16711680,d=d||1,c=new THREE.Geometry,a=a.geometry.faces,e=0,f=a.length;el;l++){b[0]=m[e[l]];b[1]=m[e[(l+1)%3]];b.sort(d);var p=b.toString();void 0===c[p]&&(f.vertices.push(h[b[0]]),f.vertices.push(h[b[1]]),c[p]=!0)}THREE.Line.call(this,f,new THREE.LineBasicMaterial({color:16777215}),THREE.LinePieces);this.matrixAutoUpdate=!1;this.matrixWorld=a.matrixWorld}; - THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);THREE.LensFlare=function(a,b,c,d,e){THREE.Object3D.call(this);this.lensFlares=[];this.positionScreen=new THREE.Vector3;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)};THREE.LensFlare.prototype=Object.create(THREE.Object3D.prototype); - THREE.LensFlare.prototype.add=function(a,b,c,d,e,f){void 0===b&&(b=-1);void 0===c&&(c=0);void 0===f&&(f=1);void 0===e&&(e=new THREE.Color(16777215));void 0===d&&(d=THREE.NormalBlending);c=Math.min(c,Math.max(0,c));this.lensFlares.push({texture:a,size:b,distance:c,x:0,y:0,z:0,scale:1,rotation:1,opacity:f,color:e,blending:d})}; - THREE.LensFlare.prototype.updateLensFlares=function(){var a,b=this.lensFlares.length,c,d=2*-this.positionScreen.x,e=2*-this.positionScreen.y;for(a=0;ag.end&&(g.end=f);c||(c=i)}}for(i in d)g=d[i],this.createAnimation(i,g.start,g.end,a);this.firstAnimation=c}; - THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; - THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; - THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; - THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),h=d.weight; - f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*h,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*h;this.morphTargetInfluences[d.lastFrame]=(1-e)*h}}};THREE.LensFlarePlugin=function(){function a(a,c){var d=b.createProgram(),e=b.createShader(b.FRAGMENT_SHADER),f=b.createShader(b.VERTEX_SHADER),g="precision "+c+" float;\n";b.shaderSource(e,g+a.fragmentShader);b.shaderSource(f,g+a.vertexShader);b.compileShader(e);b.compileShader(f);b.attachShader(d,e);b.attachShader(d,f);b.linkProgram(d);return d}var b,c,d,e,f,h,g,i,k,m,l,p,s;this.init=function(t){b=t.context;c=t;d=t.getPrecision();e=new Float32Array(16);f=new Uint16Array(6);t=0;e[t++]=-1;e[t++]=-1; - e[t++]=0;e[t++]=0;e[t++]=1;e[t++]=-1;e[t++]=1;e[t++]=0;e[t++]=1;e[t++]=1;e[t++]=1;e[t++]=1;e[t++]=-1;e[t++]=1;e[t++]=0;e[t++]=1;t=0;f[t++]=0;f[t++]=1;f[t++]=2;f[t++]=0;f[t++]=2;f[t++]=3;h=b.createBuffer();g=b.createBuffer();b.bindBuffer(b.ARRAY_BUFFER,h);b.bufferData(b.ARRAY_BUFFER,e,b.STATIC_DRAW);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,g);b.bufferData(b.ELEMENT_ARRAY_BUFFER,f,b.STATIC_DRAW);i=b.createTexture();k=b.createTexture();b.bindTexture(b.TEXTURE_2D,i);b.texImage2D(b.TEXTURE_2D,0,b.RGB,16,16, - 0,b.RGB,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.bindTexture(b.TEXTURE_2D,k);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,16,16,0,b.RGBA,b.UNSIGNED_BYTE,null);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE); - b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);0>=b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)?(m=!1,l=a(THREE.ShaderFlares.lensFlare,d)):(m=!0,l=a(THREE.ShaderFlares.lensFlareVertexTexture,d));p={};s={};p.vertex=b.getAttribLocation(l,"position");p.uv=b.getAttribLocation(l,"uv");s.renderType=b.getUniformLocation(l,"renderType");s.map=b.getUniformLocation(l,"map");s.occlusionMap=b.getUniformLocation(l,"occlusionMap");s.opacity= - b.getUniformLocation(l,"opacity");s.color=b.getUniformLocation(l,"color");s.scale=b.getUniformLocation(l,"scale");s.rotation=b.getUniformLocation(l,"rotation");s.screenPosition=b.getUniformLocation(l,"screenPosition")};this.render=function(a,d,e,f){var a=a.__webglFlares,u=a.length;if(u){var w=new THREE.Vector3,z=f/e,B=0.5*e,D=0.5*f,x=16/f,F=new THREE.Vector2(x*z,x),A=new THREE.Vector3(1,1,0),O=new THREE.Vector2(1,1),C=s,x=p;b.useProgram(l);b.enableVertexAttribArray(p.vertex);b.enableVertexAttribArray(p.uv); - b.uniform1i(C.occlusionMap,0);b.uniform1i(C.map,1);b.bindBuffer(b.ARRAY_BUFFER,h);b.vertexAttribPointer(x.vertex,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(x.uv,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,g);b.disable(b.CULL_FACE);b.depthMask(!1);var E,I,y,v,G;for(E=0;EF;F++)z[F]=new THREE.Vector3,u[F]=new THREE.Vector3;z=B.shadowCascadeNearZ[w];B=B.shadowCascadeFarZ[w];u[0].set(-1,-1,z);u[1].set(1,-1,z);u[2].set(-1, - 1,z);u[3].set(1,1,z);u[4].set(-1,-1,B);u[5].set(1,-1,B);u[6].set(-1,1,B);u[7].set(1,1,B);x.originalCamera=p;u=new THREE.Gyroscope;u.position=n.shadowCascadeOffset;u.add(x);u.add(x.target);p.add(u);n.shadowCascadeArray[q]=x;console.log("Created virtualLight",x)}w=n;z=q;B=w.shadowCascadeArray[z];B.position.copy(w.position);B.target.position.copy(w.target.position);B.lookAt(B.target);B.shadowCameraVisible=w.shadowCameraVisible;B.shadowDarkness=w.shadowDarkness;B.shadowBias=w.shadowCascadeBias[z];u=w.shadowCascadeNearZ[z]; - w=w.shadowCascadeFarZ[z];B=B.pointsFrustum;B[0].z=u;B[1].z=u;B[2].z=u;B[3].z=u;B[4].z=w;B[5].z=w;B[6].z=w;B[7].z=w;D[r]=x;r++}else D[r]=n,r++;s=0;for(t=D.length;sw;w++)z=B[w],z.copy(u[w]),THREE.ShadowMapPlugin.__projector.unprojectVector(z,q),z.applyMatrix4(r.matrixWorldInverse),z.xk.x&&(k.x=z.x),z.yk.y&&(k.y=z.y),z.zk.z&& - (k.z=z.z);r.left=i.x;r.right=k.x;r.top=k.y;r.bottom=i.y;r.updateProjectionMatrix()}r=n.shadowMap;u=n.shadowMatrix;q=n.shadowCamera;q.position.getPositionFromMatrix(n.matrixWorld);m.getPositionFromMatrix(n.target.matrixWorld);q.lookAt(m);q.updateMatrixWorld();q.matrixWorldInverse.getInverse(q.matrixWorld);n.cameraHelper&&(n.cameraHelper.visible=n.shadowCameraVisible);n.shadowCameraVisible&&n.cameraHelper.update();u.set(0.5,0,0,0.5,0,0.5,0,0.5,0,0,0.5,0.5,0,0,0,1);u.multiply(q.projectionMatrix);u.multiply(q.matrixWorldInverse); - g.multiplyMatrices(q.projectionMatrix,q.matrixWorldInverse);h.setFromMatrix(g);b.setRenderTarget(r);b.clear();B=l.__webglObjects;n=0;for(r=B.length;n 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"}}; + return { + getState: getState, + setState: setState, + getGrade: getGrade + }; + }()); diff --git a/docs/course_authors/source/javascript_input.rst b/docs/course_authors/source/javascript_input.rst deleted file mode 100644 index 639e30a4d25d..000000000000 --- a/docs/course_authors/source/javascript_input.rst +++ /dev/null @@ -1,113 +0,0 @@ -.. _JavaScript Input: - -JavaScript Input ----------------- - -The JavaScript Input problem type allows you to create your own learning tool -using HTML and other standard Internet languages and then add the tool directly -into Studio. When you use this problem type, Studio embeds your tool in an -IFrame so that your students can interact with it in the LMS. You can grade -your students' work using JavaScript and some basic Python, and the grading -is integrated into the edX grading system. - -This problem type doesn't appear in the menu of advanced problems in Studio. To -create a JavaScript input problem type, you'll create a blank advanced problem, -and then enter your code into the component editor. - -.. image:: /Images/JavaScriptInputExample.gif - -Create a JavaScript Input Problem -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#. Create your JavaScript application, and then upload all files associated with - that application to the **Files & Uploads** page. -#. In the unit where you want to create the problem, click **Problem** - under **Add New Component**, and then click the **Advanced** tab. -#. Click **Blank Advanced Problem**. -#. In the component that appears, click **Edit**. -#. Click the **Settings** tab. -#. Set **Maximum Attempts** to a number larger than zero. -#. In the component editor, enter your code. -#. Click **Save**. - -To re-create the example problem above, follow these steps. - -#. Go to :ref:`Appendix F` and create the following files: - - - webGLDemo.html - - webGLDemo.js - - webGLDemo.css - - three.min.js - -#. On the **Files & Uploads** page, upload the four files you just created. -#. Create a new blank advanced problem component. -#. On the **Settings** tab, set **Maximum Attempts** to a number larger than - zero. -#. In the problem component editor, paste the code below. -#. Click **Save.** - - - -JavaScript Input Problem Code -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - - In the image below, click the cone. - - - - - - - - -**Notes** - -- The webGLDemo.js file defines the three JavaScript functions (**WebGLDemo.getGrade**, - **WebGLDemo.getState**, and **WebGLDemo.setState**). - -- The JavaScript input problem code uses **WebGLDemo.getGrade**, **WebGLDemo.getState**, - and **WebGLDemo.setState** to grade, save, or restore a problem. These functions must - be global in scope. - -- **WebGLDemo.getState** and **WebGLDemo.setState** are optional. You only have to define - these functions if you want to conserve the state of the problem. - -- **Width** and **height** represent the dimensions of the IFrame that holds the - application. - -- When the problem opens, the cone and the cube are both blue, or "unselected." When - you click either shape once, the shape becomes yellow, or "selected." To unselect - the shape, click it again. Continue clicking the shape to select and unselect it. - -- The response is graded as correct if the cone is selected (yellow) when the user - clicks **Check**. - -- Clicking **Check** or **Save** registers the problem's current state. \ No newline at end of file From 6cfe7669e313c8868f2f2155b2d00de7502ee672 Mon Sep 17 00:00:00 2001 From: spearce Date: Tue, 24 Dec 2013 13:24:45 -0500 Subject: [PATCH 04/15] Update JS Input to reflect new template in Studio Update Advanced Problems file and Appendix F --- .../source/advanced_problems.rst | 35 ++++++++++++------- docs/course_authors/source/appendices/f.rst | 33 ++++++++--------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/docs/course_authors/source/advanced_problems.rst b/docs/course_authors/source/advanced_problems.rst index 88814e597584..b55539d7fcc1 100644 --- a/docs/course_authors/source/advanced_problems.rst +++ b/docs/course_authors/source/advanced_problems.rst @@ -64,17 +64,14 @@ Create a Circuit Schematic Builder Problem Custom JavaScript Display and Grading ------------------------------------- -Custom JavaScript display and grading problems allow you to create your own learning tool +Custom JavaScript display and grading problems (also called custom JavaScript problems or +JS Input problems) allow you to create your own learning tool using HTML and other standard Internet languages and then add the tool directly into Studio. When you use this problem type, Studio embeds your tool in an inline frame (IFrame) so that your students can interact with it in the LMS. You can grade your students' work using JavaScript and some basic Python, and the grading is integrated into the edX grading system. -This problem type doesn't appear in the menu of advanced problems in Studio. To -create a JavaScript input problem type, you'll create a blank advanced problem, -and then enter your code into the component editor. - .. image:: /Images/JavaScriptInputExample.gif Create a Custom JavaScript Display and Grading Problem @@ -97,28 +94,42 @@ Create a Custom JavaScript Display and Grading Problem #. Set **Maximum Attempts** to a number larger than zero. #. Click **Save**. -To re-create the example problem above, follow these steps. +Re-create the Example Problem +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#. Go to :ref:`Appendix F` and use the code samples to create the following files. +To re-create the example problem above, you'll need the following files. - webGLDemo.html - webGLDemo.js - webGLDemo.css - three.min.js - **Note** *If you need to bypass the SOP, you'll also create a jschannel.js file.* +#. Go to :ref:`Appendix F` and use the code samples to create the following files. -#. On the **Files & Uploads** page, upload the files you just created. + - webGLDemo.html + - webGLDemo.js + - webGLDemo.css + +#. Download the **three.min.js** file. To do this, go to the `three.js home page `_, + and then click **Download** in + the left pane. After the .zip file has finished downloading, open the .zip file, and then + open the **build** folder to access the three.min.js file. + + **Note** If you need to bypass the SOP, you'll also need the **jschannel.js** file. To do + this, go to the `jschannel.js `_ + page, copy the code for the file into a text editor, and then save the file as jschannel.js. + +#. On the **Files & Uploads** page, upload all the files you just created or downloaded. #. Create a new custom JavaScript display and grading problem component. #. On the **Settings** tab, set **Maximum Attempts** to a number larger than zero. -#. In the problem component editor, paste the code below. +#. In the problem component editor, replace the example code with the code below. #. Click **Save.** JavaScript Input Problem Code -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +############################# :: @@ -157,7 +168,7 @@ JavaScript Input Problem Code -.. note:: When you create a JavaScript Input problem, keep the following in mind. +.. note:: When you create this problem, keep the following in mind. - The webGLDemo.js file defines the three JavaScript functions (**WebGLDemo.getGrade**, **WebGLDemo.getState**, and **WebGLDemo.setState**). diff --git a/docs/course_authors/source/appendices/f.rst b/docs/course_authors/source/appendices/f.rst index be499a047a16..0b984eb1c3bf 100644 --- a/docs/course_authors/source/appendices/f.rst +++ b/docs/course_authors/source/appendices/f.rst @@ -3,38 +3,35 @@ Appendix F - Files for the Example Custom JavaScript Display and Grading Problem ================================================================================ -For the example custom JavaScript display and grading problem, you need the `three.min.js `_ -library file. - -- On the `three.js home page `_ page, click **Download** in - the left pane. After the .zip file has finished downloading, open it, and then - open the **build** folder to access the three.min.js file. - -Additionally, you need the following files. You can find the code to create each -of these files below. +For the example :ref:`Custom JavaScript Display and Grading` problem, you need the following files. You can find +instructions for obtaining each +of these files below. After you obtain the files, add all of them to the **Files & Uploads** page in Studio. - :ref:`webGLDemo.html` - :ref:`webGLDemo.css` - :ref:`webGLDemo.js` +- `three.min.js `_ -To create these files, copy the code for each file into a text editor, and -then save each file. Make sure to use the correct file name extension when you save -each file. +For the **webGLDemo.html**, **webGLDemo.js**, and **webGLDemo.css** files, copy the code provided +for each file into a text editor, and then save each file. Make sure to use the correct +file name extension when you save each file. -After you create these files, add them to the **Files & Uploads** page in Studio. +For the **three.min.js** library file, go to the `three.js home page `_ page, +and then click **Download** in +the left pane. After the .zip file has finished downloading, open the .zip file, and then +open the **build** folder to access the **three.min.js** file. .. note:: If you need to bypass the same-origin policy (SOP), you also need the - `jschannel.js `_ file. - - - On the `jschannel.js `_ - web page, copy the code for the file into a text editor, and then save the file as **jschannel.js**. + `jschannel.js `_ file. On + the `jschannel.js `_ + web page, copy the code for the file into a text editor, and then save the file as **jschannel.js**. .. _webGLDemo.html: webGLDemo.html -------------- -If you don't need to bypass the SOP, use the following code. +If you **don't** need to bypass the SOP, use the following code. :: From 06798ae032bff731b5dc1ec59a2dd3422864ca34 Mon Sep 17 00:00:00 2001 From: spearce Date: Tue, 24 Dec 2013 14:10:27 -0500 Subject: [PATCH 05/15] Create Tools topic Create Tools topic that includes descriptions of Qualtrics surveys, word clouds, and zooming images --- .../course_authors/source/Images/ZoomingImage | Bin 0 -> 33067 bytes docs/course_authors/source/tools.rst | 138 ++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 docs/course_authors/source/Images/ZoomingImage create mode 100644 docs/course_authors/source/tools.rst diff --git a/docs/course_authors/source/Images/ZoomingImage b/docs/course_authors/source/Images/ZoomingImage new file mode 100644 index 0000000000000000000000000000000000000000..4a3493a7c1f991e64e4e109995d22d4b97ef15f3 GIT binary patch literal 33067 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
    d-e`Cv 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 literal 0 HcmV?d00001 diff --git a/docs/course_authors/source/tools.rst b/docs/course_authors/source/tools.rst new file mode 100644 index 000000000000..6a9703cf51bc --- /dev/null +++ b/docs/course_authors/source/tools.rst @@ -0,0 +1,138 @@ +.. _Tools: + + +############################# +Working with Tools +############################# + +*************************** +Overview of Tools in Studio +*************************** + +**Intro to Tools text** - you can use various tools in Studio, etc. (Sometimes +called blades, though that's not intuitive for very many people.) + +- :ref:`Qualtrics Survey` +- Interactive periodic table (if we document this) +- :ref:`Word Cloud` +- :ref:`Zooming image` + + +.. _Qualtrics Survey: + +**************** +Qualtrics Survey +**************** + +**description of Qualtrics survey and explanation of why course teams would want to +use it** + +**image of Qualtrics survey** + +Create a Qualtrics Survey +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a Qualtrics survey, you'll use the Anonymous User ID template. This +template contains HTML with instructions. + +#. Under **Add New Component**, click **html**, and then click **Anonymous User ID**. + +#. In the empty component that appears, click **Edit**. + +#. When the component editor opens, replace the example content with your own content. + + - **flesh these instructions out more** + + - To use your survey, you must edit the link in the template to include your university and survey ID. + + - You can also embed the survey in an iframe in the HTML component. + + - For more details, read the instructions in the HTML view of the component. + +#. Click **Save** to save the HTML component. + + +.. _Word Cloud: + +********** +Word Cloud +********** + + +In a word cloud problem, students enter words into a field in response +to a question or prompt. The words all the students have entered then +appear instantly as a colorful graphic, with the most popular responses +appearing largest. The graphic becomes larger as more students answer. +Students can both see the way their peers have answered and contribute +their thoughts to the group. + + +For example, the following word cloud was created from students' +responses to a question in a HarvardX course. + +.. image:: Images/WordCloudExample.gif + +Create a Word Cloud Exercise +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a word cloud exercise: + + +#. Add the Word Cloud advanced component. To do this, add the + "word_cloud" key value to the **Advanced Settings** page. (For more + information, see the instructions in :ref:`Specialized Problems`.) +#. In the unit where you want to create the problem, click **Advanced** + under **Add New Component**. +#. In the list of problem types, click **Word Cloud**. +#. In the component that appears, click **Edit**. +#. In the component editor, specify the settings that you want. You can + leave the default value for everything except **Display Name**. + + + - **Display Name**: The name that appears in the course ribbon and + as a heading above the problem. + - **Inputs**: The number of text boxes into which students can enter + words, phrases, or sentences. + - **Maximum Words**: The maximum number of words that the word cloud + displays. If students enter 300 different words but the maximum is + set to 250, only the 250 most commonly entered words appear in the + word cloud. + - **Show Percents**: The number of times that students have entered + a given word as a percentage of all words entered appears near + that word. + + +#. Click **Save**. + + +For more information, see `Xml Format of "Word Cloud" Module +`_. + +.. _Zooming Image: + +****************** +Zooming Image Tool +****************** + +To create a new HTML component in an existing unit, ensure the unit is private. +For more information on public and private units, see :ref:`Public and Private Units`. + +Some edX classes use extremely large, extremely detailed graphics. To make it +easier to understand we can offer two versions of those graphics, with the zoomed +section showing when you click on the main view. + +The example below is from 7.00x: Introduction to Biology and shows a subset of the +biochemical reactions that cells carry out. + +.. image:: Images/ZoomingImage.gif + +Create a Zooming Image Tool +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. Under **Add New Component**, click **html**, and then click **Zooming Image**. + +#. In the empty component that appears, click **Edit**. + +#. When the component editor opens, replace the example content with your own content. + +#. Click **Save** to save the HTML component. From 2157b4d8b74f8af33f59dab9a9946313c6835482 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 2 Jan 2014 08:42:10 -0500 Subject: [PATCH 06/15] Miscellaneous fixes to strings found during i18n work. --- cms/templates/registration/reg_complete.html | 2 +- .../shoppingcart/processors/CyberSource.py | 38 +++++++++---------- lms/static/admin/js/calendar.js | 6 ++- lms/static/admin/js/dateparse.js | 6 ++- .../static_templates/server-overloaded.html | 2 +- .../_reverification_support.html | 2 +- .../verify_student/_verification_support.html | 2 +- .../verify_student/show_requirements.html | 2 +- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/cms/templates/registration/reg_complete.html b/cms/templates/registration/reg_complete.html index c6af5d94a5e5..1e760f9fb8e5 100644 --- a/cms/templates/registration/reg_complete.html +++ b/cms/templates/registration/reg_complete.html @@ -1,3 +1,3 @@ <%! from django.utils.translation import ugettext as _ %>

    Check your email

    -

    ${_("An activation link has been sent to {emaiL}, along with instructions for activating your account.").format(email=email)}

    +

    ${_("An activation link has been sent to {email}, along with instructions for activating your account.").format(email=email)}

    diff --git a/lms/djangoapps/shoppingcart/processors/CyberSource.py b/lms/djangoapps/shoppingcart/processors/CyberSource.py index d6811303a1f7..5c980073d71f 100644 --- a/lms/djangoapps/shoppingcart/processors/CyberSource.py +++ b/lms/djangoapps/shoppingcart/processors/CyberSource.py @@ -217,14 +217,14 @@ def get_processor_decline_html(params): """Have to parse through the error codes to return a helpful message""" payment_support_email = settings.PAYMENT_SUPPORT_EMAIL - msg = _(dedent( + msg = dedent(_( """

    Sorry! Our payment processor did not accept your payment. - The decision in they returned was {decision}, + The decision they returned was {decision}, and the reason was {reason_code}:{reason_msg}. You were not charged. Please try a different form of payment. - Contact us with payment-specific questions at {email}. + Contact us with payment-related questions at {email}.

    """)) @@ -240,7 +240,7 @@ def get_processor_exception_html(exception): payment_support_email = settings.PAYMENT_SUPPORT_EMAIL if isinstance(exception, CCProcessorDataException): - msg = _(dedent( + msg = dedent(_( """

    Sorry! Our payment processor sent us back a payment confirmation that had inconsistent data! @@ -251,7 +251,7 @@ def get_processor_exception_html(exception): """.format(msg=exception.message, email=payment_support_email))) return msg elif isinstance(exception, CCProcessorWrongAmountException): - msg = _(dedent( + msg = dedent(_( """

    Sorry! Due to an error your purchase was charged for a different amount than the order total! @@ -261,7 +261,7 @@ def get_processor_exception_html(exception): """.format(msg=exception.message, email=payment_support_email))) return msg elif isinstance(exception, CCProcessorSignatureException): - msg = _(dedent( + msg = dedent(_( """

    Sorry! Our payment processor sent us back a corrupted message regarding your charge, so we are @@ -307,32 +307,32 @@ def get_processor_exception_html(exception): '100': _('Successful transaction.'), '101': _('The request is missing one or more required fields.'), '102': _('One or more fields in the request contains invalid data.'), - '104': _(dedent( + '104': dedent(_( """ The merchantReferenceCode sent with this authorization request matches the merchantReferenceCode of another authorization request that you sent in the last 15 minutes. Possible fix: retry the payment after 15 minutes. """)), '150': _('Error: General system failure. Possible fix: retry the payment after a few minutes.'), - '151': _(dedent( + '151': dedent(_( """ Error: The request was received but there was a server timeout. This error does not include timeouts between the client and the server. Possible fix: retry the payment after some time. """)), - '152': _(dedent( + '152': dedent(_( """ Error: The request was received, but a service did not finish running in time Possible fix: retry the payment after some time. """)), '201': _('The issuing bank has questions about the request. Possible fix: retry with another form of payment'), - '202': _(dedent( + '202': dedent(_( """ Expired card. You might also receive this if the expiration date you provided does not match the date the issuing bank has on file. Possible fix: retry with another form of payment """)), - '203': _(dedent( + '203': dedent(_( """ General decline of the card. No other information provided by the issuing bank. Possible fix: retry with another form of payment @@ -341,7 +341,7 @@ def get_processor_exception_html(exception): # 205 was Stolen or lost card. Might as well not show this message to the person using such a card. '205': _('Unknown reason'), '207': _('Issuing bank unavailable. Possible fix: retry again after a few minutes'), - '208': _(dedent( + '208': dedent(_( """ Inactive card or card not authorized for card-not-present transactions. Possible fix: retry with another form of payment @@ -352,13 +352,13 @@ def get_processor_exception_html(exception): # Might as well not show this message to the person using such a card. '221': _('Unknown reason'), '231': _('Invalid account number. Possible fix: retry with another form of payment'), - '232': _(dedent( + '232': dedent(_( """ The card type is not accepted by the payment processor. Possible fix: retry with another form of payment """)), '233': _('General decline by the processor. Possible fix: retry with another form of payment'), - '234': _(dedent( + '234': dedent(_( """ There is a problem with our CyberSource merchant configuration. Please let us know at {0} """.format(settings.PAYMENT_SUPPORT_EMAIL))), @@ -370,7 +370,7 @@ def get_processor_exception_html(exception): # reason code 239 only applies if we are processing a capture or credit through the API, # so we should never see it '239': _('The requested transaction amount must match the previous transaction amount.'), - '240': _(dedent( + '240': dedent(_( """ The card type sent is invalid or does not correlate with the credit card number. Possible fix: retry with the same card or another form of payment @@ -382,26 +382,26 @@ def get_processor_exception_html(exception): # if the previously successful authorization has already been used by another capture request. # This reason code only applies when we are processing a capture through the API # so we should never see it - '242': _(dedent( + '242': dedent(_( """ You requested a capture through the API, but there is no corresponding, unused authorization record. """)), # we should never see 243 '243': _('The transaction has already been settled or reversed.'), # reason code 246 applies only if we are processing a void through the API. so we should never see it - '246': _(dedent( + '246': dedent(_( """ The capture or credit is not voidable because the capture or credit information has already been submitted to your processor. Or, you requested a void for a type of transaction that cannot be voided. """)), # reason code 247 applies only if we are processing a void through the API. so we should never see it '247': _('You requested a credit for a capture that was previously voided'), - '250': _(dedent( + '250': dedent(_( """ Error: The request was received, but there was a timeout at the payment processor. Possible fix: retry the payment. """)), - '520': _(dedent( + '520': dedent(_( """ The authorization request was approved by the issuing bank but declined by CyberSource.' Possible fix: retry with a different form of payment. diff --git a/lms/static/admin/js/calendar.js b/lms/static/admin/js/calendar.js index c95a95db1b14..750e8ee463d0 100644 --- a/lms/static/admin/js/calendar.js +++ b/lms/static/admin/js/calendar.js @@ -23,8 +23,10 @@ function quickElement() { // CalendarNamespace -- Provides a collection of HTML calendar-related helper functions var CalendarNamespace = { - monthsOfYear: gettext('January February March April May June July August September October November December').split(' '), - daysOfWeek: gettext('S M T W T F S').split(' '), + // Translators: the names of months, keep the pipe (|) separators. + monthsOfYear: gettext('January|February|March|April|May|June|July|August|September|October|November|December').split('|'), + // Translators: abbreviations for days of the week, keep the pipe (|) separators. + daysOfWeek: gettext('S|M|T|W|T|F|S').split('|'), firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')), isLeapYear: function(year) { return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0)); diff --git a/lms/static/admin/js/dateparse.js b/lms/static/admin/js/dateparse.js index 3cb82dea1352..e46ab1dc29be 100644 --- a/lms/static/admin/js/dateparse.js +++ b/lms/static/admin/js/dateparse.js @@ -29,8 +29,10 @@ if (typeof Array.prototype.filter == 'undefined') { }; } -var monthNames = gettext("January February March April May June July August September October November December").split(" "); -var weekdayNames = gettext("Sunday Monday Tuesday Wednesday Thursday Friday Saturday").split(" "); +// Translators: the names of months, keep the pipe (|) separators. +var monthNames = gettext("January|February|March|April|May|June|July|August|September|October|November|December").split("|"); +// Translators: the names of days, keep the pipe (|) separators. +var weekdayNames = gettext("Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday").split("|"); /* Takes a string, returns the index of the month matching that string, throws an error if 0 or more than 1 matches diff --git a/lms/templates/static_templates/server-overloaded.html b/lms/templates/static_templates/server-overloaded.html index 7079ad4d2e7d..05a25f228c78 100644 --- a/lms/templates/static_templates/server-overloaded.html +++ b/lms/templates/static_templates/server-overloaded.html @@ -3,5 +3,5 @@

    ${_("Currently the {platform_name} servers are overloaded").format(platform_name=settings.PLATFORM_NAME)}

    -

    ${_("Our staff is currently working to get the site back up as soon as possible. Please email us at {tech_support_email} to report any problems or downtime.").format(tech_support_email=settings.TECH_SUPPORT_EMAIL)}

    +

    ${_("Our staff is currently working to get the site back up as soon as possible. Please email us at {tech_support_email} to report any problems or downtime.").format(tech_support_email=settings.TECH_SUPPORT_EMAIL)}

    diff --git a/lms/templates/verify_student/_reverification_support.html b/lms/templates/verify_student/_reverification_support.html index 14b249762e21..44bf0c89d8cb 100644 --- a/lms/templates/verify_student/_reverification_support.html +++ b/lms/templates/verify_student/_reverification_support.html @@ -18,7 +18,7 @@

    ${_("Why Do I Need to Re-Verify?")}

  1. ${_("Having Technical Trouble?")}

    -

    ${_("Please make sure your browser is updated to the {strong_start}{a_start}most recent version possible{a_end}{strong_end}. Also, please make sure your {strong_start}web cam is plugged in, turned on, and allowed to function in your web browser (commonly adjustable in your browser settings).{strong_end}").format(a_start='', a_end="", strong_start="", strong_end="")}

    +

    ${_("Please make sure your browser is updated to the {a_start}most recent version possible{a_end}. Also, please make sure your web cam is plugged in, turned on, and allowed to function in your web browser (commonly adjustable in your browser settings)").format(a_start='', a_end="")}

  2. diff --git a/lms/templates/verify_student/_verification_support.html b/lms/templates/verify_student/_verification_support.html index 260ba7bae380..a4d219695894 100644 --- a/lms/templates/verify_student/_verification_support.html +++ b/lms/templates/verify_student/_verification_support.html @@ -27,7 +27,7 @@

    ${_("Change your mind?")}

  3. ${_("Technical Requirements")}

    -

    ${_("Please make sure your browser is updated to the {strong_start}{a_start}most recent version possible{a_end}{strong_end}. Also, please make sure your {strong_start}web cam is plugged in, turned on, and allowed to function in your web browser (commonly adjustable in your browser settings).{strong_end}").format(a_start='', a_end="", strong_start="", strong_end="")}

    +

    ${_("Please make sure your browser is updated to the {a_start}most recent version possible{a_end}. Also, please make sure your web cam is plugged in, turned on, and allowed to function in your web browser (commonly adjustable in your browser settings).").format(a_start='', a_end="")}

  4. diff --git a/lms/templates/verify_student/show_requirements.html b/lms/templates/verify_student/show_requirements.html index 3280fec89a29..ed9fa4747b12 100644 --- a/lms/templates/verify_student/show_requirements.html +++ b/lms/templates/verify_student/show_requirements.html @@ -169,7 +169,7 @@

    ${_("Credit or Debit Card")}

    %if upgrade: ${_("Missing something? You can always continue to audit this course instead.")} %else: - ${_("Missing something? You can always {a_start} audit this course instead {a_end}").format(a_start='', a_end="")} + ${_("Missing something? You can always {a_start}audit this course instead{a_end}").format(a_start='', a_end="")} %endif
      From c7cf0c6d3e1a517f1c7f4edfe19dee23cfb0d258 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 24 Dec 2013 10:44:25 -0500 Subject: [PATCH 07/15] Fixes to Translator comments found while debugging the i18n pipeline. --- cms/templates/export.html | 1 - cms/templates/import.html | 4 ---- lms/templates/courseware/courseware-error.html | 1 - lms/templates/wiki/includes/cheatsheet.html | 15 ++++++--------- lms/templates/wiki/includes/editor_widget.html | 9 +++------ 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/cms/templates/export.html b/cms/templates/export.html index 6f2853e77de7..b70bf7ae3691 100644 --- a/cms/templates/export.html +++ b/cms/templates/export.html @@ -94,7 +94,6 @@

      ${_("About Exporting Courses")}

      ## Translators: ".tar.gz" is a file extension, and should not be translated -

      ${_("You can export courses and edit them outside of Studio. The exported file is a .tar.gz file (that is, a .tar file compressed with GNU Zip) that contains the course structure and content. You can also re-import courses that you've exported.").format(em_start='', em_end="")}

      diff --git a/cms/templates/import.html b/cms/templates/import.html index a4ad922b89c0..51ee1ef83929 100644 --- a/cms/templates/import.html +++ b/cms/templates/import.html @@ -126,20 +126,16 @@

      ${_("Success")}

      diff --git a/lms/templates/courseware/courseware-error.html b/lms/templates/courseware/courseware-error.html index 9018495bff7e..71744259a663 100644 --- a/lms/templates/courseware/courseware-error.html +++ b/lms/templates/courseware/courseware-error.html @@ -2,7 +2,6 @@ <%inherit file="/main.html" /> <%namespace name='static' file='../static_content.html'/> <%block name="bodyclass">courseware -## Translators: "edX" should *not* be translated <%block name="title">${_("Courseware")} - ${settings.PLATFORM_NAME} <%block name="headextra"> diff --git a/lms/templates/wiki/includes/cheatsheet.html b/lms/templates/wiki/includes/cheatsheet.html index 6c3f359ef760..4ac9bbd85adb 100644 --- a/lms/templates/wiki/includes/cheatsheet.html +++ b/lms/templates/wiki/includes/cheatsheet.html @@ -21,9 +21,7 @@

      {% trans "Wiki Syntax Help" %}

      {% trans "[Article Name](wiki:ArticleName)" %}
      - {% comment %} - Translators: Do not translate "edX" - {% endcomment %} + {# Translators: Do not translate "edX" #}

      {% trans "edX Additions:" %}

      circuit-schematic:
      $LaTeX Math Expression$
      @@ -34,12 +32,9 @@

      {% trans "edX Additions:" %}

      {% trans "Useful examples:" %}

      -{% comment %}
      -  Translators: Do not translate "edX" or "Wikipedia"
      -{% endcomment %}
      -{% trans "http://wikipedia.org" %}
      -{% trans "[Wikipedia](http://wikipedia.org)" %}
      -{% trans "[edX Wiki](wiki:/edx/)" %}
      +http://wikipedia.org
      +[Wikipedia](http://wikipedia.org)
      +[edX Wiki](wiki:/edx/)
                     
       {% trans "Huge Header" %}
      @@ -48,8 +43,10 @@ 

      {% trans "Useful examples:" %}

      {% trans "Smaller Header" %} --------------
      +{# Translators: Leave the punctuation, but translate "emphasis" #}
       {% trans "*emphasis* or _emphasis_" %}
      +{# Translators: Leave the punctuation, but translate "strong" #}
       {% trans "**strong** or __strong__" %}
       - {% trans "Unordered List" %}
      diff --git a/lms/templates/wiki/includes/editor_widget.html b/lms/templates/wiki/includes/editor_widget.html
      index e306787488bc..54cef5e36ebe 100644
      --- a/lms/templates/wiki/includes/editor_widget.html
      +++ b/lms/templates/wiki/includes/editor_widget.html
      @@ -1,10 +1,7 @@
       {% load i18n %}
       
       

      - {% comment %} - Translators: Do not translate 'cheatsheetLink' - {% endcomment %} - {% blocktrans with start_link="" end_link="" %} - Markdown syntax is allowed. See the {{ start_link }}cheatsheet{{ end_link }} for help. - {% endblocktrans %} + {% blocktrans with start_link="" end_link="" %} + Markdown syntax is allowed. See the {{ start_link }}cheatsheet{{ end_link }} for help. + {% endblocktrans %}

      From be6c57f53a798cd2b83ddbe9f6d6e836c93167df Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Mon, 23 Dec 2013 15:26:44 -0500 Subject: [PATCH 08/15] Mark XModule strings for i18n --- .../xmodule/js/src/annotatable/display.coffee | 15 +++++++++++---- .../xmodule/xmodule/js/src/capa/display.coffee | 10 +++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/annotatable/display.coffee b/common/lib/xmodule/xmodule/js/src/annotatable/display.coffee index 8a32c8f51edf..531ea9114518 100644 --- a/common/lib/xmodule/xmodule/js/src/annotatable/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/annotatable/display.coffee @@ -160,7 +160,10 @@ class @Annotatable @hideTips visible toggleAnnotationButtonText: (hide) -> - buttonText = (if hide then 'Show' else 'Hide')+' Annotations' + if hide + buttonText = gettext('Show Annotations') + else + buttonText = gettext('Hide Annotations') @$(@toggleAnnotationsSelector).text(buttonText) toggleInstructions: () -> @@ -169,7 +172,10 @@ class @Annotatable @toggleInstructionsText hide toggleInstructionsButton: (hide) -> - txt = (if hide then 'Expand' else 'Collapse')+' Instructions' + if hide + txt = gettext('Expand Instructions') + else + txt = gettext('Collapse Instructions') cls = (if hide then ['expanded', 'collapsed'] else ['collapsed','expanded']) @$(@toggleInstructionsSelector).text(txt).removeClass(cls[0]).addClass(cls[1]) @@ -221,13 +227,14 @@ class @Annotatable makeTipTitle: (el) -> (api) => title = $(el).data('comment-title') - (if title then title else 'Commentary') + (if title then title else gettext('Commentary')) createComment: (text) -> $("
      #{text}
      ") createReplyLink: (problem_id) -> - $("Reply to Annotation") + linktxt = gettext('Reply to Annotation') + $("#{linktxt}") findVisibleTips: () -> visible = [] diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee index 967b98017920..91b83e21f306 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee @@ -318,14 +318,16 @@ class @Problem @el.find('.problem > div').each (index, element) => MathJax.Hub.Queue ["Typeset", MathJax.Hub, element] - @$('.show-label').text 'Hide Answer(s)' + `// Translators: the word Answer here refers to the answer to a problem the student must solve.` + @$('.show-label').text gettext('Hide Answer(s)') @el.addClass 'showed' @updateProgress response else @$('[id^=answer_], [id^=solution_]').text '' @$('[correct_answer]').attr correct_answer: null @el.removeClass 'showed' - @$('.show-label').text 'Show Answer(s)' + `// Translators: the word Answer here refers to the answer to a problem the student must solve.` + @$('.show-label').text gettext('Show Answer(s)') @el.find(".capa_inputtype").each (index, inputtype) => display = @inputtypeDisplays[$(inputtype).attr('id')] @@ -403,6 +405,7 @@ class @Problem formulaequationinput: (element) -> $(element).find('input').on 'input', -> $p = $(element).find('p.status') + `// Translators: the word Answer here is about answering a problem the student must solve.` $p.text gettext("unanswered") $p.parent().removeClass().addClass "unanswered" @@ -431,7 +434,8 @@ class @Problem textline: (element) -> $(element).find('input').on 'input', -> $p = $(element).find('p.status') - $p.text "unanswered" + `// Translators: the word Answer here is about answering a problem the student must solve.` + $p.text gettext("unanswered") $p.parent().removeClass().addClass "unanswered" inputtypeSetupMethods: From b998a161d270c1071f47b8cb5f8d07beed41a1f7 Mon Sep 17 00:00:00 2001 From: zubiar-arbi Date: Fri, 3 Jan 2014 18:27:26 +0500 Subject: [PATCH 09/15] Assign valid content_type to static resource (import_static_content) STUD-878 --- cms/djangoapps/contentstore/tests/test_assets.py | 8 ++++++++ .../xmodule/xmodule/modulestore/xml_importer.py | 10 ++++++---- common/test/data/toy/policies/assets.json | 10 ++++++++++ common/test/data/toy/static/textbook.pdf | Bin 0 -> 9478 bytes 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 common/test/data/toy/policies/assets.json create mode 100644 common/test/data/toy/static/textbook.pdf diff --git a/cms/djangoapps/contentstore/tests/test_assets.py b/cms/djangoapps/contentstore/tests/test_assets.py index 9ed9650b45eb..f9e2a65e1de9 100644 --- a/cms/djangoapps/contentstore/tests/test_assets.py +++ b/cms/djangoapps/contentstore/tests/test_assets.py @@ -61,6 +61,14 @@ def test_toy_assets(self): self.assertContains(resp, "new AssetCollection([{") self.assertContains(resp, "/c4x/edX/toy/asset/handouts_sample_handout.txt") + # Test valid contentType for pdf asset (textbook.pdf) + self.assertContains(resp, "/c4x/edX/toy/asset/textbook.pdf") + asset_location = StaticContent.get_location_from_path('/c4x/edX/toy/asset/textbook.pdf') + content = contentstore().find(asset_location) + # Check after import textbook.pdf has valid contentType ('application/pdf') + # Note: Actual contentType for textbook.pdf in asset.json is 'text/pdf' + self.assertEqual(content.content_type, 'application/pdf') + class UploadTestCase(CourseTestCase): """ diff --git a/common/lib/xmodule/xmodule/modulestore/xml_importer.py b/common/lib/xmodule/xmodule/modulestore/xml_importer.py index 64392b764395..744a771e1a43 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_importer.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_importer.py @@ -33,6 +33,7 @@ def import_static_content( policy = {} verbose = True + mimetypes_list = mimetypes.types_map.values() for dirname, _, filenames in os.walk(static_dir): for filename in filenames: @@ -64,10 +65,11 @@ def import_static_content( policy_ele = policy.get(content_loc.name, {}) displayname = policy_ele.get('displayname', filename) locked = policy_ele.get('locked', False) - mime_type = policy_ele.get( - 'contentType', - mimetypes.guess_type(filename)[0] - ) + mime_type = policy_ele.get('contentType') + + # Check extracted contentType in list of all valid mimetypes + if not mime_type or mime_type not in mimetypes_list: + mime_type = mimetypes.guess_type(filename)[0] # Assign guessed mimetype content = StaticContent( content_loc, displayname, mime_type, data, import_path=fullname_with_subpath, locked=locked diff --git a/common/test/data/toy/policies/assets.json b/common/test/data/toy/policies/assets.json new file mode 100644 index 000000000000..c051b44f8145 --- /dev/null +++ b/common/test/data/toy/policies/assets.json @@ -0,0 +1,10 @@ +{ + "textbook.pdf":{ + "contentType":"text/pdf", + "displayname":"textbook.pdf", + "locked":false, + "filename":"/c4x/edx/toy/asset/textbook.pdf", + "import_path":null, + "thumbnail_location":null + } +} diff --git a/common/test/data/toy/static/textbook.pdf b/common/test/data/toy/static/textbook.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e6e7a031ce590307d2233cc3f1176ac2309cde27 GIT binary patch literal 9478 zcmbt)by$>J_qKFNhtflX(PvMc$9UO@g7P0N~W>Y#;0MZ@8&;?&m3`S{k3PXcw0d z(_aKtE21)1N)wT6x$p2uN%E8?45#B3U2#8ql6H|1;AsGK0?NsGXPEBwrb7U^Q)oGf zL@^8c5uOC+EyVL6@o;s#E`|2|H^KL?z5>$t&{uH^eWE~a>QTuQg#p@=4ADU3&{8|v}>pKGG6(Aj$tFt=-3UdXB{1V7HJGmkIT>+?|A|t2{v$BQAI(q?3 z1dsv|pddh0OwbG;8N@&ApvL_Uz81n6sta=im>`YGD+2iSU|wzjGXTGwvx752*98KF z0Z=)Ta|HrKuhmOQA#;PYcrDh`1M&#~z^D$SepH_RFd_CA6My6vh?)&@dKv&AfL{ic zWG7^X0sQhX4_hcq2?6o`-^mZtS9hS*Ct!CAM0788*f=Y}7CfCNzqe}F!^!l+%m0#V! zLn{N{SkCzN(I{MQ+UMkSZDcs(9Nw!s>HmITvRRd6MB;@->hNfrq_3LWLN4EUN%;P4 z_##ZT5U=;ymh#n(->$zZSMuE4P@DLe$mhZ#L4gZH z+%|v#v}YY3kFAK#B&(=Cp^wX9Z7MGaDs+fa$q#sPCuco%uXR1C-V}2FAZ8HY0r`gc zru5O}3GbNB%1 z&2iC9JRzKYciVG9r#9ak{`~$f2X1n5+LRnj+jK9nsr8~>rki6vuO=7n3veN4Iq~KAm_h62`tFepsg%6m&(DTq z`t_wv7p&6(?y~+G^g7`xCHy5glj~EG1zlgS`g_B7&|50jJ4ENhJ`@#yD9L`hKKJZ` zVa#_uhV7^R(B<05f;i7-k2%+f@7Zo#c>s!DT`t5CU-w&AvVsryA2X_#Cc6vzJ=R zl>K^GnLTG9q5l~ELnW+f>!3VbR3rT0?)Yeg5in7l-g_XF!S$n+ufO@3MWkH#r*!0w5%a+`l1z zG=PEv0R9KIR&F-eE{cNjQIP-te~AhTA~lIzN9ez`iHM-mg}VN||5qOfBmzKvkuCf` zey`htf+%l60s;Wk6Ick9*T1~`t49YLGysT!0sMx)#P}dVpQVuQLbK33wa!a2?Bt>&K`fRy=%em#rJ!I|Kt4es|f^%35p;s|F830 ztFf<}-qh5>dYd(S+OXPMR@(5K8k~KP15=inT9&Mn8#_1-@Sc@K*~=z0j)o_oBRDC7 zQvuyF#o0R@5-G2?8N8(q$R2x`o7f*E+-9tJXgc`>t6Gve{E^+Kve9O!H^vE0t-*Yw zS7^@JowW%A(8AsEdoAJKr}QJ`#?WuN487ntE2E$+mUFwOV;0EmY9^JwRNKKMYD|j#@cG`L|F@ISaef(ouJcdU_X@h-&bx0$R+?0vfj$*F zS4o46b9!ZcSm^=J0D*?J{!jBI!(}XSzY59;(3jq{mDGW+QE(r}weAayCo1#2PQ=Nj zwIvwOSDrKcdSmTLKL$o71z4l0Lj#T}oN1r^eyyeqRI%_RLg1`n%Wdu4Dlf6%u`@s# zOP^`r=$MCp0;6UB8@z&yS?Mv0B?%dJh5iY+z^No;BLc33UsmV~v%;_I7BO=yIn^1kdG9OmLip z_1{%0pEzt~s^Qbp%bHFx-#INBLwHY=Uk0d+-Q#egaHcGdz_Kh#WxtR&QX`8=kQrAo z=F-qnO<;Y}KZZSM+KGq29VAJXQ(}`@miw}9*q;Rmf8N0BNO_i){$mz%i#5cg*M?Nl_G!-vX`)z>Nn?b9GNZ4G71 z3s~y-*22S=rzy|DA^t*JUqf)R2s_ZzBgAPH%T1KXe~RpyM!%ds93D<{ZI1PD=dm!J z{aWg9s8`1f!eZR8tHt&;p4(*^lHly3xAIr#js9daH%GI*|JndE#rMvfQd81;1(d&V zn@_Wc)X-S0@~VGa+P+8nL2mi@gz0;i*M)xWDMeWs^ZH|b4O$cR?{?bR%@vi3 zgHA8}LE~*SwidiWRE7NFXM-nAhoG#ItlhzrwB3isW-b?*Vc%ptUF8%awtG6G-n8eS z(+84`pD|RqHZGz^w8b0~#jw=N-&-9E=Bv4L;aP{t;T}Oo&cz+3yAP1W{sCwYP%G|m ztfDn%8anuFjv3+-#41Ph(VR$DfWVyX{RV9nMRw0cmJ5wXCuu~NwLuVGVPfMU5ju`mkS5 zM|C<;sbAwzf<2@$tkgQ7eQv~WaJnjb#_7a!j>hTn!r&g2a6ErLN1kGFm~mv;l^Pgb6~Re-sU?BIZ-*J)f|D$^kawWZwv7b06s`AS)e-6C%2=2$n7ojq~W z%0nPLbz<1wL83X)Kj{a{cQ(;9>$BoBP0Y$OrvkPbwnO9BtQXqH_QKU<{a~S0EsT0O zp=Wg%y&Zu|oJ1?1V{1LI&4V8#eTObThMdu8->?LD=t#p?%;cQdRaGRsGwJ%iV<{w8 z-p<5T?Af3uSb6w0l?qNd(RCTL2}zu}>4DuGx6}8X&Nrxa*nG{4FJ9=;M8js)bCaH( z4qyKI9NI*=8y~lfFIK(;m9)2fyN{5(NXS_TK+t~ zpIghyckWx<@NBo#kulCCwqD^Hzu8)1rrIA%T1liFEmCt@Gm$De`Q+9j!{qecDu%kM z=*7|vlWiF!v#hqdGmPI$eI9FKm39$Fs1H{!%@xkDi%eeG+=nfv*`N0e)Fv&Al1^+)c6w zM$PE*!1&XhIhpY<6*mps-+VI=(YLaWe{rMp#pr0>6P6n^A6-a_L@Jdq2y|^@26I2_ zYE!@V7Ko9YHkoZ(HzVgULX=WxWu3ks6ThKY96qcHBYx)N=uplikaPX;xG#B`A7x$#Ub{~g~{@a zP@%AI?hKxLDI2dcB)bAz>k7OJJBZ&T@Rrh7V%F9g^F? zcX7hW4vsddp*vs3J@!do&VPE$%fo1k1})?iefs>c=3QD%+s6yBZyniD1rKxc(5%s> zPW2r9_bKe0QC4?fmBTmMdZf`X@8`~@2qX(2(@0o?F5O2 z?vFqd%tKsw2mOQ;yha0wmKr|*Oiw@Kj?pI4hP7Z7W)%Y@fBMRLb;JNn1LbfVMp!1g5u&N1iQSU-)$V-?mTr$y=8_aR*~d|ktEb}J11vH3A~NMTOrvo}VIsGx*K5KRqG9rbF#bW6=#}wn#&hb7^0-BH|D(O#%g9%jkZmmCq)zBv#Q)e2gk}ErNS2o z(84iOsTM+3qD+s3VxioU!(+ok{F6gI_jJVSdEHhuF9!lO2p`q*uXqx_JfIsLx7_An zIE@`buNXn<)&O6_0i#k0P%t9l3Cl;)}ul3bZQ&INstnDbX4Sl zS;fLU6!771U1HU8C_|4mR)5*Ar&}W5x(|B(YYg(*(de`kilqd z&?(x;nIg@tGt)V1Tr9skd;esCMKcrnRe859>szeCF7YX&@cEvDSFRJy`^3zl=JRe* zO{Mv>p@IGz&w>^Ma2i6u*pw7FFD(W8N@uJtz48-6DZ48mZ2U8m=_E!jdh_S={UrA{ zZ}Z6-8Esa*0N?71=ghFW%cgnH_k6H?n09Hd_Hv*@**nk+uP5^40Ce&Kn?)F>x4!QU zZPUs$b%PzWwR)ssv_Dd(#=KaU+!1}pgclgh^h}pJ<~;LrX09x$+8W9GT-H07gZG%=@zd_OY%-*v!8lFqC;yS zW8mQr*L%@VJYD1xO-Vhzbx{yg!~C&eln~Q)jZiBRY7HGD9*>6MD)a1So|%GI^+rPW zZYgk!PCouAy*dNG`-Q3Wd?RBl6j-g2*}iOfKlSCua<+f2-}B-{mtII}e1DomZ;u`j z%^7xzK`wL{VO*>d<$6X??!HsDDqd|U*j+kPfDY7Oo$L`)6->)KPFPn>O$feODZ_D? z(3NBPC{)?G9r~zA{;iNw7r4*;u`f@XeS+J)7?na2yZY>KyInk)-vj}*wsB0bzkb_o3uCLLwTm*RrpS&GwqcjDy!uRkt- z-gT|9f7L^q@^Y;I5Cl)vCpZ7TG@97w`K_%@!2V)>hdn$u#`6mw3wI%p{YhSv5w$!2 zJp;2=iI$=G&YFznP=sc#&pCfU%h9YnBK|A!NW;!XOX%+_V8z6>G}h5O3z zcYa2hEhP^)BtSIz7B$T~Voh`jL_QfqtwvI_C6A+y0uGk@P422OP2JjpZWs~5WgMxV zN?B?_ACmD(C6wGh>6wS)>sr3ZmW8~drN%-_zeN5x$~g?u%vzz8lfyksx9v(e940vsvuNpHocXPiC;^#0+sD=DNn z0SZS64brE4o7&%{ZVlO|Vb0r((~zn4N}ING7JeE~8v&m1c&FXXI8HvU`x?B(J7%3c zCYfG)QHu?a?;a|}^Bo?Yw3MM3shMCZ%Yw%|m|LA$_hNXo+_HvQ8B$-mBHuclvv_>u z5oq^pqkh)!YGKG1dV@&{U-B*SE!rsUsVLx}<5OFU?Ke||(9%2?{lz6Os(TWo+2p2D zt)scBlhp2+BTI?ZBY9@Z^7CM1%22ErNckx z1B{q$-FX)*5)pMYPuF;s_N1@NHPyO_eR8jnL`rEDTH;rLxx?@+O#vr3Yr()}B+qVTS4BvORfa|Ip&0 z3WglJN_Q_{p9+HZ_URtgE|ut!+&1^N#LM(`EXe|`>S4t-(lw(euqeVilzl5WK*)16 z?L_%Y;a-9}k=9_U2ZVIoB?>aUGb{Q}#p#9X8qUxfVG*fNs#uy;9g~<{U2bNBs9bGT zr8tqX(SfAtE%PrT>xM$K=ii!i#Y^?_urtdB?C9{h^p^CZd^E=(haZdM3%~Ri#|N2( zpC>*bim#2A=;D2vFNz2kY~uy@XHaa9V}PT<_?U!1jOpHk2QpNA^jJLD)5#q&O}Sbh zr7yAgMG5_?xU`t>=NTwhDO0^->)<~>m@2Cq`M@*L?cHM6JOR}e%Ix8m;2rgn!DJd( zf{{}U4S=gHPY#uG>We*jK8yCR?zV}2 zE2^0+J9odARnIFKbnc+AQ`fq*GaRXpCBzt*Wye6k_P$;$t-Rw+4yD7sORh`(WU=q$ zC0)J6$8w2>L@MhAqK%rbb7)uCRe~q(^okMEWZ2ZE-3|=CtFkIOyRE{MCw`}rp;{y= zJf9#jHB5W>K9wOjhg~}?S!V1k!lr|QF_!BMa1=*AJjja5FLcT>cZP_@Dlbd}^pw#% zGPPI`@_P4(?J#gpse+^{Crl%us(!Cdsp2MGQ-2%z zId}So%a?W5BYg4B8=61Vzfg@v*BKFTy`%0I2kg`e*d}~>@c~~WF%@8wMWh~;d|-&93>Sf%}weCPi*-634NWx@jRT&WHJ`pSUON0$iF}e(Vspfw>dbRdzaCun3%9 zsVO*TCjkAsb}gJtW;}E|UZ+dzKjD3!mZ5*%FSouBkZ_K@^M>sLD}VXcGOgI@tpl;I zy2fP8Ff@K^zPhSlgID$Wr5)r&ZUVOIcrT-2Gu-gGRnz#CSB$gF!c;jgwjP-ccYo6Zp0BWXGv zbX91Rf&4pK4s5&jv#|}P#~dr0yF_ERHa(sxkZsiQrR>gQ`b`n`^c@^O5@w4jI6NdL zNQ}UGB>~zW$O-&5(j0GA@O`5HL43c$_{gfFNTQRJpV%eexyl!!-e@yR-$6>p9-(IE z<_&&Up0k6?N)mQyEWKrFz}?mIpo{}L1Yb7KXgHSFeWlhHXp!dVyDpH6OOrd!6$3Aw z%x0%P&bBoemAk1%h>%_(~;qZJqzuopbr z=*RMkDa3229C~1yQrW~8yJL1F`F!u|Ny+hpb(4xA?isVGz)$X%CtHWy6+;uQZ^}PC zxEgCLYn7;6@ia}ba5XbOf4f$;zE^bl6Gt27FZeGU)bCmd5Li^`H^Bt_T^_)x@8o9d z<^Z$e`cKzy`koU>%m6fX0fqpe03Vo77@+MALAdz+S%bRN`I3{oTvf-1uNUXjQ!2!bIOYg3IK%!LnS? zk>dPQ^qbW(`I9{REke~5=%IWATziWw4UlnnvvEcMkkrLB1%<3luyThYi$Q?DD;jHILh*S!Fz-!cI~G2{$TpFd?lQQ?2c z1O)zVEEpNPzmF9V7C^Etf0qG8fymYJUotTGpK}2T{6hv55&Ne;Fp_@yFMWc7C`#?` zHUvSakpEo*69^TOSxQmjHepXJ;e<`zzV}Do$``BpZ9Z%2ec$e5|CXpr{oxsZgk(Fj5%=d56Q{ qAP`&tDr^Y>T0)Sg=l}W2FLKb;4f$Vqy@ Date: Mon, 6 Jan 2014 11:31:58 -0500 Subject: [PATCH 10/15] Fix URI vendor module to be referenced via a relative URL. --- cms/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/templates/base.html b/cms/templates/base.html index 9be2b92a01fc..6f87c4c5a973 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -77,7 +77,7 @@ "utility": "js/src/utility", "accessibility": "js/src/accessibility_tools", "draggabilly": "js/vendor/draggabilly.pkgd", - "URI": "/js/vendor/URI.min", + "URI": "js/vendor/URI.min", // externally hosted files "tender": "//edxedge.tenderapp.com/tender_widget", From bdd6b739570999d989dda28cc2e052330797e312 Mon Sep 17 00:00:00 2001 From: spearce Date: Mon, 6 Jan 2014 11:37:54 -0500 Subject: [PATCH 11/15] Update JSInput info with feedback from Jean-Michel Add more specific info about HTML+CSS+JS files, SOP --- .../source/advanced_problems.rst | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/docs/course_authors/source/advanced_problems.rst b/docs/course_authors/source/advanced_problems.rst index b55539d7fcc1..8b48df4d0400 100644 --- a/docs/course_authors/source/advanced_problems.rst +++ b/docs/course_authors/source/advanced_problems.rst @@ -64,13 +64,16 @@ Create a Circuit Schematic Builder Problem Custom JavaScript Display and Grading ------------------------------------- -Custom JavaScript display and grading problems (also called custom JavaScript problems or -JS Input problems) allow you to create your own learning tool -using HTML and other standard Internet languages and then add the tool directly -into Studio. When you use this problem type, Studio embeds your tool in an -inline frame (IFrame) so that your students can interact with it in the LMS. You can grade -your students' work using JavaScript and some basic Python, and the grading -is integrated into the edX grading system. +Custom JavaScript display and grading problems (also called custom JavaScript problems +or JS Input problems) allow you to create a custom problem or tool that uses JavaScript +and then add the problem or tool directly into Studio. When you create a JS Input problem, +Studio embeds the problem in an inline frame (IFrame) so that your students can interact with +it in the LMS. You can grade your students’ work using JavaScript and some basic Python, and +the grading is integrated into the edX grading system. + +The JS Input problem that you create must use HTML, JavaScript, and cascading style sheets +(CSS). You can use any application creation tool, such as the Google Web Toolkit (GWT), to +create your JS Input problem. .. image:: /Images/JavaScriptInputExample.gif @@ -85,13 +88,20 @@ Create a Custom JavaScript Display and Grading Problem #. In the component that appears, click **Edit**. #. In the component editor, modify the example code according to your problem. - - If some elements of your problem are located in different places, you need to - bypass the same-origin policy (SOP). To do this, change **sop="false"** - in line 8 to **sop="true"**. For more information, see - `same-origin policy `_. - -#. Click the **Settings** tab. -#. Set **Maximum Attempts** to a number larger than zero. + - All problems have more than one element. Most problems conform to the same-origin + policy (SOP), meaning that all elements have the same protocol, host, and port. + For example, **http**://**store.company.com**:**81**/subdirectory_1/JSInputElement.html and + **http**://**store.company.com**:**81**/subdirectory_2/JSInputElement.js have the same protocol + (http), host (store.company.com), and port (81). + + If any elements of your problem use a different protocol, host, or port, you need to + bypass the SOP. For example, **https**://**info.company.com**/JSInputElement2.html + uses a different protocol, host, and port. To bypass the SOP, change + **sop="false"** in line 8 of the example code to **sop="true"**. For more information, see the same-origin policy + page on the `Mozilla Developer Network `_ + or on `Wikipedia `_. +#. If you want your problem to have a **Save** button, click the **Settings** tab, and then set + **Maximum Attempts** to a number larger than zero. #. Click **Save**. Re-create the Example Problem @@ -104,6 +114,9 @@ To re-create the example problem above, you'll need the following files. - webGLDemo.css - three.min.js +You'll create the first three files using the code in :ref:`Appendix F`. The three.min.js file is a library +file that you'll download. + #. Go to :ref:`Appendix F` and use the code samples to create the following files. - webGLDemo.html From 3939b138953cac86e187e21acb723baa45c3858f Mon Sep 17 00:00:00 2001 From: spearce Date: Mon, 6 Jan 2014 13:53:04 -0500 Subject: [PATCH 12/15] Move JSInput info to Advanced Problems. Move LTI into to Tools. Create Tools topic that includes info about LTI components, word clouds, zooming images. --- .../Images/TextInput_MultipleAnswer.gif | Bin 0 -> 16123 bytes .../{ZoomingImage => Zooming_Image.gif} | Bin docs/course_authors/source/create_lti.rst | 188 --------------- .../source/create_problem_component.rst | 46 ++-- docs/course_authors/source/index.rst | 10 +- .../source/javascript_input.rst | 113 --------- docs/course_authors/source/tools.rst | 217 +++++++++++++++--- .../source/tools_unpublished.rst | 49 ++++ 8 files changed, 257 insertions(+), 366 deletions(-) create mode 100644 docs/course_authors/source/Images/TextInput_MultipleAnswer.gif rename docs/course_authors/source/Images/{ZoomingImage => Zooming_Image.gif} (100%) delete mode 100644 docs/course_authors/source/create_lti.rst delete mode 100644 docs/course_authors/source/javascript_input.rst create mode 100644 docs/course_authors/source/tools_unpublished.rst diff --git a/docs/course_authors/source/Images/TextInput_MultipleAnswer.gif b/docs/course_authors/source/Images/TextInput_MultipleAnswer.gif new file mode 100644 index 0000000000000000000000000000000000000000..1e9ecd9e128c21f615844fa5685fa9971cad217d GIT binary patch literal 16123 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 O-|pe63&vr9ga04`_ -version 1.1.1 specifications. - -You can use an LTI component in two ways. - -- You can add external LTI content that is displayed only, such as - textbook content that doesn’t require a student response. -- You can add external LTI content that requires a student response. An - external provider will grade student responses. - -Before you create an LTI component from an external LTI provider in a -unit, you need the following information. - -- The **LTI ID**. This is a value that you create to refer to the external LTI - provider. You should create an LTI ID that you can remember easily. - - The LTI ID can contain uppercase and lowercase alphanumeric - characters, as well as underscore characters (_). It can contain any - number of characters. For example, you may create an LTI ID that is - as simple as **test_lti_id**, or your LTI ID may be a string of - numbers and letters such as **id_21441** or - **book_lti_provider_from_new_york**. -- The **client key**. This value is a sequence of characters that you - obtain from the LTI provider. The client key is used for - authentication and can contain any number of characters. For example, - your client key may be **b289378-f88d-2929-ctools.umich.edu**. -- The **client secret**. This value is a sequence of characters that - you obtain from the LTI provider. The client secret is used for - authentication and can contain any number of characters. For example, - your client secret may be something as simple as **secret**, or it - may be a string of numbers and letters such as **23746387264** or - **yt4984yr8**. -- The **launch URL** (if the LTI component requires a student response - that will be graded). You obtain the launch URL from the LTI - provider. The launch URL is the URL that Studio sends to the external - LTI provider so that the provider can send back students’ grades. - -Create an LTI Component ------------------------ - -Creating an LTI component in your course has three steps. - -#. Add LTI to the **advanced_modules** policy key. -#. Register the LTI provider. -#. Create the LTI component in an individual unit. - -Step 1. Add LTI to the Advanced Modules Policy Key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#. On the **Settings** menu, click **Advanced Settings**. -#. On the **Advanced Settings** page, locate the **Manual Policy - Definition** section, and then locate the **advanced_modules** - policy key (this key is at the top of the list). - - .. image:: Images/AdvancedModulesEmpty.gif - -#. Under **Policy Value**, place your cursor between the brackets, and - then enter **“lti”**. Make sure to include the quotation marks, but - not the period. - - .. image:: Images/LTI_Policy_Key.gif - - **Note** If the **Policy Value** field already contains text, place your - cursor directly after the closing quotation mark for the final item, and - then enter a comma followed by **“lti”** (make sure that you include the - quotation marks). - -#. At the bottom of the page, click **Save Changes**. - -The page refreshes automatically. At the top of the page, -you see a notification that your changes have been saved. - -Step 2. Register the External LTI Provider -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To regiser the external LTI provider, you’ll add the LIT ID, the client -key, and the client secret in the **lti_passports** policy key. - -#. On the **Advanced Settings** page, locate the **lti_passports** - policy key. - -#. Under **Policy Value**, place your cursor between the brackets, and - then enter the LTI ID, client key, and client secret in the following - format (make sure to include the quotation marks and the colons). - - :: - - “lti_id:client_key:client_secret” - - For example, the value in the **lti_passports** field may be the following. - - :: - - “test_lti_id:b289378-f88d-2929-ctools.umich.edu:secret” - - If you have multiple LTI providers, separate the values with a comma. - Make sure to surround each entry with quotation marks. - - :: - - "test_lti_id:b289378-f88d-2929-ctools.umich.edu:secret", - "id_21441:b289378-f88d-2929-ctools.school.edu:23746387264", - "book_lti_provider_from_new_york:b289378-f88d-2929-ctools.company.com:yt4984yr8" - - -#. At the bottom of the page, click **Save Changes**. - -The page refreshes automatically. At the top of the page, -you see a notification that your changes have been saved, and you can -see your entries in the **lti_passports** policy key. - -Step 3. Add the LTI Component to a Unit -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#. In the unit where you want to create the problem, click **Advanced** - under **Add New Component**, and then click **LTI**. -#. In the component that appears, click **Edit**. -#. In the component editor, set the options that you want. See the table - below for a description of each option. -#. Click **Save**. - - .. list-table:: - :widths: 10 80 - :header-rows: 1 - - * - `Setting` - - Description - * - `Display Name` - - Specifies the name of the problem. This name appears above the problem and in - the course ribbon at the top of the page in the courseware. - * - `custom_parameters` - - Enables you to add one or more custom parameters. For example, if you've added an - e-book, a custom parameter may include the page that your e-book should open to. - You could also use a custom parameter to set the background color of the LTI component. - - Every custom parameter has a key and a value. You must add the key and value in the following format. - - :: - - key=value - - For example, a custom parameter may resemble the following. - - :: - - bgcolor=red - - page=144 - - To add a custom parameter, click **Add**. - * - `graded` - - Indicates whether the grade for the problem counts towards student's total grade. By - default, this value is set to **False**. - * - `has_score` - - Specifies whether the problem has a numerical score. By default, this value - is set to **False**. - * - `launch_url` - - Lists the URL that Studio sends to the external LTI provider so that the provider - can send back students' grades. This setting is only used if **graded** is set to - **True**. - * - `lti_id` - - Specifies the LTI ID for the external LTI provider. This value must be the same - LTI ID that you entered on the **Advanced Settings** page. - * - `open_in_a_new_page` - - Indicates whether the problem opens in a new page. If you set this value to **True**, - the student clicks a link that opens the LTI content in a new window. If you set - this value to **False**, the LTI content opens in an IFrame in the current page. - * - `weight` - - Specifies the number of points possible for the problem. By default, if an - external LTI provider grades the problem, the problem is worth 1 point, and - a student’s score can be any value between 0 and 1. - - For more information about problem weights and computing point scores, see :ref:`Problem Weight`. \ No newline at end of file diff --git a/docs/course_authors/source/create_problem_component.rst b/docs/course_authors/source/create_problem_component.rst index 696baf9fd602..bf10a75ace1e 100644 --- a/docs/course_authors/source/create_problem_component.rst +++ b/docs/course_authors/source/create_problem_component.rst @@ -4,20 +4,20 @@ Working with Problem Components ################################ -********* -Overview -********* +****************************** +Overview of Problem Components +****************************** The problem component allows you to add interactive, automatically graded exercises to your course content. You can create many different -types of problems in Studio. +types of problems in Studio. All problems receive a point score, but, by default, problems do not count toward a student's grade. If you want the problems to count toward the -student's grade, change the assignment type of the subsection that contains the +student's grade, change the assignment type of the subsection that contains the problems. -See the following topics: +For more information, see the following topics. * :ref:`Components and the User Interface` * :ref:`Problem Settings` @@ -74,7 +74,7 @@ All problems on the edX platform have several component parts. #. **Feedback.** After a student clicks **Check**, all problems return a green check mark or a red X. - + .. image:: Images/AnatomyofaProblem_Feedback.gif #. **Correct answer.** Most problems require that the instructor specify @@ -92,8 +92,8 @@ All problems on the edX platform have several component parts. #. **Grading.** The instructor may specify whether a group of problems is graded. If a group of problems is graded, a clock icon appears for - that assignment in the course accordion. - + that assignment in the course accordion. + .. image:: Images/clock_icon.gif #. **Due date.** The date that the problem is due. A problem that is @@ -124,9 +124,9 @@ Studio offers two interfaces for editing problem components: the Simple Editor and the Advanced Editor. - The **Simple Editor** allows you to edit problems visually, without - having to work with XML. + having to work with XML. - The **Advanced Editor** converts the problem to edX’s XML standard - and allows you to edit that XML directly. + and allows you to edit that XML directly. .. note:: You can switch at any time from the Simple Editor to the Advanced Editor by clicking **Advanced Editor** in the top right corner @@ -135,11 +135,11 @@ Editor and the Advanced Editor. The Simple Editor ~~~~~~~~~~~~~~~~~ -The Common Problem templates, including multiple choice, open in the Simple Editor. The -following image shows a multiple choice problem in the Simple Editor. +The Common Problem templates, including multiple choice, open in the Simple Editor. The +following image shows a multiple choice problem in the Simple Editor. -The Simple Editor includes a toolbar that helps you format the text of your problem. -When you select text and then click the formatting buttons, the Simple Editor formats +The Simple Editor includes a toolbar that helps you format the text of your problem. +When you select text and then click the formatting buttons, the Simple Editor formats the text for you automatically. The toolbar buttons are the following: 1. Create a level 1 heading. @@ -154,17 +154,17 @@ the text for you automatically. The toolbar buttons are the following: The following image shows a multiple choice problem in the Simple Editor. -.. image:: Images/MultipleChoice_SimpleEditor.gif +.. image:: Images/MultipleChoice_SimpleEditor.gif -.. _Advanced Editor: +.. _Advanced Editor: The Advanced Editor ~~~~~~~~~~~~~~~~~~~ -The **Advanced Editor** opens a problem in XML. The Advanced Problem templates, -such as the circuit schematic builder, open directly in the Advanced Editor. +The **Advanced Editor** opens a problem in XML. The Advanced Problem templates, +such as the circuit schematic builder, open directly in the Advanced Editor. For more information about the XML for different problem types, see :ref:`Appendix E`. - + The following image shows the multiple choice problem above in the Advanced Editor instead of the Simple Editor. @@ -328,8 +328,8 @@ Problem Types Studio includes templates for many different types of problems, from simple multiple choice problems to advanced problems that require the -student to “build” a virtual circuit. Details about each problem type, -including information about how to create the problem, appears in the +student to “build” a virtual circuit. Details about each problem type, +including information about how to create the problem, appears in the page for the problem type. - :ref:`Common Problems` appear on the **Common Problem Types** tab when you @@ -344,7 +344,7 @@ page for the problem type. **Add New Component** in each unit, and these problems are available in the Advanced component. - :ref:`Open Response Assessment Problems` are a new kind of problem that allow you, the - students in your course, or a computer algorithm to grade responses in the form + students in your course, or a computer algorithm to grade responses in the form of essays, files such as computer code, and images. .. _Multiple Problems in One Component: diff --git a/docs/course_authors/source/index.rst b/docs/course_authors/source/index.rst index b5bbc60976ba..ed88c364ed65 100755 --- a/docs/course_authors/source/index.rst +++ b/docs/course_authors/source/index.rst @@ -22,10 +22,9 @@ Contents create_problem_component common_problems advanced_problems - javascript_input - create_lti specialized_problems open_response_assessment + tools set_content_releasedates view_course_content export_import_course @@ -45,10 +44,3 @@ Appendices :glob: appendices/* - - - - - - - diff --git a/docs/course_authors/source/javascript_input.rst b/docs/course_authors/source/javascript_input.rst deleted file mode 100644 index 639e30a4d25d..000000000000 --- a/docs/course_authors/source/javascript_input.rst +++ /dev/null @@ -1,113 +0,0 @@ -.. _JavaScript Input: - -JavaScript Input ----------------- - -The JavaScript Input problem type allows you to create your own learning tool -using HTML and other standard Internet languages and then add the tool directly -into Studio. When you use this problem type, Studio embeds your tool in an -IFrame so that your students can interact with it in the LMS. You can grade -your students' work using JavaScript and some basic Python, and the grading -is integrated into the edX grading system. - -This problem type doesn't appear in the menu of advanced problems in Studio. To -create a JavaScript input problem type, you'll create a blank advanced problem, -and then enter your code into the component editor. - -.. image:: /Images/JavaScriptInputExample.gif - -Create a JavaScript Input Problem -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#. Create your JavaScript application, and then upload all files associated with - that application to the **Files & Uploads** page. -#. In the unit where you want to create the problem, click **Problem** - under **Add New Component**, and then click the **Advanced** tab. -#. Click **Blank Advanced Problem**. -#. In the component that appears, click **Edit**. -#. Click the **Settings** tab. -#. Set **Maximum Attempts** to a number larger than zero. -#. In the component editor, enter your code. -#. Click **Save**. - -To re-create the example problem above, follow these steps. - -#. Go to :ref:`Appendix F` and create the following files: - - - webGLDemo.html - - webGLDemo.js - - webGLDemo.css - - three.min.js - -#. On the **Files & Uploads** page, upload the four files you just created. -#. Create a new blank advanced problem component. -#. On the **Settings** tab, set **Maximum Attempts** to a number larger than - zero. -#. In the problem component editor, paste the code below. -#. Click **Save.** - - - -JavaScript Input Problem Code -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - - In the image below, click the cone. - - - - - - - - -**Notes** - -- The webGLDemo.js file defines the three JavaScript functions (**WebGLDemo.getGrade**, - **WebGLDemo.getState**, and **WebGLDemo.setState**). - -- The JavaScript input problem code uses **WebGLDemo.getGrade**, **WebGLDemo.getState**, - and **WebGLDemo.setState** to grade, save, or restore a problem. These functions must - be global in scope. - -- **WebGLDemo.getState** and **WebGLDemo.setState** are optional. You only have to define - these functions if you want to conserve the state of the problem. - -- **Width** and **height** represent the dimensions of the IFrame that holds the - application. - -- When the problem opens, the cone and the cube are both blue, or "unselected." When - you click either shape once, the shape becomes yellow, or "selected." To unselect - the shape, click it again. Continue clicking the shape to select and unselect it. - -- The response is graded as correct if the cone is selected (yellow) when the user - clicks **Check**. - -- Clicking **Check** or **Save** registers the problem's current state. \ No newline at end of file diff --git a/docs/course_authors/source/tools.rst b/docs/course_authors/source/tools.rst index 6a9703cf51bc..d9d8febf2c99 100644 --- a/docs/course_authors/source/tools.rst +++ b/docs/course_authors/source/tools.rst @@ -9,48 +9,202 @@ Working with Tools Overview of Tools in Studio *************************** -**Intro to Tools text** - you can use various tools in Studio, etc. (Sometimes -called blades, though that's not intuitive for very many people.) +In addition to text, images, and different types of problems, Studio allows you +to add customized learning tools such as word clouds to your course. + +- :ref:`LTI Component`: LTI components allow you to add an external learning application + or textbook to Studio. +- :ref:`Word Cloud`: Word clouds arrange text that students enter - for example, in + response to a question - into a colorful graphic that students can see. +- :ref:`Zooming image`: Zooming images allow you to enlarge sections of an image so + that students can see the section in detail. -- :ref:`Qualtrics Survey` -- Interactive periodic table (if we document this) -- :ref:`Word Cloud` -- :ref:`Zooming image` +.. _LTI Component: -.. _Qualtrics Survey: +************** +LTI Components +************** -**************** -Qualtrics Survey -**************** +You may have discovered or developed an external learning application +that you want to add to your online course. Or, you may have a digital +copy of your textbook that uses a format other than PDF. You can add +external learning applications or textbooks to Studio by using a +Learning Tools Interoperability (LTI) component. The LTI component is +based on the `IMS Global Learning Tools +Interoperability `_ +version 1.1.1 specifications. -**description of Qualtrics survey and explanation of why course teams would want to -use it** +You can use an LTI component in two ways. -**image of Qualtrics survey** +- You can add external LTI content that is displayed only, such as + textbook content that doesn’t require a student response. +- You can add external LTI content that requires a student response. An + external provider will grade student responses. -Create a Qualtrics Survey -~~~~~~~~~~~~~~~~~~~~~~~~~ +Before you create an LTI component from an external LTI provider in a +unit, you need the following information. -To create a Qualtrics survey, you'll use the Anonymous User ID template. This -template contains HTML with instructions. +- The **LTI ID**. This is a value that you create to refer to the external LTI + provider. You should create an LTI ID that you can remember easily. -#. Under **Add New Component**, click **html**, and then click **Anonymous User ID**. + The LTI ID can contain uppercase and lowercase alphanumeric + characters, as well as underscore characters (_). It can contain any + number of characters. For example, you may create an LTI ID that is + as simple as **test_lti_id**, or your LTI ID may be a string of + numbers and letters such as **id_21441** or + **book_lti_provider_from_new_york**. +- The **client key**. This value is a sequence of characters that you + obtain from the LTI provider. The client key is used for + authentication and can contain any number of characters. For example, + your client key may be **b289378-f88d-2929-ctools.umich.edu**. +- The **client secret**. This value is a sequence of characters that + you obtain from the LTI provider. The client secret is used for + authentication and can contain any number of characters. For example, + your client secret may be something as simple as **secret**, or it + may be a string of numbers and letters such as **23746387264** or + **yt4984yr8**. +- The **launch URL** (if the LTI component requires a student response + that will be graded). You obtain the launch URL from the LTI + provider. The launch URL is the URL that Studio sends to the external + LTI provider so that the provider can send back students’ grades. -#. In the empty component that appears, click **Edit**. +Create an LTI Component +----------------------- -#. When the component editor opens, replace the example content with your own content. +Creating an LTI component in your course has three steps. - - **flesh these instructions out more** +#. Add LTI to the **advanced_modules** policy key. +#. Register the LTI provider. +#. Create the LTI component in an individual unit. - - To use your survey, you must edit the link in the template to include your university and survey ID. +Step 1. Add LTI to the Advanced Modules Policy Key +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - You can also embed the survey in an iframe in the HTML component. +#. On the **Settings** menu, click **Advanced Settings**. +#. On the **Advanced Settings** page, locate the **Manual Policy + Definition** section, and then locate the **advanced_modules** + policy key (this key is at the top of the list). - - For more details, read the instructions in the HTML view of the component. + .. image:: Images/AdvancedModulesEmpty.gif -#. Click **Save** to save the HTML component. +#. Under **Policy Value**, place your cursor between the brackets, and + then enter **“lti”**. Make sure to include the quotation marks, but + not the period. + + .. image:: Images/LTI_Policy_Key.gif + + **Note** If the **Policy Value** field already contains text, place your + cursor directly after the closing quotation mark for the final item, and + then enter a comma followed by **“lti”** (make sure that you include the + quotation marks). + +#. At the bottom of the page, click **Save Changes**. + +The page refreshes automatically. At the top of the page, +you see a notification that your changes have been saved. + +Step 2. Register the External LTI Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To regiser the external LTI provider, you’ll add the LIT ID, the client +key, and the client secret in the **lti_passports** policy key. + +#. On the **Advanced Settings** page, locate the **lti_passports** + policy key. + +#. Under **Policy Value**, place your cursor between the brackets, and + then enter the LTI ID, client key, and client secret in the following + format (make sure to include the quotation marks and the colons). + + :: + + “lti_id:client_key:client_secret” + + For example, the value in the **lti_passports** field may be the following. + :: + + “test_lti_id:b289378-f88d-2929-ctools.umich.edu:secret” + + If you have multiple LTI providers, separate the values with a comma. + Make sure to surround each entry with quotation marks. + + :: + + "test_lti_id:b289378-f88d-2929-ctools.umich.edu:secret", + "id_21441:b289378-f88d-2929-ctools.school.edu:23746387264", + "book_lti_provider_from_new_york:b289378-f88d-2929-ctools.company.com:yt4984yr8" + + +#. At the bottom of the page, click **Save Changes**. + +The page refreshes automatically. At the top of the page, +you see a notification that your changes have been saved, and you can +see your entries in the **lti_passports** policy key. + +Step 3. Add the LTI Component to a Unit +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. In the unit where you want to create the problem, click **Advanced** + under **Add New Component**, and then click **LTI**. +#. In the component that appears, click **Edit**. +#. In the component editor, set the options that you want. See the table + below for a description of each option. +#. Click **Save**. + + .. list-table:: + :widths: 10 80 + :header-rows: 1 + + * - `Setting` + - Description + * - `Display Name` + - Specifies the name of the problem. This name appears above the problem and in + the course ribbon at the top of the page in the courseware. + * - `custom_parameters` + - Enables you to add one or more custom parameters. For example, if you've added an + e-book, a custom parameter may include the page that your e-book should open to. + You could also use a custom parameter to set the background color of the LTI component. + + Every custom parameter has a key and a value. You must add the key and value in the following format. + + :: + + key=value + + For example, a custom parameter may resemble the following. + + :: + + bgcolor=red + + page=144 + + To add a custom parameter, click **Add**. + * - `graded` + - Indicates whether the grade for the problem counts towards student's total grade. By + default, this value is set to **False**. + * - `has_score` + - Specifies whether the problem has a numerical score. By default, this value + is set to **False**. + * - `launch_url` + - Lists the URL that Studio sends to the external LTI provider so that the provider + can send back students' grades. This setting is only used if **graded** is set to + **True**. + * - `lti_id` + - Specifies the LTI ID for the external LTI provider. This value must be the same + LTI ID that you entered on the **Advanced Settings** page. + * - `open_in_a_new_page` + - Indicates whether the problem opens in a new page. If you set this value to **True**, + the student clicks a link that opens the LTI content in a new window. If you set + this value to **False**, the LTI content opens in an IFrame in the current page. + * - `weight` + - Specifies the number of points possible for the problem. By default, if an + external LTI provider grades the problem, the problem is worth 1 point, and + a student’s score can be any value between 0 and 1. + + For more information about problem weights and computing point scores, see :ref:`Problem Weight`. .. _Word Cloud: @@ -59,7 +213,7 @@ Word Cloud ********** -In a word cloud problem, students enter words into a field in response +In a word cloud exercise, students enter words into a field in response to a question or prompt. The words all the students have entered then appear instantly as a colorful graphic, with the most popular responses appearing largest. The graphic becomes larger as more students answer. @@ -73,7 +227,7 @@ responses to a question in a HarvardX course. .. image:: Images/WordCloudExample.gif Create a Word Cloud Exercise -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------- To create a word cloud exercise: @@ -114,20 +268,17 @@ For more information, see `Xml Format of "Word Cloud" Module Zooming Image Tool ****************** -To create a new HTML component in an existing unit, ensure the unit is private. -For more information on public and private units, see :ref:`Public and Private Units`. - -Some edX classes use extremely large, extremely detailed graphics. To make it +Some edX courses use extremely large, extremely detailed graphics. To make it easier to understand we can offer two versions of those graphics, with the zoomed section showing when you click on the main view. The example below is from 7.00x: Introduction to Biology and shows a subset of the biochemical reactions that cells carry out. -.. image:: Images/ZoomingImage.gif +.. image:: Images/Zooming_Image.gif Create a Zooming Image Tool -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--------------------------- #. Under **Add New Component**, click **html**, and then click **Zooming Image**. diff --git a/docs/course_authors/source/tools_unpublished.rst b/docs/course_authors/source/tools_unpublished.rst new file mode 100644 index 000000000000..d80ed8bfe0c9 --- /dev/null +++ b/docs/course_authors/source/tools_unpublished.rst @@ -0,0 +1,49 @@ +############################# +Working with Tools +############################# + +*************************** +Overview of Tools in Studio +*************************** + +**Intro to Tools text** - you can use various tools in Studio, etc. (Sometimes +called blades, though that's not intuitive for very many people.) + +- Interactive periodic table (if we document this) +- :ref:`Qualtrics Survey` +- :ref:`Word Cloud` +- :ref:`Zooming image` + + +.. _Qualtrics Survey: + +**************** +Qualtrics Survey +**************** + +**description of Qualtrics survey and explanation of why course teams would want to +use it** + +**image of Qualtrics survey** + +Create a Qualtrics Survey +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a Qualtrics survey, you'll use the Anonymous User ID template. This +template contains HTML with instructions. + +#. Under **Add New Component**, click **html**, and then click **Anonymous User ID**. + +#. In the empty component that appears, click **Edit**. + +#. When the component editor opens, replace the example content with your own content. + + - **flesh these instructions out more** + + - To use your survey, you must edit the link in the template to include your university and survey ID. + + - You can also embed the survey in an iframe in the HTML component. + + - For more details, read the instructions in the HTML view of the component. + +#. Click **Save** to save the HTML component. From e60524912f203fa4043146b1e656905decb3367e Mon Sep 17 00:00:00 2001 From: spearce Date: Mon, 6 Jan 2014 14:12:25 -0500 Subject: [PATCH 13/15] Update index Remove javascript_input and create_lti; add tools --- docs/course_authors/source/index.rst | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/course_authors/source/index.rst b/docs/course_authors/source/index.rst index b5bbc60976ba..ed88c364ed65 100755 --- a/docs/course_authors/source/index.rst +++ b/docs/course_authors/source/index.rst @@ -22,10 +22,9 @@ Contents create_problem_component common_problems advanced_problems - javascript_input - create_lti specialized_problems open_response_assessment + tools set_content_releasedates view_course_content export_import_course @@ -45,10 +44,3 @@ Appendices :glob: appendices/* - - - - - - - From c7eed1ce31e9b46377569d36090ec5361bb54337 Mon Sep 17 00:00:00 2001 From: spearce Date: Tue, 24 Dec 2013 14:10:27 -0500 Subject: [PATCH 14/15] Create Tools topic Create Tools topic that includes descriptions of Qualtrics surveys, word clouds, and zooming images --- .../course_authors/source/Images/ZoomingImage | Bin 0 -> 33067 bytes docs/course_authors/source/tools.rst | 138 ++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 docs/course_authors/source/Images/ZoomingImage create mode 100644 docs/course_authors/source/tools.rst diff --git a/docs/course_authors/source/Images/ZoomingImage b/docs/course_authors/source/Images/ZoomingImage new file mode 100644 index 0000000000000000000000000000000000000000..4a3493a7c1f991e64e4e109995d22d4b97ef15f3 GIT binary patch literal 33067 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
        d-e`Cv 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 literal 0 HcmV?d00001 diff --git a/docs/course_authors/source/tools.rst b/docs/course_authors/source/tools.rst new file mode 100644 index 000000000000..6a9703cf51bc --- /dev/null +++ b/docs/course_authors/source/tools.rst @@ -0,0 +1,138 @@ +.. _Tools: + + +############################# +Working with Tools +############################# + +*************************** +Overview of Tools in Studio +*************************** + +**Intro to Tools text** - you can use various tools in Studio, etc. (Sometimes +called blades, though that's not intuitive for very many people.) + +- :ref:`Qualtrics Survey` +- Interactive periodic table (if we document this) +- :ref:`Word Cloud` +- :ref:`Zooming image` + + +.. _Qualtrics Survey: + +**************** +Qualtrics Survey +**************** + +**description of Qualtrics survey and explanation of why course teams would want to +use it** + +**image of Qualtrics survey** + +Create a Qualtrics Survey +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a Qualtrics survey, you'll use the Anonymous User ID template. This +template contains HTML with instructions. + +#. Under **Add New Component**, click **html**, and then click **Anonymous User ID**. + +#. In the empty component that appears, click **Edit**. + +#. When the component editor opens, replace the example content with your own content. + + - **flesh these instructions out more** + + - To use your survey, you must edit the link in the template to include your university and survey ID. + + - You can also embed the survey in an iframe in the HTML component. + + - For more details, read the instructions in the HTML view of the component. + +#. Click **Save** to save the HTML component. + + +.. _Word Cloud: + +********** +Word Cloud +********** + + +In a word cloud problem, students enter words into a field in response +to a question or prompt. The words all the students have entered then +appear instantly as a colorful graphic, with the most popular responses +appearing largest. The graphic becomes larger as more students answer. +Students can both see the way their peers have answered and contribute +their thoughts to the group. + + +For example, the following word cloud was created from students' +responses to a question in a HarvardX course. + +.. image:: Images/WordCloudExample.gif + +Create a Word Cloud Exercise +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a word cloud exercise: + + +#. Add the Word Cloud advanced component. To do this, add the + "word_cloud" key value to the **Advanced Settings** page. (For more + information, see the instructions in :ref:`Specialized Problems`.) +#. In the unit where you want to create the problem, click **Advanced** + under **Add New Component**. +#. In the list of problem types, click **Word Cloud**. +#. In the component that appears, click **Edit**. +#. In the component editor, specify the settings that you want. You can + leave the default value for everything except **Display Name**. + + + - **Display Name**: The name that appears in the course ribbon and + as a heading above the problem. + - **Inputs**: The number of text boxes into which students can enter + words, phrases, or sentences. + - **Maximum Words**: The maximum number of words that the word cloud + displays. If students enter 300 different words but the maximum is + set to 250, only the 250 most commonly entered words appear in the + word cloud. + - **Show Percents**: The number of times that students have entered + a given word as a percentage of all words entered appears near + that word. + + +#. Click **Save**. + + +For more information, see `Xml Format of "Word Cloud" Module +`_. + +.. _Zooming Image: + +****************** +Zooming Image Tool +****************** + +To create a new HTML component in an existing unit, ensure the unit is private. +For more information on public and private units, see :ref:`Public and Private Units`. + +Some edX classes use extremely large, extremely detailed graphics. To make it +easier to understand we can offer two versions of those graphics, with the zoomed +section showing when you click on the main view. + +The example below is from 7.00x: Introduction to Biology and shows a subset of the +biochemical reactions that cells carry out. + +.. image:: Images/ZoomingImage.gif + +Create a Zooming Image Tool +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. Under **Add New Component**, click **html**, and then click **Zooming Image**. + +#. In the empty component that appears, click **Edit**. + +#. When the component editor opens, replace the example content with your own content. + +#. Click **Save** to save the HTML component. From 7e0574698a3af4e0ed3e83bdf05542033797e5c9 Mon Sep 17 00:00:00 2001 From: Mark Hoeber Date: Tue, 7 Jan 2014 10:42:10 -0500 Subject: [PATCH 15/15] Removing conflict with tools.rst Removing conflict with tools.rst --- docs/course_authors/source/tools.rst | 217 +++++++++++++++++++++++---- 1 file changed, 184 insertions(+), 33 deletions(-) diff --git a/docs/course_authors/source/tools.rst b/docs/course_authors/source/tools.rst index 6a9703cf51bc..d9d8febf2c99 100644 --- a/docs/course_authors/source/tools.rst +++ b/docs/course_authors/source/tools.rst @@ -9,48 +9,202 @@ Working with Tools Overview of Tools in Studio *************************** -**Intro to Tools text** - you can use various tools in Studio, etc. (Sometimes -called blades, though that's not intuitive for very many people.) +In addition to text, images, and different types of problems, Studio allows you +to add customized learning tools such as word clouds to your course. + +- :ref:`LTI Component`: LTI components allow you to add an external learning application + or textbook to Studio. +- :ref:`Word Cloud`: Word clouds arrange text that students enter - for example, in + response to a question - into a colorful graphic that students can see. +- :ref:`Zooming image`: Zooming images allow you to enlarge sections of an image so + that students can see the section in detail. -- :ref:`Qualtrics Survey` -- Interactive periodic table (if we document this) -- :ref:`Word Cloud` -- :ref:`Zooming image` +.. _LTI Component: -.. _Qualtrics Survey: +************** +LTI Components +************** -**************** -Qualtrics Survey -**************** +You may have discovered or developed an external learning application +that you want to add to your online course. Or, you may have a digital +copy of your textbook that uses a format other than PDF. You can add +external learning applications or textbooks to Studio by using a +Learning Tools Interoperability (LTI) component. The LTI component is +based on the `IMS Global Learning Tools +Interoperability `_ +version 1.1.1 specifications. -**description of Qualtrics survey and explanation of why course teams would want to -use it** +You can use an LTI component in two ways. -**image of Qualtrics survey** +- You can add external LTI content that is displayed only, such as + textbook content that doesn’t require a student response. +- You can add external LTI content that requires a student response. An + external provider will grade student responses. -Create a Qualtrics Survey -~~~~~~~~~~~~~~~~~~~~~~~~~ +Before you create an LTI component from an external LTI provider in a +unit, you need the following information. -To create a Qualtrics survey, you'll use the Anonymous User ID template. This -template contains HTML with instructions. +- The **LTI ID**. This is a value that you create to refer to the external LTI + provider. You should create an LTI ID that you can remember easily. -#. Under **Add New Component**, click **html**, and then click **Anonymous User ID**. + The LTI ID can contain uppercase and lowercase alphanumeric + characters, as well as underscore characters (_). It can contain any + number of characters. For example, you may create an LTI ID that is + as simple as **test_lti_id**, or your LTI ID may be a string of + numbers and letters such as **id_21441** or + **book_lti_provider_from_new_york**. +- The **client key**. This value is a sequence of characters that you + obtain from the LTI provider. The client key is used for + authentication and can contain any number of characters. For example, + your client key may be **b289378-f88d-2929-ctools.umich.edu**. +- The **client secret**. This value is a sequence of characters that + you obtain from the LTI provider. The client secret is used for + authentication and can contain any number of characters. For example, + your client secret may be something as simple as **secret**, or it + may be a string of numbers and letters such as **23746387264** or + **yt4984yr8**. +- The **launch URL** (if the LTI component requires a student response + that will be graded). You obtain the launch URL from the LTI + provider. The launch URL is the URL that Studio sends to the external + LTI provider so that the provider can send back students’ grades. -#. In the empty component that appears, click **Edit**. +Create an LTI Component +----------------------- -#. When the component editor opens, replace the example content with your own content. +Creating an LTI component in your course has three steps. - - **flesh these instructions out more** +#. Add LTI to the **advanced_modules** policy key. +#. Register the LTI provider. +#. Create the LTI component in an individual unit. - - To use your survey, you must edit the link in the template to include your university and survey ID. +Step 1. Add LTI to the Advanced Modules Policy Key +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - You can also embed the survey in an iframe in the HTML component. +#. On the **Settings** menu, click **Advanced Settings**. +#. On the **Advanced Settings** page, locate the **Manual Policy + Definition** section, and then locate the **advanced_modules** + policy key (this key is at the top of the list). - - For more details, read the instructions in the HTML view of the component. + .. image:: Images/AdvancedModulesEmpty.gif -#. Click **Save** to save the HTML component. +#. Under **Policy Value**, place your cursor between the brackets, and + then enter **“lti”**. Make sure to include the quotation marks, but + not the period. + + .. image:: Images/LTI_Policy_Key.gif + + **Note** If the **Policy Value** field already contains text, place your + cursor directly after the closing quotation mark for the final item, and + then enter a comma followed by **“lti”** (make sure that you include the + quotation marks). + +#. At the bottom of the page, click **Save Changes**. + +The page refreshes automatically. At the top of the page, +you see a notification that your changes have been saved. + +Step 2. Register the External LTI Provider +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To regiser the external LTI provider, you’ll add the LIT ID, the client +key, and the client secret in the **lti_passports** policy key. + +#. On the **Advanced Settings** page, locate the **lti_passports** + policy key. + +#. Under **Policy Value**, place your cursor between the brackets, and + then enter the LTI ID, client key, and client secret in the following + format (make sure to include the quotation marks and the colons). + + :: + + “lti_id:client_key:client_secret” + + For example, the value in the **lti_passports** field may be the following. + :: + + “test_lti_id:b289378-f88d-2929-ctools.umich.edu:secret” + + If you have multiple LTI providers, separate the values with a comma. + Make sure to surround each entry with quotation marks. + + :: + + "test_lti_id:b289378-f88d-2929-ctools.umich.edu:secret", + "id_21441:b289378-f88d-2929-ctools.school.edu:23746387264", + "book_lti_provider_from_new_york:b289378-f88d-2929-ctools.company.com:yt4984yr8" + + +#. At the bottom of the page, click **Save Changes**. + +The page refreshes automatically. At the top of the page, +you see a notification that your changes have been saved, and you can +see your entries in the **lti_passports** policy key. + +Step 3. Add the LTI Component to a Unit +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. In the unit where you want to create the problem, click **Advanced** + under **Add New Component**, and then click **LTI**. +#. In the component that appears, click **Edit**. +#. In the component editor, set the options that you want. See the table + below for a description of each option. +#. Click **Save**. + + .. list-table:: + :widths: 10 80 + :header-rows: 1 + + * - `Setting` + - Description + * - `Display Name` + - Specifies the name of the problem. This name appears above the problem and in + the course ribbon at the top of the page in the courseware. + * - `custom_parameters` + - Enables you to add one or more custom parameters. For example, if you've added an + e-book, a custom parameter may include the page that your e-book should open to. + You could also use a custom parameter to set the background color of the LTI component. + + Every custom parameter has a key and a value. You must add the key and value in the following format. + + :: + + key=value + + For example, a custom parameter may resemble the following. + + :: + + bgcolor=red + + page=144 + + To add a custom parameter, click **Add**. + * - `graded` + - Indicates whether the grade for the problem counts towards student's total grade. By + default, this value is set to **False**. + * - `has_score` + - Specifies whether the problem has a numerical score. By default, this value + is set to **False**. + * - `launch_url` + - Lists the URL that Studio sends to the external LTI provider so that the provider + can send back students' grades. This setting is only used if **graded** is set to + **True**. + * - `lti_id` + - Specifies the LTI ID for the external LTI provider. This value must be the same + LTI ID that you entered on the **Advanced Settings** page. + * - `open_in_a_new_page` + - Indicates whether the problem opens in a new page. If you set this value to **True**, + the student clicks a link that opens the LTI content in a new window. If you set + this value to **False**, the LTI content opens in an IFrame in the current page. + * - `weight` + - Specifies the number of points possible for the problem. By default, if an + external LTI provider grades the problem, the problem is worth 1 point, and + a student’s score can be any value between 0 and 1. + + For more information about problem weights and computing point scores, see :ref:`Problem Weight`. .. _Word Cloud: @@ -59,7 +213,7 @@ Word Cloud ********** -In a word cloud problem, students enter words into a field in response +In a word cloud exercise, students enter words into a field in response to a question or prompt. The words all the students have entered then appear instantly as a colorful graphic, with the most popular responses appearing largest. The graphic becomes larger as more students answer. @@ -73,7 +227,7 @@ responses to a question in a HarvardX course. .. image:: Images/WordCloudExample.gif Create a Word Cloud Exercise -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------- To create a word cloud exercise: @@ -114,20 +268,17 @@ For more information, see `Xml Format of "Word Cloud" Module Zooming Image Tool ****************** -To create a new HTML component in an existing unit, ensure the unit is private. -For more information on public and private units, see :ref:`Public and Private Units`. - -Some edX classes use extremely large, extremely detailed graphics. To make it +Some edX courses use extremely large, extremely detailed graphics. To make it easier to understand we can offer two versions of those graphics, with the zoomed section showing when you click on the main view. The example below is from 7.00x: Introduction to Biology and shows a subset of the biochemical reactions that cells carry out. -.. image:: Images/ZoomingImage.gif +.. image:: Images/Zooming_Image.gif Create a Zooming Image Tool -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--------------------------- #. Under **Add New Component**, click **html**, and then click **Zooming Image**.