diff --git a/README.md b/README.md index e97a1d649..0d9fa37df 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # πŸš‡ μ§€ν•˜μ²  노선도 λ―Έμ…˜ +[/docs/README.md둜 μ΄λ™ν•˜κΈ°](./docs/README.md) + ## πŸš€ κΈ°λŠ₯ μš”κ΅¬μ‚¬ν•­ ### μ§€ν•˜μ²  μ—­ κ΄€λ ¨ κΈ°λŠ₯ diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..c12fb49d1 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,95 @@ +# πŸš‡ μ§€ν•˜μ²  노선도 λ―Έμ…˜ + +## 🎯 λ―Έμ…˜ λͺ©ν‘œ + +μ§€ν•˜μ²  노선도 λ―Έμ…˜μ€ μ§€ν•˜μ² μ˜ μ—­κ³Ό 노선을 μΆ”κ°€, μ‚­μ œν•˜λŠ” λ“± μ§€ν•˜μ² μ˜ ꡬ쑰λ₯Ό 관리할 수 μžˆλŠ” 웹을 μ œμž‘ν•˜λŠ” λ―Έμ…˜μž…λ‹ˆλ‹€. + +웹은 'μ—­ 관리', 'λ…Έμ„  관리', 'ꡬ간 관리', 'μ§€ν•˜μ²  노선도 좜λ ₯'의 4κ°€μ§€ 컨텐츠λ₯Ό κ°€μ§€κ³  있고 μ›Ή μƒλ‹¨μ˜ 메뉴 λ°”λ‘œ 컨텐츠 κ°„μ˜ 이동이 κ°€λŠ₯ν•©λ‹ˆλ‹€. + +μ§€ν•˜μ²  노선도 웹에 μ˜ν•΄ κ΄€λ¦¬λ˜λŠ” μ •λ³΄λŠ” 컴퓨터에 μ €μž₯λ˜μ–΄ 웹을 끄고 μΌœλ”λΌλ„ λ§ˆμ§€λ§‰μœΌλ‘œ μž‘μ—…ν•œ 정보λ₯Ό λΆˆλŸ¬μ˜΅λ‹ˆλ‹€. + +## πŸ’» ν”„λ‘œκ·Έλž¨ κΈ°λŠ₯ + +### 1. μ—­ 관리 + + + +ν˜„μž¬ μ§€ν•˜μ² μ΄ κ°€μ§€κ³  μžˆλŠ” μ—­ 정보듀을 λͺ©λ‘μœΌλ‘œ ν‘œμ‹œν•©λ‹ˆλ‹€. + +μƒˆλ‘œμš΄ 역을 μΆ”κ°€ν•˜κ³ , 기쑴의 역을 μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€. + +### 2. λ…Έμ„  관리 + + + +μ§€ν•˜μ² μ΄ κ°€μ§€κ³  μžˆλŠ” λ…Έμ„  정보듀을 λͺ©λ‘μœΌλ‘œ ν‘œμ‹œν•©λ‹ˆλ‹€. + +ν‘œμ‹œλ˜λŠ” λ…Έμ„  μ •λ³΄λŠ” λ…Έμ„  이름, 상행 쒅점, ν•˜ν–‰ μ’…μ μž…λ‹ˆλ‹€. + +μƒˆλ‘œμš΄ 노선을 μž…λ ₯λ°›μ•„ μΆ”κ°€ν•  수 있고 기쑴의 노선을 μ‚­μ œλ„ κ°€λŠ₯ν•©λ‹ˆλ‹€. + +### 3. ꡬ간 관리 + + + +ꡬ간 κ΄€λ¦¬λŠ” 노선에 λ“±λ‘λœ 역을 κ΄€λ¦¬ν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€. + +각 노선에 λŒ€ν•΄ μƒˆλ‘œμš΄ 역을 λ“±λ‘μ‹œν‚¬ μˆ˜λ„ 있고 노선에 ν¬ν•¨λ˜μ–΄μžˆλ˜ κΈ°μ‘΄ 역을 μ œκ±°ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. + +### 4. 노선도 좜λ ₯ + + + +노선도 좜λ ₯은 μ €μž₯된 노선에 λŒ€ν•œ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ 각 λ…Έμ„ μ˜ 이름과 노선에 λ“±λ‘λœ μ—­ 이름을 λ‚˜μ—΄ν•˜μ—¬ κ°„λ‹¨ν•˜κ²Œ λ³΄μ—¬μ€λ‹ˆλ‹€. + +## πŸ“ κ΅¬ν˜„ν•  κΈ°λŠ₯ λͺ©λ‘ + +- (μ™„λ£Œ)4κ°€μ§€ νŽ˜μ΄μ§€λ₯Ό μ „ν™˜ν•˜λŠ” 메뉴 λ²„νŠΌ κ΅¬ν˜„ +- μ—­ 관리 + - (μ™„λ£Œ)html string μž‘μ„± + - (μ™„λ£Œ)μ—­μ˜ 정보λ₯Ό μ €μž₯ν•˜λŠ” 클래슀 생성 + - (μ™„λ£Œ)μ—­ μΆ”κ°€ λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ μ—­ λͺ©λ‘μ— μ—­ μΆ”κ°€ + - (μ™„λ£Œ)μ—­ 이름 μž…λ ₯이 2κΈ€μž 미만이면 μ—λŸ¬λ©”μ„Έμ§€ 좜λ ₯ + - (μ™„λ£Œ)μ€‘λ³΅λœ μ—­ 이름 등둝 μ œν•œ, μ—λŸ¬ λ©”μ„Έμ§€ 띄움 + - (μ™„λ£Œ)μ—­ λͺ©λ‘μ„ ν‘œλ‘œ 좜λ ₯ν•˜λ„λ‘ κ΅¬ν˜„ + - (μ™„λ£Œ)μ—­ μ‚­μ œ λ²„νŠΌ 클릭 μ‹œ ν•΄λ‹Ή μ—­ 제거(data 속성 ν™œμš©) + - (μ™„λ£Œ)μ—­ μ‚­μ œ λ²„νŠΌ 클릭 μ‹œ confirm μ°½ λ„μš°κΈ° + - (μ™„λ£Œ)μž…λ ₯값을 λͺ©λ‘μ— λ‹΄κΈ° 전에 μž…λ ₯κ°’μ˜ μ•žλ’€ 곡백을 제거 + - (μ™„λ£Œ)노선에 λ“±λ‘λœ 역은 μ‚­μ œ λΆˆκ°€ν•˜λ„λ‘ κ΅¬ν˜„ +- λ…Έμ„  관리 + - (μ™„λ£Œ)html string μž‘μ„± + - (μ™„λ£Œ)λ…Έμ„ μ˜ 정보λ₯Ό μ €μž₯ν•  수 μžˆλŠ” 자료ꡬ쑰λ₯Ό κ΅¬ν˜„ + - (μ™„λ£Œ)λ…Έμ„  이름과 쒅점 정보듀을 λ°›μ•„ λ…Έμ„  μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯ κ΅¬ν˜„ + - (μ™„λ£Œ)λ…Έμ„  λͺ©λ‘μ„ ν‘œλ‘œ 화면에 좜λ ₯ + - (μ™„λ£Œ)λ…Έμ„  이름이 ν•œ κΈ€μž 미만이면 μ—λŸ¬ λ©”μ„Έμ§€ 좜λ ₯ + - (μ™„λ£Œ)λ…Έμ„  이름이 쀑볡이면, 상행 쒅점과 ν•˜ν–‰ 쒅점이 같은 역이면 μ—λŸ¬ + - (μ™„λ£Œ)쒅점 정보가 μ„ νƒλ˜μ§€ μ•Šμ•˜λ‹€λ©΄ μ—λŸ¬ λ©”μ„Έμ§€ 좜λ ₯ + - (μ™„λ£Œ)μž…λ ₯값을 λͺ©λ‘μ— λ‹΄κΈ° 전에 μž…λ ₯κ°’μ˜ μ•žλ’€ 곡백을 제거 + - (μ™„λ£Œ)μ‚­μ œ λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ 노선이 μ‚­μ œλ˜λ„λ‘ κ΅¬ν˜„ + - (μ™„λ£Œ)노선이 μ‚­μ œλ˜κΈ° 이전에 comfirm 창을 λ„μš°κΈ° +- ꡬ간 관리 + - (μ™„λ£Œ)html string μž‘μ„± + - (μ™„λ£Œ)ꡬ간 μˆ˜μ •ν•  노선을 μ„ νƒν•˜λŠ” λ²„νŠΌ 생성 + - (μ™„λ£Œ)λ…Έμ„  선택 λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ λ…Έμ„  관리 UIκ°€ 생성됨 + - (μ™„λ£Œ)μ„ νƒλœ 노선에 ν¬ν•¨λ˜μ–΄ μžˆμ§€ μ•Šμ€ μ—­λ“€λ§Œ 콀보 λ°•μŠ€μ˜ μ˜΅μ…˜μœΌλ‘œ μ„€μ • + - (μ™„λ£Œ)노선에 λ“±λ‘λœ 역듀을 ν‘œλ‘œ 좜λ ₯ + - (μ™„λ£Œ)등둝 λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ μž…λ ₯받은 λ…Έμ„ μ˜ μˆœμ„œμ— 역이 좔가됨 + - (μ™„λ£Œ)μˆœμ„œ input textκ°€ 0 μ΄μƒμ˜ μˆ«μžκ°€ μ•„λ‹ˆλ©΄ μ—λŸ¬λ©”μ„Έμ§€ 생성 + - (μ™„λ£Œ)노선에 μΆ”κ°€ν•  역이 μ„ νƒλ˜μ§€ μ•Šμ•˜λ‹€λ©΄ μ—λŸ¬ λ©”μ„Έμ§€ 좜λ ₯ + - (μ™„λ£Œ)λ…Έμ„ μ—μ„œ 제거 λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ λ…Έμ„ μ—μ„œ ν•΄λ‹Ή 역이 μ œμ™Έλ¨ + - (μ™„λ£Œ)λ…Έμ„ μ—μ„œ 제거 λ™μž‘μ„ μˆ˜ν–‰ν•˜κΈ° 전에 confirm 창을 λ„μš°κΈ° + - (μ™„λ£Œ)노선에 ν¬ν•¨λœ 역이 2개 μ΄ν•˜μΌ λ•ŒλŠ” μ œκ±°ν•  수 없도둝 κ΅¬ν˜„ +- 노선도 좜λ ₯ + - (μ™„λ£Œ)html string μž‘μ„± + - (μ™„λ£Œ)노선도 정보λ₯Ό 받아와 좜λ ₯함 +- κ·Έ μ™Έμ˜ μΆ”κ°€ν•΄μ•Όν•  κΈ°λŠ₯λ“€ + - (μ™„λ£Œ)μ—­κ³Ό λ…Έμ„  정보λ₯Ό localStorageλ₯Ό μ΄μš©ν•˜μ—¬ μ €μž₯ + +## 😡 κ³ λ―Όν•΄μ•Όν•  사항듀 + +- ν™”λ©΄ μ „ν™˜μ€ μ–΄λ–»κ²Œ ν•  것인가 +- ν΄λž˜μŠ€λŠ” μ–΄λ–»κ²Œ λ‚˜λˆ„μ–΄μ•Ό ν• κΉŒ +- IOλ₯Ό ν•˜λ‚˜μ˜ ν΄λž˜μŠ€κ°€ μ΄κ΄„ν•˜λ„λ‘ ν•  것인가 λ‚˜λˆŒ 것인가 +- μ§€ν•˜μ²  μ—­κ³Ό 노선을 μ €μž₯ν•˜κΈ° μœ„ν•΄ μ–΄λ–€ 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•  것인가 +- μˆ˜ν–‰ν•˜λŠ” κΈ°λŠ₯이 λΉ„μŠ·ν•œ λ©”μ†Œλ“œλ“€μ„ μ–΄λ–»κ²Œ μ»΄ν¬λ„ŒνŠΈν™”ν•˜μ—¬ ν™œμš©ν•  것인가 +- λ©”μ†Œλ“œμ™€ λ³€μˆ˜ 이름을 μ–΄λ–»κ²Œ ν•΄μ•Ό 가독성 μ’‹κ²Œ μ •ν• μˆ˜ μžˆμ„κΉŒ diff --git a/docs/images/line-manager.png b/docs/images/line-manager.png new file mode 100644 index 000000000..78a981af8 Binary files /dev/null and b/docs/images/line-manager.png differ diff --git a/docs/images/map-print-manager.png b/docs/images/map-print-manager.png new file mode 100644 index 000000000..2e89a54da Binary files /dev/null and b/docs/images/map-print-manager.png differ diff --git a/docs/images/section-manager.png b/docs/images/section-manager.png new file mode 100644 index 000000000..84c0e0aee Binary files /dev/null and b/docs/images/section-manager.png differ diff --git a/docs/images/stations-manager.png b/docs/images/stations-manager.png new file mode 100644 index 000000000..fad405656 Binary files /dev/null and b/docs/images/stations-manager.png differ diff --git a/index.html b/index.html index fc99deac2..84953915d 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,11 @@

