Parcourir la source

Parsing codeforces

Marcelo Fornet il y a 6 ans
Parent
commit
e083ddc52a
15 fichiers modifiés avec 454 ajouts et 15574 suppressions
  1. 238 63
      package-lock.json
  2. 11 6
      package.json
  3. 25 22
      src/conn.ts
  4. 5 5
      src/core.ts
  5. 12 5
      src/extension.ts
  6. 43 54
      src/parsers/codeforces.ts
  7. 23 0
      src/parsers/util.ts
  8. 0 1900
      src/test/codeforces.html
  9. 0 13406
      src/test/contest.html
  10. 37 95
      src/test/extension.test.ts
  11. 9 4
      src/types.ts
  12. 9 14
      todo.md
  13. 2 0
      tsconfig.json
  14. 9 0
      types/jssoup.d.ts
  15. 31 0
      types/unescape.d.ts

+ 238 - 63
package-lock.json

@@ -1,9 +1,22 @@
 {
     "name": "acmhelper-vscode",
-    "version": "1.0.0",
+    "version": "0.1.0",
     "lockfileVersion": 1,
     "requires": true,
     "dependencies": {
+        "@sindresorhus/is": {
+            "version": "0.14.0",
+            "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+            "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ=="
+        },
+        "@szmarczak/http-timer": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+            "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+            "requires": {
+                "defer-to-connect": "^1.0.1"
+            }
+        },
         "@types/concat-stream": {
             "version": "1.6.0",
             "resolved": "http://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz",
@@ -20,6 +33,16 @@
                 "@types/node": "*"
             }
         },
+        "@types/got": {
+            "version": "9.3.0",
+            "resolved": "https://registry.npmjs.org/@types/got/-/got-9.3.0.tgz",
+            "integrity": "sha512-XEyz4tCx6RnybUcw0ZmpEkNNNxc+QcnEY0r0VV5Ocp+7fjK60iMOvj1mfNMwgzMS7sNQMl+L8SIW7lO/QBAkxg==",
+            "dev": true,
+            "requires": {
+                "@types/node": "*",
+                "@types/tough-cookie": "*"
+            }
+        },
         "@types/mocha": {
             "version": "2.2.48",
             "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz",
@@ -36,6 +59,12 @@
             "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.1.tgz",
             "integrity": "sha512-mNhVdZHdtKHMMxbqzNK3RzkBcN1cux3AvuCYGTvjEIQT2uheH3eCAyYsbMbh2Bq8nXkeOWs1kyDiF7geWRFQ4Q=="
         },
+        "@types/tough-cookie": {
+            "version": "2.3.4",
+            "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.4.tgz",
+            "integrity": "sha512-Set5ZdrAaKI/qHdFlVMgm/GsAv/wkXhSTuZFkJ+JI7HK+wIkIlOaUXSXieIvJ0+OvGIqtREFoE+NHJtEq0gtEw==",
+            "dev": true
+        },
         "ajv": {
             "version": "6.6.2",
             "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz",
@@ -194,15 +223,6 @@
             "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
             "dev": true
         },
-        "axios": {
-            "version": "0.18.0",
-            "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
-            "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
-            "requires": {
-                "follow-redirects": "^1.3.0",
-                "is-buffer": "^1.1.5"
-            }
-        },
         "babel-code-frame": {
             "version": "6.26.0",
             "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@@ -244,14 +264,6 @@
                 "tweetnacl": "^0.14.3"
             }
         },
-        "biskviit": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz",
-            "integrity": "sha1-A3oM1LcbnjMf2QoRIt4X3EnkIKc=",
-            "requires": {
-                "psl": "^1.1.7"
-            }
-        },
         "block-stream": {
             "version": "0.0.9",
             "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@@ -300,6 +312,20 @@
             "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
             "dev": true
         },
+        "cacheable-request": {
+            "version": "5.2.1",
+            "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-5.2.1.tgz",
+            "integrity": "sha512-+dLut9zvvuIM/MrtdHBVSh/QYJ9+uCKYoqww9cOYrndQH4O4rD/qH0IAwFhD5WJKfmWE6WgCOrLQPd/H5YJRVQ==",
+            "requires": {
+                "clone-response": "^1.0.2",
+                "get-stream": "^4.0.0",
+                "http-cache-semantics": "^4.0.0",
+                "keyv": "^3.0.0",
+                "lowercase-keys": "^1.0.1",
+                "normalize-url": "^3.1.0",
+                "responselike": "^1.0.2"
+            }
+        },
         "caseless": {
             "version": "0.12.0",
             "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -348,6 +374,14 @@
             "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
             "dev": true
         },
+        "clone-response": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+            "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+            "requires": {
+                "mimic-response": "^1.0.0"
+            }
+        },
         "clone-stats": {
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
@@ -438,10 +472,19 @@
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
             "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+            "dev": true,
             "requires": {
                 "ms": "2.0.0"
             }
         },
