Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: src/js/i18n.js

Issue 1919763002: Migrate Object.definePropert{ies,y} from v8natives to builtins. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@v8natives
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/js/array.js ('k') | src/js/messages.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project 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 // ECMAScript 402 API implementation. 5 // ECMAScript 402 API implementation.
6 6
7 /** 7 /**
8 * Intl object is a single object that has some named properties, 8 * Intl object is a single object that has some named properties,
9 * all of which are constructors. 9 * all of which are constructors.
10 */ 10 */
(...skipping 17 matching lines...) Expand all
28 var InstallFunctions = utils.InstallFunctions; 28 var InstallFunctions = utils.InstallFunctions;
29 var InstallGetter = utils.InstallGetter; 29 var InstallGetter = utils.InstallGetter;
30 var InternalPackedArray = utils.InternalPackedArray; 30 var InternalPackedArray = utils.InternalPackedArray;
31 var InternalRegExpMatch; 31 var InternalRegExpMatch;
32 var InternalRegExpReplace 32 var InternalRegExpReplace
33 var IsFinite; 33 var IsFinite;
34 var IsNaN; 34 var IsNaN;
35 var MakeError; 35 var MakeError;
36 var MakeRangeError; 36 var MakeRangeError;
37 var MakeTypeError; 37 var MakeTypeError;
38 var ObjectDefineProperties = utils.ImportNow("ObjectDefineProperties");
39 var ObjectDefineProperty = utils.ImportNow("ObjectDefineProperty");
40 var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty"); 38 var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
41 var OverrideFunction = utils.OverrideFunction; 39 var OverrideFunction = utils.OverrideFunction;
42 var patternSymbol = utils.ImportNow("intl_pattern_symbol"); 40 var patternSymbol = utils.ImportNow("intl_pattern_symbol");
43 var resolvedSymbol = utils.ImportNow("intl_resolved_symbol"); 41 var resolvedSymbol = utils.ImportNow("intl_resolved_symbol");
44 var SetFunctionName = utils.SetFunctionName; 42 var SetFunctionName = utils.SetFunctionName;
45 var StringIndexOf; 43 var StringIndexOf;
46 var StringLastIndexOf; 44 var StringLastIndexOf;
47 var StringSplit; 45 var StringSplit;
48 var StringSubstr; 46 var StringSubstr;
49 var StringSubstring; 47 var StringSubstring;
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 565
568 566
569 /** 567 /**
570 * Converts all OwnProperties into 568 * Converts all OwnProperties into
571 * configurable: false, writable: false, enumerable: true. 569 * configurable: false, writable: false, enumerable: true.
572 */ 570 */
573 function freezeArray(array) { 571 function freezeArray(array) {
574 var l = array.length; 572 var l = array.length;
575 for (var i = 0; i < l; i++) { 573 for (var i = 0; i < l; i++) {
576 if (i in array) { 574 if (i in array) {
577 ObjectDefineProperty(array, i, {value: array[i], 575 %object_define_property(array, i, {value: array[i],
578 configurable: false, 576 configurable: false,
579 writable: false, 577 writable: false,
580 enumerable: true}); 578 enumerable: true});
581 } 579 }
582 } 580 }
583 581
584 ObjectDefineProperty(array, 'length', {value: l, writable: false}); 582 %object_define_property(array, 'length', {value: l, writable: false});
585 return array; 583 return array;
586 } 584 }
587 585
588 586
589 /** 587 /**
590 * It's sometimes desireable to leave user requested locale instead of ICU 588 * It's sometimes desireable to leave user requested locale instead of ICU
591 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter 589 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter
592 * one, if that was what user requested). 590 * one, if that was what user requested).
593 * This function returns user specified tag if its maximized form matches ICU 591 * This function returns user specified tag if its maximized form matches ICU
594 * resolved locale. If not we return ICU result. 592 * resolved locale. If not we return ICU result.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 634
637 return available; 635 return available;
638 } 636 }
639 637
640 638
641 /** 639 /**
642 * Defines a property and sets writable and enumerable to true. 640 * Defines a property and sets writable and enumerable to true.
643 * Configurable is false by default. 641 * Configurable is false by default.
644 */ 642 */
645 function defineWEProperty(object, property, value) { 643 function defineWEProperty(object, property, value) {
646 ObjectDefineProperty(object, property, 644 %object_define_property(object, property,
647 {value: value, writable: true, enumerable: true}); 645 {value: value, writable: true, enumerable: true});
648 } 646 }
649 647
650 648
651 /** 649 /**
652 * Adds property to an object if the value is not undefined. 650 * Adds property to an object if the value is not undefined.
653 * Sets configurable descriptor to false. 651 * Sets configurable descriptor to false.
654 */ 652 */
655 function addWEPropertyIfDefined(object, property, value) { 653 function addWEPropertyIfDefined(object, property, value) {
656 if (!IS_UNDEFINED(value)) { 654 if (!IS_UNDEFINED(value)) {
657 defineWEProperty(object, property, value); 655 defineWEProperty(object, property, value);
658 } 656 }
659 } 657 }
660 658
661 659
662 /** 660 /**
663 * Defines a property and sets writable, enumerable and configurable to true. 661 * Defines a property and sets writable, enumerable and configurable to true.
664 */ 662 */
665 function defineWECProperty(object, property, value) { 663 function defineWECProperty(object, property, value) {
666 ObjectDefineProperty(object, property, {value: value, 664 %object_define_property(object, property, {value: value,
667 writable: true, 665 writable: true,
668 enumerable: true, 666 enumerable: true,
669 configurable: true}); 667 configurable: true});
670 } 668 }
671 669
672 670
673 /** 671 /**
674 * Adds property to an object if the value is not undefined. 672 * Adds property to an object if the value is not undefined.
675 * Sets all descriptors to true. 673 * Sets all descriptors to true.
676 */ 674 */
677 function addWECPropertyIfDefined(object, property, value) { 675 function addWECPropertyIfDefined(object, property, value) {
678 if (!IS_UNDEFINED(value)) { 676 if (!IS_UNDEFINED(value)) {
679 defineWECProperty(object, property, value); 677 defineWECProperty(object, property, value);
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 } else if (internalOptions.usage === 'search') { 956 } else if (internalOptions.usage === 'search') {
959 extension = '-u-co-search'; 957 extension = '-u-co-search';
960 } 958 }
961 defineWEProperty(internalOptions, 'collation', collation); 959 defineWEProperty(internalOptions, 'collation', collation);
962 960
963 var requestedLocale = locale.locale + extension; 961 var requestedLocale = locale.locale + extension;
964 962
965 // We define all properties C++ code may produce, to prevent security 963 // We define all properties C++ code may produce, to prevent security
966 // problems. If malicious user decides to redefine Object.prototype.locale 964 // problems. If malicious user decides to redefine Object.prototype.locale
967 // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us"). 965 // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
968 // ObjectDefineProperties will either succeed defining or throw an error. 966 // %object_define_properties will either succeed defining or throw an error.
969 var resolved = ObjectDefineProperties({}, { 967 var resolved = %object_define_properties({}, {
970 caseFirst: {writable: true}, 968 caseFirst: {writable: true},
971 collation: {value: internalOptions.collation, writable: true}, 969 collation: {value: internalOptions.collation, writable: true},
972 ignorePunctuation: {writable: true}, 970 ignorePunctuation: {writable: true},
973 locale: {writable: true}, 971 locale: {writable: true},
974 numeric: {writable: true}, 972 numeric: {writable: true},
975 requestedLocale: {value: requestedLocale, writable: true}, 973 requestedLocale: {value: requestedLocale, writable: true},
976 sensitivity: {writable: true}, 974 sensitivity: {writable: true},
977 strength: {writable: true}, 975 strength: {writable: true},
978 usage: {value: internalOptions.usage, writable: true} 976 usage: {value: internalOptions.usage, writable: true}
979 }); 977 });
980 978
981 var internalCollator = %CreateCollator(requestedLocale, 979 var internalCollator = %CreateCollator(requestedLocale,
982 internalOptions, 980 internalOptions,
983 resolved); 981 resolved);
984 982
985 // Writable, configurable and enumerable are set to false by default. 983 // Writable, configurable and enumerable are set to false by default.
986 %MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator); 984 %MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator);
987 collator[resolvedSymbol] = resolved; 985 collator[resolvedSymbol] = resolved;
988 ObjectDefineProperty(collator, 'resolved', resolvedAccessor); 986 %object_define_property(collator, 'resolved', resolvedAccessor);
989 987
990 return collator; 988 return collator;
991 } 989 }
992 990
993 991
994 /** 992 /**
995 * Constructs Intl.Collator object given optional locales and options 993 * Constructs Intl.Collator object given optional locales and options
996 * parameters. 994 * parameters.
997 * 995 *
998 * @constructor 996 * @constructor
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1191 * for a number format. 1189 * for a number format.
1192 */ 1190 */
1193 var NUMBER_FORMAT_KEY_MAP = { 1191 var NUMBER_FORMAT_KEY_MAP = {
1194 'nu': {'property': UNDEFINED, 'type': 'string'} 1192 'nu': {'property': UNDEFINED, 'type': 'string'}
1195 }; 1193 };
1196 1194
1197 var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP, 1195 var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP,
1198 getOption, internalOptions); 1196 getOption, internalOptions);
1199 1197
1200 var requestedLocale = locale.locale + extension; 1198 var requestedLocale = locale.locale + extension;
1201 var resolved = ObjectDefineProperties({}, { 1199 var resolved = %object_define_properties({}, {
1202 currency: {writable: true}, 1200 currency: {writable: true},
1203 currencyDisplay: {writable: true}, 1201 currencyDisplay: {writable: true},
1204 locale: {writable: true}, 1202 locale: {writable: true},
1205 maximumFractionDigits: {writable: true}, 1203 maximumFractionDigits: {writable: true},
1206 minimumFractionDigits: {writable: true}, 1204 minimumFractionDigits: {writable: true},
1207 minimumIntegerDigits: {writable: true}, 1205 minimumIntegerDigits: {writable: true},
1208 numberingSystem: {writable: true}, 1206 numberingSystem: {writable: true},
1209 pattern: patternAccessor, 1207 pattern: patternAccessor,
1210 requestedLocale: {value: requestedLocale, writable: true}, 1208 requestedLocale: {value: requestedLocale, writable: true},
1211 style: {value: internalOptions.style, writable: true}, 1209 style: {value: internalOptions.style, writable: true},
1212 useGrouping: {writable: true} 1210 useGrouping: {writable: true}
1213 }); 1211 });
1214 if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) { 1212 if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) {
1215 defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED); 1213 defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED);
1216 } 1214 }
1217 if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) { 1215 if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) {
1218 defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED); 1216 defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED);
1219 } 1217 }
1220 var formatter = %CreateNumberFormat(requestedLocale, 1218 var formatter = %CreateNumberFormat(requestedLocale,
1221 internalOptions, 1219 internalOptions,
1222 resolved); 1220 resolved);
1223 1221
1224 if (internalOptions.style === 'currency') { 1222 if (internalOptions.style === 'currency') {
1225 ObjectDefineProperty(resolved, 'currencyDisplay', {value: currencyDisplay, 1223 %object_define_property(resolved, 'currencyDisplay',
1226 writable: true}); 1224 {value: currencyDisplay, writable: true});
1227 } 1225 }
1228 1226
1229 %MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter); 1227 %MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter);
1230 numberFormat[resolvedSymbol] = resolved; 1228 numberFormat[resolvedSymbol] = resolved;
1231 ObjectDefineProperty(numberFormat, 'resolved', resolvedAccessor); 1229 %object_define_property(numberFormat, 'resolved', resolvedAccessor);
1232 1230
1233 return numberFormat; 1231 return numberFormat;
1234 } 1232 }
1235 1233
1236 1234
1237 /** 1235 /**
1238 * Constructs Intl.NumberFormat object given optional locales and options 1236 * Constructs Intl.NumberFormat object given optional locales and options
1239 * parameters. 1237 * parameters.
1240 * 1238 *
1241 * @constructor 1239 * @constructor
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
1501 needsDefault = false; 1499 needsDefault = false;
1502 } 1500 }
1503 1501
1504 if ((required === 'time' || required === 'any') && 1502 if ((required === 'time' || required === 'any') &&
1505 (!IS_UNDEFINED(options.hour) || !IS_UNDEFINED(options.minute) || 1503 (!IS_UNDEFINED(options.hour) || !IS_UNDEFINED(options.minute) ||
1506 !IS_UNDEFINED(options.second))) { 1504 !IS_UNDEFINED(options.second))) {
1507 needsDefault = false; 1505 needsDefault = false;
1508 } 1506 }
1509 1507
1510 if (needsDefault && (defaults === 'date' || defaults === 'all')) { 1508 if (needsDefault && (defaults === 'date' || defaults === 'all')) {
1511 ObjectDefineProperty(options, 'year', {value: 'numeric', 1509 %object_define_property(options, 'year', {value: 'numeric',
1512 writable: true, 1510 writable: true,
1513 enumerable: true, 1511 enumerable: true,
1514 configurable: true}); 1512 configurable: true});
1515 ObjectDefineProperty(options, 'month', {value: 'numeric', 1513 %object_define_property(options, 'month', {value: 'numeric',
1516 writable: true, 1514 writable: true,
1517 enumerable: true, 1515 enumerable: true,
1518 configurable: true}); 1516 configurable: true});
1519 ObjectDefineProperty(options, 'day', {value: 'numeric', 1517 %object_define_property(options, 'day', {value: 'numeric',
1520 writable: true,
1521 enumerable: true,
1522 configurable: true});
1523 }
1524
1525 if (needsDefault && (defaults === 'time' || defaults === 'all')) {
1526 ObjectDefineProperty(options, 'hour', {value: 'numeric',
1527 writable: true,
1528 enumerable: true,
1529 configurable: true});
1530 ObjectDefineProperty(options, 'minute', {value: 'numeric',
1531 writable: true,
1532 enumerable: true,
1533 configurable: true});
1534 ObjectDefineProperty(options, 'second', {value: 'numeric',
1535 writable: true, 1518 writable: true,
1536 enumerable: true, 1519 enumerable: true,
1537 configurable: true}); 1520 configurable: true});
1538 } 1521 }
1539 1522
1523 if (needsDefault && (defaults === 'time' || defaults === 'all')) {
1524 %object_define_property(options, 'hour', {value: 'numeric',
1525 writable: true,
1526 enumerable: true,
1527 configurable: true});
1528 %object_define_property(options, 'minute', {value: 'numeric',
1529 writable: true,
1530 enumerable: true,
1531 configurable: true});
1532 %object_define_property(options, 'second', {value: 'numeric',
1533 writable: true,
1534 enumerable: true,
1535 configurable: true});
1536 }
1537
1540 return options; 1538 return options;
1541 } 1539 }
1542 1540
1543 1541
1544 /** 1542 /**
1545 * Initializes the given object so it's a valid DateTimeFormat instance. 1543 * Initializes the given object so it's a valid DateTimeFormat instance.
1546 * Useful for subclassing. 1544 * Useful for subclassing.
1547 */ 1545 */
1548 function initializeDateTimeFormat(dateFormat, locales, options) { 1546 function initializeDateTimeFormat(dateFormat, locales, options) {
1549 1547
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1585 */ 1583 */
1586 var DATETIME_FORMAT_KEY_MAP = { 1584 var DATETIME_FORMAT_KEY_MAP = {
1587 'ca': {'property': UNDEFINED, 'type': 'string'}, 1585 'ca': {'property': UNDEFINED, 'type': 'string'},
1588 'nu': {'property': UNDEFINED, 'type': 'string'} 1586 'nu': {'property': UNDEFINED, 'type': 'string'}
1589 }; 1587 };
1590 1588
1591 var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP, 1589 var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP,
1592 getOption, internalOptions); 1590 getOption, internalOptions);
1593 1591
1594 var requestedLocale = locale.locale + extension; 1592 var requestedLocale = locale.locale + extension;
1595 var resolved = ObjectDefineProperties({}, { 1593 var resolved = %object_define_properties({}, {
1596 calendar: {writable: true}, 1594 calendar: {writable: true},
1597 day: {writable: true}, 1595 day: {writable: true},
1598 era: {writable: true}, 1596 era: {writable: true},
1599 hour12: {writable: true}, 1597 hour12: {writable: true},
1600 hour: {writable: true}, 1598 hour: {writable: true},
1601 locale: {writable: true}, 1599 locale: {writable: true},
1602 minute: {writable: true}, 1600 minute: {writable: true},
1603 month: {writable: true}, 1601 month: {writable: true},
1604 numberingSystem: {writable: true}, 1602 numberingSystem: {writable: true},
1605 [patternSymbol]: {writable: true}, 1603 [patternSymbol]: {writable: true},
1606 pattern: patternAccessor, 1604 pattern: patternAccessor,
1607 requestedLocale: {value: requestedLocale, writable: true}, 1605 requestedLocale: {value: requestedLocale, writable: true},
1608 second: {writable: true}, 1606 second: {writable: true},
1609 timeZone: {writable: true}, 1607 timeZone: {writable: true},
1610 timeZoneName: {writable: true}, 1608 timeZoneName: {writable: true},
1611 tz: {value: tz, writable: true}, 1609 tz: {value: tz, writable: true},
1612 weekday: {writable: true}, 1610 weekday: {writable: true},
1613 year: {writable: true} 1611 year: {writable: true}
1614 }); 1612 });
1615 1613
1616 var formatter = %CreateDateTimeFormat( 1614 var formatter = %CreateDateTimeFormat(
1617 requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved); 1615 requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved);
1618 1616
1619 if (resolved.timeZone === "Etc/Unknown") { 1617 if (resolved.timeZone === "Etc/Unknown") {
1620 throw MakeRangeError(kUnsupportedTimeZone, tz); 1618 throw MakeRangeError(kUnsupportedTimeZone, tz);
1621 } 1619 }
1622 1620
1623 %MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter); 1621 %MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter);
1624 dateFormat[resolvedSymbol] = resolved; 1622 dateFormat[resolvedSymbol] = resolved;
1625 ObjectDefineProperty(dateFormat, 'resolved', resolvedAccessor); 1623 %object_define_property(dateFormat, 'resolved', resolvedAccessor);
1626 1624
1627 return dateFormat; 1625 return dateFormat;
1628 } 1626 }
1629 1627
1630 1628
1631 /** 1629 /**
1632 * Constructs Intl.DateTimeFormat object given optional locales and options 1630 * Constructs Intl.DateTimeFormat object given optional locales and options
1633 * parameters. 1631 * parameters.
1634 * 1632 *
1635 * @constructor 1633 * @constructor
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1819 } 1817 }
1820 1818
1821 var getOption = getGetOption(options, 'breakiterator'); 1819 var getOption = getGetOption(options, 'breakiterator');
1822 1820
1823 var internalOptions = {}; 1821 var internalOptions = {};
1824 1822
1825 defineWEProperty(internalOptions, 'type', getOption( 1823 defineWEProperty(internalOptions, 'type', getOption(
1826 'type', 'string', ['character', 'word', 'sentence', 'line'], 'word')); 1824 'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
1827 1825
1828 var locale = resolveLocale('breakiterator', locales, options); 1826 var locale = resolveLocale('breakiterator', locales, options);
1829 var resolved = ObjectDefineProperties({}, { 1827 var resolved = %object_define_properties({}, {
1830 requestedLocale: {value: locale.locale, writable: true}, 1828 requestedLocale: {value: locale.locale, writable: true},
1831 type: {value: internalOptions.type, writable: true}, 1829 type: {value: internalOptions.type, writable: true},
1832 locale: {writable: true} 1830 locale: {writable: true}
1833 }); 1831 });
1834 1832
1835 var internalIterator = %CreateBreakIterator(locale.locale, 1833 var internalIterator = %CreateBreakIterator(locale.locale,
1836 internalOptions, 1834 internalOptions,
1837 resolved); 1835 resolved);
1838 1836
1839 %MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator', 1837 %MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator',
1840 internalIterator); 1838 internalIterator);
1841 iterator[resolvedSymbol] = resolved; 1839 iterator[resolvedSymbol] = resolved;
1842 ObjectDefineProperty(iterator, 'resolved', resolvedAccessor); 1840 %object_define_property(iterator, 'resolved', resolvedAccessor);
1843 1841
1844 return iterator; 1842 return iterator;
1845 } 1843 }
1846 1844
1847 1845
1848 /** 1846 /**
1849 * Constructs Intl.v8BreakIterator object given optional locales and options 1847 * Constructs Intl.v8BreakIterator object given optional locales and options
1850 * parameters. 1848 * parameters.
1851 * 1849 *
1852 * @constructor 1850 * @constructor
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
2132 } 2130 }
2133 2131
2134 var locales = arguments[0]; 2132 var locales = arguments[0];
2135 var options = arguments[1]; 2133 var options = arguments[1];
2136 return toLocaleDateTime( 2134 return toLocaleDateTime(
2137 this, locales, options, 'time', 'time', 'dateformattime'); 2135 this, locales, options, 'time', 'time', 'dateformattime');
2138 } 2136 }
2139 ); 2137 );
2140 2138
2141 }) 2139 })
OLDNEW
« no previous file with comments | « src/js/array.js ('k') | src/js/messages.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698