<commit_before>//todo write angular scripts for developer page.

var developerKingdomModule = angular.module('app', []).
	controller("forumCtrl", function forumCtrl($scope, $window, $http){

		$scope.forum = {
			threads: [{subject: "blah blah blah", posts: [{user: "user1", time:  (new Date()).toLocaleString(), message: "hi how u doing"}, {user: "user2", time:  (new Date()).toLocaleString(), message: "lol wassup"}]},
				{subject: "how to add your own functions", posts: [{user: "user1", time: (new Date()).toLocaleString(), message: "asdfasdf"}, {user: "user2", time:  (new Date()).toLocaleString(), message: "j jajajajajajh"}]}]
		};

		$scope.fetch = function(){
			var additionalPosts = [];
			$http({method: "GET", url: "http://localhost:3000/posts"})
				.success(function(data, status){
					additionalPosts = data;
					console.log(additionalPosts);

					for(var i = 0; i < additionalPosts.length; i++){
						$scope.forum.threads[0].posts.push(additionalPosts[i]);
					}
				})
				.error(function(data, status){
					additionalPosts = data || "Request failed";
					console.log(additionalPosts);
				});
		};

		$scope.fetch();

		$scope.currentThread = {};
		$scope.currentThreadOn = false;

		$scope.setThread = function(thread){
			$scope.currentThread = thread;
			$scope.currentThreadOn = true;
		}

		$scope.backToForum = function(){
			$scope.currentThreadOn = false;
		}

		$scope.addPost = function(thread){
			if($scope.currentUser == "" || $scope.currentUser == null){
				$scope.currentUser = "Guest";
			}
			$scope.currentThread.posts.push({user: $scope.currentUser, message: $scope.newPost, time: (new Date()).toLocaleString()});

			$scope.newPost = "";
		}

		$scope.addThread = function(){
			if($scope.currentUser == "" || $scope.currentUser == null){
				$scope.currentUser = "Guest";
			}
			$scope.forum.threads.push({
				subject: $scope.newSubject,
				posts: [{user: $scope.currentUser, message: $scope.newPost, time: (new Date()).toLocaleString()}]
			});

			$scope.newSubject = "";
			$scope.newPost = "";
		}

		$scope.currentUser = "";
		$scope.newPost = "";
		$scope.newSubject = "";
		$scope.predicate = '';
	});
<commit_msg>Update forum.js<commit_after>//todo write angular scripts for developer page.

var developerKingdomModule = angular.module('app', []).
	controller("forumCtrl", function forumCtrl($scope, $window, $http){

		$scope.forum = {
			threads: [{subject: "blah blah blah", posts: [{user: "user1", time:  (new Date()).toLocaleString(), message: "hi how u doing"}, {user: "user2", time:  (new Date()).toLocaleString(), message: "lol wassup"}]},
				{subject: "how to add your own functions", posts: [{user: "user1", time: (new Date()).toLocaleString(), message: "asdfasdf"}, {user: "user2", time:  (new Date()).toLocaleString(), message: "j jajajajajajh"}]}]
		};

		$scope.fetch = function(){
			var additionalPosts = [];
			$http({method: "GET", url: "http://localhost:3000/posts"})
				.success(function(data, status){
					additionalPosts = data;
					console.log(additionalPosts);

					for(var i = 0; i < additionalPosts.length; i++){
						$scope.forum.threads[0].posts.push(additionalPosts[i]);
					}
				})
				.error(function(data, status){
					additionalPosts = data || "Request failed";
					console.log(additionalPosts);
				});
		};

		$scope.fetch();

		$scope.currentThread = {};
		$scope.currentThreadOn = false;

		$scope.setThread = function(thread){
			$scope.currentThread = thread;
			$scope.currentThreadOn = true;
		}

		$scope.backToForum = function(){
			$scope.currentThreadOn = false;
		}

		$scope.addPost = function(thread){
			if($scope.currentUser == "" || $scope.currentUser == null){
				$scope.currentUser = "Guest";
			}

			var postObject = {user: $scope.currentUser, message: $scope.newPost, time: (new Date()).toLocaleString()};

			$scope.currentThread.posts.push(postObject);

			var stringifiedPost = JSON.stringify(postObject);
			$http({method: "POST", url: "http://localhost:3000/posts", data: stringifiedPost})

			$scope.newPost = "";
		}

		$scope.addThread = function(){
			if($scope.currentUser == "" || $scope.currentUser == null){
				$scope.currentUser = "Guest";
			}
			$scope.forum.threads.push({
				subject: $scope.newSubject,
				posts: [{user: $scope.currentUser, message: $scope.newPost, time: (new Date()).toLocaleString()}]
			});

			$scope.newSubject = "";
			$scope.newPost = "";
		}

		$scope.currentUser = "";
		$scope.newPost = "";
		$scope.newSubject = "";
		$scope.predicate = '';
	});
<|endoftext|>


<commit_before>const identity = require("lodash/identity")
const withActiveItem = require("./withActiveItem")
const activeItem = require("./activeItem")
const withEnsureItemVisible = require("./withEnsureItemVisible")
const ctxAssign = require("./assign")

module.exports = ({ next, inheritActiveItem, inheritOpenItem }, cmp) =>
  (inheritActiveItem ? identity : withActiveItem)(
    withEnsureItemVisible(
      inheritOpenItem
        ? cmp
        : ctxAssign(
            {
              openItem: activeItem(ctx => id => id, next),
              activateItem: activeItem(ctx => id => id),
            },
            cmp
          )
    )
  )
<commit_msg>withOpenItem: withEnsureItemVisible made optional according to argument<commit_after>const identity = require("lodash/identity")
const withActiveItem = require("./withActiveItem")
const activeItem = require("./activeItem")
const withEnsureItemVisible = require("./withEnsureItemVisible")
const ctxAssign = require("./assign")

module.exports = ({ next, inheritActiveItem, inheritOpenItem }, cmp) =>
  (inheritActiveItem ? identity : withActiveItem)(
    (inheritActiveItem ? identity : withEnsureItemVisible)(
      inheritOpenItem
        ? cmp
        : ctxAssign(
            {
              openItem: activeItem(ctx => id => id, next),
              activateItem: activeItem(ctx => id => id),
            },
            cmp
          )
    )
  )
<|endoftext|>


<commit_before>
var wffWS = new function() {

	var encoder = wffGlobal.encoder;
	var decoder = wffGlobal.decoder;

	var webSocket;

	this.openSocket = function(wsUtl) {

		// Ensures only one connection is open at a time
		if (webSocket !== undefined
				&& webSocket.readyState !== WebSocket.CLOSED
				&& webSocket.readyState !== WebSocket.CLOSING) {
			console.log("WebSocket is already opened.");
			return;
		}

		// Create a new instance of websocket
		webSocket = new WebSocket(wsUtl);

		// this is required to send binary data
		webSocket.binaryType = 'arraybuffer';

		webSocket.onopen = function(event) {

			wffBMClientEvents.wffRemovePrevBPInstance();

			if (event.data === undefined) {
				return;
			}

			var binary = new Int8Array(event.data);

			if (binary.length == 0) {
				return;
			}

			wffClientCRUDUtil.invokeTasks(binary);

		};

		webSocket.onmessage = function(event) {

			var binary = new Int8Array(event.data);
			console.log(binary);

			if (binary.length == 0) {
				return;
			}

			// for (var i = 0; i < binary.length; i++) {
			// console.log(i, binary[i]);
			// }

			var executed = wffClientMethods.exePostFun(binary);

			if (!executed) {
				wffClientCRUDUtil.invokeTasks(binary);
			}

			// var wffMessage = wffBMUtil.parseWffBinaryMessageBytes(binary);
			// console.log('wffMessage', wffMessage);
			//
			// for (var i = 0; i < wffMessage.length; i++) {
			// var decodedString = decoder.decode(new Uint8Array(
			// wffMessage[i].name));
			// console.log('decodedString', decodedString,
			// 'wffMessage[i].values.length', wffMessage[i].values.length);
			// console.log('values');
			// for (var j = 0; j < wffMessage[i].values.length; j++) {
			// console.log('value', decoder.decode(new Uint8Array(
			// wffMessage[i].values[j])));
			// }
			// }

			// var string = new TextDecoder("utf-8").decode(binary);
			// console.log(string, string);

			// var binary = new Uint8Array(event.data.length);
			// for (var i = 0; i < event.data.length; i++) {
			// console.log(i, event.data[i]);
			// // binary[i] = event.data[i];
			// }
			// console.dir(binary);
			// sendBinary(binary.buffer);

			// console.log('going to writeResponse');
			// writeResponse(event.data);

			// var uint8array = new TextEncoder("utf-8").encode("¢");
			// var string = new TextDecoder("utf-8").decode(uint8array);
		};

		webSocket.onclose = function(event) {
			console.log("onclose", event);
			setTimeout(function() {
				if (!webSocket || webSocket.readyState == 3) {
					console.log("2 seconds loop");
					wffWS.openSocket(wffGlobal.WS_URL);
				}
			}, 2000);
		};
	};

	/**
	 * Sends the bytes to the server
	 */
	this.send = function(bytes) {
		webSocket.send(new Int8Array(bytes));
	};

	this.closeSocket = function() {
		webSocket.close();
	};

};
<commit_msg>Minor improvement<commit_after>
var wffWS = new function() {

	var encoder = wffGlobal.encoder;
	var decoder = wffGlobal.decoder;

	var webSocket;

	this.openSocket = function(wsUtl) {

		// Ensures only one connection is open at a time
		if (webSocket !== undefined
				&& webSocket.readyState !== WebSocket.CLOSED
				&& webSocket.readyState !== WebSocket.CLOSING) {
			console.log("WebSocket is already opened.");
			return;
		}

		// Create a new instance of websocket
		webSocket = new WebSocket(wsUtl);

		// this is required to send binary data
		webSocket.binaryType = 'arraybuffer';

		webSocket.onopen = function(event) {

			wffBMClientEvents.wffRemovePrevBPInstance();

			if (event.data === undefined) {
				return;
			}

			var binary = new Int8Array(event.data);

			if (binary.length < 4) {
				//invalid wff bm message so not to process
				return;
			}

			wffClientCRUDUtil.invokeTasks(binary);

		};

		webSocket.onmessage = function(event) {

			var binary = new Int8Array(event.data);
			console.log(binary);

			if (binary.length < 4) {
				//invalid wff bm message so not to process
				return;
			}

			// for (var i = 0; i < binary.length; i++) {
			// console.log(i, binary[i]);
			// }

			var executed = wffClientMethods.exePostFun(binary);

			if (!executed) {
				wffClientCRUDUtil.invokeTasks(binary);
			}

			// var wffMessage = wffBMUtil.parseWffBinaryMessageBytes(binary);
			// console.log('wffMessage', wffMessage);
			//
			// for (var i = 0; i < wffMessage.length; i++) {
			// var decodedString = decoder.decode(new Uint8Array(
			// wffMessage[i].name));
			// console.log('decodedString', decodedString,
			// 'wffMessage[i].values.length', wffMessage[i].values.length);
			// console.log('values');
			// for (var j = 0; j < wffMessage[i].values.length; j++) {
			// console.log('value', decoder.decode(new Uint8Array(
			// wffMessage[i].values[j])));
			// }
			// }

			// var string = new TextDecoder("utf-8").decode(binary);
			// console.log(string, string);

			// var binary = new Uint8Array(event.data.length);
			// for (var i = 0; i < event.data.length; i++) {
			// console.log(i, event.data[i]);
			// // binary[i] = event.data[i];
			// }
			// console.dir(binary);
			// sendBinary(binary.buffer);

			// console.log('going to writeResponse');
			// writeResponse(event.data);

			// var uint8array = new TextEncoder("utf-8").encode("¢");
			// var string = new TextDecoder("utf-8").decode(uint8array);
		};

		webSocket.onclose = function(event) {
			console.log("onclose", event);
			setTimeout(function() {
				if (!webSocket || webSocket.readyState == 3) {
					console.log("2 seconds loop");
					wffWS.openSocket(wffGlobal.WS_URL);
				}
			}, 2000);
		};
	};

	/**
	 * Sends the bytes to the server
	 */
	this.send = function(bytes) {
		webSocket.send(new Int8Array(bytes));
	};

	this.closeSocket = function() {
		webSocket.close();
	};

};
<|endoftext|>


