Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /// Debugger custom formatter tests. | 1 /// Debugger custom formatter tests. |
| 2 /// If the tests fail, paste the expected output into the [expectedGolden] | 2 /// If the tests fail, paste the expected output into the [expectedGolden] |
| 3 /// string literal in this file and audit the diff to ensure changes are | 3 /// string literal in this file and audit the diff to ensure changes are |
| 4 /// expected. | 4 /// expected. |
| 5 /// | 5 /// |
| 6 /// Currently only DDC supports debugging objects with custom formatters | 6 /// Currently only DDC supports debugging objects with custom formatters |
| 7 /// but it is reasonable to add support to Dart2JS in the future. | 7 /// but it is reasonable to add support to Dart2JS in the future. |
| 8 @JS() | 8 @JS() |
| 9 library debugger_test; | 9 library debugger_test; |
| 10 | 10 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 List get devtoolsFormatters => _devtoolsFormatters; | 55 List get devtoolsFormatters => _devtoolsFormatters; |
| 56 | 56 |
| 57 @JS('JSON.stringify') | 57 @JS('JSON.stringify') |
| 58 external stringify(value, [Function replacer, int space]); | 58 external stringify(value, [Function replacer, int space]); |
| 59 | 59 |
| 60 // TODO(jacobr): this is only valid if the legacy library loader is used. | 60 // TODO(jacobr): this is only valid if the legacy library loader is used. |
| 61 // We need a solution that works with all library loaders. | 61 // We need a solution that works with all library loaders. |
| 62 @JS('dart_library.import') | 62 @JS('dart_library.import') |
| 63 external importDartLibrary(String path); | 63 external importDartLibrary(String path); |
| 64 | 64 |
| 65 @JS('ExampleJSClass') | |
| 66 class ExampleJSClass<T> { | |
| 67 external factory ExampleJSClass(T x); | |
| 68 external T get x; | |
| 69 } | |
| 70 | |
| 65 // Replacer normalizes file names that could vary depending on the test runner. | 71 // Replacer normalizes file names that could vary depending on the test runner. |
| 66 // styles. | 72 // styles. |
| 67 replacer(String key, value) { | 73 replacer(String key, value) { |
| 68 // The values for keys with name 'object' may be arbitrary Dart nested | 74 // The values for keys with name 'object' may be arbitrary Dart nested |
| 69 // Objects so are not safe to stringify. | 75 // Objects so are not safe to stringify. |
| 70 if (key == 'object') return '<OBJECT>'; | 76 if (key == 'object') return '<OBJECT>'; |
| 71 if (value is String) { | 77 if (value is String) { |
| 72 if (value.contains('dart_sdk.js')) return '<DART_SDK>'; | 78 if (value.contains('dart_sdk.js')) return '<DART_SDK>'; |
| 73 if (new RegExp(r'[.](js|dart|html)').hasMatch(value)) return '<FILE>'; | 79 if (new RegExp(r'[.](js|dart|html)').hasMatch(value)) return '<FILE>'; |
| 74 } | 80 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 ret.addAll(extractNestedFormattedObjects(js_util.getProperty(json, name))); | 116 ret.addAll(extractNestedFormattedObjects(js_util.getProperty(json, name))); |
| 111 } | 117 } |
| 112 return ret; | 118 return ret; |
| 113 } | 119 } |
| 114 | 120 |
| 115 main() { | 121 main() { |
| 116 if (devtoolsFormatters == null) { | 122 if (devtoolsFormatters == null) { |
| 117 print("Warning: no devtools custom formatters specified. Skipping tests."); | 123 print("Warning: no devtools custom formatters specified. Skipping tests."); |
| 118 return; | 124 return; |
| 119 } | 125 } |
| 126 document.body.append(new ScriptElement() | |
| 127 ..type = 'text/javascript' | |
| 128 ..innerHtml = r""" | |
| 129 window.ExampleJSClass = function ExampleJSClass(x) { | |
| 130 this.x = x; | |
| 131 }; | |
| 132 """); | |
| 133 | |
| 120 var _devtoolsFormatter = devtoolsFormatters.first; | 134 var _devtoolsFormatter = devtoolsFormatters.first; |
| 121 | 135 |
| 122 var actual = new StringBuffer(); | 136 var actual = new StringBuffer(); |
| 123 | 137 |
| 124 // Accumulate the entire expected custom formatted data as a single | 138 // Accumulate the entire expected custom formatted data as a single |
| 125 // massive string buffer so it is simple to update expectations when | 139 // massive string buffer so it is simple to update expectations when |
| 126 // modifying the formatting code. | 140 // modifying the formatting code. |
| 127 // Otherwise a small formatting change would result in tweaking lots | 141 // Otherwise a small formatting change would result in tweaking lots |
| 128 // of expectations. | 142 // of expectations. |
| 129 // The verify golden match test cases does the final comparison of golden | 143 // The verify golden match test cases does the final comparison of golden |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 271 }); | 285 }); |
| 272 }); | 286 }); |
| 273 | 287 |
| 274 group('Class formatting', () { | 288 group('Class formatting', () { |
| 275 addNestedFormatterGoldens('TestClass', new TestClass(17)); | 289 addNestedFormatterGoldens('TestClass', new TestClass(17)); |
| 276 addNestedFormatterGoldens('MouseEvent', new MouseEvent("click")); | 290 addNestedFormatterGoldens('MouseEvent', new MouseEvent("click")); |
| 277 // This is a good class to test as it has statics and a deep inheritance hei rarchy | 291 // This is a good class to test as it has statics and a deep inheritance hei rarchy |
| 278 addNestedFormatterGoldens('HttpRequest', new HttpRequest()); | 292 addNestedFormatterGoldens('HttpRequest', new HttpRequest()); |
| 279 }); | 293 }); |
| 280 | 294 |
| 295 group('Generics formatting', () { | |
| 296 addNestedFormatterGoldens( | |
| 297 'TestGenericClass', new TestGenericClass<int, List>(42)); | |
| 298 addNestedFormatterGoldens( | |
| 299 'TestGenericClassJSInterop', | |
| 300 new TestGenericClass<ExampleJSClass<String>, int>( | |
| 301 new ExampleJSClass("Hello"))); | |
| 302 }); | |
| 303 | |
| 281 test('verify golden match', () { | 304 test('verify golden match', () { |
| 282 // Warning: all other test groups must have run for this test to be meaningf ul | 305 // Warning: all other test groups must have run for this test to be meaningf ul |
| 283 print("Actual:##############\n$actual\n#################"); | 306 print("Actual:##############\n$actual\n#################"); |
| 284 | 307 |
| 285 expect(actual.toString().trim(), equals(expectedGolden().trim())); | 308 expect(actual.toString().trim(), equals(expectedGolden().trim())); |
| 286 }); | 309 }); |
| 287 } | 310 } |
| 288 | 311 |
| 289 /// The golden custom formatter output is placed at the bottom of the file | 312 /// The golden custom formatter output is placed at the bottom of the file |
| 290 /// to simplify replacing the golden data when the custom formatter code is | 313 /// to simplify replacing the golden data when the custom formatter code is |
| (...skipping 1554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1845 [ | 1868 [ |
| 1846 "li", | 1869 "li", |
| 1847 { | 1870 { |
| 1848 "style": "padding-left: 13px;" | 1871 "style": "padding-left: 13px;" |
| 1849 }, | 1872 }, |
| 1850 [ | 1873 [ |
| 1851 "span", | 1874 "span", |
| 1852 { | 1875 { |
| 1853 "style": "color: rgb(136, 19, 145); margin-right: -13px" | 1876 "style": "color: rgb(136, 19, 145); margin-right: -13px" |
| 1854 }, | 1877 }, |
| 1878 "toString: " | |
| 1879 ], | |
| 1880 [ | |
| 1881 "span", | |
| 1882 { | |
| 1883 "style": "margin-left: 13px" | |
| 1884 }, | |
| 1885 [ | |
| 1886 "object", | |
| 1887 { | |
| 1888 "object": "<OBJECT>", | |
| 1889 "config": { | |
| 1890 "name": "none" | |
| 1891 } | |
| 1892 } | |
| 1893 ] | |
| 1894 ] | |
| 1895 ], | |
| 1896 [ | |
| 1897 "li", | |
| 1898 { | |
| 1899 "style": "padding-left: 13px;" | |
| 1900 }, | |
| 1901 [ | |
| 1902 "span", | |
| 1903 { | |
| 1904 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 1905 }, | |
| 1855 "where: " | 1906 "where: " |
| 1856 ], | 1907 ], |
| 1857 [ | 1908 [ |
| 1858 "span", | 1909 "span", |
| 1859 { | 1910 { |
| 1860 "style": "margin-left: 13px" | 1911 "style": "margin-left: 13px" |
| 1861 }, | 1912 }, |
| 1862 [ | 1913 [ |
| 1863 "object", | 1914 "object", |
| 1864 { | 1915 { |
| (...skipping 1522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3387 [ | 3438 [ |
| 3388 "li", | 3439 "li", |
| 3389 { | 3440 { |
| 3390 "style": "padding-left: 13px;" | 3441 "style": "padding-left: 13px;" |
| 3391 }, | 3442 }, |
| 3392 [ | 3443 [ |
| 3393 "span", | 3444 "span", |
| 3394 { | 3445 { |
| 3395 "style": "color: rgb(136, 19, 145); margin-right: -13px" | 3446 "style": "color: rgb(136, 19, 145); margin-right: -13px" |
| 3396 }, | 3447 }, |
| 3448 "toString: " | |
| 3449 ], | |
| 3450 [ | |
| 3451 "span", | |
| 3452 { | |
| 3453 "style": "margin-left: 13px" | |
| 3454 }, | |
| 3455 [ | |
| 3456 "object", | |
| 3457 { | |
| 3458 "object": "<OBJECT>", | |
| 3459 "config": { | |
| 3460 "name": "none" | |
| 3461 } | |
| 3462 } | |
| 3463 ] | |
| 3464 ] | |
| 3465 ], | |
| 3466 [ | |
| 3467 "li", | |
| 3468 { | |
| 3469 "style": "padding-left: 13px;" | |
| 3470 }, | |
| 3471 [ | |
| 3472 "span", | |
| 3473 { | |
| 3474 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 3475 }, | |
| 3397 "where: " | 3476 "where: " |
| 3398 ], | 3477 ], |
| 3399 [ | 3478 [ |
| 3400 "span", | 3479 "span", |
| 3401 { | 3480 { |
| 3402 "style": "margin-left: 13px" | 3481 "style": "margin-left: 13px" |
| 3403 }, | 3482 }, |
| 3404 [ | 3483 [ |
| 3405 "object", | 3484 "object", |
| 3406 { | 3485 { |
| (...skipping 1389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4796 ] | 4875 ] |
| 4797 ] | 4876 ] |
| 4798 ----------------------------------- | 4877 ----------------------------------- |
| 4799 Test: Map<dynamic, dynamic> instance header | 4878 Test: Map<dynamic, dynamic> instance header |
| 4800 Value: | 4879 Value: |
| 4801 [ | 4880 [ |
| 4802 "span", | 4881 "span", |
| 4803 { | 4882 { |
| 4804 "style": "background-color: #d9edf7;" | 4883 "style": "background-color: #d9edf7;" |
| 4805 }, | 4884 }, |
| 4806 "JsLinkedHashMap<Object, Object> length 3" | 4885 "JsLinkedHashMap length 3" |
| 4807 ] | 4886 ] |
| 4808 ----------------------------------- | 4887 ----------------------------------- |
| 4809 Test: Map<dynamic, dynamic> instance body | 4888 Test: Map<dynamic, dynamic> instance body |
| 4810 Value: | 4889 Value: |
| 4811 [ | 4890 [ |
| 4812 "ol", | 4891 "ol", |
| 4813 { | 4892 { |
| 4814 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" | 4893 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" |
| 4815 }, | 4894 }, |
| 4816 [ | 4895 [ |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4927 ] | 5006 ] |
| 4928 ] | 5007 ] |
| 4929 ----------------------------------- | 5008 ----------------------------------- |
| 4930 Test: Map<dynamic, dynamic> definition formatting header | 5009 Test: Map<dynamic, dynamic> definition formatting header |
| 4931 Value: | 5010 Value: |
| 4932 [ | 5011 [ |
| 4933 "span", | 5012 "span", |
| 4934 { | 5013 { |
| 4935 "style": "background-color: #d9edf7;" | 5014 "style": "background-color: #d9edf7;" |
| 4936 }, | 5015 }, |
| 4937 "JsLinkedHashMap<Object, Object> implements LinkedHashMap<Object, Object>, I nternalMap<Object, Object>" | 5016 "JsLinkedHashMap implements LinkedHashMap, InternalMap" |
| 4938 ] | 5017 ] |
| 4939 ----------------------------------- | 5018 ----------------------------------- |
| 4940 Test: Map<dynamic, dynamic> definition formatting body | 5019 Test: Map<dynamic, dynamic> definition formatting body |
| 4941 Value: | 5020 Value: |
| 4942 [ | 5021 [ |
| 4943 "ol", | 5022 "ol", |
| 4944 { | 5023 { |
| 4945 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" | 5024 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" |
| 4946 }, | 5025 }, |
| 4947 [ | 5026 [ |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5401 [ | 5480 [ |
| 5402 "li", | 5481 "li", |
| 5403 { | 5482 { |
| 5404 "style": "padding-left: 13px;" | 5483 "style": "padding-left: 13px;" |
| 5405 }, | 5484 }, |
| 5406 [ | 5485 [ |
| 5407 "span", | 5486 "span", |
| 5408 { | 5487 { |
| 5409 "style": "color: rgb(136, 19, 145); margin-right: -13px" | 5488 "style": "color: rgb(136, 19, 145); margin-right: -13px" |
| 5410 }, | 5489 }, |
| 5490 "toString: " | |
| 5491 ], | |
| 5492 [ | |
| 5493 "span", | |
| 5494 { | |
| 5495 "style": "margin-left: 13px" | |
| 5496 }, | |
| 5497 [ | |
| 5498 "object", | |
| 5499 { | |
| 5500 "object": "<OBJECT>", | |
| 5501 "config": { | |
| 5502 "name": "none" | |
| 5503 } | |
| 5504 } | |
| 5505 ] | |
| 5506 ] | |
| 5507 ], | |
| 5508 [ | |
| 5509 "li", | |
| 5510 { | |
| 5511 "style": "padding-left: 13px;" | |
| 5512 }, | |
| 5513 [ | |
| 5514 "span", | |
| 5515 { | |
| 5516 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 5517 }, | |
| 5411 "_addHashTableEntry: " | 5518 "_addHashTableEntry: " |
| 5412 ], | 5519 ], |
| 5413 [ | 5520 [ |
| 5414 "span", | 5521 "span", |
| 5415 { | 5522 { |
| 5416 "style": "margin-left: 13px" | 5523 "style": "margin-left: 13px" |
| 5417 }, | 5524 }, |
| 5418 [ | 5525 [ |
| 5419 "object", | 5526 "object", |
| 5420 { | 5527 { |
| (...skipping 3385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8806 "object": "<OBJECT>", | 8913 "object": "<OBJECT>", |
| 8807 "config": { | 8914 "config": { |
| 8808 "name": "asClass" | 8915 "name": "asClass" |
| 8809 } | 8916 } |
| 8810 } | 8917 } |
| 8811 ] | 8918 ] |
| 8812 ] | 8919 ] |
| 8813 ] | 8920 ] |
| 8814 ] | 8921 ] |
| 8815 ----------------------------------- | 8922 ----------------------------------- |
| 8923 Test: TestGenericClass instance header | |
| 8924 Value: | |
| 8925 [ | |
| 8926 "span", | |
| 8927 { | |
| 8928 "style": "background-color: #d9edf7;" | |
| 8929 }, | |
| 8930 "TestGenericClass<int, List>" | |
| 8931 ] | |
| 8932 ----------------------------------- | |
| 8933 Test: TestGenericClass instance body | |
| 8934 Value: | |
| 8935 [ | |
| 8936 "ol", | |
| 8937 { | |
| 8938 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" | |
| 8939 }, | |
| 8940 [ | |
| 8941 "li", | |
| 8942 { | |
| 8943 "style": "padding-left: 13px;" | |
| 8944 }, | |
| 8945 [ | |
| 8946 "span", | |
| 8947 {}, | |
| 8948 [ | |
| 8949 "span", | |
| 8950 { | |
| 8951 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 8952 }, | |
| 8953 "x: " | |
| 8954 ], | |
| 8955 [ | |
| 8956 "span", | |
| 8957 { | |
| 8958 "style": "margin-left: 13px" | |
| 8959 }, | |
| 8960 "42" | |
| 8961 ] | |
| 8962 ] | |
| 8963 ], | |
| 8964 [ | |
| 8965 "li", | |
| 8966 { | |
| 8967 "style": "padding-left: 13px;" | |
| 8968 }, | |
| 8969 [ | |
| 8970 "span", | |
| 8971 { | |
| 8972 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 8973 }, | |
| 8974 "[[class]]: " | |
| 8975 ], | |
| 8976 [ | |
| 8977 "span", | |
| 8978 { | |
| 8979 "style": "margin-left: 13px" | |
| 8980 }, | |
| 8981 [ | |
| 8982 "object", | |
| 8983 { | |
| 8984 "object": "<OBJECT>", | |
| 8985 "config": { | |
| 8986 "name": "asClass" | |
| 8987 } | |
| 8988 } | |
| 8989 ] | |
| 8990 ] | |
| 8991 ] | |
| 8992 ] | |
| 8993 ----------------------------------- | |
| 8994 Test: TestGenericClass definition formatting header | |
| 8995 Value: | |
| 8996 [ | |
| 8997 "span", | |
| 8998 { | |
| 8999 "style": "background-color: #d9edf7;" | |
| 9000 }, | |
| 9001 "TestGenericClass<int, List>" | |
| 9002 ] | |
| 9003 ----------------------------------- | |
| 9004 Test: TestGenericClass definition formatting body | |
| 9005 Value: | |
| 9006 [ | |
| 9007 "ol", | |
| 9008 { | |
| 9009 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" | |
| 9010 }, | |
| 9011 [ | |
| 9012 "li", | |
| 9013 { | |
| 9014 "style": "padding-left: 13px;" | |
| 9015 }, | |
| 9016 [ | |
| 9017 "span", | |
| 9018 { | |
| 9019 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 9020 }, | |
| 9021 "[[base class]]: " | |
| 9022 ], | |
| 9023 [ | |
| 9024 "span", | |
| 9025 { | |
| 9026 "style": "margin-left: 13px" | |
| 9027 }, | |
| 9028 [ | |
| 9029 "object", | |
| 9030 { | |
| 9031 "object": "<OBJECT>", | |
| 9032 "config": { | |
| 9033 "name": "asClass" | |
| 9034 } | |
| 9035 } | |
| 9036 ] | |
| 9037 ] | |
| 9038 ] | |
| 9039 ] | |
| 9040 ----------------------------------- | |
| 9041 Test: TestGenericClassJSInterop instance header | |
| 9042 Value: | |
| 9043 [ | |
| 9044 "span", | |
| 9045 { | |
| 9046 "style": "background-color: #d9edf7;" | |
| 9047 }, | |
| 9048 "TestGenericClass<JSObject<ExampleJSClass>, int>" | |
| 9049 ] | |
| 9050 ----------------------------------- | |
| 9051 Test: TestGenericClassJSInterop instance body | |
| 9052 Value: | |
| 9053 [ | |
| 9054 "ol", | |
| 9055 { | |
| 9056 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" | |
| 9057 }, | |
| 9058 [ | |
| 9059 "li", | |
| 9060 { | |
| 9061 "style": "padding-left: 13px;" | |
| 9062 }, | |
| 9063 [ | |
| 9064 "span", | |
| 9065 { | |
| 9066 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 9067 }, | |
| 9068 "x: " | |
| 9069 ], | |
| 9070 [ | |
| 9071 "span", | |
| 9072 { | |
| 9073 "style": "margin-left: 13px" | |
| 9074 }, | |
| 9075 [ | |
| 9076 "object", | |
| 9077 { | |
| 9078 "object": "<OBJECT>", | |
| 9079 "config": { | |
| 9080 "name": "none" | |
| 9081 } | |
| 9082 } | |
| 9083 ] | |
| 9084 ] | |
| 9085 ], | |
| 9086 [ | |
| 9087 "li", | |
| 9088 { | |
| 9089 "style": "padding-left: 13px;" | |
| 9090 }, | |
| 9091 [ | |
| 9092 "span", | |
| 9093 { | |
| 9094 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 9095 }, | |
| 9096 "[[class]]: " | |
| 9097 ], | |
| 9098 [ | |
| 9099 "span", | |
| 9100 { | |
| 9101 "style": "margin-left: 13px" | |
| 9102 }, | |
| 9103 [ | |
| 9104 "object", | |
| 9105 { | |
| 9106 "object": "<OBJECT>", | |
| 9107 "config": { | |
| 9108 "name": "asClass" | |
| 9109 } | |
| 9110 } | |
| 9111 ] | |
| 9112 ] | |
| 9113 ] | |
| 9114 ] | |
| 9115 ----------------------------------- | |
| 9116 Test: TestGenericClassJSInterop definition formatting header | |
| 9117 Value: | |
| 9118 [ | |
| 9119 "span", | |
| 9120 { | |
| 9121 "style": "background-color: #d9edf7;" | |
| 9122 }, | |
| 9123 "TestGenericClass<JSObject<ExampleJSClass>, int>" | |
| 9124 ] | |
| 9125 ----------------------------------- | |
| 9126 Test: TestGenericClassJSInterop definition formatting body | |
| 9127 Value: | |
| 9128 [ | |
| 9129 "ol", | |
| 9130 { | |
| 9131 "style": "list-style-type: none;padding-left: 0px;margin-top: 0px;margin -bottom: 0px;margin-left: 12px;" | |
| 9132 }, | |
| 9133 [ | |
| 9134 "li", | |
| 9135 { | |
| 9136 "style": "padding-left: 13px;" | |
| 9137 }, | |
| 9138 [ | |
| 9139 "span", | |
| 9140 { | |
| 9141 "style": "color: rgb(136, 19, 145); margin-right: -13px" | |
| 9142 }, | |
| 9143 "[[base class]]: " | |
| 9144 ], | |
| 9145 [ | |
| 9146 "span", | |
| 9147 { | |
| 9148 "style": "margin-left: 13px" | |
| 9149 }, | |
| 9150 [ | |
| 9151 "object", | |
| 9152 { | |
| 9153 "object": "<OBJECT>", | |
| 9154 "config": { | |
| 9155 "name": "asClass" | |
| 9156 } | |
| 9157 } | |
| 9158 ] | |
| 9159 ] | |
| 9160 ] | |
| 9161 ] | |
| 9162 ----------------------------------- | |
| 8816 """; | 9163 """; |
|
vsm
2017/03/31 15:14:08
How about putting this literal into a helper file
Jacob
2017/04/01 00:51:13
Made it a little easier by adding a button to copy
| |
| OLD | NEW |