diff --git "a/\353\260\225\354\247\200\355\231\230/README.md" "b/\353\260\225\354\247\200\355\231\230/README.md" new file mode 100644 index 0000000..b685a84 --- /dev/null +++ "b/\353\260\225\354\247\200\355\231\230/README.md" @@ -0,0 +1,5 @@ +테스트 코드에서 아래 문장 때문에 오류가 발생하여 2번 문장으로 수정했습니다. + +before) import assert from 'assert'; + +after) import * as assert from 'assert'; \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/book-edit.html" "b/\353\260\225\354\247\200\355\231\230/ex1/book-edit.html" index e69de29..2c111bd 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex1/book-edit.html" +++ "b/\353\260\225\354\247\200\355\231\230/ex1/book-edit.html" @@ -0,0 +1,121 @@ + + + + + + + + +
+ +
+ + BookMark + for Digital Hana路 +
+
+
+ +
+ +
+
+
+ +
+
+

Categories

+ +
+ +
+
+ +
+

Study

+ +
+ +
+
+
+ + + + diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/index.html" "b/\353\260\225\354\247\200\355\231\230/ex1/index.html" index e69de29..d9b4a6a 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex1/index.html" +++ "b/\353\260\225\354\247\200\355\231\230/ex1/index.html" @@ -0,0 +1,58 @@ + + + + + + + + +
+
+
+
BookMark
+
for Digital Hana路
+
+
+ +
+ +
|
+
SignIn
+
+
+
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+

There is no marks.

+
+
+ + + + \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/register.html" "b/\353\260\225\354\247\200\355\231\230/ex1/register.html" index e69de29..eaf6117 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex1/register.html" +++ "b/\353\260\225\354\247\200\355\231\230/ex1/register.html" @@ -0,0 +1,35 @@ + + + + + + + + +
+

회원가입

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+

이미 계정이 있으신가요? 로그인

