<commit_before>function motion(element) {
    var base = "https://res.cloudinary.com/demo/video/upload/so_0,du_3/vs_30,e_loop/w_260,h_105,c_fill/q_50,r_5,b_white/fl_lossy.animated,f_auto/";
    var suffix = ".gif";
    switchImage(element.getElementsByTagName('img')[0],element.id,base,suffix);
}
function still(element) {
	var base = "https://res.cloudinary.com/demo/video/upload/so_0,w_260,h_105,c_fill,r_5,b_white,q_auto,f_auto/";
	var suffix = ".jpg";
	switchImage(element.getElementsByTagName('img')[0],element.id,base,suffix);
}
function switchImage(elm,id,base,suffix) {
    switch (id) {
		case "sec01":
			elm.setAttribute('src', base+"rafting_short"+suffix);
			break;
		case "sec02":
			elm.setAttribute('src', base+"forest_bike"+suffix);
			break;
		case "sec03":
			elm.setAttribute('src', base+"snow_horses"+suffix);
			break;
		case "sec04":
			elm.setAttribute('src', base+"snow_deer"+suffix);
			break;
		default:
			console.log("switchImage id=",id);
		}
}

function toggleClass() {
    var theme = document.getElementById("theme-area");
    theme.classList.toggle("active");
}
function setTheme(btn) {
    var newTheme = "cld-video-player-skin-" + btn.value;
    var oldTheme = "cld-video-player-skin-";

    if(btn.value == "dark")
        oldTheme += "light";
    else
        oldTheme += "dark";

    var vplayers = document.getElementsByClassName("cld-video-player");
    for(var i = 0; i < vplayers.length; i++) {
        vplayers[i].classList.remove(oldTheme);
        vplayers[i].classList.add(newTheme);
    }
    toggleClass();
}

window.addEventListener('scroll',checkPosition,false);
function checkPosition()
{
    var themeArea = document.getElementById("theme-area");
    var fixedHeader = document.getElementById("header");
    if(window.scrollY > 50)
    {
        themeArea.classList.add("scrolling");
        fixedHeader.classList.add("fixed-position");
    } else {
        themeArea.classList.remove("scrolling");
        fixedHeader.classList.remove("fixed-position");
    }
}

function playerSizeChange(input) {
  var area = document.getElementById("video-area-adaptive");
  var border = document.getElementById("player-border");
  var val = input.value + "%";
  area.style.width = val;
  border.style.width = val;
  var pwidth = document.getElementById("player-width");
  pwidth.innerHTML = area.clientWidth;
}
function updateOnResize() {
  var width = demoplayer.videojs.videoWidth();
  var current = document.getElementById(width);
  var oldactive = document.getElementsByClassName("range-info active");
  for (var i = 0; i < oldactive.length; i++) {
    oldactive[i].setAttribute("class","range-info");
  }
  current.setAttribute("class","range-info active");
}
function requestResolution(btn) {
  if(!safari)
  {
    document.getElementById("checkbox").checked = false;
    document.getElementById("checkboxLabel").classList.add("disabled");
    for (var i = 0; i < qualityLevels.length; i++) {
      qualityLevels[i].enabled = (Number(btn.id) == qualityLevels[i].width);
    }
  }
}
function requestAuto() {
  var auto = document.getElementById("checkbox");
  console.log("requestAuto() ",auto.checked);
  if(auto.checked) {
    for (var i = 0; i < qualityLevels.length; i++) {
        qualityLevels[i].enabled = true;
    }
  }
  document.getElementById("checkboxLabel").classList.toggle("disabled");
}

function reportQuality() {
	for (var i = 0; i < qualityLevels.length; i++)
        	console.log("reportQuality",i,qualityLevels[i].width,qualityLevels[i].enabled);
}

function changeOfResolution() {
  var index = qualityLevels.selectedIndex;
  var res = document.getElementById(qualityLevels[index].width);
  var old = document.getElementsByClassName("range-info second-hover");
  for (var i = 0; i < old.length; i++) {
    old[i].setAttribute("class","range-info");
  }
  res.setAttribute("class","range-info second-hover");
}

function setProfile(profile) {
  updateResolutionRange(profile.value);
  demoplayer.source("kayak", { sourceTypes: ['hls'], transformation: {streaming_profile: profile.value } }).play();
}

function updateResolutionRange(profileVal) {
  var elements = document.getElementsByClassName('range-info');
  var i = elements.length;

    while(i--) {
        if(elements[i].getElementsByClassName(profileVal).length > 0)
          elements[i].setAttribute("class","range-info");
        else
          elements[i].setAttribute("class","range-info out-of-range");

    }
  document.getElementById("checkbox").checked = true;
  document.getElementById("checkboxLabel").classList.remove("disabled");
}

var mobile = window.matchMedia("(max-width: 1199px)");
openThemeSlide();
mobile.addListener(openThemeSlide);

function openThemeSlide() {
  var theme = document.getElementById("theme-area");
  if(mobile.matches)
    theme.classList.remove("active");
  else
    theme.classList.add("active");
}

var chrome   = navigator.userAgent.indexOf('Chrome') > -1;
var safari   = navigator.userAgent.indexOf("Safari") > -1;
if ((chrome) && (safari)) safari = false;

if(safari)
  document.getElementById("checkbox").disabled = true;

playerSizeChange(document.getElementById("player-slider"));

addLi();

var cld = cloudinary.Cloudinary.new({ cloud_name: 'demo' });

var adaptive = document.getElementById("adaptive");
document.getElementById("demo-adaptive-player").addEventListener('resize',updateOnResize, false);

var demoplayer = cld.videoPlayer('demo-adaptive-player');

var qualityLevels = demoplayer.videojs.qualityLevels();
qualityLevels.on('change', changeOfResolution);
// qualityLevels.on('addqualitylevel', function(event) { console.log(event.qualityLevel.width); });

if(window.innerWidth < 960) {
	document.getElementById('streaming4').checked = true;
	updateResolutionRange("sd");
	demoplayer.source("kayak", { sourceTypes: ['hls'],
				    transformation: {streaming_profile: 'sd' },
			  poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }}
                          });
}
else {
	demoplayer.source('kayak',{ sourceTypes: ['hls'],
                            transformation: {streaming_profile: 'full_hd' },
                            poster: { transformation: { width: 1920, crop: 'limit', quality: 'auto', fetch_format: 'auto' }}
                          });
}

function updateOnEvent(eventStr,automatic) {
  var list = document.getElementById('events-list');
  var entry = document.createElement('li');
  if(automatic)
      entry.className = "orange";
  entry.appendChild(document.createTextNode(eventStr));
  list.appendChild(entry);
  list.scrollTop = list.scrollHeight;
}

function checkTime(i) {
        return (i < 10) ? "0" + i : i;
    }

function startTime() {
        var today = new Date(),
            h = checkTime(today.getHours()),
            m = checkTime(today.getMinutes()),
            s = checkTime(today.getSeconds());
        return (h + ":" + m + ":" + s);
}

function addLi() {
  var resolutions = ['3840ul', '2560ul', '1920ul', '1280ul', '960ul', '640ul', '480ul', '320ul'];
  var li = null;
  for (var i = 0; i < resolutions.length; i++) {
      var res = resolutions[i];
      var ul = document.getElementById(res);
      for (var j = 0; j<11; j++) {
        li = document.createElement('li');
        if(j == 5 )
          li.className = "long";
        ul.appendChild(li);
      }
  }
}

var eventplayer = cld.videoPlayer('demo-events-player',
  { playedEventTimes: [3, 10],
    analytics: { // Enable player analytics
    events: [
    'play',
    'pause',
    'percentsplayed',
    'start',
    'ended',
    'fullscreenchange']}});

var autoEventTypes = ['sourcechanged', 'timeplayed', 'percentsplayed', 'ended'];

var manualEventTypes = ['play', 'pause', 'volumechange', 'mute', 'unmute', 'fullscreenchange',
      'seek'];

autoEventTypes.forEach(function(eventType) {
      eventplayer.on(eventType, function(event) {
        var eventStr = startTime() + " " + eventType;
        if (event.eventData) {
          eventStr = eventStr + ": " + JSON.stringify(event.eventData)
        }
        updateOnEvent(eventStr,true);
      })
    });

manualEventTypes.forEach(function(eventType) {
      eventplayer.on(eventType, function(event) {
        var eventStr = startTime() + " " + eventType;
        if (event.eventData) {
          eventStr = eventStr + ": " + JSON.stringify(event.eventData)
        }
        updateOnEvent(eventStr,false);
      })
    });

 eventplayer.source('forest_bike',{ sourceTypes: ['hls'],
                                    transformation: {streaming_profile: 'full_hd' },
                                    poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }}
                                  });