+        "decompress-response": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+            "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+            "requires": {
+                "mimic-response": "^1.0.0"
+            }
+        },
         "deep-assign": {
             "version": "1.0.0",
             "resolved": "http://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz",
@@ -451,6 +494,11 @@
                 "is-obj": "^1.0.0"
             }
         },
+        "defer-to-connect": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.1.tgz",
+            "integrity": "sha512-2e0FJesseUqQj671gvZWfUyxpnFx/5n4xleamlpCD3U6Fm5dh5qzmmLNxNhtmHF06+SYVHH8QU6FACffYTnj0Q=="
+        },
         "define-properties": {
             "version": "1.1.3",
             "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -471,17 +519,17 @@
             "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
             "dev": true
         },
-        "dom-parser": {
-            "version": "0.1.5",
-            "resolved": "https://registry.npmjs.org/dom-parser/-/dom-parser-0.1.5.tgz",
-            "integrity": "sha1-pPYBn5oxW3XXQoqqfMv1vYWeFvs="
-        },
         "duplexer": {
             "version": "0.1.1",
             "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
             "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
             "dev": true
         },
+        "duplexer3": {
+            "version": "0.1.4",
+            "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+            "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+        },
         "duplexify": {
             "version": "3.6.1",
             "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz",
@@ -504,19 +552,10 @@
                 "safer-buffer": "^2.1.0"
             }
         },
-        "encoding": {
-            "version": "0.1.12",
-            "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
-            "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
-            "requires": {
-                "iconv-lite": "~0.4.13"
-            }
-        },
         "end-of-stream": {
             "version": "1.4.1",
             "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
             "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
-            "dev": true,
             "requires": {
                 "once": "^1.4.0"
             }
@@ -596,15 +635,6 @@
                 "pend": "~1.2.0"
             }
         },
-        "fetch": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz",
-            "integrity": "sha1-CoJ58Gvjf58Ou1Z1YKMKSA2lmi4=",
-            "requires": {
-                "biskviit": "1.0.1",
-                "encoding": "0.1.12"
-            }
-        },
         "flush-write-stream": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
@@ -615,14 +645,6 @@
                 "readable-stream": "^2.0.4"
             }
         },
-        "follow-redirects": {
-            "version": "1.5.10",
-            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
-            "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
-            "requires": {
-                "debug": "=3.1.0"
-            }
-        },
         "forever-agent": {
             "version": "0.6.1",
             "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -684,6 +706,25 @@
             "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
             "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw="
         },
+        "get-stream": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+            "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+            "requires": {
+                "pump": "^3.0.0"
+            },
+            "dependencies": {
+                "pump": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+                    "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+                    "requires": {
+                        "end-of-stream": "^1.1.0",
+                        "once": "^1.3.1"
+                    }
+                }
+            }
+        },
         "getpass": {
             "version": "0.1.7",
             "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@@ -735,6 +776,24 @@
                 "unique-stream": "^2.0.2"
             }
         },
+        "got": {
+            "version": "9.5.0",
+            "resolved": "https://registry.npmjs.org/got/-/got-9.5.0.tgz",
+            "integrity": "sha512-N+4kb6i9t1lauJ4NwLVVoFVLxZNa6i+iivtNzCSVw7+bVbTXoq0qXctdd8i9rj3lrI0zDk5NGzcO4bfpEP6Uuw==",
+            "requires": {
+                "@sindresorhus/is": "^0.14.0",
+                "@szmarczak/http-timer": "^1.1.0",
+                "cacheable-request": "^5.1.0",
+                "decompress-response": "^3.3.0",
+                "duplexer3": "^0.1.4",
+                "get-stream": "^4.1.0",
+                "lowercase-keys": "^1.0.1",
+                "mimic-response": "^1.0.1",
+                "p-cancelable": "^1.0.0",
+                "to-readable-stream": "^1.0.0",
+                "url-parse-lax": "^3.0.0"
+            }
+        },
         "graceful-fs": {
             "version": "4.1.15",
             "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
@@ -989,6 +1048,11 @@
             "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
             "dev": true
         },
+        "htmlparser": {
+            "version": "1.7.7",
+            "resolved": "https://registry.npmjs.org/htmlparser/-/htmlparser-1.7.7.tgz",
+            "integrity": "sha1-GeezmX/2+6yZrlp9J2ZInv5+LQ4="
+        },
         "http-basic": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-7.0.0.tgz",
@@ -1009,6 +1073,11 @@
                 }
             }
         },
+        "http-cache-semantics": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
+            "integrity": "sha512-OO/9K7uFN30qwAKvslzmCTbimZ/uRjtdN5S50vvWLwUKqFuZj0n96XyCzF5tHRHEO/Q4JYC01hv41gkX06gmHA=="
+        },
         "http-response-object": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.1.tgz",
