├── .gitignore ├── ch12 ├── 02.js ├── 01.js ├── 06-1.js ├── 07.js ├── 03-1.js ├── 03-1.test.js ├── 06-2.js ├── 03-2.js ├── 08.js ├── 11.js ├── 10-2.js └── 10-1.js ├── ch10 ├── 02-2.js ├── 02-1.js ├── 03-2.js ├── 03-1.js ├── 06.js ├── 07.js ├── 01.js ├── 05-2.js ├── 04-1.js ├── 05-1.js ├── 05-3.js └── 04-2.js ├── ch1 ├── plays.json ├── main.js ├── invoices.json └── statement.js ├── ch11 ├── 02-1.js ├── 07.js ├── 01.js ├── 11.js ├── 02-2.js ├── 05.js ├── 10.js ├── 08.js ├── 06.js ├── 09.js ├── 12.js ├── 04-1.js ├── 04-2.js ├── 13.js ├── 03-1.js └── 03-2.js ├── ch7 ├── 01-1.js ├── 09.js ├── 04.js ├── 03.js ├── 01-2.json ├── 05.js ├── 08.js ├── 01-2.js ├── 01-2.test.js ├── 07.js ├── 06.js └── 02.js ├── fileController.js ├── ch6 ├── 06-1-1_defaultOwner.js ├── 06-1-0.js ├── 02-1.js ├── 05-1.js ├── 03-1.js ├── 02-2.js ├── 08.js ├── 03-2.js ├── 01.js ├── 05-2.js ├── 11-2.js ├── 11-products.json ├── 11-1.js ├── 09.js └── 10.js ├── ch9 ├── 01-2.js ├── 05.js ├── 02.js ├── 03-1.js ├── 03-2.js ├── 01-1.js └── 04.js ├── ch4 ├── province.test.js ├── producer.js └── province.js ├── ch8 ├── 06-2.js ├── 07.js ├── 02-2.js ├── 01-1.js ├── 08.js ├── 02-1.js ├── 03.js ├── 01-2.js ├── 06-1.js └── 04.js ├── package.json ├── README.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /ch12/02.js: -------------------------------------------------------------------------------- 1 | class Employee {} 2 | class SalesPerson extends Employee { 3 | #name 4 | } 5 | class Engineer extends Employee { 6 | #name 7 | } 8 | -------------------------------------------------------------------------------- /ch10/02-2.js: -------------------------------------------------------------------------------- 1 | const func = anEmployee => { 2 | if (anEmployee.onVacation) { 3 | if (anEmployee.seniority > 10) return 1 4 | } 5 | return 0.5 6 | } 7 | -------------------------------------------------------------------------------- /ch1/plays.json: -------------------------------------------------------------------------------- 1 | { 2 | "hamlet": { "name": "Hamlet", "type": "tragedy" }, 3 | "as-like": { "name": "As You Like It", "type": "comedy" }, 4 | "othello": { "name": "Othello", "type": "tragedy" } 5 | } 6 | -------------------------------------------------------------------------------- /ch11/02-1.js: -------------------------------------------------------------------------------- 1 | const tenPercentRaise = person => { 2 | person.salary = person.salary.multiply(1.1) 3 | } 4 | const fivePercentRaise = person => { 5 | person.salary = person.salary.multiply(1.05) 6 | } 7 | -------------------------------------------------------------------------------- /ch7/01-1.js: -------------------------------------------------------------------------------- 1 | let result = '' 2 | const organization = { name: '애크미 구스베리', country: 'GB' } 3 | 4 | organization.name = '애그머니 블루베리' 5 | result += `

${organization.name}

` 6 | 7 | console.log(result) 8 | -------------------------------------------------------------------------------- /fileController.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import { resolve } from 'path' 3 | 4 | const basePath = resolve() 5 | 6 | export const readJSON = path => JSON.parse(fs.readFileSync(resolve(basePath, path), 'utf-8')) 7 | -------------------------------------------------------------------------------- /ch10/02-1.js: -------------------------------------------------------------------------------- 1 | const disabilityAmount = anEmployee => { 2 | if (anEmployee.seniority < 2) return 0 3 | if (anEmployee.monthsDisabled > 12) return 0 4 | if (anEmployee.isPartTime) return 0 5 | // 장애 수당 계산 6 | } 7 | -------------------------------------------------------------------------------- /ch6/06-1-1_defaultOwner.js: -------------------------------------------------------------------------------- 1 | let defaultOwnerData = { firstName: '마틴', lastName: '파울러' } 2 | 3 | export const defaultOwner = () => ({ ...defaultOwnerData }) 4 | export const sertDefaultOwner = arg => { 5 | defaultOwnerData = arg 6 | } 7 | -------------------------------------------------------------------------------- /ch1/main.js: -------------------------------------------------------------------------------- 1 | import { readJSON } from '../fileController.js' 2 | import statement from './statement.js' 3 | 4 | const invoices = readJSON('invoices.json') 5 | const plays = readJSON('plays.json') 6 | 7 | invoices.forEach(invoice => { 8 | console.log(statement(invoice, plays)) 9 | }) 10 | -------------------------------------------------------------------------------- /ch12/01.js: -------------------------------------------------------------------------------- 1 | class Party { 2 | monthlyCost 3 | } 4 | 5 | class Employee extends Party { 6 | get annualCost() { 7 | return this.monthlyCost * 12 8 | } 9 | } 10 | class Department extends Party { 11 | get totalAnnualCost() { 12 | return this.monthlyCost * 12 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch9/01-2.js: -------------------------------------------------------------------------------- 1 | const discount = (inputValue, quantity) => { 2 | if (inputValue > 50) inputValue = inputValue - 2 3 | if (quantity > 100) inputValue = inputValue - 1 4 | return inputValue 5 | } 6 | console.log(discount(40, 90)) 7 | console.log(discount(70, 90)) 8 | console.log(discount(70, 110)) 9 | -------------------------------------------------------------------------------- /ch6/06-1-0.js: -------------------------------------------------------------------------------- 1 | let defaultOwner = { firstName: '마틴', lastName: '파울러' } 2 | 3 | const spaceship = { 4 | owner: defaultOwner, 5 | } 6 | 7 | defaultOwner = { firstName: '레베카', lastName: '파슨스' } 8 | 9 | const getDefaultOwner = () => defaultOwner 10 | const sertDefaultOwner = arg => { 11 | defaultOwner = arg 12 | } 13 | -------------------------------------------------------------------------------- /ch10/03-2.js: -------------------------------------------------------------------------------- 1 | const adjustCapital = anInstrument => { 2 | let result = 0 3 | if (anInstrument.capital > 0) { 4 | if (anInstrument.interestRate > 0 && anInstrument.duration > 0) { 5 | result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor 6 | } 7 | } 8 | return result 9 | } 10 | -------------------------------------------------------------------------------- /ch11/07.js: -------------------------------------------------------------------------------- 1 | class Person { 2 | #name 3 | #id 4 | get name() { 5 | return this.#name 6 | } 7 | set name(name) { 8 | this.#name = name 9 | } 10 | get id() { 11 | return this.#id 12 | } 13 | set id(id) { 14 | this.#id = id 15 | } 16 | } 17 | const martin = new Person() 18 | martin.name = 'Martin' 19 | martin.id = '1234' 20 | -------------------------------------------------------------------------------- /ch7/09.js: -------------------------------------------------------------------------------- 1 | const findPerson = people => { 2 | for (let i = 0; i < people.length; i++) { 3 | if (people[i] === 'Don') return 'Don' 4 | if (people[i] === 'John') return 'John' 5 | if (people[i] === 'Kent') return 'Kent' 6 | } 7 | return '' 8 | } 9 | console.log(findPerson(['Roy', 'Jay', 'Don', 'Kay', 'John', 'Peter', 'Kent', 'Clark'])) 10 | -------------------------------------------------------------------------------- /ch4/province.test.js: -------------------------------------------------------------------------------- 1 | import Province from './province.js' 2 | 3 | const sampleProvinceData = () => ({ 4 | name: 'Asia', 5 | producers: [ 6 | { name: 'Byzzantium', cost: 10, production: 9 }, 7 | { name: 'Attalia', cost: 12, production: 10 }, 8 | { name: 'Sinope', cost: 10, production: 6 }, 9 | ], 10 | demand: 30, 11 | price: 20, 12 | }) 13 | -------------------------------------------------------------------------------- /ch1/invoices.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "customer": "BigCo", 4 | "performances": [ 5 | { 6 | "playID": "hamlet", 7 | "audience": 55 8 | }, 9 | { 10 | "playID": "as-like", 11 | "audience": 35 12 | }, 13 | { 14 | "playID": "othello", 15 | "audience": 40 16 | } 17 | ] 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /ch6/02-1.js: -------------------------------------------------------------------------------- 1 | const moreThanFiveLateDeliveries = aDriver => aDriver.numberOfLateDeliveries > 5 2 | const rating = aDriver => (moreThanFiveLateDeliveries(aDriver) ? 2 : 1) 3 | 4 | const DriverA = { name: 'A', numberOfLateDeliveries: 10 } 5 | const DriverB = { name: 'B', numberOfLateDeliveries: 4 } 6 | 7 | console.log(DriverA.name, rating(DriverA)) 8 | console.log(DriverB.name, rating(DriverB)) 9 | -------------------------------------------------------------------------------- /ch6/05-1.js: -------------------------------------------------------------------------------- 1 | class Book { 2 | _reservations = [] 3 | 4 | get reservation() { 5 | return this._reservations 6 | } 7 | 8 | addReservation(customer) { 9 | this._reservations.push(customer) 10 | } 11 | } 12 | 13 | const bookcafe = new Book() 14 | bookcafe.addReservation({ name: 'roy' }) 15 | bookcafe.addReservation({ name: 'jay' }) 16 | console.log(bookcafe.reservation) 17 | -------------------------------------------------------------------------------- /ch10/03-1.js: -------------------------------------------------------------------------------- 1 | const payAmount = employee => { 2 | let result 3 | if (employee.isSeperated) result = { amount: 0, reasonCode: 'SEP' } 4 | // 퇴사 5 | else { 6 | if (employee.isRetired) result = { amount: 0, reasonCode: 'RET' } 7 | // 은퇴 8 | else { 9 | // 급여계산 10 | result = { amount: 100, reasonCode: 'WRK' } // 재직 11 | } 12 | } 13 | return result 14 | } 15 | -------------------------------------------------------------------------------- /ch10/06.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'assert' 2 | 3 | class Customer { 4 | _discountRate 5 | applyDiscount(number) { 6 | if (!this._discountRate) return number 7 | assert(this._discountRate >= 0) 8 | return number - this._discountRate * number 9 | } 10 | set discountRate(number) { 11 | assert(number === null || number >= 0) 12 | this._discountRate = number 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch8/06-2.js: -------------------------------------------------------------------------------- 1 | const createResource = () => ({}) 2 | const availableResources = [] 3 | const allocatedResources = [] 4 | 5 | const func = () => { 6 | let result 7 | if (availableResources.length === 0) { 8 | result = createResource() 9 | allocatedResources.push(result) 10 | } else { 11 | result = availableResources.pop() 12 | allocatedResources.push(result) 13 | } 14 | return result 15 | } 16 | -------------------------------------------------------------------------------- /ch11/01.js: -------------------------------------------------------------------------------- 1 | const setOffAlarms = () => { 2 | console.warn('악당을 찾았소') 3 | } 4 | const alertForMiscreant = people => { 5 | for (const p of people) { 6 | if (p === '조커') { 7 | setOffAlarms() 8 | return '조커' 9 | } 10 | if (p === '사루만') { 11 | setOffAlarms() 12 | return '사루만' 13 | } 14 | } 15 | return '' 16 | } 17 | alertForMiscreant(['슈퍼맨', '배트맨', '아이언맨', '사루만', '블랙위도우', '조커', '스파이더맨']) 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "refactoring", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "dependencies": { 8 | "chai": "^4.3.4", 9 | "dayjs": "^1.10.6", 10 | "lodash": "^4.17.21", 11 | "mocha": "^9.0.2", 12 | "nodemon": "^2.0.7" 13 | }, 14 | "scripts": { 15 | "start": "nodemon", 16 | "test": "nodemon --exec 'mocha ${0}'" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch6/03-1.js: -------------------------------------------------------------------------------- 1 | const price = order => { 2 | return ( 3 | order.quantity * order.itemPrice - 4 | Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 + 5 | Math.min(order.quantity * order.itemPrice * 0.1, 100) 6 | ) 7 | } 8 | 9 | const orderA = { 10 | itemPrice: 600, 11 | quantity: 3, 12 | } 13 | const orderB = { 14 | itemPrice: 8000, 15 | quantity: 2, 16 | } 17 | 18 | console.log(price(orderA)) 19 | console.log(price(orderB)) 20 | -------------------------------------------------------------------------------- /ch7/04.js: -------------------------------------------------------------------------------- 1 | class Order { 2 | _quantity 3 | _item 4 | constructor(quantity, item) { 5 | this._quantity = quantity 6 | this._item = item 7 | } 8 | get price() { 9 | let basePrice = this._quantity * this._item.price 10 | let discountFactor = 0.98 11 | if (basePrice > 1000) discountFactor -= 0.03 12 | return basePrice * discountFactor 13 | } 14 | } 15 | const order = new Order(10, { price: 1000 }) 16 | console.log(order.price) 17 | -------------------------------------------------------------------------------- /ch10/07.js: -------------------------------------------------------------------------------- 1 | const sendAlert = () => console.warn('악당을 찾았소') 2 | 3 | const checkForMiscreants = people => { 4 | let found = false 5 | for (const p of people) { 6 | if (!found) { 7 | if (p === '조커') { 8 | sendAlert() 9 | found = true 10 | } 11 | if (p === '사루만') { 12 | sendAlert() 13 | found = true 14 | } 15 | } 16 | } 17 | } 18 | checkForMiscreants(['슈퍼맨', '배트맨', '아이언맨', '사루만', '블랙위도우', '조커', '스파이더맨']) 19 | -------------------------------------------------------------------------------- /ch7/03.js: -------------------------------------------------------------------------------- 1 | class Order { 2 | priority = '' 3 | constructor(data) { 4 | this.priority = data.priority 5 | } 6 | } 7 | const client1 = () => { 8 | const orders = [{ priority: 'high' }, { priority: 'rush' }, { priority: 'low' }, { priority: 'normal' }].map( 9 | o => new Order(o), 10 | ) 11 | const highPriorityCount = orders.filter(o => o.priority === 'high' || o.priority === 'rush').length 12 | return highPriorityCount 13 | } 14 | console.log(client1()) 15 | -------------------------------------------------------------------------------- /ch6/02-2.js: -------------------------------------------------------------------------------- 1 | const gatherCustomerData = (out, aCustomer) => { 2 | out.push(['name', aCustomer.name]) 3 | out.push(['location', aCustomer.location]) 4 | } 5 | const reportLines = aCustomer => { 6 | const lines = [] 7 | gatherCustomerData(lines, aCustomer) 8 | return lines 9 | } 10 | 11 | const customerA = { name: 'roy', location: 'seoul' } 12 | const customerB = { name: 'jay', location: 'incheon' } 13 | console.log(reportLines(customerA)) 14 | console.log(reportLines(customerB)) 15 | -------------------------------------------------------------------------------- /ch9/05.js: -------------------------------------------------------------------------------- 1 | class Customer { 2 | #id 3 | constructor(id) { 4 | this.#id = id 5 | } 6 | get id() { 7 | return this.#id 8 | } 9 | } 10 | 11 | class Order { 12 | #number 13 | #customer 14 | constructor(data) { 15 | this.#number = data.number 16 | this.#customer = new Customer(data.customer) 17 | } 18 | get customer() { 19 | return this.#customer 20 | } 21 | } 22 | 23 | const o = new Order({ number: 1, customer: 'a' }) 24 | console.log(o.customer.id) 25 | -------------------------------------------------------------------------------- /ch9/02.js: -------------------------------------------------------------------------------- 1 | class Organization { 2 | #name 3 | #country 4 | constructor(data) { 5 | this.#name = data.name 6 | this.#country = data.country 7 | } 8 | get name() { 9 | return this.#name 10 | } 11 | set name(aString) { 12 | this.#name = aString 13 | } 14 | get country() { 15 | return this.#country 16 | } 17 | set country(aCountry) { 18 | this.#country = aCountry 19 | } 20 | } 21 | const organization = new Organization({ name: '애크미 구스베리', country: 'GB' }) 22 | -------------------------------------------------------------------------------- /ch9/03-1.js: -------------------------------------------------------------------------------- 1 | class ProductionPlan { 2 | #production = 0 3 | #adjustments = [] 4 | get production() { 5 | return this.#production 6 | } 7 | applyAdjustment(anAdjustment) { 8 | this.#adjustments.push(anAdjustment) 9 | this.#production += anAdjustment.amount 10 | } 11 | } 12 | 13 | const products = new ProductionPlan() 14 | products.applyAdjustment({ name: '사과', amount: 10 }) 15 | products.applyAdjustment({ name: '바나나', amount: 20 }) 16 | 17 | console.log(products.production) 18 | -------------------------------------------------------------------------------- /ch11/11.js: -------------------------------------------------------------------------------- 1 | const calculateAscent = () => { 2 | for (let i = 1; i < points.length; i++) { 3 | const verticalChange = points[i].elevation - points[i - 1].elevation 4 | totalAscent += verticalChange > 0 ? verticalChange : 0 5 | } 6 | } 7 | const calculateTime = () => {} 8 | const calculateDistance = () => {} 9 | 10 | let points = [] 11 | let totalAscent = 0 12 | let totalTime = 0 13 | let totalDistance = 0 14 | calculateAscent() 15 | calculateTime() 16 | calculateDistance() 17 | const pace = totalTime / 60 / totalDistance 18 | -------------------------------------------------------------------------------- /ch7/01-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "1920": { 3 | "name": "마틴 파울러", 4 | "id": "1920", 5 | "usages": { 6 | "2016": { 7 | "1": 50, 8 | "2": 55 9 | }, 10 | "2015": { 11 | "1": 70, 12 | "2": 63 13 | } 14 | } 15 | }, 16 | "38673": { 17 | "name": "닐 포드", 18 | "id": "38673", 19 | "usages": { 20 | "2016": { 21 | "1": 30, 22 | "2": 45 23 | }, 24 | "2015": { 25 | "1": 60, 26 | "2": 73 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ch7/05.js: -------------------------------------------------------------------------------- 1 | class Person { 2 | get name() { 3 | return this._name 4 | } 5 | set name(arg) { 6 | this._name = arg 7 | } 8 | get officeAreaCode() { 9 | return this._officeAreaCode 10 | } 11 | set officeAreaCode(arg) { 12 | this._officeAreaCode = arg 13 | } 14 | get officeNumber() { 15 | return this._officeNumber 16 | } 17 | set officeNumber(arg) { 18 | this._officeNumber = arg 19 | } 20 | get telephoneNumber() { 21 | return `(${this.officeAreaCode}) ${this.officeNumber}` 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch8/07.js: -------------------------------------------------------------------------------- 1 | const PEOPLE = [ 2 | { age: 30, salary: 4000 }, 3 | { age: 40, salary: 7000 }, 4 | { age: 24, salary: 2800 }, 5 | { age: 37, salary: 4600 }, 6 | { age: 27, salary: 3200 }, 7 | ] 8 | 9 | const getInfos = people => { 10 | let youngest = people[0] ? people[0].age : Infinity 11 | let totalSalary = 0 12 | for (const p of people) { 13 | if (p.age < youngest) youngest = p.age 14 | totalSalary += p.salary 15 | } 16 | return `최연소: ${youngest}, 총급여: ${totalSalary}` 17 | } 18 | console.log(getInfos(PEOPLE)) 19 | -------------------------------------------------------------------------------- /ch8/02-2.js: -------------------------------------------------------------------------------- 1 | class Account { 2 | _number 3 | _type 4 | _interestRate 5 | constructor(number, type, interestRate) { 6 | this._number = number 7 | this._type = type 8 | this._interestRate = interestRate 9 | } 10 | get interestRate() { 11 | return this._interestRate 12 | } 13 | } 14 | class AccountType { 15 | _name 16 | constructor(nameString) { 17 | this._name = nameString 18 | } 19 | } 20 | const minus = new AccountType('마통') 21 | const acc = new Account(100000, minus, 0.39) 22 | console.log(acc.interestRate) 23 | -------------------------------------------------------------------------------- /ch10/01.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs' 2 | 3 | const plan = { 4 | summerStart: dayjs('2021-07-01'), 5 | summerEnd: dayjs('2021-08-31'), 6 | summerRate: 1000, 7 | regularRate: 1100, 8 | regularServiceCharge: 100, 9 | } 10 | 11 | const getCharge = (quantity, aDate) => { 12 | if (!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd)) return quantity * plan.summerRate 13 | return quantity * plan.regularRate + plan.regularServiceCharge 14 | } 15 | console.log(getCharge(10, dayjs('2021-06-29'))) 16 | console.log(getCharge(10, dayjs('2021-08-15'))) 17 | -------------------------------------------------------------------------------- /ch7/08.js: -------------------------------------------------------------------------------- 1 | class Person { 2 | _name 3 | _department 4 | constructor(name, department) { 5 | this._name = name 6 | this._department = department 7 | } 8 | get name() { 9 | return this._name 10 | } 11 | get manager() { 12 | return this._department.manager 13 | } 14 | } 15 | 16 | class Department { 17 | _manager 18 | constructor(manager) { 19 | this._manager = manager 20 | } 21 | get manager() { 22 | return this._manager 23 | } 24 | } 25 | 26 | const jn = new Person('재남', new Department('로이')) 27 | console.log(jn.manager) 28 | -------------------------------------------------------------------------------- /ch9/03-2.js: -------------------------------------------------------------------------------- 1 | class ProductionPlan { 2 | #production = 0 3 | #adjustments = [] 4 | constructor(production) { 5 | this.#production = production 6 | } 7 | get production() { 8 | return this.#production 9 | } 10 | applyAdjustment(anAdjustment) { 11 | this.#adjustments.push(anAdjustment) 12 | this.#production += anAdjustment.amount 13 | } 14 | } 15 | 16 | const products = new ProductionPlan(0) 17 | products.applyAdjustment({ name: '사과', amount: 10 }) 18 | products.applyAdjustment({ name: '바나나', amount: 20 }) 19 | 20 | console.log(products.production) 21 | -------------------------------------------------------------------------------- /ch11/02-2.js: -------------------------------------------------------------------------------- 1 | const usd = aNumber => 2 | new Intl.NumberFormat('en-US', { 3 | style: 'currency', 4 | currency: 'USD', 5 | minimumFractionDigits: 2, 6 | }).format(aNumber / 100) 7 | 8 | const bottomBand = usage => Math.min(usage, 100) 9 | const middleBand = usage => (usage > 100 ? Math.min(usage, 200) - 100 : 0) 10 | const topBand = usage => (usage > 200 ? usage - 200 : 0) 11 | const baseCharge0 = usage => { 12 | if (usage < 0) return usd(0) 13 | const amount = bottomBand(usage) * 0.03 + middleBand(usage) * 0.05 + topBand(usage) * 0.07 14 | return usd(amount) 15 | } 16 | -------------------------------------------------------------------------------- /ch7/01-2.js: -------------------------------------------------------------------------------- 1 | import { readJSON } from '../fileController.js' 2 | 3 | const customerData = readJSON('ch7/01-2.json') 4 | 5 | export const writeData = (customerId, year, month, amount) => { 6 | customerData[customerId].usages[year][month] = amount 7 | } 8 | 9 | export const compareUsage = (customerId, laterYear, month) => { 10 | const later = customerData[customerId].usages[laterYear][month] 11 | const earlier = customerData[customerId].usages[laterYear - 1][month] 12 | return { laterAmount: later, change: later - earlier } 13 | } 14 | export const getCustomer = () => customerData 15 | -------------------------------------------------------------------------------- /ch12/06-1.js: -------------------------------------------------------------------------------- 1 | class Employee { 2 | #name 3 | #type 4 | constructor(name, type) { 5 | this.validateType(type) 6 | this.#name = name 7 | this.#type = type 8 | } 9 | validateType(arg) { 10 | if (!['engineer', 'manager', 'salesperson'].includes(arg)) throw new Error(`${arg}라는 직원 유형은 없습니다.`) 11 | } 12 | toString() { 13 | return `${this.#name} is a ${this.#type}` 14 | } 15 | } 16 | const roy = new Employee('roy', 'engineer') 17 | const jay = new Employee('jay', 'manager') 18 | const kay = new Employee('kay', 'salesperson') 19 | const tei = new Employee('tei', 'nobody') 20 | -------------------------------------------------------------------------------- /ch12/07.js: -------------------------------------------------------------------------------- 1 | class Person { 2 | #name 3 | constructor(name) { 4 | this.#name = name 5 | } 6 | get name() { 7 | return this.#name 8 | } 9 | get genderCode() { 10 | return 'X' 11 | } 12 | } 13 | class Male extends Person { 14 | get genderCode() { 15 | return 'M' 16 | } 17 | } 18 | class Female extends Person { 19 | get genderCode() { 20 | return 'F' 21 | } 22 | } 23 | 24 | const people = [new Male('재남'), new Female('지금'), new Male('로이'), new Female('이지')] 25 | const numberOfMales = people.filter(p => p instanceof Male).length 26 | console.log(numberOfMales) 27 | -------------------------------------------------------------------------------- /ch11/05.js: -------------------------------------------------------------------------------- 1 | class Order { 2 | quantity 3 | itemPrice 4 | constructor() {} 5 | get finalPrice() { 6 | const basePrice = this.quantity * this.itemPrice 7 | let discountLevel 8 | if (this.quantity > 100) discountLevel = 2 9 | else discountLevel = 1 10 | return this.discountedPrice(basePrice, discountLevel) 11 | } 12 | discountedPrice(basePrice, discountLevel) { 13 | switch (discountLevel) { 14 | case 1: 15 | return basePrice * 0.95 16 | case 2: 17 | return basePrice * 0.9 18 | default: 19 | return basePrice 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch11/10.js: -------------------------------------------------------------------------------- 1 | class ChargeCalculator { 2 | #customer 3 | #usage 4 | #provider 5 | constructor(customer, usage, provider) { 6 | this.#customer = customer 7 | this.#usage = usage 8 | this.#provider = provider 9 | } 10 | get baseCharge() { 11 | return this.#customer.baseRate * this.#usage 12 | } 13 | get charge() { 14 | return this.baseCharge + this.#provider.connectionCharge 15 | } 16 | } 17 | 18 | const customer = { baseRate: 100 } 19 | const usage = 1000 20 | const provider = { connectionCharge: 50 } 21 | const monthCharge = new ChargeCalculator(customer, usage, provider).charge 22 | console.log(monthCharge) 23 | -------------------------------------------------------------------------------- /ch6/08.js: -------------------------------------------------------------------------------- 1 | const station = { 2 | name: 'ZB1', 3 | readings: [ 4 | { temp: 47, time: '2016-11-10 09:10' }, 5 | { temp: 53, time: '2016-11-10 09:20' }, 6 | { temp: 58, time: '2016-11-10 09:30' }, 7 | { temp: 53, time: '2016-11-10 09:40' }, 8 | { temp: 51, time: '2016-11-10 09:50' }, 9 | ], 10 | } 11 | const operatingPlan = { 12 | temperatureFloor: 50, 13 | temperatureCeiling: 56, 14 | } 15 | 16 | const readingsOutsideRange = (station, min, max) => station.readings.filter(r => r.temp < min || r.temp > max) 17 | console.log(readingsOutsideRange(station, operatingPlan.temperatureFloor, operatingPlan.temperatureCeiling)) 18 | -------------------------------------------------------------------------------- /ch8/01-1.js: -------------------------------------------------------------------------------- 1 | const trackSummary = points => { 2 | const calculateTime = () => 10000 3 | const distance = (p1, p2) => Math.abs(p1 - p2) 4 | 5 | const calculateDistance = () => { 6 | let result = 0 7 | for (let i = 1; i < points.length; i++) { 8 | result += distance(points[i - 1], points[i]) 9 | } 10 | return result 11 | } 12 | 13 | const totalTime = calculateTime() 14 | const totalDistance = calculateDistance() 15 | const pace = totalTime / 60 / totalDistance 16 | 17 | return { 18 | time: totalTime, 19 | distance: totalDistance, 20 | pace, 21 | } 22 | } 23 | 24 | console.log(trackSummary([30, 250, 150, 550, 660])) 25 | -------------------------------------------------------------------------------- /ch7/01-2.test.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai' 2 | import { describe, it } from 'mocha' 3 | import { getCustomer, writeData, compareUsage } from './01-2.js' 4 | 5 | describe('customerData', () => { 6 | it('initial usage of 1920 at 2016/1 to be 50', () => { 7 | assert.equal(getCustomer()['1920'].usages['2016']['1'], 50) 8 | }) 9 | it('writeData', () => { 10 | writeData('1920', '2016', '1', 53) 11 | assert.equal(getCustomer()['1920'].usages['2016']['1'], 53) 12 | }) 13 | it('compareUsage', () => { 14 | const { laterAmount, change } = compareUsage('1920', '2016', '1') 15 | assert.equal(laterAmount, 53) 16 | assert.equal(change, -17) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /ch6/03-2.js: -------------------------------------------------------------------------------- 1 | class Order { 2 | constructor(aRecord) { 3 | this._data = aRecord 4 | } 5 | get quantity() { 6 | return this._data.quantity 7 | } 8 | get itemPrice() { 9 | return this._data.itemPrice 10 | } 11 | get price() { 12 | return ( 13 | this.quantity * this.itemPrice - 14 | Math.max(0, this.quantity - 500) * this.itemPrice * 0.05 + 15 | Math.min(this.quantity * this.itemPrice * 0.1, 100) 16 | ) 17 | } 18 | } 19 | 20 | const orderA = new Order({ 21 | itemPrice: 600, 22 | quantity: 3, 23 | }) 24 | const orderB = new Order({ 25 | itemPrice: 8000, 26 | quantity: 2, 27 | }) 28 | 29 | console.log(orderA.price) 30 | console.log(orderB.price) 31 | -------------------------------------------------------------------------------- /ch12/03-1.js: -------------------------------------------------------------------------------- 1 | class Party {} 2 | 3 | export class Employee extends Party { 4 | #name 5 | #id 6 | #monthlyCost 7 | constructor(name, id, monthlyCost) { 8 | super() 9 | this.#name = name 10 | this.#id = id 11 | this.#monthlyCost = monthlyCost 12 | } 13 | get name() { 14 | return this.#name 15 | } 16 | get monthlyCost() { 17 | return this.#monthlyCost 18 | } 19 | } 20 | 21 | export class Department extends Party { 22 | #name 23 | #staff 24 | constructor(name, staff) { 25 | super() 26 | this.#name = name 27 | this.#staff = staff 28 | } 29 | get name() { 30 | return this.#name 31 | } 32 | get staff() { 33 | return this.#staff 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ch6/01.js: -------------------------------------------------------------------------------- 1 | const printOwing = invoice => { 2 | let outstanding = 0 3 | 4 | console.log('*******************') 5 | console.log('***** 고객채무 *****') 6 | console.log('*******************') 7 | 8 | for (const o of invoice.orders) { 9 | outstanding += o.amount 10 | } 11 | 12 | const today = new Date() 13 | invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30) 14 | 15 | console.log(`고객명: ${invoice.customer}`) 16 | console.log(`채무액: ${outstanding}`) 17 | console.log(`마감일: ${invoice.dueDate?.toLocaleString()}`) 18 | } 19 | 20 | printOwing({ 21 | customer: '재남', 22 | orders: [ 23 | { name: '사채', amount: 100 }, 24 | { name: '대출', amount: 1000 }, 25 | ], 26 | }) 27 | -------------------------------------------------------------------------------- /ch12/03-1.test.js: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'mocha' 2 | import { expect } from 'chai' 3 | import { Employee, Department } from './03-1.js' 4 | 5 | describe('Employee', () => { 6 | it('should be an instance of Employee', () => { 7 | const e = new Employee('Roy', 'A001', 3000) 8 | expect(e.name).to.equal('Roy') 9 | expect(e.monthlyCost).to.equal(3000) 10 | }) 11 | }) 12 | describe('Department', () => { 13 | it('should be an instance of Department', () => { 14 | const roy = new Employee('Roy', 'A001', 3000) 15 | const jay = new Employee('Jay', 'B002', 2500) 16 | const dep = new Department('영업', [roy, jay]) 17 | expect(dep.name).to.equal('영업') 18 | expect(dep.staff).to.deep.equal([roy, jay]) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /ch9/01-1.js: -------------------------------------------------------------------------------- 1 | const scenario = { 2 | primaryForce: 100, 3 | secondaryForce: 10, 4 | mass: 10, 5 | delay: 40, 6 | } 7 | 8 | const distanceTravelled = (scenario, time) => { 9 | let result 10 | let acc = scenario.primaryForce / scenario.mass // (a = F / m) 11 | let primaryTime = Math.min(time, scenario.delay) 12 | result = 0.5 * acc * primaryTime ** 2 13 | let secondaryTime = time - scenario.delay 14 | if (secondaryTime > 0) { 15 | let primaryVelocity = acc * scenario.delay 16 | acc = (scenario.primaryForce + scenario.secondaryForce) / scenario.mass 17 | result += primaryVelocity * secondaryTime + 0.5 * acc * secondaryTime ** 2 18 | } 19 | return result 20 | } 21 | 22 | console.log(distanceTravelled(scenario, 100)) 23 | -------------------------------------------------------------------------------- /ch4/producer.js: -------------------------------------------------------------------------------- 1 | export default class Producer { 2 | constructor(aProvince, data) { 3 | this._province = aProvince 4 | this._cost = data.cost 5 | this._name = data.name 6 | this._production = data.production || 0 7 | } 8 | 9 | get name() { 10 | return this._name 11 | } 12 | get cost() { 13 | return this._cost 14 | } 15 | set cost(arg) { 16 | this._cost = parseInt(arg) 17 | } 18 | get production() { 19 | return this._production 20 | } 21 | set production(amountStr) { 22 | const amount = parseInt(amountStr) 23 | const newProduction = Number.isNaN(amount) ? 0 : amount 24 | this._province.totalProduction += newProduction - this._production 25 | this._production = newProduction 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch8/08.js: -------------------------------------------------------------------------------- 1 | const csvData = `office, country, telephone 2 | Chicago, USA, +1 312 373 1000 3 | Beijing, China, +86 4008 900 505 4 | Banalore, India, +91 80 4064 9570 5 | Porto Alegre, Brazil, +55 51 3079 3550 6 | Chennai, India, +91 44 660 44766` 7 | 8 | const acquireData = input => { 9 | const lines = input.split('\n') 10 | let firstLine = true 11 | const result = [] 12 | for (const line of lines) { 13 | if (firstLine) { 14 | firstLine = false 15 | continue 16 | } 17 | if (line.trim() === '') continue 18 | const record = line.split(',') 19 | if (record[1].trim() === 'India') { 20 | result.push({ city: record[0].trim(), phone: record[2].trim() }) 21 | } 22 | } 23 | return result 24 | } 25 | console.log(acquireData(csvData)) 26 | -------------------------------------------------------------------------------- /ch11/08.js: -------------------------------------------------------------------------------- 1 | class Employee { 2 | #name 3 | #typeCode 4 | constructor(name, typeCode) { 5 | this.#name = name 6 | this.#typeCode = typeCode 7 | } 8 | get name() { 9 | return this.#name 10 | } 11 | get type() { 12 | return this.#typeCode 13 | } 14 | static get legalTypeCodes() { 15 | return { 16 | E: 'Engineer', 17 | M: 'Manager', 18 | S: 'Salesperson', 19 | } 20 | } 21 | } 22 | 23 | const client1 = () => { 24 | const document = { name: '재남', empType: 'M', leadEngineer: '로이' } 25 | const candidate = new Employee(document.name, document.empType) 26 | const leadEngineer = new Employee(document.leadEngineer, 'E') 27 | return { candidate: candidate.name, leadEngineer: leadEngineer.name } 28 | } 29 | 30 | console.log(client1()) 31 | -------------------------------------------------------------------------------- /ch11/06.js: -------------------------------------------------------------------------------- 1 | const thermostat = { 2 | selectedTemperature: 25, 3 | currentTemperature: 27, 4 | } 5 | 6 | class HeatingPlan { 7 | #max 8 | #min 9 | get targetTemperature() { 10 | if (thermostat.selectedTemperature > this.#max) return this.#max 11 | else if (thermostat.selectedTemperature < this.#min) return this.#min 12 | else return thermostat.selectedTemperature 13 | } 14 | } 15 | 16 | const temperatureController = () => { 17 | const setToHeat = () => {} 18 | const setToCool = () => {} 19 | const setOff = () => {} 20 | 21 | const heatingPlan = new HeatingPlan() 22 | if (heatingPlan.targetTemperature > thermostat.currentTemperature) setToHeat() 23 | else if (heatingPlan.targetTemperature < thermostat.currentTemperature) setToCool() 24 | else setOff() 25 | } 26 | -------------------------------------------------------------------------------- /ch8/02-1.js: -------------------------------------------------------------------------------- 1 | class Customer { 2 | _name 3 | _discountRate 4 | _contract 5 | 6 | constructor(name, discountRate) { 7 | this._name = name 8 | this._discountRate = discountRate 9 | this._contract = new CustomerContract(new Date()) 10 | } 11 | get discountRate() { 12 | return this._discountRate 13 | } 14 | becomePreferred() { 15 | this._discountRate += 0.03 16 | // do other stuff 17 | } 18 | applyDiscount(amount) { 19 | return amount.subtract(amount.multiply(this._discountRate)) 20 | } 21 | } 22 | 23 | class CustomerContract { 24 | _startDate 25 | constructor(startDate) { 26 | this._startDate = startDate 27 | } 28 | } 29 | 30 | const customer1 = new Customer('재남', 0.1) 31 | customer1.becomePreferred() 32 | console.log(customer1.discountRate) 33 | -------------------------------------------------------------------------------- /ch6/05-2.js: -------------------------------------------------------------------------------- 1 | const someCustomers = [ 2 | { 3 | name: 'roy', 4 | address: { state: 'MA' }, 5 | }, 6 | { 7 | name: 'jay', 8 | address: { state: 'CT' }, 9 | }, 10 | { 11 | name: 'kay', 12 | address: { state: 'ME' }, 13 | }, 14 | { 15 | name: 'kai', 16 | address: { state: 'NONE' }, 17 | }, 18 | { 19 | name: 'roi', 20 | address: { state: 'VT' }, 21 | }, 22 | { 23 | name: 'rai', 24 | address: { state: 'NH' }, 25 | }, 26 | { 27 | name: 'rey', 28 | address: { state: 'RI' }, 29 | }, 30 | ] 31 | 32 | const inNewEngland = aCustomer => { 33 | return ['MA', 'CT', 'ME', 'VT', 'NH', 'RI'].includes(aCustomer.address.state) 34 | } 35 | 36 | const newEnglanders = someCustomers.filter(c => inNewEngland(c)) 37 | 38 | console.log(newEnglanders) 39 | -------------------------------------------------------------------------------- /ch11/09.js: -------------------------------------------------------------------------------- 1 | const score = (candidate, medicalExam, scoringGuide) => { 2 | let result = 0 3 | let healthLevel = 0 4 | let highMedicalRiskFlag = false 5 | if (medicalExam.isSmoker) { 6 | healthLevel += 10 7 | highMedicalRiskFlag = true 8 | } 9 | let certificationGrade = 'regular' 10 | if (scoringGuide.stateWithLowCertification(candidate.originState)) { 11 | certificationGrade = 'low' 12 | result -= 5 13 | } 14 | result -= Math.max(healthLevel - 5, 0) 15 | return { result, certificationGrade, highMedicalRiskFlag } 16 | } 17 | 18 | const scoringGuide = { stateWithLowCertification: state => state === 'CA' || state === 'ME' } 19 | console.log(score({ originState: 'CA' }, { isSmoker: true }, scoringGuide)) 20 | console.log(score({ originState: 'NY' }, { isSmoker: false }, scoringGuide)) 21 | -------------------------------------------------------------------------------- /ch6/11-2.js: -------------------------------------------------------------------------------- 1 | import { readJSON } from '../fileController.js' 2 | 3 | console.log(process.argv) 4 | class Order { 5 | product = {} 6 | constructor(product) { 7 | this.product = product 8 | } 9 | } 10 | 11 | const main = () => { 12 | try { 13 | const argv = process.argv 14 | if (argv.length < 3) throw new Error('파일명을 입력하세요') 15 | const filename = argv[argv.length - 1] 16 | const input = readJSON(filename) 17 | const orders = input.map(item => new Order(item)) 18 | 19 | if (argv.includes('-r')) { 20 | const readyOrders = orders.filter(o => o.product.status === 'ready') 21 | console.log('ready', readyOrders.length) 22 | } else { 23 | console.log('not ready', orders.length) 24 | } 25 | } catch (err) { 26 | console.error(err) 27 | } 28 | } 29 | main() 30 | -------------------------------------------------------------------------------- /ch6/11-products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "apple", 4 | "status": "ready", 5 | "basePrice": 3000, 6 | "discountThreshold": 0.1, 7 | "discountRate": 0.1 8 | }, 9 | { 10 | "name": "peer", 11 | "status": "pending", 12 | "basePrice": 4000, 13 | "discountThreshold": 0.05, 14 | "discountRate": 0.04 15 | }, 16 | { 17 | "name": "banana", 18 | "status": "ready", 19 | "basePrice": 2000, 20 | "discountThreshold": 0, 21 | "discountRate": 0 22 | }, 23 | { 24 | "name": "strawberry", 25 | "status": "ready", 26 | "basePrice": 3500, 27 | "discountThreshold": 0.15, 28 | "discountRate": 0.1 29 | }, 30 | { 31 | "name": "melon", 32 | "status": "shipping", 33 | "basePrice": 5000, 34 | "discountThreshold": 0.1, 35 | "discountRate": 0.09 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /ch6/11-1.js: -------------------------------------------------------------------------------- 1 | import { readJSON } from '../fileController.js' 2 | 3 | const products = readJSON('ch6/11-products.json') 4 | const shippingMethod = { 5 | discountFee: 0.1, 6 | feePerCase: 0.03, 7 | discountThreshold: 0.12, 8 | } 9 | 10 | const priceOrder = (product, quantity, shippingMethod) => { 11 | const basePrice = product.basePrice * quantity 12 | const discount = Math.max(quantity - product.discountThreshold, 0) * product.basePrice * product.discountRate 13 | const shippingPerCase = 14 | basePrice > shippingMethod.discountThreshold ? shippingMethod.discountFee : shippingMethod.feePerCase 15 | const shippingCost = quantity * shippingPerCase 16 | const price = basePrice - discount + shippingCost 17 | return price 18 | } 19 | 20 | products.forEach(product => { 21 | console.log(priceOrder(product, 10, shippingMethod)) 22 | }) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # refactoring 2판 스터디 2 | 3 | 지난 스터디 영상: https://www.youtube.com/playlist?list=PLjQV3hketAJmyZmqXZ1OVEFNctalbf9SX 4 | 5 | ### before vs. after 6 | 7 | - *21. 06. 29.* [Ch01](https://github.com/roy-jung/refactoring/pull/4/files) 8 | - *21. 07. 06.* [Ch04](https://github.com/roy-jung/refactoring/pull/5/files) 9 | - *21. 07. 06.* [Ch06](https://github.com/roy-jung/refactoring/pull/6/files) 10 | - *21. 07. 08.* [Ch07](https://github.com/roy-jung/refactoring/pull/7/files) 11 | - *21. 07. 13.* [Ch08](https://github.com/roy-jung/refactoring/pull/8/files) 12 | - *21. 07. 13.* [Ch09](https://github.com/roy-jung/refactoring/pull/9/files) 13 | - *21. 07. 15.* [Ch10](https://github.com/roy-jung/refactoring/pull/10/files) 14 | - *21. 07. 20.* [Ch11](https://github.com/roy-jung/refactoring/pull/11/files) 15 | - *21. 07. 22.* [Ch12](https://github.com/roy-jung/refactoring/pull/12/files) 16 | -------------------------------------------------------------------------------- /ch12/06-2.js: -------------------------------------------------------------------------------- 1 | class Employee { 2 | #name 3 | #type 4 | constructor(name, type) { 5 | this.validateType(type) 6 | this.#name = name 7 | this.#type = type 8 | } 9 | validateType(arg) { 10 | if (!['engineer', 'manager', 'salesperson'].includes(arg)) throw new Error(`${arg}라는 직원 유형은 없습니다.`) 11 | } 12 | get type() { 13 | return this.#type 14 | } 15 | set type(arg) { 16 | this.#type = arg 17 | } 18 | get capitalizedType() { 19 | return this.#type.charAt(0).toUpperCase() + this.#type.slice(1).toLowerCase() 20 | } 21 | toString() { 22 | return `${this.#name} is a ${this.capitalizedType}` 23 | } 24 | } 25 | 26 | console.log(new Employee('roy', 'engineer').toString()) 27 | console.log(new Employee('jay', 'manager').toString()) 28 | console.log(new Employee('kay', 'salesperson').toString()) 29 | console.log(new Employee('tei', 'nobody').toString()) 30 | -------------------------------------------------------------------------------- /ch11/12.js: -------------------------------------------------------------------------------- 1 | class ShippingRules { 2 | data 3 | constructor(data) { 4 | this.data = data 5 | } 6 | } 7 | const countryData = { 8 | shippingRules: { 9 | US: 10, 10 | CA: 7, 11 | }, 12 | } 13 | const errorList = [] 14 | 15 | const localShippingRules = country => { 16 | const data = countryData.shippingRules[country] 17 | if (data) return new ShippingRules(data) 18 | else return -23 19 | } 20 | const calculateShippingCosts = order => { 21 | // 관련 없는 코드 22 | const shippingRules = localShippingRules(order.country) 23 | if (shippingRules < 0) return shippingRules 24 | // 관련 없는 코드 25 | } 26 | const execute = order => { 27 | const state = calculateShippingCosts(order) 28 | if (state < 0) errorList.push({ order, errorCode: state }) 29 | } 30 | 31 | execute({ country: 'US' }) 32 | execute({ country: 'CA' }) 33 | execute({ country: 'KO' }) 34 | 35 | console.log(errorList) 36 | -------------------------------------------------------------------------------- /ch12/03-2.js: -------------------------------------------------------------------------------- 1 | class Employee { 2 | #name 3 | constructor(name) { 4 | this.#name = name 5 | } 6 | get isPrivileged() { 7 | return false 8 | } 9 | assignCar() { 10 | console.log(this.#name, 'car assigned') 11 | } 12 | } 13 | 14 | class Manager extends Employee { 15 | #grade 16 | constructor(name, grade) { 17 | super(name) 18 | this.#grade = grade 19 | if (this.isPrivileged) this.assignCar() 20 | } 21 | get isPrivileged() { 22 | return this.#grade > 4 23 | } 24 | } 25 | 26 | class Producer extends Employee { 27 | #grade 28 | constructor(name, grade) { 29 | super(name) 30 | this.#grade = grade 31 | if (this.isPrivileged) this.assignCar() 32 | } 33 | get isPrivileged() { 34 | return this.#grade > 4 35 | } 36 | } 37 | 38 | const roy = new Employee('로이') 39 | const jay = new Manager('제이', 5) 40 | const kay = new Producer('케이', 6) 41 | -------------------------------------------------------------------------------- /ch7/07.js: -------------------------------------------------------------------------------- 1 | class Person { 2 | _name 3 | _department 4 | constructor(name) { 5 | this._name = name 6 | } 7 | get name() { 8 | return this._name 9 | } 10 | get department() { 11 | return this._department 12 | } 13 | set department(arg) { 14 | this._department = arg 15 | } 16 | } 17 | 18 | class Department { 19 | _chargeCode 20 | _manager 21 | constructor(chargeCode, manager) { 22 | this._chargeCode = chargeCode 23 | this._manager = manager 24 | } 25 | get chargeCode() { 26 | return this._chargeCode 27 | } 28 | set chargeCode(arg) { 29 | this._chargeCode = arg 30 | } 31 | get manager() { 32 | return this._manager 33 | } 34 | set manager(arg) { 35 | this._manager = arg 36 | } 37 | } 38 | 39 | const feDev = new Department('FEDEV', '로이') 40 | const jn = new Person('재남') 41 | jn.department = feDev 42 | 43 | console.log(jn.department.manager) 44 | -------------------------------------------------------------------------------- /ch8/03.js: -------------------------------------------------------------------------------- 1 | const renderPhoto = aPhoto => { 2 | return `` 3 | } 4 | const emitPhotoData = aPhoto => { 5 | const result = [] 6 | result.push(`

위치: ${aPhoto.location}

`) 7 | result.push(`

날짜: ${aPhoto.date.toDateString()}

`) 8 | return result.join('\n') 9 | } 10 | 11 | const renderPerson = person => { 12 | const result = [] 13 | result.push(`

${person.name}

`) 14 | result.push(renderPhoto(person.photo)) 15 | result.push(`

제목: ${person.photo.title}

`) 16 | result.push(emitPhotoData(person.photo)) 17 | return result.join('\n') 18 | } 19 | 20 | const photoDiv = p => ['
', `

제목: ${p.title}

`, emitPhotoData(p), '
'].join('\n') 21 | 22 | const photo = { title: '로이사진', location: '양재천', date: new Date(), url: 'http://abc.com' } 23 | console.log('** renderPerson **\n', renderPerson({ name: '로이', photo })) 24 | console.log('\n** photoDiv **\n', photoDiv(photo)) 25 | -------------------------------------------------------------------------------- /ch9/04.js: -------------------------------------------------------------------------------- 1 | class TelephoneNumber { 2 | #areaCode 3 | #number 4 | get areaCode() { 5 | return this.#areaCode 6 | } 7 | set areaCode(arg) { 8 | this.#areaCode = arg 9 | } 10 | get number() { 11 | return this.#number 12 | } 13 | set number(arg) { 14 | this.#number = arg 15 | } 16 | } 17 | 18 | class Person { 19 | #telephoneNumber 20 | constructor() { 21 | this.#telephoneNumber = new TelephoneNumber() 22 | } 23 | get officeAreaCode() { 24 | return this.#telephoneNumber.areaCode 25 | } 26 | set officeAreaCode(arg) { 27 | this.#telephoneNumber.areaCode = arg 28 | } 29 | get officeNumber() { 30 | return this.#telephoneNumber.number 31 | } 32 | set officeNumber(arg) { 33 | this.#telephoneNumber.number = arg 34 | } 35 | } 36 | 37 | const p = new Person() 38 | p.officeAreaCode = '312' 39 | p.officeNumber = '555-0142' 40 | console.log(p.officeAreaCode, p.officeNumber) 41 | -------------------------------------------------------------------------------- /ch11/04-1.js: -------------------------------------------------------------------------------- 1 | class TemperatureRange { 2 | high 3 | low 4 | constructor(low, high) { 5 | this.high = high 6 | this.low = low 7 | } 8 | } 9 | class Room { 10 | daysTempRange 11 | constructor(min, max) { 12 | this.daysTempRange = new TemperatureRange(min, max) 13 | } 14 | } 15 | const room = new Room(22, 24) 16 | 17 | class HeatingPlan { 18 | _temperatureRange 19 | constructor(low, high) { 20 | this._temperatureRange = new TemperatureRange(low, high) 21 | } 22 | withinRange(bottom, top) { 23 | return bottom >= this._temperatureRange.low && top <= this._temperatureRange.high 24 | } 25 | } 26 | 27 | const client = () => { 28 | const plan = new HeatingPlan(21, 25) 29 | const low = room.daysTempRange.low 30 | const high = room.daysTempRange.high 31 | if (!plan.withinRange(low, high)) { 32 | console.log('방 온도가 지정 범위를 벗어났습니다.') 33 | } else { 34 | console.log('적정 온도입니다.') 35 | } 36 | } 37 | client() 38 | -------------------------------------------------------------------------------- /ch11/04-2.js: -------------------------------------------------------------------------------- 1 | class TemperatureRange { 2 | high 3 | low 4 | constructor(low, high) { 5 | this.high = high 6 | this.low = low 7 | } 8 | } 9 | class Room { 10 | daysTempRange 11 | constructor(min, max) { 12 | this.daysTempRange = new TemperatureRange(min, max) 13 | } 14 | } 15 | const room = new Room(22, 24) 16 | 17 | class HeatingPlan { 18 | _temperatureRange 19 | constructor(low, high) { 20 | this._temperatureRange = new TemperatureRange(low, high) 21 | } 22 | withinRange(bottom, top) { 23 | return bottom >= this._temperatureRange.low && top <= this._temperatureRange.high 24 | } 25 | } 26 | 27 | const client = () => { 28 | const plan = new HeatingPlan(21, 25) 29 | const low = room.daysTempRange.low 30 | const high = room.daysTempRange.high 31 | if (!plan.withinRange(low, high)) { 32 | console.log('방 온도가 지정 범위를 벗어났습니다.') 33 | } else { 34 | console.log('적정 온도입니다.') 35 | } 36 | } 37 | client() 38 | -------------------------------------------------------------------------------- /ch8/01-2.js: -------------------------------------------------------------------------------- 1 | class Account { 2 | daysOverdrawn 3 | type = { isPremium: false } 4 | constructor(daysOverdrawn, type) { 5 | this.daysOverdrawn = daysOverdrawn 6 | this.type = type 7 | } 8 | get bankCharge() { 9 | let result = 4.5 10 | if (this.daysOverdrawn > 0) result += this.overdraftCharge 11 | return result 12 | } 13 | get overdraftCharge() { 14 | // 마통이자 15 | if (this.type.isPremium) { 16 | const baseCharge = 10 17 | if (this.daysOverdrawn <= 7) return baseCharge 18 | return baseCharge + (this.daysOverdrawn - 7) * 0.85 19 | } 20 | return this.daysOverdrawn * 1.75 21 | } 22 | } 23 | 24 | const loan = new Account(10, { isPremium: true }) 25 | const repo = new Account(10, { isPremium: false }) 26 | 27 | console.log({ name: 'loan', charge: loan.bankCharge, overdraftCharge: loan.overdraftCharge }) 28 | console.log({ name: 'repo', charge: repo.bankCharge, overdraftCharge: repo.overdraftCharge }) 29 | -------------------------------------------------------------------------------- /ch8/06-1.js: -------------------------------------------------------------------------------- 1 | const retreivePricingPlan = () => ({ 2 | base: 50, // 기본요금 3 | unit: 100, // 제품 하나당 가격 4 | discountThreshold: 7, // 몇개 이상부터 할인 적용할지 (8개: 0개 할인. 8개: 1개 할인. 10개: 3개 할인) 5 | discountFactor: 20, // 개당 할인액 6 | }) 7 | const retreiveOrder = () => ({ 8 | units: 8, 9 | isRepeat: true, // 반복주문시 추가할인 10 | }) 11 | const chargeOrder = charge => console.log(charge) 12 | 13 | // 반복주문, 8개 주문시: 14 | // 기본요금50 + 주문액 100 * 8 = 850 15 | // threshold 초과 1개에 대한 할인액 20 16 | // 반복주문에 대한 추가할인액 20 17 | // result: 810 18 | 19 | const pricingPlan = retreivePricingPlan() 20 | const order = retreiveOrder() 21 | const baseCharge = pricingPlan.base 22 | let charge 23 | const chargePerUnit = pricingPlan.unit 24 | const units = order.units 25 | let discount 26 | charge = baseCharge + units * chargePerUnit 27 | let discountableUnits = Math.max(units - pricingPlan.discountThreshold, 0) 28 | discount = discountableUnits * pricingPlan.discountFactor 29 | if (order.isRepeat) discount += 20 30 | charge = charge - discount 31 | chargeOrder(charge) 32 | -------------------------------------------------------------------------------- /ch6/09.js: -------------------------------------------------------------------------------- 1 | const acquireReading = () => ({ 2 | customer: 'ivan', 3 | quantity: 10, 4 | month: 5, 5 | year: 2017, 6 | }) 7 | const baseRate = (month, year) => year - 2000 + month 8 | 9 | const client1 = () => { 10 | const aReading = acquireReading() 11 | const baseCharge = baseRate(aReading.month, aReading.year) * aReading.quantity 12 | return baseCharge 13 | } 14 | 15 | const client2 = () => { 16 | const taxThreshold = year => (year - 2000) * 0.1 17 | const aReading = acquireReading() 18 | const base = baseRate(aReading.month, aReading.year) * aReading.quantity 19 | const taxableCharge = Math.max(0, base - taxThreshold(aReading.year)) 20 | return taxableCharge 21 | } 22 | 23 | const client3 = () => { 24 | const aReading = acquireReading() 25 | const calculateBaseCharge = aReading => baseRate(aReading.month, aReading.year) * aReading.quantity 26 | const basicChargeAmount = calculateBaseCharge(aReading) 27 | return basicChargeAmount 28 | } 29 | 30 | ;[client1, client2, client3].forEach(c => console.log(c())) 31 | -------------------------------------------------------------------------------- /ch6/10.js: -------------------------------------------------------------------------------- 1 | const acquireReading = () => ({ 2 | customer: 'ivan', 3 | quantity: 10, 4 | month: 5, 5 | year: 2017, 6 | }) 7 | const baseRate = (month, year) => year - 2000 + month 8 | 9 | const client1 = () => { 10 | const aReading = acquireReading() 11 | const baseCharge = baseRate(aReading.month, aReading.year) * aReading.quantity 12 | return baseCharge 13 | } 14 | 15 | const client2 = () => { 16 | const taxThreshold = year => (year - 2000) * 0.1 17 | const aReading = acquireReading() 18 | const base = baseRate(aReading.month, aReading.year) * aReading.quantity 19 | const taxableCharge = Math.max(0, base - taxThreshold(aReading.year)) 20 | return taxableCharge 21 | } 22 | 23 | const client3 = () => { 24 | const aReading = acquireReading() 25 | const calculateBaseCharge = aReading => baseRate(aReading.month, aReading.year) * aReading.quantity 26 | const basicChargeAmount = calculateBaseCharge(aReading) 27 | return basicChargeAmount 28 | } 29 | 30 | ;[client1, client2, client3].forEach(c => console.log(c())) 31 | -------------------------------------------------------------------------------- /ch10/05-2.js: -------------------------------------------------------------------------------- 1 | const registry = { billingPlans: { basic: '' } } 2 | class Site { 3 | _customer 4 | get customer() { 5 | return this._customer 6 | } 7 | } 8 | 9 | class Customer { 10 | _name 11 | _billingPlan 12 | _paymentHistory 13 | get name() { 14 | return this._name 15 | } 16 | get billingPlan() { 17 | return this._billingPlan 18 | } 19 | set billingPlan(arg) { 20 | this._billingPlan = arg 21 | } 22 | get paymentHistory() { 23 | return this._paymentHistory 24 | } 25 | } 26 | 27 | const client1 = () => { 28 | const customer = new Site().customer 29 | //... 30 | let customerName 31 | if (customer === '미확인 고객') customerName = '거주자' 32 | else customerName = customer.name 33 | } 34 | const client2 = () => { 35 | const customer = new Site().customer 36 | const plan = customer === '미확인 고객' ? registry.billingPlans.basic : customer.billingPlan 37 | } 38 | const client3 = () => { 39 | const customer = new Site().customer 40 | const weeksDelinquent = customer === '미확인 고객' ? 0 : customer.paymentHsitry.weeksDelinquentInLastYear 41 | } 42 | -------------------------------------------------------------------------------- /ch11/13.js: -------------------------------------------------------------------------------- 1 | const Resource = (() => { 2 | let id = 0 3 | return class Resource { 4 | id 5 | constructor() { 6 | id += 1 7 | this.id = id 8 | } 9 | static create() { 10 | return new Resource() 11 | } 12 | } 13 | })() 14 | 15 | class ResourcePool { 16 | available = [] 17 | allocated = new Set() 18 | get() { 19 | let result 20 | try { 21 | result = this.available.pop() 22 | if (!result) throw Error('no available resource') 23 | this.allocated.add(result) 24 | } catch (e) { 25 | result = Resource.create() 26 | this.allocated.add(result) 27 | } 28 | return result 29 | } 30 | add() { 31 | this.available.push(Resource.create()) 32 | } 33 | } 34 | 35 | const pool = new ResourcePool() 36 | pool.get() 37 | console.log({ available: pool.available, allocated: pool.allocated }) 38 | pool.add() 39 | pool.add() 40 | pool.add() 41 | console.log({ available: pool.available, allocated: pool.allocated }) 42 | pool.get() 43 | pool.get() 44 | pool.get() 45 | console.log({ available: pool.available, allocated: pool.allocated }) 46 | pool.get() 47 | console.log({ available: pool.available, allocated: pool.allocated }) 48 | -------------------------------------------------------------------------------- /ch10/04-1.js: -------------------------------------------------------------------------------- 1 | const feathers = birds => new Map(birds.map(b => [b.name, feather(b)])) 2 | const velocities = birds => new Map(birds.map(b => [b.name, velocity(b)])) 3 | 4 | const feather = bird => { 5 | switch (bird.type) { 6 | case '유럽 제비': 7 | return '보통' 8 | case '아프리카 제비': 9 | return bird.numberOfCoconuts > 2 ? '지침' : '보통' 10 | case '노르웨이 파랑 앵무': 11 | return bird.voltage > 100 ? '그을림' : '예쁨' 12 | default: 13 | return '알수없음' 14 | } 15 | } 16 | const velocity = bird => { 17 | switch (bird.type) { 18 | case '유럽 제비': 19 | return 35 20 | case '아프리카 제비': 21 | return 40 - 2 * bird.numberOfCoconuts 22 | case '노르웨이 파랑 앵무': 23 | return bird.isNailed ? 0 : 10 + bird.voltage / 10 24 | default: 25 | return null 26 | } 27 | } 28 | 29 | const birds = [ 30 | { name: '유제', type: '유럽 제비' }, 31 | { name: '아제1', type: '아프리카 제비', numberOfCoconuts: 2 }, 32 | { name: '아제2', type: '아프리카 제비', numberOfCoconuts: 4 }, 33 | { name: '파앵1', type: '노르웨이 파랑 앵무', isNailed: false, voltage: 3000 }, 34 | { name: '파앵2', type: '노르웨이 파랑 앵무', isNailed: true, voltage: 50 }, 35 | ] 36 | console.log(...feathers(birds)) 37 | console.log(...velocities(birds)) 38 | -------------------------------------------------------------------------------- /ch11/03-1.js: -------------------------------------------------------------------------------- 1 | class Place { 2 | plusDays(time) { 3 | const d = new Date('2021-07-08T10:00:00.000Z') 4 | d.setHours(d.getHours() + time) 5 | return d 6 | } 7 | } 8 | class Order { 9 | deliveryState 10 | placedOn 11 | constructor(deliveryState) { 12 | this.deliveryState = deliveryState 13 | this.placedOn = new Place() 14 | } 15 | } 16 | const deliveryDate = (anOrder, isRush) => { 17 | if (isRush) { 18 | let deliveryTime 19 | if (['MA', 'CT'].includes(anOrder.deliveryState)) deliveryTime = 1 20 | else if (['NY', 'NH'].includes(anOrder.deliveryState)) deliveryTime = 2 21 | else deliveryTime = 3 22 | return anOrder.placedOn.plusDays(1 + deliveryTime) 23 | } else { 24 | let deliveryTime 25 | if (['MA', 'CT', 'NY'].includes(anOrder.deliveryState)) deliveryTime = 2 26 | else if (['ME', 'NH'].includes(anOrder.deliveryState)) deliveryTime = 3 27 | else deliveryTime = 4 28 | return anOrder.placedOn.plusDays(2 + deliveryTime) 29 | } 30 | } 31 | 32 | console.log(deliveryDate(new Order('MA'), true)) 33 | console.log(deliveryDate(new Order('NH'), true)) 34 | console.log(deliveryDate(new Order('CT'), false)) 35 | console.log(deliveryDate(new Order('ME'), false)) 36 | -------------------------------------------------------------------------------- /ch10/05-1.js: -------------------------------------------------------------------------------- 1 | const registry = { billingPlans: { basic: '' } } 2 | class Site { 3 | _customer 4 | get customer() { 5 | return this._customer 6 | } 7 | } 8 | 9 | class Customer { 10 | _name 11 | _billingPlan 12 | _paymentHistory 13 | get name() { 14 | return this._name 15 | } 16 | get billingPlan() { 17 | return this._billingPlan 18 | } 19 | set billingPlan(arg) { 20 | this._billingPlan = arg 21 | } 22 | get paymentHistory() { 23 | return this._paymentHistory 24 | } 25 | } 26 | 27 | const client1 = () => { 28 | const customer = new Site().customer 29 | //... 30 | let customerName 31 | if (customer === '미확인 고객') customerName = '거주자' 32 | else customerName = customer.name 33 | } 34 | const client2 = () => { 35 | const customer = new Site().customer 36 | const plan = customer === '미확인 고객' ? registry.billingPlans.basic : customer.billingPlan 37 | } 38 | const client3 = () => { 39 | const customer = new Site().customer 40 | if (customer !== '미확인 고객') customer.billingPlan = 'new Plan' 41 | } 42 | const client4 = () => { 43 | const customer = new Site().customer 44 | const weeksDelinquent = customer === '미확인 고객' ? 0 : customer.paymentHsitry.weeksDelinquentInLastYear 45 | } 46 | -------------------------------------------------------------------------------- /ch10/05-3.js: -------------------------------------------------------------------------------- 1 | import cloneDeep from 'lodash/cloneDeep.js' 2 | const RECORDS = [ 3 | { 4 | name: '애크미 보스턴', 5 | location: 'Malden MA', 6 | customer: { 7 | name: '애크미 산업', 8 | billingPlan: 'plan-451', 9 | paymentHistory: { 10 | weeksDelinquentInLastYear: 7, 11 | }, 12 | }, 13 | }, 14 | { 15 | name: '물류창고 15', 16 | location: 'Malden MA', 17 | customer: '미확인 고객', 18 | }, 19 | ] 20 | const registry = { billingPlans: { basic: '' } } 21 | class Site { 22 | _customer 23 | get customer() { 24 | return this._customer 25 | } 26 | } 27 | const acquireSiteData = () => new Site() 28 | 29 | const client1 = () => { 30 | const site = acquireSiteData() 31 | const customer = site.customer 32 | let customerName 33 | if (customer === '미확인 고객') customerName = '거주자' 34 | else customerName = customer.name 35 | } 36 | const client2 = () => { 37 | const customer = acquireSiteData().customer 38 | const plan = customer === '미확인 고객' ? registry.billingPlans.basic : customer.billingPlan 39 | } 40 | const client3 = () => { 41 | const customer = acquireSiteData().customer 42 | const weeksDelinquent = customer === '미확인 고객' ? 0 : customer.paymentHsitry.weeksDelinquentInLastYear 43 | } 44 | -------------------------------------------------------------------------------- /ch7/06.js: -------------------------------------------------------------------------------- 1 | class TrackingInformation { 2 | _shippingCompany 3 | _trackingNumber 4 | get shippingCompany() { 5 | return this._shippingCompany 6 | } 7 | set shippingCompany(arg) { 8 | this._shippingCompany = arg 9 | } 10 | get trackingNumber() { 11 | return this._trackingNumber 12 | } 13 | set trackingNumber(arg) { 14 | this._trackingNumber = arg 15 | } 16 | get display() { 17 | return `${this.shippingCompany}: ${this.trackingNumber}` 18 | } 19 | } 20 | 21 | class Shipment { 22 | _trackingInformation 23 | constructor() { 24 | this._trackingInformation = new TrackingInformation() 25 | } 26 | get trackingInfo() { 27 | return this._trackingInformation.display 28 | } 29 | get trackingInformation() { 30 | return this._trackingInformation 31 | } 32 | set trackingInformation(aTrackingInformation) { 33 | this._trackingInformation = aTrackingInformation 34 | } 35 | } 36 | 37 | const client1 = () => { 38 | const aShipment = new Shipment() 39 | const vendor = { name: 'A-SHIP', number: '010-1234-5678' } 40 | aShipment.trackingInformation.shippingCompany = vendor.name 41 | aShipment.trackingInformation.trackingNumber = vendor.number 42 | return aShipment.trackingInfo 43 | } 44 | console.log(client1()) 45 | -------------------------------------------------------------------------------- /ch12/08.js: -------------------------------------------------------------------------------- 1 | class Employee { 2 | #name 3 | #id 4 | #monthlyCost 5 | constructor(name, id, monthlyCost) { 6 | this.#name = name 7 | this.#id = id 8 | this.#monthlyCost = monthlyCost 9 | } 10 | get monthlyCost() { 11 | return this.#monthlyCost 12 | } 13 | get name() { 14 | return this.#name 15 | } 16 | get id() { 17 | return this.#id 18 | } 19 | get annualCost() { 20 | return this.#monthlyCost * 12 21 | } 22 | } 23 | 24 | class Department { 25 | #name 26 | #staff 27 | constructor(name, staff) { 28 | this.#name = name 29 | this.#staff = staff 30 | } 31 | get name() { 32 | return this.#name 33 | } 34 | get staff() { 35 | return this.#staff 36 | } 37 | get totalMonthlyCost() { 38 | return this.#staff.map(e => e.monthlyCost).reduce((sum, cost) => sum + cost, 0) 39 | } 40 | get headCount() { 41 | return this.staff.length 42 | } 43 | get totalAnnualCost() { 44 | return this.totalMonthlyCost * 12 45 | } 46 | } 47 | 48 | const roy = new Employee('Roy', '123', 100) 49 | const jay = new Employee('Jay', '456', 200) 50 | const sales = new Department('Sales', [roy, jay]) 51 | 52 | console.log(roy.annualCost) 53 | console.log(jay.annualCost) 54 | console.log(sales.totalAnnualCost) 55 | -------------------------------------------------------------------------------- /ch1/statement.js: -------------------------------------------------------------------------------- 1 | const statement = (invoice, plays) => { 2 | let totalAmount = 0 3 | let volumeCredits = 0 4 | let result = `청구 내역 (고객명: ${invoice.customer})\n` 5 | const format = new Intl.NumberFormat('en-US', { 6 | style: 'currency', 7 | currency: 'USD', 8 | minimumFractionDigits: 2, 9 | }).format 10 | 11 | for (let perf of invoice.performances) { 12 | const play = plays[perf.playID] 13 | let thisAmount = 0 14 | 15 | switch (play.type) { 16 | case 'tragedy': { 17 | thisAmount = 40000 18 | if (perf.audience > 30) thisAmount += 1000 * (perf.audience - 30) 19 | break 20 | } 21 | case 'comedy': { 22 | thisAmount = 30000 23 | if (perf.audience > 20) thisAmount += 10000 + 500 * (perf.audience - 20) 24 | thisAmount += 300 * perf.audience 25 | break 26 | } 27 | default: 28 | throw new Error(`알 수 없는 장르: ${play.type}`) 29 | } 30 | 31 | volumeCredits += Math.max(perf.audience - 30, 0) 32 | if (play.type === 'comedy') volumeCredits += Math.floor(perf.audience / 5) 33 | result += ` ${play.name}: ${format(thisAmount / 100)} (${perf.audience}석)\n` 34 | totalAmount += thisAmount 35 | } 36 | result += `총액: ${format(totalAmount / 100)}\n` 37 | result += `적립 포인트: ${volumeCredits}점\n` 38 | return result 39 | } 40 | 41 | export default statement 42 | -------------------------------------------------------------------------------- /ch11/03-2.js: -------------------------------------------------------------------------------- 1 | class Place { 2 | _date 3 | constructor() { 4 | this._date = new Date('2021-07-08T10:00:00.000Z') 5 | } 6 | plusDays(time) { 7 | this._date.setHours(this._date.getHours() + time) 8 | return this 9 | } 10 | minusDays(time) { 11 | this._date.setHours(this._date.getHours() - time) 12 | return this 13 | } 14 | get date() { 15 | return this._date 16 | } 17 | } 18 | class Order { 19 | deliveryState 20 | placedOn 21 | constructor(deliveryState) { 22 | this.deliveryState = deliveryState 23 | this.placedOn = new Place() 24 | } 25 | } 26 | 27 | const deliveryDate = (anOrder, isRush) => { 28 | let deliveryTime 29 | if (['MA', 'CT'].includes(anOrder.deliveryState)) deliveryTime = isRush ? 1 : 2 30 | else if (['NY', 'NH'].includes(anOrder.deliveryState)) { 31 | deliveryTime = 2 32 | if (anOrder.deliveryState === 'NH' && isRush) deliveryTime = 3 33 | } else if (isRush) deliveryTime = 3 34 | else if (anOrder.deliveryState === 'ME') deliveryTime = 3 35 | else deliveryTime = 4 36 | let result = anOrder.placedOn.plusDays(2 + deliveryTime) 37 | if (isRush) result = result.minusDays(1) 38 | return result 39 | } 40 | 41 | console.log(deliveryDate(new Order('MA'), true).date) 42 | console.log(deliveryDate(new Order('NH'), true).date) 43 | console.log(deliveryDate(new Order('CT'), false).date) 44 | console.log(deliveryDate(new Order('ME'), false).date) 45 | -------------------------------------------------------------------------------- /ch7/02.js: -------------------------------------------------------------------------------- 1 | const COURSES = { 2 | korean: { basic: 'korean', advanced: 'korean advanced' }, 3 | english: { basic: 'english', advanced: 'english advanced' }, 4 | mathematics: { basic: 'mathematics', advanced: 'mathematics advanced' }, 5 | } 6 | 7 | class Person { 8 | _name = '' 9 | _courses = [] 10 | constructor(name) { 11 | this._name = name 12 | } 13 | get name() { 14 | return this._name 15 | } 16 | get courses() { 17 | return this._courses 18 | } 19 | set courses(aList) { 20 | this._courses = aList 21 | } 22 | } 23 | 24 | class Course { 25 | _name = '' 26 | _isAdvanced = false 27 | constructor(name, isAdvanced) { 28 | this._name = name 29 | this._isAdvanced = isAdvanced 30 | } 31 | get name() { 32 | return this._name 33 | } 34 | get isAdvanced() { 35 | return this._isAdvanced 36 | } 37 | } 38 | 39 | const readBasicCourseNames = filename => Object.values(filename).map(c => c.basic) 40 | 41 | const client1 = () => { 42 | const aPerson = new Person('파울러') 43 | 44 | const numAdvancedCourses = aPerson.courses.filter(c => c.isAdvanced).length 45 | 46 | const basicCourseNames = readBasicCourseNames(COURSES) 47 | aPerson.courses = basicCourseNames.map(name => new Course(name, false)) 48 | 49 | return aPerson 50 | 51 | // 52 | // for(const name of readBasicCourseNames(COURSES)) { 53 | // aPerson.courses.push(new Course(name, false)) 54 | // } 55 | } 56 | console.log(client1()) 57 | -------------------------------------------------------------------------------- /ch4/province.js: -------------------------------------------------------------------------------- 1 | import Producer from './producer.js' 2 | 3 | export default class Province { 4 | constructor(doc) { 5 | this._name = doc.name 6 | this._producers = [] 7 | this._totalProduction = 0 8 | this._demand = doc.demand 9 | this._price = doc.price 10 | doc.producers.forEach(d => this.addProducer(new Producer(this, d))) 11 | } 12 | 13 | addProducer(arg) { 14 | this._producers.push(arg) 15 | this._totalProduction += arg.production 16 | } 17 | get name() { 18 | return this._name 19 | } 20 | get producers() { 21 | return this._producers 22 | } 23 | get totalProduction() { 24 | return this._totalProduction 25 | } 26 | set totalProduction(arg) { 27 | this._totalProduction = arg 28 | } 29 | get demand() { 30 | return this._demand 31 | } 32 | set demand(arg) { 33 | this._demand = parseInt(arg) 34 | } 35 | get price() { 36 | return this._price 37 | } 38 | set price(arg) { 39 | this._price = parseInt(arg) 40 | } 41 | get shortfall() { 42 | return this._demand - this.totalProduction 43 | } 44 | get profit() { 45 | return this.demandValue - this.demandCost 46 | } 47 | get demandValue() { 48 | return this.satisfiedDemand * this.price 49 | } 50 | get satisfiedDemand() { 51 | return Math.min(this._demand, this.totalProduction) 52 | } 53 | get demandCost() { 54 | let remainingDemand = this.demand 55 | let result = 0 56 | this.producers 57 | .sort((a, b) => a.cost - b.cost) 58 | .forEach(p => { 59 | const contribution = Math.min(remainingDemand, p.production) 60 | remainingDemand -= contribution 61 | result += contribution * p.cost 62 | }) 63 | return result 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ch12/11.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs' 2 | 3 | class CatalogItem { 4 | _id 5 | _title 6 | _tags 7 | constructor(id, title, tags) { 8 | this._id = id 9 | this._title = title 10 | this._tags = tags 11 | } 12 | get id() { 13 | return this._id 14 | } 15 | get title() { 16 | return this._title 17 | } 18 | hasTag(arg) { 19 | return this._tags.includes(arg) 20 | } 21 | } 22 | 23 | class Scroll extends CatalogItem { 24 | #lastCleaned 25 | constructor(id, title, tags, dataLastCleaned) { 26 | super(id, title, tags) 27 | this.#lastCleaned = dataLastCleaned 28 | } 29 | needsCleaning(targetDate) { 30 | const threshold = this.hasTag('revered') ? 700 : 1500 31 | return this.daysSinceLastCleaning(targetDate) > threshold 32 | } 33 | daysSinceLastCleaning(targetDate) { 34 | return targetDate.diff(this.#lastCleaned, 'd') 35 | } 36 | } 37 | 38 | const data = [ 39 | { 40 | id: 'A001', 41 | catalogData: { 42 | id: 'icespear', 43 | title: '아이스스피어', 44 | tags: ['magic', 'revered'], 45 | }, 46 | lastCleaned: '2018-11-01', 47 | }, 48 | { 49 | id: 'B002', 50 | catalogData: { 51 | id: 'fieball', 52 | title: '파이어볼', 53 | tags: ['magic'], 54 | }, 55 | lastCleaned: '2018-09-01', 56 | }, 57 | { 58 | id: 'C003', 59 | catalogData: { 60 | id: 'meteor', 61 | title: '메테오', 62 | tags: ['magic', 'revered'], 63 | }, 64 | lastCleaned: '2020-02-01', 65 | }, 66 | ] 67 | const scrolls = data.map( 68 | record => new Scroll(record.id, record.catalogData.title, record.catalogData.tags, dayjs(record.lastCleaned)), 69 | ) 70 | scrolls.forEach(scroll => { 71 | console.log({ 72 | title: scroll.title, 73 | needsCleaning: scroll.needsCleaning(dayjs()), 74 | daysSinceLastCleaning: scroll.daysSinceLastCleaning(dayjs()), 75 | hasRevered: scroll.hasTag('revered'), 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /ch10/04-2.js: -------------------------------------------------------------------------------- 1 | const rating = (voyage, history) => { 2 | // 투자 등급 3 | const vpf = voyageProfitFactor(voyage, history) 4 | const vr = voyageRisk(voyage) 5 | const chr = captainHistoryRisk(voyage, history) 6 | if (vpf * 3 > vr + chr * 2) return 'A' 7 | return 'B' 8 | } 9 | 10 | const voyageRisk = voyage => { 11 | // 항해 경로 위험요소 12 | let result = 1 13 | if (voyage.length > 4) result += 2 14 | if (voyage.length > 8) result += voyage.length - 8 15 | if (['중국', '동인도'].includes(voyage.zone)) result += 4 16 | return Math.max(result, 0) 17 | } 18 | 19 | const hasChina = history => history.some(v => v.zone === '중국') 20 | const captainHistoryRisk = (voyage, history) => { 21 | // 선장의 항해이력 위험요소 22 | let result = 1 23 | if (history.length < 5) result += 4 24 | result += history.filter(v => v.profit < 0).length 25 | if (voyage.zone === '중국' && hasChina(history)) result -= 2 26 | return Math.max(result, 0) 27 | } 28 | 29 | const voyageProfitFactor = (voyage, history) => { 30 | // 수익 요인 31 | let result = 2 32 | if (voyage.zone === '중국') result += 1 33 | if (voyage.zone === '동인도') result += 1 34 | if (voyage.zone === '중국' && hasChina(history)) { 35 | result += 3 36 | if (history.length > 10) result += 1 37 | if (voyage.length > 12) result += 1 38 | if (voyage.length > 18) result -= 1 39 | } else { 40 | if (history.length > 8) result += 1 41 | if (voyage.length > 14) result -= 1 42 | } 43 | return result 44 | } 45 | 46 | const voyage = { zone: '서인도', length: 10 } 47 | const histories = [ 48 | { zone: '동인도', profit: 5 }, 49 | { zone: '서인도', profit: 15 }, 50 | { zone: '중국', profit: -2 }, 51 | { zone: '서아프리카', profit: 7 }, 52 | ] 53 | const myRating = rating(voyage, histories) 54 | console.log({ 55 | voyageRisk: voyageRisk(voyage), 56 | captainHistoryRisk: captainHistoryRisk(voyage, histories), 57 | voyageProfitFactor: voyageProfitFactor(voyage, histories), 58 | myRating, 59 | }) 60 | -------------------------------------------------------------------------------- /ch12/10-2.js: -------------------------------------------------------------------------------- 1 | class Bird { 2 | _name 3 | _feather 4 | constructor(data) { 5 | this._name = data.name 6 | this._feather = data.feather 7 | } 8 | get name() { 9 | return this._name 10 | } 11 | get feather() { 12 | return this._feather || '보통' 13 | } 14 | get airSpeedVelocity() { 15 | return null 16 | } 17 | } 18 | 19 | class EuropeanSwallow extends Bird { 20 | get airSpeedVelocity() { 21 | return 35 22 | } 23 | } 24 | class AfricanSwallow extends Bird { 25 | #numberOfCoconuts 26 | constructor(data) { 27 | super(data) 28 | this.#numberOfCoconuts = data.numberOfCoconuts 29 | } 30 | get airSpeedVelocity() { 31 | return 40 - 2 * this.#numberOfCoconuts 32 | } 33 | } 34 | class NorwegianBlueParrot extends Bird { 35 | #voltage 36 | #isNailed 37 | constructor(data) { 38 | super(data) 39 | this.#voltage = data.voltage 40 | this.#isNailed = data.isNailed 41 | } 42 | get feather() { 43 | if (this.#voltage > 100) return '그을림' 44 | return this._feather || '예쁨' 45 | } 46 | get airSpeedVelocity() { 47 | return this.#isNailed ? 0 : 10 + this.#voltage / 10 48 | } 49 | } 50 | 51 | const createBird = data => { 52 | switch (data.type) { 53 | case 'european': 54 | return new EuropeanSwallow(data) 55 | case 'african': 56 | return new AfricanSwallow(data) 57 | case 'norwegian': 58 | return new NorwegianBlueParrot(data) 59 | default: 60 | return new Bird(data) 61 | } 62 | } 63 | const birds = [ 64 | createBird({ type: 'european', name: '유제' }), 65 | createBird({ type: 'african', name: '아제1', numberOfCoconuts: 2 }), 66 | createBird({ type: 'african', name: '아제2', numberOfCoconuts: 4 }), 67 | createBird({ type: 'norwegian', name: '파앵1', isNailed: false, voltage: 3000 }), 68 | createBird({ type: 'norwegian', name: '파앵2', isNailed: true, voltage: 50 }), 69 | new Bird({ name: '가짜새' }), 70 | ] 71 | console.log(birds.map(b => ({ name: b.name, velocity: b.airSpeedVelocity, feather: b.feather }))) 72 | -------------------------------------------------------------------------------- /ch12/10-1.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs' 2 | 3 | class Booking { 4 | #show 5 | #date 6 | constructor(show, date) { 7 | this.#show = show 8 | this.#date = date 9 | } 10 | get date() { 11 | return this.#date 12 | } 13 | get show() { 14 | return this.#show 15 | } 16 | get hasTalkback() { 17 | return this.show.hasOwnProperty('talkback') && !this.isPeakDay 18 | } 19 | get basePrice() { 20 | let result = this.show.price 21 | if (this.isPeakDay) result += Math.round(result * 0.15) 22 | return result 23 | } 24 | get isPeakDay() { 25 | return this.date.isAfter(dayjs('2021-07-15')) && this.date.isBefore(dayjs('2021-07-31')) 26 | } 27 | } 28 | 29 | class PremiumBooking extends Booking { 30 | #extras 31 | constructor(show, date, extras) { 32 | super(show, date) 33 | this.#extras = extras 34 | } 35 | get hasTalkback() { 36 | return this.show.hasOwnProperty('talkback') 37 | } 38 | get basePrice() { 39 | return Math.round(super.basePrice + this.#extras.premiumFee) 40 | } 41 | get hasDinner() { 42 | return this.#extras.hasOwnProperty('dinner') && !this.isPeakDay 43 | } 44 | } 45 | 46 | const booking = new Booking({ price: 100, talkback: true }, dayjs('2021-07-11')) 47 | const premiumBooking1 = new PremiumBooking({ price: 100, talkback: true }, dayjs('2021-07-13'), { 48 | dinner: true, 49 | premiumFee: 10, 50 | }) 51 | const premiumBooking2 = new PremiumBooking({ price: 100 }, dayjs('2021-07-17'), { 52 | dinner: true, 53 | premiumFee: 10, 54 | }) 55 | console.log({ 56 | price: booking.basePrice, 57 | dinner: booking.hasDinner, 58 | talkback: booking.hasTalkback, 59 | peakDay: booking.isPeakDay, 60 | }) 61 | console.log({ 62 | price: premiumBooking1.basePrice, 63 | dinner: premiumBooking1.hasDinner, 64 | talkback: premiumBooking1.hasTalkback, 65 | peakDay: premiumBooking1.isPeakDay, 66 | }) 67 | console.log({ 68 | price: premiumBooking2.basePrice, 69 | dinner: premiumBooking2.hasDinner, 70 | talkback: premiumBooking2.hasTalkback, 71 | peakDay: premiumBooking2.isPeakDay, 72 | }) 73 | -------------------------------------------------------------------------------- /ch8/04.js: -------------------------------------------------------------------------------- 1 | const previousDateFromNow = days => new Date(Date.now() - 1000 * 60 * 60 * 24 * days) 2 | const recentDateCutoff = () => previousDateFromNow(3) 3 | 4 | const renderPhoto = (outStream, aPhoto) => { 5 | outStream.write(``) 6 | } 7 | const emitPhotoData = (outStream, photo) => { 8 | outStream.write(`

제목: ${photo.title}

`) 9 | outStream.write(`

날짜: ${photo.date.toDateString()}

`) 10 | outStream.write(`

위치: ${photo.location}

`) 11 | } 12 | const listRecentPhotos = (outStream, photos) => { 13 | photos 14 | .filter(p => p.date > recentDateCutoff()) 15 | .forEach(p => { 16 | outStream.write('
\n') 17 | emitPhotoData(outStream, p) 18 | outStream.write('
\n') 19 | }) 20 | } 21 | const renderPerson = (outStream, person) => { 22 | outStream.write(`

${person.name}

\n`) 23 | renderPhoto(outStream, person.photo) 24 | emitPhotoData(outStream, person.photo) 25 | } 26 | 27 | const photos = [ 28 | { title: '로이사진1', location: '양재천', date: previousDateFromNow(0), url: 'http://abc.com/1' }, 29 | { title: '로이사진2', location: '홍대', date: previousDateFromNow(1), url: 'http://abc.com/2' }, 30 | { title: '로이사진3', location: '이태원', date: previousDateFromNow(2), url: 'http://abc.com/3' }, 31 | { title: '로이사진4', location: '판교', date: previousDateFromNow(3), url: 'http://abc.com/4' }, 32 | { title: '로이사진5', location: '이태원', date: previousDateFromNow(4), url: 'http://abc.com/5' }, 33 | { title: '로이사진6', location: '강남', date: previousDateFromNow(5), url: 'http://abc.com/6' }, 34 | { title: '로이사진7', location: '탄천', date: previousDateFromNow(6), url: 'http://abc.com/7' }, 35 | { title: '로이사진8', location: '잠실새내', date: previousDateFromNow(7), url: 'http://abc.com/8' }, 36 | ] 37 | const outstream = { 38 | res: '', 39 | write(text) { 40 | this.res += text 41 | }, 42 | } 43 | outstream.write('** renderPerson **\n') 44 | renderPerson(outstream, { name: '재남', photo: photos[0] }) 45 | outstream.write('\n\n** listRecentPhotos **\n') 46 | listRecentPhotos(outstream, photos) 47 | console.log(outstream.res) 48 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@sindresorhus/is@^0.14.0": 6 | version "0.14.0" 7 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" 8 | integrity sha1-n7OjzzEyMoFR81PeRjLgHlIQK+o= 9 | 10 | "@szmarczak/http-timer@^1.1.2": 11 | version "1.1.2" 12 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" 13 | integrity sha1-sWZeLEYaLNkvTBu/UNVFTeDUtCE= 14 | dependencies: 15 | defer-to-connect "^1.0.1" 16 | 17 | "@ungap/promise-all-settled@1.1.2": 18 | version "1.1.2" 19 | resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" 20 | integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== 21 | 22 | abbrev@1: 23 | version "1.1.1" 24 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 25 | integrity sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg= 26 | 27 | ansi-align@^3.0.0: 28 | version "3.0.0" 29 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" 30 | integrity sha1-tTazcc9ofKrvI2wY0+If43l0Z8s= 31 | dependencies: 32 | string-width "^3.0.0" 33 | 34 | ansi-colors@4.1.1: 35 | version "4.1.1" 36 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" 37 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== 38 | 39 | ansi-regex@^3.0.0: 40 | version "3.0.0" 41 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 42 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 43 | 44 | ansi-regex@^4.1.0: 45 | version "4.1.0" 46 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 47 | integrity sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc= 48 | 49 | ansi-regex@^5.0.0: 50 | version "5.0.0" 51 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 52 | integrity sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U= 53 | 54 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 55 | version "4.3.0" 56 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 57 | integrity sha1-7dgDYornHATIWuegkG7a00tkiTc= 58 | dependencies: 59 | color-convert "^2.0.1" 60 | 61 | anymatch@~3.1.2: 62 | version "3.1.2" 63 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 64 | integrity sha1-wFV8CWrzLxBhmPT04qODU343hxY= 65 | dependencies: 66 | normalize-path "^3.0.0" 67 | picomatch "^2.0.4" 68 | 69 | argparse@^2.0.1: 70 | version "2.0.1" 71 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 72 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 73 | 74 | assertion-error@^1.1.0: 75 | version "1.1.0" 76 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 77 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 78 | 79 | balanced-match@^1.0.0: 80 | version "1.0.2" 81 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 82 | integrity sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4= 83 | 84 | binary-extensions@^2.0.0: 85 | version "2.2.0" 86 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 87 | integrity sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0= 88 | 89 | boxen@^4.2.0: 90 | version "4.2.0" 91 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" 92 | integrity sha1-5BG2I1fW1tNlh8isPV2XTaoHDmQ= 93 | dependencies: 94 | ansi-align "^3.0.0" 95 | camelcase "^5.3.1" 96 | chalk "^3.0.0" 97 | cli-boxes "^2.2.0" 98 | string-width "^4.1.0" 99 | term-size "^2.1.0" 100 | type-fest "^0.8.1" 101 | widest-line "^3.1.0" 102 | 103 | brace-expansion@^1.1.7: 104 | version "1.1.11" 105 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 106 | integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= 107 | dependencies: 108 | balanced-match "^1.0.0" 109 | concat-map "0.0.1" 110 | 111 | braces@~3.0.2: 112 | version "3.0.2" 113 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 114 | integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= 115 | dependencies: 116 | fill-range "^7.0.1" 117 | 118 | browser-stdout@1.3.1: 119 | version "1.3.1" 120 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 121 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 122 | 123 | cacheable-request@^6.0.0: 124 | version "6.1.0" 125 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" 126 | integrity sha1-IP+4vRYrpL4R6VZ9gj22UQUsqRI= 127 | dependencies: 128 | clone-response "^1.0.2" 129 | get-stream "^5.1.0" 130 | http-cache-semantics "^4.0.0" 131 | keyv "^3.0.0" 132 | lowercase-keys "^2.0.0" 133 | normalize-url "^4.1.0" 134 | responselike "^1.0.2" 135 | 136 | camelcase@^5.3.1: 137 | version "5.3.1" 138 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 139 | integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA= 140 | 141 | camelcase@^6.0.0: 142 | version "6.2.0" 143 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" 144 | integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== 145 | 146 | chai@^4.3.4: 147 | version "4.3.4" 148 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" 149 | integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== 150 | dependencies: 151 | assertion-error "^1.1.0" 152 | check-error "^1.0.2" 153 | deep-eql "^3.0.1" 154 | get-func-name "^2.0.0" 155 | pathval "^1.1.1" 156 | type-detect "^4.0.5" 157 | 158 | chalk@^3.0.0: 159 | version "3.0.0" 160 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" 161 | integrity sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ= 162 | dependencies: 163 | ansi-styles "^4.1.0" 164 | supports-color "^7.1.0" 165 | 166 | chalk@^4.1.0: 167 | version "4.1.1" 168 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" 169 | integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== 170 | dependencies: 171 | ansi-styles "^4.1.0" 172 | supports-color "^7.1.0" 173 | 174 | check-error@^1.0.2: 175 | version "1.0.2" 176 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 177 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 178 | 179 | chokidar@3.5.2, chokidar@^3.2.2: 180 | version "3.5.2" 181 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" 182 | integrity sha1-26OXb8rbAW9m/TZQIdkWANAcHnU= 183 | dependencies: 184 | anymatch "~3.1.2" 185 | braces "~3.0.2" 186 | glob-parent "~5.1.2" 187 | is-binary-path "~2.1.0" 188 | is-glob "~4.0.1" 189 | normalize-path "~3.0.0" 190 | readdirp "~3.6.0" 191 | optionalDependencies: 192 | fsevents "~2.3.2" 193 | 194 | ci-info@^2.0.0: 195 | version "2.0.0" 196 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" 197 | integrity sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y= 198 | 199 | cli-boxes@^2.2.0: 200 | version "2.2.1" 201 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" 202 | integrity sha1-3dUDXSUJT84iDpyrQKRYQKRAMY8= 203 | 204 | cliui@^7.0.2: 205 | version "7.0.4" 206 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 207 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 208 | dependencies: 209 | string-width "^4.2.0" 210 | strip-ansi "^6.0.0" 211 | wrap-ansi "^7.0.0" 212 | 213 | clone-response@^1.0.2: 214 | version "1.0.2" 215 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" 216 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= 217 | dependencies: 218 | mimic-response "^1.0.0" 219 | 220 | color-convert@^2.0.1: 221 | version "2.0.1" 222 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 223 | integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= 224 | dependencies: 225 | color-name "~1.1.4" 226 | 227 | color-name@~1.1.4: 228 | version "1.1.4" 229 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 230 | integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= 231 | 232 | concat-map@0.0.1: 233 | version "0.0.1" 234 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 235 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 236 | 237 | configstore@^5.0.1: 238 | version "5.0.1" 239 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" 240 | integrity sha1-02UCG130uYzdGH1qOw4/anzF7ZY= 241 | dependencies: 242 | dot-prop "^5.2.0" 243 | graceful-fs "^4.1.2" 244 | make-dir "^3.0.0" 245 | unique-string "^2.0.0" 246 | write-file-atomic "^3.0.0" 247 | xdg-basedir "^4.0.0" 248 | 249 | crypto-random-string@^2.0.0: 250 | version "2.0.0" 251 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" 252 | integrity sha1-7yp6lm7BEIM4g2m6oC6+rSKbMNU= 253 | 254 | dayjs@^1.10.6: 255 | version "1.10.6" 256 | resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63" 257 | integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw== 258 | 259 | debug@4.3.1: 260 | version "4.3.1" 261 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" 262 | integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== 263 | dependencies: 264 | ms "2.1.2" 265 | 266 | debug@^2.2.0: 267 | version "2.6.9" 268 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 269 | integrity sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8= 270 | dependencies: 271 | ms "2.0.0" 272 | 273 | debug@^3.2.6: 274 | version "3.2.7" 275 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" 276 | integrity sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o= 277 | dependencies: 278 | ms "^2.1.1" 279 | 280 | decamelize@^4.0.0: 281 | version "4.0.0" 282 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" 283 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 284 | 285 | decompress-response@^3.3.0: 286 | version "3.3.0" 287 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 288 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= 289 | dependencies: 290 | mimic-response "^1.0.0" 291 | 292 | deep-eql@^3.0.1: 293 | version "3.0.1" 294 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 295 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 296 | dependencies: 297 | type-detect "^4.0.0" 298 | 299 | deep-extend@^0.6.0: 300 | version "0.6.0" 301 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 302 | integrity sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw= 303 | 304 | defer-to-connect@^1.0.1: 305 | version "1.1.3" 306 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" 307 | integrity sha1-MxrgUMCNz3ifjIOnuB8O2U9KxZE= 308 | 309 | diff@5.0.0: 310 | version "5.0.0" 311 | resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" 312 | integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== 313 | 314 | dot-prop@^5.2.0: 315 | version "5.3.0" 316 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" 317 | integrity sha1-kMzOcIzZzYLMTcjD3dmr3VWyDog= 318 | dependencies: 319 | is-obj "^2.0.0" 320 | 321 | duplexer3@^0.1.4: 322 | version "0.1.4" 323 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" 324 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= 325 | 326 | emoji-regex@^7.0.1: 327 | version "7.0.3" 328 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 329 | integrity sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY= 330 | 331 | emoji-regex@^8.0.0: 332 | version "8.0.0" 333 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 334 | integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc= 335 | 336 | end-of-stream@^1.1.0: 337 | version "1.4.4" 338 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 339 | integrity sha1-WuZKX0UFe682JuwU2gyl5LJDHrA= 340 | dependencies: 341 | once "^1.4.0" 342 | 343 | escalade@^3.1.1: 344 | version "3.1.1" 345 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 346 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 347 | 348 | escape-goat@^2.0.0: 349 | version "2.1.1" 350 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" 351 | integrity sha1-Gy3HcANnbEV+x2Cy3GjttkgYhnU= 352 | 353 | escape-string-regexp@4.0.0: 354 | version "4.0.0" 355 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 356 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 357 | 358 | fill-range@^7.0.1: 359 | version "7.0.1" 360 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 361 | integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= 362 | dependencies: 363 | to-regex-range "^5.0.1" 364 | 365 | find-up@5.0.0: 366 | version "5.0.0" 367 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 368 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 369 | dependencies: 370 | locate-path "^6.0.0" 371 | path-exists "^4.0.0" 372 | 373 | flat@^5.0.2: 374 | version "5.0.2" 375 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" 376 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== 377 | 378 | fs.realpath@^1.0.0: 379 | version "1.0.0" 380 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 381 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 382 | 383 | fsevents@~2.3.2: 384 | version "2.3.2" 385 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 386 | integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro= 387 | 388 | get-caller-file@^2.0.5: 389 | version "2.0.5" 390 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 391 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 392 | 393 | get-func-name@^2.0.0: 394 | version "2.0.0" 395 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 396 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 397 | 398 | get-stream@^4.1.0: 399 | version "4.1.0" 400 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 401 | integrity sha1-wbJVV189wh1Zv8ec09K0axw6VLU= 402 | dependencies: 403 | pump "^3.0.0" 404 | 405 | get-stream@^5.1.0: 406 | version "5.2.0" 407 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" 408 | integrity sha1-SWaheV7lrOZecGxLe+txJX1uItM= 409 | dependencies: 410 | pump "^3.0.0" 411 | 412 | glob-parent@~5.1.2: 413 | version "5.1.2" 414 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 415 | integrity sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ= 416 | dependencies: 417 | is-glob "^4.0.1" 418 | 419 | glob@7.1.7: 420 | version "7.1.7" 421 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" 422 | integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== 423 | dependencies: 424 | fs.realpath "^1.0.0" 425 | inflight "^1.0.4" 426 | inherits "2" 427 | minimatch "^3.0.4" 428 | once "^1.3.0" 429 | path-is-absolute "^1.0.0" 430 | 431 | global-dirs@^2.0.1: 432 | version "2.1.0" 433 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" 434 | integrity sha1-6QRqScgG/wTWwYJeGWyPAJHo300= 435 | dependencies: 436 | ini "1.3.7" 437 | 438 | got@^9.6.0: 439 | version "9.6.0" 440 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" 441 | integrity sha1-7fRefWf5lUVwXeH3u+7rEhdl7YU= 442 | dependencies: 443 | "@sindresorhus/is" "^0.14.0" 444 | "@szmarczak/http-timer" "^1.1.2" 445 | cacheable-request "^6.0.0" 446 | decompress-response "^3.3.0" 447 | duplexer3 "^0.1.4" 448 | get-stream "^4.1.0" 449 | lowercase-keys "^1.0.1" 450 | mimic-response "^1.0.1" 451 | p-cancelable "^1.0.0" 452 | to-readable-stream "^1.0.0" 453 | url-parse-lax "^3.0.0" 454 | 455 | graceful-fs@^4.1.2: 456 | version "4.2.6" 457 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" 458 | integrity sha1-/wQLKwhTsjw9MQJ1I3BvGIXXa+4= 459 | 460 | growl@1.10.5: 461 | version "1.10.5" 462 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 463 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 464 | 465 | has-flag@^3.0.0: 466 | version "3.0.0" 467 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 468 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 469 | 470 | has-flag@^4.0.0: 471 | version "4.0.0" 472 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 473 | integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= 474 | 475 | has-yarn@^2.1.0: 476 | version "2.1.0" 477 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" 478 | integrity sha1-E34RNUp7W/EapctknPDG8/8rLnc= 479 | 480 | he@1.2.0: 481 | version "1.2.0" 482 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 483 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 484 | 485 | http-cache-semantics@^4.0.0: 486 | version "4.1.0" 487 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" 488 | integrity sha1-SekcXL82yblLz81xwj1SSex045A= 489 | 490 | ignore-by-default@^1.0.1: 491 | version "1.0.1" 492 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" 493 | integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= 494 | 495 | import-lazy@^2.1.0: 496 | version "2.1.0" 497 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" 498 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= 499 | 500 | imurmurhash@^0.1.4: 501 | version "0.1.4" 502 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 503 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 504 | 505 | inflight@^1.0.4: 506 | version "1.0.6" 507 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 508 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 509 | dependencies: 510 | once "^1.3.0" 511 | wrappy "1" 512 | 513 | inherits@2: 514 | version "2.0.4" 515 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 516 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 517 | 518 | ini@1.3.7: 519 | version "1.3.7" 520 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" 521 | integrity sha1-oJNj4ZEZcuoW16iFEAXYTPCamoQ= 522 | 523 | ini@~1.3.0: 524 | version "1.3.8" 525 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" 526 | integrity sha1-op2kJbSIBvNHZ6Tvzjlyaa8oQyw= 527 | 528 | is-binary-path@~2.1.0: 529 | version "2.1.0" 530 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 531 | integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= 532 | dependencies: 533 | binary-extensions "^2.0.0" 534 | 535 | is-ci@^2.0.0: 536 | version "2.0.0" 537 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" 538 | integrity sha1-a8YzQYGBDgS1wis9WJ/cpVAmQEw= 539 | dependencies: 540 | ci-info "^2.0.0" 541 | 542 | is-extglob@^2.1.1: 543 | version "2.1.1" 544 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 545 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 546 | 547 | is-fullwidth-code-point@^2.0.0: 548 | version "2.0.0" 549 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 550 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 551 | 552 | is-fullwidth-code-point@^3.0.0: 553 | version "3.0.0" 554 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 555 | integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0= 556 | 557 | is-glob@^4.0.1, is-glob@~4.0.1: 558 | version "4.0.1" 559 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 560 | integrity sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw= 561 | dependencies: 562 | is-extglob "^2.1.1" 563 | 564 | is-installed-globally@^0.3.1: 565 | version "0.3.2" 566 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" 567 | integrity sha1-/T76ee5nDRGHIzGC1bCh3QAxMUE= 568 | dependencies: 569 | global-dirs "^2.0.1" 570 | is-path-inside "^3.0.1" 571 | 572 | is-npm@^4.0.0: 573 | version "4.0.0" 574 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" 575 | integrity sha1-yQ3YOAaW34enptgjwg0LErvjyE0= 576 | 577 | is-number@^7.0.0: 578 | version "7.0.0" 579 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 580 | integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= 581 | 582 | is-obj@^2.0.0: 583 | version "2.0.0" 584 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" 585 | integrity sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI= 586 | 587 | is-path-inside@^3.0.1: 588 | version "3.0.3" 589 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 590 | integrity sha1-0jE2LlOgf/Kw4Op/7QSRYf/RYoM= 591 | 592 | is-plain-obj@^2.1.0: 593 | version "2.1.0" 594 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" 595 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== 596 | 597 | is-typedarray@^1.0.0: 598 | version "1.0.0" 599 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 600 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 601 | 602 | is-unicode-supported@^0.1.0: 603 | version "0.1.0" 604 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" 605 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== 606 | 607 | is-yarn-global@^0.3.0: 608 | version "0.3.0" 609 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" 610 | integrity sha1-1QLTOCWQ6jAEiTdGdUyJE5lz4jI= 611 | 612 | isexe@^2.0.0: 613 | version "2.0.0" 614 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 615 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 616 | 617 | js-yaml@4.1.0: 618 | version "4.1.0" 619 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 620 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 621 | dependencies: 622 | argparse "^2.0.1" 623 | 624 | json-buffer@3.0.0: 625 | version "3.0.0" 626 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" 627 | integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= 628 | 629 | keyv@^3.0.0: 630 | version "3.1.0" 631 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" 632 | integrity sha1-7MIoSG9pmR5J6UdkhaW+Ho/FxNk= 633 | dependencies: 634 | json-buffer "3.0.0" 635 | 636 | latest-version@^5.0.0: 637 | version "5.1.0" 638 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" 639 | integrity sha1-EZ3+kI/jjRXfpD7NE/oS7Igy+s4= 640 | dependencies: 641 | package-json "^6.3.0" 642 | 643 | locate-path@^6.0.0: 644 | version "6.0.0" 645 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 646 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 647 | dependencies: 648 | p-locate "^5.0.0" 649 | 650 | lodash@^4.17.21: 651 | version "4.17.21" 652 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 653 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 654 | 655 | log-symbols@4.1.0: 656 | version "4.1.0" 657 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" 658 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== 659 | dependencies: 660 | chalk "^4.1.0" 661 | is-unicode-supported "^0.1.0" 662 | 663 | lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: 664 | version "1.0.1" 665 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" 666 | integrity sha1-b54wtHCE2XGnyCD/FabFFnt0wm8= 667 | 668 | lowercase-keys@^2.0.0: 669 | version "2.0.0" 670 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" 671 | integrity sha1-JgPni3tLAAbLyi+8yKMgJVislHk= 672 | 673 | make-dir@^3.0.0: 674 | version "3.1.0" 675 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 676 | integrity sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8= 677 | dependencies: 678 | semver "^6.0.0" 679 | 680 | mimic-response@^1.0.0, mimic-response@^1.0.1: 681 | version "1.0.1" 682 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 683 | integrity sha1-SSNTiHju9CBjy4o+OweYeBSHqxs= 684 | 685 | minimatch@3.0.4, minimatch@^3.0.4: 686 | version "3.0.4" 687 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 688 | integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= 689 | dependencies: 690 | brace-expansion "^1.1.7" 691 | 692 | minimist@^1.2.0: 693 | version "1.2.5" 694 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 695 | integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= 696 | 697 | mocha@^9.0.2: 698 | version "9.0.2" 699 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.0.2.tgz#e84849b61f406a680ced85af76425f6f3108d1a0" 700 | integrity sha512-FpspiWU+UT9Sixx/wKimvnpkeW0mh6ROAKkIaPokj3xZgxeRhcna/k5X57jJghEr8X+Cgu/Vegf8zCX5ugSuTA== 701 | dependencies: 702 | "@ungap/promise-all-settled" "1.1.2" 703 | ansi-colors "4.1.1" 704 | browser-stdout "1.3.1" 705 | chokidar "3.5.2" 706 | debug "4.3.1" 707 | diff "5.0.0" 708 | escape-string-regexp "4.0.0" 709 | find-up "5.0.0" 710 | glob "7.1.7" 711 | growl "1.10.5" 712 | he "1.2.0" 713 | js-yaml "4.1.0" 714 | log-symbols "4.1.0" 715 | minimatch "3.0.4" 716 | ms "2.1.3" 717 | nanoid "3.1.23" 718 | serialize-javascript "6.0.0" 719 | strip-json-comments "3.1.1" 720 | supports-color "8.1.1" 721 | which "2.0.2" 722 | wide-align "1.1.3" 723 | workerpool "6.1.5" 724 | yargs "16.2.0" 725 | yargs-parser "20.2.4" 726 | yargs-unparser "2.0.0" 727 | 728 | ms@2.0.0: 729 | version "2.0.0" 730 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 731 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 732 | 733 | ms@2.1.2: 734 | version "2.1.2" 735 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 736 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 737 | 738 | ms@2.1.3, ms@^2.1.1: 739 | version "2.1.3" 740 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 741 | integrity sha1-V0yBOM4dK1hh8LRFedut1gxmFbI= 742 | 743 | nanoid@3.1.23: 744 | version "3.1.23" 745 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" 746 | integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== 747 | 748 | nodemon@^2.0.7: 749 | version "2.0.7" 750 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/nodemon/-/nodemon-2.0.7.tgz#6f030a0a0ebe3ea1ba2a38f71bf9bab4841ced32" 751 | integrity sha1-bwMKCg6+PqG6Kjj3G/m6tIQc7TI= 752 | dependencies: 753 | chokidar "^3.2.2" 754 | debug "^3.2.6" 755 | ignore-by-default "^1.0.1" 756 | minimatch "^3.0.4" 757 | pstree.remy "^1.1.7" 758 | semver "^5.7.1" 759 | supports-color "^5.5.0" 760 | touch "^3.1.0" 761 | undefsafe "^2.0.3" 762 | update-notifier "^4.1.0" 763 | 764 | nopt@~1.0.10: 765 | version "1.0.10" 766 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" 767 | integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= 768 | dependencies: 769 | abbrev "1" 770 | 771 | normalize-path@^3.0.0, normalize-path@~3.0.0: 772 | version "3.0.0" 773 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 774 | integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= 775 | 776 | normalize-url@^4.1.0: 777 | version "4.5.1" 778 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" 779 | integrity sha1-DdkM8SiO4dExO4cIHJpZMu5IUYo= 780 | 781 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 782 | version "1.4.0" 783 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 784 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 785 | dependencies: 786 | wrappy "1" 787 | 788 | p-cancelable@^1.0.0: 789 | version "1.1.0" 790 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" 791 | integrity sha1-0HjRWjr0CSIMiG8dmgyi5EGrJsw= 792 | 793 | p-limit@^3.0.2: 794 | version "3.1.0" 795 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 796 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 797 | dependencies: 798 | yocto-queue "^0.1.0" 799 | 800 | p-locate@^5.0.0: 801 | version "5.0.0" 802 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 803 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 804 | dependencies: 805 | p-limit "^3.0.2" 806 | 807 | package-json@^6.3.0: 808 | version "6.5.0" 809 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" 810 | integrity sha1-b+7ayjXnVyWHbQsOZJdGl/7RRbA= 811 | dependencies: 812 | got "^9.6.0" 813 | registry-auth-token "^4.0.0" 814 | registry-url "^5.0.0" 815 | semver "^6.2.0" 816 | 817 | path-exists@^4.0.0: 818 | version "4.0.0" 819 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 820 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 821 | 822 | path-is-absolute@^1.0.0: 823 | version "1.0.1" 824 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 825 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 826 | 827 | pathval@^1.1.1: 828 | version "1.1.1" 829 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" 830 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== 831 | 832 | picomatch@^2.0.4, picomatch@^2.2.1: 833 | version "2.3.0" 834 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" 835 | integrity sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI= 836 | 837 | prepend-http@^2.0.0: 838 | version "2.0.0" 839 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" 840 | integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= 841 | 842 | pstree.remy@^1.1.7: 843 | version "1.1.8" 844 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" 845 | integrity sha1-wkIiT0pnwh9oaDm720rCgrg3PTo= 846 | 847 | pump@^3.0.0: 848 | version "3.0.0" 849 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 850 | integrity sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ= 851 | dependencies: 852 | end-of-stream "^1.1.0" 853 | once "^1.3.1" 854 | 855 | pupa@^2.0.1: 856 | version "2.1.1" 857 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" 858 | integrity sha1-9ej9SvwsXZeCj6pSNUnth0SiDWI= 859 | dependencies: 860 | escape-goat "^2.0.0" 861 | 862 | randombytes@^2.1.0: 863 | version "2.1.0" 864 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 865 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 866 | dependencies: 867 | safe-buffer "^5.1.0" 868 | 869 | rc@^1.2.8: 870 | version "1.2.8" 871 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 872 | integrity sha1-zZJL9SAKB1uDwYjNa54hG3/A0+0= 873 | dependencies: 874 | deep-extend "^0.6.0" 875 | ini "~1.3.0" 876 | minimist "^1.2.0" 877 | strip-json-comments "~2.0.1" 878 | 879 | readdirp@~3.6.0: 880 | version "3.6.0" 881 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 882 | integrity sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc= 883 | dependencies: 884 | picomatch "^2.2.1" 885 | 886 | registry-auth-token@^4.0.0: 887 | version "4.2.1" 888 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" 889 | integrity sha1-bXtABkQZGJcszV/tzUHcMix5slA= 890 | dependencies: 891 | rc "^1.2.8" 892 | 893 | registry-url@^5.0.0: 894 | version "5.1.0" 895 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" 896 | integrity sha1-6YM0tQ1UNLgRNrROxjjZwgCcUAk= 897 | dependencies: 898 | rc "^1.2.8" 899 | 900 | require-directory@^2.1.1: 901 | version "2.1.1" 902 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 903 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 904 | 905 | responselike@^1.0.2: 906 | version "1.0.2" 907 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" 908 | integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= 909 | dependencies: 910 | lowercase-keys "^1.0.0" 911 | 912 | safe-buffer@^5.1.0: 913 | version "5.2.1" 914 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 915 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 916 | 917 | semver-diff@^3.1.1: 918 | version "3.1.1" 919 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" 920 | integrity sha1-Bfd85Z8yXgDicGr9Z7tQbdscoys= 921 | dependencies: 922 | semver "^6.3.0" 923 | 924 | semver@^5.7.1: 925 | version "5.7.1" 926 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 927 | integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= 928 | 929 | semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: 930 | version "6.3.0" 931 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 932 | integrity sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0= 933 | 934 | serialize-javascript@6.0.0: 935 | version "6.0.0" 936 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" 937 | integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== 938 | dependencies: 939 | randombytes "^2.1.0" 940 | 941 | signal-exit@^3.0.2: 942 | version "3.0.3" 943 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" 944 | integrity sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw= 945 | 946 | "string-width@^1.0.2 || 2": 947 | version "2.1.1" 948 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 949 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 950 | dependencies: 951 | is-fullwidth-code-point "^2.0.0" 952 | strip-ansi "^4.0.0" 953 | 954 | string-width@^3.0.0: 955 | version "3.1.0" 956 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 957 | integrity sha1-InZ74htirxCBV0MG9prFG2IgOWE= 958 | dependencies: 959 | emoji-regex "^7.0.1" 960 | is-fullwidth-code-point "^2.0.0" 961 | strip-ansi "^5.1.0" 962 | 963 | string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: 964 | version "4.2.2" 965 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" 966 | integrity sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU= 967 | dependencies: 968 | emoji-regex "^8.0.0" 969 | is-fullwidth-code-point "^3.0.0" 970 | strip-ansi "^6.0.0" 971 | 972 | strip-ansi@^4.0.0: 973 | version "4.0.0" 974 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 975 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 976 | dependencies: 977 | ansi-regex "^3.0.0" 978 | 979 | strip-ansi@^5.1.0: 980 | version "5.2.0" 981 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 982 | integrity sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4= 983 | dependencies: 984 | ansi-regex "^4.1.0" 985 | 986 | strip-ansi@^6.0.0: 987 | version "6.0.0" 988 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 989 | integrity sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI= 990 | dependencies: 991 | ansi-regex "^5.0.0" 992 | 993 | strip-json-comments@3.1.1: 994 | version "3.1.1" 995 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 996 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 997 | 998 | strip-json-comments@~2.0.1: 999 | version "2.0.1" 1000 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1001 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1002 | 1003 | supports-color@8.1.1: 1004 | version "8.1.1" 1005 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 1006 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 1007 | dependencies: 1008 | has-flag "^4.0.0" 1009 | 1010 | supports-color@^5.5.0: 1011 | version "5.5.0" 1012 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1013 | integrity sha1-4uaaRKyHcveKHsCzW2id9lMO/I8= 1014 | dependencies: 1015 | has-flag "^3.0.0" 1016 | 1017 | supports-color@^7.1.0: 1018 | version "7.2.0" 1019 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1020 | integrity sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= 1021 | dependencies: 1022 | has-flag "^4.0.0" 1023 | 1024 | term-size@^2.1.0: 1025 | version "2.2.1" 1026 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" 1027 | integrity sha1-KmpUhAQywvtjIP6g9BVTHpAYn1Q= 1028 | 1029 | to-readable-stream@^1.0.0: 1030 | version "1.0.0" 1031 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" 1032 | integrity sha1-zgqgwvPfat+FLvtASng+d8BHV3E= 1033 | 1034 | to-regex-range@^5.0.1: 1035 | version "5.0.1" 1036 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1037 | integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= 1038 | dependencies: 1039 | is-number "^7.0.0" 1040 | 1041 | touch@^3.1.0: 1042 | version "3.1.0" 1043 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" 1044 | integrity sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds= 1045 | dependencies: 1046 | nopt "~1.0.10" 1047 | 1048 | type-detect@^4.0.0, type-detect@^4.0.5: 1049 | version "4.0.8" 1050 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 1051 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 1052 | 1053 | type-fest@^0.8.1: 1054 | version "0.8.1" 1055 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" 1056 | integrity sha1-CeJJ696FHTseSNJ8EFREZn8XuD0= 1057 | 1058 | typedarray-to-buffer@^3.1.5: 1059 | version "3.1.5" 1060 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1061 | integrity sha1-qX7nqf9CaRufeD/xvFES/j/KkIA= 1062 | dependencies: 1063 | is-typedarray "^1.0.0" 1064 | 1065 | undefsafe@^2.0.3: 1066 | version "2.0.3" 1067 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" 1068 | integrity sha1-axZucJStRjE7IgLafsws18xueq4= 1069 | dependencies: 1070 | debug "^2.2.0" 1071 | 1072 | unique-string@^2.0.0: 1073 | version "2.0.0" 1074 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" 1075 | integrity sha1-OcZFH4GvsnSd4rIz4/fF6IQ72J0= 1076 | dependencies: 1077 | crypto-random-string "^2.0.0" 1078 | 1079 | update-notifier@^4.1.0: 1080 | version "4.1.3" 1081 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" 1082 | integrity sha1-vobuE+jOSPtQBD/3IFe1vVmOHqM= 1083 | dependencies: 1084 | boxen "^4.2.0" 1085 | chalk "^3.0.0" 1086 | configstore "^5.0.1" 1087 | has-yarn "^2.1.0" 1088 | import-lazy "^2.1.0" 1089 | is-ci "^2.0.0" 1090 | is-installed-globally "^0.3.1" 1091 | is-npm "^4.0.0" 1092 | is-yarn-global "^0.3.0" 1093 | latest-version "^5.0.0" 1094 | pupa "^2.0.1" 1095 | semver-diff "^3.1.1" 1096 | xdg-basedir "^4.0.0" 1097 | 1098 | url-parse-lax@^3.0.0: 1099 | version "3.0.0" 1100 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" 1101 | integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= 1102 | dependencies: 1103 | prepend-http "^2.0.0" 1104 | 1105 | which@2.0.2: 1106 | version "2.0.2" 1107 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1108 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1109 | dependencies: 1110 | isexe "^2.0.0" 1111 | 1112 | wide-align@1.1.3: 1113 | version "1.1.3" 1114 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 1115 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 1116 | dependencies: 1117 | string-width "^1.0.2 || 2" 1118 | 1119 | widest-line@^3.1.0: 1120 | version "3.1.0" 1121 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" 1122 | integrity sha1-gpIzO79my0X/DeFgOxNreuFJbso= 1123 | dependencies: 1124 | string-width "^4.0.0" 1125 | 1126 | workerpool@6.1.5: 1127 | version "6.1.5" 1128 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" 1129 | integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== 1130 | 1131 | wrap-ansi@^7.0.0: 1132 | version "7.0.0" 1133 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 1134 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 1135 | dependencies: 1136 | ansi-styles "^4.0.0" 1137 | string-width "^4.1.0" 1138 | strip-ansi "^6.0.0" 1139 | 1140 | wrappy@1: 1141 | version "1.0.2" 1142 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1143 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1144 | 1145 | write-file-atomic@^3.0.0: 1146 | version "3.0.3" 1147 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" 1148 | integrity sha1-Vr1cWlxwSBzRnFcb05q5ZaXeVug= 1149 | dependencies: 1150 | imurmurhash "^0.1.4" 1151 | is-typedarray "^1.0.0" 1152 | signal-exit "^3.0.2" 1153 | typedarray-to-buffer "^3.1.5" 1154 | 1155 | xdg-basedir@^4.0.0: 1156 | version "4.0.0" 1157 | resolved "https://registry.navercorp.com:443/api/npm/npm-naver/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" 1158 | integrity sha1-S8jZmEQDaWIl74OhVzy7y0552xM= 1159 | 1160 | y18n@^5.0.5: 1161 | version "5.0.8" 1162 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 1163 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 1164 | 1165 | yargs-parser@20.2.4: 1166 | version "20.2.4" 1167 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" 1168 | integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== 1169 | 1170 | yargs-parser@^20.2.2: 1171 | version "20.2.9" 1172 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 1173 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 1174 | 1175 | yargs-unparser@2.0.0: 1176 | version "2.0.0" 1177 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" 1178 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== 1179 | dependencies: 1180 | camelcase "^6.0.0" 1181 | decamelize "^4.0.0" 1182 | flat "^5.0.2" 1183 | is-plain-obj "^2.1.0" 1184 | 1185 | yargs@16.2.0: 1186 | version "16.2.0" 1187 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" 1188 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 1189 | dependencies: 1190 | cliui "^7.0.2" 1191 | escalade "^3.1.1" 1192 | get-caller-file "^2.0.5" 1193 | require-directory "^2.1.1" 1194 | string-width "^4.2.0" 1195 | y18n "^5.0.5" 1196 | yargs-parser "^20.2.2" 1197 | 1198 | yocto-queue@^0.1.0: 1199 | version "0.1.0" 1200 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 1201 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 1202 | --------------------------------------------------------------------------------