+
+
+ + \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Bold.ttf" "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Bold.ttf" new file mode 100644 index 0000000..4520094 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Bold.ttf" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-CM.ttf" "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-CM.ttf" new file mode 100644 index 0000000..1a3cf30 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-CM.ttf" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Heavy.ttf" "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Heavy.ttf" new file mode 100644 index 0000000..2b5e943 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Heavy.ttf" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Light.ttf" "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Light.ttf" new file mode 100644 index 0000000..48a0d38 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Light.ttf" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Medium.ttf" "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Medium.ttf" new file mode 100644 index 0000000..33ea660 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Medium.ttf" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Regular.ttf" "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Regular.ttf" new file mode 100644 index 0000000..860ce08 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/Hana2.0_TTF/Hana2-Regular.ttf" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_alpaca.jpg" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_alpaca.jpg" new file mode 100644 index 0000000..52fda43 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_alpaca.jpg" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_coupang.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_coupang.png" new file mode 100644 index 0000000..526f792 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_coupang.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_hana.svg" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_hana.svg" new file mode 100644 index 0000000..0f8fae3 --- /dev/null +++ "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_hana.svg" @@ -0,0 +1 @@ + \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_js.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_js.png" new file mode 100644 index 0000000..0b1aef1 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_js.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_kakao.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_kakao.png" new file mode 100644 index 0000000..b65b1c8 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_kakao.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_naver.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_naver.png" new file mode 100644 index 0000000..0fc7b98 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_naver.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_reset.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_reset.png" new file mode 100644 index 0000000..b9fb085 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_reset.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_save.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_save.png" new file mode 100644 index 0000000..8dc320c Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_save.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_ts.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_ts.png" new file mode 100644 index 0000000..27221d3 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_ts.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/img_youtube.png" "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_youtube.png" new file mode 100644 index 0000000..035a2a7 Binary files /dev/null and "b/\353\260\225\354\247\200\355\231\230/ex1/src/img_youtube.png" differ diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/input.css" "b/\353\260\225\354\247\200\355\231\230/ex1/src/input.css" new file mode 100644 index 0000000..f15d154 --- /dev/null +++ "b/\353\260\225\354\247\200\355\231\230/ex1/src/input.css" @@ -0,0 +1,14 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@font-face { + font-family: "hana-regular"; + src: url("Hana2.0_TTF/Hana2-Regular.ttf") + format("truetype"); +} +@font-face { + font-family: "hana-bold"; + src: url("Hana2.0_TTF/Hana2-Bold.ttf") + format("truetype"); +} \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/src/output.css" "b/\353\260\225\354\247\200\355\231\230/ex1/src/output.css" new file mode 100644 index 0000000..4743cae --- /dev/null +++ "b/\353\260\225\354\247\200\355\231\230/ex1/src/output.css" @@ -0,0 +1,1013 @@ +/* +! tailwindcss v3.4.11 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.ml-3 { + margin-left: 0.75rem; +} + +.mt-1 { + margin-top: 0.25rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.line-clamp-1 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +.block { + display: block; +} + +.flex { + display: flex; +} + +.h-10 { + height: 2.5rem; +} + +.h-4 { + height: 1rem; +} + +.h-5 { + height: 1.25rem; +} + +.h-8 { + height: 2rem; +} + +.h-screen { + height: 100vh; +} + +.min-h-screen { + min-height: 100vh; +} + +.w-1\/2 { + width: 50%; +} + +.w-1\/3 { + width: 33.333333%; +} + +.w-1\/4 { + width: 25%; +} + +.w-10 { + width: 2.5rem; +} + +.w-4 { + width: 1rem; +} + +.w-5 { + width: 1.25rem; +} + +.w-8 { + width: 2rem; +} + +.w-full { + width: 100%; +} + +.flex-1 { + flex: 1 1 0%; +} + +.transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.flex-col { + flex-direction: column; +} + +.items-end { + align-items: flex-end; +} + +.items-center { + align-items: center; +} + +.justify-start { + justify-content: flex-start; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.space-x-2 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-x-5 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1.25rem * var(--tw-space-x-reverse)); + margin-left: calc(1.25rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-y-3 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); +} + +.space-y-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); +} + +.rounded { + border-radius: 0.25rem; +} + +.rounded-full { + border-radius: 9999px; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-md { + border-radius: 0.375rem; +} + +.border { + border-width: 1px; +} + +.border-b-4 { + border-bottom-width: 4px; +} + +.border-t-2 { + border-top-width: 2px; +} + +.border-t-4 { + border-top-width: 4px; +} + +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.border-hana-green { + --tw-border-opacity: 1; + border-color: rgb(2 147 119 / var(--tw-border-opacity)); +} + +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.bg-hana-green { + --tw-bg-opacity: 1; + background-color: rgb(2 147 119 / var(--tw-bg-opacity)); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.p-3 { + padding: 0.75rem; +} + +.p-4 { + padding: 1rem; +} + +.p-5 { + padding: 1.25rem; +} + +.p-8 { + padding: 2rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.text-center { + text-align: center; +} + +.font-hana_regular { + font-family: hana-regular; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + +.font-bold { + font-weight: 700; +} + +.font-medium { + font-weight: 500; +} + +.font-semibold { + font-weight: 600; +} + +.leading-none { + line-height: 1; +} + +.text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} + +.text-hana-green { + --tw-text-opacity: 1; + color: rgb(2 147 119 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.shadow-lg { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-sm { + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.transition-all { + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.transition-transform { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.duration-300 { + transition-duration: 300ms; +} + +@font-face { + font-family: "hana-regular"; + + src: url("Hana2.0_TTF/Hana2-Regular.ttf") + format("truetype"); +} + +@font-face { + font-family: "hana-bold"; + + src: url("Hana2.0_TTF/Hana2-Bold.ttf") + format("truetype"); +} + +.hover\:scale-105:hover { + --tw-scale-x: 1.05; + --tw-scale-y: 1.05; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:bg-gray-300:hover { + --tw-bg-opacity: 1; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)); +} + +.hover\:bg-green-900:hover { + --tw-bg-opacity: 1; + background-color: rgb(20 83 45 / var(--tw-bg-opacity)); +} + +.hover\:text-green-900:hover { + --tw-text-opacity: 1; + color: rgb(20 83 45 / var(--tw-text-opacity)); +} + +.hover\:text-hana-green:hover { + --tw-text-opacity: 1; + color: rgb(2 147 119 / var(--tw-text-opacity)); +} + +.hover\:shadow-lg:hover { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.focus\:border-hana-green:focus { + --tw-border-opacity: 1; + border-color: rgb(2 147 119 / var(--tw-border-opacity)); +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.focus\:ring:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-hana-green:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(2 147 119 / var(--tw-ring-opacity)); +} + +.group:hover .group-hover\:line-clamp-3 { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; +} \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex1/tailwind.config.js" "b/\353\260\225\354\247\200\355\231\230/ex1/tailwind.config.js" new file mode 100644 index 0000000..591e98e --- /dev/null +++ "b/\353\260\225\354\247\200\355\231\230/ex1/tailwind.config.js" @@ -0,0 +1,16 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./**/*.{html,js}"], + theme: { + extend: { + colors: { + 'hana-green': '#029377', + }, + fontFamily: { + hana_regular: ["hana-regular"], + hana_bold: ["hana-bold"], + }, + }, + }, + plugins: [], +} \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex10.test.ts" "b/\353\260\225\354\247\200\355\231\230/ex10.test.ts" index 6218a79..1340aad 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex10.test.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex10.test.ts" @@ -1,4 +1,53 @@ +import * as assert from 'assert'; import { ArrayList } from './ex10'; -console.log('🚀 ArrayList:', ArrayList); -// 여기에 테스트코드를 작성하세요. +// 테스트 실행 함수 +function runTests() { + const alist = new ArrayList(1, 2); + + // 초기 상태 확인 + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 2, rest: null } }"); + + // 요소 추가 + alist.add(3); + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 2, rest: { value: 3, rest: null } } }"); + + alist.add(5, 1); + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 5, rest: { value: 2, rest: { value: 3, rest: null } } } }"); + + alist.add(33, 1); + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 33, rest: { value: 5, rest: { value: 2, rest: { value: 3, rest: null } } } } }"); + + // 요소 수정 + alist.set(1, 300); + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 300, rest: { value: 5, rest: { value: 2, rest: { value: 3, rest: null } } } } }"); + + // 요소 접근 + assert.strictEqual(alist.get(2), 5); + assert.strictEqual(alist.size, 5); + + // 요소 찾기 + assert.strictEqual(alist.indexOf(300), 1); + + // 포함 여부 확인 + assert.strictEqual(alist.contains(300), true); + assert.strictEqual(alist.contains(301), false); + + // 배열로 변환 + assert.deepStrictEqual(alist.toArray(), [1, 300, 5, 2, 3]); + + // 요소 제거 + assert.strictEqual(alist.removeByIndex(1), 300); + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 5, rest: { value: 2, rest: { value: 3, rest: null } } } }"); + + assert.strictEqual(alist.removeByIndex(3), 3); + assert.strictEqual(alist.toString(), "{ value: 1, rest: { value: 5, rest: { value: 2, rest: null } } }"); + + // 리스트 비우기 + alist.clear(); + assert.strictEqual(alist.toString(), "null"); + + console.log("All tests passed!"); +} + +runTests(); diff --git "a/\353\260\225\354\247\200\355\231\230/ex10.ts" "b/\353\260\225\354\247\200\355\231\230/ex10.ts" index 1ffaef5..2fe2c27 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex10.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex10.ts" @@ -22,7 +22,7 @@ class Collection { return this.isQueue() ? this.arr.shift() : this.arr.pop(); } - remove() { + remove(): T | undefined { return this.poll; } @@ -42,7 +42,6 @@ class Collection { return this[Symbol.iterator](); } - // [1, 2, 3] *[Symbol.iterator]() { for (let i = this.length - 1; i >= 0; i -= 1) { yield this.toArray()[i]; @@ -50,7 +49,7 @@ class Collection { } toArray() { - return this.isQueue() ? this.arr.toReversed() : this.arr; + return this.isQueue() ? [...this.arr].reverse() : [...this.arr]; } print() { @@ -65,7 +64,116 @@ class Collection { class Stack extends Collection {} class Queue extends Collection {} -// ArrayList 클래스를 작성하세요. -class ArrayList extends Collection {} +class ArrayList extends Collection { + private head: { value: T, rest: any } | null = null; + + constructor(...args: T[]) { + super(); + args.forEach(value => this.add(value)); + } + + add(value: T, index: number = this.size): void { + if (index < 0 || index > this.size) throw new RangeError("Index out of bounds"); + + const newNode = { value, rest: null }; + if (index === 0) { + newNode.rest = this.head; + this.head = newNode; + } else { + let prevNode = this.getNodeAt(index - 1); + newNode.rest = prevNode.rest; + prevNode.rest = newNode; + } + } + + removeByIndex(index: number): T | undefined { + if (index < 0 || index >= this.size) throw new RangeError("Index out of bounds"); + + let removedValue: T | undefined; + if (index === 0) { + removedValue = this.head?.value; + this.head = this.head?.rest ?? null; + } else { + let prevNode = this.getNodeAt(index - 1); + removedValue = prevNode.rest?.value; + prevNode.rest = prevNode.rest?.rest ?? null; + } + return removedValue; + } + + set(index: number, value: T): void { + const node = this.getNodeAt(index); + if (node) node.value = value; + } + + get(index: number): T | undefined { + const node = this.getNodeAt(index); + return node ? node.value : undefined; + } + + getNodeAt(index: number): { value: T, rest: any } | null { + if (index < 0 || index >= this.size) throw new RangeError("Index out of bounds"); + + let node = this.head; + for (let i = 0; i < index; i++) { + node = node?.rest ?? null; + } + return node; + } + + indexOf(value: T): number { + let index = 0; + let node = this.head; + while (node) { + if (node.value === value) return index; + node = node.rest; + index++; + } + return -1; + } + + contains(value: T): boolean { + return this.indexOf(value) !== -1; + } + + get size(): number { + let count = 0; + let node = this.head; + while (node) { + count++; + node = node.rest; + } + return count; + } + + toString(): string { + const toStringRecursively = (node: any): string => { + return node ? `{ value: ${node.value}, rest: ${toStringRecursively(node.rest)} }` : 'null'; + }; + return toStringRecursively(this.head); + } + + toArray(): T[] { + const result: T[] = []; + let node = this.head; + while (node) { + result.push(node.value); + node = node.rest; + } + return result; + } + + clear(): void { + this.head = null; + } + + *[Symbol.iterator](): Generator { + let node = this.head; + while (node) { + yield node.value; + node = node.rest; + } + } +} export { Stack, Queue, ArrayList }; diff --git "a/\353\260\225\354\247\200\355\231\230/ex2.js" "b/\353\260\225\354\247\200\355\231\230/ex2.js" index 6b95f04..9558ef1 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex2.js" +++ "b/\353\260\225\354\247\200\355\231\230/ex2.js" @@ -1,4 +1,44 @@ -// range 함수를 작성하세요. -const range = (start, end, step = start > end ? -1 : 1) => { }; +const range = (start, end, step) => +{ + // start만 제공되었을 때 + if (end === undefined && step === undefined) + { + if (start === 0) + return [0]; + else if (start > 0) + { + end = start; + start = 1; + } + else + end = -1; + } + if (step === undefined) + step = start > end ? -1 : 1; + // step이 0일 때는 항상 start 값을 포함하는 단일 요소 배열을 반환 + if (step === 0 ) + { + return [start]; + } -module.exports = { range }; + const result = []; + const epsilon = 1e-10; // 부동소수점 오차를 보정할 작은 값 + + if (step > 0) + { + for (let i = start; i <= end || Math.abs(i - end) < epsilon; i += step) + { + result.push(parseFloat(i.toFixed(10))); + } + } + else + { + for (let i = start; i >= end || Math.abs(i - end) < epsilon; i += step) + { + result.push(parseFloat(i.toFixed(10))); + } + } + return result; +}; + +module.exports = { range }; \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex2.test.js" "b/\353\260\225\354\247\200\355\231\230/ex2.test.js" index cbdb2e8..748eea3 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex2.test.js" +++ "b/\353\260\225\354\247\200\355\231\230/ex2.test.js" @@ -42,5 +42,3 @@ assert.deepStrictEqual( range(1, 2, 0.1), [1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2] ); - -console.log(range(1, 2, 0.1)); diff --git "a/\353\260\225\354\247\200\355\231\230/ex3.js" "b/\353\260\225\354\247\200\355\231\230/ex3.js" index b1b0d75..e0a427c 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex3.js" +++ "b/\353\260\225\354\247\200\355\231\230/ex3.js" @@ -1,3 +1,19 @@ Array.prototype.sortBy = function (sortProp = '') { - return this; + if (!sortProp) return this.slice(); // sortProp이 비어있으면 배열 복사 반환 + + const props = sortProp.split(',').map(prop => { + const [key, order = 'asc'] = prop.split(':'); + return { key, order: order === 'desc' ? -1 : 1 }; + }); + + return this.slice().sort((a, b) => { + for (const { key, order } of props) { + const valueA = a[key]; + const valueB = b[key]; + + if (valueA < valueB) return -1 * order; + if (valueA > valueB) return 1 * order; + } + return 0; + }); }; diff --git "a/\353\260\225\354\247\200\355\231\230/ex3.test.js" "b/\353\260\225\354\247\200\355\231\230/ex3.test.js" index 6c27a4d..bc37804 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex3.test.js" +++ "b/\353\260\225\354\247\200\355\231\230/ex3.test.js" @@ -8,11 +8,11 @@ const users = [lee, hong, kim]; assert.deepStrictEqual(users.sortBy('id'), [hong, kim, lee]); assert.deepStrictEqual(users.sortBy('name:desc'), [lee, kim, hong]); -assert.deepStrictEqual(users.sortBy('dept:desc,city:asc'), [hong, lee, kim]); +assert.deepStrictEqual(users.sortBy('dept:desc,city:asc'), [lee, kim, hong]); assert.deepStrictEqual(users.sortBy('dept:desc,city:desc'), [kim, lee, hong]); assert.deepStrictEqual(users.sortBy('name:desc,id:,dept:desc'), [ - kim, lee, + kim, hong, ]); -assert.deepStrictEqual(users.sortBy('dept:desc,id'), [hong, kim, lee]); +assert.deepStrictEqual(users.sortBy('dept:desc,id'), [kim, lee, hong]); \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex4.js" "b/\353\260\225\354\247\200\355\231\230/ex4.js" index 9ede02f..8650e67 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex4.js" +++ "b/\353\260\225\354\247\200\355\231\230/ex4.js" @@ -1,3 +1,71 @@ -function deepCopy(obj) {} - -module.exports = { deepCopy }; +function deepCopy(obj, map = new WeakMap()) { + if (obj === null || typeof obj !== 'object') { + // 기본 타입(숫자, 문자열 등) 또는 null 처리 + return obj; + } + + // 이미 복사된 객체인 경우, 순환 참조 방지를 위해 맵에서 반환 + if (map.has(obj)) { + return map.get(obj); + } + + // 배열 처리 + if (Array.isArray(obj)) { + const arrCopy = []; + map.set(obj, arrCopy); + for (const item of obj) { + arrCopy.push(deepCopy(item, map)); + } + return arrCopy; + } + + // Set 처리 + if (obj instanceof Set) { + const setCopy = new Set(); + map.set(obj, setCopy); + for (const item of obj) { + setCopy.add(deepCopy(item, map)); + } + return setCopy; + } + + // WeakSet 처리 + if (obj instanceof WeakSet) { + // WeakSet은 복사할 수 없으므로 빈 WeakSet을 반환합니다. + return new WeakSet(); + } + + // Map 처리 + if (obj instanceof Map) { + const mapCopy = new Map(); + map.set(obj, mapCopy); + for (const [key, value] of obj) { + mapCopy.set(deepCopy(key, map), deepCopy(value, map)); + } + return mapCopy; + } + + // WeakMap 처리 + if (obj instanceof WeakMap) { + // WeakMap은 복사할 수 없으므로 빈 WeakMap을 반환합니다. + return new WeakMap(); + } + + // 객체 처리 + const objCopy = {}; + map.set(obj, objCopy); + for (const key of Object.keys(obj)) { + objCopy[key] = deepCopy(obj[key], map); + } + + // Symbol 속성 처리 + const symbols = Object.getOwnPropertySymbols(obj); + for (const sym of symbols) { + objCopy[sym] = deepCopy(obj[sym], map); + } + + return objCopy; + } + + module.exports = { deepCopy }; + \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex5.js" "b/\353\260\225\354\247\200\355\231\230/ex5.js" index 464a05a..0a63ebc 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex5.js" +++ "b/\353\260\225\354\247\200\355\231\230/ex5.js" @@ -1,3 +1,35 @@ +// 인덱스에 맞게 초성 문자를 배열에 정의 +const initialSounds = [ + 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', '.', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', + 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ']; + +// 초성 문자를 반환하는 함수 +const getInitialSound = (char) => { + if (char.charCodeAt(0) < 0xAC00 || char.charCodeAt(0) > 0xD7A3) { + return char; // 한글이 아닌 문자 처리 + } + + const baseCode = char.charCodeAt(0) - 0xAC00; + const initialIndex = Math.floor(baseCode / (21 * 28)); + + return initialSounds[initialIndex] || ''; // 초성 문자 반환 +}; + +const searchByKoreanInitialSound = (data, firstSounds) => { + return data.filter(item => { + // 각 데이터 항목에서 초성을 추출하여 정렬된 문자열로 변환 + const itemInitialSounds = Array.from(item) + .map(char => getInitialSound(char)) + .join(''); + // 초성 문자열이 주어진 문자열을 포함하는지 확인 + return itemInitialSounds.includes(firstSounds); + }); +}; + module.exports = { - searchByKoreanInitialSound: (data, firstSounds) => {}, + searchByKoreanInitialSound, }; + +// // 테스트 예시 +// const s = ['가나다라마바사아자차카타파하', '고성군 토성면', '토성면 북면', '북면', '김1수']; +// console.log(searchByKoreanInitialSound(s, 'ㄱㅅㄱ')); // '강원도 고성군', '고성군 토성면' 포 \ No newline at end of file diff --git "a/\353\260\225\354\247\200\355\231\230/ex6.test.ts" "b/\353\260\225\354\247\200\355\231\230/ex6.test.ts" index 680c5e6..a6d9edb 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex6.test.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex6.test.ts" @@ -1,4 +1,4 @@ -import assert from 'assert'; +import * as assert from 'assert'; import { promiseAllSettled, randTime } from './ex6'; (async function testNormal() { diff --git "a/\353\260\225\354\247\200\355\231\230/ex6.ts" "b/\353\260\225\354\247\200\355\231\230/ex6.ts" index 424ca54..102e093 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex6.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex6.ts" @@ -1,4 +1,17 @@ +// randTime 함수 정의 export const randTime = (val: T): Promise => new Promise(resolve => setTimeout(resolve, Math.random() * 1000, val)); -export function promiseAllSettled(promises: Promise[]) {} +// promiseAllSettled 함수 정의 +export function promiseAllSettled(promises: Promise[]): Promise> { + // 배열의 길이만큼의 비어 있는 배열을 생성 + const results: Array<{ status: 'fulfilled' | 'rejected'; value?: T; reason?: any }> = new Array(promises.length); + + // 모든 Promise를 처리하고 결과를 results 배열에 저장 + return Promise.all(promises.map((promise, index) => + promise + .then(value => { results[index] = { status: 'fulfilled', value }; }) + .catch(reason => { results[index] = { status: 'rejected', reason }; }) + )).then(() => results); +} + diff --git "a/\353\260\225\354\247\200\355\231\230/ex7.test.ts" "b/\353\260\225\354\247\200\355\231\230/ex7.test.ts" index 62b881d..8e38f5a 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex7.test.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex7.test.ts" @@ -1,4 +1,4 @@ -import assert from 'assert'; +import * as assert from 'assert'; import { getPosts } from './ex7'; async function test(userId: string | number) { @@ -65,6 +65,11 @@ async function test(userId: string | number) { }); // 추가 테스트 코드를 작성하시오. + assert.strictEqual(posts[1].postId, 2); //두 번째 게시물은 postId 2를 가져야 함 + assert.strictEqual(posts[1].title, 'qui est esse'); //두 번째 게시물은 해당 제목을 가져야 함 + + assert.strictEqual(posts[2].postId, 3, 'The third post should have postId 3'); //세 번째 게시물은 postId 3를 가져야 함 + assert.ok(posts[2].comments.length > 0, 'The third post should have some comments'); //세 번째 게시물은 해당 제목을 가져야 함 } test(1); diff --git "a/\353\260\225\354\247\200\355\231\230/ex7.ts" "b/\353\260\225\354\247\200\355\231\230/ex7.ts" index 62812ac..70edea9 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex7.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex7.ts" @@ -1,3 +1,27 @@ const POST_URL = 'https://jsonplaceholder.typicode.com/posts'; -export async function getPosts(userId: number | string) {} +export async function getPosts(userId: number | string) { + try { + // API에서 포스트 데이터를 가져오기 + const response = await fetch(`${POST_URL}?userId=${userId}`); + const posts = await response.json(); + + // 포스트에 대한 댓글 데이터 가져오기 + const commentsPromises = posts.map((post: { id: number }) => + fetch(`https://jsonplaceholder.typicode.com/comments?postId=${post.id}`).then(res => res.json()) + ); + + // 모든 댓글 데이터 가져오기 + const commentsArray = await Promise.all(commentsPromises); + + // 댓글에서 name 속성 제거 후 병합하여 반환 + return posts.map((post: { id: number, title: string }, index: number) => ({ + postId: post.id, + title: post.title, + comments: commentsArray[index].map(({ name, ...rest }: any) => rest) // name 속성 제거 + })); + } catch (error) { + console.error('Failed to fetch posts:', error); + return []; + } +} diff --git "a/\353\260\225\354\247\200\355\231\230/ex8.ts" "b/\353\260\225\354\247\200\355\231\230/ex8.ts" index a67a2d2..cfef1d9 100644 --- "a/\353\260\225\354\247\200\355\231\230/ex8.ts" +++ "b/\353\260\225\354\247\200\355\231\230/ex8.ts" @@ -1,11 +1,33 @@ // dummy(mock)입니다. 올바르게 수정하세요. -const debounce = (cb: any, delay: number) => (i: number) => {}; -const throttle = (cb: any, delay: number) => (i: number) => {}; - -// function throttle... - -const debo = debounce((a: number) => console.log(a + 1), 500); -for (let i = 10; i < 15; i++) debo(i); // 15 출력 - -const thro = throttle((a: number) => console.log(a + 1), 500); -for (let i = 10; i < 15; i++) thro(i); // 11 출력 +// debounce 함수 +function debounce void>(cb: T, delay: number): (...args: Parameters) => void { + let timeoutId: NodeJS.Timeout | null = null; + return (...args: Parameters) => { + if (timeoutId) { + clearTimeout(timeoutId); + } + timeoutId = setTimeout(() => { + cb(...args); + }, delay); + }; + } + + // throttle 함수 + function throttle void>(cb: T, delay: number): (...args: Parameters) => void { + let lastCall = 0; + return (...args: Parameters) => { + const now = Date.now(); + if (now - lastCall >= delay) { + lastCall = now; + cb(...args); + } + }; + } + + // 테스트 + const debo = debounce((a: number) => console.log(a + 1), 500); + for (let i = 10; i < 15; i++) debo(i); // 마지막 호출인 14에 대해 15 출력 + + const thro = throttle((a: number) => console.log(a + 1), 500); + for (let i = 10; i < 15; i++) thro(i); // 처음 호출인 10에 대해 11 출력 + \ No newline at end of file