| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 * @param {!WebInspector.Workspace} workspace | 34 * @param {!WebInspector.Workspace} workspace |
| 35 */ | 35 */ |
| 36 WebInspector.CSSStyleModel = function(workspace) | 36 WebInspector.CSSStyleModel = function(workspace) |
| 37 { | 37 { |
| 38 this._workspace = workspace; | 38 this._workspace = workspace; |
| 39 this._pendingCommandsMajorState = []; | 39 this._pendingCommandsMajorState = []; |
| 40 this._styleLoader = new WebInspector.CSSStyleModel.ComputedStyleLoader(this)
; | 40 this._styleLoader = new WebInspector.CSSStyleModel.ComputedStyleLoader(this)
; |
| 41 WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedo
Requested, this._undoRedoRequested, this); | 41 WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedo
Requested, this._undoRedoRequested, this); |
| 42 WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedo
Completed, this._undoRedoCompleted, this); | 42 WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedo
Completed, this._undoRedoCompleted, this); |
| 43 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeMod
el.EventTypes.MainFrameCreatedOrNavigated, this._mainFrameCreatedOrNavigated, th
is); | 43 WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeMod
el.EventTypes.MainFrameCreatedOrNavigated, this._mainFrameCreatedOrNavigated, th
is); |
| 44 this._namedFlowCollections = {}; | |
| 45 WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.Document
Updated, this._resetNamedFlowCollections, this); | |
| 46 InspectorBackend.registerCSSDispatcher(new WebInspector.CSSDispatcher(this))
; | 44 InspectorBackend.registerCSSDispatcher(new WebInspector.CSSDispatcher(this))
; |
| 47 CSSAgent.enable(this._wasEnabled.bind(this)); | 45 CSSAgent.enable(this._wasEnabled.bind(this)); |
| 48 this._resetStyleSheets(); | 46 this._resetStyleSheets(); |
| 49 } | 47 } |
| 50 | 48 |
| 51 /** | 49 /** |
| 52 * @param {!Array.<!CSSAgent.RuleMatch>|undefined} matchArray | 50 * @param {!Array.<!CSSAgent.RuleMatch>|undefined} matchArray |
| 53 */ | 51 */ |
| 54 WebInspector.CSSStyleModel.parseRuleMatchArrayPayload = function(matchArray) | 52 WebInspector.CSSStyleModel.parseRuleMatchArrayPayload = function(matchArray) |
| 55 { | 53 { |
| 56 if (!matchArray) | 54 if (!matchArray) |
| 57 return []; | 55 return []; |
| 58 | 56 |
| 59 var result = []; | 57 var result = []; |
| 60 for (var i = 0; i < matchArray.length; ++i) | 58 for (var i = 0; i < matchArray.length; ++i) |
| 61 result.push(WebInspector.CSSRule.parsePayload(matchArray[i].rule, matchA
rray[i].matchingSelectors)); | 59 result.push(WebInspector.CSSRule.parsePayload(matchArray[i].rule, matchA
rray[i].matchingSelectors)); |
| 62 return result; | 60 return result; |
| 63 } | 61 } |
| 64 | 62 |
| 65 WebInspector.CSSStyleModel.Events = { | 63 WebInspector.CSSStyleModel.Events = { |
| 66 ModelWasEnabled: "ModelWasEnabled", | 64 ModelWasEnabled: "ModelWasEnabled", |
| 67 StyleSheetAdded: "StyleSheetAdded", | 65 StyleSheetAdded: "StyleSheetAdded", |
| 68 StyleSheetChanged: "StyleSheetChanged", | 66 StyleSheetChanged: "StyleSheetChanged", |
| 69 StyleSheetRemoved: "StyleSheetRemoved", | 67 StyleSheetRemoved: "StyleSheetRemoved", |
| 70 MediaQueryResultChanged: "MediaQueryResultChanged", | 68 MediaQueryResultChanged: "MediaQueryResultChanged", |
| 71 NamedFlowCreated: "NamedFlowCreated", | |
| 72 NamedFlowRemoved: "NamedFlowRemoved", | |
| 73 RegionLayoutUpdated: "RegionLayoutUpdated", | |
| 74 RegionOversetChanged: "RegionOversetChanged" | |
| 75 } | 69 } |
| 76 | 70 |
| 77 WebInspector.CSSStyleModel.MediaTypes = ["all", "braille", "embossed", "handheld
", "print", "projection", "screen", "speech", "tty", "tv"]; | 71 WebInspector.CSSStyleModel.MediaTypes = ["all", "braille", "embossed", "handheld
", "print", "projection", "screen", "speech", "tty", "tv"]; |
| 78 | 72 |
| 79 WebInspector.CSSStyleModel.prototype = { | 73 WebInspector.CSSStyleModel.prototype = { |
| 80 /** | 74 /** |
| 81 * @return {boolean} | 75 * @return {boolean} |
| 82 */ | 76 */ |
| 83 isEnabled: function() | 77 isEnabled: function() |
| 84 { | 78 { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 * @param {!DOMAgent.NodeId} nodeId | 199 * @param {!DOMAgent.NodeId} nodeId |
| 206 * @param {?Array.<string>|undefined} forcedPseudoClasses | 200 * @param {?Array.<string>|undefined} forcedPseudoClasses |
| 207 * @param {function()=} userCallback | 201 * @param {function()=} userCallback |
| 208 */ | 202 */ |
| 209 forcePseudoState: function(nodeId, forcedPseudoClasses, userCallback) | 203 forcePseudoState: function(nodeId, forcedPseudoClasses, userCallback) |
| 210 { | 204 { |
| 211 CSSAgent.forcePseudoState(nodeId, forcedPseudoClasses || [], userCallbac
k); | 205 CSSAgent.forcePseudoState(nodeId, forcedPseudoClasses || [], userCallbac
k); |
| 212 }, | 206 }, |
| 213 | 207 |
| 214 /** | 208 /** |
| 215 * @param {!DOMAgent.NodeId} documentNodeId | |
| 216 * @param {function(?WebInspector.NamedFlowCollection)} userCallback | |
| 217 */ | |
| 218 getNamedFlowCollectionAsync: function(documentNodeId, userCallback) | |
| 219 { | |
| 220 var namedFlowCollection = this._namedFlowCollections[documentNodeId]; | |
| 221 if (namedFlowCollection) { | |
| 222 userCallback(namedFlowCollection); | |
| 223 return; | |
| 224 } | |
| 225 | |
| 226 /** | |
| 227 * @param {function(?WebInspector.NamedFlowCollection)} userCallback | |
| 228 * @param {?Protocol.Error} error | |
| 229 * @param {?Array.<!CSSAgent.NamedFlow>} namedFlowPayload | |
| 230 * @this {WebInspector.CSSStyleModel} | |
| 231 */ | |
| 232 function callback(userCallback, error, namedFlowPayload) | |
| 233 { | |
| 234 if (error || !namedFlowPayload) | |
| 235 userCallback(null); | |
| 236 else { | |
| 237 var namedFlowCollection = new WebInspector.NamedFlowCollection(n
amedFlowPayload); | |
| 238 this._namedFlowCollections[documentNodeId] = namedFlowCollection
; | |
| 239 userCallback(namedFlowCollection); | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 CSSAgent.getNamedFlowCollection(documentNodeId, callback.bind(this, user
Callback)); | |
| 244 }, | |
| 245 | |
| 246 /** | |
| 247 * @param {!DOMAgent.NodeId} documentNodeId | |
| 248 * @param {string} flowName | |
| 249 * @param {function(?WebInspector.NamedFlow)} userCallback | |
| 250 */ | |
| 251 getFlowByNameAsync: function(documentNodeId, flowName, userCallback) | |
| 252 { | |
| 253 var namedFlowCollection = this._namedFlowCollections[documentNodeId]; | |
| 254 if (namedFlowCollection) { | |
| 255 userCallback(namedFlowCollection.flowByName(flowName)); | |
| 256 return; | |
| 257 } | |
| 258 | |
| 259 /** | |
| 260 * @param {function(?WebInspector.NamedFlow)} userCallback | |
| 261 * @param {?WebInspector.NamedFlowCollection} namedFlowCollection | |
| 262 */ | |
| 263 function callback(userCallback, namedFlowCollection) | |
| 264 { | |
| 265 if (!namedFlowCollection) | |
| 266 userCallback(null); | |
| 267 else | |
| 268 userCallback(namedFlowCollection.flowByName(flowName)); | |
| 269 } | |
| 270 | |
| 271 this.getNamedFlowCollectionAsync(documentNodeId, callback.bind(this, use
rCallback)); | |
| 272 }, | |
| 273 | |
| 274 /** | |
| 275 * @param {!CSSAgent.CSSRuleId} ruleId | 209 * @param {!CSSAgent.CSSRuleId} ruleId |
| 276 * @param {!DOMAgent.NodeId} nodeId | 210 * @param {!DOMAgent.NodeId} nodeId |
| 277 * @param {string} newSelector | 211 * @param {string} newSelector |
| 278 * @param {function(!WebInspector.CSSRule)} successCallback | 212 * @param {function(!WebInspector.CSSRule)} successCallback |
| 279 * @param {function()} failureCallback | 213 * @param {function()} failureCallback |
| 280 */ | 214 */ |
| 281 setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, fail
ureCallback) | 215 setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, fail
ureCallback) |
| 282 { | 216 { |
| 283 /** | 217 /** |
| 284 * @param {!DOMAgent.NodeId} nodeId | 218 * @param {!DOMAgent.NodeId} nodeId |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 */ | 425 */ |
| 492 styleSheetIdsByFrameIdForURL: function(url) | 426 styleSheetIdsByFrameIdForURL: function(url) |
| 493 { | 427 { |
| 494 var styleSheetIdsForFrame = this._styleSheetIdsForURL[url]; | 428 var styleSheetIdsForFrame = this._styleSheetIdsForURL[url]; |
| 495 if (!styleSheetIdsForFrame) | 429 if (!styleSheetIdsForFrame) |
| 496 return {}; | 430 return {}; |
| 497 return styleSheetIdsForFrame; | 431 return styleSheetIdsForFrame; |
| 498 }, | 432 }, |
| 499 | 433 |
| 500 /** | 434 /** |
| 501 * @param {!CSSAgent.NamedFlow} namedFlowPayload | |
| 502 */ | |
| 503 _namedFlowCreated: function(namedFlowPayload) | |
| 504 { | |
| 505 var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload); | |
| 506 var namedFlowCollection = this._namedFlowCollections[namedFlow.documentN
odeId]; | |
| 507 | |
| 508 if (!namedFlowCollection) | |
| 509 return; | |
| 510 | |
| 511 namedFlowCollection._appendNamedFlow(namedFlow); | |
| 512 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlo
wCreated, namedFlow); | |
| 513 }, | |
| 514 | |
| 515 /** | |
| 516 * @param {!DOMAgent.NodeId} documentNodeId | |
| 517 * @param {string} flowName | |
| 518 */ | |
| 519 _namedFlowRemoved: function(documentNodeId, flowName) | |
| 520 { | |
| 521 var namedFlowCollection = this._namedFlowCollections[documentNodeId]; | |
| 522 | |
| 523 if (!namedFlowCollection) | |
| 524 return; | |
| 525 | |
| 526 namedFlowCollection._removeNamedFlow(flowName); | |
| 527 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlo
wRemoved, { documentNodeId: documentNodeId, flowName: flowName }); | |
| 528 }, | |
| 529 | |
| 530 /** | |
| 531 * @param {!CSSAgent.NamedFlow} namedFlowPayload | |
| 532 */ | |
| 533 _regionLayoutUpdated: function(namedFlowPayload) | |
| 534 { | |
| 535 var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload); | |
| 536 var namedFlowCollection = this._namedFlowCollections[namedFlow.documentN
odeId]; | |
| 537 | |
| 538 if (!namedFlowCollection) | |
| 539 return; | |
| 540 | |
| 541 namedFlowCollection._appendNamedFlow(namedFlow); | |
| 542 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.RegionLa
youtUpdated, namedFlow); | |
| 543 }, | |
| 544 | |
| 545 /** | |
| 546 * @param {!CSSAgent.NamedFlow} namedFlowPayload | |
| 547 */ | |
| 548 _regionOversetChanged: function(namedFlowPayload) | |
| 549 { | |
| 550 var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload); | |
| 551 var namedFlowCollection = this._namedFlowCollections[namedFlow.documentN
odeId]; | |
| 552 | |
| 553 if (!namedFlowCollection) | |
| 554 return; | |
| 555 | |
| 556 namedFlowCollection._appendNamedFlow(namedFlow); | |
| 557 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.RegionOv
ersetChanged, namedFlow); | |
| 558 }, | |
| 559 | |
| 560 /** | |
| 561 * @param {!CSSAgent.StyleSheetId} styleSheetId | 435 * @param {!CSSAgent.StyleSheetId} styleSheetId |
| 562 * @param {string} newText | 436 * @param {string} newText |
| 563 * @param {boolean} majorChange | 437 * @param {boolean} majorChange |
| 564 * @param {function(?Protocol.Error)} userCallback | 438 * @param {function(?Protocol.Error)} userCallback |
| 565 */ | 439 */ |
| 566 setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback
) | 440 setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback
) |
| 567 { | 441 { |
| 568 var header = this._styleSheetIdToHeader[styleSheetId]; | 442 var header = this._styleSheetIdToHeader[styleSheetId]; |
| 569 console.assert(header); | 443 console.assert(header); |
| 570 this._pendingCommandsMajorState.push(majorChange); | 444 this._pendingCommandsMajorState.push(majorChange); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 601 }, | 475 }, |
| 602 | 476 |
| 603 _resetStyleSheets: function() | 477 _resetStyleSheets: function() |
| 604 { | 478 { |
| 605 /** @type {!Object.<string, !Object.<!PageAgent.FrameId, !Array.<!CSSAge
nt.StyleSheetId>>>} */ | 479 /** @type {!Object.<string, !Object.<!PageAgent.FrameId, !Array.<!CSSAge
nt.StyleSheetId>>>} */ |
| 606 this._styleSheetIdsForURL = {}; | 480 this._styleSheetIdsForURL = {}; |
| 607 /** @type {!Object.<!CSSAgent.StyleSheetId, !WebInspector.CSSStyleSheetH
eader>} */ | 481 /** @type {!Object.<!CSSAgent.StyleSheetId, !WebInspector.CSSStyleSheetH
eader>} */ |
| 608 this._styleSheetIdToHeader = {}; | 482 this._styleSheetIdToHeader = {}; |
| 609 }, | 483 }, |
| 610 | 484 |
| 611 _resetNamedFlowCollections: function() | |
| 612 { | |
| 613 this._namedFlowCollections = {}; | |
| 614 }, | |
| 615 | |
| 616 updateLocations: function() | 485 updateLocations: function() |
| 617 { | 486 { |
| 618 var headers = Object.values(this._styleSheetIdToHeader); | 487 var headers = Object.values(this._styleSheetIdToHeader); |
| 619 for (var i = 0; i < headers.length; ++i) | 488 for (var i = 0; i < headers.length; ++i) |
| 620 headers[i].updateLocations(); | 489 headers[i].updateLocations(); |
| 621 }, | 490 }, |
| 622 | 491 |
| 623 /** | 492 /** |
| 624 * @param {?CSSAgent.StyleSheetId} styleSheetId | 493 * @param {?CSSAgent.StyleSheetId} styleSheetId |
| 625 * @param {!WebInspector.CSSLocation} rawLocation | 494 * @param {!WebInspector.CSSLocation} rawLocation |
| (...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1614 this._cssModel._styleSheetAdded(header); | 1483 this._cssModel._styleSheetAdded(header); |
| 1615 }, | 1484 }, |
| 1616 | 1485 |
| 1617 /** | 1486 /** |
| 1618 * @param {!CSSAgent.StyleSheetId} id | 1487 * @param {!CSSAgent.StyleSheetId} id |
| 1619 */ | 1488 */ |
| 1620 styleSheetRemoved: function(id) | 1489 styleSheetRemoved: function(id) |
| 1621 { | 1490 { |
| 1622 this._cssModel._styleSheetRemoved(id); | 1491 this._cssModel._styleSheetRemoved(id); |
| 1623 }, | 1492 }, |
| 1624 | |
| 1625 /** | |
| 1626 * @param {!CSSAgent.NamedFlow} namedFlowPayload | |
| 1627 */ | |
| 1628 namedFlowCreated: function(namedFlowPayload) | |
| 1629 { | |
| 1630 this._cssModel._namedFlowCreated(namedFlowPayload); | |
| 1631 }, | |
| 1632 | |
| 1633 /** | |
| 1634 * @param {!DOMAgent.NodeId} documentNodeId | |
| 1635 * @param {string} flowName | |
| 1636 */ | |
| 1637 namedFlowRemoved: function(documentNodeId, flowName) | |
| 1638 { | |
| 1639 this._cssModel._namedFlowRemoved(documentNodeId, flowName); | |
| 1640 }, | |
| 1641 | |
| 1642 /** | |
| 1643 * @param {!CSSAgent.NamedFlow} namedFlowPayload | |
| 1644 */ | |
| 1645 regionLayoutUpdated: function(namedFlowPayload) | |
| 1646 { | |
| 1647 this._cssModel._regionLayoutUpdated(namedFlowPayload); | |
| 1648 }, | |
| 1649 | |
| 1650 /** | |
| 1651 * @param {!CSSAgent.NamedFlow} namedFlowPayload | |
| 1652 */ | |
| 1653 regionOversetChanged: function(namedFlowPayload) | |
| 1654 { | |
| 1655 this._cssModel._regionOversetChanged(namedFlowPayload); | |
| 1656 } | |
| 1657 } | 1493 } |
| 1658 | 1494 |
| 1659 /** | 1495 /** |
| 1660 * @constructor | |
| 1661 * @param {!CSSAgent.NamedFlow} payload | |
| 1662 */ | |
| 1663 WebInspector.NamedFlow = function(payload) | |
| 1664 { | |
| 1665 this.documentNodeId = payload.documentNodeId; | |
| 1666 this.name = payload.name; | |
| 1667 this.overset = payload.overset; | |
| 1668 this.content = payload.content; | |
| 1669 this.regions = payload.regions; | |
| 1670 } | |
| 1671 | |
| 1672 /** | |
| 1673 * @param {!CSSAgent.NamedFlow} payload | |
| 1674 * @return {!WebInspector.NamedFlow} | |
| 1675 */ | |
| 1676 WebInspector.NamedFlow.parsePayload = function(payload) | |
| 1677 { | |
| 1678 return new WebInspector.NamedFlow(payload); | |
| 1679 } | |
| 1680 | |
| 1681 /** | |
| 1682 * @constructor | |
| 1683 * @param {!Array.<!CSSAgent.NamedFlow>} payload | |
| 1684 */ | |
| 1685 WebInspector.NamedFlowCollection = function(payload) | |
| 1686 { | |
| 1687 /** @type {!Object.<string, !WebInspector.NamedFlow>} */ | |
| 1688 this.namedFlowMap = {}; | |
| 1689 | |
| 1690 for (var i = 0; i < payload.length; ++i) { | |
| 1691 var namedFlow = WebInspector.NamedFlow.parsePayload(payload[i]); | |
| 1692 this.namedFlowMap[namedFlow.name] = namedFlow; | |
| 1693 } | |
| 1694 } | |
| 1695 | |
| 1696 WebInspector.NamedFlowCollection.prototype = { | |
| 1697 /** | |
| 1698 * @param {!WebInspector.NamedFlow} namedFlow | |
| 1699 */ | |
| 1700 _appendNamedFlow: function(namedFlow) | |
| 1701 { | |
| 1702 this.namedFlowMap[namedFlow.name] = namedFlow; | |
| 1703 }, | |
| 1704 | |
| 1705 /** | |
| 1706 * @param {string} flowName | |
| 1707 */ | |
| 1708 _removeNamedFlow: function(flowName) | |
| 1709 { | |
| 1710 delete this.namedFlowMap[flowName]; | |
| 1711 }, | |
| 1712 | |
| 1713 /** | |
| 1714 * @param {string} flowName | |
| 1715 * @return {?WebInspector.NamedFlow} | |
| 1716 */ | |
| 1717 flowByName: function(flowName) | |
| 1718 { | |
| 1719 var namedFlow = this.namedFlowMap[flowName]; | |
| 1720 | |
| 1721 if (!namedFlow) | |
| 1722 return null; | |
| 1723 return namedFlow; | |
| 1724 } | |
| 1725 } | |
| 1726 | |
| 1727 /** | |
| 1728 * @constructor | 1496 * @constructor |
| 1729 * @param {!WebInspector.CSSStyleModel} cssModel | 1497 * @param {!WebInspector.CSSStyleModel} cssModel |
| 1730 */ | 1498 */ |
| 1731 WebInspector.CSSStyleModel.ComputedStyleLoader = function(cssModel) | 1499 WebInspector.CSSStyleModel.ComputedStyleLoader = function(cssModel) |
| 1732 { | 1500 { |
| 1733 this._cssModel = cssModel; | 1501 this._cssModel = cssModel; |
| 1734 /** @type {!Object.<*, !Array.<function(?WebInspector.CSSStyleDeclaration)>>
} */ | 1502 /** @type {!Object.<*, !Array.<function(?WebInspector.CSSStyleDeclaration)>>
} */ |
| 1735 this._nodeIdToCallbackData = {}; | 1503 this._nodeIdToCallbackData = {}; |
| 1736 } | 1504 } |
| 1737 | 1505 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1780 for (var i = 0; i < callbacks.length; ++i) | 1548 for (var i = 0; i < callbacks.length; ++i) |
| 1781 callbacks[i](computedStyle); | 1549 callbacks[i](computedStyle); |
| 1782 } | 1550 } |
| 1783 } | 1551 } |
| 1784 } | 1552 } |
| 1785 | 1553 |
| 1786 /** | 1554 /** |
| 1787 * @type {!WebInspector.CSSStyleModel} | 1555 * @type {!WebInspector.CSSStyleModel} |
| 1788 */ | 1556 */ |
| 1789 WebInspector.cssModel; | 1557 WebInspector.cssModel; |
| OLD | NEW |