<commit_before>import AudioUtils from '../../util/audioUtils';

Entry.AI_UTILIZE_BLOCK.audio = {
    name: 'audio',
    imageName: 'audio.svg',
    sponserText: 'Powered by NAVER Clova',
    title: {
        ko: '오디오 감지',
        en: 'Audio Detection',
        jp: 'オーディオ検出',
    },
    titleKey: 'template.audio_title_text',
    description: Lang.Msgs.ai_utilize_audio_description,
    descriptionKey: 'Msgs.ai_utilize_audio_description',
    isInitialized: false,
    async init() {
        await AudioUtils.initialize();
        Entry.AI_UTILIZE_BLOCK.audio.isInitialized = true;
    },
};

Entry.AI_UTILIZE_BLOCK.audio.getBlocks = function() {
    return {
        audio_title: {
            skeleton: 'basic_text',
            color: EntryStatic.colorSet.common.TRANSPARENT,
            params: [
                {
                    type: 'Text',
                    text: Lang.template.audio_title_text,
                    color: EntryStatic.colorSet.common.TEXT,
                    align: 'center',
                },
            ],
            def: {
                type: 'audio_title',
            },
            class: 'audio',
            isNotFor: ['audio'],
            events: {},
        },
        check_microphone: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_boolean_field',
            statements: [],
            params: [],
            events: {},
            def: {
                type: 'check_microphone',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            async func(sprite, script) {
                if (!AudioUtils.isInitialized) {
                    await AudioUtils.initialize();
                }
                return AudioUtils.audioInputList.length > 0;
            },
            syntax: {
                js: [],
                py: [],
            },
        },

        speech_to_text_convert: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            params: [
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'speech_to_text_convert',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            async func(sprite, script) {
                if (!AudioUtils.isInitialized) {
                    await AudioUtils.initialize();
                }
                if (AudioUtils.isRecording) {
                    return;
                }
                try {
                    AudioUtils.isRecording = true;
                    Entry.container.enableSttValue();
                    const result = await AudioUtils.startRecord(60 * 1000);
                    Entry.dispatchEvent('audioRecordingDone');
                    Entry.container.setSttValue(result || 0);
                } catch (e) {
                    Entry.container.setSttValue(0);
                    throw e;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },

        speech_to_text_get_value: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            params: [],
            events: {},
            def: {
                type: 'speech_to_text_get_value',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            func(sprite, script) {
                return Entry.container.getSttValue();
            },
            syntax: {
                js: [],
                py: [],
            },
        },

        get_microphone_volume: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            params: [],
            events: {},
            def: {
                type: 'get_microphone_volume',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            async func(sprite, script) {
                if (!AudioUtils.isInitialized) {
                    await AudioUtils.initialize();
                }
                return AudioUtils.currentVolume;
            },
            syntax: {
                js: [],
                py: [],
            },
        },
    };
};
<commit_msg>#3586 사이드 이펙트 수정 (#2146)<commit_after>import AudioUtils from '../../util/audioUtils';

Entry.AI_UTILIZE_BLOCK.audio = {
    name: 'audio',
    imageName: 'audio.svg',
    sponserText: 'Powered by NAVER Clova',
    title: {
        ko: '오디오 감지',
        en: 'Audio Detection',
        jp: 'オーディオ検出',
    },
    titleKey: 'template.audio_title_text',
    description: Lang.Msgs.ai_utilize_audio_description,
    descriptionKey: 'Msgs.ai_utilize_audio_description',
    isInitialized: false,
    async init() {
        await AudioUtils.initialize();
        Entry.AI_UTILIZE_BLOCK.audio.isInitialized = true;
    },
};

Entry.AI_UTILIZE_BLOCK.audio.getBlocks = function() {
    return {
        audio_title: {
            skeleton: 'basic_text',
            color: EntryStatic.colorSet.common.TRANSPARENT,
            params: [
                {
                    type: 'Text',
                    text: Lang.template.audio_title_text,
                    color: EntryStatic.colorSet.common.TEXT,
                    align: 'center',
                },
            ],
            def: {
                type: 'audio_title',
            },
            class: 'audio',
            isNotFor: ['audio'],
            events: {},
        },
        check_microphone: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_boolean_field',
            statements: [],
            params: [],
            events: {},
            def: {
                type: 'check_microphone',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            async func(sprite, script) {
                try {
                    if (!AudioUtils.isInitialized) {
                        await AudioUtils.initialize();
                    }
                    return AudioUtils.audioInputList.length > 0;
                } catch (err) {
                    return false;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },

        speech_to_text_convert: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            params: [
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'speech_to_text_convert',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            async func(sprite, script) {
                if (!AudioUtils.isInitialized) {
                    await AudioUtils.initialize();
                }
                if (AudioUtils.isRecording) {
                    return;
                }
                try {
                    AudioUtils.isRecording = true;
                    Entry.container.enableSttValue();
                    const result = await AudioUtils.startRecord(60 * 1000);
                    Entry.dispatchEvent('audioRecordingDone');
                    Entry.container.setSttValue(result || 0);
                } catch (e) {
                    Entry.container.setSttValue(0);
                    throw e;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },

        speech_to_text_get_value: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            params: [],
            events: {},
            def: {
                type: 'speech_to_text_get_value',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            func(sprite, script) {
                return Entry.container.getSttValue();
            },
            syntax: {
                js: [],
                py: [],
            },
        },

        get_microphone_volume: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            params: [],
            events: {},
            def: {
                type: 'get_microphone_volume',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'audio',
            isNotFor: ['audio'],
            async func(sprite, script) {
                if (!AudioUtils.isInitialized) {
                    await AudioUtils.initialize();
                }
                return AudioUtils.currentVolume;
            },
            syntax: {
                js: [],
                py: [],
            },
        },
    };
};
<|endoftext|>


<commit_before>import VideoUtils from '../../util/videoUtils';
import clamp from 'lodash/clamp';
Entry.videoUtils = VideoUtils;
Entry.AI_UTILIZE_BLOCK.video = {
    name: 'video',
    imageName: 'video.svg',
    sponserText: 'Powered by Naver',
    title: {
        ko: '비디오 감지',
        en: 'Video Detection',
        jp: 'ビデオ検出',
    },
    titleKey: 'template.video_title_text',
    description: Lang.Msgs.ai_utilize_video_description,
    descriptionKey: 'Msgs.ai_utilize_video_description',
    isInitialized: false,
    async init() {
        await VideoUtils.initialize();
        Entry.AI_UTILIZE_BLOCK.video.isInitialized = true;
    },
};

Entry.AI_UTILIZE_BLOCK.video.getBlocks = function() {
    return {
        video_title: {
            skeleton: 'basic_text',
            color: EntryStatic.colorSet.common.TRANSPARENT,
            params: [
                {
                    type: 'Text',
                    text: Lang.template.video_title_text,
                    color: EntryStatic.colorSet.common.TEXT,
                    align: 'center',
                },
            ],
            def: {
                type: 'video_title',
            },
            class: 'video',
            isNotFor: ['video'],
            events: {},
        },
        video_check_webcam: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            template: '비디오가 연결되었는가?',
            params: [],
            events: {},
            def: {
                type: 'video_check_webcam',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                if (!VideoUtils.isInitialized) {
                    await VideoUtils.initialize();
                }
                const result = await VideoUtils.checkUserCamAvailable();
                return result.toString();
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_draw_webcam: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            template: '비디오 화면 %1 %2',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['보이기', 'on'],
                        ['숨기기', 'off'],
                    ],
                    value: 'on',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'video_draw_webcam',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                const value = script.getField('VALUE');
                if (!VideoUtils.isInitialized) {
                    await VideoUtils.initialize();
                }
                VideoUtils.cameraSwitch(value);
                return script.callReturn();
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_set_camera_option: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            template: '비디오 %1 효과를 %2 으로 정하기 %3',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['밝기', 'brightness'],
                        ['투명도', 'opacity'],
                    ],
                    value: 'brightness',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Block',
                    accept: 'string',
                    defaultType: 'number',
                    value: '0',
                },
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'video_set_camera_option',
            },
            paramsKeyMap: {
                TARGET: 0,
                VALUE: 1,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                const target = script.getField('TARGET');
                const value = clamp(
                    script.getNumberValue('VALUE'),
                    target === 'brightness' ? -100 : 0,
                    100
                );
                try {
                    if (!VideoUtils.isInitialized) {
                        await VideoUtils.initialize();
                    }
                    VideoUtils.setOptions(target, value);
                    return script.callReturn();
                } catch (err) {
                    console.log(err);
                    throw err;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_flip_camera: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            template: '비디오 화면 %1 뒤집기 %2',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['좌우', 'hflip'],
                        ['상하', 'vflip'],
                    ],
                    value: 'hflip',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'video_flip_camera',
            },
            paramsKeyMap: {
                TARGET: 0,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                const target = script.getField('TARGET');
                if (!VideoUtils.isInitialized) {
                    await VideoUtils.initialize();
                }
                VideoUtils.setOptions(target);
                return script.callReturn();
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_number_of_person: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            template: '인식된 사람의 수',
            params: [],
            events: {},
            def: {
                type: 'video_number_of_person',
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                try {
                    if (!VideoUtils.isInitialized) {
                        await VideoUtils.initialize();
                    }
                    const poses = await VideoUtils.estimatePoseOnImage();
                    return poses.length || 0;
                } catch (err) {
                    return 0;
                }
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_body_part_coord: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            template: '%1 번째 얼굴 %2 의 %3 좌표',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['1', 1],
                        ['2', 2],
                        ['3', 3],
                        ['4', 4],
                    ],
                    value: 1,
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Dropdown',
                    options: [
                        // ['코', 'nose'],
                        // ['왼쪽 눈', 'leftEye'],
                        // ['오른쪽 눈', 'rightEye'],
                        // ['왼쪽 귀', 'leftEar'],
                        // ['오른쪽 귀', 'rightEar'],
                        // ['왼족 어깨', 'leftShoulder'],
                        // ['오른쪽 어깨', 'rightShoulder'],
                        // ['왼쪽 팔꿈치', 'leftElbow'],
                        // ['오른쪽 팔꿈치', 'rightElbow'],
                        // ['왼쪽 손목', 'leftWrist'],
                        // ['오른쪽 손목', 'rightWrist'],
                        // ['왼쪽 엉덩이', 'leftHip'],
                        // ['오른쪽 엉덩이', 'rightHip'],
                        // ['왼쪽 무릎', 'leftKnee'],
                        // ['오른쪽 무릎', 'rightKnee'],
                        // ['왼쪽 발목', 'leftAnkle'],
                        // ['오른쪽 발목', 'rightAnkle'],

                        ['코', 0],
                        ['왼쪽 눈', 1],
                        ['오른쪽 눈', 2],
                        ['왼쪽 귀', 3],
                        ['오른쪽 귀', 4],
                        ['왼족 어깨', 5],
                        ['오른쪽 어깨', 6],
                        ['왼쪽 팔꿈치', 7],
                        ['오른쪽 팔꿈치', 8],
                        ['왼쪽 손목', 9],
                        ['오른쪽 손목', 10],
                        ['왼쪽 엉덩이', 11],
                        ['오른쪽 엉덩이', 12],
                        ['왼쪽 무릎', 13],
                        ['오른쪽 무릎', 14],
                        ['왼쪽 발목', 15],
                        ['오른쪽 발목', 16],
                    ],
                    value: 1,
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Dropdown',
                    options: [
                        ['x', 'x'],
                        ['y', 'y'],
                    ],
                    value: 'x',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
            ],
            events: {},
            def: {
                type: 'video_body_part_coord',
            },
            paramsKeyMap: {
                INDEX: 0,
                PART: 1,
                COORD: 2,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                try {
                    if (!VideoUtils.isInitialized) {
                        await VideoUtils.initialize();
                    }
                    const index = script.getField('INDEX');
                    const part = script.getField('PART');
                    const coord = script.getField('COORD');

                    const poses = await VideoUtils.estimatePoseOnImage();
                    if (poses.length < index) {
                        return 0;
                    }
                    // offset since value shown starts from 1;
                    const rawValue = poses[index - 1].keypoints[part].position[coord];
                    if (!rawValue) {
                        return 0;
                    }
                    let returningValue = 0;
                    if (coord === 'x') {
                        returningValue = rawValue - VideoUtils.CANVAS_WIDTH / 2;
                    }
                    returningValue = VideoUtils.CANVAS_HEIGHT / 2 - rawValue;

                    return returningValue.toFixed(1);
                } catch (err) {
                    return 0;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },
    };
};
<commit_msg>텍스트 수정<commit_after>import VideoUtils from '../../util/videoUtils';
import clamp from 'lodash/clamp';
Entry.videoUtils = VideoUtils;
Entry.AI_UTILIZE_BLOCK.video = {
    name: 'video',
    imageName: 'video.svg',
    sponserText: 'Powered by Naver',
    title: {
        ko: '비디오 감지',
        en: 'Video Detection',
        jp: 'ビデオ検出',
    },
    titleKey: 'template.video_title_text',
    description: Lang.Msgs.ai_utilize_video_description,
    descriptionKey: 'Msgs.ai_utilize_video_description',
    isInitialized: false,
    async init() {
        await VideoUtils.initialize();
        Entry.AI_UTILIZE_BLOCK.video.isInitialized = true;
    },
};

Entry.AI_UTILIZE_BLOCK.video.getBlocks = function() {
    return {
        video_title: {
            skeleton: 'basic_text',
            color: EntryStatic.colorSet.common.TRANSPARENT,
            params: [
                {
                    type: 'Text',
                    text: Lang.template.video_title_text,
                    color: EntryStatic.colorSet.common.TEXT,
                    align: 'center',
                },
            ],
            def: {
                type: 'video_title',
            },
            class: 'video',
            isNotFor: ['video'],
            events: {},
        },
        video_check_webcam: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            template: '비디오가 연결되었는가?',
            params: [],
            events: {},
            def: {
                type: 'video_check_webcam',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                if (!VideoUtils.isInitialized) {
                    await VideoUtils.initialize();
                }
                const result = await VideoUtils.checkUserCamAvailable();
                return result.toString();
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_draw_webcam: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            template: '비디오 화면 %1 %2',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['보이기', 'on'],
                        ['숨기기', 'off'],
                    ],
                    value: 'on',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'video_draw_webcam',
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                const value = script.getField('VALUE');
                if (!VideoUtils.isInitialized) {
                    await VideoUtils.initialize();
                }
                VideoUtils.cameraSwitch(value);
                return script.callReturn();
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_set_camera_option: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            template: '비디오 %1 효과를 %2 으로 정하기 %3',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['밝기', 'brightness'],
                        ['투명도', 'opacity'],
                    ],
                    value: 'brightness',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Block',
                    accept: 'string',
                    defaultType: 'number',
                    value: '0',
                },
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'video_set_camera_option',
            },
            paramsKeyMap: {
                TARGET: 0,
                VALUE: 1,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                const target = script.getField('TARGET');
                const value = clamp(
                    script.getNumberValue('VALUE'),
                    target === 'brightness' ? -100 : 0,
                    100
                );
                try {
                    if (!VideoUtils.isInitialized) {
                        await VideoUtils.initialize();
                    }
                    VideoUtils.setOptions(target, value);
                    return script.callReturn();
                } catch (err) {
                    console.log(err);
                    throw err;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_flip_camera: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic',
            statements: [],
            template: '비디오 화면 %1 뒤집기 %2',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['좌우', 'hflip'],
                        ['상하', 'vflip'],
                    ],
                    value: 'hflip',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Indicator',
                    img: 'block_icon/ai_utilize_icon.svg',
                    size: 11,
                },
            ],
            events: {},
            def: {
                type: 'video_flip_camera',
            },
            paramsKeyMap: {
                TARGET: 0,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                const target = script.getField('TARGET');
                if (!VideoUtils.isInitialized) {
                    await VideoUtils.initialize();
                }
                VideoUtils.setOptions(target);
                return script.callReturn();
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_number_of_person: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            template: '인식된 사람의 수',
            params: [],
            events: {},
            def: {
                type: 'video_number_of_person',
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                try {
                    if (!VideoUtils.isInitialized) {
                        await VideoUtils.initialize();
                    }
                    const poses = await VideoUtils.estimatePoseOnImage();
                    return poses.length || 0;
                } catch (err) {
                    return 0;
                }
            },
            paramsKeyMap: {
                VALUE: 0,
            },
            syntax: {
                js: [],
                py: [],
            },
        },
        video_body_part_coord: {
            color: EntryStatic.colorSet.block.default.AI_UTILIZE,
            outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE,
            skeleton: 'basic_string_field',
            statements: [],
            template: '%1 번째 사람의 %2 의 %3 좌표',
            params: [
                {
                    type: 'Dropdown',
                    options: [
                        ['1', 1],
                        ['2', 2],
                        ['3', 3],
                        ['4', 4],
                    ],
                    value: 1,
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Dropdown',
                    options: [
                        // ['코', 'nose'],
                        // ['왼쪽 눈', 'leftEye'],
                        // ['오른쪽 눈', 'rightEye'],
                        // ['왼쪽 귀', 'leftEar'],
                        // ['오른쪽 귀', 'rightEar'],
                        // ['왼족 어깨', 'leftShoulder'],
                        // ['오른쪽 어깨', 'rightShoulder'],
                        // ['왼쪽 팔꿈치', 'leftElbow'],
                        // ['오른쪽 팔꿈치', 'rightElbow'],
                        // ['왼쪽 손목', 'leftWrist'],
                        // ['오른쪽 손목', 'rightWrist'],
                        // ['왼쪽 엉덩이', 'leftHip'],
                        // ['오른쪽 엉덩이', 'rightHip'],
                        // ['왼쪽 무릎', 'leftKnee'],
                        // ['오른쪽 무릎', 'rightKnee'],
                        // ['왼쪽 발목', 'leftAnkle'],
                        // ['오른쪽 발목', 'rightAnkle'],

                        ['얼굴', 0],
                        ['왼쪽 눈', 1],
                        ['오른쪽 눈', 2],
                        ['왼쪽 귀', 3],
                        ['오른쪽 귀', 4],
                        ['왼족 어깨', 5],
                        ['오른쪽 어깨', 6],
                        ['왼쪽 팔꿈치', 7],
                        ['오른쪽 팔꿈치', 8],
                        ['왼쪽 손목', 9],
                        ['오른쪽 손목', 10],
                        ['왼쪽 엉덩이', 11],
                        ['오른쪽 엉덩이', 12],
                        ['왼쪽 무릎', 13],
                        ['오른쪽 무릎', 14],
                        ['왼쪽 발목', 15],
                        ['오른쪽 발목', 16],
                    ],
                    value: 1,
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
                {
                    type: 'Dropdown',
                    options: [
                        ['x', 'x'],
                        ['y', 'y'],
                    ],
                    value: 'x',
                    fontSize: 11,
                    bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE,
                    arrowColor: EntryStatic.colorSet.common.WHITE,
                },
            ],
            events: {},
            def: {
                type: 'video_body_part_coord',
            },
            paramsKeyMap: {
                INDEX: 0,
                PART: 1,
                COORD: 2,
            },
            class: 'video',
            isNotFor: ['video'],
            async func(sprite, script) {
                try {
                    if (!VideoUtils.isInitialized) {
                        await VideoUtils.initialize();
                    }
                    const index = script.getField('INDEX');
                    const part = script.getField('PART');
                    const coord = script.getField('COORD');

                    const poses = await VideoUtils.estimatePoseOnImage();
                    if (poses.length < index) {
                        return 0;
                    }
                    // offset since value shown starts from 1;
                    const rawValue = poses[index - 1].keypoints[part].position[coord];
                    if (!rawValue) {
                        return 0;
                    }
                    let returningValue = 0;
                    if (coord === 'x') {
                        returningValue = rawValue - VideoUtils.CANVAS_WIDTH / 2;
                    }
                    returningValue = VideoUtils.CANVAS_HEIGHT / 2 - rawValue;

                    return returningValue.toFixed(1);
                } catch (err) {
                    return 0;
                }
            },
            syntax: {
                js: [],
                py: [],
            },
        },
    };
};
<|endoftext|>


<commit_before>import React from 'react';
import { mount } from 'enzyme';
import _ from 'underscore';
import url from 'url';

// Import test component and data.
import Experiment from '../experiment';
import context from '../testdata/experiment';

describe('Experiment Page', () => {
    describe('Minimal Experiment', () => {
        let experiment;
        let summary;

        beforeAll(() => {
            const contextMin = _.clone(context);
            contextMin.references = [require('../testdata/publication/PMID16395128'), require('../testdata/publication/PMID23000965')];
            experiment = mount(
                <Experiment context={context} />
            );

            summary = experiment.find('.data-display');
        });

        test('has proper links in dbxrefs key-value', () => {
            const item = summary.at(0).find('[data-test="external-resources"]');
            const desc = item.find('dd');
            const dbxrefs = desc.at(0).find('a');
            expect(dbxrefs).toHaveLength(2);
            expect(dbxrefs.at(0).prop('href')).toEqual('http://genome.ucsc.edu/cgi-bin/hgTracks?tsCurTab=advancedTab&tsGroup=Any&tsType=Any&hgt_mdbVar1=dccAccession&hgt_tSearch=search&hgt_tsDelRow=&hgt_tsAddRow=&hgt_tsPage=&tsSimple=&tsName=&tsDescr=&db=hg19&hgt_mdbVal1=wgEncodeEH003317');
            expect(dbxrefs.at(1).prop('href')).toEqual('https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM1010811');
        });

        test('has proper release date', () => {
            const item = summary.at(0).find('[data-test="date-released"]');
            const desc = item.find('dd');
            expect(desc.at(0).text()).toEqual('2011-10-29');
        });

        test('has one experiment status element in header', () => {
            const statusList = experiment.find('.status-list');
            expect(statusList.children().exists()).toBeTruthy();
            expect(statusList.children()).toHaveLength(1);
        });
    });

    describe('Document Panel', () => {
        let experiment;
        let doc;

        beforeAll(() => {
            const contextDoc = _.clone(context);
            contextDoc.documents = [require('../testdata/document/myerschipseq')];
            experiment = mount(
                <Experiment context={contextDoc} />
            );
            doc = experiment.find('.type-Document');
        });

        test('has one document panel with a PDF image anchor', () => {
            const figures = doc.find('figure');
            expect(figures).toHaveLength(1);
            const anchors = figures.find('.file-pdf');
            expect(anchors).toHaveLength(1);
        });

        test('has a single proper download link', () => {
            const dlBar = doc.find('.document__file');
            expect(dlBar).toHaveLength(1);
            const anchors = dlBar.find('a');
            expect(anchors).toHaveLength(2);
            expect(url.parse(anchors.at(0).prop('href')).pathname).toEqual('/documents/df9dd0ec-c1cf-4391-a745-a933ab1af7a7/@@download/attachment/Myers_Lab_ChIP-seq_Protocol_v042211.pdf');
        });

        test('has two key-value pairs, and proper DL link', () => {
            const trigger = doc.find('.document__file-detail-switch');
            trigger.at(0).simulate('click');

            const docKeyValue = doc.find('.key-value-doc');
            expect(docKeyValue).toHaveLength(1);
            const defTerms = docKeyValue.at(0).find('dt');
            expect(defTerms).toHaveLength(3);
            const defDescs = docKeyValue.at(0).find('dd');
            expect(defDescs).toHaveLength(3);
        });
    });

    describe('Document Panel References', () => {
        let experiment;
        let doc;

        beforeAll(() => {
            const contextDoc = _.clone(context);
            contextDoc.documents = [require('../testdata/document/wgEncodeSydhHist-refs')];
            experiment = mount(
                <Experiment context={contextDoc} />
            );
            doc = experiment.find('.type-Document');
        });

        test('has five key-value pairs, and two good references links', () => {
            const docKeyValue = doc.find('.key-value-doc');
            expect(docKeyValue).toHaveLength(1);
            const defTerms = docKeyValue.at(0).find('dt');
            expect(defTerms).toHaveLength(3);
            const defDescs = docKeyValue.at(0).find('dd');
            expect(defDescs).toHaveLength(3);
        });
    });

    describe('Replicate Panels', () => {
        let experiment;
        let summary;

        beforeAll(() => {
            const contextRep = _.clone(context);
            contextRep.replicates = [require('../testdata/replicate/human'), require('../testdata/replicate/mouse')];
            contextRep.replicates[0].library = require('../testdata/library/sid38806');
            contextRep.replicates[1].library = require('../testdata/library/sid38807');
            contextRep.files = [require('../testdata/file/fastq')];
            experiment = mount(
                <Experiment context={contextRep} />
            );
            summary = experiment.find('.data-display');
        });

        test('has proper treatment', () => {
            const item = summary.find('[data-test="treatments"]');
            const desc = item.find('dd');
            expect(desc.text()).toEqual('97.2 nM doxycycline hyclate (CHEBI:34730) for 6 hour [1-1]');
        });

        test('has proper strand specificity', () => {
            const item = summary.find('[data-test="strandspecificity"]');
            const desc = item.find('dd');
            expect(desc.text()).toEqual('Strand-specific');
        });

        test('has proper spikeins', () => {
            const item = summary.find('[data-test="spikeins"]');
            const desc = item.find('dd');
            expect(desc.text()).toEqual('ENCSR000AJW [1-1]');
        });
    });

    describe('Alternate accession display', () => {
        let experiment;
        let alt;

        beforeAll(() => {
            const contextAlt = _.clone(context);
            contextAlt.alternate_accessions = ['ENCSR000ACT', 'ENCSR999NOF'];
            experiment = mount(
                <Experiment context={contextAlt} />
            );
            alt = experiment.find('.repl-acc');
        });

        test('displays two alternate accessions', () => {
            expect(alt.text()).toEqual('Replaces ENCSR000ACT, ENCSR999NOF');
        });
    });
});
<commit_msg>Change didn’t stick?<commit_after>import React from 'react';
import { mount } from 'enzyme';
import _ from 'underscore';
import url from 'url';

// Import test component and data.
import Experiment from '../experiment';
import context from '../testdata/experiment';

describe('Experiment Page', () => {
    describe('Minimal Experiment', () => {
        let experiment;
        let summary;

        beforeAll(() => {
            const contextMin = _.clone(context);
            contextMin.references = [require('../testdata/publication/PMID16395128'), require('../testdata/publication/PMID23000965')];
            experiment = mount(
                <Experiment context={context} />
            );

            summary = experiment.find('.data-display');
        });

        test('has proper links in dbxrefs key-value', () => {
            const item = summary.at(0).find('[data-test="external-resources"]');
            const desc = item.find('dd');
            const dbxrefs = desc.at(0).find('a');
            expect(dbxrefs).toHaveLength(2);
            expect(dbxrefs.at(0).prop('href')).toEqual('http://genome.ucsc.edu/cgi-bin/hgTracks?tsCurTab=advancedTab&tsGroup=Any&tsType=Any&hgt_mdbVar1=dccAccession&hgt_tSearch=search&hgt_tsDelRow=&hgt_tsAddRow=&hgt_tsPage=&tsSimple=&tsName=&tsDescr=&db=hg19&hgt_mdbVal1=wgEncodeEH003317');
            expect(dbxrefs.at(1).prop('href')).toEqual('https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM1010811');
        });

        test('has proper release date', () => {
            const item = summary.at(0).find('[data-test="date-released"]');
            const desc = item.find('dd');
            expect(desc.at(0).text()).toEqual('2011-10-29');
        });

        test('has one experiment status element in header', () => {
            const statusList = experiment.find('.status-list');
            expect(statusList.children().exists()).toBeTruthy();
            expect(statusList.children()).toHaveLength(1);
        });
    });

    describe('Document Panel', () => {
        let experiment;
        let doc;

        beforeAll(() => {
            const contextDoc = _.clone(context);
            contextDoc.documents = [require('../testdata/document/myerschipseq')];
            experiment = mount(
                <Experiment context={contextDoc} />
            );
            doc = experiment.find('.type-Document');
        });

        test('has one document panel with a PDF image anchor', () => {
            const figures = doc.find('figure');
            expect(figures).toHaveLength(1);
            const anchors = figures.find('.file-pdf');
            expect(anchors).toHaveLength(1);
        });

        test('has a single proper download link', () => {
            const dlBar = doc.find('.document__file');
            expect(dlBar).toHaveLength(1);
            const anchors = dlBar.find('a');
            expect(anchors).toHaveLength(1);
            expect(url.parse(anchors.at(0).prop('href')).pathname).toEqual('/documents/df9dd0ec-c1cf-4391-a745-a933ab1af7a7/@@download/attachment/Myers_Lab_ChIP-seq_Protocol_v042211.pdf');
        });

        test('has two key-value pairs, and proper DL link', () => {
            const trigger = doc.find('.document__file-detail-switch');
            trigger.at(0).simulate('click');

            const docKeyValue = doc.find('.key-value-doc');
            expect(docKeyValue).toHaveLength(1);
            const defTerms = docKeyValue.at(0).find('dt');
            expect(defTerms).toHaveLength(3);
            const defDescs = docKeyValue.at(0).find('dd');
            expect(defDescs).toHaveLength(3);
        });
    });

    describe('Document Panel References', () => {
        let experiment;
        let doc;

        beforeAll(() => {
            const contextDoc = _.clone(context);
            contextDoc.documents = [require('../testdata/document/wgEncodeSydhHist-refs')];
            experiment = mount(
                <Experiment context={contextDoc} />
            );
            doc = experiment.find('.type-Document');
        });

        test('has five key-value pairs, and two good references links', () => {
            const docKeyValue = doc.find('.key-value-doc');
            expect(docKeyValue).toHaveLength(1);
            const defTerms = docKeyValue.at(0).find('dt');
            expect(defTerms).toHaveLength(3);
            const defDescs = docKeyValue.at(0).find('dd');
            expect(defDescs).toHaveLength(3);
        });
    });

    describe('Replicate Panels', () => {
        let experiment;
        let summary;

        beforeAll(() => {
            const contextRep = _.clone(context);
            contextRep.replicates = [require('../testdata/replicate/human'), require('../testdata/replicate/mouse')];
            contextRep.replicates[0].library = require('../testdata/library/sid38806');
            contextRep.replicates[1].library = require('../testdata/library/sid38807');
            contextRep.files = [require('../testdata/file/fastq')];
            experiment = mount(
                <Experiment context={contextRep} />
            );
            summary = experiment.find('.data-display');
        });

        test('has proper treatment', () => {
            const item = summary.find('[data-test="treatments"]');
            const desc = item.find('dd');
            expect(desc.text()).toEqual('97.2 nM doxycycline hyclate (CHEBI:34730) for 6 hour [1-1]');
        });

        test('has proper strand specificity', () => {
            const item = summary.find('[data-test="strandspecificity"]');
            const desc = item.find('dd');
            expect(desc.text()).toEqual('Strand-specific');
        });

        test('has proper spikeins', () => {
            const item = summary.find('[data-test="spikeins"]');
            const desc = item.find('dd');
            expect(desc.text()).toEqual('ENCSR000AJW [1-1]');
        });
    });

    describe('Alternate accession display', () => {
        let experiment;
        let alt;

        beforeAll(() => {
            const contextAlt = _.clone(context);
            contextAlt.alternate_accessions = ['ENCSR000ACT', 'ENCSR999NOF'];
            experiment = mount(
                <Experiment context={contextAlt} />
            );
            alt = experiment.find('.repl-acc');
        });

        test('displays two alternate accessions', () => {
            expect(alt.text()).toEqual('Replaces ENCSR000ACT, ENCSR999NOF');
        });
    });
});
<|endoftext|>


<commit_before>var destination = document.getElementById("summary_destination").textContent;
console.log("Destination: " + destination);

var distancesObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("class") && addedNode.getAttribute("class").indexOf("distances") > -1)
			{
				var distancesNode = addedNode;
				console.log("Added distances node:");
				console.log(distancesNode);
				console.log("Tooltip data:");
				console.log(distancesNode.children[0].children[0].tooltipData);
			}
		}
	})
});

