Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 cr.define('print_preview', function() { | 5 cr.define('print_preview', function() { |
| 6 'use strict'; | 6 'use strict'; |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * A data store that stores destinations and dispatches events when the data | 9 * A data store that stores destinations and dispatches events when the data |
| 10 * store changes. | 10 * store changes. |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 */ | 273 */ |
| 274 this.extensionSearchTimeout_ = null; | 274 this.extensionSearchTimeout_ = null; |
| 275 | 275 |
| 276 /** | 276 /** |
| 277 * MDNS service name of destination that we are waiting to register. | 277 * MDNS service name of destination that we are waiting to register. |
| 278 * @type {?string} | 278 * @type {?string} |
| 279 * @private | 279 * @private |
| 280 */ | 280 */ |
| 281 this.waitForRegisterDestination_ = null; | 281 this.waitForRegisterDestination_ = null; |
| 282 | 282 |
| 283 /** | |
| 284 * Local destinations are CROS destinations on ChromeOS because they require | |
| 285 * extra setup. | |
| 286 * @type {!print_preview.Destination.Origin} | |
| 287 * @private | |
| 288 */ | |
| 289 this.platformOrigin_ = cr.isChromeOS ? | |
| 290 print_preview.Destination.Origin.CROS : | |
| 291 print_preview.Destination.Origin.LOCAL; | |
| 292 | |
| 283 this.addEventListeners_(); | 293 this.addEventListeners_(); |
| 284 this.reset_(); | 294 this.reset_(); |
| 285 }; | 295 }; |
| 286 | 296 |
| 287 /** | 297 /** |
| 298 * @typedef {{ | |
| 299 * printerId: string, | |
| 300 * success: boolean, | |
| 301 * capabilities: Object, | |
| 302 * }} | |
| 303 */ | |
| 304 var PrinterSetupResponse; | |
| 305 | |
| 306 /** | |
| 288 * Event types dispatched by the data store. | 307 * Event types dispatched by the data store. |
| 289 * @enum {string} | 308 * @enum {string} |
| 290 */ | 309 */ |
| 291 DestinationStore.EventType = { | 310 DestinationStore.EventType = { |
| 292 DESTINATION_SEARCH_DONE: | 311 DESTINATION_SEARCH_DONE: |
| 293 'print_preview.DestinationStore.DESTINATION_SEARCH_DONE', | 312 'print_preview.DestinationStore.DESTINATION_SEARCH_DONE', |
| 294 DESTINATION_SEARCH_STARTED: | 313 DESTINATION_SEARCH_STARTED: |
| 295 'print_preview.DestinationStore.DESTINATION_SEARCH_STARTED', | 314 'print_preview.DestinationStore.DESTINATION_SEARCH_STARTED', |
| 296 DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT', | 315 DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT', |
| 297 DESTINATIONS_INSERTED: | 316 DESTINATIONS_INSERTED: |
| 298 'print_preview.DestinationStore.DESTINATIONS_INSERTED', | 317 'print_preview.DestinationStore.DESTINATIONS_INSERTED', |
| 299 PROVISIONAL_DESTINATION_RESOLVED: | 318 PROVISIONAL_DESTINATION_RESOLVED: |
| 300 'print_preview.DestinationStore.PROVISIONAL_DESTINATION_RESOLVED', | 319 'print_preview.DestinationStore.PROVISIONAL_DESTINATION_RESOLVED', |
| 301 CACHED_SELECTED_DESTINATION_INFO_READY: | 320 CACHED_SELECTED_DESTINATION_INFO_READY: |
| 302 'print_preview.DestinationStore.CACHED_SELECTED_DESTINATION_INFO_READY', | 321 'print_preview.DestinationStore.CACHED_SELECTED_DESTINATION_INFO_READY', |
| 303 SELECTED_DESTINATION_CAPABILITIES_READY: | 322 SELECTED_DESTINATION_CAPABILITIES_READY: |
| 304 'print_preview.DestinationStore.SELECTED_DESTINATION_CAPABILITIES_READY' | 323 'print_preview.DestinationStore.SELECTED_DESTINATION_CAPABILITIES_READY' , |
| 324 PRINTER_CONFIGURED: | |
| 325 'print_preview.DestinationStore.PRINTER_CONFIGURED', | |
| 305 }; | 326 }; |
| 306 | 327 |
| 307 /** | 328 /** |
| 308 * Delay in milliseconds before the destination store ignores the initial | 329 * Delay in milliseconds before the destination store ignores the initial |
| 309 * destination ID and just selects any printer (since the initial destination | 330 * destination ID and just selects any printer (since the initial destination |
| 310 * was not found). | 331 * was not found). |
| 311 * @private {number} | 332 * @private {number} |
| 312 * @const | 333 * @const |
| 313 */ | 334 */ |
| 314 DestinationStore.AUTO_SELECT_TIMEOUT_ = 15000; | 335 DestinationStore.AUTO_SELECT_TIMEOUT_ = 15000; |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 683 return; | 704 return; |
| 684 } | 705 } |
| 685 } | 706 } |
| 686 | 707 |
| 687 if (!this.systemDefaultDestinationId_ && | 708 if (!this.systemDefaultDestinationId_ && |
| 688 !this.appState_.isSelectedDestinationValid()) { | 709 !this.appState_.isSelectedDestinationValid()) { |
| 689 this.selectPdfDestination_(); | 710 this.selectPdfDestination_(); |
| 690 return; | 711 return; |
| 691 } | 712 } |
| 692 | 713 |
| 693 var origin = print_preview.Destination.Origin.LOCAL; | 714 var origin = null; |
| 694 var id = this.systemDefaultDestinationId_; | 715 var id = ''; |
| 695 var account = ''; | 716 var account = ''; |
| 696 var name = ''; | 717 var name = ''; |
| 697 var capabilities = null; | 718 var capabilities = null; |
| 698 var extensionId = ''; | 719 var extensionId = ''; |
| 699 var extensionName = ''; | 720 var extensionName = ''; |
| 700 var foundDestination = false; | 721 var foundDestination = false; |
| 701 if (this.appState_.recentDestinations) { | 722 if (this.appState_.recentDestinations) { |
| 702 // Run through the destinations forward. As soon as we find a | 723 // Run through the destinations forward. As soon as we find a |
| 703 // destination, don't select any future destinations, just mark | 724 // destination, don't select any future destinations, just mark |
| 704 // them recent. Otherwise, there is a race condition between selecting | 725 // them recent. Otherwise, there is a race condition between selecting |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 728 id, | 749 id, |
| 729 account, | 750 account, |
| 730 name, | 751 name, |
| 731 capabilities, | 752 capabilities, |
| 732 extensionId, | 753 extensionId, |
| 733 extensionName); | 754 extensionName); |
| 734 } | 755 } |
| 735 } | 756 } |
| 736 } | 757 } |
| 737 if (foundDestination) return; | 758 if (foundDestination) return; |
| 759 | |
| 738 // Try the system default | 760 // Try the system default |
| 761 id = this.systemDefaultDestinationId_; | |
| 762 origin = id == print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ? | |
| 763 print_preview.Destination.Origin.LOCAL : | |
| 764 this.platformOrigin_; | |
| 765 account = ''; | |
| 739 var candidate = | 766 var candidate = |
| 740 this.destinationMap_[this.getDestinationKey_(origin, id, account)]; | 767 this.destinationMap_[this.getDestinationKey_(origin, id, account)]; |
| 741 if (candidate != null) { | 768 if (candidate != null) { |
| 742 this.selectDestination(candidate); | 769 this.selectDestination(candidate); |
| 743 return; | 770 return; |
| 744 } | 771 } |
| 745 | 772 |
| 746 if (this.fetchPreselectedDestination_( | 773 if (this.fetchPreselectedDestination_( |
| 747 origin, | 774 origin, |
| 748 id, | 775 id, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 769 * destination. | 796 * destination. |
| 770 * @param {string} extensionName Extension name associated with this | 797 * @param {string} extensionName Extension name associated with this |
| 771 * destination. | 798 * destination. |
| 772 * @private | 799 * @private |
| 773 */ | 800 */ |
| 774 fetchPreselectedDestination_: function( | 801 fetchPreselectedDestination_: function( |
| 775 origin, id, account, name, capabilities, extensionId, extensionName) { | 802 origin, id, account, name, capabilities, extensionId, extensionName) { |
| 776 this.autoSelectMatchingDestination_ = | 803 this.autoSelectMatchingDestination_ = |
| 777 this.createExactDestinationMatch_(origin, id); | 804 this.createExactDestinationMatch_(origin, id); |
| 778 | 805 |
| 779 if (origin == print_preview.Destination.Origin.LOCAL) { | 806 if (origin == print_preview.Destination.Origin.LOCAL || |
| 807 origin == print_preview.Destination.Origin.CROS) { | |
| 780 this.nativeLayer_.startGetLocalDestinationCapabilities(id); | 808 this.nativeLayer_.startGetLocalDestinationCapabilities(id); |
| 781 return true; | 809 return true; |
| 782 } | 810 } |
| 783 | 811 |
| 784 if (this.cloudPrintInterface_ && | 812 if (this.cloudPrintInterface_ && |
| 785 (origin == print_preview.Destination.Origin.COOKIES || | 813 (origin == print_preview.Destination.Origin.COOKIES || |
| 786 origin == print_preview.Destination.Origin.DEVICE)) { | 814 origin == print_preview.Destination.Origin.DEVICE)) { |
| 787 this.cloudPrintInterface_.printer(id, origin, account); | 815 this.cloudPrintInterface_.printer(id, origin, account); |
| 788 return true; | 816 return true; |
| 789 } | 817 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 840 | 868 |
| 841 /** | 869 /** |
| 842 * Attempts to find a destination matching the provided rules. | 870 * Attempts to find a destination matching the provided rules. |
| 843 * @param {!print_preview.DestinationMatch} destinationMatch Rules to match. | 871 * @param {!print_preview.DestinationMatch} destinationMatch Rules to match. |
| 844 * @private | 872 * @private |
| 845 */ | 873 */ |
| 846 fetchMatchingDestination_: function(destinationMatch) { | 874 fetchMatchingDestination_: function(destinationMatch) { |
| 847 this.autoSelectMatchingDestination_ = destinationMatch; | 875 this.autoSelectMatchingDestination_ = destinationMatch; |
| 848 | 876 |
| 849 if (destinationMatch.matchOrigin( | 877 if (destinationMatch.matchOrigin( |
| 850 print_preview.Destination.Origin.LOCAL)) { | 878 print_preview.Destination.Origin.LOCAL) || |
| 879 destinationMatch.matchOrigin( | |
| 880 print_preview.Destination.Origin.CROS)) { | |
| 851 this.startLoadLocalDestinations(); | 881 this.startLoadLocalDestinations(); |
| 852 } | 882 } |
| 853 if (destinationMatch.matchOrigin( | 883 if (destinationMatch.matchOrigin( |
| 854 print_preview.Destination.Origin.PRIVET)) { | 884 print_preview.Destination.Origin.PRIVET)) { |
| 855 this.startLoadPrivetDestinations(); | 885 this.startLoadPrivetDestinations(); |
| 856 } | 886 } |
| 857 if (destinationMatch.matchOrigin( | 887 if (destinationMatch.matchOrigin( |
| 858 print_preview.Destination.Origin.EXTENSION)) { | 888 print_preview.Destination.Origin.EXTENSION)) { |
| 859 this.startLoadExtensionDestinations(); | 889 this.startLoadExtensionDestinations(); |
| 860 } | 890 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 895 if (!isLocal && !isCloud) { | 925 if (!isLocal && !isCloud) { |
| 896 console.error('Unsupported type: "' + matchRules.kind + '"'); | 926 console.error('Unsupported type: "' + matchRules.kind + '"'); |
| 897 return null; | 927 return null; |
| 898 } | 928 } |
| 899 | 929 |
| 900 var origins = []; | 930 var origins = []; |
| 901 if (isLocal) { | 931 if (isLocal) { |
| 902 origins.push(print_preview.Destination.Origin.LOCAL); | 932 origins.push(print_preview.Destination.Origin.LOCAL); |
| 903 origins.push(print_preview.Destination.Origin.PRIVET); | 933 origins.push(print_preview.Destination.Origin.PRIVET); |
| 904 origins.push(print_preview.Destination.Origin.EXTENSION); | 934 origins.push(print_preview.Destination.Origin.EXTENSION); |
| 935 origins.push(print_preview.Destination.Origin.CROS); | |
| 905 } | 936 } |
| 906 if (isCloud) { | 937 if (isCloud) { |
| 907 origins.push(print_preview.Destination.Origin.COOKIES); | 938 origins.push(print_preview.Destination.Origin.COOKIES); |
| 908 origins.push(print_preview.Destination.Origin.DEVICE); | 939 origins.push(print_preview.Destination.Origin.DEVICE); |
| 909 origins.push(print_preview.Destination.Origin.PROFILE); | 940 origins.push(print_preview.Destination.Origin.PROFILE); |
| 910 } | 941 } |
| 911 | 942 |
| 912 var idRegExp = null; | 943 var idRegExp = null; |
| 913 try { | 944 try { |
| 914 if (matchRules.idPattern) { | 945 if (matchRules.idPattern) { |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 940 * @private | 971 * @private |
| 941 */ | 972 */ |
| 942 convertPreselectedToDestinationMatch_: function() { | 973 convertPreselectedToDestinationMatch_: function() { |
| 943 if (this.appState_.isSelectedDestinationValid()) { | 974 if (this.appState_.isSelectedDestinationValid()) { |
| 944 return this.createExactDestinationMatch_( | 975 return this.createExactDestinationMatch_( |
| 945 this.appState_.selectedDestination.origin, | 976 this.appState_.selectedDestination.origin, |
| 946 this.appState_.selectedDestination.id); | 977 this.appState_.selectedDestination.id); |
| 947 } | 978 } |
| 948 if (this.systemDefaultDestinationId_) { | 979 if (this.systemDefaultDestinationId_) { |
| 949 return this.createExactDestinationMatch_( | 980 return this.createExactDestinationMatch_( |
| 950 print_preview.Destination.Origin.LOCAL, | 981 this.platformOrigin_, |
| 951 this.systemDefaultDestinationId_); | 982 this.systemDefaultDestinationId_); |
| 952 } | 983 } |
| 953 return null; | 984 return null; |
| 954 }, | 985 }, |
| 955 | 986 |
| 956 /** | 987 /** |
| 957 * @param {!print_preview.Destination.Origin} origin Destination origin. | 988 * @param {!print_preview.Destination.Origin} origin Destination origin. |
| 958 * @param {string} id Destination id. | 989 * @param {string} id Destination id. |
| 959 * @return {!print_preview.DestinationMatch} Creates rules matching | 990 * @return {!print_preview.DestinationMatch} Creates rules matching |
| 960 * provided destination. | 991 * provided destination. |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1077 destination.id, destination.origin, destination.account); | 1108 destination.id, destination.origin, destination.account); |
| 1078 } | 1109 } |
| 1079 } else { | 1110 } else { |
| 1080 cr.dispatchSimpleEvent( | 1111 cr.dispatchSimpleEvent( |
| 1081 this, | 1112 this, |
| 1082 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); | 1113 DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); |
| 1083 } | 1114 } |
| 1084 }, | 1115 }, |
| 1085 | 1116 |
| 1086 /** | 1117 /** |
| 1118 * Attempt to resolve the capabilities for a Chrome OS printer. | |
| 1119 * @param {!print_preview.Destination} destination The destination which | |
| 1120 * requires resolution. | |
| 1121 */ | |
| 1122 resolveCrosDestination: function(destination) { | |
| 1123 assert(destination.origin == print_preview.Destination.Origin.CROS); | |
| 1124 this.nativeLayer_.setupPrinter(destination.id). | |
| 1125 then( | |
|
dpapad
2017/01/12 19:32:50
Nit: You would avoid a lot of indentation if you p
skau
2017/01/12 23:24:04
Done.
| |
| 1126 /** | |
| 1127 * Handle the result of a successful PRINTER_SETUP request. | |
| 1128 * @param {!PrinterSetupResponse} response. | |
| 1129 */ | |
| 1130 function(response) { | |
| 1131 this.dispatchEvent(new CustomEvent( | |
| 1132 DestinationStore.EventType.PRINTER_CONFIGURED, { | |
| 1133 detail: { | |
|
dpapad
2017/01/12 19:32:50
Why not the following?
detail: response
Instead
skau
2017/01/12 23:24:04
No particular reason.
| |
| 1134 printerId: response.printerId, | |
| 1135 capabilities: response.capabilities, | |
| 1136 success: response.success | |
| 1137 } | |
| 1138 })); | |
| 1139 }.bind(this), | |
| 1140 /** | |
| 1141 * Calling printer setup failed. | |
| 1142 */ | |
| 1143 function() { | |
| 1144 this.dispatchEvent(new CustomEvent( | |
| 1145 DestinationStore.EventType.PRINTER_CONFIGURED, { | |
| 1146 detail: { | |
| 1147 printerId: destination.id, | |
| 1148 success: false | |
| 1149 } | |
| 1150 })); | |
| 1151 }.bind(this)); | |
| 1152 }, | |
| 1153 | |
| 1154 /** | |
| 1087 * Attempts to resolve a provisional destination. | 1155 * Attempts to resolve a provisional destination. |
| 1088 * @param {!print_preview.Destination} destinaion Provisional destination | 1156 * @param {!print_preview.Destination} destinaion Provisional destination |
| 1089 * that should be resolved. | 1157 * that should be resolved. |
| 1090 */ | 1158 */ |
| 1091 resolveProvisionalDestination: function(destination) { | 1159 resolveProvisionalDestination: function(destination) { |
| 1092 assert( | 1160 assert( |
| 1093 destination.provisionalType == | 1161 destination.provisionalType == |
| 1094 print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION, | 1162 print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION, |
| 1095 'Provisional type cannot be resolved.'); | 1163 'Provisional type cannot be resolved.'); |
| 1096 this.nativeLayer_.grantExtensionPrinterAccess(destination.id); | 1164 this.nativeLayer_.grantExtensionPrinterAccess(destination.id); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1112 /** | 1180 /** |
| 1113 * Attempts to select system default destination with a fallback to | 1181 * Attempts to select system default destination with a fallback to |
| 1114 * 'Save to PDF' destination. | 1182 * 'Save to PDF' destination. |
| 1115 * @private | 1183 * @private |
| 1116 */ | 1184 */ |
| 1117 selectDefaultDestination_: function() { | 1185 selectDefaultDestination_: function() { |
| 1118 if (this.systemDefaultDestinationId_) { | 1186 if (this.systemDefaultDestinationId_) { |
| 1119 if (this.autoSelectMatchingDestination_ && | 1187 if (this.autoSelectMatchingDestination_ && |
| 1120 !this.autoSelectMatchingDestination_.matchIdAndOrigin( | 1188 !this.autoSelectMatchingDestination_.matchIdAndOrigin( |
| 1121 this.systemDefaultDestinationId_, | 1189 this.systemDefaultDestinationId_, |
| 1122 print_preview.Destination.Origin.LOCAL)) { | 1190 this.plaformOrigin_)) { |
| 1123 if (this.fetchPreselectedDestination_( | 1191 if (this.fetchPreselectedDestination_( |
| 1124 print_preview.Destination.Origin.LOCAL, | 1192 this.platformOrigin_, |
| 1125 this.systemDefaultDestinationId_, | 1193 this.systemDefaultDestinationId_, |
| 1126 '' /*account*/, | 1194 '' /*account*/, |
| 1127 '' /*name*/, | 1195 '' /*name*/, |
| 1128 null /*capabilities*/, | 1196 null /*capabilities*/, |
| 1129 '' /*extensionId*/, | 1197 '' /*extensionId*/, |
| 1130 '' /*extensionName*/)) { | 1198 '' /*extensionName*/)) { |
| 1131 return; | 1199 return; |
| 1132 } | 1200 } |
| 1133 } | 1201 } |
| 1134 } | 1202 } |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1517 * destination already exists, otherwise it creates a new destination and | 1585 * destination already exists, otherwise it creates a new destination and |
| 1518 * then updates its capabilities. | 1586 * then updates its capabilities. |
| 1519 * @param {Event} event Contains the capabilities of the local print | 1587 * @param {Event} event Contains the capabilities of the local print |
| 1520 * destination. | 1588 * destination. |
| 1521 * @private | 1589 * @private |
| 1522 */ | 1590 */ |
| 1523 onLocalDestinationCapabilitiesSet_: function(event) { | 1591 onLocalDestinationCapabilitiesSet_: function(event) { |
| 1524 var destinationId = event.settingsInfo['printerId']; | 1592 var destinationId = event.settingsInfo['printerId']; |
| 1525 var printerName = event.settingsInfo['printerName']; | 1593 var printerName = event.settingsInfo['printerName']; |
| 1526 var printerDescription = event.settingsInfo['printerDescription']; | 1594 var printerDescription = event.settingsInfo['printerDescription']; |
| 1595 // PDF is special since we don't need to query the device for | |
| 1596 // capabilities. | |
| 1597 var origin = destinationId == | |
| 1598 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ? | |
| 1599 print_preview.Destination.Origin.LOCAL : this.platformOrigin_; | |
| 1527 var key = this.getDestinationKey_( | 1600 var key = this.getDestinationKey_( |
| 1528 print_preview.Destination.Origin.LOCAL, | 1601 origin, |
| 1529 destinationId, | 1602 destinationId, |
| 1530 ''); | 1603 ''); |
| 1531 var destination = this.destinationMap_[key]; | 1604 var destination = this.destinationMap_[key]; |
| 1532 var capabilities = DestinationStore.localizeCapabilities_( | 1605 var capabilities = DestinationStore.localizeCapabilities_( |
| 1533 event.settingsInfo.capabilities); | 1606 event.settingsInfo.capabilities); |
| 1534 // Special case for PDF printer (until local printers capabilities are | 1607 // Special case for PDF printer (until local printers capabilities are |
| 1535 // reported in CDD format too). | 1608 // reported in CDD format too). |
| 1536 if (destinationId == | 1609 if (destinationId == |
| 1537 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) { | 1610 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) { |
| 1538 if (destination) { | 1611 if (destination) { |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1745 return this.getDestinationKey_( | 1818 return this.getDestinationKey_( |
| 1746 destination.origin, destination.id, destination.account); | 1819 destination.origin, destination.id, destination.account); |
| 1747 } | 1820 } |
| 1748 }; | 1821 }; |
| 1749 | 1822 |
| 1750 // Export | 1823 // Export |
| 1751 return { | 1824 return { |
| 1752 DestinationStore: DestinationStore | 1825 DestinationStore: DestinationStore |
| 1753 }; | 1826 }; |
| 1754 }); | 1827 }); |
| OLD | NEW |