@@ -1035,14 +1104,6 @@
                 "sshpk": "^1.7.0"
             }
         },
-        "iconv-lite": {
-            "version": "0.4.24",
-            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-            "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-            "requires": {
-                "safer-buffer": ">= 2.1.2 < 3"
-            }
-        },
         "inflight": {
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -1077,7 +1138,13 @@
         "is-buffer": {
             "version": "1.1.6",
             "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
-            "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+            "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+            "dev": true
+        },
+        "is-extendable": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+            "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
         },
         "is-extglob": {
             "version": "2.1.1",
@@ -1181,6 +1248,11 @@
             "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
             "dev": true
         },
+        "json-buffer": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+            "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg="
+        },
         "json-schema": {
             "version": "0.2.3",
             "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
@@ -1217,6 +1289,40 @@
                 "verror": "1.10.0"
             }
         },
+        "jssoup": {
+            "version": "0.0.10",
+            "resolved": "https://registry.npmjs.org/jssoup/-/jssoup-0.0.10.tgz",
+            "integrity": "sha512-t7V4AX16R3NZKFgBdNT4BsrFome790p3Ado1cqWJ+gr9yNAoR50cw68EH7e5kaxqMGucjXjBvYwP1fY/RpKplQ==",
+            "requires": {
+                "debug": "^2.6.9",
+                "growl": "^1.10.5",
+                "htmlparser": "^1.7.7",
+                "lodash": "^4.17.5"
+            },
+            "dependencies": {
+                "debug": {
+                    "version": "2.6.9",
+                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+                    "requires": {
+                        "ms": "2.0.0"
+                    }
+                },
+                "growl": {
+                    "version": "1.10.5",
+                    "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+                    "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
+                }
+            }
+        },
+        "keyv": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
+            "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
+            "requires": {
+                "json-buffer": "3.0.0"
+            }
+        },
         "kind-of": {
             "version": "1.1.0",
             "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
@@ -1241,6 +1347,16 @@
                 "flush-write-stream": "^1.0.2"
             }
         },
+        "lodash": {
+            "version": "4.17.11",
+            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+            "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+        },
+        "lowercase-keys": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+            "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+        },
         "map-stream": {
             "version": "0.1.0",
             "resolved": "http://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
@@ -1260,6 +1376,11 @@
                 "mime-db": "~1.37.0"
             }
         },
+        "mimic-response": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+            "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
+        },
         "minimatch": {
             "version": "3.0.4",
             "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -1381,6 +1502,11 @@
                 "remove-trailing-separator": "^1.0.1"
             }
         },
+        "normalize-url": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
+            "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg=="
+        },
         "now-and-later": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz",
@@ -1418,7 +1544,6 @@
             "version": "1.4.0",
             "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
             "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-            "dev": true,
             "requires": {
                 "wrappy": "1"
             }
@@ -1432,6 +1557,11 @@
                 "readable-stream": "^2.0.1"
             }
         },
+        "p-cancelable": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.0.0.tgz",
+            "integrity": "sha512-USgPoaC6tkTGlS831CxsVdmZmyb8tR1D+hStI84MyckLOzfJlYQUweomrwE3D8T7u5u5GVuW064LT501wHTYYA=="
+        },
         "parse-cache-control": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
@@ -1489,6 +1619,11 @@
                 "extend-shallow": "^1.1.2"
             }
         },
+        "prepend-http": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+            "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc="
+        },
         "process-nextick-args": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
@@ -1505,7 +1640,8 @@
         "psl": {
             "version": "1.1.31",
             "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
-            "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
+            "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==",
+            "dev": true
         },
         "pump": {
             "version": "2.0.1",
@@ -1653,6 +1789,14 @@
                 "value-or-function": "^3.0.0"
             }
         },
+        "responselike": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+            "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+            "requires": {
+                "lowercase-keys": "^1.0.0"
+            }
+        },
         "rimraf": {
             "version": "2.6.2",
             "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
@@ -1670,7 +1814,8 @@
         "safer-buffer": {
             "version": "2.1.2",
             "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+            "dev": true
         },
         "semver": {
             "version": "5.6.0",
@@ -1868,6 +2013,11 @@
                 "is-negated-glob": "^1.0.0"
             }
         },
+        "to-readable-stream": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+            "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q=="
+        },
         "to-through": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
@@ -1962,6 +2112,24 @@
             "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
             "dev": true
         },
+        "unescape": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz",
+            "integrity": "sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==",
+            "requires": {
+                "extend-shallow": "^2.0.1"
+            },
+            "dependencies": {
+                "extend-shallow": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+                    "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+                    "requires": {
+                        "is-extendable": "^0.1.0"
+                    }
+                }
+            }
+        },
         "unique-stream": {
             "version": "2.3.1",
             "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
@@ -1991,6 +2159,14 @@
                 "requires-port": "^1.0.0"
             }
         },