function ms2str(milliseconds)
{
	var ret = '';
	if(milliseconds) {
		milliseconds = parseInt( milliseconds / 1000 / 60);
		ret = milliseconds + ' min';
	} else {
		ret = '0 min';
	}

	return ret;
}

function injectResults(data)
{
	console.log(data);

	var hotelElement = document.getElementById(data.requestId);
	if(hotelElement) {
		var dists = hotelElement.getElementsByClassName('distances_centered');
		if(dists.length > 0) {
			var elem = dists[0];
			elem.innerHTML += '
' + ms2str(data.travelDuration) + '
';
			elem.innerHTML += '
' + ms2str(data.walkDuration) + '
';
			elem.innerHTML += '
' + data.numChanges + ' umst.
';
		}
	}
}

function callAPIFunction(address, hotelId)
{
	var now = new Date().getTime();
	var url = 'http://api.hotelroute.org/queryTripSummary?to=' + encodeURIComponent(destination) + '&from=' + encodeURIComponent(address) + '&startDate=' + now + '&endDate=' + now + '&requestId=' + hotelId;
//	console.log(url);

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				if( '' != xhr.responseText) {
					var response = JSON.parse(xhr.responseText);
					injectResults(response)
				}
//				scrapeHRSHotelAddress(xhr.responseText);
			} else {
//				console.error(xhr.statusText);
			}
		}
	};
	xhr.onerror = function (e) {
//		console.error(xhr.statusText);
	};
	xhr.send(null);
}

