From 978b9049d057d2a0995758275f68da8641193201 Mon Sep 17 00:00:00 2001 From: Nivesh Rajbhandari Date: Wed, 27 Jun 2012 14:21:27 -0700 Subject: Integrating Materials UI changes. Squashed commit of the following: commit 89ccb55130e67c4516e616ccc56d2a649a2b9160 Author: Nivesh Rajbhandari Date: Wed Jun 27 14:20:01 2012 -0700 Position Materials Editor popup and change buttons' text color. Signed-off-by: Nivesh Rajbhandari commit 89bca82adc781f4913f8d302a49a8baa907631c5 Author: Nivesh Rajbhandari Date: Wed Jun 27 12:00:51 2012 -0700 Support deleting and editing custom materials. Signed-off-by: Nivesh Rajbhandari commit 5be5160c4786beb70e8ad4d75562adb135718c6c Merge: 1d9d9f6 2ebf3e3 Author: Nivesh Rajbhandari Date: Wed Jun 27 11:11:37 2012 -0700 Merge branch 'refs/heads/ninja-internal' into WebGLMaterials Conflicts: js/data/panels-data.js Signed-off-by: Nivesh Rajbhandari commit 1d9d9f6e66ea7585f07ed461cebba99e71f65de0 Author: Nivesh Rajbhandari Date: Tue Jun 26 22:01:22 2012 -0700 "Save as" support to duplicate material with modified settings. Also removed Add button and disabled Reset button for now. Signed-off-by: Nivesh Rajbhandari commit bf1037508dbc686f2884765344832f906cbf06d0 Author: Nivesh Rajbhandari Date: Tue Jun 26 17:23:31 2012 -0700 Added UI for duplicating and deleting materials in the Materials Library. Signed-off-by: Nivesh Rajbhandari commit 54930792f9c417df5f739831164aa1f96a41d67a Author: Nivesh Rajbhandari Date: Tue Jun 26 14:29:17 2012 -0700 Added preview of material in materials editor popup and fixed some styling. Signed-off-by: Nivesh Rajbhandari Signed-off-by: Nivesh Rajbhandari --- .../materials-popup.reel/materials-popup.js | 333 +++++++-------------- 1 file changed, 106 insertions(+), 227 deletions(-) (limited to 'js/panels/Materials/materials-popup.reel/materials-popup.js') diff --git a/js/panels/Materials/materials-popup.reel/materials-popup.js b/js/panels/Materials/materials-popup.reel/materials-popup.js index 40f07509..3f702459 100755 --- a/js/panels/Materials/materials-popup.reel/materials-popup.js +++ b/js/panels/Materials/materials-popup.reel/materials-popup.js @@ -6,7 +6,10 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot var Montage = require("montage/core/core").Montage, Component = require("montage/ui/component").Component, - MaterialsModel = require("js/models/materials-model").MaterialsModel; + MaterialsModel = require("js/models/materials-model").MaterialsModel, + NJUtils = require("js/lib/NJUtils").NJUtils, + World = require("js/lib/drawing/world").World, + Rectangle = require("js/lib/geom/rectangle").Rectangle; //////////////////////////////////////////////////////////////////////// //Exporting as MaterialsPopup @@ -22,11 +25,35 @@ exports.MaterialsPopup = Montage.create(Component, { serializable: true }, + saveAsButton: { + value: null, + serializable: true + }, + + resetButton: { + value: null, + serializable: true + }, + + materialsLibraryRef: { + value: null + }, + materialTitle: { value: null, serializable: true }, + previewCanvas: { + value: null, + serializable: true + }, + + previewShape: { + value: null, + serializable: true + }, + // Material Properties _materialName: { enumerable: true, @@ -65,6 +92,12 @@ exports.MaterialsPopup = Montage.create(Component, { } break; + case "Save As...": + this.saveAs(); + break; + case "Reset": + this.reset(); + break; } // Notify Materials Library to close popup @@ -72,6 +105,28 @@ exports.MaterialsPopup = Montage.create(Component, { } }, + saveAs: + { + value: function() + { + console.log("Save As..."); + var materialCopy = prompt("Save material as", this._materialName + "_Copy"); + + if (materialCopy) + { + this.materialsLibraryRef.duplicateMaterial(materialCopy); + } + } + }, + + reset: + { + value: function() + { + console.log("Reset"); + } + }, + revertToOriginalValues: { value: function() @@ -195,6 +250,7 @@ exports.MaterialsPopup = Montage.create(Component, { this._material.setProperty( this._propNames[index], value ); } + var obj, matArray, matTypeArray, nMats, iMat, world; if (this._useSelection) { console.log( "apply to selection" ); @@ -206,25 +262,38 @@ exports.MaterialsPopup = Montage.create(Component, { for (var iObj=0; iObj --- .../materials-popup.reel/materials-popup.js | 51 +++++++++++----------- 1 file changed, 26 insertions(+), 25 deletions(-) (limited to 'js/panels/Materials/materials-popup.reel/materials-popup.js') diff --git a/js/panels/Materials/materials-popup.reel/materials-popup.js b/js/panels/Materials/materials-popup.reel/materials-popup.js index 3f702459..9b7b031b 100755 --- a/js/panels/Materials/materials-popup.reel/materials-popup.js +++ b/js/panels/Materials/materials-popup.reel/materials-popup.js @@ -69,11 +69,11 @@ exports.MaterialsPopup = Montage.create(Component, { switch(event._currentTarget.label) { case "Cancel": - console.log("Cancel material edit"); +// console.log("Cancel material edit"); this.revertToOriginalValues(); break; case "OK": - console.log("Committing material with the following values:"); +// console.log("Committing material with the following values:"); for(var i=0, len=this.materialsProperties.childComponents.length; i< len; i++) { var childControl = this.materialsProperties.childComponents[i]; @@ -109,7 +109,7 @@ exports.MaterialsPopup = Montage.create(Component, { { value: function() { - console.log("Save As..."); +// console.log("Save As..."); var materialCopy = prompt("Save material as", this._materialName + "_Copy"); if (materialCopy) @@ -123,7 +123,7 @@ exports.MaterialsPopup = Montage.create(Component, { { value: function() { - console.log("Reset"); +// console.log("Reset"); } }, @@ -186,15 +186,15 @@ exports.MaterialsPopup = Montage.create(Component, { { value: function(event) { - if(typeof event.propertyValue === "object") - { - console.log(event.propertyLabel + " changing to "); - console.dir(event.propertyValue); - } - else - { - console.log(event.propertyLabel + " changing to " + event.propertyValue); - } +// if(typeof event.propertyValue === "object") +// { +// console.log(event.propertyLabel + " changing to "); +// console.dir(event.propertyValue); +// } +// else +// { +// console.log(event.propertyLabel + " changing to " + event.propertyValue); +// } if (event.propertyLabel && event.propertyValue) this.applyProperty( event.propertyLabel, event.propertyValue ); @@ -206,15 +206,15 @@ exports.MaterialsPopup = Montage.create(Component, { value: function(theEvent) { var event = theEvent._event; - if(typeof event.propertyValue === "object") - { - console.log(event.propertyLabel + " changed to "); - console.dir(event.propertyValue); - } - else - { - console.log(event.propertyLabel + " changed to " + event.propertyValue); - } +// if(typeof event.propertyValue === "object") +// { +// console.log(event.propertyLabel + " changed to "); +// console.dir(event.propertyValue); +// } +// else +// { +// console.log(event.propertyLabel + " changed to " + event.propertyValue); +// } if (event.propertyLabel) this.applyProperty( event.propertyLabel, event.propertyValue ); @@ -253,7 +253,7 @@ exports.MaterialsPopup = Montage.create(Component, { var obj, matArray, matTypeArray, nMats, iMat, world; if (this._useSelection) { - console.log( "apply to selection" ); +// console.log( "apply to selection" ); var selection = this.application.ninja.selectedElements; if (selection && (selection.length > 0)) @@ -385,7 +385,7 @@ exports.MaterialsPopup = Montage.create(Component, { this.previewShape.setFillMaterial(this._material); this.previewShape.buildBuffers(); - world.render(); + world.restartRenderLoop(); } }, @@ -393,7 +393,8 @@ exports.MaterialsPopup = Montage.create(Component, { destroy: { enumerable: false, value: function() { - // add cleanup routines here +// console.log("cleanup routines here"); + this.previewShape.getWorld().stop(); } }, -- cgit v1.2.3 From 648ee61ae84216d0236e0dbc211addc13b2cfa3a Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Fri, 6 Jul 2012 11:52:06 -0700 Subject: Expand tabs --- .../materials-popup.reel/materials-popup.js | 842 ++++++++++----------- 1 file changed, 421 insertions(+), 421 deletions(-) (limited to 'js/panels/Materials/materials-popup.reel/materials-popup.js') diff --git a/js/panels/Materials/materials-popup.reel/materials-popup.js b/js/panels/Materials/materials-popup.reel/materials-popup.js index 7c5493c6..cecb0a71 100755 --- a/js/panels/Materials/materials-popup.reel/materials-popup.js +++ b/js/panels/Materials/materials-popup.reel/materials-popup.js @@ -51,26 +51,26 @@ exports.MaterialsPopup = Montage.create(Component, { serializable: true }, - // Material Properties + // Material Properties _materialName: { enumerable: true, value: "" }, - _useSelection: { value: false, enumerable: true }, - _whichMaterial: { value: "fill", enumerable: true }, - _originalValues: {value: null, enumerable: true }, - - captureAction: { - value:function(event) { - switch(event._currentTarget.label) - { - case "Cancel": - console.log("Cancel material edit"); - this.revertToOriginalValues(); - break; - case "OK": - console.log("Committing material with the following values:"); + _useSelection: { value: false, enumerable: true }, + _whichMaterial: { value: "fill", enumerable: true }, + _originalValues: {value: null, enumerable: true }, + + captureAction: { + value:function(event) { + switch(event._currentTarget.label) + { + case "Cancel": + console.log("Cancel material edit"); + this.revertToOriginalValues(); + break; + case "OK": + console.log("Committing material with the following values:"); for(var i=0, len=this.materialsProperties.childComponents.length; i< len; i++) { var childControl = this.materialsProperties.childComponents[i]; @@ -88,53 +88,53 @@ exports.MaterialsPopup = Montage.create(Component, { console.log("--------------"); } - break; - } + break; + } // Notify Materials Library to close popup NJevent("hideMaterialPopup"); - } - }, - - revertToOriginalValues: - { - value: function() - { - if (this._originalValues) - { - this._material.importJSON( this._originalValues ); - - if (this._useSelection) - { - var selection = this.application.ninja.selectedElements; - if (selection && (selection.length > 0)) - { - var nObjs = selection.length; - for (var iObj=0; iObj 0)) + { + var nObjs = selection.length; + for (var iObj=0; iObj 0)) - { - var nObjs = selection.length; - for (var iObj=0; iObj 0)) - { - var index = value.lastIndexOf( "/" ); - if (index < 0) index = value.lastIndexOf( "\\" ); - if (index >= 0) - { - value = value.substr( index+1 ); - value = "assets/images/" + value; - } - rtnValue = value.slice(0); - } - break; - - case "checkbox": - rtnValue = value; - break; - - default: - console.log( "unrecognized material control type: " + type ); - break; - } - return rtnValue; - } - }, + applyProperty: + { + value: function( propLabel, propValue) + { + // find the property lable in the array + // This assumes no duplication in labels + if (this._propLabels) + { + // the label cones through with a trailing ':'. remove that + var ch = propLabel[ propLabel.length - 1]; + if (ch == ':') + propLabel = propLabel.substr(0, propLabel.length - 1); + + var index; + var nProps = this._propLabels.length; + for (var i=0; i 0)) + { + var nObjs = selection.length; + for (var iObj=0; iObj 0)) + { + var index = value.lastIndexOf( "/" ); + if (index < 0) index = value.lastIndexOf( "\\" ); + if (index >= 0) + { + value = value.substr( index+1 ); + value = "assets/images/" + value; + } + rtnValue = value.slice(0); + } + break; + + case "checkbox": + rtnValue = value; + break; + + default: + console.log( "unrecognized material control type: " + type ); + break; + } + return rtnValue; + } + }, //////////////////////////////////////////////////////////////////// - // - prepareForDraw: { - enumerable: false, - value: function() { + // + prepareForDraw: { + enumerable: false, + value: function() { this.cancelButton.addEventListener("action", this, true); this.okButton.addEventListener("action", this, true); } }, - //////////////////////////////////////////////////////////////////// - // - didDraw: { - enumerable: false, - value: function() { + //////////////////////////////////////////////////////////////////// + // + didDraw: { + enumerable: false, + value: function() { this.materialTitle.innerHTML = this._materialName; - } - }, - - //Garbage collection (Manual method) - destroy: { - enumerable: false, - value: function() { - // add cleanup routines here - } - }, - - loadMaterials: - { - enumerable: true, - value: function(materialID, useSelection, whichMaterial) - { - //TODO - Hack to force repetition to draw. Setting .length = 0 did not work. - this.materialsData = []; - - var material; - this._materialName = materialID; - if (useSelection) - { - this._useSelection = true; - var selection = this.application.ninja.selectedElements; - if (selection && (selection.length > 0)) - { - var canvas = selection[0]; - var obj; - this._whichMaterial = whichMaterial; - if (canvas.elementModel && canvas.elementModel.shapeModel) obj = canvas.elementModel.shapeModel.GLGeomObj; - if (obj) - material = (whichMaterial === 'stroke') ? obj.getStrokeMaterial() : obj.getFillMaterial(); - } - } - else - { - this._useSelection = false; - - if( - (materialID === "Bump Metal") || - (materialID === "Deform") || - (materialID === "Flat") || - (materialID === "Flag") || - (materialID === "Fly") || - (materialID === "Julia") || - (materialID === "Keleidoscope") || - (materialID === "Linear Gradient") || - (materialID === "Mandel") || - (materialID === "Paris") || - (materialID === "Plasma") || - (materialID === "Pulse") || - (materialID === "Radial Blur") || - (materialID === "Radial Gradient") || - (materialID === "Raiders") || - (materialID === "Relief Tunnel") || - (materialID === "Square Tunnel") || - (materialID === "Star") || - (materialID === "Taper") || - (materialID === "Tunnel") || - (materialID === "Twist") || - (materialID === "Twist Vertex") || - (materialID === "Uber") || - (materialID === "Water") || - (materialID === "Z-Invert") - ) - { - material = MaterialsModel.getMaterial( materialID ); - } - } - - if (material) - { - this._material = material; - this._originalValues = material.exportJSON(); - this.materialsData = this.getMaterialData( material ); - } - else - { - this.materialsData = this[materialID]; - } - this.needsDraw = true; - } - }, - - getMaterialData: - { - value: function( material ) - { - // declare the array to hold the results - var rtnArray = []; - - var propNames = [], propValues = [], propTypes = [], propLabels = []; - this._propNames = propNames; - this._propValues = propValues; - this._propTypes = propTypes; - this._propLabels = propLabels; - material.getAllProperties( propNames, propValues, propTypes, propLabels); - var n = propNames.length; - for (var i=0; i 0)) + { + var canvas = selection[0]; + var obj; + this._whichMaterial = whichMaterial; + if (canvas.elementModel && canvas.elementModel.shapeModel) obj = canvas.elementModel.shapeModel.GLGeomObj; + if (obj) + material = (whichMaterial === 'stroke') ? obj.getStrokeMaterial() : obj.getFillMaterial(); + } + } + else + { + this._useSelection = false; + + if( + (materialID === "Bump Metal") || + (materialID === "Deform") || + (materialID === "Flat") || + (materialID === "Flag") || + (materialID === "Fly") || + (materialID === "Julia") || + (materialID === "Keleidoscope") || + (materialID === "Linear Gradient") || + (materialID === "Mandel") || + (materialID === "Paris") || + (materialID === "Plasma") || + (materialID === "Pulse") || + (materialID === "Radial Blur") || + (materialID === "Radial Gradient") || + (materialID === "Raiders") || + (materialID === "Relief Tunnel") || + (materialID === "Square Tunnel") || + (materialID === "Star") || + (materialID === "Taper") || + (materialID === "Tunnel") || + (materialID === "Twist") || + (materialID === "Twist Vertex") || + (materialID === "Uber") || + (materialID === "Water") || + (materialID === "Z-Invert") + ) + { + material = MaterialsModel.getMaterial( materialID ); + } + } + + if (material) + { + this._material = material; + this._originalValues = material.exportJSON(); + this.materialsData = this.getMaterialData( material ); + } + else + { + this.materialsData = this[materialID]; + } + this.needsDraw = true; + } + }, + + getMaterialData: + { + value: function( material ) + { + // declare the array to hold the results + var rtnArray = []; + + var propNames = [], propValues = [], propTypes = [], propLabels = []; + this._propNames = propNames; + this._propValues = propValues; + this._propTypes = propTypes; + this._propLabels = propLabels; + material.getAllProperties( propNames, propValues, propTypes, propLabels); + var n = propNames.length; + for (var i=0; i 2) - { - obj["defaults"]["data"][2] = - { - "label": "Z", - "description": "Z value", - "controlType": "HotText", - "defaults": - { - "minValue": -1.e8, - "maxValue": 1.e8, - "value": value[2] - } - } - } - - return obj; - } - }, + } + + if (dimen > 2) + { + obj["defaults"]["data"][2] = + { + "label": "Z", + "description": "Z value", + "controlType": "HotText", + "defaults": + { + "minValue": -1.e8, + "maxValue": 1.e8, + "value": value[2] + } + } + } + + return obj; + } + }, // _dummyData1 CheckerBoard: { @@ -800,11 +800,11 @@ exports.MaterialsPopup = Montage.create(Component, { }, _materialsData: { - enumerable: true, + enumerable: true, serializable: true, - value: [] + value: [] - }, + }, materialsData: { enumerable: true, -- cgit v1.2.3 From 04343eda8c2f870b0da55cfdc8003c99fe1cc4de Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Fri, 6 Jul 2012 11:53:10 -0700 Subject: Remove trailing spaces --- js/panels/Materials/materials-popup.reel/materials-popup.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'js/panels/Materials/materials-popup.reel/materials-popup.js') diff --git a/js/panels/Materials/materials-popup.reel/materials-popup.js b/js/panels/Materials/materials-popup.reel/materials-popup.js index cecb0a71..12a86c47 100755 --- a/js/panels/Materials/materials-popup.reel/materials-popup.js +++ b/js/panels/Materials/materials-popup.reel/materials-popup.js @@ -202,7 +202,7 @@ exports.MaterialsPopup = Montage.create(Component, { var ch = propLabel[ propLabel.length - 1]; if (ch == ':') propLabel = propLabel.substr(0, propLabel.length - 1); - + var index; var nProps = this._propLabels.length; for (var i=0; i --- .../materials-popup.reel/materials-popup.js | 76 ++++++++++++++++++---- 1 file changed, 64 insertions(+), 12 deletions(-) (limited to 'js/panels/Materials/materials-popup.reel/materials-popup.js') diff --git a/js/panels/Materials/materials-popup.reel/materials-popup.js b/js/panels/Materials/materials-popup.reel/materials-popup.js index 9b7b031b..a1415343 100755 --- a/js/panels/Materials/materials-popup.reel/materials-popup.js +++ b/js/panels/Materials/materials-popup.reel/materials-popup.js @@ -9,7 +9,8 @@ var Montage = require("montage/core/core").Montage, MaterialsModel = require("js/models/materials-model").MaterialsModel, NJUtils = require("js/lib/NJUtils").NJUtils, World = require("js/lib/drawing/world").World, - Rectangle = require("js/lib/geom/rectangle").Rectangle; + Rectangle = require("js/lib/geom/rectangle").Rectangle, + ShapesController = require("js/controllers/elements/shapes-controller").ShapesController; //////////////////////////////////////////////////////////////////////// //Exporting as MaterialsPopup @@ -341,6 +342,10 @@ exports.MaterialsPopup = Montage.create(Component, { rtnValue = value; break; + case "gradient": + rtnValue = value; + break; + default: console.log( "unrecognized material control type: " + type ); break; @@ -432,7 +437,11 @@ exports.MaterialsPopup = Montage.create(Component, { { this._material = material; this._originalValues = material.exportJSON(); - this.materialsData = this.getMaterialData( material ); + if((materialID === "Linear Gradient") || (materialID === "Radial Gradient")) { + this.materialsData = this.getEditableProperties( material ); + } else { + this.materialsData = this.getMaterialData( material ); + } } else { @@ -442,6 +451,26 @@ exports.MaterialsPopup = Montage.create(Component, { } }, + getEditableProperties: { + value: function(material) { + // declare the array to hold the results + var rtnArray = [], + obj, + colorObj = ShapesController.getMaterialColor(material.getName()); + + this._propNames = ["gradient"]; + this._propValues = ["gradient"]; + this._propTypes = ["gradient"]; + this._propLabels = ["gradient"]; + + obj = this.createGradientData("gradient", colorObj); + + rtnArray.push(obj); + + return rtnArray; + } + }, + getMaterialData: { value: function( material ) @@ -489,17 +518,21 @@ exports.MaterialsPopup = Montage.create(Component, { obj = this.createCheckboxData( propLabels[i], propValues[i] ); break; - default: - console.log( "unrecognized material control type: " + propType[i] ); - break; - } + case "gradient": + obj = this.createGradientData( propLabels[i], propValues[i] ); + break; - if (obj) - { - rtnArray.push( obj ); - obj = null; - } - } + default: + console.log( "unrecognized material control type: " + propType[i] ); + break; + } + + if (obj) + { + rtnArray.push( obj ); + obj = null; + } + } return rtnArray; } @@ -650,6 +683,25 @@ exports.MaterialsPopup = Montage.create(Component, { } }, + createGradientData: + { + value: function( label, colorObj ) + { + var obj = { + "label": label, + "description": "a gradient", + "controlType": "GradientPicker", + "defaults": + { + "_mode": colorObj.gradientMode, + "value": colorObj.color + } + }; + + return obj; + } + }, + materialsProperties: { serializable: true, value: null -- cgit v1.2.3 From fdbec324dad4ab33d97282ab021d2c1661bc097c Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Mon, 9 Jul 2012 16:27:52 -0700 Subject: BSD License --- .../materials-popup.reel/materials-popup.js | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'js/panels/Materials/materials-popup.reel/materials-popup.js') diff --git a/js/panels/Materials/materials-popup.reel/materials-popup.js b/js/panels/Materials/materials-popup.reel/materials-popup.js index 501df282..a5e09c52 100755 --- a/js/panels/Materials/materials-popup.reel/materials-popup.js +++ b/js/panels/Materials/materials-popup.reel/materials-popup.js @@ -1,24 +1,25 @@ /* -Copyright (c) 2012, Motorola Mobility, Inc +Copyright (c) 2012, Motorola Mobility LLC. All Rights Reserved. -BSD License. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - Neither the name of Motorola Mobility nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of Motorola Mobility LLC nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -- cgit v1.2.3