+        "url-parse-lax": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+            "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+            "requires": {
+                "prepend-http": "^2.0.0"
+            }
+        },
         "util-deprecate": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -2160,8 +2336,7 @@
         "wrappy": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-            "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-            "dev": true
+            "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
         },
         "xtend": {
             "version": "4.0.1",

+ 11 - 6
package.json

@@ -18,7 +18,8 @@
         "onCommand:extension.addTestcase",
         "onCommand:extension.coding",
         "onCommand:extension.stress",
-        "onCommand:extension.upgrade"
+        "onCommand:extension.upgrade",
+        "onCommand:extension.debugTest"
     ],
     "main": "./out/extension",
     "contributes": {
@@ -65,13 +66,17 @@
         "test": "npm run compile && node ./node_modules/vscode/bin/test"
     },
     "devDependencies": {
-        "typescript": "^3.1.4",
-        "vscode": "^1.1.25",
-        "tslint": "^5.8.0",
+        "@types/got": "^9.3.0",
+        "@types/mocha": "^2.2.42",
         "@types/node": "^8.10.25",
-        "@types/mocha": "^2.2.42"
+        "tslint": "^5.8.0",
+        "typescript": "^3.1.4",
+        "vscode": "^1.1.25"
     },
     "dependencies": {
-        "sync-request": "^6.0.0"
+        "got": "^9.5.0",
+        "jssoup": "0.0.10",
+        "sync-request": "^6.0.0",
+        "unescape": "^1.0.1"
     }
 }

+ 25 - 22
src/conn.ts

@@ -2,31 +2,34 @@ import { SiteDescription, Contest, Problem } from "./types";
 import { CODEFORCES } from "./parsers/codeforces";
 
 /**
- * Register a new site creating an entry in this dictionary.
+ * Not a real site.
+ *
+ * Util to create personal problems and debug this tool.
  */
-export const SITES: SiteDescription[] = [
-    /**
-     * Not a real site.
-     *
-     * Util to create personal problems and debug this tool.
-     */
-    new SiteDescription(
-        "personal",
-        "Not a site. Custom problems and contest.",
-        numProblems => {
-            let problems = [];
-
-            for (let i = 0; i < numProblems; i++) {
-                problems.push(new Problem(`P${i+1}`, ["0\n", "2\n", "9\n"], ["2\n", "4\n", "11\n"]));
-            }
-
-            return new Contest(problems);
-        },
-        problemId => {
-            return new Problem("W", ["0\n", "2\n", "9\n"], ["2\n", "4\n", "11\n"]);
+const PERSONAL = new SiteDescription(
+    "personal",
+    "Not a site. Custom problems and contest.",
+    async numProblems => {
+        let total = Number.parseInt(numProblems);
+
+        let problems = [];
+
+        for (let i = 0; i < total; i++) {
+            problems.push(new Problem(`P${i+1}`, `P${i+1}`, ["0\n", "2\n", "9\n"], ["2\n", "4\n", "11\n"]));
         }
-    ),
 
+        return new Contest(problems);
+    },
+    async problemId => {
+        return new Problem("W", "W", ["0\n", "2\n", "9\n"], ["2\n", "4\n", "11\n"]);
+    }
+);
+
+/**
+ * Register a new site creating an entry in this dictionary.
+ */
+export const SITES: SiteDescription[] = [
+    PERSONAL,
     CODEFORCES,
 ];
 

+ 5 - 5
src/core.ts

@@ -182,17 +182,17 @@ function newProblem(path: string, problem: Problem){
     });
 }
 