var plistplayer = cld.videoPlayer('demo-playlist-player',{
  playlistWidget: {
    direction: "horizontal",
    total: 4
  }});

var psource1 = { publicId: 'snow_horses', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Horses', subtitle: 'Snow Horses Movie' } };
var psource2 = { publicId: 'snow_deer', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Deer', subtitle: 'Snow Deer Movie' } };
var psource3 = { publicId: 'sea_turtle', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Sea Turtle', subtitle: 'Sea Turtle Movie' } };
var psource4 = { publicId: 'elephants', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
	       poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Elephants', subtitle: 'Elephants' } };

plistplayer.playlist([psource1, psource2, psource3, psource4], { autoAdvance: 0, repeat: true, presentUpcoming: 5 });

var recplayer = cld.videoPlayer('demo-recommendation-player',{ autoShowRecommendations: true });

var source1 = { publicId: 'snow_deer_short', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Deer', subtitle: 'Snow Deer Movie' } };
var source2 = { publicId: 'snow_horses', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Horses', subtitle: 'Snow Horses Movie' } };
var source3 = { publicId: 'sea_turtle', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Sea Turtle', subtitle: 'Sea Turtle Movie' } };
var source4 = { publicId: 'elephants', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
	       poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Elephants', subtitle: 'Elephants' } };
var source5 = { publicId: 'marmots', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Marmots', subtitle: 'Marmots' } };

source1.recommendations = [source2];
source2.recommendations = [source3];
source3.recommendations = [source4, source5, source1, source2];
source4.recommendations = [source5];
source5.recommendations = [source2, source3, source4, source1];
var first = true;
recplayer.on('sourcechanged', function(event) {if (first) {first = false;} else {recplayer.play();}});
recplayer.source(source3);
var adTagUrl = ["https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear&correlator=6",
"https://googleads.g.doubleclick.net/pagead/ads?ad_type=image_text_flash&client=ca-video-pub-4968145218643279&videoad_start_delay=0&description_url=http%3A%2F%2Fwww.google.com&max_ad_duration=40000&adtest=on",
"https://res.cloudinary.com/demo/raw/upload/vastdemo_preroll"];
 var adsplayer = cld.videoPlayer('demo-ads-player', {ads: {adTagUrl: adTagUrl[0]}});
var adsPlaylistSources = [source1, source2, source3, source4, source5];
var adsPlaylistOptions = {
  autoAdvance: true,
  repeat: true,
  presentUpcoming: 8
};
adsplayer.playlist(adsPlaylistSources, adsPlaylistOptions);

function setVAST(vastOption) {
  var option = Number(vastOption.value)
  if(option < adTagUrl.length)
  {
    adsplayer.ima().playAd(adTagUrl[option]);
  }
}
<commit_msg>Update main.js<commit_after>function motion(element) {
    var base = "https://res.cloudinary.com/demo/video/upload/so_0,du_3/vs_30,e_loop/w_260,h_105,c_fill/q_50,r_5,b_white/fl_lossy.animated,f_auto/";
    var suffix = ".gif";
    switchImage(element.getElementsByTagName('img')[0],element.id,base,suffix);
}
function still(element) {
	var base = "https://res.cloudinary.com/demo/video/upload/so_0,w_260,h_105,c_fill,r_5,b_white,q_auto,f_auto/";
	var suffix = ".jpg";
	switchImage(element.getElementsByTagName('img')[0],element.id,base,suffix);
}
function switchImage(elm,id,base,suffix) {
    switch (id) {
		case "sec01":
			elm.setAttribute('src', base+"rafting_short"+suffix);
			break;
		case "sec02":
			elm.setAttribute('src', base+"forest_bike"+suffix);
			break;
		case "sec03":
			elm.setAttribute('src', base+"snow_horses"+suffix);
			break;
		case "sec04":
			elm.setAttribute('src', base+"snow_deer"+suffix);
			break;
		default:
			console.log("switchImage id=",id);
		}
}

function toggleClass() {
    var theme = document.getElementById("theme-area");
    theme.classList.toggle("active");
}
function setTheme(btn) {
    var newTheme = "cld-video-player-skin-" + btn.value;
    var oldTheme = "cld-video-player-skin-";

    if(btn.value == "dark")
        oldTheme += "light";
    else
        oldTheme += "dark";

    var vplayers = document.getElementsByClassName("cld-video-player");
    for(var i = 0; i < vplayers.length; i++) {
        vplayers[i].classList.remove(oldTheme);
        vplayers[i].classList.add(newTheme);
    }
    toggleClass();
}

window.addEventListener('scroll',checkPosition,false);
function checkPosition()
{
    var themeArea = document.getElementById("theme-area");
    var fixedHeader = document.getElementById("header");
    if(window.scrollY > 50)
    {
        themeArea.classList.add("scrolling");
        fixedHeader.classList.add("fixed-position");
    } else {
        themeArea.classList.remove("scrolling");
        fixedHeader.classList.remove("fixed-position");
    }
}

function playerSizeChange(input) {
  var area = document.getElementById("video-area-adaptive");
  var border = document.getElementById("player-border");
  var val = input.value + "%";
  area.style.width = val;
  border.style.width = val;
  var pwidth = document.getElementById("player-width");
  pwidth.innerHTML = area.clientWidth;
}
function updateOnResize() {
  var width = demoplayer.videojs.videoWidth();
  var current = document.getElementById(width);
  var oldactive = document.getElementsByClassName("range-info active");
  for (var i = 0; i < oldactive.length; i++) {
    oldactive[i].setAttribute("class","range-info");
  }
  current.setAttribute("class","range-info active");
}
function requestResolution(btn) {
  if(!safari)
  {
    document.getElementById("checkbox").checked = false;
    document.getElementById("checkboxLabel").classList.add("disabled");
    for (var i = 0; i < qualityLevels.length; i++) {
      qualityLevels[i].enabled = (Number(btn.id) == qualityLevels[i].width);
    }
  }
}
function requestAuto() {
  var auto = document.getElementById("checkbox");
  console.log("requestAuto() ",auto.checked);
  if(auto.checked) {
    for (var i = 0; i < qualityLevels.length; i++) {
        qualityLevels[i].enabled = true;
    }
  }
  document.getElementById("checkboxLabel").classList.toggle("disabled");
}

function reportQuality() {
	for (var i = 0; i < qualityLevels.length; i++)
        	console.log("reportQuality",i,qualityLevels[i].width,qualityLevels[i].enabled);
}

function changeOfResolution() {
  var index = qualityLevels.selectedIndex;
  var res = document.getElementById(qualityLevels[index].width);
  var old = document.getElementsByClassName("range-info second-hover");
  for (var i = 0; i < old.length; i++) {
    old[i].setAttribute("class","range-info");
  }
  res.setAttribute("class","range-info second-hover");
}

function setProfile(profile) {
  updateResolutionRange(profile.value);
  demoplayer.source("kayak", { sourceTypes: ['hls'], transformation: {streaming_profile: profile.value } }).play();
}

function updateResolutionRange(profileVal) {
  var elements = document.getElementsByClassName('range-info');
  var i = elements.length;

    while(i--) {
        if(elements[i].getElementsByClassName(profileVal).length > 0)
          elements[i].setAttribute("class","range-info");
        else
          elements[i].setAttribute("class","range-info out-of-range");

    }
  document.getElementById("checkbox").checked = true;
  document.getElementById("checkboxLabel").classList.remove("disabled");
}

var mobile = window.matchMedia("(max-width: 1199px)");
openThemeSlide();
mobile.addListener(openThemeSlide);

function openThemeSlide() {
  var theme = document.getElementById("theme-area");
  if(mobile.matches)
    theme.classList.remove("active");
  else
    theme.classList.add("active");
}

var chrome   = navigator.userAgent.indexOf('Chrome') > -1;
var safari   = navigator.userAgent.indexOf("Safari") > -1;
if ((chrome) && (safari)) safari = false;

if(safari)
  document.getElementById("checkbox").disabled = true;

playerSizeChange(document.getElementById("player-slider"));

addLi();

var cld = cloudinary.Cloudinary.new({ cloud_name: 'demo' });

var adaptive = document.getElementById("adaptive");
document.getElementById("demo-adaptive-player").addEventListener('resize',updateOnResize, false);

var demoplayer = cld.videoPlayer('demo-adaptive-player');

var qualityLevels = demoplayer.videojs.qualityLevels();
qualityLevels.on('change', changeOfResolution);
// qualityLevels.on('addqualitylevel', function(event) { console.log(event.qualityLevel.width); });

if(window.innerWidth < 960) {
	document.getElementById('streaming4').checked = true;
	updateResolutionRange("sd");
	demoplayer.source("kayak", { sourceTypes: ['hls'],
				    transformation: {streaming_profile: 'sd' },
			  poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }}
                          });
}
else {
	demoplayer.source('kayak',{ sourceTypes: ['hls'],
                            transformation: {streaming_profile: 'full_hd' },
                            poster: { transformation: { width: 1920, crop: 'limit', quality: 'auto', fetch_format: 'auto' }}
                          });
}

function updateOnEvent(eventStr,automatic) {
  var list = document.getElementById('events-list');
  var entry = document.createElement('li');
  if(automatic)
      entry.className = "orange";
  entry.appendChild(document.createTextNode(eventStr));
  list.appendChild(entry);
  list.scrollTop = list.scrollHeight;
}

function checkTime(i) {
        return (i < 10) ? "0" + i : i;
    }

function startTime() {
        var today = new Date(),
            h = checkTime(today.getHours()),
            m = checkTime(today.getMinutes()),
            s = checkTime(today.getSeconds());
        return (h + ":" + m + ":" + s);
}

function addLi() {
  var resolutions = ['3840ul', '2560ul', '1920ul', '1280ul', '960ul', '640ul', '480ul', '320ul'];
  var li = null;
  for (var i = 0; i < resolutions.length; i++) {
      var res = resolutions[i];
      var ul = document.getElementById(res);
      for (var j = 0; j<11; j++) {
        li = document.createElement('li');
        if(j == 5 )
          li.className = "long";
        ul.appendChild(li);
      }
  }
}

var eventplayer = cld.videoPlayer('demo-events-player',
  { playedEventTimes: [3, 10],
    analytics: { // Enable player analytics
    events: [
    'play',
    'pause',
    'percentsplayed',
    'start',
    'ended',
    'fullscreenchange']}});

var autoEventTypes = ['sourcechanged', 'timeplayed', 'percentsplayed', 'ended'];

var manualEventTypes = ['play', 'pause', 'volumechange', 'mute', 'unmute', 'fullscreenchange',
      'seek'];

autoEventTypes.forEach(function(eventType) {
      eventplayer.on(eventType, function(event) {
        var eventStr = startTime() + " " + eventType;
        if (event.eventData) {
          eventStr = eventStr + ": " + JSON.stringify(event.eventData)
        }
        updateOnEvent(eventStr,true);
      })
    });

manualEventTypes.forEach(function(eventType) {
      eventplayer.on(eventType, function(event) {
        var eventStr = startTime() + " " + eventType;
        if (event.eventData) {
          eventStr = eventStr + ": " + JSON.stringify(event.eventData)
        }
        updateOnEvent(eventStr,false);
      })
    });

 eventplayer.source('forest_bike',{ sourceTypes: ['hls'],
                                    transformation: {streaming_profile: 'full_hd' },
                                    poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }}
                                  });

var plistplayer = cld.videoPlayer('demo-playlist-player',{
  playlistWidget: {
    direction: "horizontal",
    total: 4
  }});

var psource1 = { publicId: 'snow_horses', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Horses', subtitle: 'Snow Horses Movie' } };
var psource2 = { publicId: 'snow_deer', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Deer', subtitle: 'Snow Deer Movie' } };
var psource3 = { publicId: 'sea_turtle', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Sea Turtle', subtitle: 'Sea Turtle Movie' } };
var psource4 = { publicId: 'elephants', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
	       poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Elephants', subtitle: 'Elephants' } };

plistplayer.playlist([psource1, psource2, psource3, psource4], { autoAdvance: 0, repeat: true, presentUpcoming: 5 });

var recplayer = cld.videoPlayer('demo-recommendation-player',{ autoShowRecommendations: true });

var source1 = { publicId: 'snow_deer_short', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Deer', subtitle: 'Snow Deer Movie' } };
var source2 = { publicId: 'snow_horses', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Snow Horses', subtitle: 'Snow Horses Movie' } };
var source3 = { publicId: 'sea_turtle', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Sea Turtle', subtitle: 'Sea Turtle Movie' } };
var source4 = { publicId: 'elephants', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
	       poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Elephants', subtitle: 'Elephants' } };
var source5 = { publicId: 'marmots', sourceTypes: ['hls'], transformation: {streaming_profile: 'full_hd'},
               poster: { transformation: { width: 960, crop: 'limit', quality: 'auto', fetch_format: 'auto' }},
               info: { title: 'Marmots', subtitle: 'Marmots' } };

source1.recommendations = [source2];
source2.recommendations = [source3];
source3.recommendations = [source4, source5, source1, source2];
source4.recommendations = [source5];
source5.recommendations = [source2, source3, source4, source1];
var first = true;
recplayer.on('sourcechanged', function(event) {if (first) {first = false;} else {recplayer.play();}});
recplayer.source(source3);
var adTagUrl = ["https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear&correlator=6",
"https://googleads.g.doubleclick.net/pagead/ads?ad_type=image_text_flash&client=ca-video-pub-4968145218643279&videoad_start_delay=0&description_url=http%3A%2F%2Fwww.google.com&max_ad_duration=40000&adtest=on",
"https://res.cloudinary.com/demo/raw/upload/vastdemo_preroll"];
 var adsplayer = cld.videoPlayer('demo-ads-player', {ads: {adTagUrl: adTagUrl[0]}});
var adsPlaylistSources = [source1, source2, source3, source4, source5];
var adsPlaylistOptions = {
  autoAdvance: true,
  repeat: true,
  presentUpcoming: 8
};
adsplayer.playlist(adsPlaylistSources, adsPlaylistOptions);

function setVAST(vastOption) {
  var option = Number(vastOption.value)
  if(option < adTagUrl.length)
  {
    initializePlayer(adTagUrl[option]);
  }
}

function initializePlayer(adTag) {
	if (adsplayer) {
	  adsplayer.dispose();
	  var continer = document.getElementById('video-ads');
	  var vid = document.createElement('video');
	  vid.id = 'demo-ads-player',
	  vid.controls = true;
	  vid.muted = true;
	  vid.autoplay = true;
	  vid.classList.add(['cld-video-player', 'cld-video-player-skin-dark', 'cld-fluid']);
	  vid.setAttribute('data-cld-transformation', '{ "width": 720, "crop": "limit" }');
	  continer.appendChild(vid);
	}
	player = cld.videoPlayer("demo-ads-player", {ads: {adTagUrl: adTag}});
	player.source("rafting");
}

<|endoftext|>


<commit_before>/**
 * Contains the custom text and tooltip title tests
 * These tests ensure the text-* and text-title-* attributes are applied correctly
 */
describe('Angular-Paging: Custom Text and Tooltip Title Tests', function() {

    // Global Variable Declaration
    var scope, paging, compile;

    /**
    * This helps to quickly set scope values
    * And update the paging directive per test
    */
    var recompile = function(){

        // Set our test template markup
        var template =
            '<div paging ' +
                'page="currentPage" ' +
                'page-size="pageSize" ' +
                'total="total" ' +
                'show-prev-next="{{showPrevNext}}" ' +
                'text-first="{{textFirst}}" ' +
                'text-last="{{textLast}}" ' +
                'text-next="{{textNext}}" ' +
                'text-prev="{{textPrev}}" ' +
                'text-title-page="{{textTitlePage}}" ' +
                'text-title-first="{{textTitleFirst}}" ' +
                'text-title-last="{{textTitleLast}}" ' +
                'text-title-next="{{textTitleNext}}" ' +
                'text-title-prev="{{textTitlePrev}}" ' +
            '
';

        paging = compile(template)(scope);
        scope.$digest();
    };

    /**
    * Add our paging directive module to the tests
    */
    beforeEach(module('bw.paging'));

    /**
    * Inject the default and setup values to the test
    */
    beforeEach(inject(function($rootScope, $compile) {

        // Set compile
        compile = $compile;

        // Set default scope values
        scope = $rootScope.$new();
        scope.currentPage = 1;
        scope.pageSize = 10;
        scope.total = 50;
        scope.showPrevNext = true;
        recompile();

    }));

    it('Should assign the default text and title tool tip values', function(){

        // Hook in our click action
        var li = paging.find('li');
        var first = li.eq(0);
        var prev = li.eq(1);
        var next = li.eq(li.length - 2);
        var last = li.eq(li.length - 1);

        // Test that our values are equal to the defaul values
        expect(first.text().trim()).toEqual('<<');
        expect(first.attr('title')).toEqual('First Page');

        expect(prev.text().trim()).toEqual('<');
        expect(prev.attr('title')).toEqual('Previous Page');

        expect(next.text().trim()).toEqual('>');
        expect(next.attr('title')).toEqual('Next Page');

        expect(last.text().trim()).toEqual('>>');
        expect(last.attr('title')).toEqual('Last Page');

    });

    it('Should assign the custom text and title tool tip values', function(){

        // Test text variables
        var textFirst = 'Custom First';
        var textLast = 'Custom Last';
        var textNext = 'Custom Next';
        var textPrev = 'Custom Prev';

        // Test title text variables
        var textTitlePage = "Custom Page Title"
        var textTitleFirst = "Custom First Title"
        var textTitleLast = "Custom Last Title"
        var textTitleNext = "Custom Next Title"
        var textTitlePrev = "Custom Prev Title"

        // Baseline our scope
        scope.textFirst = textFirst;
        scope.textLast = textLast;
        scope.textNext = textNext;
        scope.textPrev =textPrev;

        scope.textTitlePage = textTitlePage;
        scope.textTitleFirst = textTitleFirst;
        scope.textTitleLast = textTitleLast;
        scope.textTitleNext =textTitleNext;
        scope.textTitlePrev =textTitlePrev;

        recompile();

        // Hook in our click action
        var li = paging.find('li');
        var page = li.eq(4);
        var first = li.eq(0);
        var prev = li.eq(1);
        var next = li.eq(li.length - 2);
        var last = li.eq(li.length - 1);

        // Test that our values are equal to the defaul values
        expect(first.text().trim()).toEqual(textFirst);
        expect(first.attr('title')).toEqual(textTitleFirst);

        expect(prev.text().trim()).toEqual(textPrev);
        expect(prev.attr('title')).toEqual(textTitlePrev);

        expect(next.text().trim()).toEqual(textNext);
        expect(next.attr('title')).toEqual(textTitleNext);

        expect(last.text().trim()).toEqual(textLast);
        expect(last.attr('title')).toEqual(textTitleLast);

    });

    it('Should replace {page} for the actual page number in title text', function(){

        // Page to test against
        var pageIndex = 4;
        var pageTitleIndex = 3

        // Baseline our scope
        scope.textTitlePage = 'Page {page} and Again {page}';
        recompile();

        // Hook in our click action
        var li = paging.find('li');
        var pageItem = li.eq(pageIndex);

        // Check that our page has been replaced correctly
        expect(pageItem.attr('title')).toEqual('Page ' + pageTitleIndex + ' and Again ' + pageTitleIndex);

    });

});
<commit_msg>Adding text test to check for page number {page} replace in anchor link<commit_after>/**
 * Contains the custom text and tooltip title tests
 * These tests ensure the text-* and text-title-* attributes are applied correctly
 */
describe('Angular-Paging: Custom Text and Tooltip Title Tests', function() {

    // Global Variable Declaration
    var scope, paging, compile;

    /**
    * This helps to quickly set scope values
    * And update the paging directive per test
    */
    var recompile = function(){

        // Set our test template markup
        var template =
            '<div paging ' +
                'page="currentPage" ' +
                'page-size="pageSize" ' +
                'total="total" ' +
                'pg-href="{{pgHref}}" ' +
                'show-prev-next="{{showPrevNext}}" ' +
                'text-first="{{textFirst}}" ' +
                'text-last="{{textLast}}" ' +
                'text-next="{{textNext}}" ' +
                'text-prev="{{textPrev}}" ' +
                'text-title-page="{{textTitlePage}}" ' +
                'text-title-first="{{textTitleFirst}}" ' +
                'text-title-last="{{textTitleLast}}" ' +
                'text-title-next="{{textTitleNext}}" ' +
                'text-title-prev="{{textTitlePrev}}" ' +
            '
';

        paging = compile(template)(scope);
        scope.$digest();
    };

    /**
    * Add our paging directive module to the tests
    */
    beforeEach(module('bw.paging'));

    /**
    * Inject the default and setup values to the test
    */
    beforeEach(inject(function($rootScope, $compile) {

        // Set compile
        compile = $compile;

        // Set default scope values
        scope = $rootScope.$new();
        scope.currentPage = 1;
        scope.pageSize = 10;
        scope.total = 50;
        scope.showPrevNext = true;
        recompile();

    }));

    it('Should assign the default text and title tool tip values', function(){

        // Hook in our click action
        var li = paging.find('li');
        var first = li.eq(0);
        var prev = li.eq(1);
        var next = li.eq(li.length - 2);
        var last = li.eq(li.length - 1);

        // Test that our values are equal to the defaul values
        expect(first.text().trim()).toEqual('<<');
        expect(first.attr('title')).toEqual('First Page');

        expect(prev.text().trim()).toEqual('<');
        expect(prev.attr('title')).toEqual('Previous Page');

        expect(next.text().trim()).toEqual('>');
        expect(next.attr('title')).toEqual('Next Page');

        expect(last.text().trim()).toEqual('>>');
        expect(last.attr('title')).toEqual('Last Page');

    });

    it('Should assign the custom text and title tool tip values', function(){

        // Test text variables
        var textFirst = 'Custom First';
        var textLast = 'Custom Last';
        var textNext = 'Custom Next';
        var textPrev = 'Custom Prev';

        // Test title text variables
        var textTitlePage = "Custom Page Title"
        var textTitleFirst = "Custom First Title"
        var textTitleLast = "Custom Last Title"
        var textTitleNext = "Custom Next Title"
        var textTitlePrev = "Custom Prev Title"

        // Baseline our scope
        scope.textFirst = textFirst;
        scope.textLast = textLast;
        scope.textNext = textNext;
        scope.textPrev =textPrev;

        scope.textTitlePage = textTitlePage;
        scope.textTitleFirst = textTitleFirst;
        scope.textTitleLast = textTitleLast;
        scope.textTitleNext =textTitleNext;
        scope.textTitlePrev =textTitlePrev;

        recompile();

        // Hook in our click action
        var li = paging.find('li');
        var page = li.eq(4);
        var first = li.eq(0);
        var prev = li.eq(1);
        var next = li.eq(li.length - 2);
        var last = li.eq(li.length - 1);

        // Test that our values are equal to the defaul values
        expect(first.text().trim()).toEqual(textFirst);
        expect(first.attr('title')).toEqual(textTitleFirst);

        expect(prev.text().trim()).toEqual(textPrev);
        expect(prev.attr('title')).toEqual(textTitlePrev);

        expect(next.text().trim()).toEqual(textNext);
        expect(next.attr('title')).toEqual(textTitleNext);

        expect(last.text().trim()).toEqual(textLast);
        expect(last.attr('title')).toEqual(textTitleLast);

    });

    it('Should replace {page} for the actual page number in title text', function(){

        // Page to test against
        var pageIndex = 4;
        var pageTitleIndex = 3

        // Baseline our scope
        scope.textTitlePage = 'Page {page} and Again {page}';
        recompile();

        // Hook in our click action
        var li = paging.find('li');
        var pageItem = li.eq(pageIndex);

        // Check that our page has been replaced correctly
        expect(pageItem.attr('title')).toEqual('Page ' + pageTitleIndex + ' and Again ' + pageTitleIndex);

    });

    it('Should replace {page} for the actual page number in anchor link', function(){

        // Page to test against
        var pageIndex = 4;
        var pageTitleIndex = 3

        // Baseline our scope
        scope.pgHref = 'Goto {page} and Again {page}';
        recompile();

        // Hook in our click action
        var li = paging.find('a');
        var pageItem = li.eq(pageIndex);

        // Check that our page has been replaced correctly
        expect(pageItem.attr('href')).toEqual('Goto ' + pageTitleIndex + ' and Again ' + pageTitleIndex);

    });

});
<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError, RateLimitExceeded, ArgumentsRequired } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class coinfalcon extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'coinfalcon',
            'name': 'CoinFalcon',
            'countries': [ 'GB' ],
            'rateLimit': 1000,
            'version': 'v1',
            'has': {
                'cancelOrder': true,
                'createOrder': true,
                'fetchBalance': true,
                'fetchMarkets': true,
                'fetchMyTrades': true,
                'fetchOpenOrders': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchTicker': true,
                'fetchTickers': true,
                'fetchTrades': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/41822275-ed982188-77f5-11e8-92bb-496bcd14ca52.jpg',
                'api': 'https://coinfalcon.com',
                'www': 'https://coinfalcon.com',
                'doc': 'https://docs.coinfalcon.com',
                'fees': 'https://coinfalcon.com/fees',
                'referral': 'https://coinfalcon.com/?ref=CFJSVGTUPASB',
            },
            'api': {
                'public': {
                    'get': [
                        'markets',
                        'markets/{market}/orders',
                        'markets/{market}/trades',
                    ],
                },
                'private': {
                    'get': [
                        'user/accounts',
                        'user/orders',
                        'user/orders/{id}',
                        'user/trades',
                    ],
                    'post': [
                        'user/orders',
                    ],
                    'delete': [
                        'user/orders/{id}',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'maker': 0.0,
                    'taker': 0.002, // tiered fee starts at 0.2%
                },
            },
            'precision': {
                'amount': 8,
                'price': 8,
            },
        });
    }

    async fetchMarkets (params = {}) {
        const response = await this.publicGetMarkets (params);
        const markets = this.safeValue (response, 'data');
        const result = [];
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            const [ baseId, quoteId ] = market['name'].split ('-');
            const base = this.safeCurrencyCode (baseId);
            const quote = this.safeCurrencyCode (quoteId);
            const symbol = base + '/' + quote;
            const precision = {
                'amount': this.safeInteger (market, 'size_precision'),
                'price': this.safeInteger (market, 'price_precision'),
            };
            result.push ({
                'id': market['name'],
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': true,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': Math.pow (10, -precision['amount']),
                        'max': undefined,
                    },
                    'price': {
                        'min': Math.pow (10, -precision['price']),
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'info': market,
            });
        }
        return result;
    }

    parseTicker (ticker, market = undefined) {
        const marketId = this.safeString (ticker, 'name');
        const symbol = this.safeSymbol (marketId, market, '-');
        const timestamp = this.milliseconds ();
        const last = parseFloat (ticker['last_price']);
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': undefined,
            'low': undefined,
            'bid': undefined,
            'bidVolume': undefined,
            'ask': undefined,
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': this.safeFloat (ticker, 'change_in_24h'),
            'percentage': undefined,
            'average': undefined,
            'baseVolume': undefined,
            'quoteVolume': this.safeFloat (ticker, 'volume'),
            'info': ticker,
        };
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        const tickers = await this.fetchTickers (params);
        return tickers[symbol];
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        const response = await this.publicGetMarkets (params);
        const tickers = this.safeValue (response, 'data');
        const result = {};
        for (let i = 0; i < tickers.length; i++) {
            const ticker = this.parseTicker (tickers[i]);
            const symbol = ticker['symbol'];
            result[symbol] = ticker;
        }
        return this.filterByArray (result, 'symbol', symbols);
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'market': this.marketId (symbol),
            'level': '3',
        };
        const response = await this.publicGetMarketsMarketOrders (this.extend (request, params));
        const data = this.safeValue (response, 'data', {});
        return this.parseOrderBook (data, undefined, 'bids', 'asks', 'price', 'size');
    }

    parseTrade (trade, market = undefined) {
        const timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
        const price = this.safeFloat (trade, 'price');
        const amount = this.safeFloat (trade, 'size');
        const symbol = market['symbol'];
        let cost = undefined;
        if (price !== undefined) {
            if (amount !== undefined) {
                cost = parseFloat (this.costToPrecision (symbol, price * amount));
            }
        }
        const tradeId = this.safeString (trade, 'id');
        const side = this.safeString (trade, 'side');
        const orderId = this.safeString (trade, 'order_id');
        let fee = undefined;
        const feeCost = this.safeFloat (trade, 'fee');
        if (feeCost !== undefined) {
            const feeCurrencyCode = this.safeString (trade, 'fee_currency_code');
            fee = {
                'cost': feeCost,
                'currency': this.safeCurrencyCode (feeCurrencyCode),
            };
        }
        return {
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'id': tradeId,
            'order': orderId,
            'type': undefined,
            'side': side,
            'takerOrMaker': undefined,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': fee,
        };
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'market': market['id'],
        };
        if (since !== undefined) {
            request['start_time'] = this.iso8601 (since);
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetUserTrades (this.extend (request, params));
        const data = this.safeValue (response, 'data', []);
        return this.parseTrades (data, market, since, limit);
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'market': market['id'],
        };
        if (since !== undefined) {
            request['since'] = this.iso8601 (since);
        }
        const response = await this.publicGetMarketsMarketTrades (this.extend (request, params));
        const data = this.safeValue (response, 'data', []);
        return this.parseTrades (data, market, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        const response = await this.privateGetUserAccounts (params);
        const result = { 'info': response };
        const balances = this.safeValue (response, 'data');
        for (let i = 0; i < balances.length; i++) {
            const balance = balances[i];
            const currencyId = this.safeString (balance, 'currency_code');
            const code = this.safeCurrencyCode (currencyId);
            const account = {
                'free': this.safeFloat (balance, 'available_balance'),
                'used': this.safeFloat (balance, 'hold_balance'),
                'total': this.safeFloat (balance, 'balance'),
            };
            result[code] = account;
        }
        return this.parseBalance (result);
    }

    parseOrderStatus (status) {
        const statuses = {
            'fulfilled': 'closed',
            'canceled': 'canceled',
            'pending': 'open',
            'open': 'open',
            'partially_filled': 'open',
        };
        return this.safeString (statuses, status, status);
    }

    parseOrder (order, market = undefined) {
        //
        //     {
        //         "id":"8bdd79f4-8414-40a2-90c3-e9f4d6d1eef4"
        //         "market":"IOT-BTC"
        //         "price":"0.0000003"
        //         "size":"4.0"
        //         "size_filled":"3.0"
        //         "fee":"0.0075"
        //         "fee_currency_code":"iot"
        //         "funds":"0.0"
        //         "status":"canceled"
        //         "order_type":"buy"
        //         "post_only":false
        //         "operation_type":"market_order"
        //         "created_at":"2018-01-12T21:14:06.747828Z"
        //     }
        //
        const marketId = this.safeString (order, 'market');
        const symbol = this.safeSymbol (marketId, market, '-');
        const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
        const price = this.safeFloat (order, 'price');
        const amount = this.safeFloat (order, 'size');
        const filled = this.safeFloat (order, 'size_filled');
        let remaining = undefined;
        let cost = undefined;
        if (amount !== undefined) {
            if (filled !== undefined) {
                remaining = Math.max (0, amount - filled);
            }
            if (price !== undefined) {
                cost = filled * price;
            }
        }
        const status = this.parseOrderStatus (this.safeString (order, 'status'));
        let type = this.safeString (order, 'operation_type');
        if (type !== undefined) {
            type = type.split ('_');
            type = type[0];
        }
        const side = this.safeString (order, 'order_type');
        const postOnly = this.safeValue (order, 'post_only');
        return {
            'id': this.safeString (order, 'id'),
            'clientOrderId': undefined,
            'datetime': this.iso8601 (timestamp),
            'timestamp': timestamp,
            'status': status,
            'symbol': symbol,
            'type': type,
            'timeInForce': undefined,
            'postOnly': postOnly,
            'side': side,
            'price': price,
            'stopPrice': undefined,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'trades': undefined,
            'fee': undefined,
            'info': order,
            'lastTradeTimestamp': undefined,
            'average': undefined,
        };
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        // price/size must be string
        const request = {
            'market': market['id'],
            'size': this.amountToPrecision (symbol, amount),
            'order_type': side,
        };
        if (type === 'limit') {
            price = this.priceToPrecision (symbol, price);
            request['price'] = price.toString ();
        }
        request['operation_type'] = type + '_order';
        const response = await this.privatePostUserOrders (this.extend (request, params));
        const data = this.safeValue (response, 'data', {});
        return this.parseOrder (data, market);
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'id': id,
        };
        const response = await this.privateDeleteUserOrdersId (this.extend (request, params));
        const market = this.market (symbol);
        const data = this.safeValue (response, 'data', {});
        return this.parseOrder (data, market);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'id': id,
        };
        const response = await this.privateGetUserOrdersId (this.extend (request, params));
        const data = this.safeValue (response, 'data', {});
        return this.parseOrder (data);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market (symbol);
            request['market'] = market['id'];
        }
        if (since !== undefined) {
            request['since_time'] = this.iso8601 (since);
        }
        // TODO: test status=all if it works for closed orders too
        const response = await this.privateGetUserOrders (this.extend (request, params));
        const data = this.safeValue (response, 'data', []);
        const orders = this.filterByArray (data, 'status', [ 'pending', 'open', 'partially_filled' ], false);
        return this.parseOrders (orders, market, since, limit);
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = '/api/' + this.version + '/' + this.implodeParams (path, params);
        const query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length) {
                request += '?' + this.urlencode (query);
            }
        } else {
            this.checkRequiredCredentials ();
            if (method === 'GET') {
                if (Object.keys (query).length) {
                    request += '?' + this.urlencode (query);
                }
            } else {
                body = this.json (query);
            }
            const seconds = this.seconds ().toString ();
            let payload = [ seconds, method, request ].join ('|');
            if (body) {
                payload += '|' + body;
            }
            const signature = this.hmac (this.encode (payload), this.encode (this.secret));
            headers = {
                'CF-API-KEY': this.apiKey,
                'CF-API-TIMESTAMP': seconds,
                'CF-API-SIGNATURE': signature,
                'Content-Type': 'application/json',
            };
        }
        const url = this.urls['api'] + request;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (code < 400) {
            return;
        }
        const ErrorClass = this.safeValue ({
            '401': AuthenticationError,
            '429': RateLimitExceeded,
        }, code, ExchangeError);
        throw new ErrorClass (body);
    }
};
<commit_msg>coinfalcon ArgumentsRequired message unification<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError, RateLimitExceeded, ArgumentsRequired } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class coinfalcon extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'coinfalcon',
            'name': 'CoinFalcon',
            'countries': [ 'GB' ],
            'rateLimit': 1000,
            'version': 'v1',
            'has': {
                'cancelOrder': true,
                'createOrder': true,
                'fetchBalance': true,
                'fetchMarkets': true,
                'fetchMyTrades': true,
                'fetchOpenOrders': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchTicker': true,
                'fetchTickers': true,
                'fetchTrades': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/41822275-ed982188-77f5-11e8-92bb-496bcd14ca52.jpg',
                'api': 'https://coinfalcon.com',
                'www': 'https://coinfalcon.com',
                'doc': 'https://docs.coinfalcon.com',
                'fees': 'https://coinfalcon.com/fees',
                'referral': 'https://coinfalcon.com/?ref=CFJSVGTUPASB',
            },
            'api': {
                'public': {
                    'get': [
                        'markets',
                        'markets/{market}/orders',
                        'markets/{market}/trades',
                    ],
                },
                'private': {
                    'get': [
                        'user/accounts',
                        'user/orders',
                        'user/orders/{id}',
                        'user/trades',
                    ],
                    'post': [
                        'user/orders',
                    ],
                    'delete': [
                        'user/orders/{id}',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'tierBased': true,
                    'maker': 0.0,
                    'taker': 0.002, // tiered fee starts at 0.2%
                },
            },
            'precision': {
                'amount': 8,
                'price': 8,
            },
        });
    }

    async fetchMarkets (params = {}) {
        const response = await this.publicGetMarkets (params);
        const markets = this.safeValue (response, 'data');
        const result = [];
        for (let i = 0; i < markets.length; i++) {
            const market = markets[i];
            const [ baseId, quoteId ] = market['name'].split ('-');
            const base = this.safeCurrencyCode (baseId);
            const quote = this.safeCurrencyCode (quoteId);
            const symbol = base + '/' + quote;
            const precision = {
                'amount': this.safeInteger (market, 'size_precision'),
                'price': this.safeInteger (market, 'price_precision'),
            };
            result.push ({
                'id': market['name'],
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': true,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': Math.pow (10, -precision['amount']),
                        'max': undefined,
                    },
                    'price': {
                        'min': Math.pow (10, -precision['price']),
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'info': market,
            });
        }
        return result;
    }

    parseTicker (ticker, market = undefined) {
        const marketId = this.safeString (ticker, 'name');
        const symbol = this.safeSymbol (marketId, market, '-');
        const timestamp = this.milliseconds ();
        const last = parseFloat (ticker['last_price']);
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': undefined,
            'low': undefined,
            'bid': undefined,
            'bidVolume': undefined,
            'ask': undefined,
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': this.safeFloat (ticker, 'change_in_24h'),
            'percentage': undefined,
            'average': undefined,
            'baseVolume': undefined,
            'quoteVolume': this.safeFloat (ticker, 'volume'),
            'info': ticker,
        };
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        const tickers = await this.fetchTickers (params);
        return tickers[symbol];
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        const response = await this.publicGetMarkets (params);
        const tickers = this.safeValue (response, 'data');
        const result = {};
        for (let i = 0; i < tickers.length; i++) {
            const ticker = this.parseTicker (tickers[i]);
            const symbol = ticker['symbol'];
            result[symbol] = ticker;
        }
        return this.filterByArray (result, 'symbol', symbols);
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'market': this.marketId (symbol),
            'level': '3',
        };
        const response = await this.publicGetMarketsMarketOrders (this.extend (request, params));
        const data = this.safeValue (response, 'data', {});
        return this.parseOrderBook (data, undefined, 'bids', 'asks', 'price', 'size');
    }

    parseTrade (trade, market = undefined) {
        const timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
        const price = this.safeFloat (trade, 'price');
        const amount = this.safeFloat (trade, 'size');
        const symbol = market['symbol'];
        let cost = undefined;
        if (price !== undefined) {
            if (amount !== undefined) {
                cost = parseFloat (this.costToPrecision (symbol, price * amount));
            }
        }
        const tradeId = this.safeString (trade, 'id');
        const side = this.safeString (trade, 'side');
        const orderId = this.safeString (trade, 'order_id');
        let fee = undefined;
        const feeCost = this.safeFloat (trade, 'fee');
        if (feeCost !== undefined) {
            const feeCurrencyCode = this.safeString (trade, 'fee_currency_code');
            fee = {
                'cost': feeCost,
                'currency': this.safeCurrencyCode (feeCurrencyCode),
            };
        }
        return {
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'id': tradeId,
            'order': orderId,
            'type': undefined,
            'side': side,
            'takerOrMaker': undefined,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': fee,
        };
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'market': market['id'],
        };
        if (since !== undefined) {
            request['start_time'] = this.iso8601 (since);
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetUserTrades (this.extend (request, params));
        const data = this.safeValue (response, 'data', []);
        return this.parseTrades (data, market, since, limit);
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'market': market['id'],
        };
        if (since !== undefined) {
            request['since'] = this.iso8601 (since);
        }
        const response = await this.publicGetMarketsMarketTrades (this.extend (request, params));
        const data = this.safeValue (response, 'data', []);
        return this.parseTrades (data, market, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        const response = await this.privateGetUserAccounts (params);
        const result = { 'info': response };
        const balances = this.safeValue (response, 'data');
        for (let i = 0; i < balances.length; i++) {
            const balance = balances[i];
            const currencyId = this.safeString (balance, 'currency_code');
            const code = this.safeCurrencyCode (currencyId);
            const account = {
                'free': this.safeFloat (balance, 'available_balance'),
                'used': this.safeFloat (balance, 'hold_balance'),
                'total': this.safeFloat (balance, 'balance'),
            };
            result[code] = account;
        }
        return this.parseBalance (result);
    }

    parseOrderStatus (status) {
        const statuses = {
            'fulfilled': 'closed',
            'canceled': 'canceled',
            'pending': 'open',
            'open': 'open',
            'partially_filled': 'open',
        };
        return this.safeString (statuses, status, status);
    }

    parseOrder (order, market = undefined) {
        //
        //     {
        //         "id":"8bdd79f4-8414-40a2-90c3-e9f4d6d1eef4"
        //         "market":"IOT-BTC"
        //         "price":"0.0000003"
        //         "size":"4.0"
        //         "size_filled":"3.0"
        //         "fee":"0.0075"
        //         "fee_currency_code":"iot"
        //         "funds":"0.0"
        //         "status":"canceled"
        //         "order_type":"buy"
        //         "post_only":false
        //         "operation_type":"market_order"
        //         "created_at":"2018-01-12T21:14:06.747828Z"
        //     }
        //
        const marketId = this.safeString (order, 'market');
        const symbol = this.safeSymbol (marketId, market, '-');
        const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
        const price = this.safeFloat (order, 'price');
        const amount = this.safeFloat (order, 'size');
        const filled = this.safeFloat (order, 'size_filled');
        let remaining = undefined;
        let cost = undefined;
        if (amount !== undefined) {
            if (filled !== undefined) {
                remaining = Math.max (0, amount - filled);
            }
            if (price !== undefined) {
                cost = filled * price;
            }
        }
        const status = this.parseOrderStatus (this.safeString (order, 'status'));
        let type = this.safeString (order, 'operation_type');
        if (type !== undefined) {
            type = type.split ('_');
            type = type[0];
        }
        const side = this.safeString (order, 'order_type');
        const postOnly = this.safeValue (order, 'post_only');
        return {
            'id': this.safeString (order, 'id'),
            'clientOrderId': undefined,
            'datetime': this.iso8601 (timestamp),
            'timestamp': timestamp,
            'status': status,
            'symbol': symbol,
            'type': type,
            'timeInForce': undefined,
            'postOnly': postOnly,
            'side': side,
            'price': price,
            'stopPrice': undefined,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'trades': undefined,
            'fee': undefined,
            'info': order,
            'lastTradeTimestamp': undefined,
            'average': undefined,
        };
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        const market = this.market (symbol);
        // price/size must be string
        const request = {
            'market': market['id'],
            'size': this.amountToPrecision (symbol, amount),
            'order_type': side,
        };
        if (type === 'limit') {
            price = this.priceToPrecision (symbol, price);
            request['price'] = price.toString ();
        }
        request['operation_type'] = type + '_order';
        const response = await this.privatePostUserOrders (this.extend (request, params));
        const data = this.safeValue (response, 'data', {});
        return this.parseOrder (data, market);
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'id': id,
        };
        const response = await this.privateDeleteUserOrdersId (this.extend (request, params));
        const market = this.market (symbol);
        const data = this.safeValue (response, 'data', {});
        return this.parseOrder (data, market);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'id': id,
        };
        const response = await this.privateGetUserOrdersId (this.extend (request, params));
        const data = this.safeValue (response, 'data', {});
        return this.parseOrder (data);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {};
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market (symbol);
            request['market'] = market['id'];
        }
        if (since !== undefined) {
            request['since_time'] = this.iso8601 (since);
        }
        // TODO: test status=all if it works for closed orders too
        const response = await this.privateGetUserOrders (this.extend (request, params));
        const data = this.safeValue (response, 'data', []);
        const orders = this.filterByArray (data, 'status', [ 'pending', 'open', 'partially_filled' ], false);
        return this.parseOrders (orders, market, since, limit);
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = '/api/' + this.version + '/' + this.implodeParams (path, params);
        const query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length) {
                request += '?' + this.urlencode (query);
            }
        } else {
            this.checkRequiredCredentials ();
            if (method === 'GET') {
                if (Object.keys (query).length) {
                    request += '?' + this.urlencode (query);
                }
            } else {
                body = this.json (query);
            }
            const seconds = this.seconds ().toString ();
            let payload = [ seconds, method, request ].join ('|');
            if (body) {
                payload += '|' + body;
            }
            const signature = this.hmac (this.encode (payload), this.encode (this.secret));
            headers = {
                'CF-API-KEY': this.apiKey,
                'CF-API-TIMESTAMP': seconds,
                'CF-API-SIGNATURE': signature,
                'Content-Type': 'application/json',
            };
        }
        const url = this.urls['api'] + request;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (code < 400) {
            return;
        }
        const ErrorClass = this.safeValue ({
            '401': AuthenticationError,
            '429': RateLimitExceeded,
        }, code, ExchangeError);
        throw new ErrorClass (body);
    }
};
<|endoftext|>