function scrapeHRSHotelAddress(html, hotelId)
{
	var div = document.createElement('div');
	div.innerHTML = html;

	var elements = div.getElementsByTagName('address');
	for(var i=0; i<elements.length; i++) {
		var address = elements[i];
		callAPIFunction(address.innerHTML, hotelId);
	}
}

function getHRSHotelAddress(hotelItem, hotelId)
{
	var url = 'http://www.hrs.de' + hotelItem;

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				scrapeHRSHotelAddress(xhr.responseText, hotelId);
			}
		}
	};
	xhr.send(null);
}

var hotelsObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("data-hpos"))
			{
				var hotelNode = addedNode;
				var hotelId = hotelNode.getAttribute("id");
//				console.log("Added hotel with id [" + hotelId + "].");

				var hotelItem = hotelNode.getAttribute("data-hotelitemurl");
				getHRSHotelAddress(hotelItem,hotelId);

				distancesObserver.observe(hotelNode, { childList: true });
			}
		}
	})
});

var target = document.getElementById("containerAllHotels");

var config = { childList: true };

hotelsObserver.observe(target, config);
<commit_msg>added delay loader of information<commit_after>var destination = document.getElementById("summary_destination").textContent;
//console.log("Destination: " + destination);

var distancesObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("class") && addedNode.getAttribute("class").indexOf("distances") > -1)
			{
				for(var j = 0; j < mutation.target.attributes.length; ++j)
				{
					var attribute = mutation.target.attributes[j];
					if( 'data-hotelitemurl' == attribute.nodeName) {
						var hotelItem = attribute.nodeValue;
						var hotelId = mutation.target.id;
//						console.log("Added hotel with id [" + hotelId + "].");

						getHRSHotelAddress(hotelItem,hotelId);
					}
				}
			}
		}
	})
});