πŸš‡ μ§€ν•˜μ²  노선도 관리

+ +

+
+
diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..104414d89 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,949 @@ +{ + "name": "javascript-subway-map-precourse", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", + "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-google": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", + "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", + "dev": true + }, + "eslint-config-prettier": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.0.0.tgz", + "integrity": "sha512-8Y8lGLVPPZdaNA7JXqnvETVC7IiVRgAP6afQu9gOQRn90YY3otMNh+x7Vr2vMePQntF+5erdSUBqSzCmU/AxaQ==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz", + "integrity": "sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", + "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..5b34e6d68 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "javascript-subway-map-precourse", + "version": "1.0.0", + "description": "- μ§€ν•˜μ²  역을 λ“±λ‘ν•˜κ³  μ‚­μ œν•  수 μžˆλ‹€. (단, 노선에 λ“±λ‘λœ 역은 μ‚­μ œν•  수 μ—†λ‹€)\r - μ€‘λ³΅λœ μ§€ν•˜μ²  μ—­ 이름이 등둝될 수 μ—†λ‹€.\r - μ§€ν•˜μ²  역은 2κΈ€μž 이상이어야 ν•œλ‹€.\r - μ§€ν•˜μ²  μ—­μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€.", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/0307kwon/javascript-subway-map-precourse.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/0307kwon/javascript-subway-map-precourse/issues" + }, + "homepage": "https://github.com/0307kwon/javascript-subway-map-precourse#readme", + "devDependencies": { + "eslint": "^7.15.0", + "eslint-config-google": "^0.14.0", + "eslint-config-prettier": "^7.0.0", + "eslint-plugin-prettier": "^3.3.0", + "prettier": "^2.2.1" + } +} diff --git a/src/html-manager.js b/src/html-manager.js new file mode 100644 index 000000000..28b1f4f1f --- /dev/null +++ b/src/html-manager.js @@ -0,0 +1,44 @@ +import MenubarUI from "./ui/menubar-ui.js"; +import StationManagerUI from "./ui/contents-ui/station-manager-ui.js"; +import LineManagerUI from "./ui/contents-ui/line-manager-ui.js"; +import SectionManagerUI from "./ui/contents-ui/section-manager-ui.js"; +import MapPrintManagerUI from "./ui/contents-ui/map-print-manager-ui.js"; + +export default class HTMLManager { + constructor(subwayINFOManager) { + this._subwayINFOManager = subwayINFOManager; + this._menubarUI = new MenubarUI({ + htmlManager: this, + menubarID: MENUBAR_ID, + }); + this._contentsUI = null; + this.setContentsUIOnStationUI(); + } + setContentsUIOnStationUI() { + this._contentsUI = new StationManagerUI( + CONTENTS_ID, + this._subwayINFOManager + ); + } + setContentsUIOnSectionUI() { + this._contentsUI = new LineManagerUI( + CONTENTS_ID, + this._subwayINFOManager + ); + } + setContentsUIOnLineUI() { + this._contentsUI = new SectionManagerUI( + CONTENTS_ID, + this._subwayINFOManager + ); + } + setContentsUIOnMapPrintUI() { + this._contentsUI = new MapPrintManagerUI( + CONTENTS_ID, + this._subwayINFOManager + ); + } +} + +const MENUBAR_ID = "menubar"; +const CONTENTS_ID = "contents"; diff --git a/src/index.js b/src/index.js index e69de29bb..7f2f31324 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,5 @@ +import HTMLManager from "./html-manager.js"; +import SubwayINFOManager from "./subway-info-manager.js"; + +const subwayINFOManager = new SubwayINFOManager(); +new HTMLManager(subwayINFOManager); diff --git a/src/info-manager/line-info-manager.js b/src/info-manager/line-info-manager.js new file mode 100644 index 000000000..4976fcdcc --- /dev/null +++ b/src/info-manager/line-info-manager.js @@ -0,0 +1,97 @@ +import { hasNotOverlapName } from "../utility/input-check-utility.js"; +import { + saveToLocalStorage, + loadFromLocalStorage, +} from "../utility/storage-utility.js"; + +export default class LineINFOManager { + constructor(subwayINFOManager) { + this._lines = loadFromLocalStorage(ITEM_NAME_OF_LINES); + if (this._lines === null) { + this._lines = []; + } + this._subwayINFOManager = subwayINFOManager; + } + addNewLine({ lineName, startStationName, endStationName }) { + const newLine = this._makeNewLineByTemplate( + lineName, + startStationName, + endStationName + ); + this._lines.push(newLine); + saveToLocalStorage(ITEM_NAME_OF_LINES, this._lines); + } + deleteLine(nameToDelete) { + const lineIndexToDelete = this._lines.findIndex(({ name }) => { + return nameToDelete === name; + }); + if (lineIndexToDelete === -1) { + return; + } + this._lines.splice(lineIndexToDelete, 1); + saveToLocalStorage(ITEM_NAME_OF_LINES, this._lines); + } + deleteSection(targetStationName, targetLineName) { + const targetLine = this.getOneLineByName(targetLineName); + if (targetLine.stationsOfLine.length <= MINIMUM_NUMBER_STATIONS_OF_LINE) { + alert(NOT_MINIMUM_NUMBER_STATIONS_OF_LINE_ERROR_MESSAGE); + return; + } + this._deleteStationInLine(targetStationName, targetLineName); + saveToLocalStorage(ITEM_NAME_OF_LINES, this._lines); + } + getOneLineByName(name) { + for (let line of this._lines) { + if (line.name === name) { + return line; + } + } + return -1; + } + getAllLinesByCondition(condition) { + const returnlines = []; + this._lines.forEach((line) => { + if (condition(line)) { + returnlines.push(line); + } + }); + return returnlines; + } + getAllLines() { + return [...this._lines]; + } + hasNotOverlapNameAmongLines(inputName) { + const isValid = hasNotOverlapName(this._lines, inputName); + if (!isValid) { + alert(OVERLAP_LINE_ERROR_MESSAGE); + } + return isValid; + } + registerStationToLine(lineName, orderToRegister, stationName) { + const targetLine = this.getOneLineByName(lineName); + targetLine.stationsOfLine.splice(orderToRegister, 0, stationName); + saveToLocalStorage(ITEM_NAME_OF_LINES, this._lines); + } + + _deleteStationInLine(targetStationName, targetLineName) { + const targetLine = this.getOneLineByName(targetLineName); + const targetStationIndex = targetLine.stationsOfLine.findIndex( + (stationName) => { + return stationName === targetStationName; + } + ); + targetLine.stationsOfLine.splice(targetStationIndex, 1); + } + _makeNewLineByTemplate(lineName, startStationName, endStationName) { + return { + name: lineName, + stationsOfLine: [startStationName, endStationName], + }; + } +} + +const MINIMUM_NUMBER_STATIONS_OF_LINE = 2; +const NOT_MINIMUM_NUMBER_STATIONS_OF_LINE_ERROR_MESSAGE = `λ…Έμ„ μ—λŠ” μ΅œμ†Œ ${MINIMUM_NUMBER_STATIONS_OF_LINE}개의 역이 ν¬ν•¨λ˜μ–΄ μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.`; +const OVERLAP_LINE_ERROR_MESSAGE = "κΈ°μ‘΄ λ…Έμ„  이름과 μ€‘λ³΅λ˜λŠ” μ΄λ¦„μž…λ‹ˆλ‹€."; + +const ITEM_NAME_OF_LINES = "lines"; diff --git a/src/info-manager/station-info-manager.js b/src/info-manager/station-info-manager.js new file mode 100644 index 000000000..a07e7027d --- /dev/null +++ b/src/info-manager/station-info-manager.js @@ -0,0 +1,80 @@ +import { hasNotOverlapName } from "../utility/input-check-utility.js"; +import { + saveToLocalStorage, + loadFromLocalStorage, +} from "../utility/storage-utility.js"; + +export default class StationINFOManager { + constructor(subwayINFOManager) { + this._stations = loadFromLocalStorage(ITEM_NAME_OF_STATIONS); + if (this._stations === null) { + this._stations = []; + } + this._subwayINFOManager = subwayINFOManager; + } + addNewStation({ name }) { + const newStation = this._makeNewStationByTemplate(name); + this._stations.push(newStation); + saveToLocalStorage(ITEM_NAME_OF_STATIONS, this._stations); + } + deleteStation(nameToDelete, lines) { + const stationIndexToDelete = this._stations.findIndex(({ name }) => { + return nameToDelete === name; + }); + const isRegistedStationInLine = this._hasRegistedStationInLine( + nameToDelete, + lines + ); + if (isRegistedStationInLine) { + alert(STATION_INCLUDE_IN_LINE_ERROR_MESSAGE); + return; + } + this._stations.splice(stationIndexToDelete, 1); + saveToLocalStorage(ITEM_NAME_OF_STATIONS, this._stations); + } + getOneStationByName(name) { + for (let station of this._stations) { + if (station.name === name) { + return station; + } + } + return -1; + } + getAllStationNames() { + const stationNames = []; + this._stations.forEach(({ name }) => { + stationNames.push(name); + }); + return stationNames; + } + getAllStations() { + return [...this._stations]; + } + hasNotOverlapNameAmongStations(inputName) { + const isNotOverlapName = hasNotOverlapName(this._stations, inputName); + if (!isNotOverlapName) { + alert(OVERLAP_STATION_ERROR_MESSAGE); + } + return isNotOverlapName; + } + + _makeNewStationByTemplate(stationName) { + return { + name: stationName, + }; + } + _hasRegistedStationInLine(stationName, lines) { + const isRegistedStationInLine = lines.some((line) => { + const indexToEqualStationName = line.stationsOfLine.findIndex((name) => { + return name === stationName; + }); + return indexToEqualStationName !== -1; + }); + return isRegistedStationInLine; + } +} + +const OVERLAP_STATION_ERROR_MESSAGE = "κΈ°μ‘΄ μ—­ 이름과 μ€‘λ³΅λ˜λŠ” μ΄λ¦„μž…λ‹ˆλ‹€."; +const STATION_INCLUDE_IN_LINE_ERROR_MESSAGE = `1개 μ΄μƒμ˜ 노선에 ν¬ν•¨λ˜μ–΄ μžˆλŠ” 역은 μ‚­μ œν•  수 μ—†μŠ΅λ‹ˆλ‹€.`; + +const ITEM_NAME_OF_STATIONS = "stations"; diff --git a/src/subway-info-manager.js b/src/subway-info-manager.js new file mode 100644 index 000000000..9e60eccd7 --- /dev/null +++ b/src/subway-info-manager.js @@ -0,0 +1,16 @@ +import StationINFOManager from "./info-manager/station-info-manager.js"; +import LineINFOManager from "./info-manager/line-info-manager.js"; + +export default class SubwayINFOManager { + constructor() { + this._stationINFOManager = new StationINFOManager(this); + this._lineINFOManager = new LineINFOManager(this); + } + + getStationINFOManager() { + return this._stationINFOManager; + } + getLineINFOManager() { + return this._lineINFOManager; + } +} diff --git a/src/ui/contents-ui/contents-ui.js b/src/ui/contents-ui/contents-ui.js new file mode 100644 index 000000000..8ba538e89 --- /dev/null +++ b/src/ui/contents-ui/contents-ui.js @@ -0,0 +1,36 @@ +export class contentsUI { + constructor(contentsID, subwayINFOManager) { + this._contentsID = contentsID; + this._subwayINFOManager = subwayINFOManager; + this._stationINFOManager = this._subwayINFOManager.getStationINFOManager(); + this._lineINFOManager = this._subwayINFOManager.getLineINFOManager(); + } + setContentsHTML(initialTemplate) { + document.getElementById(this._contentsID).innerHTML = initialTemplate; + } + + _getInputTextByID(id) { + return document.getElementById(id).value.trim(); + } + _getAllElementsByClass(className) { + return document.querySelectorAll("." + className); + } + _getSelectedOptionByID(id) { + const selector = document.getElementById(id); + return selector[selector.selectedIndex].value; + } + _addClickEventToButtonByID(id, callback) { + const button = document.getElementById(id); + button.addEventListener("click", () => { + callback.call(this); + }); + } + _addClickEventToAllButtonByClassName(className, callback) { + const buttons = document.querySelectorAll("." + className); + Array.prototype.forEach.call(buttons, (button) => { + button.addEventListener("click", (event) => { + callback.call(this, event); + }); + }); + } +} diff --git a/src/ui/contents-ui/line-manager-ui.js b/src/ui/contents-ui/line-manager-ui.js new file mode 100644 index 000000000..05cb87756 --- /dev/null +++ b/src/ui/contents-ui/line-manager-ui.js @@ -0,0 +1,137 @@ +import { + DELETE_CONFIRM_MESSAGE, + SELECTOR_DEFAULT_TEMPLATE, +} from "../../utility/share-constant-utility.js"; +import { + hasValidLine, + hasValidOption, +} from "../../utility/input-check-utility.js"; +import { contentsUI } from "./contents-ui.js"; + +export default class LineManagerUI extends contentsUI { + constructor(contentsID, subwayINFOManager) { + super(contentsID, subwayINFOManager); + this.setContentsHTML(INITIAL_TEMPLATE); + } + setContentsHTML(initialTemplate) { + super.setContentsHTML(initialTemplate); + this._setStationSelector(START_STATION_SELECTOR_ID); + this._setStationSelector(END_STATION_SELECTOR_ID); + this._addEventToLineAddButton(); + this.updateLinesTable(); + } + updateLinesTable() { + const lines = this._lineINFOManager.getAllLines(); + const tableContainer = document.getElementById(TABLE_ID); + let innerHTMLOfTable = TABLE_HEADER_TEMPLATE; + lines.forEach((lineINFOs) => { + innerHTMLOfTable += this._makeNewTableRowHTML(lineINFOs); + }); + tableContainer.innerHTML = innerHTMLOfTable; + this._addEventToAllTableDeleteButton(); + } + + _setStationSelector(selectorID) { + const selector = document.getElementById(selectorID); + selector.innerHTML = this._makeSelectorInnerHTML(); + } + _addEventToLineAddButton() { + this._addClickEventToButtonByID( + LINE_ADD_BUTTON_ID, + this._callbackLineAddButton + ); + } + _addEventToAllTableDeleteButton() { + this._addClickEventToAllButtonByClassName( + LINE_DELETE_BUTTON_CLASS, + this._callbackOfDeleteButton + ); + } + _callbackLineAddButton() { + const lineName = this._getInputTextByID(NAME_INPUT_ID); + const startStation = this._getSelectedOptionByID(START_STATION_SELECTOR_ID); + const endStation = this._getSelectedOptionByID(END_STATION_SELECTOR_ID); + if (!this._hasValidLineInput(lineName, startStation, endStation)) { + return; + } + this._lineINFOManager.addNewLine({ + lineName: lineName, + startStationName: startStation, + endStationName: endStation, + }); + this.updateLinesTable(); + } + _callbackOfDeleteButton(event) { + if (!confirm(DELETE_CONFIRM_MESSAGE)) { + return; + } + this._lineINFOManager.deleteLine(event.target.dataset.name); + this.updateLinesTable(); + } + _hasValidLineInput(lineName, startStationName, endStationName) { + const isValidLine = hasValidLine( + lineName, + startStationName, + endStationName + ); + const isNotOverlapName = this._lineINFOManager.hasNotOverlapNameAmongLines( + lineName + ); + const isValidOption = hasValidOption([startStationName, endStationName]); + return isValidLine && isNotOverlapName && isValidOption; + } + _makeNewTableRowHTML({ name, stationsOfLine }) { + return ` + + ${name} + ${stationsOfLine[0]} + ${stationsOfLine[stationsOfLine.length - 1]} + + + + + `; + } + _makeSelectorInnerHTML() { + const stationNames = this._stationINFOManager.getAllStationNames(); + let selectorInnerHTML = SELECTOR_DEFAULT_TEMPLATE; + stationNames.forEach((name) => { + selectorInnerHTML += this._makeNewSelectorOptionHTML(name); + }); + return selectorInnerHTML; + } + _makeNewSelectorOptionHTML(name) { + return ` + + `; + } +} +const NAME_INPUT_ID = "line-name-input"; +const START_STATION_SELECTOR_ID = "line-start-station-selector"; +const END_STATION_SELECTOR_ID = "line-end-station-selector"; +const LINE_ADD_BUTTON_ID = "line-add-button"; +const TABLE_ID = "line-table"; +const LINE_DELETE_BUTTON_CLASS = "line-delete-button"; + +const INITIAL_TEMPLATE = ` +λ…Έμ„  이름
+ +

