diff --git a/250321_DIC_2502A_TEST.xlsx b/250321_DIC_2502A_TEST.xlsx index 637ebbf..a6fcf88 100644 Binary files a/250321_DIC_2502A_TEST.xlsx and b/250321_DIC_2502A_TEST.xlsx differ diff --git a/DIC_2502A.json b/DIC_2502A.json index fcbb4ca..9c0d716 100644 --- a/DIC_2502A.json +++ b/DIC_2502A.json @@ -411,6 +411,87 @@ } }, "4": { + "1": { + "type": "multi", + "ele": "//Document/Width/@value | //Document/Height/@value", + "value": [ + "650", + "350" + ], + "point": 5, + "desc": "캔버스 사이즈 650*350" + }, + "2": { + "ele": "none", + "point": 5, + "desc": "자유 변형 문항은 채점 불가" + }, + "3": { + "type" : "isExist", + "ele": "//Layer/Name/@value", + "value": "Germs", + "point": 5, + "desc": "Germs 레이어가 있는지 여부 체크" + }, + "4": { + "type" : "multiValue", + "ele": "//Layer[Name[@value='Germs']]/Effects/Item/Name/@value | //Layer[Name[@value='Germs']]/Effects/Item/EffectData/amount/@value", + "value" : [ + "12", + "선명하게" + ], + "point": 5, + "desc": "Germs 레이어의 효과 체크" + }, + "5": { + "ele": "none", + "point": 6, + "desc": "올가미 도구/이미지 제거 문항은 채점 불가" + }, + "6": { + "type" : "isExist", + "ele": "//Layer/Effects/Item/Name/@value", + "value" : "세피아", + "point": 6, + "desc": "세피아 효과가 있는지 여부 체크" + }, + "7": { + "type": "exact", + "ele": "//Layer/Shapes/Shape/shape_type/@value", + "value": "ELLIPSE", + "point": 3, + "desc": "레이어 쉐이프 타입이 타원인지 체크" + }, + "8": { + "type": "size", + "posX": "//Layer//op_points[Item]/Item[last()]/X/@value - //Layer//op_points[Item]/Item[1]/X/@value", + "posY": "//Layer//op_points[Item]/Item[last()]/Y/@value - //Layer//op_points[Item]/Item[1]/Y/@value", + "value": { + "width": 130, + "height": 80 + }, + "point": 3, + "desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점" + }, + "9": { + "type": "color", + "ele": "//Layer//Shape[contains(draw_type/@value, 'Interior')]/secondary_color/@value", + "value": "000555", + "point": 6, + "desc": "색상 코드 비교 시 소문자로 입력할 것" + }, + "10": { + "type" : "multiValue", + "ele": "//Layer/BlendOp/@value | //Layer/Opacity/@value", + "value" : [ + "중첩", + "75" + ], + "point": 5, + "desc": "혼합모드(중첩, 불투명도 : 75) 체크" + } + }, + "5": { "1": { "type": "multi", "ele": "//Document/Width/@value | //Document/Height/@value", diff --git a/gpdpScoring.js b/gpdpScoring.js index 1f5d7f4..17ee7c7 100644 --- a/gpdpScoring.js +++ b/gpdpScoring.js @@ -24,249 +24,300 @@ function parseColorToHex(colorString) { } module.exports = getGpdpScore; +/** + * /Document/Layers/Layer/Shapes/Shape/draw_type 속성값 + * > Interior: 내부 채우기 / Outline: 외곽선 + * /Document/Layers/Layer/Shapes/Shape/interior_type 속성값 + * > Fill: 채우기 / Gradient: 그라데이션 + * @param {*} gpdpData + * @param {*} scoringJson + * @param {*} index + * @returns + */ + + + // xml 형식의 GPDP 파일을 읽어서 점수를 계산 // scoring.json 파일 내에 있는 ele 요소는 xpath 형식으로 접근하여 요소를 탐색하고 나오는 값을 value와 비교하여 점수를 계산 // scoring.json 파일 내에 있는 type은 비교할 값의 타입을 의미하며, boolean, array 등이 있음 // scoring.json 파일 내에 있는 type에 따라 비교하는 방식이 달라짐 // 채점 결과를 scoringResultList 배열에 저장 function getGpdpScore(gpdpData, scoringJson, index) { - const gpdpXmlDoc = gpdpData; - const scoringResult = {}; - - const scoringData = scoringJson[index]; - // console.log(scoringData); - - let totalScore = 0; - - // 채점기준표 문항별 분류 - for (const key in scoringData) { - let ele = scoringData[key].ele; - let ele2 = scoringData[key].ele2; - let existEle = scoringData[key].existEle; - let rightAnswer = scoringData[key].value; - let point = scoringData[key].point; - let type = scoringData[key].type; - let search = scoringData[key].search; - - // search 값이 undefined 아니면 ele의 {search}부분을 search로 치환 - /** - * JSON파일 곰믹스 5번문항/22번 문항 - * type : "subtitle" 인 항목들 - * GPString태그 VID7속성 찾는 xpath구문 - * CRCUnitArr태그 Name속성 찾는 구문으로 변환 - * > 멀티라인 텍스트 유사도 판별하기 어려움 - */ - if (search !== undefined) { - let result = findSimilarString(gpdpXmlDoc, search, 0.8) - // xpath 내부 "(큰따옴표) 필터링 - if (result !== null) { - result = result.replace(/"/g, "'"); - } - ele = ele.replace(/{search}/g, result); - if (existEle !== undefined) { - existEle = existEle.replace(/{search}/g, result); - } + const gpdpXmlDoc = gpdpData; + const scoringResult = {}; + + const scoringData = scoringJson[index]; + // console.log(scoringData); + + let totalScore = 0; + + // 채점기준표 문항별 분류 + for (const key in scoringData) { + let ele = scoringData[key].ele; + let ele2 = scoringData[key].ele2; + let existEle = scoringData[key].existEle; + let rightAnswer = scoringData[key].value; + let point = scoringData[key].point; + let type = scoringData[key].type; + let search = scoringData[key].search; + + if (search !== undefined) { + let result = findSimilarString(gpdpXmlDoc, search, 0.8) + // xpath 내부 "(큰따옴표) 필터링 + if (result !== null) { + result = result.replace(/"/g, "'"); } - console.log(`example number: ${key}`) - if (type == "exact") { - let result = xpath.select(ele, gpdpXmlDoc); - if (result.length == 0) { - scoringResult[key] = 0; - console.log('ele not found'); - continue; - } - if (result[0].value === rightAnswer) { - totalScore += point; - scoringResult[key] = point; - } else { - scoringResult[key] = 0; - console.log('ele not matched, ' + result[0].value); - } - } - else if (type == "color") { - let result = xpath.select(ele, gpdpXmlDoc); - if (result.length == 0) { - scoringResult[key] = 0; - console.log('ele not found'); - continue; - } - const hexColor = parseColorToHex(result[0].value); - - if (hexColor === rightAnswer) { - totalScore += point; - scoringResult[key] = point; - console.log('color matched, ' + hexColor); - } else { - scoringResult[key] = 0; - console.log('color not matched, ' + hexColor); - } - } - else if (type == "multi") { - try { - const result = xpath.select(ele, gpdpXmlDoc); - let isSame = true; - // console.log(`ele: ${ele}, value: ${value} result: ${result}`); - - if (result.length == 0) { - console.log('result length 0'); - scoringResult[key] = 0; - continue; - } - - result.forEach((v, i) => { - // value[i] 값이 정수형인 경우에는 float로 변환하여 비교 - // 정수형 v값을 float 형으로 변환하고 소수점 3자리까지 버림 - let temp = v.value; - let answer = rightAnswer[i]; - - if (Number.isFinite(rightAnswer[i]) && !Number.isInteger(rightAnswer[i])) { - temp = parseFloat(v.value); - answer = parseFloat(rightAnswer[i]); - // 소수점 3자리까지 버림 - temp = Math.floor(temp * 1000) / 1000; - } - // answer 문자열 중 : 가 포함되어 있다면 각각 분리하고 그 값의 차이를 구함 - if (typeof answer == "string" && answer.indexOf(':') > -1) { - const [answerStart, answerEnd] = answer.split(':').map(Number); - const [tempStart, tempEnd] = temp.split(':').map(Number); - answer = answerEnd - answerStart; - temp = tempEnd - tempStart; - } - - console.log(`temp: ${temp} answer: ${answer}`); - if (answer !== temp) { - console.log(`answer !== temp`); - isSame = false; - } - }); - totalScore += isSame ? point : 0; - scoringResult[key] = isSame ? point : 0; - } catch (e) { - console.log('err :', e); - scoringResult[key] = 0; - } - } - else if (type == "size") { - let posX = scoringData[key].posX; - let posY = scoringData[key].posY; - - let answerWidth = rightAnswer["width"]; - let answerHeight = rightAnswer["height"]; - - let width = xpath.select(posX, gpdpXmlDoc); - let height = xpath.select(posY, gpdpXmlDoc); - width = Math.round(width); - height = Math.round(height); - - console.log(`width:${answerWidth},${width}, height: ${answerHeight},${height}`); - if (answerWidth === width && answerHeight === height) { - totalScore += point; - scoringResult[key] = point; - console.log("same size"); - } - else { - scoringResult[key] = 0; - console.log("different size"); - } - } - else if (type == "gradient") { - let startColor = scoringData[key].startColor; - let endColor = scoringData[key].endColor; - - let answerStartColor = rightAnswer["startColor"]; - let answerEndColor = rightAnswer["endColor"]; - - let start = xpath.select(startColor, gpdpXmlDoc); - let end = xpath.select(endColor, gpdpXmlDoc); - - // console.log(start[0].value, end[0].value); - if (start.length == 0 || end.length == 0) { - console.log("gradient color not found"); - scoringResult[key] = 0; - continue; - } - - const startHexColor = parseColorToHex(start[0].value); - const endHexColor = parseColorToHex(end[0].value); - console.log(startHexColor + ":" + answerStartColor, endHexColor + ":" + answerEndColor); - - if (startHexColor === answerStartColor && endHexColor === answerEndColor) { - totalScore += point; - scoringResult[key] = point; - console.log("same color"); - } - else { - scoringResult[key] = 0; - console.log("different color"); - } - } - // 그림자 속성이 있는지 여부 파악해서 그림자 속성 별로 점수 1 점씩 부여 - else if(type == "shadow"){ - - let result = xpath.select(ele["shadow"], gpdpXmlDoc); - let shadowScore = 0; - if (result.length == 0) { - scoringResult[key] = 0; - console.log('shadow not found'); - continue; - } - - shadowScore += 1; - let width = xpath.select(ele["width"], gpdpXmlDoc); - let distance = xpath.select(ele["distance"], gpdpXmlDoc); - let blur = xpath.select(ele["blur"], gpdpXmlDoc); - let angle = xpath.select(ele["angle"], gpdpXmlDoc); - - if(width.length !== 0 && width[0].value == rightAnswer["width"]){ - shadowScore += 1; - console.log('width matched'); - } - if(distance.length !== 0 && distance[0].value == rightAnswer["distance"]){ - shadowScore += 1; - console.log('distance matched'); - } - if(blur.length !== 0 && blur[0].value == rightAnswer["blur"]){ - shadowScore += 1; - console.log('blur matched'); - } - if(angle.length !== 0 && angle[0].value == rightAnswer["angle"]){ - shadowScore += 1; - console.log('angle matched'); - } - totalScore += shadowScore; - scoringResult[key] = shadowScore; - } - else { - let result = xpath.select(ele, gpdpXmlDoc); - let result2 = null; - let isCheck = false; - - if (ele === 'none') { - scoringResult[key] = "확인필요"; - continue; - } - - if (result.length == 0) { - isCheck = true; - } - if (isCheck && ele2) { - result2 = xpath.select(ele2, gpdpXmlDoc); - - if (result2.length == 0) { - scoringResult[key] = 0; - continue; - } - result = result2; - // console.log(`1st isChecked: ${isCheck}, result: ${result}`) - } - // value와 result[0].value를 비교하여 같으면 점수 point 부여 - // console.log(`${(value === result[0].value)}, ${result.length > 0 && value === result[0].value} `) - // console.log(`2nd isChecked: ${isCheck}, result: ${result}`) - totalScore += result.length > 0 ? point : 0; - scoringResult[key] = result.length > 0 ? point : 0; + ele = ele.replace(/{search}/g, result); + if (existEle !== undefined) { + existEle = existEle.replace(/{search}/g, result); } } - scoringResult['총점'] = totalScore; - return scoringResult; + console.log(`example number: ${key}`) + + if (type == "multiValue") { + if (Array.isArray(rightAnswer)) { + const result = ele ? xpath.select(ele, gpdpXmlDoc) : []; + const resultValues = Array.isArray(result) ? result.map(r => (typeof r === 'object' ? r.value : r)) : [result]; + console.log("🚀 ~ getGpdpScore ~ resultValues:", resultValues) + + const groupSize = rightAnswer.length; + const groupedResult = []; + for (let i = 0; i < resultValues.length; i += groupSize) { + groupedResult.push(resultValues.slice(i, i + groupSize)); + } + console.log("🚀 ~ getGpdpScore ~ groupedResult:", groupedResult) + + // 배열 비교 함수 + function arraysEqual(arr1, arr2) { + if (arr1.length !== arr2.length) return false; + return arr1.every((value, index) => value === arr2[index]); + } + + // groupedResult 내부 배열에서 rightAnswer와 일치하는 배열이 있는지 확인 + const isMatch = groupedResult.some(group => arraysEqual(group, rightAnswer)); + + if (isMatch) { + totalScore += point; + scoringResult[key] = point; + console.log("🚀 ~ 정답 포함"); + } else { + scoringResult[key] = 0; + console.log("🚀 ~ 오답"); + } + } + } + else if (type == "isExist" ) { + const result = xpath.select(ele, gpdpXmlDoc); + result.forEach((v, i) => { + if ( v.value === rightAnswer ) { + totalScore += point; + scoringResult[key] = point; + console.log("🚀 ~ result.forEach ~ 정답 일치:", rightAnswer) + return; + } else { + scoringResult[key] = 0; + } + }); + } + + else if (type == "exact") { + let result = xpath.select(ele, gpdpXmlDoc); + if (result.length == 0) { + scoringResult[key] = 0; + console.log('ele not found'); + continue; + } + if (result[0].value === rightAnswer) { + totalScore += point; + scoringResult[key] = point; + } else { + scoringResult[key] = 0; + console.log('ele not matched, ' + result[0].value); + } + } + else if (type == "color") { + let result = xpath.select(ele, gpdpXmlDoc); + if (result.length == 0) { + scoringResult[key] = 0; + console.log('ele not found'); + continue; + } + const hexColor = parseColorToHex(result[0].value); + + if (hexColor === rightAnswer) { + totalScore += point; + scoringResult[key] = point; + console.log('color matched, ' + hexColor); + } else { + scoringResult[key] = 0; + console.log('color not matched, ' + hexColor); + } + } + else if (type == "multi") { + try { + const result = xpath.select(ele, gpdpXmlDoc); + let isSame = true; + // console.log(`ele: ${ele}, value: ${value} result: ${result}`); + + if (result.length == 0) { + console.log('result length 0'); + scoringResult[key] = 0; + continue; + } + + result.forEach((v, i) => { + // value[i] 값이 정수형인 경우에는 float로 변환하여 비교 + // 정수형 v값을 float 형으로 변환하고 소수점 3자리까지 버림 + let temp = v.value; + let answer = rightAnswer[i]; + + if (Number.isFinite(rightAnswer[i]) && !Number.isInteger(rightAnswer[i])) { + temp = parseFloat(v.value); + answer = parseFloat(rightAnswer[i]); + // 소수점 3자리까지 버림 + temp = Math.floor(temp * 1000) / 1000; + } + // answer 문자열 중 : 가 포함되어 있다면 각각 분리하고 그 값의 차이를 구함 + if (typeof answer == "string" && answer.indexOf(':') > -1) { + const [answerStart, answerEnd] = answer.split(':').map(Number); + const [tempStart, tempEnd] = temp.split(':').map(Number); + answer = answerEnd - answerStart; + temp = tempEnd - tempStart; + } + + console.log(`temp: ${temp} answer: ${answer}`); + if (answer !== temp) { + console.log(`answer !== temp`); + isSame = false; + } + }); + totalScore += isSame ? point : 0; + scoringResult[key] = isSame ? point : 0; + } catch (e) { + console.log('err :', e); + scoringResult[key] = 0; + } + } + else if (type == "size") { + let posX = scoringData[key].posX; + let posY = scoringData[key].posY; + + let answerWidth = rightAnswer["width"]; + let answerHeight = rightAnswer["height"]; + + let width = xpath.select(posX, gpdpXmlDoc); + let height = xpath.select(posY, gpdpXmlDoc); + width = Math.round(width); + height = Math.round(height); + + console.log(`width:${answerWidth},${width}, height: ${answerHeight},${height}`); + if (answerWidth === width && answerHeight === height) { + totalScore += point; + scoringResult[key] = point; + console.log("same size"); + } + else { + scoringResult[key] = 0; + console.log("different size"); + } + } + else if (type == "gradient") { + let startColor = scoringData[key].startColor; + let endColor = scoringData[key].endColor; + + let answerStartColor = rightAnswer["startColor"]; + let answerEndColor = rightAnswer["endColor"]; + + let start = xpath.select(startColor, gpdpXmlDoc); + let end = xpath.select(endColor, gpdpXmlDoc); + + // console.log(start[0].value, end[0].value); + if (start.length == 0 || end.length == 0) { + console.log("gradient color not found"); + scoringResult[key] = 0; + continue; + } + + const startHexColor = parseColorToHex(start[0].value); + const endHexColor = parseColorToHex(end[0].value); + console.log(startHexColor + ":" + answerStartColor, endHexColor + ":" + answerEndColor); + + if (startHexColor === answerStartColor && endHexColor === answerEndColor) { + totalScore += point; + scoringResult[key] = point; + console.log("same color"); + } + else { + scoringResult[key] = 0; + console.log("different color"); + } + } + // 그림자 속성이 있는지 여부 파악해서 그림자 속성 별로 점수 1 점씩 부여 + else if (type == "shadow") { + + let result = xpath.select(ele["shadow"], gpdpXmlDoc); + let shadowScore = 0; + if (result.length == 0) { + scoringResult[key] = 0; + console.log('shadow not found'); + continue; + } + + shadowScore += 1; + let width = xpath.select(ele["width"], gpdpXmlDoc); + let distance = xpath.select(ele["distance"], gpdpXmlDoc); + let blur = xpath.select(ele["blur"], gpdpXmlDoc); + let angle = xpath.select(ele["angle"], gpdpXmlDoc); + + if (width.length !== 0 && width[0].value == rightAnswer["width"]) { + shadowScore += 1; + console.log('width matched'); + } + if (distance.length !== 0 && distance[0].value == rightAnswer["distance"]) { + shadowScore += 1; + console.log('distance matched'); + } + if (blur.length !== 0 && blur[0].value == rightAnswer["blur"]) { + shadowScore += 1; + console.log('blur matched'); + } + if (angle.length !== 0 && angle[0].value == rightAnswer["angle"]) { + shadowScore += 1; + console.log('angle matched'); + } + totalScore += shadowScore; + scoringResult[key] = shadowScore; + } + else { + let result = xpath.select(ele, gpdpXmlDoc); + let result2 = null; + let isCheck = false; + + if (ele === 'none') { + scoringResult[key] = "확인필요"; + continue; + } + + if (result.length == 0) { + isCheck = true; + } + if (isCheck && ele2) { + result2 = xpath.select(ele2, gpdpXmlDoc); + + if (result2.length == 0) { + scoringResult[key] = 0; + continue; + } + result = result2; + // console.log(`1st isChecked: ${isCheck}, result: ${result}`) + } + // value와 result[0].value를 비교하여 같으면 점수 point 부여 + // console.log(`${(value === result[0].value)}, ${result.length > 0 && value === result[0].value} `) + // console.log(`2nd isChecked: ${isCheck}, result: ${result}`) + totalScore += result.length > 0 ? point : 0; + scoringResult[key] = result.length > 0 ? point : 0; + } } - \ No newline at end of file + scoringResult['총점'] = totalScore; + return scoringResult; +} diff --git a/psdExport_2.js b/psdExport_2.js index 75bf232..c6e501d 100644 --- a/psdExport_2.js +++ b/psdExport_2.js @@ -102,7 +102,7 @@ studentDirs.forEach(student => { const xmlDocument = new DOMParser().parseFromString(xmlString, 'application/xml'); // console.log('xmlDocument:', xmlDocument); - scoringResult[index + 1] = getGpdpScore(xmlDocument, scoringJson, index + 3); + scoringResult[index + 1] = getGpdpScore(xmlDocument, scoringJson, index + 4); }); gmepFile.forEach((gmep, index) => { const gmepPath = path.join('./', studentDir, gmep); @@ -260,9 +260,9 @@ function getGmepScore(gmepData, scoringJson, index) { } } - console.log("🚀 ~ getGmepScore ~ ele:", ele) - console.log("🚀 ~ getGmepScore ~ ele2:", ele2) - console.log("🚀 ~ getGmepScore ~ ele3:", ele3) + // console.log("🚀 ~ getGmepScore ~ ele:", ele) + // console.log("🚀 ~ getGmepScore ~ ele2:", ele2) + // console.log("🚀 ~ getGmepScore ~ ele3:", ele3) // xpath if (ele === 'none') { @@ -525,7 +525,9 @@ function getGmepScore(gmepData, scoringJson, index) { } else if (arr2.length > 1) { for (let i = 0; i < arr1.length; i++) { - if (Math.abs(arr1[i] - arr2[i]) > 0.1) return false; + // 좌표값 범위 비교 + const errorRange = 0.1; + if (Math.abs(arr1[i] - arr2[i]) > errorRange) return false; } return true; } diff --git a/z.xbook b/z.xbook index 8f91250..6528a7b 100644 --- a/z.xbook +++ b/z.xbook @@ -1 +1 @@ -[{"kind":2,"language":"xpath","value":"//CROwneUnit[position() = (//CRTrackList[@Name='텍스트']/CRTrackClip[sum(preceding-sibling::CRTrackClip/@Length) = 170]/@ClipIndex) + 1]/CRCUnitArr/@VID600 | //CROwneUnit[position() = (//CRTrackList[@Name='텍스트']/CRTrackClip[sum(preceding-sibling::CRTrackClip/@Length) = 170]/@ClipIndex) + 1]/CRCUnitArr/@VID601"},{"kind":2,"language":"xpath","value":"//CRCUnitArr[@Name='대룡산의 아름다움']/@*[name()='VID600' or name()='VID601']"},{"kind":2,"language":"xpath","value":"sum(//CRTrackList[@Name='텍스트']/CRTrackClip[@ClipIndex=count(//CROwneUnit[CRCUnitArr[@Name='나무기차']]/preceding-sibling::CROwneUnit)]/preceding-sibling::CRTrackClip/@Length)"},{"kind":2,"language":"xpath","value":"//CROwneUnit[CRCUnitArr[@Name='나무 기차']]"},{"kind":2,"language":"xpath","value":"sum(//CRTrackList[@Name='텍스트']/CRTrackClip[not(@ClipIndex='-1')][{subtitleOrder}]/preceding-sibling::CRTrackClip/@Length)\r\nsum(//CRTrackList[@Name='텍스트']/CRTrackClip[]/preceding-sibling::CRTrackClip/@Length)"},{"kind":2,"language":"xpath","value":"count(//CROwneUnit[CRCUnitArr[@Name='나무 기차']]/preceding-sibling::CROwneUnit)"},{"kind":2,"language":"xpath","value":"//CRTrackList[@Name='텍스트']/CRTrackClip[@ClipIndex=count(//CROwneUnit[CRCUnitArr[@Name='나무 기차']]/preceding-sibling::CROwneUnit)]"},{"kind":2,"language":"xpath","value":"//CRTrackList[@Name='텍스트']/CRTrackClip[@ClipIndex=1]"},{"kind":2,"language":"xpath","value":"sum(//CRTrackList[@Name='텍스트']/CRTrackClip[not(@ClipIndex='-1')][@ClipIndex=0]/preceding-sibling::CRTrackClip/@Length)"},{"kind":2,"language":"xpath","value":"//CRTrackList[@Name='텍스트']/CRTrackClip[not(@ClipIndex='-1')][@ClipIndex=1]/@Length"}] \ No newline at end of file +[{"kind":2,"language":"xpath","value":"//Layer/Name/@value = 'Germs'"},{"kind":2,"language":"xpath","value":"//Layer[Name[@value='Germs']]/Effects/Item[Name[@value='선명하게'] and EffectData[amount[@value=\"12\"]]]"},{"kind":2,"language":"xpath","value":"//Layer[Name[@value='Germs']]/Effects/Item/(Name/@value | EffectData/amount/@value)"},{"kind":2,"language":"xpath","value":"//CRCUnitArr[@Name='{search}']//GCUnitPool/GCUnit[@Type='2']/@*[name()='VID100' or name()='VID101']"},{"kind":2,"language":"xpath","value":"//Layer//op_points[Item]/Item[last()]/X/@value"},{"kind":2,"language":"xpath","value":"//Layer//op_points[Item]/Item[1]/X/@value"},{"kind":2,"language":"xpath","value":"//Layer//Shape[contains(draw_type/@value, 'Interior')]/secondary_color/@value"},{"kind":2,"language":"xpath","value":"//Layer//Shape[contains(draw_type/@value, 'Interior')]/secondary_color/@value"},{"kind":2,"language":"xpath","value":"//Layer/BlendOp/@value | //Layer/Opacity/@value"}] \ No newline at end of file diff --git a/회차별채점자료/2502/excel_채점기준표/DIC_2502C.xlsx b/회차별채점자료/2502/excel_채점기준표/DIC_2502C.xlsx index 17b8717..9f06dde 100644 Binary files a/회차별채점자료/2502/excel_채점기준표/DIC_2502C.xlsx and b/회차별채점자료/2502/excel_채점기준표/DIC_2502C.xlsx differ