G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현 G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건) G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST) G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직 G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트 G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트 G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트 G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트 G-10: core/push_notify.py + routers/push.py + PushSubscription 모델 G-11: approvals 다중승인 (위임/서명/기한초과/마감연장) G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh 하네스: guardia-orchestrator 확장기능 Phase 반영 봇명령어: /sr /status /license /bulk 슬래시 명령어 추가 설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
572 lines
13 KiB
JavaScript
572 lines
13 KiB
JavaScript
/*-------------------------------------------------------------------+
|
|
* 1. 파일명: valid.biz.js
|
|
* 2. 설 명: 업무로직과 관련한 유효성 점검 함수를 정의한다.
|
|
* 3. 의존성: util.js, string.js
|
|
* 4. 작성자:
|
|
* 5. 작성일: 2006.10.11.
|
|
-------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
* E 메일 주소 형식이 맞는지 검사하여 맞으면 true,
|
|
* 형식에 맞지 않으면 false를 돌려 준다.
|
|
*/
|
|
function checkEmail(email) {
|
|
if ( isEmpty(email) ) return true;
|
|
|
|
var emailRegEx = /^[-\w]+@[-\w]+(\.[-\w]+){1,3}\s*$/g;
|
|
|
|
return emailRegEx.test(email);
|
|
}
|
|
|
|
|
|
function checkEmailObj(emailObj) {
|
|
return checkEmail(emailObj.value);
|
|
}
|
|
|
|
|
|
function validateEmail(email, fieldName) {
|
|
if ( fieldName == undefined ) fieldName = "E메일";
|
|
|
|
var valid = checkEmail(email);
|
|
|
|
if ( ! valid ) {
|
|
showMessage(fieldName + " 항목의 값은 E 메일의 형식에 맞지 않습니다.");
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
function validateEmailObj(emailObj) {
|
|
var valid = validateEmail(emailObj.value);
|
|
|
|
if ( ! valid ) {
|
|
emailObj.focus();
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
|
|
/* 전화번호용 지역번호 목록 */
|
|
var tpLocalNoList = [
|
|
"02" ,
|
|
"031", "032", "033",
|
|
"041", "042", "043",
|
|
"051", "052", "053", "054", "055",
|
|
"061", "062", "063", "064"
|
|
];
|
|
|
|
|
|
/**
|
|
* Text형 입력 폼의 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 true를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param obj 전화번호를 입력 받는 Text형 입력폼
|
|
*/
|
|
function checkTelNoObj(obj) {
|
|
return checkTelNo(obj.value);
|
|
}
|
|
|
|
|
|
/**
|
|
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 0를, 그렇지 않으면 적절한 음수를 돌려 준다.
|
|
* 전화번호의 각 요소는 구별자(-)가 없는 것으로 가정한다.
|
|
*
|
|
* 오류시 돌려주는 음수의 의미는 다음과 같다.
|
|
* <ul>
|
|
* <li>-1 : 숫자와 대쉬(-) 이외의 문자 사용</li>
|
|
* <li>-2 : 전화번호의 형식에 맞지 않음</li>
|
|
* <li>-4 : 지역번호가 사용하지 않는 번호임</li>
|
|
* <li>-8 : 국번호 자릿수가 3, 4자리가 아님</li>
|
|
* <li>-16 : 맨 뒤 번호 자릿수가 4자리가 아님</li>
|
|
* </ul>
|
|
*
|
|
* @date 2004-02-02
|
|
* @param phoneNo 검사하려는 전화번호 값
|
|
*/
|
|
function checkTelNo(phoneNo) {
|
|
// 빈값이면 검사하지 않는다.
|
|
if ( trim(phoneNo) == "" ) return 0;
|
|
|
|
phoneNo = removeChar(phoneNo, '-');
|
|
|
|
if ( isNaN(phoneNo) ) return -1;
|
|
|
|
|
|
/* 형식에 문자가 있는지 검사한다. */
|
|
//var tpNoRegExp = /^(0[1-9]{1,2}-)?[\d]{3,4}-[\d]{4}$/;
|
|
var tpNoRegExp = /^(02|0[3-6][1-5])?[1-9][\d]{6,7}$/;
|
|
|
|
if ( ! tpNoRegExp.test(phoneNo) ) return -2;
|
|
|
|
/* 각 요소를 자른다. */
|
|
var localNo = ""; // 지역번호
|
|
var areaNo = ""; // 국번
|
|
var restNo = ""; // 기타 번호
|
|
|
|
var hasLocalNo = ( phoneNo.length >= 9 && phoneNo.length <= 11 );
|
|
|
|
/* 지역번호가 유무에 따라 처리. */
|
|
if ( hasLocalNo ) {
|
|
/* 지역번호가 있을 때. */
|
|
|
|
/* 지역번호가 02인가? */
|
|
if ( phoneNo.indexOf("02") == 0 ) {
|
|
localNo = "02";
|
|
areaNo = ( phoneNo.length == 9
|
|
? phoneNo.substr(2, 3) : phoneNo.substr(2, 4) );
|
|
restNo = phoneNo.substr(2 + areaNo.length);
|
|
}
|
|
else {
|
|
localNo = phoneNo.substr(0, 3);
|
|
areaNo = ( phoneNo.length == 10
|
|
? phoneNo.substr(3, 3) : phoneNo.substr(3, 4) );
|
|
restNo = phoneNo.substr(3 + areaNo.length);
|
|
}
|
|
}
|
|
else {
|
|
/* 지역번호가 없을 때. */
|
|
areaNo = ( phoneNo.length == 7
|
|
? phoneNo.substr(0, 3) : phoneNo.substr(0, 4) );
|
|
restNo = phoneNo.substr(areaNo.length);
|
|
}
|
|
|
|
/* 지역 번호가 있을 때만 처리한다. */
|
|
if ( hasLocalNo ) {
|
|
/* 유효한 지역번호가 아니면 오류이다. */
|
|
var isExistsLocalNo = existsInArray(tpLocalNoList, localNo);
|
|
|
|
if ( ! isExistsLocalNo ) {
|
|
return -4;
|
|
}
|
|
}
|
|
|
|
// 국번호가 3자리에서 4자리인지 검사한다.
|
|
if ( areaNo.length != 3 && areaNo.length != 4 ) {
|
|
return -8;
|
|
}
|
|
|
|
// 나머지 번호를 검사한다.
|
|
if ( restNo.length != 4 ) {
|
|
return -16;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param phoneNo 검사하려는 전화번호 값
|
|
*/
|
|
function validateTelNoObj(obj, fieldName) {
|
|
var validResult = validateTelNo(obj.value, fieldName);
|
|
|
|
if ( validResult < 0 ) {
|
|
obj.focus();
|
|
}
|
|
|
|
return validResult;
|
|
}
|
|
|
|
/**
|
|
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param phoneNo 검사하려는 전화번호 값
|
|
*/
|
|
function validateTelNo(phoneNo, fieldName) {
|
|
var validResult = checkTelNo(phoneNo);
|
|
|
|
/* fieldName이 정의되어 있지 않다면 "전화번호"로 한다. */
|
|
if ( fieldName == undefined ) fieldName = "전화번호";
|
|
|
|
var msg = "";
|
|
|
|
switch ( validResult ) {
|
|
case -1 :
|
|
msg = fieldName + "은(는) 숫자만 이용해서 입력해야 합니다.";
|
|
break;
|
|
|
|
case -2 :
|
|
msg = fieldName + "의 형식에 맞지 않습니다.\n\n"
|
|
+ "[지역번호][국번3,4자리][번호4자리]\n"
|
|
+ "혹은 [국번3,4자리][번호4자리]";
|
|
break;
|
|
|
|
case -4 :
|
|
msg = "지역번호가 현재 사용하지 않는 번호입니다.";
|
|
break;
|
|
|
|
case -8 :
|
|
msg = "국번호는 3자리나 4자리이어야 합니다.";
|
|
break;
|
|
|
|
case -16 :
|
|
msg = "맨 뒤 번호는 4자리를 입력해야 합니다.";
|
|
break;
|
|
}
|
|
|
|
|
|
if ( validResult < 0 ) {
|
|
alert(msg);
|
|
}
|
|
|
|
return validResult;
|
|
}
|
|
|
|
|
|
/**
|
|
* 전화(혹은 팩스)번호의 값을 확인하여 유효한 경우이면 형식화한다.
|
|
*/
|
|
function formatTelNoObjIfValid(obj, fieldName) {
|
|
if ( validateTelNo(obj.value, fieldName) == 0 ) {
|
|
/* 유효한 값이면 형식화한다. */
|
|
formatTelNoObj(obj);
|
|
}
|
|
else {
|
|
/* 유효하지 않은 값이면 잡아 둔다. */
|
|
obj.focus();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 핸드폰용 지역번호 목록 */
|
|
var hpLocalNoList = [
|
|
"010", "011", "016", "017", "018", "019"
|
|
];
|
|
|
|
/**
|
|
* Text형 입력 폼의 값이 올바른 핸드폰(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 true를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 핸드폰 번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param obj 핸드폰 번호를 입력 받는 Text형 입력폼
|
|
*/
|
|
function checkHpNoObj(obj) {
|
|
return checkHpNo(obj.value);
|
|
}
|
|
|
|
|
|
/**
|
|
* 주어진 값이 올바른 핸드폰 번호(일반 전화번호가 아닌)인지 확인하여
|
|
* 올바르면 true를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 핸드폰 번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param phoneNo 검사하려는 핸드폰 번호값
|
|
*/
|
|
function checkHpNo(phoneNo) {
|
|
// 빈값이면 검사하지 않는다.
|
|
if ( trim(phoneNo) == "" ) return 0;
|
|
|
|
phoneNo = removeChar(phoneNo, '-');
|
|
|
|
if ( isNaN(phoneNo) ) {
|
|
return -1;
|
|
}
|
|
|
|
/* 형식에 문자가 있는지 검사한다. */
|
|
//var hpNoRegExp = /^01[016789]-[\d]{3,4}-[\d]{4}$/;
|
|
var hpNoRegExp = /^01[016789][\d]{7,8}$/;
|
|
|
|
if ( ! hpNoRegExp.test(phoneNo) ) return -2;
|
|
|
|
// 각 요소를 자른다.
|
|
var localNo = phoneNo.substr(0, 3);; // 지역번호
|
|
var areaNo = ( phoneNo.length == 10
|
|
? phoneNo.substr(3, 3) : phoneNo.substr(3, 4) ); // 국번
|
|
var restNo = phoneNo.substr(3 + areaNo.length); // 기타 번호
|
|
|
|
// 유효한 지역번호가 아니면 오류이다.
|
|
var isExistsLocalNo = existsInArray(hpLocalNoList, localNo);
|
|
|
|
if ( ! isExistsLocalNo ) {
|
|
return -4;
|
|
}
|
|
|
|
// 국번호가 3자리에서 4자리인지 검사한다.
|
|
if ( areaNo.length != 3 && areaNo.length != 4 ) {
|
|
return -8;
|
|
}
|
|
|
|
// 나머지 번호를 검사한다.
|
|
if ( restNo.length != 4 ) {
|
|
return -16;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param phoneNo 검사하려는 전화번호 값
|
|
*/
|
|
function validateHpNoObj(obj, fieldName) {
|
|
var validResult = validateHpNo(obj.value, fieldName);
|
|
|
|
if ( validResult < 0 ) {
|
|
obj.focus();
|
|
}
|
|
|
|
return validResult;
|
|
}
|
|
|
|
/**
|
|
* 주어진 값이 올바른 전화번호(핸드폰 번호가 아닌)인지 확인하여
|
|
* 올바르면 0를, 그렇지 않으면 적절한 메세지를 뿌려주고 false를 돌려 준다.
|
|
* 전화번호의 각 요소는 대쉬(-)로 구별된 것으로 가정한다.
|
|
*
|
|
* @date 2004-02-02
|
|
* @param phoneNo 검사하려는 전화번호 값
|
|
*/
|
|
function validateHpNo(phoneNo, fieldName) {
|
|
var validResult = checkHpNo(phoneNo);
|
|
|
|
/* fieldName이 정의되어 있지 않다면 "핸드폰 번호"로 한다. */
|
|
if ( fieldName == undefined ) fieldName = "핸드폰 번호";
|
|
|
|
var msg = "";
|
|
|
|
switch ( validResult ) {
|
|
case -1 :
|
|
msg = fieldName + "은(는) 숫자만 이용해서 입력해야 합니다.";
|
|
break;
|
|
|
|
case -2 :
|
|
msg = fieldName + "의 형식([지역번호 3자리][국번3,4자리][번호4자리])에 "
|
|
+ " 맞지 않습니다.";
|
|
break;
|
|
|
|
case -4 :
|
|
msg = "지역번호가 현재 사용하지 않는 번호입니다.";
|
|
break;
|
|
|
|
case -8 :
|
|
msg = "국번호는 3자리나 4자리이어야 합니다.";
|
|
break;
|
|
|
|
case -16 :
|
|
msg = "맨 뒤 번호는 4자리를 입력해야 합니다.";
|
|
break;
|
|
}
|
|
|
|
|
|
if ( validResult < 0 ) {
|
|
alert(msg);
|
|
}
|
|
|
|
return validResult;
|
|
}
|
|
|
|
|
|
/**
|
|
* 핸드폰 번호의 값을 확인하여 유효한 경우이면 형식화한다.
|
|
*/
|
|
function formatHpNoObjIfValid(obj, fieldName) {
|
|
if ( validateHpNo(obj.value, fieldName) == 0 ) {
|
|
/* 유효한 값이면 형식화한다. */
|
|
formatHpNoObj(obj);
|
|
}
|
|
else {
|
|
/* 유효하지 않은 값이면 잡아 둔다. */
|
|
obj.focus();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function validateContactNoObj(obj, fieldName) {
|
|
var result = validateContactNo(obj.value, fieldName);
|
|
|
|
if ( result < 0 ) obj.focus();
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* 연락처의 번호가 유효한지 검사한다.
|
|
* 연락처는 전화번호, 팩스번호, 핸드폰 번호를 모두 통칭하여 말한다.
|
|
*
|
|
* @param contactNo 유효성을 검증할 연락처 번호.
|
|
* @param fieldName 유효성을 검증할 항목명. 없으면 "연락처"를 사용한다.
|
|
*/
|
|
function validateContactNo(contactNo, fieldName) {
|
|
if ( contactNo == "" ) return 0;
|
|
|
|
/* fieldName이 정의되지 않았다면 "연락처"를 사용한다. */
|
|
if ( fieldName == undefined ) fieldName = "연락처";
|
|
|
|
/* 전화/팩스 번호인지, 핸드폰 번호인지를 판단한다.
|
|
-1 : 알수 없음.
|
|
-2 : 지역번호 정보 없음.
|
|
1 : 전화/팩스번호.
|
|
2 : 핸드폰 번호. */
|
|
var whichTypeNo = findWhichTypeNo(contactNo);
|
|
|
|
var result = -1;
|
|
if ( whichTypeNo == -1 || whichTypeNo == -2 || whichTypeNo == 1 ) {
|
|
/* 알수없음이거나 지역번호가 없음 일반전화 지역번호이면 전화번호로 검사. */
|
|
result = validateTelNo(contactNo, fieldName);
|
|
}
|
|
else if ( whichTypeNo == 2 ) {
|
|
/* 핸드폰 번호이면 핸드폰 번호로 검사 */
|
|
result = validateHpNo(contactNo, fieldName);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* 연락처의 번호가 구체적으로 어떤 번호인지
|
|
* 판단하여 돌려 준다.
|
|
*
|
|
* -1 : 알수 없음.
|
|
* -2 : 지역번호 정보 없음.
|
|
* 1 : 전화/팩스번호.
|
|
* 2 : 핸드폰 번호.
|
|
*/
|
|
function findWhichTypeNo(contactNo) {
|
|
var whichTypeNo = -1;
|
|
|
|
/* 형식이 맞는지 검사하여 맞지 않으면 알수 없음. */
|
|
var contactNoRegExp = /^(0[1-9]{1,2}-)?[\d]{3,4}-[\d]{4}$/;
|
|
|
|
if ( ! contactNoRegExp.test(contactNo) ) return -1;
|
|
|
|
var tempArr = contactNo.split("-");
|
|
|
|
/* 길이가 2이면 지역번호 없음. */
|
|
if ( tempArr.length == 2 ) return -2;
|
|
|
|
/* 전화지역번호에 있나? */
|
|
if ( existsInArray(tpLocalNoList, contactNo) ) {
|
|
whichTypeNo = 1;
|
|
}
|
|
/* 핸드폰지역번호에 있나? */
|
|
else if ( existsInArray(hpLocalNoList, contactNo) ) {
|
|
whichTypeNo = 2;
|
|
}
|
|
|
|
return whichTypeNo;
|
|
}
|
|
|
|
|
|
/**
|
|
* Text형 입력폼의 값이 유효한 주민등록번호 인지를
|
|
* 점검하여 유효하면 true를 돌려주고 유효하지 않으면
|
|
* 적절한 메세지를 보여준 다음 false를 돌려준다.
|
|
* 파라미터인 obj2가 넘어오지 않으면 obj1에 주민등록번호
|
|
* 전체가 담겨 있는 것으로 가정하며, obj2가 넘어오면
|
|
* 앞 6자리는 obj1에 뒤 7자리는 obj2에 담겨 있는 것으로
|
|
* 가정한다.
|
|
*
|
|
* @작성일 2004-02-05
|
|
* @param obj1 전체 주민등록번호 혹은 주민등록번호
|
|
* 앞 6자리를 담고 있는 Text형 입력폼 객체
|
|
* @param obj2 주민등록번호 뒤 7자리를 담고 있는 Text형 입력폼 객체
|
|
*/
|
|
function checkSSNObj(obj1, obj2) {
|
|
var valid = true;
|
|
|
|
if ( obj2 == undefined ) {
|
|
valid = checkSSN(obj1.value);
|
|
}
|
|
else {
|
|
valid = checkSSN(obj1.value, obj2.value);
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
/**
|
|
* 주민등록번호 유효성 여부를 점검하여 유효하면 true를
|
|
* 유효하지 않으면 적절한 메세지를 보여주고 false를 돌려준다.
|
|
* 파라미터의 갯수에 따라 그 의미가 조금 달라진다.
|
|
* ssn2가 정의되지 않았으면, 대쉬(-)의 여부에
|
|
* 상관없이 ssn1에 전체 주민등록번호가 담겨있는 것으로
|
|
* 가정하고, ssn2가 정의되어 있으면 ssn1에 앞 6자리
|
|
* ssn2에 뒤 7자리로 넘어오는 것으로 가정한다.
|
|
*
|
|
* @작성일 2004-02-05
|
|
* @param ssn1 전체 주민등록번호 혹은 주민등록번호 앞 6자리
|
|
* @param ssn2 주민등록번호 뒤 7자리
|
|
*/
|
|
function checkSSN(ssn1, ssn2) {
|
|
var ssn = "";
|
|
if ( ssn2 == undefined ) {
|
|
ssn = ssn1;
|
|
}
|
|
else {
|
|
ssn = ssn1 + "-" + ssn2;
|
|
}
|
|
|
|
// 주민번호의 형태와 7번째 자리(성별) 유효성 검사
|
|
var ssnRegEx = /^\d{6}-[1234]\d{6}$/;
|
|
if ( ! ssnRegEx.test(ssn)) {
|
|
alert("잘못된 주민등록번호입니다.");
|
|
return false;
|
|
}
|
|
|
|
// 날짜 유효성 검사
|
|
var birthYear = (ssn.charAt(7) <= "2") ? "19" : "20";
|
|
birthYear += ssn.substr(0, 2);
|
|
var birthMonth = ssn.substr(2, 2) - 1;
|
|
var birthDate = ssn.substr(4, 2);
|
|
var birth = new Date(birthYear, birthMonth, birthDate);
|
|
|
|
if ( birth.getYear() % 100 != ssn.substr(0, 2)
|
|
|| birth.getMonth() != birthMonth
|
|
|| birth.getDate() != birthDate ) {
|
|
alert("잘못된 주민등록번호입니다.");
|
|
return false;
|
|
}
|
|
|
|
// Check Sum 코드의 유효성 검사
|
|
var buf = new Array(13);
|
|
for (var i = 0; i < 6; i++) {
|
|
buf[i] = parseInt(ssn.charAt(i));
|
|
}
|
|
|
|
for (var i = 6; i < 13; i++) {
|
|
buf[i] = parseInt(ssn.charAt(i + 1));
|
|
}
|
|
|
|
var multipliers = [2,3,4,5,6,7,8,9,2,3,4,5];
|
|
var sum = 0;
|
|
for (var i = 0; i < 12; i++) {
|
|
sum += (buf[i] *= multipliers[i]);
|
|
}
|
|
|
|
if ( (11 - (sum % 11) ) % 10 != buf[12] ) {
|
|
alert("잘못된 주민등록번호입니다.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|