-export function newProblemFromId(path: string, site: string, problemId: string){
+export async function newProblemFromId(path: string, site: string, problemId: string){
     let siteDesc = getSite(site);
 
-    let problem = siteDesc.problemParser(problemId);
+    let problem = await siteDesc.problemParser(problemId);
 
     newProblem(path, problem);
 }
 
 function newContest(path: string, contest: Contest){
     contest.problems!.forEach(problem => {
-        newProblem(join(path, problem.name!), problem);
+        newProblem(join(path, problem.identifier!), problem);
     });
 }
 
@@ -201,10 +201,10 @@ function newContest(path: string, contest: Contest){
  *
  * @param contestId Can be a number if the site is `personal` and this number denote number of problems
  */
-export function newContestFromId(path: string, site: string, contestId: string | number){
+export async function newContestFromId(path: string, site: string, contestId: string){
     createFolder(path);
     let siteDesc = getSite(site);
-    let contest = siteDesc.contestParser(contestId);
+    let contest = await siteDesc.contestParser(contestId);
     newContest(path, contest);
 }
 

+ 12 - 5
src/extension.ts

@@ -51,7 +51,7 @@ async function addProblem() {
 
     path = join(path, `${id}`);
 
-    newProblemFromId(path, site, id);
+    await newProblemFromId(path, site, id);
 
     await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(path));
     // TODO: 007
@@ -95,7 +95,7 @@ async function addContest() {
             return;
         }
 
-        id = Number.parseInt(probCountStr!);
+        id = probCountStr!;
     }
     else{
         // TODO: 008
@@ -109,7 +109,7 @@ async function addContest() {
         path = join(path, `${id}`);
     }
 
-    newContestFromId(path, site, id);
+    await newContestFromId(path, site, id);
 
     vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(path));
 }
@@ -256,11 +256,15 @@ async function upgrade(){
     upgradeArena(path);
 }
 
+async function debugTest(){
+    // let contest = await parseContest("1081");
+    console.log("HEY");
+    // await parseProblem("1081-E");
+}
+
 // this method is called when your extension is activated
 // your extension is activated the very first time the command is executed
 export function activate(context: vscode.ExtensionContext) {
-    console.log('Congratulations, your extension "acmhelper-vscode" is now active!');
-
     let addProblemCommand = vscode.commands.registerCommand('extension.addProblem', addProblem);
     let addContestCommand = vscode.commands.registerCommand('extension.addContest', addContest);
     let runSolutionCommand = vscode.commands.registerCommand('extension.runSolution', runSolution);
@@ -270,6 +274,8 @@ export function activate(context: vscode.ExtensionContext) {
     let stressCommand = vscode.commands.registerCommand('extension.stress', stress);
     let upgradeCommand = vscode.commands.registerCommand('extension.upgrade', upgrade);
 
+    let debugTestCommand = vscode.commands.registerCommand('extension.debugTest', debugTest);
+
     context.subscriptions.push(addProblemCommand);
     context.subscriptions.push(addContestCommand);
     context.subscriptions.push(runSolutionCommand);
@@ -278,6 +284,7 @@ export function activate(context: vscode.ExtensionContext) {
     context.subscriptions.push(codingCommand);
     context.subscriptions.push(stressCommand);
     context.subscriptions.push(upgradeCommand);
+    context.subscriptions.push(debugTestCommand);
 }
 
 // this method is called when your extension is deactivated

+ 43 - 54
src/parsers/codeforces.ts

@@ -1,7 +1,9 @@
 import { SiteDescription, Contest, Problem } from "../types";
 
-// TODO: 009
-const request = require('request');
+import * as vscode from 'vscode';
+import JSSoup from 'jssoup';
+import * as got from 'got';
+import { getText } from './util';
 
 /**
  * contestId: ${contest}
@@ -10,29 +12,28 @@ const request = require('request');
  * Example:
  * http://codeforces.com/contest/1081/
  */
-function parseContest(contestId: string | number) {
-    let problems: Problem[] = [];
-
-    let res = request('GET', `http://codeforces.com/contest/${contestId}`);
-    let body = res.getBody('utf8');
-
-    console.log(body);
-
-    let pos = body!.indexOf('<option value="generalAnnouncement" data-problem-name="" >', 0) + 1;
+export async function parseContest(contestId: string) {
+    let url = `http://codeforces.com/contest/${contestId}`;
+    let response = await got.get(url);
 
-    while (true){
-        let option_begin = body!.indexOf('option value="', pos) + 14;
-        let option_end = body!.indexOf('" data-problem-name', option_begin);
+    if (response.statusCode !== 200){
+        throw new Error(`Contest ${url} not downloaded. ${response.statusCode}`);
+    }
 
-        if (option_begin === -1 || option_end === -1){
-            break;
-        }
+    vscode.window.showInformationMessage(`Downloading contest ${contestId}...`);
 
-        pos = option_end;
+    let soup = new JSSoup(response.body);
+    let problemsTable = soup.find("table", "problems");
+    let problems: Problem[] = [];
+    let problemSection = problemsTable.findAll("td", "id");
 
-        let problemId = body!.substring(option_begin, option_end);
+    for (let i = 0; i < problemSection.length; i++){
+        let section = problemSection[i];
+        let hrefData = section.find("a").attrs.href.split('/');
+        let pid = hrefData[hrefData.length - 1];
+        console.log(`Problem ${contestId}-${pid}`);
 
-        let prob = parseProblem(`${contestId}-${problemId}`);
+        let prob = await parseProblem(contestId + "-" + pid);
         problems.push(prob);
     }
 
@@ -46,51 +47,39 @@ function parseContest(contestId: string | number) {
  * Example:
  * http://codeforces.com/contest/1081/problem/E
  */
-function parseProblem(problemId: string) {
+export async function parseProblem(problemId: string) {
     let data = problemId.split('-');
     let contest = data[0];
-    let problem = data[1];
-
-    var res = request('GET', `http://codeforces.com/contest/${contest}/problem/${problem}`);
-    let html: string = res.getBody('utf8');
+    let pid = data[1];
 
-    let pos = 0;
+    let url = `http://codeforces.com/contest/${contest}/problem/${pid}`;
+    let response = await got.get(url);
 
-    let inputs = [];
-    let outputs = [];
-
-    while (true){
-        pos = html.indexOf('<div class="title">Input</div>', pos);
-
-        if (pos === -1){
-            break;
-        }
-
-        let begin_pre = html.indexOf('<pre>', pos);
-        let end_pre = html.indexOf('</pre>', pos);
-
-        let inputTestcase = html.substring(begin_pre + 5, end_pre);
+    if (response.statusCode !== 200){
+        throw new Error(`Problem ${url} not downloaded. ${response.statusCode}`);
+    }
 
-        while (inputTestcase.indexOf('<br />') !== -1){
-            inputTestcase = inputTestcase.replace('<br />', '\n');
-        }
+    let soup = new JSSoup(response.body);
+    let problemDescription = soup.find("div", "problemindexholder");
 
-        pos = html.indexOf('<div class="title">Output</div>', pos);
+    let name = problemDescription.find("div", "title").text;
 
-        begin_pre = html.indexOf('<pre>', pos);
-        end_pre = html.indexOf('</pre>', pos);
+    let inputTC: string[] = [];
+    let outputTC: string[] = [];
 
-        let outputTestcase = html.substring(begin_pre + 5, end_pre);
+    problemDescription.findAll("div", "input").forEach((element: any) =>{
+        let tc = element.find("pre");
+        inputTC.push(getText(tc));
+    });
 
-        while (outputTestcase.indexOf('<br />') !== -1){
-            outputTestcase = outputTestcase.replace('<br />', '\n');
-        }
+    problemDescription.findAll("div", "output").forEach((element: any) =>{
+        let tc = element.find("pre");
+        outputTC.push(getText(tc));
+    });
 
-        inputs.push(inputTestcase);
-        outputs.push(outputTestcase);
-    }
+    vscode.window.showInformationMessage(`Downloaded problem ${problemId}!`);
 
-    return new Problem(problem, inputs, outputs);
+    return new Problem(pid, name, inputTC, outputTC);
 }
 
 export const CODEFORCES = new SiteDescription(

+ 23 - 0
src/parsers/util.ts

@@ -0,0 +1,23 @@
+import * as unescape from 'unescape';
+
+export function getText(htmlNode: any){
+    let data: string[] = [];
+
+    htmlNode.contents.forEach((element: any) => {
+        if (element._text === undefined){
+            data.push('\n');
+        }
+        else{
+            if (data.length === 0 && element._text[0] === '\n'){
+                data.push(element._text.slice(1));
+            }
+            else{
+                data.push(element._text);
+            }
+        }
+    });
+
+    let pData = data.join();
+
+    return unescape(pData, undefined);
+}

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 1900
src/test/codeforces.html


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 13406
src/test/contest.html


+ 37 - 95
src/test/extension.test.ts

@@ -8,8 +8,7 @@ import * as assert from 'assert';
 import { dirname, join } from 'path';
 import { timedRun, testcasesName, testSolution, newArena, ATTIC, TESTCASES, upgradeArena, stressSolution, newProblemFromId, newContestFromId } from '../core';
 import { TestcaseResult, Veredict } from '../types';
-import { rmdirSync, existsSync, readdirSync, unlinkSync, openSync, writeSync, closeSync, readSync } from 'fs';
-// import { request } from 'http';
+import { rmdirSync, existsSync, readdirSync, unlinkSync, openSync, writeSync, closeSync } from 'fs';
 
 const SRC = join(dirname(dirname(dirname(__filename))), 'src', 'test');
 const ARENA = join(SRC, 'arena');
@@ -19,18 +18,20 @@ suite("Extension Tests", function () {
      * Recursive remove
      */
     function recRmdir(path: string){
-        readdirSync(path).forEach(name => {
-            let cPath = join(path, name);
-
-            try{
-                unlinkSync(cPath);
-            }
-            catch(err){
-                recRmdir(cPath);
-            }
-        });
-
-        rmdirSync(path);
+        if (existsSync(path)){
+            readdirSync(path).forEach(name => {
+                let cPath = join(path, name);
+
+                try{
+                    unlinkSync(cPath);
+                }
+                catch(err){
+                    recRmdir(cPath);
+                }
+            });
+
+            rmdirSync(path);
+        }
     }
 
     function writeFile(path: string, content: string){
@@ -90,27 +91,29 @@ suite("Extension Tests", function () {
         let result = testcasesName(path);
         let target = ["0", "1", "2"];
 
-        // TODO: 010
-        // I want to compare `result` & `target`
-        target.forEach(name => {assert.notEqual(result.findIndex(tname => { return tname === name; }), -1);});
-        result.forEach(name => {assert.notEqual(target.findIndex(tname => { return tname === name; }), -1);});
+        assert.equal(result.length, target.length);
+
+        result.sort();
+
+        for (let i = 0; i < 3; ++i){
+            assert.equal(target[i], result[i]);
+        }
     });
 
     /**
      * core::newProblem
      */
-    test("newProblemFromId", function(){
+    test("newProblemFromId", async function(){
         let problemId = 'testProblemFromId';
         let path = join(ARENA, problemId);
 
         assert.equal(existsSync(path), false);
+        await newProblemFromId(path, 'personal', problemId);
 
-        newProblemFromId(path, 'personal', problemId);
-
-        assert.equal(existsSync(join(path, 'sol.cpp')), true);
-        assert.equal(existsSync(join(path, ATTIC)), true);
-        assert.equal(existsSync(join(path, TESTCASES)), true);
-        assert.equal(readdirSync(join(path, TESTCASES)).length, 6);
+        assert.equal(existsSync(join(path, 'sol.cpp')), true, "Solution not found.");
+        assert.equal(existsSync(join(path, ATTIC)), true, "Attic not found.");
+        assert.equal(existsSync(join(path, TESTCASES)), true, "Testcases not found.");
+        assert.equal(readdirSync(join(path, TESTCASES)).length, 6, "Incorrect number of files.");
 
         recRmdir(path);
     });
@@ -118,15 +121,15 @@ suite("Extension Tests", function () {
     /**
      * core::newProblem
      */
-    test("newContestFromId", function(){
+    test("newContestFromId", async function(){
         let contestId = 'testContestFromId';
         let path = join(ARENA, contestId);
 
         assert.equal(existsSync(path), false);
 
-        newContestFromId(path, 'personal', 5);
+        await newContestFromId(path, 'personal', "5");
 
-        assert.equal(readdirSync(path).length, 5);
+        assert.equal(readdirSync(path).length, "5");
 
         recRmdir(path);
     });
@@ -183,8 +186,12 @@ suite("Extension Tests", function () {
     test("testSolutionCE", function() {
         let exampleContest = join(ARENA, 'exampleContest');
         let problem = join(exampleContest, 'E');
-        let result: TestcaseResult = testSolution(problem);
-        assert.equal(result.status, Veredict.CE);
+        try {
+            testSolution(problem);
+            assert(false, "This must throw Compilation Error");
+        } catch (Error) {
+
+        }
     });
 
     /**
@@ -291,69 +298,4 @@ suite("Extension Tests", function () {
 
         recRmdir(path);
     });
-
-    function readFile(path: string){
-        let fd = openSync(path, "r");
-        let buffer = new Buffer(1 << 20);
-        readSync(fd, buffer, 0, 1 << 20, 0);
-        let answer = buffer.toString();
-        return answer;
-    }
-
-    test("downloading", async function(){
-        let request = require('request');
-        // let statusCode = undefined;
-
-        await request('http://codeforces.com/contest/1081/problem/E', function(error: any, response: any, body: any){
-        // let x = request('http://localhost:8000/libros', function(error: any, response: any, body: any) {
-            // console.log(">>>" + response.statusCode);
-            // statusCode = response.statusCode;
-            writeFile(join(SRC, "codeforces.html"), body);
-        });
-
-        // assert.equal(statusCode, 200);
-    });
-
-    test("parsing", function(){
-        let html: string = readFile(join(__dirname, "codeforces.html"));
-        let pos = 0;
-
-        while (true){
-            pos = html.indexOf('<div class="title">Input</div>', pos);
-
-            if (pos === -1){
-                break;
-            }
-
-            let begin_pre = html.indexOf('<pre>', pos);
-            let end_pre = html.indexOf('</pre>', pos);
-
-            let inputTestcase = html.substring(begin_pre + 5, end_pre);
-
-            while (inputTestcase.indexOf('<br />') !== -1){
-                inputTestcase = inputTestcase.replace('<br />', '\n');
-            }
-
-            pos = html.indexOf('<div class="title">Output</div>', pos);
-
-            begin_pre = html.indexOf('<pre>', pos);
-            end_pre = html.indexOf('</pre>', pos);
-
-            let outputTestcase = html.substring(begin_pre + 5, end_pre);
-
-            while (outputTestcase.indexOf('<br />') !== -1){
-                outputTestcase = outputTestcase.replace('<br />', '\n');
-            }
-        }
-    });
-
-    test("parsingLocalhost", function(){
-        let request = require('request');
-
-        request('http://localhost:8000/libros', function (error: any, response: any, body: any) {
-            // console.log('error:', error);
-            // console.log('statusCode:', response && response.statusCode);
-            // console.log('body:', body);
-        });
-    });
 });

+ 9 - 4
src/types.ts

@@ -29,11 +29,14 @@ export class SolutionResult{
 }
 
 export class Problem{
+    // Identifier will be used as folder name
+    identifier?: string;
     name?: string;
     inputs?: string[];
     outputs?: string[];
 
-    constructor(name?: string, inputs?: string[], outputs?: string[]){
+    constructor(identifier?: string, name?: string, inputs?: string[], outputs?: string[]){
+        this.identifier = identifier;
         this.name = name;
         this.inputs = inputs;
         this.outputs = outputs;
@@ -51,10 +54,12 @@ export class Contest{
 export class SiteDescription{
     name: string;
     description: string;
-    contestParser: (contestId: string | number) => Contest;
-    problemParser: (problemId: string) => Problem;
+    contestParser: (contestId: string) => Promise<Contest>;
+    problemParser: (problemId: string) => Promise<Problem>;
 
-    constructor(name: string, description: string, contestParser: (contestId: string | number) => Contest, problemParser: (problemId: string) => Problem){
+    constructor(name: string, description: string,
+                contestParser: (contestId: string) => Promise<Contest>,
+                problemParser: (problemId: string) => Promise<Problem>){
         this.name = name;
         this.description = description;
         this.contestParser = contestParser;

+ 9 - 14
todo.md

@@ -1,27 +1,22 @@
 # List of TODO
 
-* Refactor Code!!
+* Use this tool: https://github.com/slycelote/caide-cpp-inliner.  Suggestion from jcg
 * Add How to Use (in the README.) How to add own template etc...
 * **NEXT** Create custom settings. Add (TimeLimit, Checker)
-* Allow custom checker easily
-* Add several checkers and try to infer which is the correct! [*]
-* **PARSING** Smart ID detection while parsing ContestId & ProblemId [*]
-* **NEXT** Smart generator [*]
-* Find great name/slogan!!! other than acmhelper Competitive Programming made simple
+* **IMPORTANT** When a new view is activated (after run or view:code) close all open tabs. (also (maybe) collapse everything not related to the problem)
 * Implement parser for codeforces to test on real cases
-* **INTERNET** Learn how to move static files from `src` to `out`.
+* **INTERNET** Learn how to move static files from `src` to `out`. Make this extension works.
 * Allow programming in other languages than c++
 * Figure out something for interactive problems.
-* **IMPORTANT** When a new view is activated (after run or view:code) close all open tabs. (also (maybe) collapse everything not related to the problem)
 * Allow stopping a running program (such as sol.cpp/brute.cpp/gen.py/etc...)
+* Allow custom checker easily
+* Add several checkers and try to infer which is the correct!
+* Fix name of new problems after calling addProblem
+* Add Compile command
 
-* [001](/src/core.ts): Revisit this constant. Show specific error to know when this is an issue
+* [001](/src/core.ts): Revisit this constant. Show specific error to know when this is an issue. Add in settings
 * [002](/src/core.ts): Avoid this hardcoded line. Use personalized compile line. increase stack by default. This involve allowing different languages
-* [004](/src/core.ts): **NILOX** Revisit this call to python3. How to make it cross platform
+* [004](/src/core.ts): Make crossplatform call. Solution: Configure path to python in global settings
 * [005](/src/core.ts): Restrict brute in time, and capture errors
 * [006](/src/extension.ts): **PARSING** Provide custom problem and contest id example in placeholder per different site
 * [007](/src/extension.ts): How can I have access to new proccess created using `openFolder`?
-* [009](/src/parsers/codeforces.ts): **INTERNET** Use sync requests
-* [010](/src/test/extension.test.ts): **NILOX** **INTERNET** How to check if two arrays are equal
-
-[*] Machine Learning?

+ 2 - 0
tsconfig.json

@@ -1,5 +1,7 @@
 {
     "compilerOptions": {
+        "baseUrl": ".",
+        "paths": { "*": ["types/*"] },
         "module": "commonjs",
         "target": "es6",
         "outDir": "out",

+ 9 - 0
types/jssoup.d.ts

@@ -0,0 +1,9 @@
+export default class _default {
+    constructor(text: any);
+    append(item: any): void;
+    extract(): void;
+    find(...args: any[]): any;
+    findAll(...args: any[]): any;
+    getText(...args: any[]): any;
+    prettify(...args: any[]): any;
+}

+ 31 - 0
types/unescape.d.ts

@@ -0,0 +1,31 @@
+export = index;
+declare function index(str: any, type: any): any;
+declare namespace index {
+    const all: any;
+    const chars: {
+        "&#34;": string;
+        "&#38;": string;
+        "&#39;": string;
+        "&#60;": string;
+        "&#62;": string;
+        "&amp;": string;
+        "&apos;": string;
+        "&gt;": string;
+        "&lt;": string;
+        "&quot;": string;
+    };
+    const extras: {
+        "&#162;": string;
+        "&#163;": string;
+        "&#165;": string;
+        "&#169;": string;
+        "&#174;": string;
+        "&#8364;": string;
+        "&cent;": string;
+        "&copy;": string;
+        "&euro;": string;
+        "&pound;": string;
+        "&reg;": string;
+        "&yen;": string;
+    };
+}