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

Side by Side Diff: test/mjsunit/es6/classes-subclass-builtins.js

Issue 1479233002: Deprecate the %IsConstructCall intrinsic completely. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@local_js-use-new-target-3
Patch Set: Rebased. Created 5 years 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/runtime/runtime-function.cc ('k') | test/mjsunit/regress/regress-1229.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 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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 // Flags: --allow-natives-syntax --harmony-reflect --harmony-regexp-subclass 5 // Flags: --allow-natives-syntax --harmony-reflect --harmony-regexp-subclass
6 // Flags: --expose-gc 6 // Flags: --expose-gc
7 7
8 "use strict"; 8 "use strict";
9 9
10 10
11 function checkPrototypeChain(object, constructors) { 11 function checkPrototypeChain(object, constructors) {
12 var proto = object.__proto__; 12 var proto = object.__proto__;
13 for (var i = 0; i < constructors.length; i++) { 13 for (var i = 0; i < constructors.length; i++) {
14 assertEquals(constructors[i].prototype, proto); 14 assertEquals(constructors[i].prototype, proto);
15 assertEquals(constructors[i], proto.constructor); 15 assertEquals(constructors[i], proto.constructor);
16 proto = proto.__proto__; 16 proto = proto.__proto__;
17 } 17 }
18 } 18 }
19 19
20 20
21 (function() { 21 (function() {
22 class A extends Object { 22 class A extends Object {
23 constructor(...args) { 23 constructor(...args) {
24 assertTrue(%IsConstructCall()); 24 assertFalse(new.target === undefined);
25 super(...args); 25 super(...args);
26 this.a = 42; 26 this.a = 42;
27 this.d = 4.2; 27 this.d = 4.2;
28 this.o = {foo:153}; 28 this.o = {foo:153};
29 } 29 }
30 } 30 }
31 31
32 var s = new A("foo"); 32 var s = new A("foo");
33 assertTrue(s instanceof Object); 33 assertTrue(s instanceof Object);
34 assertTrue(s instanceof A); 34 assertTrue(s instanceof A);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 assertTrue(%HaveSameMap(b, b1)); 69 assertTrue(%HaveSameMap(b, b1));
70 assertTrue(%HaveSameMap(b, s)); 70 assertTrue(%HaveSameMap(b, s));
71 71
72 gc(); 72 gc();
73 })(); 73 })();
74 74
75 75
76 (function() { 76 (function() {
77 class A extends Function { 77 class A extends Function {
78 constructor(...args) { 78 constructor(...args) {
79 assertTrue(%IsConstructCall()); 79 assertFalse(new.target === undefined);
80 super(...args); 80 super(...args);
81 this.a = 42; 81 this.a = 42;
82 this.d = 4.2; 82 this.d = 4.2;
83 this.o = {foo:153}; 83 this.o = {foo:153};
84 } 84 }
85 } 85 }
86 86
87 var o = new A("this.foo = 113;"); 87 var o = new A("this.foo = 113;");
88 assertTrue(o instanceof Object); 88 assertTrue(o instanceof Object);
89 assertTrue(o instanceof Function); 89 assertTrue(o instanceof Function);
90 assertTrue(o instanceof A); 90 assertTrue(o instanceof A);
91 assertEquals("function", typeof o); 91 assertEquals("function", typeof o);
92 checkPrototypeChain(o, [A, Function, Object]); 92 checkPrototypeChain(o, [A, Function, Object]);
93 assertEquals(42, o.a); 93 assertEquals(42, o.a);
94 assertEquals(4.2, o.d); 94 assertEquals(4.2, o.d);
95 assertEquals(153, o.o.foo); 95 assertEquals(153, o.o.foo);
96 var oo = new o(); 96 var oo = new o();
97 assertEquals(113, oo.foo); 97 assertEquals(113, oo.foo);
98 98
99 var o1 = new A("return 312;"); 99 var o1 = new A("return 312;");
100 assertTrue(%HaveSameMap(o, o1)); 100 assertTrue(%HaveSameMap(o, o1));
101 101
102 gc(); 102 gc();
103 })(); 103 })();
104 104
105 105
106 (function() { 106 (function() {
107 class A extends Boolean { 107 class A extends Boolean {
108 constructor(...args) { 108 constructor(...args) {
109 assertTrue(%IsConstructCall()); 109 assertFalse(new.target === undefined);
110 super(...args); 110 super(...args);
111 this.a = 42; 111 this.a = 42;
112 this.d = 4.2; 112 this.d = 4.2;
113 this.o = {foo:153}; 113 this.o = {foo:153};
114 } 114 }
115 } 115 }
116 116
117 var o = new A(true); 117 var o = new A(true);
118 assertTrue(o instanceof Object); 118 assertTrue(o instanceof Object);
119 assertTrue(o instanceof Boolean); 119 assertTrue(o instanceof Boolean);
120 assertTrue(o instanceof A); 120 assertTrue(o instanceof A);
121 assertEquals("object", typeof o); 121 assertEquals("object", typeof o);
122 checkPrototypeChain(o, [A, Boolean]); 122 checkPrototypeChain(o, [A, Boolean]);
123 assertTrue(o.valueOf()); 123 assertTrue(o.valueOf());
124 assertEquals(42, o.a); 124 assertEquals(42, o.a);
125 assertEquals(4.2, o.d); 125 assertEquals(4.2, o.d);
126 assertEquals(153, o.o.foo); 126 assertEquals(153, o.o.foo);
127 127
128 var o1 = new A(false); 128 var o1 = new A(false);
129 assertTrue(%HaveSameMap(o, o1)); 129 assertTrue(%HaveSameMap(o, o1));
130 130
131 gc(); 131 gc();
132 })(); 132 })();
133 133
134 134
135 function TestErrorSubclassing(error) { 135 function TestErrorSubclassing(error) {
136 class A extends error { 136 class A extends error {
137 constructor(...args) { 137 constructor(...args) {
138 assertTrue(%IsConstructCall()); 138 assertFalse(new.target === undefined);
139 super(...args); 139 super(...args);
140 this.a = 42; 140 this.a = 42;
141 this.d = 4.2; 141 this.d = 4.2;
142 this.o = {foo:153}; 142 this.o = {foo:153};
143 } 143 }
144 } 144 }
145 145
146 var o = new A("message"); 146 var o = new A("message");
147 assertTrue(o instanceof Object); 147 assertTrue(o instanceof Object);
148 assertTrue(o instanceof error); 148 assertTrue(o instanceof error);
(...skipping 25 matching lines...) Expand all
174 TestErrorSubclassing(ReferenceError); 174 TestErrorSubclassing(ReferenceError);
175 TestErrorSubclassing(SyntaxError); 175 TestErrorSubclassing(SyntaxError);
176 TestErrorSubclassing(TypeError); 176 TestErrorSubclassing(TypeError);
177 TestErrorSubclassing(URIError); 177 TestErrorSubclassing(URIError);
178 })(); 178 })();
179 179
180 180
181 (function() { 181 (function() {
182 class A extends Number { 182 class A extends Number {
183 constructor(...args) { 183 constructor(...args) {
184 assertTrue(%IsConstructCall()); 184 assertFalse(new.target === undefined);
185 super(...args); 185 super(...args);
186 this.a = 42; 186 this.a = 42;
187 this.d = 4.2; 187 this.d = 4.2;
188 this.o = {foo:153}; 188 this.o = {foo:153};
189 } 189 }
190 } 190 }
191 191
192 var o = new A(153); 192 var o = new A(153);
193 assertTrue(o instanceof Object); 193 assertTrue(o instanceof Object);
194 assertTrue(o instanceof Number); 194 assertTrue(o instanceof Number);
195 assertTrue(o instanceof A); 195 assertTrue(o instanceof A);
196 assertEquals("object", typeof o); 196 assertEquals("object", typeof o);
197 checkPrototypeChain(o, [A, Number, Object]); 197 checkPrototypeChain(o, [A, Number, Object]);
198 assertEquals(153, o.valueOf()); 198 assertEquals(153, o.valueOf());
199 assertEquals(42, o.a); 199 assertEquals(42, o.a);
200 assertEquals(4.2, o.d); 200 assertEquals(4.2, o.d);
201 assertEquals(153, o.o.foo); 201 assertEquals(153, o.o.foo);
202 202
203 var o1 = new A(312); 203 var o1 = new A(312);
204 assertTrue(%HaveSameMap(o, o1)); 204 assertTrue(%HaveSameMap(o, o1));
205 205
206 gc(); 206 gc();
207 })(); 207 })();
208 208
209 209
210 (function() { 210 (function() {
211 class A extends Date { 211 class A extends Date {
212 constructor(...args) { 212 constructor(...args) {
213 assertTrue(%IsConstructCall()); 213 assertFalse(new.target === undefined);
214 super(...args); 214 super(...args);
215 this.a = 42; 215 this.a = 42;
216 this.d = 4.2; 216 this.d = 4.2;
217 this.o = {foo:153}; 217 this.o = {foo:153};
218 } 218 }
219 } 219 }
220 220
221 var o = new A(1234567890); 221 var o = new A(1234567890);
222 assertTrue(o instanceof Object); 222 assertTrue(o instanceof Object);
223 assertTrue(o instanceof Date); 223 assertTrue(o instanceof Date);
(...skipping 11 matching lines...) Expand all
235 assertEquals(29, o1.getDate()); 235 assertEquals(29, o1.getDate());
236 assertTrue(%HaveSameMap(o, o1)); 236 assertTrue(%HaveSameMap(o, o1));
237 237
238 gc(); 238 gc();
239 })(); 239 })();
240 240
241 241
242 (function() { 242 (function() {
243 class A extends String { 243 class A extends String {
244 constructor(...args) { 244 constructor(...args) {
245 assertTrue(%IsConstructCall()); 245 assertFalse(new.target === undefined);
246 super(...args); 246 super(...args);
247 this.a = 42; 247 this.a = 42;
248 this.d = 4.2; 248 this.d = 4.2;
249 this.o = {foo:153}; 249 this.o = {foo:153};
250 } 250 }
251 } 251 }
252 252
253 var o = new A("foo"); 253 var o = new A("foo");
254 assertTrue(o instanceof Object); 254 assertTrue(o instanceof Object);
255 assertTrue(o instanceof String); 255 assertTrue(o instanceof String);
256 assertTrue(o instanceof A); 256 assertTrue(o instanceof A);
257 assertEquals("object", typeof o); 257 assertEquals("object", typeof o);
258 checkPrototypeChain(o, [A, String, Object]); 258 checkPrototypeChain(o, [A, String, Object]);
259 259
260 assertEquals("foo", o.valueOf()); 260 assertEquals("foo", o.valueOf());
261 assertEquals(42, o.a); 261 assertEquals(42, o.a);
262 assertEquals(4.2, o.d); 262 assertEquals(4.2, o.d);
263 assertEquals(153, o.o.foo); 263 assertEquals(153, o.o.foo);
264 264
265 var o1 = new A("bar"); 265 var o1 = new A("bar");
266 assertTrue(%HaveSameMap(o, o1)); 266 assertTrue(%HaveSameMap(o, o1));
267 267
268 gc(); 268 gc();
269 })(); 269 })();
270 270
271 271
272 (function() { 272 (function() {
273 class A extends RegExp { 273 class A extends RegExp {
274 constructor(...args) { 274 constructor(...args) {
275 assertTrue(%IsConstructCall()); 275 assertFalse(new.target === undefined);
276 super(...args); 276 super(...args);
277 this.a = 42; 277 this.a = 42;
278 this.d = 4.2; 278 this.d = 4.2;
279 this.o = {foo:153}; 279 this.o = {foo:153};
280 } 280 }
281 } 281 }
282 282
283 var o = new A("o(..)h", "g"); 283 var o = new A("o(..)h", "g");
284 assertTrue(o instanceof Object); 284 assertTrue(o instanceof Object);
285 assertTrue(o instanceof RegExp); 285 assertTrue(o instanceof RegExp);
(...skipping 14 matching lines...) Expand all
300 var o1 = new A(7); 300 var o1 = new A(7);
301 assertTrue(%HaveSameMap(o, o1)); 301 assertTrue(%HaveSameMap(o, o1));
302 302
303 gc(); 303 gc();
304 })(); 304 })();
305 305
306 306
307 function TestArraySubclassing(array) { 307 function TestArraySubclassing(array) {
308 class A extends array { 308 class A extends array {
309 constructor(...args) { 309 constructor(...args) {
310 assertTrue(%IsConstructCall()); 310 assertFalse(new.target === undefined);
311 super(...args); 311 super(...args);
312 this.a = 42; 312 this.a = 42;
313 this.d = 4.2; 313 this.d = 4.2;
314 this.o = {foo:153}; 314 this.o = {foo:153};
315 } 315 }
316 } 316 }
317 317
318 var o = new array(13); 318 var o = new array(13);
319 assertTrue(o instanceof Object); 319 assertTrue(o instanceof Object);
320 assertTrue(o instanceof array); 320 assertTrue(o instanceof array);
(...skipping 29 matching lines...) Expand all
350 TestArraySubclassing(Float32Array); 350 TestArraySubclassing(Float32Array);
351 TestArraySubclassing(Float64Array); 351 TestArraySubclassing(Float64Array);
352 })(); 352 })();
353 353
354 354
355 function TestMapSetSubclassing(container, is_map) { 355 function TestMapSetSubclassing(container, is_map) {
356 var keys = [{name: "banana"}, {name: "cow"}, {name: "orange"}, {name: "chicken "}, {name: "apple"}]; 356 var keys = [{name: "banana"}, {name: "cow"}, {name: "orange"}, {name: "chicken "}, {name: "apple"}];
357 357
358 class A extends container { 358 class A extends container {
359 constructor(...args) { 359 constructor(...args) {
360 assertTrue(%IsConstructCall()); 360 assertFalse(new.target === undefined);
361 super(...args); 361 super(...args);
362 this.a = 42; 362 this.a = 42;
363 this.d = 4.2; 363 this.d = 4.2;
364 this.o = {foo:153}; 364 this.o = {foo:153};
365 } 365 }
366 } 366 }
367 367
368 var o = new A(); 368 var o = new A();
369 assertTrue(o instanceof Object); 369 assertTrue(o instanceof Object);
370 assertTrue(o instanceof container); 370 assertTrue(o instanceof container);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 TestMapSetSubclassing(Map, true); 409 TestMapSetSubclassing(Map, true);
410 TestMapSetSubclassing(WeakMap, true); 410 TestMapSetSubclassing(WeakMap, true);
411 TestMapSetSubclassing(Set, false); 411 TestMapSetSubclassing(Set, false);
412 TestMapSetSubclassing(WeakSet, false); 412 TestMapSetSubclassing(WeakSet, false);
413 })(); 413 })();
414 414
415 415
416 (function() { 416 (function() {
417 class A extends ArrayBuffer { 417 class A extends ArrayBuffer {
418 constructor(...args) { 418 constructor(...args) {
419 assertTrue(%IsConstructCall()); 419 assertFalse(new.target === undefined);
420 super(...args); 420 super(...args);
421 this.a = 42; 421 this.a = 42;
422 this.d = 4.2; 422 this.d = 4.2;
423 this.o = {foo:153}; 423 this.o = {foo:153};
424 } 424 }
425 } 425 }
426 426
427 var o = new A(16); 427 var o = new A(16);
428 assertTrue(o instanceof Object); 428 assertTrue(o instanceof Object);
429 assertTrue(o instanceof ArrayBuffer); 429 assertTrue(o instanceof ArrayBuffer);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 assertEquals(0xfffffffe, uint32view[0]); 467 assertEquals(0xfffffffe, uint32view[0]);
468 assertEquals(0xffffffff, uint32view[1]); 468 assertEquals(0xffffffff, uint32view[1]);
469 469
470 gc(); 470 gc();
471 })(); 471 })();
472 472
473 473
474 (function() { 474 (function() {
475 class A extends DataView { 475 class A extends DataView {
476 constructor(...args) { 476 constructor(...args) {
477 assertTrue(%IsConstructCall()); 477 assertFalse(new.target === undefined);
478 super(...args); 478 super(...args);
479 this.a = 42; 479 this.a = 42;
480 this.d = 4.2; 480 this.d = 4.2;
481 this.o = {foo:153}; 481 this.o = {foo:153};
482 } 482 }
483 } 483 }
484 484
485 var buffer = new ArrayBuffer(16); 485 var buffer = new ArrayBuffer(16);
486 var o = new A(buffer); 486 var o = new A(buffer);
487 assertTrue(o instanceof Object); 487 assertTrue(o instanceof Object);
(...skipping 14 matching lines...) Expand all
502 502
503 gc(); 503 gc();
504 })(); 504 })();
505 505
506 506
507 (function() { 507 (function() {
508 // TODO(ishell): remove once GeneratorFunction is available. 508 // TODO(ishell): remove once GeneratorFunction is available.
509 var GeneratorFunction = (function*() {}).__proto__.constructor; 509 var GeneratorFunction = (function*() {}).__proto__.constructor;
510 class A extends GeneratorFunction { 510 class A extends GeneratorFunction {
511 constructor(...args) { 511 constructor(...args) {
512 assertTrue(%IsConstructCall()); 512 assertFalse(new.target === undefined);
513 super(...args); 513 super(...args);
514 this.a = 42; 514 this.a = 42;
515 this.d = 4.2; 515 this.d = 4.2;
516 this.o = {foo:153}; 516 this.o = {foo:153};
517 } 517 }
518 } 518 }
519 var generator_func = new A("var index = 0; while (index < 5) { yield ++index; }"); 519 var generator_func = new A("var index = 0; while (index < 5) { yield ++index; }");
520 assertTrue(generator_func instanceof Object); 520 assertTrue(generator_func instanceof Object);
521 assertTrue(generator_func instanceof Function); 521 assertTrue(generator_func instanceof Function);
522 assertTrue(generator_func instanceof GeneratorFunction); 522 assertTrue(generator_func instanceof GeneratorFunction);
(...skipping 19 matching lines...) Expand all
542 var generator_func1 = new A("return 0;"); 542 var generator_func1 = new A("return 0;");
543 assertTrue(%HaveSameMap(generator_func, generator_func1)); 543 assertTrue(%HaveSameMap(generator_func, generator_func1));
544 544
545 gc(); 545 gc();
546 })(); 546 })();
547 547
548 548
549 (function() { 549 (function() {
550 class A extends Promise { 550 class A extends Promise {
551 constructor(...args) { 551 constructor(...args) {
552 assertTrue(%IsConstructCall()); 552 assertFalse(new.target === undefined);
553 super(...args); 553 super(...args);
554 this.a = 42; 554 this.a = 42;
555 this.d = 4.2; 555 this.d = 4.2;
556 this.o = {foo:153}; 556 this.o = {foo:153};
557 } 557 }
558 } 558 }
559 559
560 var o = new A(function(resolve, reject) { 560 var o = new A(function(resolve, reject) {
561 resolve("ok"); 561 resolve("ok");
562 }); 562 });
(...skipping 19 matching lines...) Expand all
582 .catch(function(reason) { %AbortJS("catch handler called: " + reason); }); 582 .catch(function(reason) { %AbortJS("catch handler called: " + reason); });
583 assertTrue(%HaveSameMap(o, o1)); 583 assertTrue(%HaveSameMap(o, o1));
584 584
585 gc(); 585 gc();
586 })(); 586 })();
587 587
588 588
589 (function() { 589 (function() {
590 class A extends Boolean { 590 class A extends Boolean {
591 constructor() { 591 constructor() {
592 assertTrue(%IsConstructCall()); 592 assertFalse(new.target === undefined);
593 super(true); 593 super(true);
594 this.a00 = 0 594 this.a00 = 0
595 this.a01 = 0 595 this.a01 = 0
596 this.a02 = 0 596 this.a02 = 0
597 this.a03 = 0 597 this.a03 = 0
598 this.a04 = 0 598 this.a04 = 0
599 this.a05 = 0 599 this.a05 = 0
600 this.a06 = 0 600 this.a06 = 0
601 this.a07 = 0 601 this.a07 = 0
602 this.a08 = 0 602 this.a08 = 0
603 this.a09 = 0 603 this.a09 = 0
604 this.a10 = 0 604 this.a10 = 0
605 this.a11 = 0 605 this.a11 = 0
606 this.a12 = 0 606 this.a12 = 0
607 this.a13 = 0 607 this.a13 = 0
608 this.a14 = 0 608 this.a14 = 0
609 this.a15 = 0 609 this.a15 = 0
610 this.a16 = 0 610 this.a16 = 0
611 this.a17 = 0 611 this.a17 = 0
612 this.a18 = 0 612 this.a18 = 0
613 this.a19 = 0 613 this.a19 = 0
614 } 614 }
615 } 615 }
616 616
617 class B extends A { 617 class B extends A {
618 constructor() { 618 constructor() {
619 assertTrue(%IsConstructCall()); 619 assertFalse(new.target === undefined);
620 super(); 620 super();
621 this.b00 = 0 621 this.b00 = 0
622 this.b01 = 0 622 this.b01 = 0
623 this.b02 = 0 623 this.b02 = 0
624 this.b03 = 0 624 this.b03 = 0
625 this.b04 = 0 625 this.b04 = 0
626 this.b05 = 0 626 this.b05 = 0
627 this.b06 = 0 627 this.b06 = 0
628 this.b07 = 0 628 this.b07 = 0
629 this.b08 = 0 629 this.b08 = 0
630 this.b09 = 0 630 this.b09 = 0
631 this.b10 = 0 631 this.b10 = 0
632 this.b11 = 0 632 this.b11 = 0
633 this.b12 = 0 633 this.b12 = 0
634 this.b13 = 0 634 this.b13 = 0
635 this.b14 = 0 635 this.b14 = 0
636 this.b15 = 0 636 this.b15 = 0
637 this.b16 = 0 637 this.b16 = 0
638 this.b17 = 0 638 this.b17 = 0
639 this.b18 = 0 639 this.b18 = 0
640 this.b19 = 0 640 this.b19 = 0
641 } 641 }
642 } 642 }
643 643
644 class C extends B { 644 class C extends B {
645 constructor() { 645 constructor() {
646 assertTrue(%IsConstructCall()); 646 assertFalse(new.target === undefined);
647 super(); 647 super();
648 this.c00 = 0 648 this.c00 = 0
649 this.c01 = 0 649 this.c01 = 0
650 this.c02 = 0 650 this.c02 = 0
651 this.c03 = 0 651 this.c03 = 0
652 this.c04 = 0 652 this.c04 = 0
653 this.c05 = 0 653 this.c05 = 0
654 this.c06 = 0 654 this.c06 = 0
655 this.c07 = 0 655 this.c07 = 0
656 this.c08 = 0 656 this.c08 = 0
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 821
822 Object.defineProperty(pattern, Symbol.match, { 822 Object.defineProperty(pattern, Symbol.match, {
823 get() { log.push("match"); f.prototype = p2; return false; }}); 823 get() { log.push("match"); f.prototype = p2; return false; }});
824 824
825 var o = Reflect.construct(RegExp, [pattern], f); 825 var o = Reflect.construct(RegExp, [pattern], f);
826 assertEquals(["match", "tostring"], log); 826 assertEquals(["match", "tostring"], log);
827 assertEquals(/biep/, o); 827 assertEquals(/biep/, o);
828 assertTrue(o.__proto__ === p2); 828 assertTrue(o.__proto__ === p2);
829 assertTrue(f.prototype === p3); 829 assertTrue(f.prototype === p3);
830 })(); 830 })();
OLDNEW
« no previous file with comments | « src/runtime/runtime-function.cc ('k') | test/mjsunit/regress/regress-1229.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698