function ms2str(milliseconds)
{
	var ret = '';
	if(milliseconds) {
		milliseconds = parseInt( milliseconds / 1000 / 60);
		ret = milliseconds + ' min';
	} else {
		ret = '0 min';
	}

	return ret;
}

function injectResults(data)
{
//	console.log(data);

	var hotelElement = document.getElementById(data.requestId);
//	console.log(hotelElement);
	if(hotelElement) {
		var dists = hotelElement.getElementsByClassName('distances_centered');
//		console.log(dists.length);
		if(dists.length > 0) {
			var elem = dists[0];
			elem.innerHTML += '
' + ms2str(data.travelDuration) + '
';
			elem.innerHTML += '
' + ms2str(data.walkDuration) + '
';
			elem.innerHTML += '<div class="hd train" style="background-image:url(http://www.hotelroute.org/media/icon-change' + (data.numChanges <=0 ? '1' : data.numChanges == 1 ? '2' : '3') + '.png);background-position:0px 0;">' + data.numChanges + ' umst
';
		}
	}
}

function callAPIFunction(address, hotelId)
{
	var now = new Date().getTime();
	var url = 'http://api.hotelroute.org/queryTripSummary?to=' + encodeURIComponent(destination) + '&from=' + encodeURIComponent(address) + '&startDate=' + now + '&endDate=' + now + '&requestId=' + hotelId;
//	console.log(url);

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				if( '' != xhr.responseText) {
					var response = JSON.parse(xhr.responseText);
					injectResults(response)
				}
			} else {
//				console.error(xhr.statusText);
			}
		}
	};
	xhr.onerror = function (e) {
//		console.error(xhr.statusText);
	};
	xhr.send(null);
}