<commit_before>describe("About Functions", function() {

  it("should declare functions", function() {

    function add(a, b) {
      return a + b;
    }

    expect(add(1, 2)).toBe(3);
  });

  it("should know internal variables override outer variables", function () {
    var message = "Outer";

    function getMessage() {
      return message;
    }

    function overrideMessage() {
      var message = "Inner";
      return message;
    }

    expect(getMessage()).toBe("Outer");
    expect(overrideMessage()).toBe("Inner");
    expect(message).toBe("Outer");
  });

  it("should have lexical scoping", function () {
    var variable = "top-level";
    function parentfunction() {
        var variable = "local";
      function childfunction() {
          return variable;
      }
      return childfunction();
    }
    expect(parentfunction()).toBe("local");
  });

  it("should use lexical scoping to synthesise functions", function () {

    function makeIncreaseByFunction(increaseByAmount) {
      return function (numberToIncrease) {
        return numberToIncrease + increaseByAmount;
      };
    }

    var increaseBy3 = makeIncreaseByFunction(3);
    var increaseBy5 = makeIncreaseByFunction(5);

    expect(increaseBy3(10) + increaseBy5(10)).toBe(28);
  });

  it("should allow extra function arguments", function () {

    function returnFirstArg(firstArg) {
      return firstArg;
    }

    expect(returnFirstArg("first", "second", "third")).toBe("first");

    function returnSecondArg(firstArg, secondArg) {
      return secondArg;
    }

    expect(returnSecondArg("only give first arg")).toBe(undefined);

    function returnAllArgs() {
      var argsArray = [];
      for (var i = 0; i < arguments.length; i += 1) {
        argsArray.push(arguments[i]);
      }
      return argsArray.join(",");
    }

    expect(returnAllArgs("first", "second", "third")).toBe('first,second,third');
  });

  it("should pass functions as values", function () {

    var appendRules = function (name) {
      return name + " rules!";
    };

    var appendDoubleRules = function (name) {
      return name + " totally rules!";
    };

    var praiseSinger = { givePraise: appendRules };
    expect(praiseSinger.givePraise("John")).toBe('John rules!');

    praiseSinger.givePraise = appendDoubleRules;
    expect(praiseSinger.givePraise("Mary")).toBe('Mary totally rules!');

  });

  it("should use function body as a string", function () {
    var add = new Function("a", "b", "return a + b;");
    expect(add(1, 2)).toBe(3);

    var multiply = function (a, b) {
      //An internal comment
      return a * b;
    };
    expect(multiply.toString()).toBe("function (a, b) {\n      //An internal comment\n      return a * b;\n    }");
  });
});
<commit_msg>Edit functions<commit_after>describe("About Functions", function() {

  it("should declare functions", function() {

    function add(a, b) {
      return a + b;
    }

    expect(add(1, 2)).toBe(3);
  });

  it("should know internal variables override outer variables", function () {
    var message = "Outer";

    function getMessage() {
      return message;
    }

    function overrideMessage() {
      var message = "Inner";
      return message;
    }

    expect(getMessage()).toBe("Outer");
    expect(overrideMessage()).toBe("Inner");
    expect(message).toBe("Outer");
  });

  it("should have lexical scoping", function () {
    var variable = "top-level";
    function parentfunction() {
        var variable = "local";
      function childfunction() {
          return variable;
      }
      return childfunction();
    }
    expect(parentfunction()).toBe("local");
  });

  it("should use lexical scoping to synthesise functions", function () {

    function makeIncreaseByFunction(increaseByAmount) {
      return function (numberToIncrease) {
        return numberToIncrease + increaseByAmount;
      };
    }

    var increaseBy3 = makeIncreaseByFunction(3);
    var increaseBy5 = makeIncreaseByFunction(5);

    expect(increaseBy3(10) + increaseBy5(10)).toBe(28);
  });

  it("should allow extra function arguments", function () {

    function returnFirstArg(firstArg) {
      return firstArg;
    }

    expect(returnFirstArg("first", "second", "third")).toBe("first");

    function returnSecondArg(firstArg, secondArg) {
      return secondArg;
    }

    expect(returnSecondArg("only give first arg")).toBe(undefined);

    function returnAllArgs() {
      var argsArray = [];
      for (var i = 0; i < arguments.length; i += 1) {
        argsArray.push(arguments[i]);
      }
      return argsArray.join(",");
    }

    expect(returnAllArgs("first", "second", "third")).toBe('first,second,third');
  });

  it("should pass functions as values", function () {

    var appendRules = function (name) {
      return name + " rules!";
    };

    var appendDoubleRules = function (name) {
      return name + " totally rules!";
    };

    var praiseSinger = { givePraise: appendRules };
    expect(praiseSinger.givePraise("John")).toBe('John rules!');

    praiseSinger.givePraise = appendDoubleRules;
    expect(praiseSinger.givePraise("Mary")).toBe('Mary totally rules!');

  });

  it("should use function body as a string", function () {
    var add = new Function("a", "b", "return a + b;");
    expect(add(1, 2)).toBe(3);

    var multiply = function (a, b) {
      //An internal comment
      return a * b;
    };
    expect(multiply.toString()).toBe('function (a, b) {
      //An internal comment
      return a * b;
    }');
  });
});
<|endoftext|>