+상행 쒅점 +
+ν•˜ν–‰ 쒅점 + +

+ +

πŸš‰ μ§€ν•˜μ²  λ…Έμ„  λͺ©λ‘

+ +
+`; +const TABLE_HEADER_TEMPLATE = ` +λ…Έμ„  이름 +상행 쒅점역 +ν•˜ν–‰ 쒅점역 +μ„€μ • +`; diff --git a/src/ui/contents-ui/map-print-manager-ui.js b/src/ui/contents-ui/map-print-manager-ui.js new file mode 100644 index 000000000..7559e88db --- /dev/null +++ b/src/ui/contents-ui/map-print-manager-ui.js @@ -0,0 +1,37 @@ +import { contentsUI } from "./contents-ui.js"; + +export default class MapPrintManagerUI extends contentsUI { + constructor(contentsID, subwayINFOManager) { + super(contentsID, subwayINFOManager); + this.setContentsHTML(""); + } + setContentsHTML(initialTemplate) { + const lines = this._lineINFOManager.getAllLines(); + lines.forEach((line) => { + initialTemplate += this._makeLineINFOHTML(line); + }); + super.setContentsHTML(initialTemplate); + } + + _makeLineINFOHTML(line) { + const stationListHTML = this._makeStationListHTML(line); + const infoHTML = ` +
+