function scrapeHRSHotelAddress(html, hotelId)
{
	var div = document.createElement('div');
	div.innerHTML = html;

	var elements = div.getElementsByTagName('address');
	for(var i=0; i<elements.length; i++) {
		var address = elements[i];
		callAPIFunction(address.innerHTML, hotelId);
	}
}

function getHRSHotelAddress(hotelItem, hotelId)
{
	var url = 'http://www.hrs.de' + hotelItem;

	var xhr = new XMLHttpRequest();
	xhr.open('GET', url, true);
	xhr.onload = function (e) {
		if (xhr.readyState === 4) {
			if (xhr.status === 200) {
				scrapeHRSHotelAddress(xhr.responseText, hotelId);
			}
		}
	};
	xhr.send(null);
}

var hotelsObserver = new MutationObserver(function(mutations) {
	mutations.forEach(function(mutation) {
		for(var i = 0; i < mutation.addedNodes.length; i++)
		{
			var addedNode = mutation.addedNodes[i];
			if (addedNode.getAttribute("data-hpos"))
			{
				var hotelNode = addedNode;
				var hotelId = hotelNode.getAttribute("id");
				var dists = hotelNode.getElementsByClassName('distances_centered');
//				console.log("Added hotel with id [" + hotelId + "].");

				if(dists.length > 0) {
					var hotelItem = hotelNode.getAttribute("data-hotelitemurl");
					getHRSHotelAddress(hotelItem,hotelId);
				}

				distancesObserver.observe(hotelNode, { childList: true });
			}
		}
	})
});

var target = document.getElementById("containerAllHotels");

var config = { childList: true };

hotelsObserver.observe(target, config);
<|endoftext|>


<commit_before>module.exports =  {
  secondsToTime: function(secs) {
    secs = Math.round(secs);
    var hours = Math.floor(secs / (60 * 60));

    var divisor_for_minutes = secs % (60 * 60);
    var minutes = Math.floor(divisor_for_minutes / 60);

    var divisor_for_seconds = divisor_for_minutes % 60;
    var seconds = Math.ceil(divisor_for_seconds);

    var time = "";

    if(hours > 0) {
      time += hours + ":";
    }

    time += this.timeUnitFormat(minutes) + ":";
    time += this.timeUnitFormat(seconds);
    return time;
  },

  timeUnitFormat:function(time) {
    if (time < 1) {
      return "00";
    } else if (time < 10) {
      return "0" + time;
    } else {
      return time;
    }
  }
};<commit_msg>Removing mixins<commit_after><|endoftext|>


<commit_before>window.model = function () {

    var STATUS = {
        pass: "PASS",
        fail: "FAIL",
        notRun: "NOT RUN"
    };

    var KEYWORD_TYPE = {
        kw: 'KEYWORD',
        setup:'SETUP',
        teardown:'TEARDOWN'
    };

    function Suite(data) {
        var suite = createModelObject(data);
        suite.source = data.source;
        suite.fullName = data.parent ? data.parent.fullName + "." + data.name : data.name;
        setStats(suite, data.statistics);
        suite.metadata = data.metadata;
        suite.populateKeywords = createIterablePopulator("Keyword");
        suite.populateTests = createIterablePopulator("Test");
        suite.populateSuites = createIterablePopulator("Suite");
        suite.message = data.message;
        suite.children = function () {
            return suite.keywords().concat(suite.tests()).concat(suite.suites());
        };
        suite.hasTeardownFailure = function () {
            return suiteTeardownFailed(suite) || data.parentSuiteTeardownFailed;
        };
        suite.searchTests = function (predicate) {
            var tests = [];
            for (var i = 0; i < this.numberOfSuites; i++)
                tests = tests.concat(this.suite(i).searchTests(predicate));
            return tests.concat(util.filter(this.tests(), predicate));
        };
        suite.searchTestsByTag = function (tag) {
            return suite.searchTests(function (test) {
                if (tag.combined)
                    return containsTagPattern(test.tags, tag.combined);
                return containsTag(test.tags, tag.label);
            });
        };
        suite.findSuiteByName = function (name) {
            return findSuiteByName(suite, name);
        };
        suite.allTests = function () {
            return suite.searchTests(function (test) {
                return true;
            });
        };
        suite.criticalTests = function () {
            return suite.searchTests(function (test) {
                return test.isCritical;
            });
        };
        return suite;
    }

    function containsTag(testTags, tagname) {
        testTags = util.map(testTags, util.normalize);
        return util.contains(testTags, util.normalize(tagname));
    }

    function containsTagPattern(testTags, pattern) {
        testTags = util.map(testTags, util.normalize);
        if (pattern.indexOf('&') != -1) {
            var tagnames = pattern.split('&');
            return util.all(util.map(tagnames, function (name) {
                return containsTagPattern(testTags, name);
            }));
        }
        if (pattern.indexOf('NOT') != -1) {
            var tagnames = pattern.split('NOT');
            var required = tagnames[0];
            var notAllowed = tagnames.slice(1);
            return containsTagPattern(testTags, required) &&
                    util.all(util.map(notAllowed, function (name) {
                        return !containsTagPattern(testTags, name);
                    }));
        }
        var matcher = util.Matcher(pattern);
        return util.any(util.map(testTags, matcher.matches));
    }

    function findSuiteByName(suite, name) {
        if (suite.fullName == name)
            return suite;
        var subSuites = suite.suites();
        for (var i in subSuites) {
            var match = findSuiteByName(subSuites[i], name);
            if (match)
                return match;
        }
        return null;
    }

    function suiteTeardownFailed(suite) {
        if (suite.numberOfKeywords) {
            var kw = suite.keyword(suite.numberOfKeywords - 1);
            if (kw.type == KEYWORD_TYPE.teardown)
                return kw.status == STATUS.fail;
        }
        return false;
    }

    function setStats(suite, stats) {
        for (var name in stats) {
            suite[name] = stats[name];
        }
    }

    function createModelObject(data) {
        return {
            name: data.name,
            doc: data.doc,
            status: data.status,
            times: data.times
        };
    }

    function Test(data) {
        var test = createModelObject(data);
        test.fullName = data.parent.fullName + "." + test.name;
        test.formatParentName = function () { return util.formatParentName(test); };
        test.timeout = data.timeout;
        test.populateKeywords = createIterablePopulator("Keyword");
        test.children = function () {
            return test.keywords();
        };
        test.isCritical = data.isCritical;
        test.tags = data.tags;
        test.message = data.message;
        return test;
    }

    function Keyword(data) {
        var kw = createModelObject(data);
        kw.type = data.type;
        var parent = data.parent
        var parentPath = (parent.path === undefined) ? parent.fullName : parent.path;
        kw.path = parentPath + "." + data.index;
        kw.arguments = data.args;
        console.log(kw.arguments);
        kw.populateKeywords = createIterablePopulator("Keyword");
        kw.populateMessages = createIterablePopulator("Message");
        kw.children = function () {
            return kw.keywords();
        };
        return kw;
    }

    function Message(level, time, text, link) {
        var message = {};
        message.level = level;
        message.levelText = level.toUpperCase();
        message.time = time;
        message.shortTime = function () {
            return timeFromDate(message.time);
        };
        message.date = function () {
            return formatDate(message.time);
        };
        message.text = text;
        message.link = link;
        return message;
    }

    function Times(timedata) {
        var start = timedata[0];
        var end = timedata[1];
        var elapsed = timedata[2];
        return {
            elapsedMillis: elapsed,
            elapsedTime: formatElapsed(elapsed),
            startTime: formatDate(start),
            endTime:  formatDate(end)
        };
    }

    function timeFromDate(date) {
        if (!date)
            return "N/A"
        return shortTime(date.getHours(), date.getMinutes(),
                         date.getSeconds(), date.getMilliseconds());
    }

    function formatDate(date) {
        if (!date)
            return "N/A"
        return padTo(date.getFullYear(), 4) +
               padTo(date.getMonth() + 1, 2) +
               padTo(date.getDate(), 2) + " " +
               shortTime(date.getHours(), date.getMinutes(),
                         date.getSeconds(), date.getMilliseconds());
    }

    function shortTime(hours, minutes, seconds, milliseconds) {
        return padTo(hours, 2) + ":" +
               padTo(minutes, 2) + ":" +
               padTo(seconds, 2) + "." +
               padTo(milliseconds, 3);
    }

    function formatElapsed(elapsed) {
        var millis = elapsed;
        var hours = Math.floor(millis / (60 * 60 * 1000));
        millis -= hours * 60 * 60 * 1000;
        var minutes = Math.floor(millis / (60 * 1000));
        millis -= minutes * 60 * 1000;
        var seconds = Math.floor(millis / 1000);
        millis -= seconds * 1000;
        return shortTime(hours, minutes, seconds, millis);
    }

    function padTo(number, len) {
        var numString = number + "";
        while (numString.length < len) numString = "0" + numString;
        return numString;
    }

    function createIterablePopulator(name) {
        return function (populator) {
            populateIterable(this, name, populator);
        };
    }

    function populateIterable(obj, name, populator) {
        obj["numberOf" + name + "s"] = populator.numberOfItems;
        var nameInLowerCase = name.toLowerCase();
        obj[nameInLowerCase] = createGetFunction(populator.numberOfItems, populator.creator);
        obj[nameInLowerCase + "s"] = createGetAllFunction(populator.numberOfItems, obj[nameInLowerCase]);
    }

    function createGetFunction(numberOfElements, creator) {
        var cache = new Array();
        return function (index) {
            if (numberOfElements <= index)
                return undefined;
            if (!cache[index])
                cache[index] = creator(index);
            return cache[index];
        };
    }

    function createGetAllFunction(numberOfElements, getter) {
        var cached = undefined;
        return function () {
            if (cached === undefined) {
                cached = [];
                for (var i = 0; i < numberOfElements; i++) {
                    cached.push(getter(i));
                }
            }
            return cached;
        };
    }

    return {
        Suite: Suite,
        Test: Test,
        Keyword: Keyword,
        Message: Message,
        Times: Times,
        PASS: STATUS.pass,
        FAIL: STATUS.fail,
        NOT_RUN: STATUS.notRun,
        formatElapsed: formatElapsed,
        containsTag: containsTag,  // Exposed for tests
        containsTagPattern: containsTagPattern,  // Exposed for tests
        shortTime: shortTime
    };
}();