<commit_before>if (process.env.WEBDRIVER) {
	console.info("Running only selenium tests, skipping this one");
	return;
}

var expect = require('expect.js');
var request = require('request');
var express = require('express');
var dom = require('express-dom');
var Web = require('webkitgtk');

dom.settings.stall = 5000;
dom.settings.allow = 'all';
dom.settings.timeout = 10000;
dom.settings.console = true;

var renderPlugins = [
	dom.plugins.redirect,
	dom.plugins.referrer,
	dom.plugins.html
];

var host = "http://localhost";

describe("Two-phase rendering", function suite() {
	this.timeout(3000);
	var server, port;

	before(function(done) {
		var app = express();
		app.set('views', __dirname + '/public');
		app.get(/\.(json|js|css|png|templates)$/, express.static(app.get('views')));
		app.get(/\/templates\/.+\.html$/, express.static(app.get('views')));
		app.get(/\.html$/, dom().load());

		server = app.listen(function(err) {
			if (err) console.error(err);
			port = server.address().port;
			done();
		});
	});

	after(function(done) {
		server.close();
		done();
	});

	it("should run build then setup", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/build.html'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('
0
');
			expect(body).to.contain('

');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
0
');
				expect(state.body).to.contain('
0
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should run build and patch then setup", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/patch.html'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('
1
');
			expect(body).to.contain('
1
');
			expect(body).to.contain('

');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
1
');
				expect(state.body).to.contain('
1
');
				expect(state.body).to.contain('
1
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should run route and imports", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/route.html?template=import'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('data-page-stage="build"');
			expect(body).to.contain("I'm built0");
			expect(body).to.contain("your body0");
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('data-page-stage="setup"');
				expect(state.body).to.contain("I'm setup0");
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should load stylesheet when rendering", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/route.html?template=stylesheets'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('
hidden0
');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
squared0
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should load stylesheet before inline script when rendering", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/route.html?template=order-stylesheets'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.not.contain('
squared
');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
squared
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should run build and patch then setup then patch", function(done) {
		Web.load(host + ':' + port + '/repatch.html', {
			stallTimeout: 100,
			console: true,
			navigation: true
		}).once('idle', function() {
			setTimeout(function() {
				this.html().then(function(body) {
					expect(body).to.contain('
/repatch.html?test=one
');
					expect(body).to.contain('
1
');
					expect(body).to.contain('
2
');
					expect(body).to.contain('
1
');
					done();
				}).catch(function(err) {
					done(err);
				});
			}.bind(this), 500);
		});
	});

	it("should run build and patch then setup then patch then back then patch", function(done) {
		Web.load(host + ':' + port + '/back-patch.html', {
			stallTimeout: 100,
			console: true,
			navigation: true
		}).once('idle', function() {
			setTimeout(function() {
				this.html().then(function(body) {
					expect(body).to.contain('
1
');
					expect(body).to.contain('
2
');
					expect(body).to.contain('
1
');
					expect(body).to.contain('
/back-patch.html?test=one
');
					expect(body).to.contain('
/back-patch.html
');
					done();
				}).catch(function(err) {
					done(err);
				});
			}.bind(this), 500);
		});
	});

	it("should run build then setup then hash", function(done) {
		Web.load(host + ':' + port + '/hash.html#test', {
			stallTimeout: 100,
			console: true,
			navigation: true
		}).once('idle', function() {
			setTimeout(function() {
				this.html().then(function(body) {
					expect(body).to.contain('
1
');
					expect(body).to.contain('
1
');
					expect(body).to.contain('
1
');
					expect(body).to.contain('
test
');
					done();
				}).catch(function(err) {
					done(err);
				});
			}.bind(this), 500);
		});
	});
});

<commit_msg>Port Render function to other prerender-render<commit_after>if (process.env.WEBDRIVER) {
	console.info("Running only selenium tests, skipping this one");
	return;
}

var expect = require('expect.js');
var request = require('request');
var express = require('express');
var dom = require('express-dom');
var Web = require('webkitgtk');

dom.settings.stall = 5000;
dom.settings.allow = 'all';
dom.settings.timeout = 10000;
dom.settings.console = true;

var renderPlugins = [
	debugPlugin,
	dom.plugins.redirect,
	dom.plugins.referrer,
	dom.plugins.html
];

function debugPlugin(page, settings) {
	if (process.env.DEBUG) {
		if (!settings.scripts) settings.scripts = [];
		settings.scripts.push(function(n) {
			window.debug = console.error.bind(console);
		});
	}
}

function Render(url, opts) {
	if (!opts) opts = {};
	return new Promise(function(resolve, reject) {
		Web(function(err, page) {
			var settings = {
				stallTimeout: 1000,
				console: true,
				navigation: true
			};
			debugPlugin(page, settings);

			page.when('ready', function() {
				if (opts.ready) page.run(opts.ready);
			});
			page.when('idle', function() {
				setTimeout(function() {
					page.html().then(resolve);
				}, opts.delay);
			}).catch(reject);
			page.load(url, settings);
		});
	});
}

var host = "http://localhost";

describe("Two-phase rendering", function suite() {
	this.timeout(3000);
	var server, port;

	before(function(done) {
		var app = express();
		app.set('views', __dirname + '/public');
		app.get(/\.(json|js|css|png|templates)$/, express.static(app.get('views')));
		app.get(/\/templates\/.+\.html$/, express.static(app.get('views')));
		app.get(/\.html$/, dom().load());

		server = app.listen(function(err) {
			if (err) console.error(err);
			port = server.address().port;
			done();
		});
	});

	after(function(done) {
		server.close();
		done();
	});

	it("should run build then setup", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/build.html'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('
0
');
			expect(body).to.contain('

');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
0
');
				expect(state.body).to.contain('
0
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should run build and patch then setup", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/patch.html'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('
1
');
			expect(body).to.contain('
1
');
			expect(body).to.contain('

');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
1
');
				expect(state.body).to.contain('
1
');
				expect(state.body).to.contain('
1
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should run route and imports", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/route.html?template=import'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('data-page-stage="build"');
			expect(body).to.contain("I'm built0");
			expect(body).to.contain("your body0");
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('data-page-stage="setup"');
				expect(state.body).to.contain("I'm setup0");
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should load stylesheet when rendering", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/route.html?template=stylesheets'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.contain('
hidden0
');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
squared0
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should load stylesheet before inline script when rendering", function(done) {
		request({
			method: 'GET',
			url: host + ':' + port + '/route.html?template=order-stylesheets'
		}, function(err, res, body) {
			expect(res.statusCode).to.be(200);
			expect(body).to.not.contain('
squared
');
			dom(body).load({
				plugins: renderPlugins
			})(res.request.uri.href).then(function(state) {
				expect(state.body).to.contain('
squared
');
				done();
			}).catch(function(err) {
				done(err);
			});
		});
	});

	it("should run build and patch then setup then patch", function(done) {
		Web.load(host + ':' + port + '/repatch.html', {
			stallTimeout: 100,
			console: true,
			navigation: true
		}).once('idle', function() {
			setTimeout(function() {
				this.html().then(function(body) {
					expect(body).to.contain('
/repatch.html?test=one
');
					expect(body).to.contain('
1
');
					expect(body).to.contain('
2
');
					expect(body).to.contain('
1
');
					done();
				}).catch(function(err) {
					done(err);
				});
			}.bind(this), 500);
		});
	});

	it("should run build and patch then setup then patch then back then patch", function() {
		return Render(host + ':' + port + '/back-patch.html', {delay: 500}).then(function(body) {
			expect(body).to.contain('
1
');
			expect(body).to.contain('
2
');
			expect(body).to.contain('
1
');
			expect(body).to.contain('
/back-patch.html?test=one
');
			expect(body).to.contain('
/back-patch.html
');
		});
	});

	it("should run build then setup then hash", function() {
		return Render(host + ':' + port + '/hash.html#test', {delay: 500}).then(function(body) {
			expect(body).to.contain('
1
');
			expect(body).to.contain('
1
');
			expect(body).to.contain('
1
');
			expect(body).to.contain('
test
');
		});
	});
});

<|endoftext|>


<commit_before>$(function() {

    $("input,textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
          console.log(errors);
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $.ajax({
                url: "https://docs.google.com/forms/d/1iw76VGJ9_bMAa9u2VbcS-DAi1jMEVSA4LurJQ2RFv0s/formResponse",
                type: "POST",
                datatype: "xml",
                data: {
                    name: name,
                    email: email,
                    message: message
                },
                cache: false,
                success: function() {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function() {
                    // Fail message
                    $('#success').html("
");
                    $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-danger').append("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!");
                    $('#success > .alert-danger').append('
');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
            })
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});
<commit_msg>fix contact me<commit_after>$(function() {

    $("input,textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
          console.log(errors);
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $.ajax({
              url: "https://docs.google.com/forms/d/1iw76VGJ9_bMAa9u2VbcS-DAi1jMEVSA4LurJQ2RFv0s/formResponse",
                type: "POST",
                crossDomain: true,
                dataType: 'jsonp',
                data: {
                    "entry.410842087": name,
                    "entry.1917516394": email,
                    "entry.1045627991": message
                },
                cache: false,
                success: function() {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function(response) {
                  if (response.status == 200) {
                    // Success message
                    $('#success').html("
");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("Your message has been sent. ");
                    $('#success > .alert-success')
                        .append('
');

                    //clear all fields
                    $('#contactForm').trigger("reset");

                    }
                    else {
                      // Fail message
                      $('#success').html("
");
                      $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                          .append("</button>");
                      $('#success > .alert-danger').append("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!");
                      $('#success > .alert-danger').append('
');
                      //clear all fields
                      $('#contactForm').trigger("reset");
                    }
                  },
            })
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});
<|endoftext|>