${line.name}

+ +
+ `; + return infoHTML; + } + _makeStationListHTML(line) { + let listHTML = ""; + line.stationsOfLine.forEach((station) => { + listHTML += `
  • ${station}
  • `; + }); + return listHTML; + } +} + +const MAP_CLASS = "map"; diff --git a/src/ui/contents-ui/section-manager-ui.js b/src/ui/contents-ui/section-manager-ui.js new file mode 100644 index 000000000..083f27742 --- /dev/null +++ b/src/ui/contents-ui/section-manager-ui.js @@ -0,0 +1,184 @@ +import { + hasValidOrder, + hasValidOption, +} from "../../utility/input-check-utility.js"; +import { DELETE_CONFIRM_MESSAGE } from "../../utility/share-constant-utility.js"; +import { SELECTOR_DEFAULT_TEMPLATE } from "../../utility/share-constant-utility.js"; +import { contentsUI } from "./contents-ui.js"; + +export default class SectionManagerUI extends contentsUI { + constructor(contentsID, subwayINFOManager) { + super(contentsID, subwayINFOManager); + this._sectionRegisterUI = null; + this.setContentsHTML(INITIAL_TEMPLATE); + } + setContentsHTML(initialTemplate) { + super.setContentsHTML(initialTemplate); + this._updateLineButtons(); + } + + _updateLineButtons() { + const buttonDiv = document.getElementById(SECTION_LINE_MENU_DIV_ID); + const lines = this._lineINFOManager.getAllLines(); + let buttonDivInnerHTML = ""; + lines.forEach(({ name }) => { + buttonDivInnerHTML += this._makeNewSelectLineButtonHTML(name); + }); + buttonDiv.innerHTML = buttonDivInnerHTML; + this._addEventToSelectLineButton(); + } + _addEventToSelectLineButton() { + const buttons = this._getAllElementsByClass(SECTION_LINE_MENU_BUTTON_CLASS); + Array.prototype.forEach.call(buttons, (button) => { + button.addEventListener("click", (e) => { + this._sectionRegisterUI = new SectionRegisterUI( + SECTION_REGISTER_DIV_ID, + this._subwayINFOManager, + e.target.dataset.name + ); + }); + }); + } + _makeNewSelectLineButtonHTML(name) { + return ` + + `; + } +} + +class SectionRegisterUI extends contentsUI { + constructor(contentsID, subwayINFOManager, lineName) { + super(contentsID, subwayINFOManager); + this._lineName = lineName; + this.setContentsHTML(SECTION_REGISTER_TEMPLATE); + } + setContentsHTML(initialTemplate) { + initialTemplate = this._makeTitleHTML(this._lineName) + initialTemplate; + super.setContentsHTML(initialTemplate); + this._addEventToSectionAddButton(); + this.updateAllContents(); + } + updateAllContents() { + this._setComboboxOption(); + this.updateLineStationsTable(); + } + updateLineStationsTable() { + const table = document.getElementById(SECTION_REGISTER_TABLE_ID); + const myLine = this._lineINFOManager.getAllLinesByCondition((line) => { + return line.name === this._lineName; + })[0]; + let tableInnerHTML = TABLE_HEADER_TEMPLATE; + myLine.stationsOfLine.forEach((station, order) => { + tableInnerHTML += this._makeNewTableRowHTML(order, station); + }); + table.innerHTML = tableInnerHTML; + this._addEventToAllDeleteButtons(); + } + + _addEventToAllDeleteButtons() { + this._addClickEventToAllButtonByClassName( + SECTION_DELETE_BUTTON_CLASS, + this._callbackOfDeleteButton + ); + } + _addEventToSectionAddButton() { + this._addClickEventToButtonByID( + SECTION_ADD_BUTTON_ID, + this._callbackOfSectionAddButton + ); + } + _callbackOfDeleteButton(event) { + if (!confirm(DELETE_CONFIRM_MESSAGE)) { + return; + } + const targetStationName = event.target.dataset.name; + this._lineINFOManager.deleteSection(targetStationName, this._lineName); + this.updateAllContents(); + } + _callbackOfSectionAddButton() { + const orderToRegister = this._getInputTextByID(SECTION_ORDER_INPUT_ID); + const stationName = this._getSelectedOptionByID( + SECTION_STATION_SELECTOR_ID + ); + if (!this._hasValidSectionAddInput(orderToRegister, stationName)) { + return; + } + this._lineINFOManager.registerStationToLine( + this._lineName, + orderToRegister, + stationName + ); + this.updateAllContents(); + } + _hasValidSectionAddInput(orderToRegister, stationName) { + const isValidOrder = hasValidOrder(orderToRegister); + const isValidOption = hasValidOption([stationName]); + return isValidOrder && isValidOption; + } + _setComboboxOption() { + const seletor = document.getElementById(SECTION_STATION_SELECTOR_ID); + const optionNames = this._stationINFOManager.getAllStationNames(); + const currentLine = this._lineINFOManager.getOneLineByName(this._lineName); + currentLine.stationsOfLine.forEach((stationName) => { + const index = optionNames.findIndex((name) => name === stationName); + optionNames.splice(index, 1); + }); + let seletorInnerHTML = SELECTOR_DEFAULT_TEMPLATE; + optionNames.forEach((optionName) => { + seletorInnerHTML += this._makeNewOptionHTML(optionName); + }); + seletor.innerHTML = seletorInnerHTML; + } + _makeNewOptionHTML(name) { + return ` + + `; + } + _makeTitleHTML(name) { + return `

    ${name} 관리

    `; + } + _makeNewTableRowHTML(order, name) { + return ` + + ${order} + ${name} + + + + + `; + } +} + +const SECTION_REGISTER_DIV_ID = "section-register-div"; +const SECTION_STATION_SELECTOR_ID = "section-station-selector"; +const SECTION_REGISTER_TABLE_ID = "section-register-table"; +const SECTION_ORDER_INPUT_ID = "section-order-input"; +const SECTION_ADD_BUTTON_ID = "section-add-button"; +const SECTION_DELETE_BUTTON_CLASS = "section-delete-button"; +const SECTION_LINE_MENU_DIV_ID = "section-line-menu-div"; +const SECTION_LINE_MENU_BUTTON_CLASS = "section-line-menu-button"; + +const INITIAL_TEMPLATE = ` +

    ꡬ간을 μˆ˜μ •ν•  노선을 μ„ νƒν•΄μ£Όμ„Έμš”.

    +
    +
    +
    +
    +`; +const TABLE_HEADER_TEMPLATE = ` +μˆœμ„œ +이름 +μ„€μ • +`; +const SECTION_REGISTER_TEMPLATE = ` +

    ꡬ간 등둝

    +

    + + + +

    + +
    +`; diff --git a/src/ui/contents-ui/station-manager-ui.js b/src/ui/contents-ui/station-manager-ui.js new file mode 100644 index 000000000..fb860d97c --- /dev/null +++ b/src/ui/contents-ui/station-manager-ui.js @@ -0,0 +1,90 @@ +import { hasValidStationName } from "../../utility/input-check-utility.js"; +import { DELETE_CONFIRM_MESSAGE } from "../../utility/share-constant-utility.js"; +import { contentsUI } from "./contents-ui.js"; + +export default class StationManagerUI extends contentsUI { + constructor(contentsID, subwayINFOManager) { + super(contentsID, subwayINFOManager); + this.setContentsHTML(INITIAL_TEMPLATE); + } + setContentsHTML(initialTemplate) { + super.setContentsHTML(initialTemplate); + this._addEventToNameInputButton(); + this.updateStationsTable(); + } + updateStationsTable() { + const stationsNames = this._stationINFOManager.getAllStationNames(); + const tableContainer = document.getElementById(STATION_NAME_TABLE_ID); + let innerHTMLOfTable = TABLE_HEADER_TEMPLATE; + for (let name of stationsNames) { + innerHTMLOfTable += this._makeNewTableRowHTML(name); + } + tableContainer.innerHTML = innerHTMLOfTable; + this._addEventToAllTableDeleteButton(); + } + + _addEventToNameInputButton() { + this._addClickEventToButtonByID( + STATION_ADD_BUTTON_ID, + this._callbackOfNameInputButton + ); + } + _addEventToAllTableDeleteButton() { + this._addClickEventToAllButtonByClassName( + STATION_DELETE_BUTTON_CLASS, + this._callbackOfTableDeleteButton + ); + } + _callbackOfNameInputButton() { + const name = this._getInputTextByID(STATION_NAME_INPUT_ID); + if (!this._hasValidStationInput(name)) { + return; + } + this._stationINFOManager.addNewStation({ + name: name, + }); + this.updateStationsTable(); + } + _callbackOfTableDeleteButton(event) { + if (!confirm(DELETE_CONFIRM_MESSAGE)) { + return; + } + const lines = this._lineINFOManager.getAllLines(); + this._stationINFOManager.deleteStation(event.target.dataset.name, lines); + this.updateStationsTable(); + } + _hasValidStationInput(name) { + const isValidStationName = hasValidStationName(name); + const isNotOverlapName = this._stationINFOManager.hasNotOverlapNameAmongStations( + name + ); + return isValidStationName && isNotOverlapName; + } + _makeNewTableRowHTML(name) { + return ` + + ${name} + + + + + `; + } +} +const STATION_NAME_INPUT_ID = "station-name-input"; +const STATION_ADD_BUTTON_ID = "station-add-button"; +const STATION_NAME_TABLE_ID = "station-name-table"; +const STATION_DELETE_BUTTON_CLASS = "station-delete-button"; + +const INITIAL_TEMPLATE = ` +μ—­ 이름
    + + +

    πŸš‰ μ§€ν•˜μ²  μ—­ λͺ©λ‘

    + +
    +`; +const TABLE_HEADER_TEMPLATE = ` +μ—­ 이름 +μ„€μ • +`; diff --git a/src/ui/menubar-ui.js b/src/ui/menubar-ui.js new file mode 100644 index 000000000..7cef557a1 --- /dev/null +++ b/src/ui/menubar-ui.js @@ -0,0 +1,51 @@ +export default class MenubarUI { + constructor({ htmlManager, menubarID }) { + this._htmlManager = htmlManager; + this._menubarID = menubarID; + this.setMenubar(); + } + setMenubar() { + document.getElementById(this._menubarID).innerHTML = MENU_TEMPLATE; + this._addEventToStationButton(); + this._addEventToLineButton(); + this._addEventToSectionButton(); + this._addEventToMapPrintButton(); + } + + _addEventToStationButton() { + const button = document.getElementById(STATION_ID); + button.addEventListener("click", () => { + this._htmlManager.setContentsUIOnStationUI(); + }); + } + _addEventToLineButton() { + const button = document.getElementById(LINE_ID); + button.addEventListener("click", () => { + this._htmlManager.setContentsUIOnSectionUI(); + }); + } + _addEventToSectionButton() { + const button = document.getElementById(SECTION_ID); + button.addEventListener("click", () => { + this._htmlManager.setContentsUIOnLineUI(); + }); + } + _addEventToMapPrintButton() { + const button = document.getElementById(MAP_PRINT_ID); + button.addEventListener("click", () => { + this._htmlManager.setContentsUIOnMapPrintUI(); + }); + } +} + +const STATION_ID = "station-manager-button"; +const LINE_ID = "line-manager-button"; +const SECTION_ID = "section-manager-button"; +const MAP_PRINT_ID = "map-print-manager-button"; + +const MENU_TEMPLATE = ` + + + + +`; diff --git a/src/utility/input-check-utility.js b/src/utility/input-check-utility.js new file mode 100644 index 000000000..9ac11b17a --- /dev/null +++ b/src/utility/input-check-utility.js @@ -0,0 +1,104 @@ +import { SELECTEOR_NONE } from "./share-constant-utility.js"; + +export function hasValidStationName(name) { + const isValidLength = hasSatisfiedMinLengthCondition({ + operandLength: name.length, + minLength: MINIMUM_LENGTH_OF_STATION_NAME, + errorMessage: MINIMUM_LENGTH_STATION_NAME_ERROR_MESSAGE, + }); + return isValidLength; +} +export function hasValidLine(name, startStationName, endStationName) { + const isValidLength = hasSatisfiedMinLengthCondition({ + operandLength: name.length, + minLength: MINIMUM_LENGTH_OF_LINE_NAME, + errorMessage: MINIMUM_LENGTH_LINE_NAME_ERROR_MESSAGE, + }); + const isNotEqualName = hasNotEqualName({ + operand1: startStationName, + operand2: endStationName, + errorMessage: HAS_EQUAL_NAME_ERROR_MESSAGE, + }); + return isValidLength && isNotEqualName; +} +export function hasValidOrder(order) { + const isTypeOfNumber = hasTypeOfNumber({ + operand: order, + errorMessage: NOT_TYPE_OF_NUMBER_ERROR_MESSAGE, + }); + const isSatisfyLengthCondition = hasSatisfiedMinLengthCondition({ + operandLength: Number(order), + minLength: MINIMUM_VAILD_ORDER, + errorMessage: LESS_THAN_MINIMUM_ORDER_ERROR_MESSAGE, + }); + return isTypeOfNumber && isSatisfyLengthCondition; +} +export function hasValidOption(inputOptions) { + let retBool = true; + for (let inputOption of inputOptions) { + if (inputOption === SELECTEOR_NONE) { + alert(NOT_SELECTED_OPTION_ERROR_MESSAGE); + retBool = false; + break; + } + } + return retBool; +} +export function hasSatisfiedMinLengthCondition({ + operandLength, + minLength, + errorMessage, +}) { + let boolToReturn = true; + if (operandLength < minLength) { + alert(errorMessage); + boolToReturn = false; + } + return boolToReturn; +} +export function hasSatisfiedMaxLengthCondition({ + operandLength, + maxLength, + errorMessage, +}) { + let boolToReturn = true; + if (operandLength > maxLength) { + alert(errorMessage); + boolToReturn = false; + } + return boolToReturn; +} +export function hasNotOverlapName(targetToFindOverlap, inputName) { + const overlapIndex = targetToFindOverlap.findIndex( + ({ name }) => name === inputName + ); + return overlapIndex === -1; +} + +function hasTypeOfNumber({ operand, errorMessage }) { + let retBool = true; + if (operand === "") { + alert(errorMessage); + retBool = false; + } + return retBool; +} +function hasNotEqualName({ operand1, operand2, errorMessage }) { + let isNotEqualName = true; + if (operand1 === operand2) { + alert(errorMessage); + isNotEqualName = false; + } + return isNotEqualName; +} + +const MINIMUM_LENGTH_OF_STATION_NAME = 2; +const MINIMUM_LENGTH_OF_LINE_NAME = 1; +const MINIMUM_VAILD_ORDER = 0; + +const MINIMUM_LENGTH_STATION_NAME_ERROR_MESSAGE = `μ—­ 이름은 μ΅œμ†Œ ${MINIMUM_LENGTH_OF_STATION_NAME} κΈ€μžμ—¬μ•Ό ν•©λ‹ˆλ‹€.`; +const MINIMUM_LENGTH_LINE_NAME_ERROR_MESSAGE = `λ…Έμ„  이름은 μ΅œμ†Œ ${MINIMUM_LENGTH_OF_LINE_NAME} κΈ€μžμ—¬μ•Ό ν•©λ‹ˆλ‹€.`; +const NOT_TYPE_OF_NUMBER_ERROR_MESSAGE = "숫자λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”."; +const LESS_THAN_MINIMUM_ORDER_ERROR_MESSAGE = `μˆœμ„œκ°’μ€ μ΅œμ†Œ ${MINIMUM_VAILD_ORDER} 이상이어야 ν•©λ‹ˆλ‹€.`; +const HAS_EQUAL_NAME_ERROR_MESSAGE = `상행 쒅점과 ν•˜ν–‰ 쒅점이 같은 μ—­μž…λ‹ˆλ‹€.`; +const NOT_SELECTED_OPTION_ERROR_MESSAGE = "μ½€λ³΄λ°•μŠ€μ˜ μ˜΅μ…˜μ„ μ„ νƒν•΄μ£Όμ„Έμš”."; diff --git a/src/utility/share-constant-utility.js b/src/utility/share-constant-utility.js new file mode 100644 index 000000000..3e455f61f --- /dev/null +++ b/src/utility/share-constant-utility.js @@ -0,0 +1,5 @@ +export const SELECTEOR_NONE = "none"; +export const SELECTOR_DEFAULT_TEMPLATE = ` + +`; +export const DELETE_CONFIRM_MESSAGE = "μ •λ§λ‘œ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?"; diff --git a/src/utility/storage-utility.js b/src/utility/storage-utility.js new file mode 100644 index 000000000..7f8c8f9a7 --- /dev/null +++ b/src/utility/storage-utility.js @@ -0,0 +1,9 @@ +export function saveToLocalStorage(itemName, objectToSave) { + const jsonForm = JSON.stringify(objectToSave); + localStorage.setItem(itemName, jsonForm); +} + +export function loadFromLocalStorage(itemName) { + let objectToLoad = JSON.parse(localStorage.getItem(itemName)); + return objectToLoad; +}