window.stats = (function () {

    function Statistics(totalElems, tagElems, suiteElems){
        return {total: util.map(totalElems, statElem),
                tag:   util.map(tagElems, tagStatElem),
                suite: util.map(suiteElems, suiteStatElem)};
    }

    function statElem(stat) {
        stat.total = stat.pass + stat.fail;
        var percents = calculatePercents(stat.total, stat.pass, stat.fail);
        stat.passPercent = percents[0];
        stat.failPercent = percents[1];
        var widths = calculateWidths(stat.passPercent, stat.failPercent);
        stat.passWidth = widths[0];
        stat.failWidth = widths[1];
        return stat;
    }

    function tagStatElem(data) {
        var stat = statElem(data);
        stat.links = parseLinks(stat.links);
        return stat;
    }

    function suiteStatElem(data) {
        var stat = statElem(data);
        stat.fullName = stat.label;
        stat.formatParentName = function () { return util.formatParentName(stat); };
        // compatibility with RF 2.5 outputs
        if (!stat.name)
            stat.name = stat.label.split('.').pop();
        return stat;
    }

    function parseLinks(linksData) {
        if (!linksData)
            return [];
        return util.map(linksData.split(':::'), function (link) {
                var index = link.indexOf(':');
                return {title: link.slice(0, index), url: link.slice(index+1)};
            });
    }

    function calculatePercents(total, passed, failed) {
        if (total == 0)
            return [0.0, 0.0];
        pass = 100.0 * passed / total;
        fail = 100.0 * failed / total;
        if (pass > 0 && pass < 0.1)
            return [0.1, 99.9];
        if (fail > 0 && fail < 0.1)
            return [99.9, 0.1];
        return [Math.round(pass*10)/10, Math.round(fail*10)/10];
    }

    function calculateWidths(num1, num2) {
        if (num1 + num2 == 0)
            return [0.0, 0.0];
        // Make small percentages better visible
        if (num1 > 0 && num1 < 1)
            return [1.0, 99.0];
        if (num2 > 0 && num2 < 1)
            return [99.0, 1.0];
        // Handle situation where both are rounded up
        while (num1 + num2 > 100) {
            if (num1 > num2)
                num1 -= 0.1;
            if (num2 > num1)
                num2 -= 0.1;
        }
        return [num1, num2];
    }

    return {
        Statistics: Statistics
    };

}());
<commit_msg>removed console log<commit_after>window.model = function () {

    var STATUS = {
        pass: "PASS",
        fail: "FAIL",
        notRun: "NOT RUN"
    };

    var KEYWORD_TYPE = {
        kw: 'KEYWORD',
        setup:'SETUP',
        teardown:'TEARDOWN'
    };

    function Suite(data) {
        var suite = createModelObject(data);
        suite.source = data.source;
        suite.fullName = data.parent ? data.parent.fullName + "." + data.name : data.name;
        setStats(suite, data.statistics);
        suite.metadata = data.metadata;
        suite.populateKeywords = createIterablePopulator("Keyword");
        suite.populateTests = createIterablePopulator("Test");
        suite.populateSuites = createIterablePopulator("Suite");
        suite.message = data.message;
        suite.children = function () {
            return suite.keywords().concat(suite.tests()).concat(suite.suites());
        };
        suite.hasTeardownFailure = function () {
            return suiteTeardownFailed(suite) || data.parentSuiteTeardownFailed;
        };
        suite.searchTests = function (predicate) {
            var tests = [];
            for (var i = 0; i < this.numberOfSuites; i++)
                tests = tests.concat(this.suite(i).searchTests(predicate));
            return tests.concat(util.filter(this.tests(), predicate));
        };
        suite.searchTestsByTag = function (tag) {
            return suite.searchTests(function (test) {
                if (tag.combined)
                    return containsTagPattern(test.tags, tag.combined);
                return containsTag(test.tags, tag.label);
            });
        };
        suite.findSuiteByName = function (name) {
            return findSuiteByName(suite, name);
        };
        suite.allTests = function () {
            return suite.searchTests(function (test) {
                return true;
            });
        };
        suite.criticalTests = function () {
            return suite.searchTests(function (test) {
                return test.isCritical;
            });
        };
        return suite;
    }

    function containsTag(testTags, tagname) {
        testTags = util.map(testTags, util.normalize);
        return util.contains(testTags, util.normalize(tagname));
    }

    function containsTagPattern(testTags, pattern) {
        testTags = util.map(testTags, util.normalize);
        if (pattern.indexOf('&') != -1) {
            var tagnames = pattern.split('&');
            return util.all(util.map(tagnames, function (name) {
                return containsTagPattern(testTags, name);
            }));
        }
        if (pattern.indexOf('NOT') != -1) {
            var tagnames = pattern.split('NOT');
            var required = tagnames[0];
            var notAllowed = tagnames.slice(1);
            return containsTagPattern(testTags, required) &&
                    util.all(util.map(notAllowed, function (name) {
                        return !containsTagPattern(testTags, name);
                    }));
        }
        var matcher = util.Matcher(pattern);
        return util.any(util.map(testTags, matcher.matches));
    }

    function findSuiteByName(suite, name) {
        if (suite.fullName == name)
            return suite;
        var subSuites = suite.suites();
        for (var i in subSuites) {
            var match = findSuiteByName(subSuites[i], name);
            if (match)
                return match;
        }
        return null;
    }

    function suiteTeardownFailed(suite) {
        if (suite.numberOfKeywords) {
            var kw = suite.keyword(suite.numberOfKeywords - 1);
            if (kw.type == KEYWORD_TYPE.teardown)
                return kw.status == STATUS.fail;
        }
        return false;
    }

    function setStats(suite, stats) {
        for (var name in stats) {
            suite[name] = stats[name];
        }
    }

    function createModelObject(data) {
        return {
            name: data.name,
            doc: data.doc,
            status: data.status,
            times: data.times
        };
    }

    function Test(data) {
        var test = createModelObject(data);
        test.fullName = data.parent.fullName + "." + test.name;
        test.formatParentName = function () { return util.formatParentName(test); };
        test.timeout = data.timeout;
        test.populateKeywords = createIterablePopulator("Keyword");
        test.children = function () {
            return test.keywords();
        };
        test.isCritical = data.isCritical;
        test.tags = data.tags;
        test.message = data.message;
        return test;
    }

    function Keyword(data) {
        var kw = createModelObject(data);
        kw.type = data.type;
        var parent = data.parent
        var parentPath = (parent.path === undefined) ? parent.fullName : parent.path;
        kw.path = parentPath + "." + data.index;
        kw.arguments = data.args;
        kw.populateKeywords = createIterablePopulator("Keyword");
        kw.populateMessages = createIterablePopulator("Message");
        kw.children = function () {
            return kw.keywords();
        };
        return kw;
    }

    function Message(level, time, text, link) {
        var message = {};
        message.level = level;
        message.levelText = level.toUpperCase();
        message.time = time;
        message.shortTime = function () {
            return timeFromDate(message.time);
        };
        message.date = function () {
            return formatDate(message.time);
        };
        message.text = text;
        message.link = link;
        return message;
    }

    function Times(timedata) {
        var start = timedata[0];
        var end = timedata[1];
        var elapsed = timedata[2];
        return {
            elapsedMillis: elapsed,
            elapsedTime: formatElapsed(elapsed),
            startTime: formatDate(start),
            endTime:  formatDate(end)
        };
    }

    function timeFromDate(date) {
        if (!date)
            return "N/A"
        return shortTime(date.getHours(), date.getMinutes(),
                         date.getSeconds(), date.getMilliseconds());
    }

    function formatDate(date) {
        if (!date)
            return "N/A"
        return padTo(date.getFullYear(), 4) +
               padTo(date.getMonth() + 1, 2) +
               padTo(date.getDate(), 2) + " " +
               shortTime(date.getHours(), date.getMinutes(),
                         date.getSeconds(), date.getMilliseconds());
    }

    function shortTime(hours, minutes, seconds, milliseconds) {
        return padTo(hours, 2) + ":" +
               padTo(minutes, 2) + ":" +
               padTo(seconds, 2) + "." +
               padTo(milliseconds, 3);
    }

    function formatElapsed(elapsed) {
        var millis = elapsed;
        var hours = Math.floor(millis / (60 * 60 * 1000));
        millis -= hours * 60 * 60 * 1000;
        var minutes = Math.floor(millis / (60 * 1000));
        millis -= minutes * 60 * 1000;
        var seconds = Math.floor(millis / 1000);
        millis -= seconds * 1000;
        return shortTime(hours, minutes, seconds, millis);
    }

    function padTo(number, len) {
        var numString = number + "";
        while (numString.length < len) numString = "0" + numString;
        return numString;
    }

    function createIterablePopulator(name) {
        return function (populator) {
            populateIterable(this, name, populator);
        };
    }

    function populateIterable(obj, name, populator) {
        obj["numberOf" + name + "s"] = populator.numberOfItems;
        var nameInLowerCase = name.toLowerCase();
        obj[nameInLowerCase] = createGetFunction(populator.numberOfItems, populator.creator);
        obj[nameInLowerCase + "s"] = createGetAllFunction(populator.numberOfItems, obj[nameInLowerCase]);
    }

    function createGetFunction(numberOfElements, creator) {
        var cache = new Array();
        return function (index) {
            if (numberOfElements <= index)
                return undefined;
            if (!cache[index])
                cache[index] = creator(index);
            return cache[index];
        };
    }

    function createGetAllFunction(numberOfElements, getter) {
        var cached = undefined;
        return function () {
            if (cached === undefined) {
                cached = [];
                for (var i = 0; i < numberOfElements; i++) {
                    cached.push(getter(i));
                }
            }
            return cached;
        };
    }

    return {
        Suite: Suite,
        Test: Test,
        Keyword: Keyword,
        Message: Message,
        Times: Times,
        PASS: STATUS.pass,
        FAIL: STATUS.fail,
        NOT_RUN: STATUS.notRun,
        formatElapsed: formatElapsed,
        containsTag: containsTag,  // Exposed for tests
        containsTagPattern: containsTagPattern,  // Exposed for tests
        shortTime: shortTime
    };
}();

