<commit_before>/* eslint-env jquery */
'use strict';

/**
 * 화면단 UI와 연동 되는 API. APIGateWay 혹은 API 클래스로 클래스명 수정 예정
 * @class MagoFacade
 */
/**
 * mago3d 활성화/비활성화
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeMagoStateAPI(isShow)
{
	var api = new API("changeMagoState");
	api.setMagoEnable(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * render mode
 *
 * @param {Property} renderMode 0 = 호선, 1 = 지번전개
 */
function changeRenderAPI(renderMode)
{
	var api = new API("changeRender");
	api.setRenderMode(renderMode);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * outfitting 표시/비표시
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeOutFittingAPI(isShow)
{
	var api = new API("changeOutFitting");
	api.setShowOutFitting(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * Label 표시/비표시
 *
 * @param {Property} isShow true = 표시, false = 비표시
 */
function changeLabelAPI(isShow)
{
	var api = new API("changeLabel");
	api.setShowLabelInfo(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * boundingBox 표시/비표시
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeBoundingBoxAPI(isShow)
{
	var api = new API("changeBoundingBox");
	api.setShowBoundingBox(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 그림자 표시/비표시
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeShadowAPI(isShow)
{
	var api = new API("changeShadow");
	api.setShowShadow(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * frustum culling 가시 거리
 *
 * @param {Property} frustumFarDistance frustum 거리. 내부적으로는 입력값의 제곱이 사용됨
 */
function changeFrustumFarDistanceAPI(frustumFarDistance)
{
	var api = new API("changefrustumFarDistance");
	api.setFrustumFarDistance(frustumFarDistance);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * highlighting
 *
 * @param {Property} projectId 프로젝트 아이디
 * @param {Property} blockIds block id. 복수개의 경우 , 로 입력
 * @param {Property} objectIds object id. 복수개의 경우 , 로 입력
 */
function changeHighLightingAPI(projectId, blockIds, objectIds)
{
	var api = new API("changeHighLighting");
	api.setProjectId(projectId);
	api.setBlockIds(blockIds);
	api.setObjectIds(objectIds);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * color 변경
 *
 * @param {Property} projectId 프로젝트 아이디
 * @param {Property} blockIds block id. 복수개의 경우 , 로 입력
 * @param {Property} objectIds object id. 복수개의 경우 , 로 입력
 * @param {Property} color R, G, B 색깔을 ',' 로 연결한 string 값을 받음.
 */
function changeColorAPI(projectId, blockIds, objectIds, color)
{
	var api = new API("changeColor");
	api.setProjectId(projectId);
	api.setBlockIds(blockIds);
	api.setObjectIds(objectIds);
	api.setColor(color);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * location and rotation 변경
 *
 * @param {Property} data_key
 * @param {Property} latitude 위도
 * @param {Property} longitude 경도
 * @param {Property} height 높이
 * @param {Property} heading 좌, 우
 * @param {Property} pitch 위, 아래
 * @param {Property} roll 좌, 우 기울기
 */
function changeLocationAndRotationAPI(data_key, latitude, longitude, height, heading, pitch, roll)
{
	var api = new API("changeLocationAndRotation");
	api.setDataKey(data_key);
	api.setLatitude(latitude);
	api.setLongitude(longitude);
	api.setElevation(height);
	api.setHeading(heading);
	api.setPitch(pitch);
	api.setRoll(roll);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 마우스 클릭 객체 이동 대상 변경
 *
 * @param {Property} mouseMoveMode 0 = All, 1 = object, 2 = None
 */
function changeMouseMoveAPI(mouseMoveMode)
{
	var api = new API("changeMouseMove");
	api.setMouseMoveMode(mouseMoveMode);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 이슈 등록 활성화 유무
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeInsertIssueModeAPI(flag)
{
	var api = new API("changeInsertIssueMode");
	api.setIssueInsertEnable(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * object 정보 표시 활성화 유무
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeObjectInfoViewModeAPI(flag)
{
	var api = new API("changeObjectInfoViewMode");
	api.setObjectInfoViewEnable(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * Object Occlusion culling
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 * @param {Property} dataKey
 */
function changeOcclusionCullingAPI(flag, dataKey)
{
	var api = new API("changeOcclusionCulling");
	api.setOcclusionCullingEnable(flag);
	api.setDataKey(dataKey);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 1인칭, 3인칭 모드 개발중...
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeFPVModeAPI(flag)
{
	var api = new API("changeFPVMode");
	api.setFPVMode(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 현재 위치 근처 issue list. false인 경우 clear
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeNearGeoIssueListViewModeAPI(flag)
{
	var api = new API("changeNearGeoIssueListViewMode");
	api.setNearGeoIssueListEnable(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * TODO 이건 위에 이슈 등록 활성화, 비활성화 api로 통합이 가능할거 같음
 * issue 등록 geo 정보 관련 상태 변경
 *
 * @param {Property} insertIssueState 이슈 등록 좌표 상태
 */
function changeInsertIssueStateAPI(insertIssueState)
{
	var api = new API("changeInsertIssueState");
	api.setInsertIssueState(insertIssueState);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * LOD 설정을 변경
 * @param {Property} lod0DistInMeters
 * @param {Property} lod1DistInMeters
 * @param {Property} lod2DistInMeters
 * @param {Property} lod3DistInMeters
 */
function changeLodAPI(lod0DistInMeters, lod1DistInMeters, lod2DistInMeters, lod3DistInMeters)
{
	var api = new API("changeLod");
	api.setLod0DistInMeters(lod0DistInMeters);
	api.setLod1DistInMeters(lod1DistInMeters);
	api.setLod2DistInMeters(lod2DistInMeters);
	api.setLod3DistInMeters(lod3DistInMeters);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * Lighting 설정
 * @param {Property} ambientReflectionCoef
 * @param {Property} diffuseReflectionCoef
 * @param {Property} specularReflectionCoef
 * @param {Property} ambientColor
 * @param {Property} specularColor
 */
function changeLightingAPI(ambientReflectionCoef, diffuseReflectionCoef, specularReflectionCoef, ambientColor, specularColor)
{
	var api = new API("changeLighting");
	api.setAmbientReflectionCoef(ambientReflectionCoef);
	api.setDiffuseReflectionCoef(diffuseReflectionCoef);
	api.setSpecularReflectionCoef(specularReflectionCoef);
	api.setAmbientColor(ambientColor);
	api.setSpecularColor(specularColor);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * SSAD Radius 설정
 * @param {Property} ssaoRadius
 */
function changeSsadRadiusAPI(ssaoRadius)
{
	var api = new API("changeSsadRadius");
	api.setSsaoRadius(ssaoRadius);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * pin image를 그림
 *
 * @param {Property} drawType 이미지를 그리는 유형 0 : DB, 1 : 이슈등록
 * @param {Property} issue_id 이슈 고유키
 * @param {Property} issue_type 이슈 고유키
 * @param {Property} data_key 데이터 고유키
 * @param {Property} latitude 데이터 고유키
 * @param {Property} longitude 데이터 고유키
 * @param {Property} height 데이터 고유키
 */
function drawInsertIssueImageAPI(drawType, issue_id, issue_type, data_key, latitude, longitude, height)
{
	var api = new API("drawInsertIssueImage");
	api.setDrawType(drawType);
	api.setIssueId(issue_id);
	api.setIssueId(issue_type);
	api.setDataKey(data_key);
	api.setLatitude(latitude);
	api.setLongitude(longitude);
	api.setElevation(height);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 마우스를 사용할 수 없는 환경에서 버튼 이벤트로 대체
 * @param {Property} eventType 어떤 마우스 동작을 원하는지를 구분
 */
function mouseMoveAPI(eventType)
{
	if (managerFactory !== null)
	{
		managerFactory.mouseMove(eventType);
	}
}

/**
 * 데이터 검색
 *
 * @param {Property} dataKey 데이터 고유키
 */
function searchDataAPI(dataKey)
{
	var api = new API("searchData");
	api.setDataKey(dataKey);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 데이터를 Rendering
 *
 * @param type new clear 후 새로 그림, append = 추가하여 그림
 * @param dataNameArray target data 이름 배열
 * @param dataUrlArray data를 가져올 url 배열
 * @param
 */
function drawData(type, dataNameArray, dataUrlArray)
{
	if (dataNameArray.length <= 0) { return; }

	var keyMap = new Map();
	var dataCount = 0;
	dataNameArray.forEach(function(dataName, index)
	{
		if (MagoConfig.isDataExist(dataName))
		{
			var data = MagoConfig.getData(dataName);
			keyMap.set(dataName, dataName);
			keyMap.set(CODE.OBJECT_INDEX_FILE_PREFIX + data.data_key, data.data_key);
			// 맨 마지막에는 map에서 지우는 처리를 하러 가자.
			if (type === "new" && dataNameArray.length === (dataCount + 1))
			{
				MagoConfig.clearUnSelectedData(keyMap);
			}
		}
		else
		{
			console.log("not exist. dataName = " + dataName);
			var objectIndexFilePath = null;
			$.ajax({
				url      : dataUrlArray[index],
				type     : "GET",
				dataType : "json",
				success  : function(serverData)
				{
					MagoConfig.setData(dataName, serverData);
					objectIndexFilePath = serverData.data_key;
					keyMap.set(dataName, dataName);
					keyMap.set(CODE.OBJECT_INDEX_FILE_PREFIX + objectIndexFilePath, objectIndexFilePath);
					managerFactory.loadObjectIndexFile(dataName, objectIndexFilePath);

					// 맨 마지막에는 map에서 지우는 처리를 하러 가자.
					if (type === "new" && dataNameArray.length === (dataCount + 1))
					{
						MagoConfig.clearUnSelectedData(keyMap);
					}
				},
				error: function(request, status, error)
				{
					//alert(JS_MESSAGE["ajax.error.message"]);
					console.log("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
				}
			});
		}

		dataCount++;
	});
}

<commit_msg>ajax foreach 로직 버그 수정<commit_after>/* eslint-env jquery */
'use strict';

/**
 * 화면단 UI와 연동 되는 API. APIGateWay 혹은 API 클래스로 클래스명 수정 예정
 * @class MagoFacade
 */
/**
 * mago3d 활성화/비활성화
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeMagoStateAPI(isShow)
{
	var api = new API("changeMagoState");
	api.setMagoEnable(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * render mode
 *
 * @param {Property} renderMode 0 = 호선, 1 = 지번전개
 */
function changeRenderAPI(renderMode)
{
	var api = new API("changeRender");
	api.setRenderMode(renderMode);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * outfitting 표시/비표시
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeOutFittingAPI(isShow)
{
	var api = new API("changeOutFitting");
	api.setShowOutFitting(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * Label 표시/비표시
 *
 * @param {Property} isShow true = 표시, false = 비표시
 */
function changeLabelAPI(isShow)
{
	var api = new API("changeLabel");
	api.setShowLabelInfo(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * boundingBox 표시/비표시
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeBoundingBoxAPI(isShow)
{
	var api = new API("changeBoundingBox");
	api.setShowBoundingBox(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 그림자 표시/비표시
 *
 * @param {Property} isShow true = 활성화, false = 비활성화
 */
function changeShadowAPI(isShow)
{
	var api = new API("changeShadow");
	api.setShowShadow(isShow);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * frustum culling 가시 거리
 *
 * @param {Property} frustumFarDistance frustum 거리. 내부적으로는 입력값의 제곱이 사용됨
 */
function changeFrustumFarDistanceAPI(frustumFarDistance)
{
	var api = new API("changefrustumFarDistance");
	api.setFrustumFarDistance(frustumFarDistance);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * highlighting
 *
 * @param {Property} projectId 프로젝트 아이디
 * @param {Property} blockIds block id. 복수개의 경우 , 로 입력
 * @param {Property} objectIds object id. 복수개의 경우 , 로 입력
 */
function changeHighLightingAPI(projectId, blockIds, objectIds)
{
	var api = new API("changeHighLighting");
	api.setProjectId(projectId);
	api.setBlockIds(blockIds);
	api.setObjectIds(objectIds);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * color 변경
 *
 * @param {Property} projectId 프로젝트 아이디
 * @param {Property} blockIds block id. 복수개의 경우 , 로 입력
 * @param {Property} objectIds object id. 복수개의 경우 , 로 입력
 * @param {Property} color R, G, B 색깔을 ',' 로 연결한 string 값을 받음.
 */
function changeColorAPI(projectId, blockIds, objectIds, color)
{
	var api = new API("changeColor");
	api.setProjectId(projectId);
	api.setBlockIds(blockIds);
	api.setObjectIds(objectIds);
	api.setColor(color);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * location and rotation 변경
 *
 * @param {Property} data_key
 * @param {Property} latitude 위도
 * @param {Property} longitude 경도
 * @param {Property} height 높이
 * @param {Property} heading 좌, 우
 * @param {Property} pitch 위, 아래
 * @param {Property} roll 좌, 우 기울기
 */
function changeLocationAndRotationAPI(data_key, latitude, longitude, height, heading, pitch, roll)
{
	var api = new API("changeLocationAndRotation");
	api.setDataKey(data_key);
	api.setLatitude(latitude);
	api.setLongitude(longitude);
	api.setElevation(height);
	api.setHeading(heading);
	api.setPitch(pitch);
	api.setRoll(roll);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 마우스 클릭 객체 이동 대상 변경
 *
 * @param {Property} mouseMoveMode 0 = All, 1 = object, 2 = None
 */
function changeMouseMoveAPI(mouseMoveMode)
{
	var api = new API("changeMouseMove");
	api.setMouseMoveMode(mouseMoveMode);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 이슈 등록 활성화 유무
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeInsertIssueModeAPI(flag)
{
	var api = new API("changeInsertIssueMode");
	api.setIssueInsertEnable(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * object 정보 표시 활성화 유무
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeObjectInfoViewModeAPI(flag)
{
	var api = new API("changeObjectInfoViewMode");
	api.setObjectInfoViewEnable(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * Object Occlusion culling
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 * @param {Property} dataKey
 */
function changeOcclusionCullingAPI(flag, dataKey)
{
	var api = new API("changeOcclusionCulling");
	api.setOcclusionCullingEnable(flag);
	api.setDataKey(dataKey);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 1인칭, 3인칭 모드 개발중...
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeFPVModeAPI(flag)
{
	var api = new API("changeFPVMode");
	api.setFPVMode(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 현재 위치 근처 issue list. false인 경우 clear
 *
 * @param {Property} flag true = 활성화, false = 비활성화
 */
function changeNearGeoIssueListViewModeAPI(flag)
{
	var api = new API("changeNearGeoIssueListViewMode");
	api.setNearGeoIssueListEnable(flag);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * TODO 이건 위에 이슈 등록 활성화, 비활성화 api로 통합이 가능할거 같음
 * issue 등록 geo 정보 관련 상태 변경
 *
 * @param {Property} insertIssueState 이슈 등록 좌표 상태
 */
function changeInsertIssueStateAPI(insertIssueState)
{
	var api = new API("changeInsertIssueState");
	api.setInsertIssueState(insertIssueState);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * LOD 설정을 변경
 * @param {Property} lod0DistInMeters
 * @param {Property} lod1DistInMeters
 * @param {Property} lod2DistInMeters
 * @param {Property} lod3DistInMeters
 */
function changeLodAPI(lod0DistInMeters, lod1DistInMeters, lod2DistInMeters, lod3DistInMeters)
{
	var api = new API("changeLod");
	api.setLod0DistInMeters(lod0DistInMeters);
	api.setLod1DistInMeters(lod1DistInMeters);
	api.setLod2DistInMeters(lod2DistInMeters);
	api.setLod3DistInMeters(lod3DistInMeters);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * Lighting 설정
 * @param {Property} ambientReflectionCoef
 * @param {Property} diffuseReflectionCoef
 * @param {Property} specularReflectionCoef
 * @param {Property} ambientColor
 * @param {Property} specularColor
 */
function changeLightingAPI(ambientReflectionCoef, diffuseReflectionCoef, specularReflectionCoef, ambientColor, specularColor)
{
	var api = new API("changeLighting");
	api.setAmbientReflectionCoef(ambientReflectionCoef);
	api.setDiffuseReflectionCoef(diffuseReflectionCoef);
	api.setSpecularReflectionCoef(specularReflectionCoef);
	api.setAmbientColor(ambientColor);
	api.setSpecularColor(specularColor);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * SSAD Radius 설정
 * @param {Property} ssaoRadius
 */
function changeSsadRadiusAPI(ssaoRadius)
{
	var api = new API("changeSsadRadius");
	api.setSsaoRadius(ssaoRadius);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * pin image를 그림
 *
 * @param {Property} drawType 이미지를 그리는 유형 0 : DB, 1 : 이슈등록
 * @param {Property} issue_id 이슈 고유키
 * @param {Property} issue_type 이슈 고유키
 * @param {Property} data_key 데이터 고유키
 * @param {Property} latitude 데이터 고유키
 * @param {Property} longitude 데이터 고유키
 * @param {Property} height 데이터 고유키
 */
function drawInsertIssueImageAPI(drawType, issue_id, issue_type, data_key, latitude, longitude, height)
{
	var api = new API("drawInsertIssueImage");
	api.setDrawType(drawType);
	api.setIssueId(issue_id);
	api.setIssueId(issue_type);
	api.setDataKey(data_key);
	api.setLatitude(latitude);
	api.setLongitude(longitude);
	api.setElevation(height);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 마우스를 사용할 수 없는 환경에서 버튼 이벤트로 대체
 * @param {Property} eventType 어떤 마우스 동작을 원하는지를 구분
 */
function mouseMoveAPI(eventType)
{
	if (managerFactory !== null)
	{
		managerFactory.mouseMove(eventType);
	}
}

/**
 * 데이터 검색
 *
 * @param {Property} dataKey 데이터 고유키
 */
function searchDataAPI(dataKey)
{
	var api = new API("searchData");
	api.setDataKey(dataKey);
	if (managerFactory !== null)
	{
		managerFactory.callAPI(api);
	}
}

/**
 * 데이터를 Rendering
 *
 * @param type new clear 후 새로 그림, append = 추가하여 그림
 * @param dataNameArray target data 이름 배열
 * @param dataUrlArray data를 가져올 url 배열
 * @param
 */
function drawData(type, dataNameArray, dataUrlArray)
{
	if (dataNameArray.length <= 0) { return; }

	var keyMap = new Map();
	var dataCount = 0;
	dataNameArray.forEach(function(dataName, index)
	{
		if (MagoConfig.isDataExist(dataName))
		{
			var data = MagoConfig.getData(dataName);
			keyMap.set(dataName, dataName);
			keyMap.set(CODE.OBJECT_INDEX_FILE_PREFIX + data.data_key, data.data_key);
			// 맨 마지막에는 map에서 지우는 처리를 하러 가자.
			if (type === "new" && dataNameArray.length === (dataCount + 1))
			{
				MagoConfig.clearUnSelectedData(keyMap);
			}
			dataCount++;
		}
		else
		{
			console.log("not exist. dataName = " + dataName);
			var objectIndexFilePath = null;
			$.ajax({
				url      : dataUrlArray[index],
				type     : "GET",
				dataType : "json",
				success  : function(serverData)
				{
					MagoConfig.setData(dataName, serverData);
					objectIndexFilePath = serverData.data_key;
					keyMap.set(dataName, dataName);
					keyMap.set(CODE.OBJECT_INDEX_FILE_PREFIX + objectIndexFilePath, objectIndexFilePath);
					managerFactory.loadObjectIndexFile(dataName, objectIndexFilePath);

					// 맨 마지막에는 map에서 지우는 처리를 하러 가자.
					if (type === "new" && dataNameArray.length === (dataCount + 1))
					{
						MagoConfig.clearUnSelectedData(keyMap);
					}
					dataCount++;
				},
				error: function(request, status, error)
				{
					//alert(JS_MESSAGE["ajax.error.message"]);
					console.log("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
				}
			});
		}
	});
}

<|endoftext|>


<commit_before>var PF = {

	getFeatures: function (img, colors) { // (HTMLImageElement, Object) -> Object
		var canv = this._wrapByCanvas(img),
			colors = this._colorsToRgb(colors),
            features = [[]];

		for (var x = 0; x < img.clientWidth; x++) {
			for (var y = 0; y < img.clientHeight; y++) {

				var px = { x: x, y: y },
					pxCol = this._getPixelColor(canv, px),
					nPxs,
					nPxCols,
                    fPxs,
                    fPxsCols,
                    fIdx;

				// skip if px is not a pixel of the feature
				if (this._isColorInColors(this._areColorsEqual, pxCol, colors) === false) {
					continue;
				};

				nPxs = this._getNeighborPixels(px, {
                    w: canv.width - 1,
                    h: canv.height - 1
                });
				nPxCols = this._getPixelsColors(canv, nPxs);

                // skip if px is not a boundary pixel of the feature
                if (this._areColorsEqualToColor(this._areColorsEqual, nPxCols, pxCol) === true) {
                    continue;
                }

                /*var pixelColorGetterFunc = curry(this._getPixelsColors, canv);
                var nColorIntersectCheckerFunc = curry(this._areColorsIntersects, this._areColorsEqual, nPxCols);
                features.filter(function(feature) {
                    nColorIntersectCheckerFunc(pixelColorGetterFunc(feature));
                });*/
                var pushPxToFeatureFunc = curry(this._pushPixelToFeature, px);
                features.map(pushPxToFeatureFunc);

                /*for (var i = 0; i < features.length; i++) {
                    fPxs = features[i];
                    fPxsCols = this._getPixelsColors(canv, fPxs);
                    // check or pixel belongs to one of already processed features
                    if (this._areColorsIntersects(this._areColorsEqual, fPxsCols, nPxCols) === true) {
                        features[i].push(px);
                    };
                };*/

                // we need only boundary pixels & only if it does't belongs to exists features
                /*if (isFeatureUpdated === false &&
                    this._areColorsEqualToColor(this._areColorsEqual, nPxCols, pxCol) === false) {
                    features[features.length] = [];
                    features[features.length-1].push(px);
                };*/

			};
		};

		return features;
	},

	_wrapByCanvas: function (img) { // (HTMLImageElement) -> HTMLCanvasElement
        var canv = document.createElement('canvas');
        canv.width = img.width;
        canv.height = img.height;
        canv.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
        return canv;
    },

    _colorsToRgb: function (cols) { // (Object) -> Object
    	for (var i = 0; i < cols.length; i++) {
  			cols[i] = toRGB(cols[i]);
    	};
    	return cols;
    },

    _getPixelColor: function (canvas, px) { // (HTMLCanvasElement, Object) -> Array
    	return canvas.getContext('2d').getImageData(px.x, px.y, 1, 1).data;
    },

    _getPixelsColors: function (canvas, pxs) { // (HTMLCanvasElement, Array) -> Array
    	var list = [];
    	for (var i = 0; i < pxs.length; i++) {
    		list.push(canvas.getContext('2d').getImageData(pxs[i].x, pxs[i].y, 1, 1).data);
    	};
    	return list;
    },

 	_areColorsEqual: function (col1, col2) { // (Array, Array) -> Boolean
    	var r = col1[0] === col2[0],
    		g = col1[1] === col2[1],
    		b = col1[2] === col2[2];

    	return (r && g && b);
    },

    _isColorInColors: function (checkingFunc, col, cols) { // (Function, Array, Array) -> Boolean
		for (var i = 0; i < cols.length; i++) {
			if (checkingFunc(col, cols[i]) === true) {
				return true;
			};
		};
		return false;
    },

    _areColorsEqualToColor: function (checkingFunc, cols, col) { // (Function, Array, Array) -> Boolean
		for (var i = 0; i < cols.length; i++) {
			if (checkingFunc(col, cols[i]) === false) {
				return false;
			};
		};
		return true;
    },

    _areColorsIntersects: function (checkingFunc, cols1, cols2) { // (Function, Array, Array) -> Boolean
        for (var i = 0; i < cols1.length; i++) {
            for (var j = 0; j < cols2.length; j++) {
                if (checkingFunc(cols1[i], cols2[j]) === true) {
                    return true;
                };
            };
        };
        return false;
    },

    _getNeighborPixels: function (px, imgSize) { // (Object, Object) -> Array
        var res = [];

        if (px.x > 0 && px.y > 0) {
            res.push({ x: px.x-1, y: px.y-1 }); // tl
        };

        if (px.y > 0) {
            res.push({ x: px.x,   y: px.y-1 }); // t
        };

        if (px.x < imgSize.w && px.y > 0) {
            res.push({ x: px.x+1, y: px.y-1 }); // tr
        };

        if (px.x < imgSize.w) {
            res.push({ x: px.x+1, y: px.y }); // r
        };

        if (px.x < imgSize.w && px.y < imgSize.h) {
            res.push({ x: px.x+1, y: px.y+1 }); // br
        };

        if (px.y < imgSize.h) {
            res.push({ x: px.x, y: px.y+1 }); // b
        };

        if (px.x > 0 && px.y < imgSize.h) {
            res.push({ x: px.x-1, y: px.y+1 }); // bl
        };

        if (px.x > 0) {
            res.push({ x: px.x-1, y: px.y }); // l
        };

        return res;
    },

    _pushPixelToFeature: function (pixel, feature) { // {Object, Array}
        feature.push(pixel);
    }
}<commit_msg>tabs removed<commit_after>var PF = {

    getFeatures: function (img, colors) { // (HTMLImageElement, Object) -> Object
        var canv = this._wrapByCanvas(img),
            colors = this._colorsToRgb(colors),
            features = [[]];

        for (var x = 0; x < img.clientWidth; x++) {
            for (var y = 0; y < img.clientHeight; y++) {

                var px = { x: x, y: y },
                	pxCol = this._getPixelColor(canv, px),
                	nPxs,
                	nPxCols,
                    fPxs,
                    fPxsCols,
                    fIdx;

                // skip if px is not a pixel of the feature
                if (this._isColorInColors(this._areColorsEqual, pxCol, colors) === false) {
                	continue;
                };

                nPxs = this._getNeighborPixels(px, {
                    w: canv.width - 1,
                    h: canv.height - 1
                });
                nPxCols = this._getPixelsColors(canv, nPxs);

                // skip if px is not a boundary pixel of the feature
                if (this._areColorsEqualToColor(this._areColorsEqual, nPxCols, pxCol) === true) {
                    continue;
                }

                /*var pixelColorGetterFunc = curry(this._getPixelsColors, canv);
                var nColorIntersectCheckerFunc = curry(this._areColorsIntersects, this._areColorsEqual, nPxCols);
                features.filter(function(feature) {
                    nColorIntersectCheckerFunc(pixelColorGetterFunc(feature));
                });*/
                var pushPxToFeatureFunc = curry(this._pushPixelToFeature, px);
                features.map(pushPxToFeatureFunc);

                /*for (var i = 0; i < features.length; i++) {
                    fPxs = features[i];
                    fPxsCols = this._getPixelsColors(canv, fPxs);
                    // check or pixel belongs to one of already processed features
                    if (this._areColorsIntersects(this._areColorsEqual, fPxsCols, nPxCols) === true) {
                        features[i].push(px);
                    };
                };*/

                // we need only boundary pixels & only if it does't belongs to exists features
                /*if (isFeatureUpdated === false &&
                    this._areColorsEqualToColor(this._areColorsEqual, nPxCols, pxCol) === false) {
                    features[features.length] = [];
                    features[features.length-1].push(px);
                };*/

            };
        };
        return features;
    },

    _wrapByCanvas: function (img) { // (HTMLImageElement) -> HTMLCanvasElement
        var canv = document.createElement('canvas');
        canv.width = img.width;
        canv.height = img.height;
        canv.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
        return canv;
    },

    _colorsToRgb: function (cols) { // (Object) -> Object
        for (var i = 0; i < cols.length; i++) {
        		cols[i] = toRGB(cols[i]);
        };
        return cols;
    },

    _getPixelColor: function (canvas, px) { // (HTMLCanvasElement, Object) -> Array
        return canvas.getContext('2d').getImageData(px.x, px.y, 1, 1).data;
    },

    _getPixelsColors: function (canvas, pxs) { // (HTMLCanvasElement, Array) -> Array
        var list = [];
        for (var i = 0; i < pxs.length; i++) {
        	list.push(canvas.getContext('2d').getImageData(pxs[i].x, pxs[i].y, 1, 1).data);
        };
        return list;
    },

    _areColorsEqual: function (col1, col2) { // (Array, Array) -> Boolean
        var r = col1[0] === col2[0],
           g = col1[1] === col2[1],
           b = col1[2] === col2[2];

        return (r && g && b);
    },

    _isColorInColors: function (checkingFunc, col, cols) { // (Function, Array, Array) -> Boolean
        for (var i = 0; i < cols.length; i++) {
            if (checkingFunc(col, cols[i]) === true) {
                return true;
            };
        };
        return false;
    },

    _areColorsEqualToColor: function (checkingFunc, cols, col) { // (Function, Array, Array) -> Boolean
        for (var i = 0; i < cols.length; i++) {
            if (checkingFunc(col, cols[i]) === false) {
                return false;
            };
        };
        return true;
    },

    _areColorsIntersects: function (checkingFunc, cols1, cols2) { // (Function, Array, Array) -> Boolean
        for (var i = 0; i < cols1.length; i++) {
            for (var j = 0; j < cols2.length; j++) {
                if (checkingFunc(cols1[i], cols2[j]) === true) {
                    return true;
                };
            };
        };
        return false;
    },

    _getNeighborPixels: function (px, imgSize) { // (Object, Object) -> Array
        var res = [];

        if (px.x > 0 && px.y > 0) {
            res.push({ x: px.x-1, y: px.y-1 }); // tl
        };

        if (px.y > 0) {
            res.push({ x: px.x,   y: px.y-1 }); // t
        };

        if (px.x < imgSize.w && px.y > 0) {
            res.push({ x: px.x+1, y: px.y-1 }); // tr
        };

        if (px.x < imgSize.w) {
            res.push({ x: px.x+1, y: px.y }); // r
        };

        if (px.x < imgSize.w && px.y < imgSize.h) {
            res.push({ x: px.x+1, y: px.y+1 }); // br
        };

        if (px.y < imgSize.h) {
            res.push({ x: px.x, y: px.y+1 }); // b
        };

        if (px.x > 0 && px.y < imgSize.h) {
            res.push({ x: px.x-1, y: px.y+1 }); // bl
        };

        if (px.x > 0) {
            res.push({ x: px.x-1, y: px.y }); // l
        };

        return res;
    },

    _pushPixelToFeature: function (pixel, feature) { // {Object, Array}
        feature.push(pixel);
    }
}<|endoftext|>


<commit_before>require('moonstone');

var
	kind = require('enyo/kind'),
	NewDataList = require('enyo/NewDataList');

var
	Spotlight = require('spotlight'),
	VDRSpotlightSupport = require('spotlight/VDRSpotlightSupport');

var
	Scrollable = require('../Scrollable'),
	ScrollControls = require('../ScrollControls');

module.exports = kind({
	name: 'moon.NewDataList',
	kind: NewDataList,
	scrollControls: [{kind: ScrollControls}],
	touch: false,
	mixins: [Scrollable, VDRSpotlightSupport],
	handlers: {
		onSpotlightUp: 'guard5way',
		onSpotlightRight: 'guard5way',
		onSpotlightDown: 'guard5way',
		onSpotlightLeft: 'guard5way'
	},
	/**
	* Prevent accelerating 5-way focus events from trying
	* to spot elements that don't yet have DOM nodes.
	*
	* @private
	*/
	guard5way: function (sender, event) {
		var e, l, idx, d2x, row, limitRow, verMovOnHorScrol, horMovOnVerScrol;

		e = event.type;
		verMovOnHorScrol = (this.direction === 'horizintal' &&  (e === 'onSpotlightUp' || e === 'onSpotlightDown'));
		horMovOnVerScrol = (this.direction === 'vertical' &&  (e === 'onSpotlightRight' || e === 'onSpotlightLeft'));

		// Only need to guard if we are accelerating or
		// scroll direction and spotlight moving direction matches
		if (!Spotlight.Accelerator.isAccelerating() || verMovOnHorScrol || horMovOnVerScrol) return false;

		// Figure out the index of the last de-virtualized element
		// in the direction we're currently scrolling; anything
		// further out doesn't yet have a DOM node
		l = (e === 'onSpotlightUp' || e === 'onSpotlightLeft') ?
			this.first :
			this._last;

		// Get the index of the currently focused element
		idx = event.index;

		// In case we're in a grid layout, we need to translate
		// these indices into the corresponding row / column
		d2x = this.dim2extent;
		row = Math.floor(idx / d2x);
		limitRow = Math.floor(l / d2x);

		// If we're in the last de-virtualized row, the element we
		// would focus from here doesn't yet have a DOM node, so
		// we return true to prevent an attempt to focus. We'll wait
		// for the next accelerated 5-way event and try again...
		return (row === limitRow);
	},
	/**
	* Scrolls to a list item (specified by index).
	*
	* In addition to the standard scrolling options, you can specify
	* `focus: true` if you want the item you're scrolling to to be
	* Spotlight focused. Currently, setting `focus: true` forces the
	* scroll behavior to be `instant`, meaning that the scroller will
	* jump to the item (with no animation).
	*
	* @see module:enyo/NewDataList~NewDataList.scrollToItem
	* @param {number} index - The (zero-based) index of the item to scroll to
	* @param {Object} opts - Scrolling options (see module:enyo/Scrollable~Scrollable.scrollTo)
	* @public
	*/
	scrollToItem: function(index, opts) {
		var item;

		if (opts && opts.focus) {
			opts.behavior = 'instant';
		}

		NewDataList.prototype.scrollToItem.apply(this, arguments);

		if (opts && opts.focus && !Spotlight.getPointerMode()) {
			item = this.childForIndex(index);
			if (item) Spotlight.spot(item);
		}
	},
	/**
	* Called by moonstone/Scrollable.filterFocus()
	* @private
	*/
	eventIsFromScrollingChild: function (event) {
		return (typeof event.index === 'number');
	},
	/**
	* Called by moonstone/Scrollable.filterFocus()
	* @private
	*/
	spotFirstVisibleChild: function() {
		var fv = this.getFullyVisibleItems()[0] || this.getVisibleItems()[0];
		if (fv) {
			Spotlight.spot(fv);
			return true;
		}
	}
});
<commit_msg>ENYO-2839: moonstone/NewDataList: Fix 5-way guard code in RTL<commit_after>require('moonstone');

var
	kind = require('enyo/kind'),
	NewDataList = require('enyo/NewDataList');

var
	Spotlight = require('spotlight'),
	VDRSpotlightSupport = require('spotlight/VDRSpotlightSupport');

var
	Scrollable = require('../Scrollable'),
	ScrollControls = require('../ScrollControls');

module.exports = kind({
	name: 'moon.NewDataList',
	kind: NewDataList,
	scrollControls: [{kind: ScrollControls}],
	touch: false,
	mixins: [Scrollable, VDRSpotlightSupport],
	handlers: {
		onSpotlightUp: 'guard5way',
		onSpotlightRight: 'guard5way',
		onSpotlightDown: 'guard5way',
		onSpotlightLeft: 'guard5way'
	},
	/**
	* Prevent accelerating 5-way focus events from trying
	* to spot elements that don't yet have DOM nodes.
	*
	* @private
	*/
	guard5way: function (sender, event) {
		var e, limit, idx, d2x, row, limitRow, movingInScrollDimension;

		e = event.type;
		movingInScrollDimension =
			(this.direction === 'vertical' && (e === 'onSpotlightUp' || e === 'onSpotlightDown')) ||
			(this.direction === 'horizontal' && (e === 'onSpotlightRight' || e === 'onSpotlightLeft'));

		// If we're not accelerating, or not moving along
		// our scrollable dimension, then we don't need to guard
		if (!Spotlight.Accelerator.isAccelerating() || !movingInScrollDimension) return false;

		// Figure out the index of the last de-virtualized element
		// in the direction we're currently scrolling; anything
		// further out doesn't yet have a DOM node
		limit = (e === 'onSpotlightUp' || e === (this.rtl ? 'onSpotlightRight' : 'onSpotlightLeft')) ?
			this.first :
			this._last;

		// Get the index of the currently focused element
		idx = event.index;

		// In case we're in a grid layout, we need to translate
		// these indices into the corresponding row / column
		d2x = this.dim2extent;
		row = Math.floor(idx / d2x);
		limitRow = Math.floor(limit / d2x);

		// If we're in the last de-virtualized row, the element we
		// would focus from here doesn't yet have a DOM node, so
		// we return true to prevent an attempt to focus. We'll wait
		// for the next accelerated 5-way event and try again...
		return (row === limitRow);
	},
	/**
	* Scrolls to a list item (specified by index).
	*
	* In addition to the standard scrolling options, you can specify
	* `focus: true` if you want the item you're scrolling to to be
	* Spotlight focused. Currently, setting `focus: true` forces the
	* scroll behavior to be `instant`, meaning that the scroller will
	* jump to the item (with no animation).
	*
	* @see module:enyo/NewDataList~NewDataList.scrollToItem
	* @param {number} index - The (zero-based) index of the item to scroll to
	* @param {Object} opts - Scrolling options (see module:enyo/Scrollable~Scrollable.scrollTo)
	* @public
	*/
	scrollToItem: function(index, opts) {
		var item;

		if (opts && opts.focus) {
			opts.behavior = 'instant';
		}

		NewDataList.prototype.scrollToItem.apply(this, arguments);

		if (opts && opts.focus && !Spotlight.getPointerMode()) {
			item = this.childForIndex(index);
			if (item) Spotlight.spot(item);
		}
	},
	/**
	* Called by moonstone/Scrollable.filterFocus()
	* @private
	*/
	eventIsFromScrollingChild: function (event) {
		return (typeof event.index === 'number');
	},
	/**
	* Called by moonstone/Scrollable.filterFocus()
	* @private
	*/
	spotFirstVisibleChild: function() {
		var fv = this.getFullyVisibleItems()[0] || this.getVisibleItems()[0];
		if (fv) {
			Spotlight.spot(fv);
			return true;
		}
	}
});
<|endoftext|>


<commit_before>/**
 * Zero helpers
 */

/* eslint-disable no-console */

// Gulp modules
import gulp from 'gulp';
import clean from 'gulp-clean';
import file from 'gulp-file';
import rename from 'gulp-rename';
import replace from 'gulp-replace';
import sequence from 'gulp-sequence';
import shell from 'gulp-shell';

// Helper modules
import fs from 'fs';
// import semver from 'semver';
import yargs from 'yargs';

// Output commands to be executed via "--dry" flag
const DRY_RUN = !!yargs.argv.dry;

// Cloned output files
const CLONE_DIR = './__cloned__';

const CONFIGS_FILE = './gulp-helpers/zero/configs.json';

function readConfigs(platform) {
  const configs = fs.readFileSync(CONFIGS_FILE);

  const {
    packageName,
    moduleName,
    gitRemoteUrl,
    codepush: {
      release: codepushReleaseKey,
      staging: codepushStagingKey,
    },
    [platform]: platformBased,
  } = JSON.parse(configs);

  if (platform === 'general')
    return {
      packageName,
      moduleName,
      gitRemoteUrl,
    };

  const { applicationId, bundleId, ...rest } = platformBased;

  const appId = applicationId || bundleId;
  const appIdNames = {
    android: 'Android applicationId',
    ios: 'iOS bundleId',
  };

  console.assert(
    appId != null,
    `${appIdNames[platform]} must be valid (current: ${appId})`
  );

  return {
    appId,
    codepushReleaseKey,
    codepushStagingKey,
    moduleName,
    ...rest,
  };
}

function execCommands(...commands) {
  if (DRY_RUN)
    console.log(['Commands to be executed:\n', ...commands, '\n'].join('\n'));
  else
    gulp.src('.').pipe(shell(commands));
}

gulp.task('zero:backup', () => {
  gulp.src(['./package.json', './index.*.js']).pipe(gulp.dest('./bak'));
  gulp.src('./android/**').pipe(gulp.dest('./bak/android'));
  gulp.src('./app/**/*.js').pipe(gulp.dest('./bak/app'));
  gulp.src('./ios/**').pipe(gulp.dest('./bak/ios'));
  gulp.src('./gulp-helpers/codepush/configs.json').pipe(gulp.dest('./bak/gulp-helpers/codepush'));
});

gulp.task('zero:setup:clean', () => (
  gulp.src(CLONE_DIR).pipe(clean())
));

gulp.task('zero:setup:android', () => {
  const {
    appId,
    codepushReleaseKey,
    codepushStagingKey,
    moduleName,
    signingConfigs: {
      storeFile,
      storePassword,
      keyAlias,
      keyPassword,
    },
  } = readConfigs('android');

  // Replace specific files
  gulp.src([
    'android/**/MainActivity.java',
    'android/**/build.gradle',
    'android/settings.gradle',
  ])
    .pipe(replace('ZeroProj', moduleName))
    .pipe(replace('com.zeroproj', appId))
    .pipe(replace('ZEROPROJ_RELEASE_STORE_FILE', storeFile))
    .pipe(replace('ZEROPROJ_RELEASE_STORE_PASSWORD', storePassword))
    .pipe(replace('ZEROPROJ_RELEASE_KEY_ALIAS', keyAlias))
    .pipe(replace('ZEROPROJ_RELEASE_KEY_PASSWORD', keyPassword))
    .pipe(replace('code_push_release_key', codepushReleaseKey))
    .pipe(replace('code_push_staging_key', codepushStagingKey))
    .pipe(gulp.dest(`${CLONE_DIR}/android`));
});

gulp.task('zero:setup:ios', () => {
  const {
    appId,
    codepushReleaseKey,
    codepushStagingKey,
    moduleName,
  } = readConfigs('ios');
  const moduleNameReplacement = ['ZeroProj', moduleName];

  // Replace content for text files
  gulp.src(['./ios/**', '!./ios/**/*.png'])
    .pipe(replace(...moduleNameReplacement))
    .pipe(replace('com.zeroproj', appId))
    .pipe(replace('code_push_release_key', codepushReleaseKey))
    .pipe(replace('code_push_staging_key', codepushStagingKey))
    .pipe(rename(path => {
      path.dirname = path.dirname.replace(...moduleNameReplacement);
      path.basename = path.basename.replace(...moduleNameReplacement);
    }))
    .pipe(gulp.dest(`${CLONE_DIR}/ios`));

  // Copy & rename only for asset files
  gulp.src('./ios/**/*.png')
    .pipe(rename(path => {
      path.dirname = path.dirname.replace(...moduleNameReplacement);
      path.basename = path.basename.replace(...moduleNameReplacement);
    }))
    .pipe(gulp.dest(`${CLONE_DIR}/ios`));
});

gulp.task('zero:setup:js', () => {
  const { moduleName } = readConfigs('general');

  gulp.src('./index.*.js')
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(`${CLONE_DIR}`));

  gulp.src('./app/**/*.js')
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(`${CLONE_DIR}/app`));
});

gulp.task('zero:setup:general', () => {
  const { packageName, moduleName } = readConfigs('general');

  gulp.src('./package.json')
    .pipe(replace('react-native-zero', packageName))
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(CLONE_DIR));

  gulp.src('./gulp-helpers/codepush/configs.json')
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(`${CLONE_DIR}/gulp-helpers/codepush`));

  file('README.md', `# ${moduleName}`, { src: true })
    .pipe(gulp.dest('.'));
});

gulp.task('zero:apply:clean-ios', () => (
  gulp.src('./ios').pipe(clean())
));

gulp.task('zero:apply:clean-clones', () => (
  gulp.src(CLONE_DIR).pipe(clean())
));

gulp.task('zero:apply:platforms', () => (
  gulp.src(`${CLONE_DIR}/**`).pipe(gulp.dest('.'))
));

gulp.task('zero:apply:git', () => {
  const { gitRemoteUrl } = readConfigs('general');

  execCommands(
    'rm -rf .git',
    'git init',
    `git remote add origin ${gitRemoteUrl}`,
    'git config --local --add branch.master.remote origin',
    'git config --local --add branch.master.merge refs/heads/master'
  );
});

gulp.task('zero:setup', sequence(
  'zero:setup:clean',
  'zero:setup:android',
  'zero:setup:ios',
  'zero:setup:js',
  'zero:setup:general'
));

gulp.task('zero:apply', sequence(
  'zero:apply:clean-ios',
  'zero:apply:platforms',
  'zero:apply:clean-clones',
  'zero:apply:git'
));

/* eslint-enable no-console */
<commit_msg>Copy app/assets file without content replaces<commit_after>/**
 * Zero helpers
 */

/* eslint-disable no-console */

// Gulp modules
import gulp from 'gulp';
import clean from 'gulp-clean';
import file from 'gulp-file';
import rename from 'gulp-rename';
import replace from 'gulp-replace';
import sequence from 'gulp-sequence';
import shell from 'gulp-shell';

// Helper modules
import fs from 'fs';
// import semver from 'semver';
import yargs from 'yargs';

// Output commands to be executed via "--dry" flag
const DRY_RUN = !!yargs.argv.dry;

// Cloned output files
const CLONE_DIR = './__cloned__';

const CONFIGS_FILE = './gulp-helpers/zero/configs.json';

function readConfigs(platform) {
  const configs = fs.readFileSync(CONFIGS_FILE);

  const {
    packageName,
    moduleName,
    gitRemoteUrl,
    codepush: {
      release: codepushReleaseKey,
      staging: codepushStagingKey,
    },
    [platform]: platformBased,
  } = JSON.parse(configs);

  if (platform === 'general')
    return {
      packageName,
      moduleName,
      gitRemoteUrl,
    };

  const { applicationId, bundleId, ...rest } = platformBased;

  const appId = applicationId || bundleId;
  const appIdNames = {
    android: 'Android applicationId',
    ios: 'iOS bundleId',
  };

  console.assert(
    appId != null,
    `${appIdNames[platform]} must be valid (current: ${appId})`
  );

  return {
    appId,
    codepushReleaseKey,
    codepushStagingKey,
    moduleName,
    ...rest,
  };
}

function execCommands(...commands) {
  if (DRY_RUN)
    console.log(['Commands to be executed:\n', ...commands, '\n'].join('\n'));
  else
    gulp.src('.').pipe(shell(commands));
}

gulp.task('zero:backup', () => {
  gulp.src(['./package.json', './index.*.js']).pipe(gulp.dest('./bak'));
  gulp.src('./android/**').pipe(gulp.dest('./bak/android'));
  gulp.src('./app/**/*.js').pipe(gulp.dest('./bak/app'));
  gulp.src('./ios/**').pipe(gulp.dest('./bak/ios'));
  gulp.src('./gulp-helpers/codepush/configs.json').pipe(gulp.dest('./bak/gulp-helpers/codepush'));
});

gulp.task('zero:setup:clean', () => (
  gulp.src(CLONE_DIR).pipe(clean())
));

gulp.task('zero:setup:android', () => {
  const {
    appId,
    codepushReleaseKey,
    codepushStagingKey,
    moduleName,
    signingConfigs: {
      storeFile,
      storePassword,
      keyAlias,
      keyPassword,
    },
  } = readConfigs('android');

  // Replace specific files
  gulp.src([
    'android/**/MainActivity.java',
    'android/**/build.gradle',
    'android/settings.gradle',
  ])
    .pipe(replace('ZeroProj', moduleName))
    .pipe(replace('com.zeroproj', appId))
    .pipe(replace('ZEROPROJ_RELEASE_STORE_FILE', storeFile))
    .pipe(replace('ZEROPROJ_RELEASE_STORE_PASSWORD', storePassword))
    .pipe(replace('ZEROPROJ_RELEASE_KEY_ALIAS', keyAlias))
    .pipe(replace('ZEROPROJ_RELEASE_KEY_PASSWORD', keyPassword))
    .pipe(replace('code_push_release_key', codepushReleaseKey))
    .pipe(replace('code_push_staging_key', codepushStagingKey))
    .pipe(gulp.dest(`${CLONE_DIR}/android`));
});

gulp.task('zero:setup:ios', () => {
  const {
    appId,
    codepushReleaseKey,
    codepushStagingKey,
    moduleName,
  } = readConfigs('ios');
  const moduleNameReplacement = ['ZeroProj', moduleName];

  // Replace content for text files
  gulp.src(['./ios/**', '!./ios/**/*.png'])
    .pipe(replace(...moduleNameReplacement))
    .pipe(replace('com.zeroproj', appId))
    .pipe(replace('code_push_release_key', codepushReleaseKey))
    .pipe(replace('code_push_staging_key', codepushStagingKey))
    .pipe(rename(path => {
      path.dirname = path.dirname.replace(...moduleNameReplacement);
      path.basename = path.basename.replace(...moduleNameReplacement);
    }))
    .pipe(gulp.dest(`${CLONE_DIR}/ios`));

  // Copy & rename only for asset files
  gulp.src('./ios/**/*.png')
    .pipe(rename(path => {
      path.dirname = path.dirname.replace(...moduleNameReplacement);
      path.basename = path.basename.replace(...moduleNameReplacement);
    }))
    .pipe(gulp.dest(`${CLONE_DIR}/ios`));
});

gulp.task('zero:setup:js', () => {
  const { moduleName } = readConfigs('general');

  // Replace and copy `index.android.js`, `index.ios.js`
  gulp.src('./index.*.js')
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(`${CLONE_DIR}`));

  // Replace and copy JS files under `app/` dir
  gulp.src('./app/**/*.js')
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(`${CLONE_DIR}/app`));

  // Copy `assets` file without content replaces
  gulp.src('./app/assets/**')
    .pipe(gulp.dest(`${CLONE_DIR}/app/assets`));
});

gulp.task('zero:setup:general', () => {
  const { packageName, moduleName } = readConfigs('general');

  gulp.src('./package.json')
    .pipe(replace('react-native-zero', packageName))
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(CLONE_DIR));

  gulp.src('./gulp-helpers/codepush/configs.json')
    .pipe(replace('ZeroProj', moduleName))
    .pipe(gulp.dest(`${CLONE_DIR}/gulp-helpers/codepush`));

  file('README.md', `# ${moduleName}`, { src: true })
    .pipe(gulp.dest('.'));
});

gulp.task('zero:apply:clean-ios', () => (
  gulp.src('./ios').pipe(clean())
));

gulp.task('zero:apply:clean-clones', () => (
  gulp.src(CLONE_DIR).pipe(clean())
));

gulp.task('zero:apply:platforms', () => (
  gulp.src(`${CLONE_DIR}/**`).pipe(gulp.dest('.'))
));

gulp.task('zero:apply:git', () => {
  const { gitRemoteUrl } = readConfigs('general');

  execCommands(
    'rm -rf .git',
    'git init',
    `git remote add origin ${gitRemoteUrl}`,
    'git config --local --add branch.master.remote origin',
    'git config --local --add branch.master.merge refs/heads/master'
  );
});

gulp.task('zero:setup', sequence(
  'zero:setup:clean',
  'zero:setup:android',
  'zero:setup:ios',
  'zero:setup:js',
  'zero:setup:general'
));

gulp.task('zero:apply', sequence(
  'zero:apply:clean-ios',
  'zero:apply:platforms',
  'zero:apply:clean-clones',
  'zero:apply:git'
));

/* eslint-enable no-console */
<|endoftext|>


<commit_before>import React from 'react';

import { Sharrq } from 'CONTRIBUTORS';
import SPECS from 'common/SPECS';
import Wrapper from 'common/Wrapper';
import Warning from 'common/Alert/Warning';

import CombatLogParser from './CombatLogParser';
import CHANGELOG from './CHANGELOG';

export default {
  // The people that have contributed to this spec recently. People don't have to sign up to be long-time maintainers to be included in this list. If someone built a large part of the spec or contributed something recently to that spec, they can be added to the contributors list.
  contributors: [Sharrq],
  // The WoW client patch this spec was last updated to be fully compatible with.
  patchCompatibility: '7.3.5',
  // Explain the status of this spec's analysis here. Try to mention how complete it is, and perhaps show links to places users can learn more.
  // If this spec's analysis does not show a complete picture please mention this in the `<Warning>` component.
  description: (
    <Wrapper>
      Hello Everyone! We are always looking to improve the Fire Mage Analyzers and Modules; so if you find any issues or if there is something missing that you would like to see added, please open an Issue on GitHub or send a message to Sharrq on Discord (Sharrq#7530).

      <Warning>
        This spec is believed to be complete, but needs additional feedback. If there is something missing, incorrect, or inaccurate, please contact us on Discord.
      </Warning>

	    Additionally, if you need further assistance in improving your gameplay as a Fire Mage, you can refer to the following resources:

      Mage Class Discord

      Altered Time (Mage Forums/Guides)

      Icy Veins (Fire Mage Guide)

    </Wrapper>
  ),
  // A recent example report to see interesting parts of the spec. Will be shown on the homepage.
  // exampleReport: '/report/72t9vbcAqdpVRfBQ/12-Mythic+Garothi+Worldbreaker+-+Kill+(6:15)/Maxweii',

  // Don't change anything below this line;
  // The current spec identifier. This is the only place (in code) that specifies which spec this parser is about.
  spec: SPECS.FIRE_MAGE,
  // The contents of your changelog.
  changelog: CHANGELOG,
  // The CombatLogParser class for your spec.
  parser: CombatLogParser,
  // The path to the current directory (relative form project root). This is used for generating a GitHub link directly to your spec's code.
  path: __dirname,
};
<commit_msg>[Fire Mage] Config Changes<commit_after>import React from 'react';

import { Sharrq } from 'CONTRIBUTORS';
import SPECS from 'common/SPECS';
import Wrapper from 'common/Wrapper';

import CombatLogParser from './CombatLogParser';
import CHANGELOG from './CHANGELOG';

export default {
  // The people that have contributed to this spec recently. People don't have to sign up to be long-time maintainers to be included in this list. If someone built a large part of the spec or contributed something recently to that spec, they can be added to the contributors list.
  contributors: [Sharrq],
  // The WoW client patch this spec was last updated to be fully compatible with.
  patchCompatibility: '7.3.5',
  // Explain the status of this spec's analysis here. Try to mention how complete it is, and perhaps show links to places users can learn more.
  // If this spec's analysis does not show a complete picture please mention this in the `<Warning>` component.
  description: (
    <Wrapper>
      Hello Everyone! We are always looking to improve the Fire Mage Analyzers and Modules; so if you find any issues or if there is something missing that you would like to see added, please open an Issue on GitHub or send a message to Sharrq on Discord (Sharrq#7530).

	    Additionally, if you need further assistance in improving your gameplay as a Fire Mage, you can refer to the following resources:

      Mage Class Discord

      Altered Time (Mage Forums/Guides)

      Icy Veins (Fire Mage Guide)

    </Wrapper>
  ),
  // A recent example report to see interesting parts of the spec. Will be shown on the homepage.
  // exampleReport: '/report/72t9vbcAqdpVRfBQ/12-Mythic+Garothi+Worldbreaker+-+Kill+(6:15)/Maxweii',

  // Don't change anything below this line;
  // The current spec identifier. This is the only place (in code) that specifies which spec this parser is about.
  spec: SPECS.FIRE_MAGE,
  // The contents of your changelog.
  changelog: CHANGELOG,
  // The CombatLogParser class for your spec.
  parser: CombatLogParser,
  // The path to the current directory (relative form project root). This is used for generating a GitHub link directly to your spec's code.
  path: __dirname,
};
<|endoftext|>


<commit_before>/* eslint-disable no-useless-escape */

import React from 'react';
import _ from 'lodash';
import steemembed from 'steemembed';
import sanitizeHtml from 'sanitize-html';
import Remarkable from 'remarkable';

import sanitizeConfig from './../helpers/SanitizeConfig';

const remarkable = new Remarkable({
  html: true, // remarkable renders first then sanitize runs...
  breaks: true,
  linkify: true, // linkify is done locally
  typographer: false, // https://github.com/jonschlinkert/remarkable/issues/142#issuecomment-221546793
  quotes: '“”‘’'
});

function escapeRegExp(str) {
  return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
}

export default (props) => {
  const embeds = steemembed.getAll(props.body);
  let body = props.body;
  let jsonMetadata = {};
  try { jsonMetadata = JSON.parse(props.jsonMetadata); } catch (e) { }
  jsonMetadata.image = jsonMetadata.image || [];

  body = body.replace(/|$)/g, '(html comment removed: $1)');

  const imageRegex = /https?:\/\/(?:[-a-zA-Z0-9._]*[-a-zA-Z0-9])(?::\d{2,5})?(?:[/?#](?:[^\s"'<>\][()]*[^\s"'<>\][().,])?(?:(?:\.(?:tiff?|jpe?g|gif|png|svg|ico)|ipfs\/[a-z\d]{40,})))/ig;

  body.replace(imageRegex, (img) => {
    if (_.filter(jsonMetadata.image, i => i.indexOf(img) !== -1).length === 0) {
      jsonMetadata.image.push(img);
    }
  });

  if (_.has(jsonMetadata, 'users[0]')) {
    body = body.replace(/(^|\s)(@[-.a-z\d]+)/ig, (user) => {
      const space = /^\s/.test(user) ? user[0] : '';
      user = user.trim().substring(1);
      return `${space}<a href="/@${user}">@${user}</a>`;
    });
  }

  if (_.has(embeds, '[0].embed')) {
    embeds.forEach((embed) => { body = body.replace(embed.url, embed.embed); });
  }

  body = remarkable.render(body);

  if (_.has(jsonMetadata, 'image[0]')) {
    jsonMetadata.image.forEach((image) => {
      let newUrl = image;
      if (/^\/\//.test(image)) { newUrl = `https:${image}`; }

      body = body.replace(new RegExp(`<a href="${image}">${image}</a>`, 'g'), `<img src="${newUrl}">`);
      // not in img tag

      if (body.search(`<img[^>]+src="${image}"`) === -1) {
        body = body.replace(new RegExp(image, 'g'), `<img src="${newUrl}">`);
      }
    });
  }

  body.replace(/]+src="([^">]+)"/ig, (img, ...rest) => {
    if (rest.length && rest[0]) {
      const newUrl = `https://img1.steemit.com/0x0/${rest[0]}`;
      body = body.replace(new RegExp(escapeRegExp(rest[0]), 'g'), newUrl);
    }
  });

  body = sanitizeHtml(body, sanitizeConfig({}));

  return
;
};
<commit_msg>Don't proxy already proxified img<commit_after>/* eslint-disable no-useless-escape */

import React from 'react';
import _ from 'lodash';
import steemembed from 'steemembed';
import sanitizeHtml from 'sanitize-html';
import Remarkable from 'remarkable';

import sanitizeConfig from './../helpers/SanitizeConfig';

const remarkable = new Remarkable({
  html: true, // remarkable renders first then sanitize runs...
  breaks: true,
  linkify: true, // linkify is done locally
  typographer: false, // https://github.com/jonschlinkert/remarkable/issues/142#issuecomment-221546793
  quotes: '“”‘’'
});

function escapeRegExp(str) {
  return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
}

export default (props) => {
  const embeds = steemembed.getAll(props.body);
  let body = props.body;
  let jsonMetadata = {};
  try { jsonMetadata = JSON.parse(props.jsonMetadata); } catch (e) { }
  jsonMetadata.image = jsonMetadata.image || [];

  body = body.replace(/|$)/g, '(html comment removed: $1)');

  const imageRegex = /https?:\/\/(?:[-a-zA-Z0-9._]*[-a-zA-Z0-9])(?::\d{2,5})?(?:[/?#](?:[^\s"'<>\][()]*[^\s"'<>\][().,])?(?:(?:\.(?:tiff?|jpe?g|gif|png|svg|ico)|ipfs\/[a-z\d]{40,})))/ig;

  body.replace(imageRegex, (img) => {
    if (_.filter(jsonMetadata.image, i => i.indexOf(img) !== -1).length === 0) {
      jsonMetadata.image.push(img);
    }
  });

  if (_.has(jsonMetadata, 'users[0]')) {
    body = body.replace(/(^|\s)(@[-.a-z\d]+)/ig, (user) => {
      const space = /^\s/.test(user) ? user[0] : '';
      user = user.trim().substring(1);
      return `${space}<a href="/@${user}">@${user}</a>`;
    });
  }

  if (_.has(embeds, '[0].embed')) {
    embeds.forEach((embed) => { body = body.replace(embed.url, embed.embed); });
  }

  body = remarkable.render(body);

  if (_.has(jsonMetadata, 'image[0]')) {
    jsonMetadata.image.forEach((image) => {
      let newUrl = image;
      if (/^\/\//.test(image)) { newUrl = `https:${image}`; }

      body = body.replace(new RegExp(`<a href="${image}">${image}</a>`, 'g'), `<img src="${newUrl}">`);
      // not in img tag

      if (body.search(`<img[^>]+src="${image}"`) === -1) {
        body = body.replace(new RegExp(image, 'g'), `<img src="${newUrl}">`);
      }
    });
  }

  body.replace(/]+src="([^">]+)"/ig, (img, ...rest) => {
    if (rest.length && rest[0] && rest[0].indexOf('https://img1.steemit.com/0x0/') !== 0) {
      const newUrl = `https://img1.steemit.com/0x0/${rest[0]}`;
      body = body.replace(new RegExp(escapeRegExp(rest[0]), 'g'), newUrl);
    }
  });

  body = sanitizeHtml(body, sanitizeConfig({}));

  return
;
};
<|endoftext|>


<commit_before>var parser = require('./parser');
var TileMap = require('./tilemap');
var Direction = require('./direction');
var Interpreter = require('./interpreter');

function Cursor(cursor) {
  this.id = cursor.id;
  this.segment = cursor.segment;
  this.x = cursor.x;
  this.y = cursor.y;
  this.direction = {};
  this.direction.x = cursor.direction.x;
  this.direction.y = cursor.direction.y;
  this.selected = cursor.selected;
  this.memory = cursor.memory.slice(); // Copy machine state.
  this.seek = cursor.seek || false;
  this.merge = true;
  this.visit = 0;
}

// Returns initial machine cursor
Cursor.init = function() {
  var initialMemory = [];
  for(var i = 0; i < 28; ++i) initialMemory.push(0);
  return new Cursor({
    id: 0,
    segment: 0,
    x: 0,
    y: 0,
    direction: {
      x: 0,
      y: 1
    },
    selected: 0,
    memory: initialMemory
  });
}

// Calculates memory diff
Cursor.prototype.diff = function(other) {
  return this.memory.map(function(value, key) {
    return value - other.memory[key];
  });
}

// Predicts the path of the code

function Predictor(code) {
  if (typeof code == 'string') {
    this.map = parser.parse(code);
  } else {
    this.map = code;
  }
  // Create segment heading map
  this.reset();
  this.updated = [];
}

Predictor.prototype.reset = function() {
  this.segments = [];
  this.mergeCandidates = [];
  this.stack = [];
  this.headingMap = new TileMap(this.map.width, this.map.height);
  var cursor = Cursor.init();
  var segment = [];
  segment.push(cursor);
  this.segments.push(segment);
  this.stack.push(cursor);
}

Predictor.prototype.postCheck = function() {
  // Merge candidates if possible
  while(this.mergeCandidates.length) {
    var candidate = this.mergeCandidates.shift();
    // Continue if cannot merge
    if(!candidate.merge) continue;
    var segment = this.segments[candidate.segment];
    while(candidate.otherwiseSet.length) {
      var target = candidate.otherwiseSet.shift();
      var targetSeg = this.segments[target.segment];
      // Set 'previous' direction
      var direction = candidate.direction;
      var preDir = Direction.convertToBits(-direction.x, -direction.y);
      // Process only if candidate's segment is lower
      if(candidate.segment >= target.segment) continue;
      // We have to process target...
      if(targetSeg.length == 0) {
        targetSeg.push(target);
      }
      // Pop segment
      var cursor;
      while(targetSeg.length) {
        cursor = targetSeg.shift();
        // Reset segment and id
        cursor.segment = candidate.segment;
        cursor.id = segment.length;
        segment.push(cursor);
        // Go back, and redraw
        if(cursor.before) {
          Direction.process({
            x: cursor.before.x,
            y: cursor.before.y
            }, this.map, cursor.direction, preDir, this.updated,
            cursor.segment);
        }
        // Set 'previous' direction
        direction = cursor.direction;
        preDir = Direction.convertToBits(-direction.x, -direction.y);
      }
    }
    if(cursor && cursor.then) {
      Direction.process({
        x: cursor.x,
        y: cursor.y
        }, this.map, cursor.then.direction, preDir, this.updated,
        cursor.segment);
    }
    // Mark it as cannot merge as it has already processed
    candidate.merge = false;
  }
}

Predictor.prototype.next = function() {
  if (this.stack.length === 0) return false;
  // Store previous cursor.. I doubt it'll be used actually.
  var oldCursor = this.stack.pop();
  var cursor = new Cursor(oldCursor);
  cursor.before = oldCursor;
  if(!cursor.seek) oldCursor.then = cursor;
  // Fetch current segment
  var segment = this.segments[cursor.segment];
  var direction = cursor.direction;
  // Store previous reversed direction
  var preDir = Direction.convertToBits(-direction.x, -direction.y);
  var tile = this.map.get(cursor.x, cursor.y);
  var headingTile = this.headingMap.get(cursor.x, cursor.y);
  // Create headingTile if not exists.
  if (headingTile == null) {
    headingTile = {};
    this.headingMap.set(cursor.x, cursor.y, headingTile);
  }
  // Continues execution in new segment if this is set.
  var newSegment = false;
  // Stop execution if this is set.
  var stop = false;
  if (tile != null) {
    // Fetch x, y value from tile's direction
    var tileDir = Direction.map[tile.direction];
    // Calculate the direction where the cursor will go
    direction.x = Direction.calculate(direction.x, tileDir.x);
    direction.y = Direction.calculate(direction.y, tileDir.y);
    // Fetch command
    var command = Interpreter.CommandMap[tile.command];
    // Just skip if command is null
    if(command != null) {
      if(cursor.memory[cursor.selected] >= command.data) {
        cursor.memory[cursor.selected] -= command.data; // Data we lose
        cursor.memory[cursor.selected] += command.output; // Data we get
        if (tile.command == 'select') {
          cursor.selected = tile.data;
        }
        if (tile.command == 'move') {
          cursor.memory[tile.data] ++;
        }
        if (tile.command == 'end') {
          // End of segment; Stop processing.
          // Techincally 'end' operator requires one data to stop,
          // But most programs won't work with that.
          stop = true;
        }
        if (tile.command == 'condition') {
          // Condition; Always create new segment.
          // Simply create new cursor with new segment, flip direction,
          // move position and save it.
          var newCursor = new Cursor(cursor);
          newCursor.direction.x = -direction.x;
          newCursor.direction.y = -direction.y;
          oldCursor.otherwise = newCursor;
          this.processCursor(newCursor, segment, tile, headingTile,
            stop, true, preDir);
        }
        // It can't be mergeable since original path has not stopped
        oldCursor.merge = false;
      } else {
        // Underflow has occurred; Go to opposite direction.
        direction.x = -direction.x;
        direction.y = -direction.y;
        // For consistency, this should create a new segment;
        // But it can probably be merged.
        newSegment = true;
        // Saving this for good measure
        if(!oldCursor.seek) {
          if(!oldCursor.otherwiseSet) {
            oldCursor.otherwiseSet = [];
            this.mergeCandidates.push(oldCursor);
          }
          oldCursor.otherwiseSet.push(cursor);
        }
      }
    }
  }
  this.processCursor(cursor, segment, tile, headingTile,
    stop, newSegment, preDir);
  return this.stack.length > 0;
};

Predictor.prototype.processCursor = function(cursor, segment, tile, headingTile,
  stop, newSegment, preDir) {
  // Don't save current cursor and increment it if this is set.
  var seek = false;
  var direction = cursor.direction;
  var directionBits = Direction.convertToBits(direction.x, direction.y, true);
  var before;
  if (headingTile[directionBits]) {
    before = headingTile[directionBits];
    before.visit ++;
    // Continue cursor in seek mode if memory has less data than before.
    var hasLess = !cursor.memory.every(function(value, key) {
      var diff = before.memory[key] - value;
      // This has been disabled for precision.
      /*// Maximum memory space
      if(diff <= 0 && value >= 8) cursor.memory[key] = 8;
      // Check 16 times, then just check if it has less data.
      if(before.visit > 16) return diff <= 0;*/
      return diff <= 0;
    });
    before.memory = cursor.memory.slice();
    seek = hasLess;
    if(!hasLess) stop = true;
  }
  // 'newSegment' should set their ID before drawing path.
  if(before && newSegment) {
    cursor.id = before.id;
    cursor.segment = before.segment;
  }
  if (!stop) {
    if(!seek) {
      if (newSegment) {
        cursor.id = -1;
        cursor.segment = this.segments.length;
        segment = [];
        this.segments.push(segment);
      }
      // Increment cursor id to avoid confliction
      cursor.id ++;
      // Insert segment into segment.
      segment.push(cursor);
      // Write current cursor;
      headingTile[directionBits] = cursor;
    }
    // Push current cursor to stack.
    this.stack.push(cursor);
  }
  // Since this is the copy of original object, we can safely modify it.
  // This communicates with the 'old' data protocol, for now.
  Direction.process(cursor, this.map, direction, preDir, this.updated,
    cursor.segment, false);
  // Copy segment and ID to honor condition
  // But 'merging' cursor shouldn't.
  // It may cause conflicts because it doesn't add itself to segments,
  // But it's prevented because it's not added to segment if seek is true
  if(before && seek) {
    cursor.id = before.id;
    cursor.segment = before.segment;
  }
  cursor.seek = seek;
}

// Assembly command map to support ashembly
var AssemblyMap = {
  'end': 'halt',
  'add': 'add',
  'multiply': 'mul',
  'subtract': 'sub',
  'divide': 'div',
  'mod': 'mod',
  'pop': 'pop',
  'pop-number': 'popnum',
  'pop-unicode': 'popchar',
  'push': 'push',
  'push-number': 'pushnum',
  'push-unicode': 'pushchar',
  'copy': 'dup',
  'flip': 'swap',
  'select': 'sel',
  'move': 'mov',
  'compare': 'cmp',
  'condition': 'brz'
};

// Converts code to Assembly. Just for fun! :D
Predictor.prototype.assembly = function() {
  var resolves = [];
  var labels = [];
  var codes = [];
  // Start reading code from segment 0, id 0
  for(var segmentId = 0; segmentId < this.segments.length; ++segmentId) {
    var segment = this.segments[segmentId];
    for(var id = 0; id < segment.length; ++id) {
      var cursor = segment[id];
      cursor.index = codes.length;
      var headingTile = this.headingMap.get(cursor.x, cursor.y);
      var tile = this.map.get(cursor.x, cursor.y);
      if(tile == null) continue;
      if(tile.command != 'none') {
        var command = Interpreter.CommandMap[tile.command];
        var flipBit = Direction.convertToBits(-cursor.direction.x,
          -cursor.direction.y, true);
        if(headingTile[flipBit]) {
          if(command.data > 0) {
            var code = ['brpop'+command.data, headingTile[flipBit]];
            codes.push(code);
            resolves.push(code);
          }
        }
        var code = [AssemblyMap[tile.command]];
        if(tile.command == 'push') code[1] = tile.data;
        if(tile.command == 'select') code[1] = tile.data;
        if(tile.command == 'move') code[1] = tile.data;
        if(tile.command == 'condition') {
          code[1] = cursor.otherwise;
          resolves.push(code);
        }
        codes.push(code);
      } else {
        if(id == segment.length - 1) {
          // Fetch x, y value from tile's direction
          var tileDir = Direction.map[tile.direction];
          // Calculate the direction where the cursor will go
          var dirX = Direction.calculate(cursor.direction.x, tileDir.x);
          var dirY = Direction.calculate(cursor.direction.y, tileDir.y);
          var dirBit = Direction.convertToBits(dirX, dirY, true);
          var targetTile = headingTile[dirBit];
          if(!targetTile) continue;
          var code = ['jmp', targetTile];
          codes.push(code);
          resolves.push(code);
        }
      }
    }
  }
  for(var i = 0; i < resolves.length; ++i) {
    var idx = resolves[i][1].index;
    if(labels.indexOf(idx) == -1) labels.push(idx);
    resolves[i][1] = 'p'+labels.indexOf(idx);
  }
  var returned = [];
  codes.forEach(function(v, k) {
    var label = labels.indexOf(k);
    if(label != -1) {
      returned.push(":p"+label);
    }
    returned.push(v.join(' '));
  });
  console.log(returned.join("\n"));
}

module.exports = Predictor;
<commit_msg>Revert "Remove force limit routine"<commit_after>var parser = require('./parser');
var TileMap = require('./tilemap');
var Direction = require('./direction');
var Interpreter = require('./interpreter');

function Cursor(cursor) {
  this.id = cursor.id;
  this.segment = cursor.segment;
  this.x = cursor.x;
  this.y = cursor.y;
  this.direction = {};
  this.direction.x = cursor.direction.x;
  this.direction.y = cursor.direction.y;
  this.selected = cursor.selected;
  this.memory = cursor.memory.slice(); // Copy machine state.
  this.seek = cursor.seek || false;
  this.merge = true;
  this.visit = 0;
}

// Returns initial machine cursor
Cursor.init = function() {
  var initialMemory = [];
  for(var i = 0; i < 28; ++i) initialMemory.push(0);
  return new Cursor({
    id: 0,
    segment: 0,
    x: 0,
    y: 0,
    direction: {
      x: 0,
      y: 1
    },
    selected: 0,
    memory: initialMemory
  });
}

// Calculates memory diff
Cursor.prototype.diff = function(other) {
  return this.memory.map(function(value, key) {
    return value - other.memory[key];
  });
}

// Predicts the path of the code

function Predictor(code) {
  if (typeof code == 'string') {
    this.map = parser.parse(code);
  } else {
    this.map = code;
  }
  // Create segment heading map
  this.reset();
  this.updated = [];
}

Predictor.prototype.reset = function() {
  this.segments = [];
  this.mergeCandidates = [];
  this.stack = [];
  this.headingMap = new TileMap(this.map.width, this.map.height);
  var cursor = Cursor.init();
  var segment = [];
  segment.push(cursor);
  this.segments.push(segment);
  this.stack.push(cursor);
}

Predictor.prototype.postCheck = function() {
  // Merge candidates if possible
  while(this.mergeCandidates.length) {
    var candidate = this.mergeCandidates.shift();
    // Continue if cannot merge
    if(!candidate.merge) continue;
    var segment = this.segments[candidate.segment];
    while(candidate.otherwiseSet.length) {
      var target = candidate.otherwiseSet.shift();
      var targetSeg = this.segments[target.segment];
      // Set 'previous' direction
      var direction = candidate.direction;
      var preDir = Direction.convertToBits(-direction.x, -direction.y);
      // Process only if candidate's segment is lower
      if(candidate.segment >= target.segment) continue;
      // We have to process target...
      if(targetSeg.length == 0) {
        targetSeg.push(target);
      }
      // Pop segment
      var cursor;
      while(targetSeg.length) {
        cursor = targetSeg.shift();
        // Reset segment and id
        cursor.segment = candidate.segment;
        cursor.id = segment.length;
        segment.push(cursor);
        // Go back, and redraw
        if(cursor.before) {
          Direction.process({
            x: cursor.before.x,
            y: cursor.before.y
            }, this.map, cursor.direction, preDir, this.updated,
            cursor.segment);
        }
        // Set 'previous' direction
        direction = cursor.direction;
        preDir = Direction.convertToBits(-direction.x, -direction.y);
      }
    }
    if(cursor && cursor.then) {
      Direction.process({
        x: cursor.x,
        y: cursor.y
        }, this.map, cursor.then.direction, preDir, this.updated,
        cursor.segment);
    }
    // Mark it as cannot merge as it has already processed
    candidate.merge = false;
  }
}

Predictor.prototype.next = function() {
  if (this.stack.length === 0) return false;
  // Store previous cursor.. I doubt it'll be used actually.
  var oldCursor = this.stack.pop();
  var cursor = new Cursor(oldCursor);
  cursor.before = oldCursor;
  if(!cursor.seek) oldCursor.then = cursor;
  // Fetch current segment
  var segment = this.segments[cursor.segment];
  var direction = cursor.direction;
  // Store previous reversed direction
  var preDir = Direction.convertToBits(-direction.x, -direction.y);
  var tile = this.map.get(cursor.x, cursor.y);
  var headingTile = this.headingMap.get(cursor.x, cursor.y);
  // Create headingTile if not exists.
  if (headingTile == null) {
    headingTile = {};
    this.headingMap.set(cursor.x, cursor.y, headingTile);
  }
  // Continues execution in new segment if this is set.
  var newSegment = false;
  // Stop execution if this is set.
  var stop = false;
  if (tile != null) {
    // Fetch x, y value from tile's direction
    var tileDir = Direction.map[tile.direction];
    // Calculate the direction where the cursor will go
    direction.x = Direction.calculate(direction.x, tileDir.x);
    direction.y = Direction.calculate(direction.y, tileDir.y);
    // Fetch command
    var command = Interpreter.CommandMap[tile.command];
    // Just skip if command is null
    if(command != null) {
      if(cursor.memory[cursor.selected] >= command.data) {
        cursor.memory[cursor.selected] -= command.data; // Data we lose
        cursor.memory[cursor.selected] += command.output; // Data we get
        if (tile.command == 'select') {
          cursor.selected = tile.data;
        }
        if (tile.command == 'move') {
          cursor.memory[tile.data] ++;
        }
        if (tile.command == 'end') {
          // End of segment; Stop processing.
          // Techincally 'end' operator requires one data to stop,
          // But most programs won't work with that.
          stop = true;
        }
        if (tile.command == 'condition') {
          // Condition; Always create new segment.
          // Simply create new cursor with new segment, flip direction,
          // move position and save it.
          var newCursor = new Cursor(cursor);
          newCursor.direction.x = -direction.x;
          newCursor.direction.y = -direction.y;
          oldCursor.otherwise = newCursor;
          this.processCursor(newCursor, segment, tile, headingTile,
            stop, true, preDir);
        }
        // It can't be mergeable since original path has not stopped
        oldCursor.merge = false;
      } else {
        // Underflow has occurred; Go to opposite direction.
        direction.x = -direction.x;
        direction.y = -direction.y;
        // For consistency, this should create a new segment;
        // But it can probably be merged.
        newSegment = true;
        // Saving this for good measure
        if(!oldCursor.seek) {
          if(!oldCursor.otherwiseSet) {
            oldCursor.otherwiseSet = [];
            this.mergeCandidates.push(oldCursor);
          }
          oldCursor.otherwiseSet.push(cursor);
        }
      }
    }
  }
  this.processCursor(cursor, segment, tile, headingTile,
    stop, newSegment, preDir);
  return this.stack.length > 0;
};

Predictor.prototype.processCursor = function(cursor, segment, tile, headingTile,
  stop, newSegment, preDir) {
  // Don't save current cursor and increment it if this is set.
  var seek = false;
  var direction = cursor.direction;
  var directionBits = Direction.convertToBits(direction.x, direction.y, true);
  var before;
  if (headingTile[directionBits]) {
    before = headingTile[directionBits];
    before.visit ++;
    // Continue cursor in seek mode if memory has less data than before.
    var hasLess = !cursor.memory.every(function(value, key) {
      var diff = before.memory[key] - value;
      // Maximum memory space
      if(diff <= 0 && value >= 8) cursor.memory[key] = 8;
      // Check 16 times, then just check if it has less data.
      if(before.visit > 16) return diff <= 0;
      else return diff == 0;
    });
    before.memory = cursor.memory.slice();
    seek = hasLess;
    if(!hasLess) stop = true;
  }
  // 'newSegment' should set their ID before drawing path.
  if(before && newSegment) {
    cursor.id = before.id;
    cursor.segment = before.segment;
  }
  if (!stop) {
    if(!seek) {
      if (newSegment) {
        cursor.id = -1;
        cursor.segment = this.segments.length;
        segment = [];
        this.segments.push(segment);
      }
      // Increment cursor id to avoid confliction
      cursor.id ++;
      // Insert segment into segment.
      segment.push(cursor);
      // Write current cursor;
      headingTile[directionBits] = cursor;
    }
    // Push current cursor to stack.
    this.stack.push(cursor);
  }
  // Since this is the copy of original object, we can safely modify it.
  // This communicates with the 'old' data protocol, for now.
  Direction.process(cursor, this.map, direction, preDir, this.updated,
    cursor.segment, false);
  // Copy segment and ID to honor condition
  // But 'merging' cursor shouldn't.
  // It may cause conflicts because it doesn't add itself to segments,
  // But it's prevented because it's not added to segment if seek is true
  if(before && seek) {
    cursor.id = before.id;
    cursor.segment = before.segment;
  }
  cursor.seek = seek;
}

// Assembly command map to support ashembly
var AssemblyMap = {
  'end': 'halt',
  'add': 'add',
  'multiply': 'mul',
  'subtract': 'sub',
  'divide': 'div',
  'mod': 'mod',
  'pop': 'pop',
  'pop-number': 'popnum',
  'pop-unicode': 'popchar',
  'push': 'push',
  'push-number': 'pushnum',
  'push-unicode': 'pushchar',
  'copy': 'dup',
  'flip': 'swap',
  'select': 'sel',
  'move': 'mov',
  'compare': 'cmp',
  'condition': 'brz'
};

// Converts code to Assembly. Just for fun! :D
Predictor.prototype.assembly = function() {
  var resolves = [];
  var labels = [];
  var codes = [];
  // Start reading code from segment 0, id 0
  for(var segmentId = 0; segmentId < this.segments.length; ++segmentId) {
    var segment = this.segments[segmentId];
    for(var id = 0; id < segment.length; ++id) {
      var cursor = segment[id];
      cursor.index = codes.length;
      var headingTile = this.headingMap.get(cursor.x, cursor.y);
      var tile = this.map.get(cursor.x, cursor.y);
      if(tile == null) continue;
      if(tile.command != 'none') {
        var command = Interpreter.CommandMap[tile.command];
        var flipBit = Direction.convertToBits(-cursor.direction.x,
          -cursor.direction.y, true);
        if(headingTile[flipBit]) {
          if(command.data > 0) {
            var code = ['brpop'+command.data, headingTile[flipBit]];
            codes.push(code);
            resolves.push(code);
          }
        }
        var code = [AssemblyMap[tile.command]];
        if(tile.command == 'push') code[1] = tile.data;
        if(tile.command == 'select') code[1] = tile.data;
        if(tile.command == 'move') code[1] = tile.data;
        if(tile.command == 'condition') {
          code[1] = cursor.otherwise;
          resolves.push(code);
        }
        codes.push(code);
      } else {
        if(id == segment.length - 1) {
          // Fetch x, y value from tile's direction
          var tileDir = Direction.map[tile.direction];
          // Calculate the direction where the cursor will go
          var dirX = Direction.calculate(cursor.direction.x, tileDir.x);
          var dirY = Direction.calculate(cursor.direction.y, tileDir.y);
          var dirBit = Direction.convertToBits(dirX, dirY, true);
          var targetTile = headingTile[dirBit];
          if(!targetTile) continue;
          var code = ['jmp', targetTile];
          codes.push(code);
          resolves.push(code);
        }
      }
    }
  }
  for(var i = 0; i < resolves.length; ++i) {
    var idx = resolves[i][1].index;
    if(labels.indexOf(idx) == -1) labels.push(idx);
    resolves[i][1] = 'p'+labels.indexOf(idx);
  }
  var returned = [];
  codes.forEach(function(v, k) {
    var label = labels.indexOf(k);
    if(label != -1) {
      returned.push(":p"+label);
    }
    returned.push(v.join(' '));
  });
  console.log(returned.join("\n"));
}

module.exports = Predictor;
<|endoftext|>


<commit_before>/**
 * @module Lyria
 */
define('lyria/preloader', ['root', 'mixer', 'jquery', 'lyria/resource', 'lyria/log', 'eventmap'], function(root, mixer, $, Resource, Log, EventMap) {'use strict';

  /**
   * Provides a preloader to load assets before they are needed
   *
   * @class Preloader
   */
  var Preloader = (function() {

    /**
     * @constructor
     *
     * @param {Object} assetArray
     */
    var Preloader = function(assetArray) {
      mixer(Preloader.prototype, new EventMap());

      /**
       * @property assets
       * @type {Array}
       */
      if (assetArray != null) {
        this.assets = assetArray;
      } else {
        this.assets = [];
      }

      /**
       * @property maxAssets
       * @type {Number}
       * @default 0
       */
      this.maxAssets = 0;

      /**
       * @property assetsLoaded
       * @type {Number}
       * @default 0
       */
      this.assetsLoaded = 0;

      /**
       * @property percentLoaded
       * @type {Number}
       * @default 0
       */
      this.percentLoaded = 0;

      /**
       * @property steps
       * @type {Array}
       */
      this.steps = [];
    };

    /**
     * Starts the preloader and loads all assets asynchronously. Triggers
     * events when necessary.
     *
     * @method start
     */
    Preloader.prototype.start = function() {
      // Check if it's valid
      if (this.assets == null || Object.keys(this.assets).length === 0) {
        return;
      }

      this.trigger('start');

      var totalSize = this.assets.totalSize;
      var currentProgress = 0;

      if ((this.steps == null) || (this.steps.length === 0)) {

      }

      var hasLoadingScene = this.sceneDirector != null && this.loadingScene != null;

      if (hasLoadingScene) {
        this.sceneDirector.show(this.loadingScene);
      }

      var self = this;

      function loadingProgress() {

        var percentLoaded = currentProgress / totalSize;

        self.trigger('progresschange', percentLoaded);

        if (hasLoadingScene) {
          self.sceneDirector.currentScene.trigger('progresschange', percentLoaded);
        }

        if (currentProgress >= totalSize) {
          if (hasLoadingScene) {
            self.sceneDirector.currentScene.trigger('complete');
          }

          self.trigger('complete');
        }
      }

      $.each(this.assets, function(key, value) {

        if (value.files == null || !Array.isArray(value.files) || value.files.length === 0) {
          return false;
        }

        for (var i = 0, j = value.files.length; i < j; i++) {
          (function(iterator) {

            if (iterator.name.indexOf('/' + Resource.path.image + '/') >= 0) {
              var img = new root.Image();
              img.onload = function() {
                currentProgress += iterator.size;

                loadingProgress();
              };

              img.onerror = function(err) {
                Log.e('Error while loading ' + iterator.name);
              };

              img.src = iterator.name;
            } else {
              $.ajax({
                url: iterator.name,
                dataType: 'text'
              }).always(function() {
                currentProgress += iterator.size;

                loadingProgress();
              }).error(function(err) {
                Log.e('Error while loading ' + iterator.name + ': ' + err);
              });
            }

          })(value.files[i]);
        }

      });
    };

    return Preloader;

  })();

  return Preloader;
});<commit_msg>Updated progress call<commit_after>/**
 * @module Lyria
 */
define('lyria/preloader', ['root', 'mixer', 'jquery', 'lyria/resource', 'lyria/log', 'eventmap'], function(root, mixer, $, Resource, Log, EventMap) {'use strict';

  /**
   * Provides a preloader to load assets before they are needed
   *
   * @class Preloader
   */
  var Preloader = (function() {

    /**
     * @constructor
     *
     * @param {Object} assetArray
     */
    var Preloader = function(assetArray) {
      mixer(Preloader.prototype, new EventMap());

      /**
       * @property assets
       * @type {Array}
       */
      if (assetArray != null) {
        this.assets = assetArray;
      } else {
        this.assets = [];
      }

      /**
       * @property maxAssets
       * @type {Number}
       * @default 0
       */
      this.maxAssets = 0;

      /**
       * @property assetsLoaded
       * @type {Number}
       * @default 0
       */
      this.assetsLoaded = 0;

      /**
       * @property percentLoaded
       * @type {Number}
       * @default 0
       */
      this.percentLoaded = 0;

      /**
       * @property steps
       * @type {Array}
       */
      this.steps = [];
    };

    /**
     * Starts the preloader and loads all assets asynchronously. Triggers
     * events when necessary.
     *
     * @method start
     */
    Preloader.prototype.start = function() {
      // Check if it's valid
      if (this.assets == null || Object.keys(this.assets).length === 0) {
        return;
      }

      this.trigger('start');

      var totalSize = this.assets.totalSize;
      var currentProgress = 0;

      if ((this.steps == null) || (this.steps.length === 0)) {

      }

      var hasLoadingScene = this.sceneDirector != null && this.loadingScene != null;

      if (hasLoadingScene) {
        this.sceneDirector.show(this.loadingScene);
      }

      var self = this;

      function loadingProgress() {

        var percentLoaded = currentProgress / totalSize;

        self.trigger('progress', percentLoaded);

        if (hasLoadingScene) {
          self.sceneDirector.currentScene.trigger('progress', percentLoaded, currentProgress, totalSize);
        }

        if (currentProgress >= totalSize) {
          if (hasLoadingScene) {
            self.sceneDirector.currentScene.trigger('complete');
          }

          self.trigger('complete');
        }
      }

      $.each(this.assets, function(key, value) {

        if (value.files == null || !Array.isArray(value.files) || value.files.length === 0) {
          return false;
        }

        for (var i = 0, j = value.files.length; i < j; i++) {
          (function(iterator) {

            if (iterator.name.indexOf('/' + Resource.path.image + '/') >= 0) {
              var img = new root.Image();
              img.onload = function() {
                currentProgress += iterator.size;

                loadingProgress();
              };

              img.onerror = function(err) {
                Log.e('Error while loading ' + iterator.name);
              };

              img.src = iterator.name;
            } else {
              $.ajax({
                url: iterator.name,
                dataType: 'text'
              }).always(function() {
                currentProgress += iterator.size;

                loadingProgress();
              }).error(function(err) {
                Log.e('Error while loading ' + iterator.name + ': ' + err);
              });
            }

          })(value.files[i]);
        }

      });
    };

    return Preloader;

  })();

  return Preloader;
});<|endoftext|>


<commit_before>/*\
title: $:/plugins/dullroar/atomfeed/dombuilder.js
type: application/javascript
module-type: library

Micro DSL for DOM creation and stringification.

\*/

/**
 * @module Atomfeed
 * @author Devin Weaver
 */
/*jshint node: true, browser: true */
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory();
  } else {
    root.DomBuilder = factory();
  }
})(this, function() {
  /**
   * Helper utility to construct complex DOM nodes easily.
   *
   * @class DomBuilder
   * @constructor
   * @param {DomBuilder|DOMElement|String} [root=div] A DOM element or string.
   * If `root` is a DomBuilder it will become `root` instead
   * @param {DOMDocument} [document=window.document] the document object used
   * to create elements
   * @public
   */
  function DomBuilder(root, document) {
    if (root instanceof DomBuilder) {
      return root;
    }
    if (!(this instanceof DomBuilder)) {
      return new DomBuilder(root, document);
    }
    this.document   = document || window.document;
    this.tag        = root || 'div';
    this.elements   = [];
    this.attributes = {};
    this.namespace  = null;
    this.parent     = null;
  }

  DomBuilder.prototype._addElement = function(element) {
    var el = new DomBuilder(element, this.document);
    el.parent = this;
    this.elements.push(el);
    return el;
  };

  /**
   * @method add
   * @param {DomBuilder|DOMElement|String} element the element to add to this
   * DomBuilders elements list
   * @return {DomBuilder} the new child element (DomBuilder) unless `element`
   * is a DomBuilder in which case `this` is returned
   * @chainable
   * @public
   */
  DomBuilder.prototype.add = function add(element) {
    var el = this._addElement(element);
    return (element instanceof DomBuilder) ? this : el;
  };

  /**
   * @method text
   * @param {String} the text to append
   * @chainable
   * @public
   */
  DomBuilder.prototype.text = function text(content) {
    var node = this.document.createTextNode($tw.utils.htmlEncode(content));
    this._addElement(node);
    return this;
  };

  /**
   * @method attr
   * @param {String} name the attribute name
   * @param {String} value the attribute value
   * @chainable
   * @public
   */
  DomBuilder.prototype.attr = function attr(name, value) {
    this.attributes[name] = $tw.utils.htmlEncode(value);
    return this;
  };

  /**
   * @method end
   * @return {DomBuilder} the parent DomBuilder in the hierarchy
   * @chainable
   * @public
   */
  DomBuilder.prototype.end = function end() {
    return this.parent || this;
  };

  /**
   * @method toDOM
   * @param {DOMDocument} [document=this.document] the document object to
   * propagate down the recursion chain
   * @return {DOMElement} the compiled DOMElement with its child hierarchy
   * @public
   */
  DomBuilder.prototype.toDOM = function toDOM(document) {
    var node, name;
    document = document || this.document;
    if (typeof this.tag === 'string') {
      node = (this.namespace) ?
        document.createElementNS(this.namespace, this.tag) :
        document.createElement(this.tag);
    } else {
      node = this.tag;
    }
    for (name in this.attributes) {
      node.setAttribute(name, this.attributes[name]);
    }
    this.elements.forEach(function(element) {
      node.appendChild(element.toDOM(document));
    });
    return node;
  };

  /**
   * @method toString
   * @return {String} the HTML for this DomBuilder's hierarchy
   * @public
   */
  DomBuilder.prototype.toString = function toString() {
    return this.toDOM().outerHTML;
  };

  /**
   * The tag (or DOMElement) for this node.
   * @property tag
   * @type {String|DOMElement}
   * @default div
   * @private
   */

  /**
   * List of child elements for this DomBuilders hierarchy level.
   * @property elements
   * @type {Array}
   * @private
   */

  /**
   * List of attributes to apply to this DOMElement.
   * @property attributes
   * @type {Object}
   * @private
   */

  /**
   * The namespace for this DOMElement.
   * @property namespace
   * @type {String}
   * @default null
   * @private
   */

  /**
   * The parent DomBuilder in the hierarchy.
   * @property parent
   * @type {DomBuilder}
   * @default null
   * @private
   */

  return DomBuilder;
});
<commit_msg>Fix double escaping text<commit_after>/*\
title: $:/plugins/dullroar/atomfeed/dombuilder.js
type: application/javascript
module-type: library

Micro DSL for DOM creation and stringification.

\*/

/**
 * @module Atomfeed
 * @author Devin Weaver
 */
/*jshint node: true, browser: true */
(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory();
  } else {
    root.DomBuilder = factory();
  }
})(this, function() {
  /**
   * Helper utility to construct complex DOM nodes easily.
   *
   * @class DomBuilder
   * @constructor
   * @param {DomBuilder|DOMElement|String} [root=div] A DOM element or string.
   * If `root` is a DomBuilder it will become `root` instead
   * @param {DOMDocument} [document=window.document] the document object used
   * to create elements
   * @public
   */
  function DomBuilder(root, document) {
    if (root instanceof DomBuilder) {
      return root;
    }
    if (!(this instanceof DomBuilder)) {
      return new DomBuilder(root, document);
    }
    this.document   = document || window.document;
    this.tag        = root || 'div';
    this.elements   = [];
    this.attributes = {};
    this.namespace  = null;
    this.parent     = null;
  }

  DomBuilder.prototype._addElement = function(element) {
    var el = new DomBuilder(element, this.document);
    el.parent = this;
    this.elements.push(el);
    return el;
  };

  /**
   * @method add
   * @param {DomBuilder|DOMElement|String} element the element to add to this
   * DomBuilders elements list
   * @return {DomBuilder} the new child element (DomBuilder) unless `element`
   * is a DomBuilder in which case `this` is returned
   * @chainable
   * @public
   */
  DomBuilder.prototype.add = function add(element) {
    var el = this._addElement(element);
    return (element instanceof DomBuilder) ? this : el;
  };

  /**
   * @method text
   * @param {String} the text to append
   * @chainable
   * @public
   */
  DomBuilder.prototype.text = function text(content) {
    var node = this.document.createTextNode(content);
    this._addElement(node);
    return this;
  };

  /**
   * @method attr
   * @param {String} name the attribute name
   * @param {String} value the attribute value
   * @chainable
   * @public
   */
  DomBuilder.prototype.attr = function attr(name, value) {
    this.attributes[name] = $tw.utils.htmlEncode(value);
    return this;
  };

  /**
   * @method end
   * @return {DomBuilder} the parent DomBuilder in the hierarchy
   * @chainable
   * @public
   */
  DomBuilder.prototype.end = function end() {
    return this.parent || this;
  };

  /**
   * @method toDOM
   * @param {DOMDocument} [document=this.document] the document object to
   * propagate down the recursion chain
   * @return {DOMElement} the compiled DOMElement with its child hierarchy
   * @public
   */
  DomBuilder.prototype.toDOM = function toDOM(document) {
    var node, name;
    document = document || this.document;
    if (typeof this.tag === 'string') {
      node = (this.namespace) ?
        document.createElementNS(this.namespace, this.tag) :
        document.createElement(this.tag);
    } else {
      node = this.tag;
    }
    for (name in this.attributes) {
      node.setAttribute(name, this.attributes[name]);
    }
    this.elements.forEach(function(element) {
      node.appendChild(element.toDOM(document));
    });
    return node;
  };

  /**
   * @method toString
   * @return {String} the HTML for this DomBuilder's hierarchy
   * @public
   */
  DomBuilder.prototype.toString = function toString() {
    return this.toDOM().outerHTML;
  };

  /**
   * The tag (or DOMElement) for this node.
   * @property tag
   * @type {String|DOMElement}
   * @default div
   * @private
   */

  /**
   * List of child elements for this DomBuilders hierarchy level.
   * @property elements
   * @type {Array}
   * @private
   */

  /**
   * List of attributes to apply to this DOMElement.
   * @property attributes
   * @type {Object}
   * @private
   */

  /**
   * The namespace for this DOMElement.
   * @property namespace
   * @type {String}
   * @default null
   * @private
   */

  /**
   * The parent DomBuilder in the hierarchy.
   * @property parent
   * @type {DomBuilder}
   * @default null
   * @private
   */

  return DomBuilder;
});
<|endoftext|>