window.stats = (function () {

    function Statistics(totalElems, tagElems, suiteElems){
        return {total: util.map(totalElems, statElem),
                tag:   util.map(tagElems, tagStatElem),
                suite: util.map(suiteElems, suiteStatElem)};
    }

    function statElem(stat) {
        stat.total = stat.pass + stat.fail;
        var percents = calculatePercents(stat.total, stat.pass, stat.fail);
        stat.passPercent = percents[0];
        stat.failPercent = percents[1];
        var widths = calculateWidths(stat.passPercent, stat.failPercent);
        stat.passWidth = widths[0];
        stat.failWidth = widths[1];
        return stat;
    }

    function tagStatElem(data) {
        var stat = statElem(data);
        stat.links = parseLinks(stat.links);
        return stat;
    }

    function suiteStatElem(data) {
        var stat = statElem(data);
        stat.fullName = stat.label;
        stat.formatParentName = function () { return util.formatParentName(stat); };
        // compatibility with RF 2.5 outputs
        if (!stat.name)
            stat.name = stat.label.split('.').pop();
        return stat;
    }

    function parseLinks(linksData) {
        if (!linksData)
            return [];
        return util.map(linksData.split(':::'), function (link) {
                var index = link.indexOf(':');
                return {title: link.slice(0, index), url: link.slice(index+1)};
            });
    }

    function calculatePercents(total, passed, failed) {
        if (total == 0)
            return [0.0, 0.0];
        pass = 100.0 * passed / total;
        fail = 100.0 * failed / total;
        if (pass > 0 && pass < 0.1)
            return [0.1, 99.9];
        if (fail > 0 && fail < 0.1)
            return [99.9, 0.1];
        return [Math.round(pass*10)/10, Math.round(fail*10)/10];
    }

    function calculateWidths(num1, num2) {
        if (num1 + num2 == 0)
            return [0.0, 0.0];
        // Make small percentages better visible
        if (num1 > 0 && num1 < 1)
            return [1.0, 99.0];
        if (num2 > 0 && num2 < 1)
            return [99.0, 1.0];
        // Handle situation where both are rounded up
        while (num1 + num2 > 100) {
            if (num1 > num2)
                num1 -= 0.1;
            if (num2 > num1)
                num2 -= 0.1;
        }
        return [num1, num2];
    }

    return {
        Statistics: Statistics
    };

}());
<|endoftext|>


<commit_before>import express from 'express'
import {check_authentication, validate_request} from '../utils/errors'
import {counter_model} from '../models/counter_model'
import {group_model} from '../models/group_model'
import {make_update_handler} from '../models/utils'

const all_counters_router = express.Router()
all_counters_router.param('group_id', (request, response, next_handler) => {
  request.checkParams('group_id', 'parameter is required').notEmpty()
  request
    .checkParams('group_id', 'parameter must be a MongoDB ObjectId')
    .isMongoId()

  validate_request(request, next_handler)
})
all_counters_router.route('/groups/:group_id/counters')
  .get(check_authentication, (request, response, next_handler) => {
    request
      .checkQuery(
        'start_timestamp',
        'parameter must be a timestamp in the ISO 8601 format'
      )
      .optional()
      .isDate()
    request
      .checkQuery('additional_counter', 'parameter must be a boolean')
      .optional()
      .isBoolean()

    request.sanitizeQuery('start_timestamp').toDate()
    request.sanitizeQuery('additional_counter').toBoolean()

    validate_request(request, next_handler)
  }, (request, response, next_handler) => {
    const query = {
      group_id: request.params.group_id,
    }
    if (request.query.start_timestamp instanceof Date) {
      query.timestamp = {
        $gte: request.query.start_timestamp,
      }
    }

    counter_model
      .find(query)
      .sort({
        timestamp: 'descending',
      })
      .then(counters => response.json({
        data: counters,
      }))
      .catch(next_handler)
  })
  .post(check_authentication, (request, response, next_handler) => {
    group_model
      .findById(request.params.group_id)
      .then(group => group.update(make_update_handler(
        response,
        next_handler
      )))
      .catch(next_handler)
  })

export const counter_router = express.Router()
counter_router.use(all_counters_router)
<commit_msg>Issue #36: extend GET /groups/:group_id/counters API endpoint<commit_after>import express from 'express'
import {check_authentication, validate_request} from '../utils/errors'
import {counter_model} from '../models/counter_model'
import {group_model} from '../models/group_model'
import {make_update_handler} from '../models/utils'

function request_counters(db_request, response, next_handler) {
  db_request
    .sort({
      timestamp: 'descending',
    })
    .then(counters => response.json({
      data: counters,
    }))
    .catch(next_handler)
}

const all_counters_router = express.Router()
all_counters_router.param('group_id', (request, response, next_handler) => {
  request.checkParams('group_id', 'parameter is required').notEmpty()
  request
    .checkParams('group_id', 'parameter must be a MongoDB ObjectId')
    .isMongoId()

  validate_request(request, next_handler)
})
all_counters_router.route('/groups/:group_id/counters')
  .get(check_authentication, (request, response, next_handler) => {
    request
      .checkQuery(
        'start_timestamp',
        'parameter must be a timestamp in the ISO 8601 format'
      )
      .optional()
      .isDate()
    request
      .checkQuery('additional_counter', 'parameter must be a boolean')
      .optional()
      .isBoolean()

    request.sanitizeQuery('start_timestamp').toDate()
    request.sanitizeQuery('additional_counter').toBoolean()

    validate_request(request, next_handler)
  }, (request, response, next_handler) => {
    const full_query = {
      group_id: request.params.group_id,
    }
    const short_query = Object.assign({}, full_query, {
      timestamp: {
        $gte: request.query.start_timestamp,
      },
    })
    if (typeof request.query.start_timestamp === 'undefined') {
      request_counters(counter_model.find(full_query), response, next_handler)
    } else if (
      typeof request.query.additional_counter === 'undefined'
      || !request.query.additional_counter
    ) {
      request_counters(counter_model.find(short_query), response, next_handler)
    } else {
      counter_model
        .count(short_query)
        .then(counters_number => request_counters(
          counter_model
            .find(full_query)
            .limit(counters_number + 1),
          response,
          next_handler
        ))
        .catch(next_handler)
    }
  })
  .post(check_authentication, (request, response, next_handler) => {
    group_model
      .findById(request.params.group_id)
      .then(group => group.update(make_update_handler(
        response,
        next_handler
      )))
      .catch(next_handler)
  })

export const counter_router = express.Router()
counter_router.use(all_counters_router)
<|endoftext|>